summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /lib
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/README9
-rw-r--r--lib/addns/dns.h366
-rw-r--r--lib/addns/dnserr.h87
-rw-r--r--lib/addns/dnsgss.c344
-rw-r--r--lib/addns/dnsmarshall.c534
-rw-r--r--lib/addns/dnsquery.c782
-rw-r--r--lib/addns/dnsquery.h84
-rw-r--r--lib/addns/dnsquery_srv.c560
-rw-r--r--lib/addns/dnsquery_srv.h54
-rw-r--r--lib/addns/dnsrecord.c484
-rw-r--r--lib/addns/dnssock.c420
-rw-r--r--lib/addns/dnsutils.c149
-rw-r--r--lib/addns/error.c59
-rw-r--r--lib/addns/wscript_build16
-rw-r--r--lib/afs/afs_funcs.c313
-rw-r--r--lib/afs/afs_funcs.h42
-rw-r--r--lib/afs/afs_settoken.c264
-rw-r--r--lib/afs/afs_settoken.h21
-rw-r--r--lib/afs/wscript_build10
-rw-r--r--lib/async_req/async_connect_send_test.c130
-rw-r--r--lib/async_req/async_sock.c774
-rw-r--r--lib/async_req/async_sock.h68
-rw-r--r--lib/async_req/wscript_build14
-rw-r--r--lib/audit_logging/audit_logging.c1356
-rw-r--r--lib/audit_logging/audit_logging.h113
-rw-r--r--lib/audit_logging/tests/audit_logging_error_test.c901
-rw-r--r--lib/audit_logging/tests/audit_logging_test.c919
-rw-r--r--lib/audit_logging/wscript_build60
-rw-r--r--lib/cmdline/closefrom_except.c93
-rw-r--r--lib/cmdline/closefrom_except.h29
-rw-r--r--lib/cmdline/cmdline.c1415
-rw-r--r--lib/cmdline/cmdline.h319
-rw-r--r--lib/cmdline/cmdline_private.h121
-rw-r--r--lib/cmdline/cmdline_s3.c152
-rw-r--r--lib/cmdline/cmdline_s4.c125
-rw-r--r--lib/cmdline/tests/test_cmdline.c97
-rw-r--r--lib/cmdline/wscript35
-rw-r--r--lib/compression/lzxpress.c507
-rw-r--r--lib/compression/lzxpress.h50
-rw-r--r--lib/compression/lzxpress_huffman.c2045
-rw-r--r--lib/compression/lzxpress_huffman.h95
-rw-r--r--lib/compression/pycompression.c304
-rw-r--r--lib/compression/tests/scripts/README19
-rwxr-xr-xlib/compression/tests/scripts/decode-huffman-header54
-rw-r--r--lib/compression/tests/scripts/generate-windows-test-vectors.c206
-rwxr-xr-xlib/compression/tests/scripts/make-fuzz-examples45
-rwxr-xr-xlib/compression/tests/scripts/make-test-vectors185
-rwxr-xr-xlib/compression/tests/scripts/three-byte-hash49
-rw-r--r--lib/compression/tests/test_lzx_huffman.c1255
-rw-r--r--lib/compression/tests/test_lzxpress_plain.c1194
-rw-r--r--lib/compression/wscript_build25
-rw-r--r--lib/crypto/REQUIREMENTS139
-rw-r--r--lib/crypto/aes.h44
-rw-r--r--lib/crypto/crypto.h26
-rw-r--r--lib/crypto/gkdi.c396
-rw-r--r--lib/crypto/gkdi.h99
-rw-r--r--lib/crypto/gnutls_aead_aes_256_cbc_hmac_sha512.c399
-rw-r--r--lib/crypto/gnutls_arcfour_confounded_md5.c93
-rw-r--r--lib/crypto/gnutls_error.c117
-rw-r--r--lib/crypto/gnutls_helpers.h236
-rw-r--r--lib/crypto/gnutls_sp800_108.c230
-rw-r--r--lib/crypto/gnutls_weak_crypto.c47
-rw-r--r--lib/crypto/md4.c179
-rw-r--r--lib/crypto/md4.h1
-rw-r--r--lib/crypto/md4test.c85
-rw-r--r--lib/crypto/py_crypto.c444
-rw-r--r--lib/crypto/test_gkdi_key_derivation.c492
-rw-r--r--lib/crypto/tests/test_gnutls_aead_aes_256_cbc_hmac_sha512.c320
-rw-r--r--lib/crypto/tests/test_gnutls_sp800_108.c394
-rw-r--r--lib/crypto/wscript63
-rw-r--r--lib/dbwrap/dbwrap.c736
-rw-r--r--lib/dbwrap/dbwrap.h252
-rw-r--r--lib/dbwrap/dbwrap_local_open.c46
-rw-r--r--lib/dbwrap/dbwrap_private.h93
-rw-r--r--lib/dbwrap/dbwrap_rbt.c589
-rw-r--r--lib/dbwrap/dbwrap_rbt.h29
-rw-r--r--lib/dbwrap/dbwrap_tdb.c518
-rw-r--r--lib/dbwrap/dbwrap_tdb.h35
-rw-r--r--lib/dbwrap/dbwrap_util.c756
-rw-r--r--lib/dbwrap/wscript_build8
-rw-r--r--lib/fuzzing/README.md87
-rw-r--r--lib/fuzzing/afl-fuzz-main.c66
-rwxr-xr-xlib/fuzzing/decode_ndr_X_crash137
-rw-r--r--lib/fuzzing/fuzz_cli_credentials_parse_string.c63
-rw-r--r--lib/fuzzing/fuzz_conditional_ace_blob.c156
-rw-r--r--lib/fuzzing/fuzz_dcerpc_parse_binding.c76
-rw-r--r--lib/fuzzing/fuzz_ldap_decode.c66
-rw-r--r--lib/fuzzing/fuzz_ldb_comparison_fold.c58
-rw-r--r--lib/fuzzing/fuzz_ldb_dn_explode.c53
-rw-r--r--lib/fuzzing/fuzz_ldb_ldif_read.c56
-rw-r--r--lib/fuzzing/fuzz_ldb_parse_binary_decode.c55
-rw-r--r--lib/fuzzing/fuzz_ldb_parse_control.c55
-rw-r--r--lib/fuzzing/fuzz_ldb_parse_tree.c53
-rw-r--r--lib/fuzzing/fuzz_lzxpress.c35
-rw-r--r--lib/fuzzing/fuzz_lzxpress_compress.c35
-rw-r--r--lib/fuzzing/fuzz_lzxpress_huffman_compress.c58
-rw-r--r--lib/fuzzing/fuzz_lzxpress_huffman_decompress.c48
-rw-r--r--lib/fuzzing/fuzz_lzxpress_huffman_round_trip.c68
-rw-r--r--lib/fuzzing/fuzz_lzxpress_round_trip.c56
-rw-r--r--lib/fuzzing/fuzz_ndr_X.c337
-rw-r--r--lib/fuzzing/fuzz_nmblib_parse_packet.c62
-rw-r--r--lib/fuzzing/fuzz_oLschema2ldif.c71
-rw-r--r--lib/fuzzing/fuzz_parse_lpq_entry.c65
-rw-r--r--lib/fuzzing/fuzz_reg_parse.c46
-rw-r--r--lib/fuzzing/fuzz_regfio.c68
-rw-r--r--lib/fuzzing/fuzz_sddl_access_check.c206
-rw-r--r--lib/fuzzing/fuzz_sddl_conditional_ace.c121
-rw-r--r--lib/fuzzing/fuzz_sddl_parse.c110
-rw-r--r--lib/fuzzing/fuzz_security_token_vs_descriptor.c78
-rw-r--r--lib/fuzzing/fuzz_sess_crypt_blob.c55
-rw-r--r--lib/fuzzing/fuzz_stable_sort.c88
-rw-r--r--lib/fuzzing/fuzz_stable_sort_r.c69
-rw-r--r--lib/fuzzing/fuzz_tiniparser.c51
-rw-r--r--lib/fuzzing/fuzzing.c21
-rw-r--r--lib/fuzzing/fuzzing.h30
-rwxr-xr-xlib/fuzzing/oss-fuzz/build_image.sh7
-rwxr-xr-xlib/fuzzing/oss-fuzz/build_samba.sh25
-rwxr-xr-xlib/fuzzing/oss-fuzz/check_build.sh48
-rwxr-xr-xlib/fuzzing/oss-fuzz/do_build.sh294
-rw-r--r--lib/fuzzing/patches/collect-access-check-seeds.txt256
-rw-r--r--lib/fuzzing/wscript_build236
-rw-r--r--lib/krb5_wrap/enctype_convert.c108
-rw-r--r--lib/krb5_wrap/gss_samba.c222
-rw-r--r--lib/krb5_wrap/gss_samba.h49
-rw-r--r--lib/krb5_wrap/keytab_util.c65
-rw-r--r--lib/krb5_wrap/krb5_errs.c115
-rw-r--r--lib/krb5_wrap/krb5_samba.c4043
-rw-r--r--lib/krb5_wrap/krb5_samba.h443
-rw-r--r--lib/krb5_wrap/wscript_build23
-rw-r--r--lib/krb5_wrap/wscript_configure18
-rw-r--r--lib/ldb-samba/README7
-rw-r--r--lib/ldb-samba/ldb_ildap.c1018
-rw-r--r--lib/ldb-samba/ldb_matching_rules.c636
-rw-r--r--lib/ldb-samba/ldb_matching_rules.h30
-rw-r--r--lib/ldb-samba/ldb_wrap.c377
-rw-r--r--lib/ldb-samba/ldb_wrap.h70
-rw-r--r--lib/ldb-samba/ldif_handlers.c1843
-rw-r--r--lib/ldb-samba/ldif_handlers.h30
-rw-r--r--lib/ldb-samba/pyldb.c320
-rw-r--r--lib/ldb-samba/samba_extensions.c169
-rw-r--r--lib/ldb-samba/tests/index.py192
-rwxr-xr-xlib/ldb-samba/tests/match_rules.py1797
-rwxr-xr-xlib/ldb-samba/tests/match_rules_remote.py104
-rw-r--r--lib/ldb-samba/wscript_build44
-rw-r--r--lib/ldb/ABI/ldb-0.9.10.sigs218
-rw-r--r--lib/ldb/ABI/ldb-0.9.12.sigs219
-rw-r--r--lib/ldb/ABI/ldb-0.9.15.sigs226
-rw-r--r--lib/ldb/ABI/ldb-0.9.16.sigs228
-rw-r--r--lib/ldb/ABI/ldb-0.9.17.sigs229
-rw-r--r--lib/ldb/ABI/ldb-0.9.18.sigs240
-rw-r--r--lib/ldb/ABI/ldb-0.9.19.sigs245
-rw-r--r--lib/ldb/ABI/ldb-0.9.20.sigs245
-rw-r--r--lib/ldb/ABI/ldb-0.9.22.sigs245
-rw-r--r--lib/ldb/ABI/ldb-0.9.23.sigs247
-rw-r--r--lib/ldb/ABI/ldb-0.9.24.sigs248
-rw-r--r--lib/ldb/ABI/ldb-1.0.0.sigs248
-rw-r--r--lib/ldb/ABI/ldb-1.0.1.sigs248
-rw-r--r--lib/ldb/ABI/ldb-1.0.2.sigs250
-rw-r--r--lib/ldb/ABI/ldb-1.1.0.sigs253
-rw-r--r--lib/ldb/ABI/ldb-1.1.1.sigs254
-rw-r--r--lib/ldb/ABI/ldb-1.1.10.sigs259
-rw-r--r--lib/ldb/ABI/ldb-1.1.11.sigs259
-rw-r--r--lib/ldb/ABI/ldb-1.1.12.sigs260
-rw-r--r--lib/ldb/ABI/ldb-1.1.13.sigs260
-rw-r--r--lib/ldb/ABI/ldb-1.1.14.sigs262
-rw-r--r--lib/ldb/ABI/ldb-1.1.15.sigs262
-rw-r--r--lib/ldb/ABI/ldb-1.1.16.sigs262
-rw-r--r--lib/ldb/ABI/ldb-1.1.17.sigs262
-rw-r--r--lib/ldb/ABI/ldb-1.1.18.sigs262
-rw-r--r--lib/ldb/ABI/ldb-1.1.19.sigs263
-rw-r--r--lib/ldb/ABI/ldb-1.1.2.sigs256
-rw-r--r--lib/ldb/ABI/ldb-1.1.20.sigs263
-rw-r--r--lib/ldb/ABI/ldb-1.1.21.sigs263
-rw-r--r--lib/ldb/ABI/ldb-1.1.22.sigs264
-rw-r--r--lib/ldb/ABI/ldb-1.1.23.sigs264
-rw-r--r--lib/ldb/ABI/ldb-1.1.24.sigs264
-rw-r--r--lib/ldb/ABI/ldb-1.1.25.sigs265
-rw-r--r--lib/ldb/ABI/ldb-1.1.26.sigs265
-rw-r--r--lib/ldb/ABI/ldb-1.1.27.sigs266
-rw-r--r--lib/ldb/ABI/ldb-1.1.28.sigs266
-rw-r--r--lib/ldb/ABI/ldb-1.1.29.sigs268
-rw-r--r--lib/ldb/ABI/ldb-1.1.3.sigs256
-rw-r--r--lib/ldb/ABI/ldb-1.1.30.sigs272
-rw-r--r--lib/ldb/ABI/ldb-1.1.31.sigs274
-rw-r--r--lib/ldb/ABI/ldb-1.1.4.sigs256
-rw-r--r--lib/ldb/ABI/ldb-1.1.5.sigs257
-rw-r--r--lib/ldb/ABI/ldb-1.1.6.sigs258
-rw-r--r--lib/ldb/ABI/ldb-1.1.7.sigs258
-rw-r--r--lib/ldb/ABI/ldb-1.1.8.sigs258
-rw-r--r--lib/ldb/ABI/ldb-1.1.9.sigs258
-rw-r--r--lib/ldb/ABI/ldb-1.2.0.sigs276
-rw-r--r--lib/ldb/ABI/ldb-1.2.1.sigs276
-rw-r--r--lib/ldb/ABI/ldb-1.2.2.sigs277
-rw-r--r--lib/ldb/ABI/ldb-1.2.3.sigs277
-rw-r--r--lib/ldb/ABI/ldb-1.3.0.sigs279
-rw-r--r--lib/ldb/ABI/ldb-1.3.1.sigs279
-rw-r--r--lib/ldb/ABI/ldb-1.3.2.sigs279
-rw-r--r--lib/ldb/ABI/ldb-1.4.0.sigs279
-rw-r--r--lib/ldb/ABI/ldb-1.4.1.sigs279
-rw-r--r--lib/ldb/ABI/ldb-1.5.0.sigs279
-rw-r--r--lib/ldb/ABI/ldb-1.5.1.sigs280
-rw-r--r--lib/ldb/ABI/ldb-1.5.2.sigs280
-rw-r--r--lib/ldb/ABI/ldb-1.5.3.sigs280
-rw-r--r--lib/ldb/ABI/ldb-1.6.0.sigs280
-rw-r--r--lib/ldb/ABI/ldb-1.6.1.sigs280
-rw-r--r--lib/ldb/ABI/ldb-1.6.2.sigs280
-rw-r--r--lib/ldb/ABI/ldb-1.6.3.sigs280
-rw-r--r--lib/ldb/ABI/ldb-2.0.0.sigs280
-rw-r--r--lib/ldb/ABI/ldb-2.0.1.sigs280
-rw-r--r--lib/ldb/ABI/ldb-2.0.2.sigs281
-rw-r--r--lib/ldb/ABI/ldb-2.0.3.sigs281
-rw-r--r--lib/ldb/ABI/ldb-2.0.4.sigs282
-rw-r--r--lib/ldb/ABI/ldb-2.0.5.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.1.0.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.1.1.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.2.0.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.4.0.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.4.1.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.5.0.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.6.0.sigs283
-rw-r--r--lib/ldb/ABI/ldb-2.6.1.sigs291
-rw-r--r--lib/ldb/ABI/ldb-2.7.0.sigs291
-rw-r--r--lib/ldb/ABI/ldb-2.8.0.sigs305
-rw-r--r--lib/ldb/ABI/ldb-2.9.0.sigs305
-rw-r--r--lib/ldb/ABI/ldb-ildap-0.9.12.sigs224
-rw-r--r--lib/ldb/ABI/ldb-samba4-0.9.10.sigs223
-rw-r--r--lib/ldb/ABI/ldb-samba4-0.9.11.sigs224
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.10.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.11.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.12.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.13.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.14.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.15.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.16.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.17.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.18.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.19.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.2.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.20.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.21.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.22.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.23.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.24.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.25.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.26.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.27.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.28.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.29.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.3.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.30.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.31.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.4.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.5.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.6.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.7.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.8.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.1.9.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.2.0.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.2.1.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.2.2.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.2.3.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.3.0.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.3.1.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.3.2.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.4.0.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.4.1.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.5.0.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.5.1.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.5.2.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.5.3.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.6.0.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.6.1.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.6.2.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-1.6.3.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-2.0.0.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-2.0.1.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-2.0.2.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-2.0.3.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-2.0.4.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-2.0.5.sigs2
-rw-r--r--lib/ldb/ABI/pyldb-util-2.1.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.1.1.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.2.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.4.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.4.1.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.5.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.6.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.6.1.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.7.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.8.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util-2.9.0.sigs3
-rw-r--r--lib/ldb/ABI/pyldb-util.py3-2.0.0.sigs2
-rw-r--r--lib/ldb/Doxyfile26
-rw-r--r--lib/ldb/Makefile53
-rw-r--r--lib/ldb/README_gcov.txt29
-rw-r--r--lib/ldb/_ldb_text.py146
-rw-r--r--lib/ldb/common/attrib_handlers.c639
-rw-r--r--lib/ldb/common/ldb.c2204
-rw-r--r--lib/ldb/common/ldb_attributes.c411
-rw-r--r--lib/ldb/common/ldb_controls.c1342
-rw-r--r--lib/ldb/common/ldb_debug.c150
-rw-r--r--lib/ldb/common/ldb_dn.c2234
-rw-r--r--lib/ldb/common/ldb_ldif.c1128
-rw-r--r--lib/ldb/common/ldb_match.c826
-rw-r--r--lib/ldb/common/ldb_modules.c1237
-rw-r--r--lib/ldb/common/ldb_msg.c1784
-rw-r--r--lib/ldb/common/ldb_options.c107
-rw-r--r--lib/ldb/common/ldb_pack.c1362
-rw-r--r--lib/ldb/common/ldb_parse.c1028
-rw-r--r--lib/ldb/common/ldb_utf8.c140
-rw-r--r--lib/ldb/common/qsort.c251
-rwxr-xr-xlib/ldb/configure28
-rwxr-xr-xlib/ldb/docs/builddocs.sh52
-rw-r--r--lib/ldb/docs/design.txt41
-rwxr-xr-xlib/ldb/docs/installdocs.sh17
-rw-r--r--lib/ldb/examples.dox16
-rw-r--r--lib/ldb/examples/ldbreader.c122
-rw-r--r--lib/ldb/examples/ldifreader.c125
-rw-r--r--lib/ldb/include/dlinklist.h198
-rw-r--r--lib/ldb/include/ldb.h2399
-rw-r--r--lib/ldb/include/ldb_errors.h312
-rw-r--r--lib/ldb/include/ldb_handlers.h45
-rw-r--r--lib/ldb/include/ldb_module.h640
-rw-r--r--lib/ldb/include/ldb_private.h354
-rw-r--r--lib/ldb/ldb.pc.in16
-rw-r--r--lib/ldb/ldb_key_value/ldb_kv.c2291
-rw-r--r--lib/ldb/ldb_key_value/ldb_kv.h344
-rw-r--r--lib/ldb/ldb_key_value/ldb_kv_cache.c697
-rw-r--r--lib/ldb/ldb_key_value/ldb_kv_index.c4018
-rw-r--r--lib/ldb/ldb_key_value/ldb_kv_search.c795
-rw-r--r--lib/ldb/ldb_ldap/ldb_ldap.c967
-rw-r--r--lib/ldb/ldb_ldb/ldb_ldb.c80
-rw-r--r--lib/ldb/ldb_map/ldb_map.c1153
-rw-r--r--lib/ldb/ldb_map/ldb_map.h174
-rw-r--r--lib/ldb/ldb_map/ldb_map_inbound.c844
-rw-r--r--lib/ldb/ldb_map/ldb_map_outbound.c1422
-rw-r--r--lib/ldb/ldb_map/ldb_map_private.h96
-rw-r--r--lib/ldb/ldb_mdb/ldb_mdb.c1151
-rw-r--r--lib/ldb/ldb_mdb/ldb_mdb.h60
-rw-r--r--lib/ldb/ldb_mdb/ldb_mdb_init.c31
-rw-r--r--lib/ldb/ldb_sqlite3/README7
-rw-r--r--lib/ldb/ldb_sqlite3/base160.c154
-rw-r--r--lib/ldb/ldb_sqlite3/ldb_sqlite3.c1958
-rw-r--r--lib/ldb/ldb_sqlite3/schema328
-rw-r--r--lib/ldb/ldb_sqlite3/trees.ps1760
-rw-r--r--lib/ldb/ldb_tdb/ldb_tdb.c593
-rw-r--r--lib/ldb/ldb_tdb/ldb_tdb.h16
-rw-r--r--lib/ldb/ldb_tdb/ldb_tdb_err_map.c84
-rw-r--r--lib/ldb/ldb_tdb/ldb_tdb_init.c59
-rw-r--r--lib/ldb/ldb_tdb/ldb_tdb_wrap.c162
-rw-r--r--lib/ldb/mainpage.dox80
-rw-r--r--lib/ldb/man/ldb.3.xml265
-rw-r--r--lib/ldb/man/ldbadd.1.xml108
-rw-r--r--lib/ldb/man/ldbdel.1.xml108
-rw-r--r--lib/ldb/man/ldbedit.1.xml203
-rw-r--r--lib/ldb/man/ldbmodify.1.xml96
-rw-r--r--lib/ldb/man/ldbrename.1.xml110
-rw-r--r--lib/ldb/man/ldbsearch.1.xml122
-rw-r--r--lib/ldb/modules/asq.c410
-rw-r--r--lib/ldb/modules/paged_searches.c391
-rw-r--r--lib/ldb/modules/rdn_name.c596
-rw-r--r--lib/ldb/modules/skel.c147
-rw-r--r--lib/ldb/modules/sort.c402
-rw-r--r--lib/ldb/nssldb/README.txt34
-rw-r--r--lib/ldb/nssldb/ldb-grp.c429
-rw-r--r--lib/ldb/nssldb/ldb-nss.c395
-rw-r--r--lib/ldb/nssldb/ldb-nss.h84
-rw-r--r--lib/ldb/nssldb/ldb-pwd.c242
-rw-r--r--lib/ldb/pyldb-util.pc.in13
-rw-r--r--lib/ldb/pyldb.c5015
-rw-r--r--lib/ldb/pyldb.h117
-rw-r--r--lib/ldb/pyldb_util.c185
-rw-r--r--lib/ldb/tests/guidindexpackv1.ldbbin0 -> 65536 bytes
-rw-r--r--lib/ldb/tests/init.ldif41
-rwxr-xr-xlib/ldb/tests/init_slapd.sh40
-rwxr-xr-xlib/ldb/tests/kill_slapd.sh12
-rwxr-xr-xlib/ldb/tests/ldapi_url.sh11
-rw-r--r--lib/ldb/tests/ldb_filter_attrs_in_place_test.c940
-rw-r--r--lib/ldb/tests/ldb_filter_attrs_test.c989
-rw-r--r--lib/ldb/tests/ldb_key_value_sub_txn_mdb_test.valgrind97
-rw-r--r--lib/ldb/tests/ldb_key_value_sub_txn_test.c844
-rw-r--r--lib/ldb/tests/ldb_key_value_test.c388
-rw-r--r--lib/ldb/tests/ldb_kv_ops_test.c1819
-rw-r--r--lib/ldb/tests/ldb_kv_ops_test.valgrind97
-rw-r--r--lib/ldb/tests/ldb_lmdb_free_list_test.c661
-rw-r--r--lib/ldb/tests/ldb_lmdb_size_test.c249
-rw-r--r--lib/ldb/tests/ldb_lmdb_test.c590
-rw-r--r--lib/ldb/tests/ldb_match_test.c313
-rw-r--r--lib/ldb/tests/ldb_match_test.valgrind16
-rw-r--r--lib/ldb/tests/ldb_mod_op_test.c4724
-rw-r--r--lib/ldb/tests/ldb_msg.c380
-rw-r--r--lib/ldb/tests/ldb_no_lmdb_test.c159
-rw-r--r--lib/ldb/tests/ldb_parse_test.c172
-rw-r--r--lib/ldb/tests/ldb_tdb_test.c389
-rw-r--r--lib/ldb/tests/lldb_ldap.c105
-rw-r--r--lib/ldb/tests/photo.ldif5
-rwxr-xr-xlib/ldb/tests/python/api.py3858
-rw-r--r--lib/ldb/tests/python/crash.py45
-rwxr-xr-xlib/ldb/tests/python/index.py1454
-rw-r--r--lib/ldb/tests/python/repack.py204
-rw-r--r--lib/ldb/tests/samba4.pngbin0 -> 6239 bytes
-rw-r--r--lib/ldb/tests/sample_module.c122
-rw-r--r--lib/ldb/tests/schema-tests/schema-add-test.ldif66
-rw-r--r--lib/ldb/tests/schema-tests/schema-mod-test-1.ldif5
-rw-r--r--lib/ldb/tests/schema-tests/schema-mod-test-2.ldif5
-rw-r--r--lib/ldb/tests/schema-tests/schema-mod-test-3.ldif5
-rw-r--r--lib/ldb/tests/schema-tests/schema-mod-test-4.ldif5
-rw-r--r--lib/ldb/tests/schema-tests/schema-mod-test-5.ldif5
-rw-r--r--lib/ldb/tests/schema-tests/schema.ldif100
-rw-r--r--lib/ldb/tests/slapd.conf26
-rwxr-xr-xlib/ldb/tests/start_slapd.sh14
-rw-r--r--lib/ldb/tests/test-attribs.ldif6
-rw-r--r--lib/ldb/tests/test-config.ldif67
-rwxr-xr-xlib/ldb/tests/test-controls.sh43
-rw-r--r--lib/ldb/tests/test-default-config.ldif17
-rw-r--r--lib/ldb/tests/test-dup-2.ldif6
-rw-r--r--lib/ldb/tests/test-dup.ldif13
-rwxr-xr-xlib/ldb/tests/test-extended.sh69
-rwxr-xr-xlib/ldb/tests/test-generic.sh158
-rw-r--r--lib/ldb/tests/test-index.ldif7
-rwxr-xr-xlib/ldb/tests/test-ldap.sh54
-rw-r--r--lib/ldb/tests/test-modify-modrdn.ldif12
-rw-r--r--lib/ldb/tests/test-modify-unmet-2.ldif7
-rw-r--r--lib/ldb/tests/test-modify-unmet.ldif15
-rw-r--r--lib/ldb/tests/test-modify.ldif23
-rwxr-xr-xlib/ldb/tests/test-schema.sh33
-rwxr-xr-xlib/ldb/tests/test-soloading.sh31
-rwxr-xr-xlib/ldb/tests/test-sqlite3.sh23
-rw-r--r--lib/ldb/tests/test-tdb-features.sh179
-rwxr-xr-xlib/ldb/tests/test-tdb-subunit.sh7
-rwxr-xr-xlib/ldb/tests/test-tdb.sh38
-rw-r--r--lib/ldb/tests/test-wildcard.ldif5
-rw-r--r--lib/ldb/tests/test-wrong_attributes.ldif3
-rw-r--r--lib/ldb/tests/test.ldif440
-rw-r--r--lib/ldb/tests/test_ldb_dn.c232
-rw-r--r--lib/ldb/tests/test_ldb_qsort.c65
-rw-r--r--lib/ldb/tests/testdata.txt8
-rw-r--r--lib/ldb/tests/testsearch.txt5
-rw-r--r--lib/ldb/tools/cmdline.c766
-rw-r--r--lib/ldb/tools/cmdline.h62
-rw-r--r--lib/ldb/tools/ldbadd.c186
-rw-r--r--lib/ldb/tools/ldbdel.c135
-rw-r--r--lib/ldb/tools/ldbdump.c383
-rw-r--r--lib/ldb/tools/ldbedit.c383
-rw-r--r--lib/ldb/tools/ldbmodify.c190
-rw-r--r--lib/ldb/tools/ldbrename.c85
-rw-r--r--lib/ldb/tools/ldbsearch.c342
-rw-r--r--lib/ldb/tools/ldbtest.c438
-rw-r--r--lib/ldb/tools/ldbutil.c220
-rw-r--r--lib/ldb/tools/ldbutil.h46
-rw-r--r--lib/ldb/web/index.html74
-rw-r--r--lib/ldb/wscript685
-rw-r--r--lib/messaging/messages_dgm.c1790
-rw-r--r--lib/messaging/messages_dgm.h53
-rw-r--r--lib/messaging/messages_dgm_ref.c169
-rw-r--r--lib/messaging/messages_dgm_ref.h38
-rw-r--r--lib/messaging/wscript_build16
-rw-r--r--lib/mscat/dumpmscat.c197
-rw-r--r--lib/mscat/mscat.asn136
-rw-r--r--lib/mscat/mscat.h105
-rw-r--r--lib/mscat/mscat_ctl.c1197
-rw-r--r--lib/mscat/mscat_pkcs7.c292
-rw-r--r--lib/mscat/mscat_private.h27
-rw-r--r--lib/mscat/wscript41
-rw-r--r--lib/param/README86
-rw-r--r--lib/param/loadparm.c3765
-rw-r--r--lib/param/loadparm.h344
-rw-r--r--lib/param/loadparm_server_role.c155
-rw-r--r--lib/param/param.h282
-rw-r--r--lib/param/param_table.c463
-rw-r--r--lib/param/s3_param.h23
-rw-r--r--lib/param/samba-hostconfig.pc.in10
-rw-r--r--lib/param/util.c340
-rw-r--r--lib/param/wscript_build48
-rw-r--r--lib/printer_driver/printer_driver.c1255
-rw-r--r--lib/printer_driver/printer_driver.h33
-rw-r--r--lib/printer_driver/wscript_build6
-rw-r--r--lib/pthreadpool/Makefile9
-rw-r--r--lib/pthreadpool/pthreadpool.c863
-rw-r--r--lib/pthreadpool/pthreadpool.h158
-rw-r--r--lib/pthreadpool/pthreadpool_pipe.c202
-rw-r--r--lib/pthreadpool/pthreadpool_pipe.h39
-rw-r--r--lib/pthreadpool/pthreadpool_sync.c97
-rw-r--r--lib/pthreadpool/pthreadpool_tevent.c428
-rw-r--r--lib/pthreadpool/pthreadpool_tevent.h40
-rw-r--r--lib/pthreadpool/tests.c517
-rw-r--r--lib/pthreadpool/tests_cmocka.c247
-rw-r--r--lib/pthreadpool/wscript_build35
-rw-r--r--lib/replace/.checker_innocent4
-rw-r--r--lib/replace/Makefile64
-rw-r--r--lib/replace/README128
-rw-r--r--lib/replace/closefrom.c138
-rwxr-xr-xlib/replace/configure28
-rw-r--r--lib/replace/dlfcn.c76
-rw-r--r--lib/replace/getaddrinfo.c493
-rw-r--r--lib/replace/getaddrinfo.h91
-rw-r--r--lib/replace/getifaddrs.c383
-rw-r--r--lib/replace/hdr_replace.h2
-rw-r--r--lib/replace/inet_aton.c33
-rw-r--r--lib/replace/inet_ntoa.c39
-rw-r--r--lib/replace/inet_ntop.c193
-rw-r--r--lib/replace/inet_pton.c213
-rw-r--r--lib/replace/poll.c139
-rw-r--r--lib/replace/replace-test.h9
-rw-r--r--lib/replace/replace-testsuite.h10
-rw-r--r--lib/replace/replace.c1145
-rw-r--r--lib/replace/replace.h1112
-rw-r--r--lib/replace/snprintf.c1536
-rw-r--r--lib/replace/socket.c39
-rw-r--r--lib/replace/socketpair.c46
-rw-r--r--lib/replace/strptime.c995
-rw-r--r--lib/replace/system/README4
-rw-r--r--lib/replace/system/capability.h57
-rw-r--r--lib/replace/system/dir.h71
-rw-r--r--lib/replace/system/filesys.h281
-rw-r--r--lib/replace/system/glob.h37
-rw-r--r--lib/replace/system/gssapi.h53
-rw-r--r--lib/replace/system/iconv.h57
-rw-r--r--lib/replace/system/kerberos.h41
-rw-r--r--lib/replace/system/locale.h42
-rw-r--r--lib/replace/system/network.h391
-rw-r--r--lib/replace/system/passwd.h92
-rw-r--r--lib/replace/system/python.h30
-rw-r--r--lib/replace/system/readline.h61
-rw-r--r--lib/replace/system/select.h77
-rw-r--r--lib/replace/system/shmem.h59
-rw-r--r--lib/replace/system/syslog.h70
-rw-r--r--lib/replace/system/terminal.h46
-rw-r--r--lib/replace/system/threads.h72
-rw-r--r--lib/replace/system/time.h106
-rw-r--r--lib/replace/system/wait.h55
-rw-r--r--lib/replace/system/wscript_configure18
-rw-r--r--lib/replace/tests/getifaddrs.c105
-rw-r--r--lib/replace/tests/incoherent_mmap.c83
-rw-r--r--lib/replace/tests/main.c35
-rw-r--r--lib/replace/tests/os2_delete.c135
-rw-r--r--lib/replace/tests/shared_mmap.c71
-rw-r--r--lib/replace/tests/shared_mremap.c51
-rw-r--r--lib/replace/tests/snprintf.c29
-rw-r--r--lib/replace/tests/strptime.c173
-rw-r--r--lib/replace/tests/testsuite.c1227
-rw-r--r--lib/replace/timegm.c78
-rw-r--r--lib/replace/win32_replace.h159
-rw-r--r--lib/replace/wscript1010
-rw-r--r--lib/replace/xattr.c852
-rw-r--r--lib/smbconf/pysmbconf.c813
-rw-r--r--lib/smbconf/pysmbconf.h36
-rw-r--r--lib/smbconf/smbconf.c511
-rw-r--r--lib/smbconf/smbconf.h505
-rw-r--r--lib/smbconf/smbconf_private.h96
-rw-r--r--lib/smbconf/smbconf_txt.c682
-rw-r--r--lib/smbconf/smbconf_txt.h33
-rw-r--r--lib/smbconf/smbconf_util.c151
-rw-r--r--lib/smbconf/wscript_build10
-rw-r--r--lib/socket/interfaces.c435
-rw-r--r--lib/socket/interfaces.h47
-rw-r--r--lib/socket/wscript7
-rw-r--r--lib/socket/wscript_build7
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.0.6.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.0.7.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.0.8.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.0.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.1.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.10.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.11.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.12.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.13.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.14.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.15.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.16.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.2.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.3.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.4.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.5.sigs6
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.6.sigs13
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.7.sigs13
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.8.sigs13
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.1.9.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.2.0.sigs15
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.3.0.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.3.1.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.3.2.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.3.3.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.3.4.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.3.5.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.4.0.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.4.1.sigs16
-rw-r--r--lib/talloc/ABI/pytalloc-util-2.4.2.sigs16
-rw-r--r--lib/talloc/ABI/talloc-2.0.2.sigs62
-rw-r--r--lib/talloc/ABI/talloc-2.0.3.sigs62
-rw-r--r--lib/talloc/ABI/talloc-2.0.4.sigs62
-rw-r--r--lib/talloc/ABI/talloc-2.0.5.sigs62
-rw-r--r--lib/talloc/ABI/talloc-2.0.6.sigs62
-rw-r--r--lib/talloc/ABI/talloc-2.0.7.sigs62
-rw-r--r--lib/talloc/ABI/talloc-2.0.8.sigs63
-rw-r--r--lib/talloc/ABI/talloc-2.1.0.sigs64
-rw-r--r--lib/talloc/ABI/talloc-2.1.1.sigs64
-rw-r--r--lib/talloc/ABI/talloc-2.1.10.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.11.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.12.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.13.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.14.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.15.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.16.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.2.sigs64
-rw-r--r--lib/talloc/ABI/talloc-2.1.3.sigs64
-rw-r--r--lib/talloc/ABI/talloc-2.1.4.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.5.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.6.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.7.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.8.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.1.9.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.2.0.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.3.0.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.3.1.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.3.2.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.3.3.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.3.4.sigs65
-rw-r--r--lib/talloc/ABI/talloc-2.3.5.sigs66
-rw-r--r--lib/talloc/ABI/talloc-2.4.0.sigs66
-rw-r--r--lib/talloc/ABI/talloc-2.4.1.sigs66
-rw-r--r--lib/talloc/ABI/talloc-2.4.2.sigs66
-rw-r--r--lib/talloc/Makefile65
-rw-r--r--lib/talloc/NEWS13
-rw-r--r--lib/talloc/compat/talloc_compat1.c51
-rw-r--r--lib/talloc/compat/talloc_compat1.mk21
-rwxr-xr-xlib/talloc/configure28
-rw-r--r--lib/talloc/doc/context.pngbin0 -> 4715 bytes
-rw-r--r--lib/talloc/doc/context_tree.pngbin0 -> 6158 bytes
-rw-r--r--lib/talloc/doc/mainpage.dox111
-rw-r--r--lib/talloc/doc/stealing.pngbin0 -> 6994 bytes
-rw-r--r--lib/talloc/doc/tutorial_bestpractices.dox192
-rw-r--r--lib/talloc/doc/tutorial_context.dox198
-rw-r--r--lib/talloc/doc/tutorial_debugging.dox116
-rw-r--r--lib/talloc/doc/tutorial_destructors.dox82
-rw-r--r--lib/talloc/doc/tutorial_dts.dox109
-rw-r--r--lib/talloc/doc/tutorial_introduction.dox45
-rw-r--r--lib/talloc/doc/tutorial_pools.dox93
-rw-r--r--lib/talloc/doc/tutorial_stealing.dox55
-rw-r--r--lib/talloc/doc/tutorial_threads.dox203
-rw-r--r--lib/talloc/doxy.config1807
-rw-r--r--lib/talloc/man/talloc.3.xml814
-rw-r--r--lib/talloc/pytalloc-util.pc.in11
-rw-r--r--lib/talloc/pytalloc.c269
-rw-r--r--lib/talloc/pytalloc.h87
-rw-r--r--lib/talloc/pytalloc_guide.txt252
-rw-r--r--lib/talloc/pytalloc_private.h26
-rw-r--r--lib/talloc/pytalloc_util.c334
-rw-r--r--lib/talloc/talloc.c3070
-rw-r--r--lib/talloc/talloc.h1972
-rw-r--r--lib/talloc/talloc.pc.in11
-rw-r--r--lib/talloc/talloc_guide.txt768
-rw-r--r--lib/talloc/talloc_testsuite.h7
-rwxr-xr-xlib/talloc/test_magic_differs.sh16
-rw-r--r--lib/talloc/test_magic_differs_helper.c12
-rw-r--r--lib/talloc/test_pytalloc.c230
-rw-r--r--lib/talloc/test_pytalloc.py189
-rw-r--r--lib/talloc/testsuite.c2288
-rw-r--r--lib/talloc/testsuite_main.c36
-rw-r--r--lib/talloc/web/index.html51
-rw-r--r--lib/talloc/wscript192
-rw-r--r--lib/tdb/ABI/tdb-1.2.1.sigs95
-rw-r--r--lib/tdb/ABI/tdb-1.2.10.sigs66
-rw-r--r--lib/tdb/ABI/tdb-1.2.11.sigs67
-rw-r--r--lib/tdb/ABI/tdb-1.2.12.sigs67
-rw-r--r--lib/tdb/ABI/tdb-1.2.13.sigs67
-rw-r--r--lib/tdb/ABI/tdb-1.2.2.sigs60
-rw-r--r--lib/tdb/ABI/tdb-1.2.3.sigs60
-rw-r--r--lib/tdb/ABI/tdb-1.2.4.sigs60
-rw-r--r--lib/tdb/ABI/tdb-1.2.5.sigs61
-rw-r--r--lib/tdb/ABI/tdb-1.2.6.sigs61
-rw-r--r--lib/tdb/ABI/tdb-1.2.7.sigs61
-rw-r--r--lib/tdb/ABI/tdb-1.2.8.sigs61
-rw-r--r--lib/tdb/ABI/tdb-1.2.9.sigs62
-rw-r--r--lib/tdb/ABI/tdb-1.3.0.sigs68
-rw-r--r--lib/tdb/ABI/tdb-1.3.1.sigs68
-rw-r--r--lib/tdb/ABI/tdb-1.3.10.sigs69
-rw-r--r--lib/tdb/ABI/tdb-1.3.11.sigs70
-rw-r--r--lib/tdb/ABI/tdb-1.3.12.sigs70
-rw-r--r--lib/tdb/ABI/tdb-1.3.13.sigs70
-rw-r--r--lib/tdb/ABI/tdb-1.3.14.sigs71
-rw-r--r--lib/tdb/ABI/tdb-1.3.15.sigs71
-rw-r--r--lib/tdb/ABI/tdb-1.3.16.sigs71
-rw-r--r--lib/tdb/ABI/tdb-1.3.17.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.3.18.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.3.2.sigs68
-rw-r--r--lib/tdb/ABI/tdb-1.3.3.sigs68
-rw-r--r--lib/tdb/ABI/tdb-1.3.4.sigs68
-rw-r--r--lib/tdb/ABI/tdb-1.3.5.sigs69
-rw-r--r--lib/tdb/ABI/tdb-1.3.6.sigs69
-rw-r--r--lib/tdb/ABI/tdb-1.3.7.sigs69
-rw-r--r--lib/tdb/ABI/tdb-1.3.8.sigs69
-rw-r--r--lib/tdb/ABI/tdb-1.3.9.sigs69
-rw-r--r--lib/tdb/ABI/tdb-1.4.0.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.1.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.10.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.2.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.3.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.4.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.5.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.6.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.7.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.8.sigs73
-rw-r--r--lib/tdb/ABI/tdb-1.4.9.sigs73
-rw-r--r--lib/tdb/Makefile65
-rw-r--r--lib/tdb/_tdb_text.py137
-rw-r--r--lib/tdb/common/check.c489
-rw-r--r--lib/tdb/common/dump.c149
-rw-r--r--lib/tdb/common/error.c74
-rw-r--r--lib/tdb/common/freelist.c747
-rw-r--r--lib/tdb/common/freelistcheck.c107
-rw-r--r--lib/tdb/common/hash.c345
-rw-r--r--lib/tdb/common/io.c806
-rw-r--r--lib/tdb/common/lock.c1033
-rw-r--r--lib/tdb/common/mutex.c1078
-rw-r--r--lib/tdb/common/open.c968
-rw-r--r--lib/tdb/common/rescue.c351
-rw-r--r--lib/tdb/common/summary.c219
-rw-r--r--lib/tdb/common/tdb.c1348
-rw-r--r--lib/tdb/common/tdb_private.h370
-rw-r--r--lib/tdb/common/transaction.c1388
-rw-r--r--lib/tdb/common/traverse.c510
-rwxr-xr-xlib/tdb/configure28
-rw-r--r--lib/tdb/docs/README273
-rw-r--r--lib/tdb/docs/mainpage.dox61
-rw-r--r--lib/tdb/docs/mutex.txt136
-rw-r--r--lib/tdb/docs/tdb.magic10
-rw-r--r--lib/tdb/docs/tracing.txt46
-rw-r--r--lib/tdb/doxy.config1697
-rw-r--r--lib/tdb/include/tdb.h1038
-rw-r--r--lib/tdb/man/tdbbackup.8.xml157
-rw-r--r--lib/tdb/man/tdbdump.8.xml93
-rw-r--r--lib/tdb/man/tdbrestore.8.xml67
-rw-r--r--lib/tdb/man/tdbtool.8.xml275
-rw-r--r--lib/tdb/pytdb.c830
-rw-r--r--lib/tdb/python/tdbdump.py17
-rw-r--r--lib/tdb/python/tests/simple.py315
-rw-r--r--lib/tdb/tdb.pc.in11
-rw-r--r--lib/tdb/test/circular_chain.tdbbin0 -> 272 bytes
-rw-r--r--lib/tdb/test/circular_freelist.tdbbin0 -> 400 bytes
-rw-r--r--lib/tdb/test/external-agent.c224
-rw-r--r--lib/tdb/test/external-agent.h44
-rw-r--r--lib/tdb/test/jenkins-be-hash.tdbbin0 -> 696 bytes
-rw-r--r--lib/tdb/test/jenkins-le-hash.tdbbin0 -> 696 bytes
-rw-r--r--lib/tdb/test/lock-tracking.c157
-rw-r--r--lib/tdb/test/lock-tracking.h25
-rw-r--r--lib/tdb/test/logging.c33
-rw-r--r--lib/tdb/test/logging.h11
-rw-r--r--lib/tdb/test/old-nohash-be.tdbbin0 -> 696 bytes
-rw-r--r--lib/tdb/test/old-nohash-le.tdbbin0 -> 696 bytes
-rw-r--r--lib/tdb/test/run-3G-file.c145
-rw-r--r--lib/tdb/test/run-allrecord-traverse-deadlock.c203
-rw-r--r--lib/tdb/test/run-bad-tdb-header.c59
-rw-r--r--lib/tdb/test/run-check.c65
-rw-r--r--lib/tdb/test/run-circular-chain.c42
-rw-r--r--lib/tdb/test/run-circular-freelist.c50
-rw-r--r--lib/tdb/test/run-corrupt.c132
-rw-r--r--lib/tdb/test/run-die-during-transaction.c232
-rw-r--r--lib/tdb/test/run-endian.c64
-rw-r--r--lib/tdb/test/run-fcntl-deadlock.c202
-rw-r--r--lib/tdb/test/run-incompatible.c188
-rw-r--r--lib/tdb/test/run-marklock-deadlock.c278
-rw-r--r--lib/tdb/test/run-mutex-allrecord-bench.c82
-rw-r--r--lib/tdb/test/run-mutex-allrecord-block.c120
-rw-r--r--lib/tdb/test/run-mutex-allrecord-trylock.c113
-rw-r--r--lib/tdb/test/run-mutex-die.c269
-rw-r--r--lib/tdb/test/run-mutex-openflags2.c146
-rw-r--r--lib/tdb/test/run-mutex-transaction1.c236
-rw-r--r--lib/tdb/test/run-mutex-trylock.c122
-rw-r--r--lib/tdb/test/run-mutex1.c138
-rw-r--r--lib/tdb/test/run-nested-transactions.c79
-rw-r--r--lib/tdb/test/run-nested-traverse.c111
-rw-r--r--lib/tdb/test/run-no-lock-during-traverse.c114
-rw-r--r--lib/tdb/test/run-oldhash.c50
-rw-r--r--lib/tdb/test/run-open-during-transaction.c183
-rw-r--r--lib/tdb/test/run-rdlock-upgrade.c166
-rw-r--r--lib/tdb/test/run-readonly-check.c53
-rw-r--r--lib/tdb/test/run-rescue-find_entry.c51
-rw-r--r--lib/tdb/test/run-rescue.c127
-rw-r--r--lib/tdb/test/run-rwlock-check.c46
-rw-r--r--lib/tdb/test/run-summary.c65
-rw-r--r--lib/tdb/test/run-transaction-expand.c125
-rw-r--r--lib/tdb/test/run-traverse-chain.c94
-rw-r--r--lib/tdb/test/run-traverse-in-transaction.c90
-rw-r--r--lib/tdb/test/run-wronghash-fail.c121
-rw-r--r--lib/tdb/test/run-zero-append.c41
-rw-r--r--lib/tdb/test/run.c50
-rw-r--r--lib/tdb/test/rwlock-be.tdbbin0 -> 696 bytes
-rw-r--r--lib/tdb/test/rwlock-le.tdbbin0 -> 696 bytes
-rw-r--r--lib/tdb/test/sample_tdb.tdbbin0 -> 8192 bytes
-rw-r--r--lib/tdb/test/tap-interface.h58
-rw-r--r--lib/tdb/test/tap-to-subunit.h155
-rw-r--r--lib/tdb/test/tdb.corruptbin0 -> 192512 bytes
-rwxr-xr-xlib/tdb/test/test_tdbbackup.sh57
-rw-r--r--lib/tdb/tools/tdbbackup.c370
-rw-r--r--lib/tdb/tools/tdbdump.c181
-rw-r--r--lib/tdb/tools/tdbrestore.c202
-rw-r--r--lib/tdb/tools/tdbtest.c290
-rw-r--r--lib/tdb/tools/tdbtool.c924
-rw-r--r--lib/tdb/tools/tdbtortseq.c123
-rw-r--r--lib/tdb/tools/tdbtorture.c500
-rw-r--r--lib/tdb/web/index.html48
-rw-r--r--lib/tdb/wscript264
-rw-r--r--lib/tdb_wrap/tdb_wrap.c183
-rw-r--r--lib/tdb_wrap/tdb_wrap.h43
-rw-r--r--lib/tdb_wrap/wscript_build8
-rw-r--r--lib/tdr/TODO1
-rw-r--r--lib/tdr/tdr.c409
-rw-r--r--lib/tdr/tdr.h100
-rw-r--r--lib/tdr/testsuite.c186
-rw-r--r--lib/tdr/wscript_build9
-rw-r--r--lib/tevent/ABI/tevent-0.10.0.sigs126
-rw-r--r--lib/tevent/ABI/tevent-0.10.1.sigs126
-rw-r--r--lib/tevent/ABI/tevent-0.10.2.sigs126
-rw-r--r--lib/tevent/ABI/tevent-0.11.0.sigs146
-rw-r--r--lib/tevent/ABI/tevent-0.12.0.sigs151
-rw-r--r--lib/tevent/ABI/tevent-0.12.1.sigs151
-rw-r--r--lib/tevent/ABI/tevent-0.13.0.sigs152
-rw-r--r--lib/tevent/ABI/tevent-0.14.0.sigs157
-rw-r--r--lib/tevent/ABI/tevent-0.14.1.sigs157
-rw-r--r--lib/tevent/ABI/tevent-0.15.0.sigs167
-rw-r--r--lib/tevent/ABI/tevent-0.16.0.sigs167
-rw-r--r--lib/tevent/ABI/tevent-0.16.1.sigs167
-rw-r--r--lib/tevent/ABI/tevent-0.9.10.sigs73
-rw-r--r--lib/tevent/ABI/tevent-0.9.11.sigs73
-rw-r--r--lib/tevent/ABI/tevent-0.9.12.sigs74
-rw-r--r--lib/tevent/ABI/tevent-0.9.13.sigs75
-rw-r--r--lib/tevent/ABI/tevent-0.9.14.sigs78
-rw-r--r--lib/tevent/ABI/tevent-0.9.15.sigs78
-rw-r--r--lib/tevent/ABI/tevent-0.9.16.sigs82
-rw-r--r--lib/tevent/ABI/tevent-0.9.17.sigs82
-rw-r--r--lib/tevent/ABI/tevent-0.9.18.sigs83
-rw-r--r--lib/tevent/ABI/tevent-0.9.19.sigs83
-rw-r--r--lib/tevent/ABI/tevent-0.9.20.sigs87
-rw-r--r--lib/tevent/ABI/tevent-0.9.21.sigs88
-rw-r--r--lib/tevent/ABI/tevent-0.9.22.sigs88
-rw-r--r--lib/tevent/ABI/tevent-0.9.23.sigs88
-rw-r--r--lib/tevent/ABI/tevent-0.9.24.sigs88
-rw-r--r--lib/tevent/ABI/tevent-0.9.25.sigs88
-rw-r--r--lib/tevent/ABI/tevent-0.9.26.sigs90
-rw-r--r--lib/tevent/ABI/tevent-0.9.27.sigs90
-rw-r--r--lib/tevent/ABI/tevent-0.9.28.sigs90
-rw-r--r--lib/tevent/ABI/tevent-0.9.29.sigs90
-rw-r--r--lib/tevent/ABI/tevent-0.9.30.sigs96
-rw-r--r--lib/tevent/ABI/tevent-0.9.31.sigs99
-rw-r--r--lib/tevent/ABI/tevent-0.9.32.sigs99
-rw-r--r--lib/tevent/ABI/tevent-0.9.33.sigs99
-rw-r--r--lib/tevent/ABI/tevent-0.9.34.sigs99
-rw-r--r--lib/tevent/ABI/tevent-0.9.35.sigs99
-rw-r--r--lib/tevent/ABI/tevent-0.9.36.sigs100
-rw-r--r--lib/tevent/ABI/tevent-0.9.37.sigs126
-rw-r--r--lib/tevent/ABI/tevent-0.9.38.sigs126
-rw-r--r--lib/tevent/ABI/tevent-0.9.39.sigs126
-rw-r--r--lib/tevent/ABI/tevent-0.9.9.sigs73
-rw-r--r--lib/tevent/Makefile52
-rw-r--r--lib/tevent/bindings.py116
-rwxr-xr-xlib/tevent/configure28
-rw-r--r--lib/tevent/doc/img/tevent_context_stucture.pngbin0 -> 21888 bytes
-rw-r--r--lib/tevent/doc/img/tevent_subrequest.pngbin0 -> 22453 bytes
-rw-r--r--lib/tevent/doc/mainpage.dox47
-rw-r--r--lib/tevent/doc/tevent_context.dox75
-rw-r--r--lib/tevent/doc/tevent_data.dox137
-rw-r--r--lib/tevent/doc/tevent_events.dox341
-rw-r--r--lib/tevent/doc/tevent_queue.dox275
-rw-r--r--lib/tevent/doc/tevent_request.dox189
-rw-r--r--lib/tevent/doc/tevent_thread.dox322
-rw-r--r--lib/tevent/doc/tevent_tutorial.dox22
-rw-r--r--lib/tevent/doc/tutorials.dox43
-rw-r--r--lib/tevent/doxy.config1908
-rw-r--r--lib/tevent/echo_server.c667
-rw-r--r--lib/tevent/pytevent.c798
-rw-r--r--lib/tevent/test_req.c288
-rw-r--r--lib/tevent/tests/test_tevent_tag.c253
-rw-r--r--lib/tevent/tests/test_tevent_trace.c1324
-rw-r--r--lib/tevent/testsuite.c2651
-rw-r--r--lib/tevent/tevent.c1091
-rw-r--r--lib/tevent/tevent.h3103
-rw-r--r--lib/tevent/tevent.pc.in12
-rw-r--r--lib/tevent/tevent.py28
-rw-r--r--lib/tevent/tevent_debug.c371
-rw-r--r--lib/tevent/tevent_dlinklist.h198
-rw-r--r--lib/tevent/tevent_epoll.c945
-rw-r--r--lib/tevent/tevent_fd.c215
-rw-r--r--lib/tevent/tevent_immediate.c261
-rw-r--r--lib/tevent/tevent_internal.h950
-rw-r--r--lib/tevent/tevent_poll.c695
-rw-r--r--lib/tevent/tevent_queue.c462
-rw-r--r--lib/tevent/tevent_req.c642
-rw-r--r--lib/tevent/tevent_signal.c539
-rw-r--r--lib/tevent/tevent_standard.c238
-rw-r--r--lib/tevent/tevent_threads.c601
-rw-r--r--lib/tevent/tevent_timed.c477
-rw-r--r--lib/tevent/tevent_util.c77
-rw-r--r--lib/tevent/tevent_util.h28
-rw-r--r--lib/tevent/tevent_wakeup.c67
-rw-r--r--lib/tevent/tevent_wrapper.c569
-rw-r--r--lib/tevent/wscript172
-rw-r--r--lib/texpect/texpect.c470
-rw-r--r--lib/texpect/wscript10
-rw-r--r--lib/torture/simple.c85
-rw-r--r--lib/torture/subunit.c143
-rw-r--r--lib/torture/torture.c839
-rw-r--r--lib/torture/torture.h874
-rw-r--r--lib/torture/wscript_build8
-rw-r--r--lib/tsocket/doxy.config1538
-rw-r--r--lib/tsocket/tests/socketpair_tcp.c89
-rw-r--r--lib/tsocket/tests/socketpair_tcp.h29
-rw-r--r--lib/tsocket/tests/test_bsd_addr.c369
-rw-r--r--lib/tsocket/tests/test_tstream.c517
-rw-r--r--lib/tsocket/tsocket.c812
-rw-r--r--lib/tsocket/tsocket.h1319
-rw-r--r--lib/tsocket/tsocket_bsd.c2845
-rw-r--r--lib/tsocket/tsocket_guide.txt481
-rw-r--r--lib/tsocket/tsocket_helpers.c559
-rw-r--r--lib/tsocket/tsocket_internal.h144
-rw-r--r--lib/tsocket/wscript36
-rw-r--r--lib/util/Doxyfile24
-rw-r--r--lib/util/README6
-rw-r--r--lib/util/access.c377
-rw-r--r--lib/util/access.h28
-rw-r--r--lib/util/asn1.c1176
-rw-r--r--lib/util/asn1.h110
-rw-r--r--lib/util/attr.h105
-rw-r--r--lib/util/base64.c169
-rw-r--r--lib/util/base64.h52
-rw-r--r--lib/util/become_daemon.c151
-rw-r--r--lib/util/become_daemon.h89
-rw-r--r--lib/util/binsearch.h121
-rw-r--r--lib/util/bitmap.c144
-rw-r--r--lib/util/bitmap.h29
-rw-r--r--lib/util/blocking.c76
-rw-r--r--lib/util/blocking.h34
-rw-r--r--lib/util/bytearray.h124
-rw-r--r--lib/util/byteorder.h169
-rw-r--r--lib/util/charset/charset.h299
-rw-r--r--lib/util/charset/charset_macosxfs.c605
-rw-r--r--lib/util/charset/charset_proto.h36
-rw-r--r--lib/util/charset/codepoints.c16850
-rw-r--r--lib/util/charset/convert_string.c556
-rw-r--r--lib/util/charset/iconv.c1196
-rw-r--r--lib/util/charset/pull_push.c160
-rw-r--r--lib/util/charset/tests/charset.c342
-rw-r--r--lib/util/charset/tests/convert_string.c2196
-rw-r--r--lib/util/charset/tests/iconv.c495
-rw-r--r--lib/util/charset/tests/util_unistr.c166
-rw-r--r--lib/util/charset/util_str.c608
-rw-r--r--lib/util/charset/util_unistr.c644
-rw-r--r--lib/util/charset/util_unistr_w.c255
-rw-r--r--lib/util/charset/weird.c142
-rw-r--r--lib/util/charset/wscript_build22
-rw-r--r--lib/util/charset/wscript_configure51
-rw-r--r--lib/util/charset_compat.h9
-rw-r--r--lib/util/close_low_fd.c75
-rw-r--r--lib/util/close_low_fd.h28
-rw-r--r--lib/util/data_blob.c298
-rw-r--r--lib/util/data_blob.h144
-rw-r--r--lib/util/debug-classes/debug-classname-table.c62
-rw-r--r--lib/util/debug.c1978
-rw-r--r--lib/util/debug.h396
-rw-r--r--lib/util/debug_s3.c155
-rw-r--r--lib/util/debug_s3.h26
-rw-r--r--lib/util/discard.h51
-rw-r--r--lib/util/dlinklist.h198
-rw-r--r--lib/util/dprintf.c80
-rw-r--r--lib/util/fault.c318
-rw-r--r--lib/util/fault.h59
-rw-r--r--lib/util/fsusage.c160
-rw-r--r--lib/util/genrand.c87
-rw-r--r--lib/util/genrand.h49
-rw-r--r--lib/util/genrand_util.c531
-rw-r--r--lib/util/getpass.c230
-rw-r--r--lib/util/gpfswrap.c296
-rw-r--r--lib/util/gpfswrap.h57
-rw-r--r--lib/util/idtree.c395
-rw-r--r--lib/util/idtree.h63
-rw-r--r--lib/util/idtree_random.c68
-rw-r--r--lib/util/idtree_random.h41
-rw-r--r--lib/util/iov_buf.c43
-rw-r--r--lib/util/iov_buf.h102
-rw-r--r--lib/util/mainpage.dox11
-rw-r--r--lib/util/memcache.c467
-rw-r--r--lib/util/memcache.h119
-rw-r--r--lib/util/memory.h129
-rw-r--r--lib/util/mkdir_p.c70
-rw-r--r--lib/util/mkdir_p.h21
-rw-r--r--lib/util/modules.c320
-rw-r--r--lib/util/ms_fnmatch.c249
-rw-r--r--lib/util/msghdr.c273
-rw-r--r--lib/util/msghdr.h42
-rw-r--r--lib/util/params.c116
-rw-r--r--lib/util/pidfile.c238
-rw-r--r--lib/util/pidfile.h85
-rw-r--r--lib/util/rbtree.c429
-rw-r--r--lib/util/rbtree.h132
-rw-r--r--lib/util/rfc1738.c198
-rw-r--r--lib/util/safe_string.h64
-rw-r--r--lib/util/samba-util.pc.in11
-rw-r--r--lib/util/samba_modules.h61
-rw-r--r--lib/util/samba_util.h708
-rw-r--r--lib/util/select.c61
-rw-r--r--lib/util/select.h29
-rw-r--r--lib/util/server_id.c229
-rw-r--r--lib/util/server_id.h57
-rw-r--r--lib/util/server_id_db.c355
-rw-r--r--lib/util/server_id_db.h50
-rw-r--r--lib/util/setid.c249
-rw-r--r--lib/util/setid.h43
-rw-r--r--lib/util/signal.c146
-rw-r--r--lib/util/signal.h50
-rw-r--r--lib/util/smb_strtox.c177
-rw-r--r--lib/util/smb_strtox.h40
-rw-r--r--lib/util/smb_threads.c206
-rw-r--r--lib/util/smb_threads.h137
-rw-r--r--lib/util/smb_threads_internal.h74
-rw-r--r--lib/util/stable_sort.c250
-rw-r--r--lib/util/stable_sort.h46
-rw-r--r--lib/util/string_wrappers.h99
-rw-r--r--lib/util/strv.c191
-rw-r--r--lib/util/strv.h37
-rw-r--r--lib/util/strv_util.c61
-rw-r--r--lib/util/strv_util.h30
-rw-r--r--lib/util/substitute.c280
-rw-r--r--lib/util/substitute.h64
-rw-r--r--lib/util/sys_popen.c177
-rw-r--r--lib/util/sys_popen.h26
-rw-r--r--lib/util/sys_rw.c295
-rw-r--r--lib/util/sys_rw.h45
-rw-r--r--lib/util/sys_rw_data.c117
-rw-r--r--lib/util/sys_rw_data.h34
-rw-r--r--lib/util/system.c65
-rw-r--r--lib/util/talloc_keep_secret.c67
-rw-r--r--lib/util/talloc_keep_secret.h42
-rw-r--r--lib/util/talloc_report.c184
-rw-r--r--lib/util/talloc_report.h27
-rw-r--r--lib/util/talloc_report_printf.c134
-rw-r--r--lib/util/talloc_report_printf.h29
-rw-r--r--lib/util/talloc_stack.c259
-rw-r--r--lib/util/talloc_stack.h66
-rw-r--r--lib/util/tests/README22
-rw-r--r--lib/util/tests/anonymous_shared.c70
-rw-r--r--lib/util/tests/asn1_tests.c383
-rw-r--r--lib/util/tests/binsearch.c173
-rw-r--r--lib/util/tests/data_blob.c172
-rw-r--r--lib/util/tests/dlinklist.c131
-rw-r--r--lib/util/tests/file.c291
-rw-r--r--lib/util/tests/genrand.c61
-rw-r--r--lib/util/tests/genrandperf.c39
-rw-r--r--lib/util/tests/idtree.c123
-rw-r--r--lib/util/tests/rfc1738.c411
-rw-r--r--lib/util/tests/str.c180
-rw-r--r--lib/util/tests/strlist.c558
-rw-r--r--lib/util/tests/strv.c201
-rw-r--r--lib/util/tests/strv_util.c150
-rw-r--r--lib/util/tests/test_bytearray.c435
-rw-r--r--lib/util/tests/test_byteorder.c435
-rw-r--r--lib/util/tests/test_byteorder_verify.c273
-rw-r--r--lib/util/tests/test_logging.c146
-rw-r--r--lib/util/tests/test_memcache.c161
-rw-r--r--lib/util/tests/test_ms_fnmatch.c114
-rw-r--r--lib/util/tests/test_stable_sort.c317
-rw-r--r--lib/util/tests/test_sys_rw.c178
-rw-r--r--lib/util/tests/test_talloc_keep_secret.c94
-rw-r--r--lib/util/tests/test_util.c344
-rw-r--r--lib/util/tests/test_util_paths.c127
-rw-r--r--lib/util/tests/tfork-drd.supp14
-rw-r--r--lib/util/tests/tfork-helgrind.supp32
-rw-r--r--lib/util/tests/tfork.c855
-rw-r--r--lib/util/tests/time.c151
-rw-r--r--lib/util/tests/util.c652
-rw-r--r--lib/util/tests/util_str_escape.c90
-rw-r--r--lib/util/tevent_debug.c116
-rw-r--r--lib/util/tevent_ntstatus.c114
-rw-r--r--lib/util/tevent_ntstatus.h47
-rw-r--r--lib/util/tevent_req_profile.c506
-rw-r--r--lib/util/tevent_req_profile.h46
-rw-r--r--lib/util/tevent_unix.c73
-rw-r--r--lib/util/tevent_unix.h34
-rw-r--r--lib/util/tevent_werror.c94
-rw-r--r--lib/util/tevent_werror.h46
-rw-r--r--lib/util/tfork.c944
-rw-r--r--lib/util/tfork.h111
-rw-r--r--lib/util/tftw.c129
-rw-r--r--lib/util/tftw.h32
-rw-r--r--lib/util/time.c1494
-rw-r--r--lib/util/time.h404
-rw-r--r--lib/util/time_basic.c99
-rw-r--r--lib/util/time_basic.h49
-rw-r--r--lib/util/tini.c320
-rw-r--r--lib/util/tini.h45
-rw-r--r--lib/util/tiniparser.c390
-rw-r--r--lib/util/tiniparser.h56
-rw-r--r--lib/util/tsort.h40
-rw-r--r--lib/util/unix_match.c183
-rw-r--r--lib/util/unix_match.h25
-rw-r--r--lib/util/unix_privs.c92
-rw-r--r--lib/util/util.c1335
-rw-r--r--lib/util/util.h94
-rw-r--r--lib/util/util_file.c498
-rw-r--r--lib/util/util_id.c89
-rw-r--r--lib/util/util_ldb.c114
-rw-r--r--lib/util/util_ldb.h50
-rw-r--r--lib/util/util_net.c1240
-rw-r--r--lib/util/util_net.h145
-rw-r--r--lib/util/util_paths.c170
-rw-r--r--lib/util/util_paths.h63
-rw-r--r--lib/util/util_process.c101
-rw-r--r--lib/util/util_process.h84
-rw-r--r--lib/util/util_pw.c99
-rw-r--r--lib/util/util_pw.h32
-rw-r--r--lib/util/util_runcmd.c379
-rw-r--r--lib/util/util_str.c307
-rw-r--r--lib/util/util_str_common.c154
-rw-r--r--lib/util/util_str_escape.c127
-rw-r--r--lib/util/util_str_escape.h27
-rw-r--r--lib/util/util_str_hex.c69
-rw-r--r--lib/util/util_str_hex.h5
-rw-r--r--lib/util/util_strlist.c561
-rw-r--r--lib/util/util_strlist.h156
-rw-r--r--lib/util/util_strlist_v3.c128
-rw-r--r--lib/util/util_tdb.c525
-rw-r--r--lib/util/util_tdb.h125
-rw-r--r--lib/util/wscript32
-rw-r--r--lib/util/wscript_build415
-rw-r--r--lib/util/wscript_configure189
-rw-r--r--lib/wscript_build8
1125 files changed, 306720 insertions, 0 deletions
diff --git a/lib/README b/lib/README
new file mode 100644
index 0000000..c3e1117
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,9 @@
+compression - Various compression algorithms (MSZIP, lzxpress)
+popt - Command-line option parsing library
+replace - Provides replacements for standard (POSIX, C99) functions
+ not provided by the host platform.
+subunit - Utilities and bindings for working with the Subunit test result
+ reporting protocol.
+talloc - Hierarchical pool based memory allocator
+tdb - Simple but fast key/value database library, supporting multiple writers
+torture - Simple unit testing helper library
diff --git a/lib/addns/dns.h b/lib/addns/dns.h
new file mode 100644
index 0000000..2c311e7
--- /dev/null
+++ b/lib/addns/dns.h
@@ -0,0 +1,366 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DNS_H
+#define _DNS_H
+
+#include "../replace/replace.h"
+#include "system/network.h"
+#include "system/kerberos.h"
+#include "system/gssapi.h"
+
+/* make sure we have included the correct config.h */
+#ifndef NO_CONFIG_H /* for some tests */
+#ifndef CONFIG_H_IS_FROM_SAMBA
+#error "make sure you have removed all config.h files from standalone builds!"
+#error "the included config.h isn't from samba!"
+#endif
+#endif /* NO_CONFIG_H */
+
+#include <fcntl.h>
+#include <time.h>
+#include <netdb.h>
+
+#include <talloc.h>
+
+#include "dnserr.h"
+
+
+#define DNS_TCP 1
+#define DNS_UDP 2
+
+#define DNS_OPCODE_UPDATE 1
+
+/* DNS Class Types */
+
+#define DNS_CLASS_IN 1
+#define DNS_CLASS_ANY 255
+#define DNS_CLASS_NONE 254
+
+/* DNS RR Types */
+
+#define DNS_RR_A 1
+
+#define DNS_TCP_PORT 53
+#define DNS_UDP_PORT 53
+
+#define QTYPE_A 1
+#define QTYPE_NS 2
+#define QTYPE_MD 3
+#define QTYPE_CNAME 5
+#define QTYPE_SOA 6
+#define QTYPE_AAAA 28
+#define QTYPE_ANY 255
+#define QTYPE_TKEY 249
+#define QTYPE_TSIG 250
+
+/*
+MF 4 a mail forwarder (Obsolete - use MX)
+CNAME 5 the canonical name for an alias
+SOA 6 marks the start of a zone of authority
+MB 7 a mailbox domain name (EXPERIMENTAL)
+MG 8 a mail group member (EXPERIMENTAL)
+MR 9 a mail rename domain name (EXPERIMENTAL)
+NULL 10 a null RR (EXPERIMENTAL)
+WKS 11 a well known service description
+PTR 12 a domain name pointer
+HINFO 13 host information
+MINFO 14 mailbox or mail list information
+MX 15 mail exchange
+TXT 16 text strings
+*/
+
+#define QR_QUERY 0x0000
+#define QR_RESPONSE 0x0001
+
+#define OPCODE_QUERY 0x00
+#define OPCODE_IQUERY 0x01
+#define OPCODE_STATUS 0x02
+
+#define AA 1
+
+#define RECURSION_DESIRED 0x01
+
+#define RCODE_NOERROR 0
+#define RCODE_FORMATERROR 1
+#define RCODE_SERVER_FAILURE 2
+#define RCODE_NAME_ERROR 3
+#define RCODE_NOTIMPLEMENTED 4
+#define RCODE_REFUSED 5
+
+#define SENDBUFFER_SIZE 65536
+#define RECVBUFFER_SIZE 65536
+
+/*
+ * TKEY Modes from rfc2930
+ */
+
+#define DNS_TKEY_MODE_SERVER 1
+#define DNS_TKEY_MODE_DH 2
+#define DNS_TKEY_MODE_GSSAPI 3
+#define DNS_TKEY_MODE_RESOLVER 4
+#define DNS_TKEY_MODE_DELETE 5
+
+
+#define DNS_ONE_DAY_IN_SECS 86400
+#define DNS_TEN_HOURS_IN_SECS 36000
+
+#define SOCKET_ERROR -1
+#define INVALID_SOCKET -1
+
+#define DNS_NO_ERROR 0
+#define DNS_FORMAT_ERROR 1
+#define DNS_SERVER_FAILURE 2
+#define DNS_NAME_ERROR 3
+#define DNS_NOT_IMPLEMENTED 4
+#define DNS_REFUSED 5
+
+typedef long HANDLE;
+
+enum dns_ServerType { DNS_SRV_ANY, DNS_SRV_WIN2000, DNS_SRV_WIN2003 };
+
+struct dns_domain_label {
+ struct dns_domain_label *next;
+ char *label;
+ size_t len;
+};
+
+struct dns_domain_name {
+ struct dns_domain_label *pLabelList;
+};
+
+struct dns_question {
+ struct dns_domain_name *name;
+ uint16_t q_type;
+ uint16_t q_class;
+};
+
+/*
+ * Before changing the definition of dns_zone, look
+ * dns_marshall_update_request(), we rely on this being the same as
+ * dns_question right now.
+ */
+
+struct dns_zone {
+ struct dns_domain_name *name;
+ uint16_t z_type;
+ uint16_t z_class;
+};
+
+struct dns_rrec {
+ struct dns_domain_name *name;
+ uint16_t type;
+ uint16_t r_class;
+ uint32_t ttl;
+ uint16_t data_length;
+ uint8_t *data;
+};
+
+struct dns_tkey_record {
+ struct dns_domain_name *algorithm;
+ time_t inception;
+ time_t expiration;
+ uint16_t mode;
+ uint16_t error;
+ uint16_t key_length;
+ uint8_t *key;
+};
+
+struct dns_request {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t num_questions;
+ uint16_t num_answers;
+ uint16_t num_auths;
+ uint16_t num_additionals;
+ struct dns_question **questions;
+ struct dns_rrec **answers;
+ struct dns_rrec **auths;
+ struct dns_rrec **additional;
+};
+
+/*
+ * Before changing the definition of dns_update_request, look
+ * dns_marshall_update_request(), we rely on this being the same as
+ * dns_request right now.
+ */
+
+struct dns_update_request {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t num_zones;
+ uint16_t num_preqs;
+ uint16_t num_updates;
+ uint16_t num_additionals;
+ struct dns_zone **zones;
+ struct dns_rrec **preqs;
+ struct dns_rrec **updates;
+ struct dns_rrec **additional;
+};
+
+struct dns_connection {
+ int32_t hType;
+ int s;
+ struct sockaddr_storage RecvAddr;
+};
+
+struct dns_buffer {
+ uint8_t *data;
+ size_t size;
+ size_t offset;
+ DNS_ERROR error;
+};
+
+/* from dnsutils.c */
+
+DNS_ERROR dns_domain_name_from_string( TALLOC_CTX *mem_ctx,
+ const char *pszDomainName,
+ struct dns_domain_name **presult );
+char *dns_generate_keyname( TALLOC_CTX *mem_ctx );
+
+/* from dnsrecord.c */
+
+DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
+ uint16_t q_type, uint16_t q_class,
+ struct dns_request **preq );
+DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
+ struct dns_update_request **preq );
+DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
+ const char *host, int num_ips,
+ const struct sockaddr_storage *sslist,
+ struct dns_update_request **preq);
+DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
+ uint16_t type, uint16_t r_class, uint32_t ttl,
+ uint16_t data_length, uint8_t *data,
+ struct dns_rrec **prec);
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16_t *num_records, struct dns_rrec ***records);
+DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name, time_t inception,
+ time_t expiration, uint16_t mode, uint16_t error,
+ uint16_t key_length, const uint8_t *key,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct sockaddr_storage *ip,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
+ uint16_t type, uint16_t r_class,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name, uint32_t type,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32_t ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_aaaa_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32_t ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec);
+DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ struct dns_tkey_record **ptkey);
+DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name,
+ time_t time_signed, uint16_t fudge,
+ uint16_t mac_length, const uint8_t *mac,
+ uint16_t original_id, uint16_t error,
+ struct dns_rrec **prec);
+DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
+ const char *domainname,
+ const char *hostname,
+ const struct sockaddr_storage *ip_addr,
+ size_t num_adds,
+ uint32_t ttl,
+ struct dns_update_request **preq);
+
+/* from dnssock.c */
+
+DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **conn );
+DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf);
+DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ struct dns_buffer **presult);
+DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ const struct dns_request *req,
+ struct dns_request **resp);
+DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_update_request *up_req,
+ struct dns_update_request **up_resp);
+
+/* from dnsmarshall.c */
+
+struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx);
+void dns_marshall_buffer(struct dns_buffer *buf, const uint8_t *data,
+ size_t len);
+void dns_marshall_uint16(struct dns_buffer *buf, uint16_t val);
+void dns_marshall_uint32(struct dns_buffer *buf, uint32_t val);
+void dns_unmarshall_buffer(struct dns_buffer *buf, uint8_t *data,
+ size_t len);
+void dns_unmarshall_uint16(struct dns_buffer *buf, uint16_t *val);
+void dns_unmarshall_uint32(struct dns_buffer *buf, uint32_t *val);
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname);
+void dns_marshall_domain_name(struct dns_buffer *buf,
+ const struct dns_domain_name *name);
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname);
+DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
+ const struct dns_request *req,
+ struct dns_buffer **pbuf);
+DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_request **preq);
+DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_update_request *update,
+ struct dns_buffer **pbuf);
+DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_update_request **pupreq);
+struct dns_request *dns_update2request(struct dns_update_request *update);
+struct dns_update_request *dns_request2update(struct dns_request *request);
+uint16_t dns_response_code(uint16_t flags);
+const char *dns_errstr(DNS_ERROR err);
+
+/* from dnsgss.c */
+
+#ifdef HAVE_GSSAPI
+
+void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat );
+DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
+ const char *servername,
+ const char *keyname,
+ gss_ctx_id_t *gss_ctx,
+ enum dns_ServerType srv_type );
+DNS_ERROR dns_sign_update(struct dns_update_request *req,
+ gss_ctx_id_t gss_ctx,
+ const char *keyname,
+ const char *algorithmname,
+ time_t time_signed, uint16_t fudge);
+
+#endif /* HAVE_GSSAPI */
+
+#endif /* _DNS_H */
diff --git a/lib/addns/dnserr.h b/lib/addns/dnserr.h
new file mode 100644
index 0000000..1eedc8f
--- /dev/null
+++ b/lib/addns/dnserr.h
@@ -0,0 +1,87 @@
+/*
+ Error codes for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _DNSERR_H
+#define _DNSERR_H
+
+
+/* The Splint code analysis tool (http://www.splint.org.) doesn't
+ like immediate structures. */
+
+#ifdef _SPLINT_
+#undef HAVE_IMMEDIATE_STRUCTURES
+#endif
+
+/* Setup the DNS_ERROR typedef. Technique takes from nt_status.h */
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32_t v;} DNS_ERROR;
+#define ERROR_DNS(x) ((DNS_ERROR) { x })
+#define ERROR_DNS_V(x) ((x).v)
+#else
+typedef uint32_t DNS_ERROR;
+#define ERROR_DNS(x) (x)
+#define ERROR_DNS_V(x) (x)
+#endif
+
+#define ERR_DNS_IS_OK(x) (ERROR_DNS_V(x) == 0)
+#define ERR_DNS_EQUAL(x,y) (ERROR_DNS_V(x) == ERROR_DNS_V(y))
+
+/*************************************************
+ * Define the error codes here
+ *************************************************/
+
+#define ERROR_DNS_SUCCESS ERROR_DNS(0)
+#define ERROR_DNS_RECORD_NOT_FOUND ERROR_DNS(1)
+#define ERROR_DNS_BAD_RESPONSE ERROR_DNS(2)
+#define ERROR_DNS_INVALID_PARAMETER ERROR_DNS(3)
+#define ERROR_DNS_NO_MEMORY ERROR_DNS(4)
+#define ERROR_DNS_INVALID_NAME_SERVER ERROR_DNS(5)
+#define ERROR_DNS_CONNECTION_FAILED ERROR_DNS(6)
+#define ERROR_DNS_GSS_ERROR ERROR_DNS(7)
+#define ERROR_DNS_INVALID_NAME ERROR_DNS(8)
+#define ERROR_DNS_INVALID_MESSAGE ERROR_DNS(9)
+#define ERROR_DNS_SOCKET_ERROR ERROR_DNS(10)
+#define ERROR_DNS_UPDATE_FAILED ERROR_DNS(11)
+
+/*
+ * About to be removed, transitional error
+ */
+#define ERROR_DNS_UNSUCCESSFUL ERROR_DNS(999)
+
+
+#define ERROR_BAD_RESPONSE 1
+#define ERROR_RECORD_NOT_FOUND 2
+#define ERROR_OUTOFMEMORY 8
+#if !defined(ERROR_INVALID_PARAMETER)
+#define ERROR_INVALID_PARAMETER 87
+#endif
+
+/*
+ * About to be removed, transitional error
+ */
+#define ERROR_UNSUCCESSFUL 999
+
+#endif /* _DNSERR_H */
+
diff --git a/lib/addns/dnsgss.c b/lib/addns/dnsgss.c
new file mode 100644
index 0000000..a315b80
--- /dev/null
+++ b/lib/addns/dnsgss.c
@@ -0,0 +1,344 @@
+/*
+ Public Interface file for Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include <ctype.h>
+
+
+#ifdef HAVE_GSSAPI
+
+/*********************************************************************
+*********************************************************************/
+
+#ifndef HAVE_STRUPR
+static int strupr( char *szDomainName )
+{
+ if ( !szDomainName ) {
+ return ( 0 );
+ }
+ while ( *szDomainName != '\0' ) {
+ *szDomainName = toupper( *szDomainName );
+ szDomainName++;
+ }
+ return ( 0 );
+}
+#endif
+
+#if 0
+/*********************************************************************
+*********************************************************************/
+
+static void display_status_1( const char *m, OM_uint32 code, int type )
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx;
+
+ msg_ctx = 0;
+ while ( 1 ) {
+ maj_stat = gss_display_status( &min_stat, code,
+ type, GSS_C_NULL_OID,
+ &msg_ctx, &msg );
+ fprintf( stdout, "GSS-API error %s: %s\n", m,
+ ( char * ) msg.value );
+ ( void ) gss_release_buffer( &min_stat, &msg );
+
+ if ( !msg_ctx )
+ break;
+ }
+}
+
+/*********************************************************************
+*********************************************************************/
+
+void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
+{
+ display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
+ display_status_1( msg, min_stat, GSS_C_MECH_CODE );
+}
+#endif
+
+static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ const char *keyname,
+ const gss_name_t target_name,
+ gss_ctx_id_t *ctx,
+ enum dns_ServerType srv_type )
+{
+ struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
+ OM_uint32 major, minor;
+ OM_uint32 ret_flags;
+ struct dns_request *req = NULL;
+ struct dns_buffer *buf = NULL;
+ DNS_ERROR err;
+
+ gss_OID_desc krb5_oid_desc =
+ { 9, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
+
+ *ctx = GSS_C_NO_CONTEXT;
+ input_ptr = NULL;
+
+ do {
+ major = gss_init_sec_context(
+ &minor, NULL, ctx, target_name, &krb5_oid_desc,
+ GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
+ GSS_C_CONF_FLAG |
+ GSS_C_INTEG_FLAG,
+ 0, NULL, input_ptr, NULL, &output_desc,
+ &ret_flags, NULL );
+
+ if (input_ptr != NULL) {
+ TALLOC_FREE(input_desc.value);
+ }
+
+ if (output_desc.length != 0) {
+
+ struct dns_rrec *rec;
+
+ time_t t = time(NULL);
+
+ err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
+ DNS_CLASS_IN, &req);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_create_tkey_record(
+ req, keyname, "gss.microsoft.com", t,
+ t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
+ output_desc.length, (uint8_t *)output_desc.value,
+ &rec );
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /* Windows 2000 DNS is broken and requires the
+ TKEY payload in the Answer section instead
+ of the Additional section like Windows 2003 */
+
+ if ( srv_type == DNS_SRV_WIN2000 ) {
+ err = dns_add_rrec(req, rec, &req->num_answers,
+ &req->answers);
+ } else {
+ err = dns_add_rrec(req, rec, &req->num_additionals,
+ &req->additional);
+ }
+
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_marshall_request(mem_ctx, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_send(conn, buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ TALLOC_FREE(buf);
+ TALLOC_FREE(req);
+ }
+
+ gss_release_buffer(&minor, &output_desc);
+
+ if ((major != GSS_S_COMPLETE) &&
+ (major != GSS_S_CONTINUE_NEEDED)) {
+ return ERROR_DNS_GSS_ERROR;
+ }
+
+ if (major == GSS_S_CONTINUE_NEEDED) {
+
+ struct dns_request *resp;
+ struct dns_tkey_record *tkey;
+ struct dns_rrec *tkey_answer = NULL;
+ uint16_t i;
+
+ err = dns_receive(mem_ctx, conn, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_unmarshall_request(buf, buf, &resp);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * TODO: Compare id and keyname
+ */
+
+ for (i=0; i < resp->num_answers; i++) {
+ if (resp->answers[i]->type != QTYPE_TKEY) {
+ continue;
+ }
+
+ tkey_answer = resp->answers[i];
+ }
+
+ if (tkey_answer == NULL) {
+ err = ERROR_DNS_INVALID_MESSAGE;
+ goto error;
+ }
+
+ err = dns_unmarshall_tkey_record(
+ mem_ctx, resp->answers[0], &tkey);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ input_desc.length = tkey->key_length;
+ input_desc.value = talloc_move(mem_ctx, &tkey->key);
+
+ input_ptr = &input_desc;
+
+ TALLOC_FREE(buf);
+ }
+
+ } while ( major == GSS_S_CONTINUE_NEEDED );
+
+ /* If we arrive here, we have a valid security context */
+
+ err = ERROR_DNS_SUCCESS;
+
+ error:
+
+ TALLOC_FREE(buf);
+ TALLOC_FREE(req);
+ return err;
+}
+
+DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
+ const char *servername,
+ const char *keyname,
+ gss_ctx_id_t *gss_ctx,
+ enum dns_ServerType srv_type )
+{
+ OM_uint32 major, minor;
+
+ char *upcaserealm, *targetname;
+ DNS_ERROR err;
+
+ gss_buffer_desc input_name;
+ struct dns_connection *conn;
+
+ gss_name_t targ_name;
+
+ gss_OID_desc nt_host_oid_desc =
+ {10, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
+
+ TALLOC_CTX *mem_ctx;
+
+ if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
+ err = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ strupr(upcaserealm);
+
+ if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
+ servername, upcaserealm))) {
+ err = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ input_name.value = targetname;
+ input_name.length = strlen(targetname);
+
+ major = gss_import_name( &minor, &input_name,
+ &nt_host_oid_desc, &targ_name );
+
+ if (major) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname,
+ targ_name, gss_ctx, srv_type );
+
+ gss_release_name( &minor, &targ_name );
+
+ error:
+ TALLOC_FREE(mem_ctx);
+
+ return err;
+}
+
+DNS_ERROR dns_sign_update(struct dns_update_request *req,
+ gss_ctx_id_t gss_ctx,
+ const char *keyname,
+ const char *algorithmname,
+ time_t time_signed, uint16_t fudge)
+{
+ struct dns_buffer *buf;
+ DNS_ERROR err;
+ struct dns_domain_name *key, *algorithm;
+ struct gss_buffer_desc_struct msg, mic;
+ OM_uint32 major, minor;
+ struct dns_rrec *rec;
+
+ err = dns_marshall_update_request(req, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ err = dns_domain_name_from_string(buf, keyname, &key);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, key);
+ dns_marshall_uint16(buf, DNS_CLASS_ANY);
+ dns_marshall_uint32(buf, 0); /* TTL */
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
+ dns_marshall_uint32(buf, time_signed);
+ dns_marshall_uint16(buf, fudge);
+ dns_marshall_uint16(buf, 0); /* error */
+ dns_marshall_uint16(buf, 0); /* other len */
+
+ err = buf->error;
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ msg.value = (void *)buf->data;
+ msg.length = buf->offset;
+
+ major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
+ if (major != 0) {
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ if (mic.length > 0xffff) {
+ gss_release_buffer(&minor, &mic);
+ err = ERROR_DNS_GSS_ERROR;
+ goto error;
+ }
+
+ err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
+ fudge, mic.length, (uint8_t *)mic.value,
+ req->id, 0, &rec);
+ gss_release_buffer(&minor, &mic);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_additionals, &req->additional);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+#endif /* HAVE_GSSAPI */
diff --git a/lib/addns/dnsmarshall.c b/lib/addns/dnsmarshall.c
new file mode 100644
index 0000000..c954203
--- /dev/null
+++ b/lib/addns/dnsmarshall.c
@@ -0,0 +1,534 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include "assert.h"
+
+struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
+{
+ struct dns_buffer *result;
+
+ if (!(result = talloc_zero(mem_ctx, struct dns_buffer))) {
+ return NULL;
+ }
+
+ result->offset = 0;
+ result->error = ERROR_DNS_SUCCESS;
+
+ /*
+ * Small initial size to exercise the realloc code
+ */
+ result->size = 2;
+
+ if (!(result->data = talloc_zero_array(result, uint8_t, result->size))) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+void dns_marshall_buffer(struct dns_buffer *buf, const uint8_t *data,
+ size_t len)
+{
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (buf->offset + len < buf->offset) {
+ /*
+ * Wraparound!
+ */
+ buf->error = ERROR_DNS_INVALID_PARAMETER;
+ return;
+ }
+
+ if ((buf->offset + len) > 0xffff) {
+ /*
+ * Only 64k possible
+ */
+ buf->error = ERROR_DNS_INVALID_PARAMETER;
+ return;
+ }
+
+ if (buf->offset + len > buf->size) {
+ size_t new_size = buf->offset + len;
+ uint8_t *new_data;
+
+ /*
+ * Don't do too many reallocs, round up to some multiple
+ */
+
+ new_size += (64 - (new_size % 64));
+
+ if (!(new_data = talloc_realloc(buf, buf->data, uint8_t,
+ new_size))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ buf->size = new_size;
+ buf->data = new_data;
+ }
+
+ if (data != NULL) {
+ memcpy(buf->data + buf->offset, data, len);
+ }
+ buf->offset += len;
+ return;
+}
+
+void dns_marshall_uint16(struct dns_buffer *buf, uint16_t val)
+{
+ uint16_t n_val = htons(val);
+ dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
+}
+
+void dns_marshall_uint32(struct dns_buffer *buf, uint32_t val)
+{
+ uint32_t n_val = htonl(val);
+ dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
+}
+
+void dns_unmarshall_buffer(struct dns_buffer *buf, uint8_t *data,
+ size_t len)
+{
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if ((len > buf->size) || (buf->offset + len > buf->size)) {
+ buf->error = ERROR_DNS_INVALID_MESSAGE;
+ return;
+ }
+
+ memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
+ buf->offset += len;
+
+ return;
+}
+
+void dns_unmarshall_uint16(struct dns_buffer *buf, uint16_t *val)
+{
+ uint16_t n_val;
+
+ dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *val = ntohs(n_val);
+}
+
+void dns_unmarshall_uint32(struct dns_buffer *buf, uint32_t *val)
+{
+ uint32_t n_val;
+
+ dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *val = ntohl(n_val);
+}
+
+void dns_marshall_domain_name(struct dns_buffer *buf,
+ const struct dns_domain_name *name)
+{
+ struct dns_domain_label *label;
+ char end_char = '\0';
+
+ /*
+ * TODO: Implement DNS compression
+ */
+
+ for (label = name->pLabelList; label != NULL; label = label->next) {
+ uint8_t len = label->len;
+
+ dns_marshall_buffer(buf, (uint8_t *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ dns_marshall_buffer(buf, (uint8_t *)label->label, len);
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+ }
+
+ dns_marshall_buffer(buf, (uint8_t *)&end_char, 1);
+}
+
+static void dns_unmarshall_label(TALLOC_CTX *mem_ctx,
+ int level,
+ struct dns_buffer *buf,
+ struct dns_domain_label **plabel)
+{
+ struct dns_domain_label *label;
+ uint8_t len;
+
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (level > 128) {
+ /*
+ * Protect against recursion
+ */
+ buf->error = ERROR_DNS_INVALID_MESSAGE;
+ return;
+ }
+
+ dns_unmarshall_buffer(buf, &len, sizeof(len));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (len == 0) {
+ *plabel = NULL;
+ return;
+ }
+
+ if ((len & 0xc0) == 0xc0) {
+ /*
+ * We've got a compressed name. Build up a new "fake" buffer
+ * and using the calculated offset.
+ */
+ struct dns_buffer new_buf;
+ uint8_t low;
+
+ dns_unmarshall_buffer(buf, &low, sizeof(low));
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ new_buf = *buf;
+ new_buf.offset = len & 0x3f;
+ new_buf.offset <<= 8;
+ new_buf.offset |= low;
+
+ dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
+ buf->error = new_buf.error;
+ return;
+ }
+
+ if ((len & 0xc0) != 0) {
+ buf->error = ERROR_DNS_INVALID_NAME;
+ return;
+ }
+
+ if (!(label = talloc_zero(mem_ctx, struct dns_domain_label))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ label->len = len;
+
+ if (!(label->label = talloc_zero_array(label, char, len+1))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+
+ dns_unmarshall_buffer(buf, (uint8_t *)label->label, len);
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ dns_unmarshall_label(label, level+1, buf, &label->next);
+ if (!ERR_DNS_IS_OK(buf->error)) goto error;
+
+ *plabel = label;
+ return;
+
+ error:
+ TALLOC_FREE(label);
+ return;
+}
+
+void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_domain_name **pname)
+{
+ struct dns_domain_name *name;
+
+ if (!ERR_DNS_IS_OK(buf->error)) return;
+
+ if (!(name = talloc_zero(mem_ctx, struct dns_domain_name))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_label(name, 0, buf, &name->pLabelList);
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ return;
+ }
+
+ *pname = name;
+ return;
+}
+
+static void dns_marshall_question(struct dns_buffer *buf,
+ const struct dns_question *q)
+{
+ dns_marshall_domain_name(buf, q->name);
+ dns_marshall_uint16(buf, q->q_type);
+ dns_marshall_uint16(buf, q->q_class);
+}
+
+static void dns_unmarshall_question(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_question **pq)
+{
+ struct dns_question *q;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (!(q = talloc_zero(mem_ctx, struct dns_question))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_domain_name(q, buf, &q->name);
+ dns_unmarshall_uint16(buf, &q->q_type);
+ dns_unmarshall_uint16(buf, &q->q_class);
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *pq = q;
+}
+
+static void dns_marshall_rr(struct dns_buffer *buf,
+ const struct dns_rrec *r)
+{
+ dns_marshall_domain_name(buf, r->name);
+ dns_marshall_uint16(buf, r->type);
+ dns_marshall_uint16(buf, r->r_class);
+ dns_marshall_uint32(buf, r->ttl);
+ dns_marshall_uint16(buf, r->data_length);
+ dns_marshall_buffer(buf, r->data, r->data_length);
+}
+
+static void dns_unmarshall_rr(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_rrec **pr)
+{
+ struct dns_rrec *r;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (!(r = talloc_zero(mem_ctx, struct dns_rrec))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+
+ dns_unmarshall_domain_name(r, buf, &r->name);
+ dns_unmarshall_uint16(buf, &r->type);
+ dns_unmarshall_uint16(buf, &r->r_class);
+ dns_unmarshall_uint32(buf, &r->ttl);
+ dns_unmarshall_uint16(buf, &r->data_length);
+ r->data = NULL;
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ if (r->data_length != 0) {
+ if (!(r->data = talloc_zero_array(r, uint8_t, r->data_length))) {
+ buf->error = ERROR_DNS_NO_MEMORY;
+ return;
+ }
+ dns_unmarshall_buffer(buf, r->data, r->data_length);
+ }
+
+ if (!(ERR_DNS_IS_OK(buf->error))) return;
+
+ *pr = r;
+}
+
+DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
+ const struct dns_request *req,
+ struct dns_buffer **pbuf)
+{
+ struct dns_buffer *buf;
+ uint16_t i;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ dns_marshall_uint16(buf, req->id);
+ dns_marshall_uint16(buf, req->flags);
+ dns_marshall_uint16(buf, req->num_questions);
+ dns_marshall_uint16(buf, req->num_answers);
+ dns_marshall_uint16(buf, req->num_auths);
+ dns_marshall_uint16(buf, req->num_additionals);
+
+ for (i=0; i<req->num_questions; i++) {
+ dns_marshall_question(buf, req->questions[i]);
+ }
+ for (i=0; i<req->num_answers; i++) {
+ dns_marshall_rr(buf, req->answers[i]);
+ }
+ for (i=0; i<req->num_auths; i++) {
+ dns_marshall_rr(buf, req->auths[i]);
+ }
+ for (i=0; i<req->num_additionals; i++) {
+ dns_marshall_rr(buf, req->additional[i]);
+ }
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ DNS_ERROR err = buf->error;
+ TALLOC_FREE(buf);
+ return err;
+ }
+
+ *pbuf = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_request **preq)
+{
+ struct dns_request *req;
+ uint16_t i;
+ DNS_ERROR err = ERROR_DNS_NO_MEMORY;
+
+ if (!(req = talloc_zero(mem_ctx, struct dns_request))) {
+ return err;
+ }
+
+ dns_unmarshall_uint16(buf, &req->id);
+ dns_unmarshall_uint16(buf, &req->flags);
+ dns_unmarshall_uint16(buf, &req->num_questions);
+ dns_unmarshall_uint16(buf, &req->num_answers);
+ dns_unmarshall_uint16(buf, &req->num_auths);
+ dns_unmarshall_uint16(buf, &req->num_additionals);
+
+ if (!ERR_DNS_IS_OK(buf->error)){
+ err = buf->error;
+ goto error;
+ }
+
+ err = ERROR_DNS_NO_MEMORY;
+
+ if ((req->num_questions != 0) &&
+ !(req->questions = talloc_zero_array(req, struct dns_question *,
+ req->num_questions))) {
+ goto error;
+ }
+ if ((req->num_answers != 0) &&
+ !(req->answers = talloc_zero_array(req, struct dns_rrec *,
+ req->num_answers))) {
+ goto error;
+ }
+ if ((req->num_auths != 0) &&
+ !(req->auths = talloc_zero_array(req, struct dns_rrec *,
+ req->num_auths))) {
+ goto error;
+ }
+ if ((req->num_additionals != 0) &&
+ !(req->additional = talloc_zero_array(req, struct dns_rrec *,
+ req->num_additionals))) {
+ goto error;
+ }
+
+ for (i=0; i<req->num_questions; i++) {
+ dns_unmarshall_question(req->questions, buf,
+ &req->questions[i]);
+ }
+ for (i=0; i<req->num_answers; i++) {
+ dns_unmarshall_rr(req->answers, buf,
+ &req->answers[i]);
+ }
+ for (i=0; i<req->num_auths; i++) {
+ dns_unmarshall_rr(req->auths, buf,
+ &req->auths[i]);
+ }
+ for (i=0; i<req->num_additionals; i++) {
+ dns_unmarshall_rr(req->additional, buf,
+ &req->additional[i]);
+ }
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(req);
+ return err;
+}
+
+struct dns_request *dns_update2request(struct dns_update_request *update)
+{
+ struct dns_request *req;
+
+ /*
+ * This is a non-specified construct that happens to work on Linux/gcc
+ * and I would expect it to work everywhere else. dns_request and
+ * dns_update_request are essentially the same structures with
+ * different names, so any difference would mean that the compiler
+ * applied two different variations of padding given the same types in
+ * the structures.
+ */
+
+ req = (struct dns_request *)(void *)update;
+
+ /*
+ * The assert statement here looks like we could do the equivalent
+ * assignments to get portable, but it would mean that we have to
+ * allocate the dns_question record for the dns_zone records. We
+ * assume that if this assert works then the same holds true for
+ * dns_zone<>dns_question as well.
+ */
+
+#ifdef DEVELOPER
+ assert((req->id == update->id) && (req->flags == update->flags) &&
+ (req->num_questions == update->num_zones) &&
+ (req->num_answers == update->num_preqs) &&
+ (req->num_auths == update->num_updates) &&
+ (req->num_additionals == update->num_additionals) &&
+ (req->questions ==
+ (struct dns_question **)(void *)update->zones) &&
+ (req->answers == update->preqs) &&
+ (req->auths == update->updates) &&
+ (req->additional == update->additional));
+#endif
+
+ return req;
+}
+
+struct dns_update_request *dns_request2update(struct dns_request *request)
+{
+ /*
+ * For portability concerns see dns_update2request;
+ */
+ return (struct dns_update_request *)(void *)request;
+}
+
+DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_update_request *update,
+ struct dns_buffer **pbuf)
+{
+ return dns_marshall_request(mem_ctx, dns_update2request(update), pbuf);
+}
+
+DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
+ struct dns_buffer *buf,
+ struct dns_update_request **pupreq)
+{
+ /*
+ * See comments above about portability. If the above works, this will
+ * as well.
+ */
+
+ return dns_unmarshall_request(mem_ctx, buf,
+ (struct dns_request **)(void *)pupreq);
+}
+
+uint16_t dns_response_code(uint16_t flags)
+{
+ return flags & 0xF;
+}
diff --git a/lib/addns/dnsquery.c b/lib/addns/dnsquery.c
new file mode 100644
index 0000000..7590c9f
--- /dev/null
+++ b/lib/addns/dnsquery.c
@@ -0,0 +1,782 @@
+/*
+ Unix SMB/CIFS implementation.
+ DNS utility library
+ Copyright (C) Gerald (Jerry) Carter 2006.
+ Copyright (C) Jeremy Allison 2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/util_net.h"
+#include "lib/util/tsort.h"
+#include "librpc/gen_ndr/dns.h"
+#include "libcli/dns/dns_lookup.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "dnsquery.h"
+
+/*********************************************************************
+ Sort SRV record list based on weight and priority. See RFC 2782.
+*********************************************************************/
+
+static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
+{
+ if ( a->priority == b->priority ) {
+
+ /* randomize entries with an equal weight and priority */
+ if ( a->weight == b->weight )
+ return 0;
+
+ /* higher weights should be sorted lower */
+ if ( a->weight > b->weight )
+ return -1;
+ else
+ return 1;
+ }
+
+ if ( a->priority < b->priority )
+ return -1;
+
+ return 1;
+}
+
+struct ads_dns_lookup_srv_state {
+ struct dns_rr_srv *srvs;
+ size_t num_srvs;
+};
+
+static void ads_dns_lookup_srv_done(struct tevent_req *subreq);
+
+struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name)
+{
+ struct tevent_req *req, *subreq;
+ struct ads_dns_lookup_srv_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ads_dns_lookup_srv_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = dns_lookup_send(
+ state,
+ ev,
+ NULL,
+ name,
+ DNS_QCLASS_IN,
+ DNS_QTYPE_SRV);
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, ads_dns_lookup_srv_done, req);
+ return req;
+}
+
+static void ads_dns_lookup_srv_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ads_dns_lookup_srv_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_srv_state);
+ int ret;
+ struct dns_name_packet *reply;
+ uint16_t i, idx;
+
+ ret = dns_lookup_recv(subreq, state, &reply);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return;
+ }
+
+ for (i=0; i<reply->ancount; i++) {
+ if (reply->answers[i].rr_type == DNS_QTYPE_SRV) {
+ /* uint16_t can't wrap here. */
+ state->num_srvs += 1;
+ }
+ }
+
+ state->srvs = talloc_array(state, struct dns_rr_srv, state->num_srvs);
+ if (tevent_req_nomem(state->srvs, req)) {
+ return;
+ }
+
+ idx = 0;
+
+ for (i=0; i<reply->ancount; i++) {
+ struct dns_res_rec *an = &reply->answers[i];
+ struct dns_rr_srv *dst = &state->srvs[idx];
+ struct dns_srv_record *src;
+
+ if (an->rr_type != DNS_QTYPE_SRV) {
+ continue;
+ }
+ src = &an->rdata.srv_record;
+
+ *dst = (struct dns_rr_srv) {
+ .hostname = talloc_move(state->srvs, &src->target),
+ .priority = src->priority,
+ .weight = src->weight,
+ .port = src->port,
+ };
+ idx += 1;
+ }
+
+ for (i=0; i<reply->arcount; i++) {
+ struct dns_res_rec *ar = &reply->additional[i];
+ struct sockaddr_storage addr;
+ bool ok;
+ size_t j;
+
+ ok = dns_res_rec_get_sockaddr(ar, &addr);
+ if (!ok) {
+ continue;
+ }
+
+ for (j=0; j<state->num_srvs; j++) {
+ struct dns_rr_srv *srv = &state->srvs[j];
+ struct sockaddr_storage *tmp;
+
+ if (strcmp(srv->hostname, ar->name) != 0) {
+ continue;
+ }
+ /* uint16_t can't wrap here. */
+ tmp = talloc_realloc(
+ state->srvs,
+ srv->ss_s,
+ struct sockaddr_storage,
+ srv->num_ips+1);
+
+ if (tevent_req_nomem(tmp, req)) {
+ return;
+ }
+ srv->ss_s = tmp;
+
+ srv->ss_s[srv->num_ips] = addr;
+ srv->num_ips += 1;
+ }
+ }
+
+ TYPESAFE_QSORT(state->srvs, state->num_srvs, dnssrvcmp);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct dns_rr_srv **srvs,
+ size_t *num_srvs)
+{
+ struct ads_dns_lookup_srv_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_srv_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *srvs = talloc_move(mem_ctx, &state->srvs);
+ *num_srvs = state->num_srvs;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Simple wrapper for a DNS SRV query
+*********************************************************************/
+
+NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
+ const char *name,
+ struct dns_rr_srv **dclist,
+ size_t *numdcs)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ size_t num_srvs = 0;
+
+ ev = samba_tevent_context_init(ctx);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = ads_dns_lookup_srv_send(ev, ev, name);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = ads_dns_lookup_srv_recv(req, ctx, dclist, &num_srvs);
+ if (NT_STATUS_IS_OK(status)) {
+ *numdcs = num_srvs;
+ }
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+
+struct ads_dns_lookup_ns_state {
+ struct dns_rr_ns *nss;
+ size_t num_nss;
+};
+
+static void ads_dns_lookup_ns_done(struct tevent_req *subreq);
+
+struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name)
+{
+ struct tevent_req *req, *subreq;
+ struct ads_dns_lookup_ns_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ads_dns_lookup_ns_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = dns_lookup_send(state, ev, NULL, name, DNS_QCLASS_IN,
+ DNS_QTYPE_NS);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, ads_dns_lookup_ns_done, req);
+ return req;
+}
+
+static void ads_dns_lookup_ns_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ads_dns_lookup_ns_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_ns_state);
+ int ret;
+ struct dns_name_packet *reply;
+ uint16_t i, idx;
+
+ ret = dns_lookup_recv(subreq, state, &reply);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return;
+ }
+
+ for (i=0; i<reply->ancount; i++) {
+ if (reply->answers[i].rr_type == DNS_QTYPE_NS) {
+ state->num_nss += 1;
+ }
+ }
+
+ state->nss = talloc_array(state, struct dns_rr_ns, state->num_nss);
+ if (tevent_req_nomem(state->nss, req)) {
+ return;
+ }
+
+ idx = 0;
+
+ for (i=0; i<reply->ancount; i++) {
+ struct dns_res_rec *an = &reply->answers[i];
+
+ if (an->rr_type != DNS_QTYPE_NS) {
+ continue;
+ }
+
+ state->nss[idx].hostname = talloc_move(state->nss,
+ &an->rdata.ns_record);
+ idx += 1;
+ }
+
+ for (i=0; i<reply->arcount; i++) {
+ struct dns_res_rec *ar = &reply->additional[i];
+ struct sockaddr_storage addr;
+ bool ok;
+ size_t j;
+
+ ok = dns_res_rec_get_sockaddr(ar, &addr);
+ if (!ok) {
+ continue;
+ }
+
+ for (j=0; j<state->num_nss; j++) {
+ struct dns_rr_ns *ns = &state->nss[j];
+
+ if (strcmp(ns->hostname, ar->name) == 0) {
+ ns->ss = addr;
+ }
+ }
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct dns_rr_ns **nss,
+ size_t *num_nss)
+{
+ struct ads_dns_lookup_ns_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_ns_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *nss = talloc_move(mem_ctx, &state->nss);
+ *num_nss = state->num_nss;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Simple wrapper for a DNS NS query
+*********************************************************************/
+
+NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
+ const char *dnsdomain,
+ struct dns_rr_ns **nslist,
+ size_t *numns)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ size_t num_ns = 0;
+
+ ev = samba_tevent_context_init(ctx);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = ads_dns_lookup_ns_send(ev, ev, dnsdomain);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = ads_dns_lookup_ns_recv(req, ctx, nslist, &num_ns);
+ *numns = num_ns;
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+
+/*********************************************************************
+ Async A record lookup.
+*********************************************************************/
+
+struct ads_dns_lookup_a_state {
+ uint8_t rcode;
+ size_t num_names;
+ char **hostnames;
+ struct samba_sockaddr *addrs;
+};
+
+static void ads_dns_lookup_a_done(struct tevent_req *subreq);
+
+struct tevent_req *ads_dns_lookup_a_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct ads_dns_lookup_a_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ads_dns_lookup_a_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = dns_lookup_send(
+ state,
+ ev,
+ NULL,
+ name,
+ DNS_QCLASS_IN,
+ DNS_QTYPE_A);
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, ads_dns_lookup_a_done, req);
+ return req;
+}
+
+static void ads_dns_lookup_a_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ads_dns_lookup_a_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_a_state);
+ int ret;
+ struct dns_name_packet *reply = NULL;
+ uint16_t i;
+
+ ret = dns_lookup_recv(subreq, state, &reply);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return;
+ }
+
+ state->rcode = (reply->operation & DNS_RCODE);
+ if (state->rcode != DNS_RCODE_OK) {
+ /* Don't bother looking for answers. */
+ tevent_req_done(req);
+ return;
+ }
+
+ /*
+ * We don't care about CNAME answers here. We're
+ * just wanting an async name -> IPv4 lookup.
+ */
+ for (i = 0; i < reply->ancount; i++) {
+ if (reply->answers[i].rr_type == DNS_QTYPE_A) {
+ state->num_names += 1;
+ }
+ }
+
+ state->hostnames = talloc_zero_array(state,
+ char *,
+ state->num_names);
+ if (tevent_req_nomem(state->hostnames, req)) {
+ return;
+ }
+ state->addrs = talloc_zero_array(state,
+ struct samba_sockaddr,
+ state->num_names);
+ if (tevent_req_nomem(state->addrs, req)) {
+ return;
+ }
+
+ state->num_names = 0;
+
+ for (i = 0; i < reply->ancount; i++) {
+ bool ok;
+ struct sockaddr_storage ss = {0};
+ struct dns_res_rec *an = &reply->answers[i];
+
+ if (an->rr_type != DNS_QTYPE_A) {
+ continue;
+ }
+ if (an->name == NULL) {
+ /* Can this happen? */
+ continue;
+ }
+ if (an->rdata.ipv4_record == NULL) {
+ /* Can this happen? */
+ continue;
+ }
+ ok = dns_res_rec_get_sockaddr(an,
+ &ss);
+ if (!ok) {
+ continue;
+ }
+ if (is_zero_addr(&ss)) {
+ continue;
+ }
+ state->addrs[state->num_names].u.ss = ss;
+ state->addrs[state->num_names].sa_socklen =
+ sizeof(struct sockaddr_in);
+ state->hostnames[state->num_names] = talloc_strdup(
+ state->hostnames,
+ an->name);
+ if (tevent_req_nomem(state->hostnames[state->num_names], req)) {
+ return;
+ }
+ state->num_names += 1;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS ads_dns_lookup_a_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *rcode_out,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out)
+{
+ struct ads_dns_lookup_a_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_a_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ if (rcode_out != NULL) {
+ /*
+ * If we got no names, an upper layer may
+ * want to print a debug message.
+ */
+ *rcode_out = state->rcode;
+ }
+ if (hostnames_out != NULL) {
+ *hostnames_out = talloc_move(mem_ctx,
+ &state->hostnames);
+ }
+ if (addrs_out != NULL) {
+ *addrs_out = talloc_move(mem_ctx,
+ &state->addrs);
+ }
+ *num_names_out = state->num_names;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Simple wrapper for a DNS A query
+*********************************************************************/
+
+NTSTATUS ads_dns_lookup_a(TALLOC_CTX *ctx,
+ const char *name_in,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(ctx);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = ads_dns_lookup_a_send(ev, ev, name_in);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ /*
+ * Synchronous doesn't need to care about the rcode or
+ * a copy of the name_in.
+ */
+ status = ads_dns_lookup_a_recv(req,
+ ctx,
+ NULL,
+ num_names_out,
+ hostnames_out,
+ addrs_out);
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+
+#if defined(HAVE_IPV6)
+/*********************************************************************
+ Async AAAA record lookup.
+*********************************************************************/
+
+struct ads_dns_lookup_aaaa_state {
+ uint8_t rcode;
+ size_t num_names;
+ char **hostnames;
+ struct samba_sockaddr *addrs;
+};
+
+static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq);
+
+struct tevent_req *ads_dns_lookup_aaaa_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name)
+{
+ struct tevent_req *req, *subreq = NULL;
+ struct ads_dns_lookup_aaaa_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ads_dns_lookup_aaaa_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = dns_lookup_send(
+ state,
+ ev,
+ NULL,
+ name,
+ DNS_QCLASS_IN,
+ DNS_QTYPE_AAAA);
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, ads_dns_lookup_aaaa_done, req);
+ return req;
+}
+
+static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ads_dns_lookup_aaaa_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_aaaa_state);
+ int ret;
+ struct dns_name_packet *reply = NULL;
+ uint16_t i;
+
+ ret = dns_lookup_recv(subreq, state, &reply);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return;
+ }
+
+ state->rcode = (reply->operation & DNS_RCODE);
+ if (state->rcode != DNS_RCODE_OK) {
+ /* Don't bother looking for answers. */
+ tevent_req_done(req);
+ return;
+ }
+
+ /*
+ * We don't care about CNAME answers here. We're
+ * just wanting an async name -> IPv6 lookup.
+ */
+ for (i = 0; i < reply->ancount; i++) {
+ if (reply->answers[i].rr_type == DNS_QTYPE_AAAA) {
+ state->num_names += 1;
+ }
+ }
+
+ state->hostnames = talloc_zero_array(state,
+ char *,
+ state->num_names);
+ if (tevent_req_nomem(state->hostnames, req)) {
+ return;
+ }
+ state->addrs = talloc_zero_array(state,
+ struct samba_sockaddr,
+ state->num_names);
+ if (tevent_req_nomem(state->addrs, req)) {
+ return;
+ }
+
+ state->num_names = 0;
+
+ for (i = 0; i < reply->ancount; i++) {
+ bool ok;
+ struct sockaddr_storage ss = {0};
+ struct dns_res_rec *an = &reply->answers[i];
+
+ if (an->rr_type != DNS_QTYPE_AAAA) {
+ continue;
+ }
+ if (an->name == NULL) {
+ /* Can this happen? */
+ continue;
+ }
+ if (an->rdata.ipv6_record == NULL) {
+ /* Can this happen? */
+ continue;
+ }
+ ok = dns_res_rec_get_sockaddr(an,
+ &ss);
+ if (!ok) {
+ continue;
+ }
+ if (is_zero_addr(&ss)) {
+ continue;
+ }
+ state->addrs[state->num_names].u.ss = ss;
+ state->addrs[state->num_names].sa_socklen =
+ sizeof(struct sockaddr_in6);
+
+ state->hostnames[state->num_names] = talloc_strdup(
+ state->hostnames,
+ an->name);
+ if (tevent_req_nomem(state->hostnames[state->num_names], req)) {
+ return;
+ }
+ state->num_names += 1;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS ads_dns_lookup_aaaa_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *rcode_out,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out)
+{
+ struct ads_dns_lookup_aaaa_state *state = tevent_req_data(
+ req, struct ads_dns_lookup_aaaa_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ if (rcode_out != NULL) {
+ /*
+ * If we got no names, an upper layer may
+ * want to print a debug message.
+ */
+ *rcode_out = state->rcode;
+ }
+ if (hostnames_out != NULL) {
+ *hostnames_out = talloc_move(mem_ctx,
+ &state->hostnames);
+ }
+ if (addrs_out != NULL) {
+ *addrs_out = talloc_move(mem_ctx,
+ &state->addrs);
+ }
+ *num_names_out = state->num_names;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Simple wrapper for a DNS AAAA query
+*********************************************************************/
+
+NTSTATUS ads_dns_lookup_aaaa(TALLOC_CTX *ctx,
+ const char *name_in,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out)
+{
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(ctx);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = ads_dns_lookup_aaaa_send(ev, ev, name_in);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ /*
+ * Synchronous doesn't need to care about the rcode or
+ * a copy of the name_in.
+ */
+ status = ads_dns_lookup_aaaa_recv(req,
+ ctx,
+ NULL,
+ num_names_out,
+ hostnames_out,
+ addrs_out);
+fail:
+ TALLOC_FREE(ev);
+ return status;
+}
+#endif
diff --git a/lib/addns/dnsquery.h b/lib/addns/dnsquery.h
new file mode 100644
index 0000000..51f6b8f
--- /dev/null
+++ b/lib/addns/dnsquery.h
@@ -0,0 +1,84 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Gerald Carter 2006.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_ADDNS_DNSQUERY_H__
+#define __LIB_ADDNS_DNSQUERY_H__
+
+#include "replace.h"
+#include <tevent.h>
+#include "libcli/dns/dns.h"
+#include "lib/util/util_net.h"
+#include "libcli/util/ntstatus.h"
+
+/* The following definitions come from libads/dns.c */
+
+struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name);
+NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct dns_rr_srv **srvs,
+ size_t *num_srvs);
+NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
+ const char *name,
+ struct dns_rr_srv **dclist,
+ size_t *numdcs);
+struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name);
+NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct dns_rr_ns **nss,
+ size_t *num_nss);
+NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
+ const char *dnsdomain,
+ struct dns_rr_ns **nslist,
+ size_t *numns);
+struct tevent_req *ads_dns_lookup_a_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name);
+NTSTATUS ads_dns_lookup_a_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *rcode_out,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out);
+NTSTATUS ads_dns_lookup_a(TALLOC_CTX *ctx,
+ const char *name_in,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out);
+#if defined(HAVE_IPV6)
+struct tevent_req *ads_dns_lookup_aaaa_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name);
+NTSTATUS ads_dns_lookup_aaaa_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *rcode_out,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out);
+NTSTATUS ads_dns_lookup_aaaa(TALLOC_CTX *ctx,
+ const char *name_in,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out);
+#endif
+
+#endif /* __LIB_ADDNS_DNSQUERY_H__ */
diff --git a/lib/addns/dnsquery_srv.c b/lib/addns/dnsquery_srv.c
new file mode 100644
index 0000000..ac9e612
--- /dev/null
+++ b/lib/addns/dnsquery_srv.c
@@ -0,0 +1,560 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "dnsquery.h"
+#include "dnsquery_srv.h"
+#include "lib/util/debug.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/samba_util.h"
+#include "librpc/gen_ndr/dns.h"
+#include "librpc/ndr/libndr.h"
+
+/*
+ * For an array of dns_rr_srv records, issue A/AAAA queries for those
+ * records where the initial reply did not return IP addresses.
+ */
+
+struct dns_rr_srv_fill_state {
+ struct dns_rr_srv *srvs;
+ size_t num_srvs;
+
+ struct tevent_req **subreqs;
+ size_t num_outstanding;
+};
+
+static void dns_rr_srv_fill_done_a(struct tevent_req *subreq);
+#if defined(HAVE_IPV6)
+static void dns_rr_srv_fill_done_aaaa(struct tevent_req *subreq);
+#endif
+static void dns_rr_srv_fill_timedout(struct tevent_req *subreq);
+
+static struct tevent_req *dns_rr_srv_fill_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dns_rr_srv *srvs,
+ size_t num_srvs,
+ uint32_t timeout)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct dns_rr_srv_fill_state *state = NULL;
+ size_t i, num_subreqs;
+
+ req = tevent_req_create(mem_ctx, &state, struct dns_rr_srv_fill_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->srvs = srvs;
+ state->num_srvs = num_srvs;
+
+ /*
+ * Without IPv6 we only use half of this, but who does not
+ * have IPv6 these days?
+ */
+ num_subreqs = num_srvs * 2;
+
+ state->subreqs = talloc_zero_array(
+ state, struct tevent_req *, num_subreqs);
+ if (tevent_req_nomem(state->subreqs, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ for (i=0; i<num_srvs; i++) {
+
+ if (srvs[i].hostname == NULL) {
+ continue;
+ }
+ if (srvs[i].ss_s != NULL) {
+ /* IP address returned in SRV record. */
+ continue;
+ }
+
+ subreq = ads_dns_lookup_a_send(
+ state->subreqs, ev, srvs[i].hostname);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(state->subreqs);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ subreq, dns_rr_srv_fill_done_a, req);
+
+ state->subreqs[i*2] = subreq;
+ state->num_outstanding += 1;
+
+#if defined(HAVE_IPV6)
+ subreq = ads_dns_lookup_aaaa_send(
+ state->subreqs, ev, srvs[i].hostname);
+ if (tevent_req_nomem(subreq, req)) {
+ TALLOC_FREE(state->subreqs);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ subreq, dns_rr_srv_fill_done_aaaa, req);
+
+ state->subreqs[i*2+1] = subreq;
+ state->num_outstanding += 1;
+#endif
+ }
+
+ if (state->num_outstanding == 0) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tevent_wakeup_send(
+ state->subreqs,
+ ev,
+ tevent_timeval_current_ofs(timeout, 0));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dns_rr_srv_fill_timedout, req);
+
+ return req;
+}
+
+static void dns_rr_srv_fill_done(
+ struct tevent_req *subreq,
+ NTSTATUS (*recv_fn)(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *rcode_out,
+ size_t *num_names_out,
+ char ***hostnames_out,
+ struct samba_sockaddr **addrs_out))
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_rr_srv_fill_state *state = tevent_req_data(
+ req, struct dns_rr_srv_fill_state);
+ size_t num_subreqs = talloc_array_length(state->subreqs);
+ struct dns_rr_srv *srv = NULL;
+ size_t num_ips;
+ struct sockaddr_storage *tmp = NULL;
+ uint8_t rcode = 0;
+ char **hostnames_out = NULL;
+ struct samba_sockaddr *addrs = NULL;
+ size_t num_addrs = 0;
+ NTSTATUS status;
+ size_t i;
+ const char *ip_dbg_str = (recv_fn == ads_dns_lookup_a_recv) ?
+ "A" : "AAAA";
+
+ /*
+ * This loop walks all potential subreqs. Typical setups won't
+ * have more than a few DCs. If you have really many DCs
+ * (hundreds) and a DNS that doesn't return the DC IPs in the
+ * SRV reply, you have bigger problems than this loop linearly
+ * walking a pointer array. This is theoretically O(n^2), but
+ * probably the DNS roundtrip time outweighs this by a
+ * lot. And we have a global timeout on this whole
+ * dns_rr_srv_fill routine.
+ */
+ for (i=0; i<num_subreqs; i++) {
+ if (state->subreqs[i] == subreq) {
+ state->subreqs[i] = NULL;
+ break;
+ }
+ }
+ if (i == num_subreqs) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ srv = &state->srvs[i/2]; /* 2 subreq per srv */
+
+ status = recv_fn(
+ subreq,
+ state,
+ &rcode,
+ &num_addrs,
+ &hostnames_out,
+ &addrs);
+ TALLOC_FREE(subreq);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_INFO("async DNS %s lookup for %s returned %s\n",
+ ip_dbg_str,
+ srv->hostname,
+ nt_errstr(status));
+ num_addrs = 0;
+ goto done;
+ }
+
+ if (rcode != DNS_RCODE_OK) {
+ DBG_INFO("async DNS %s lookup for %s returned DNS code "
+ "%"PRIu8"\n",
+ ip_dbg_str,
+ srv->hostname,
+ rcode);
+ num_addrs = 0;
+ goto done;
+ }
+
+ if (num_addrs == 0) {
+ DBG_INFO("async DNS %s lookup for %s returned 0 addresses.\n",
+ ip_dbg_str,
+ srv->hostname);
+ goto done;
+ }
+
+ num_ips = talloc_array_length(srv->ss_s);
+
+ if (num_ips + num_addrs < num_addrs) {
+ /* overflow */
+ goto done;
+ }
+
+ tmp = talloc_realloc(
+ state->srvs,
+ srv->ss_s,
+ struct sockaddr_storage,
+ num_ips + num_addrs);
+ if (tmp == NULL) {
+ goto done;
+ }
+
+ for (i=0; i<num_addrs; i++) {
+ char addr[INET6_ADDRSTRLEN];
+ DBG_INFO("async DNS %s lookup for %s [%zu] got %s -> %s\n",
+ ip_dbg_str,
+ srv->hostname,
+ i,
+ hostnames_out[i],
+ print_sockaddr(addr, sizeof(addr), &addrs[i].u.ss));
+ tmp[num_ips + i] = addrs[i].u.ss;
+ }
+ srv->ss_s = tmp;
+ srv->num_ips = num_ips + num_addrs;
+
+done:
+ state->num_outstanding -= 1;
+ if (state->num_outstanding == 0) {
+ tevent_req_done(req);
+ }
+}
+
+static void dns_rr_srv_fill_done_a(struct tevent_req *subreq)
+{
+ dns_rr_srv_fill_done(subreq, ads_dns_lookup_a_recv);
+}
+
+#if defined(HAVE_IPV6)
+static void dns_rr_srv_fill_done_aaaa(struct tevent_req *subreq)
+{
+ dns_rr_srv_fill_done(subreq, ads_dns_lookup_aaaa_recv);
+}
+#endif
+
+static void dns_rr_srv_fill_timedout(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_rr_srv_fill_state *state = tevent_req_data(
+ req, struct dns_rr_srv_fill_state);
+ bool ok;
+
+ if (DEBUGLEVEL >= DBGLVL_INFO) {
+ size_t i, num_addrs = 0;
+
+ for (i=0; i<state->num_srvs; i++) {
+ /*
+ * Count for the debug. Code that fills this
+ * in ensures no wrap.
+ */
+ num_addrs += state->srvs[i].num_ips;
+ }
+
+ DBG_INFO("async DNS lookup timed out after %zu addresses "
+ "returned (not an error)\n",
+ num_addrs);
+ }
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ TALLOC_FREE(state->subreqs);
+ if (!ok) {
+ tevent_req_oom(subreq);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS dns_rr_srv_fill_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+/*
+ * Request a SRV record and fill in the A/AAAA records if the SRV
+ * record did not carry them.
+ */
+
+struct ads_dns_query_srv_state {
+ struct tevent_context *ev;
+ uint32_t async_dns_timeout;
+ const char *query;
+
+ struct tevent_req *fill_req;
+ struct tevent_req *timeout_req;
+ struct dns_rr_srv *srvs;
+ size_t num_srvs;
+};
+
+static void ads_dns_query_srv_site_aware_done(struct tevent_req *subreq);
+static void ads_dns_query_srv_done(struct tevent_req *subreq);
+static void ads_dns_query_srv_filled(struct tevent_req *subreq);
+
+struct tevent_req *ads_dns_query_srv_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t async_dns_timeout,
+ const char *sitename,
+ const char *query)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct ads_dns_query_srv_state *state = NULL;
+
+ req = tevent_req_create(
+ mem_ctx, &state, struct ads_dns_query_srv_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->async_dns_timeout = async_dns_timeout;
+ state->query = query;
+
+ if ((sitename != NULL) && (sitename[0] != '\0')) {
+ char *after_tcp = NULL;
+ char *site_aware = NULL;
+
+ /*
+ * ".<SITENAME>._sites" comes after "._tcp."
+ */
+ after_tcp = strstr(state->query, "._tcp.");
+ if (after_tcp == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ after_tcp += 6; /* strlen("._tcp.") */
+
+ site_aware = talloc_asprintf(
+ state,
+ "%.*s%s._sites.%s",
+ (int)(after_tcp - state->query),
+ state->query,
+ sitename,
+ after_tcp);
+ if (tevent_req_nomem(site_aware, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = ads_dns_lookup_srv_send(state, ev, site_aware);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ subreq, ads_dns_query_srv_site_aware_done, req);
+ return req;
+ }
+
+ subreq = ads_dns_lookup_srv_send(state, state->ev, state->query);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, ads_dns_query_srv_done, req);
+ return req;
+}
+
+static void ads_dns_query_srv_site_aware_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ads_dns_query_srv_state *state = tevent_req_data(
+ req, struct ads_dns_query_srv_state);
+ NTSTATUS status;
+
+ status = ads_dns_lookup_srv_recv(
+ subreq, state, &state->srvs, &state->num_srvs);
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (NT_STATUS_IS_OK(status) && (state->num_srvs != 0)) {
+ if (state->async_dns_timeout == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ subreq = dns_rr_srv_fill_send(
+ state,
+ state->ev,
+ state->srvs,
+ state->num_srvs,
+ state->async_dns_timeout);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(
+ subreq, ads_dns_query_srv_filled, req);
+ return;
+ }
+
+ subreq = ads_dns_lookup_srv_send(state, state->ev, state->query);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, ads_dns_query_srv_done, req);
+}
+
+static void ads_dns_query_srv_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ads_dns_query_srv_state *state = tevent_req_data(
+ req, struct ads_dns_query_srv_state);
+ NTSTATUS status;
+
+ status = ads_dns_lookup_srv_recv(
+ subreq, state, &state->srvs, &state->num_srvs);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if ((state->num_srvs == 0) || (state->async_dns_timeout == 0)) {
+ tevent_req_done(req);
+ return;
+ }
+
+ subreq = dns_rr_srv_fill_send(
+ state,
+ state->ev,
+ state->srvs,
+ state->num_srvs,
+ state->async_dns_timeout);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, ads_dns_query_srv_filled, req);
+}
+
+static void ads_dns_query_srv_filled(struct tevent_req *subreq)
+{
+ NTSTATUS status = dns_rr_srv_fill_recv(subreq);
+ return tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+NTSTATUS ads_dns_query_srv_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct dns_rr_srv **srvs,
+ size_t *num_srvs)
+{
+ struct ads_dns_query_srv_state *state = tevent_req_data(
+ req, struct ads_dns_query_srv_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ if (srvs != NULL) {
+ *srvs = talloc_move(mem_ctx, &state->srvs);
+ }
+ if (num_srvs != NULL) {
+ *num_srvs = state->num_srvs;
+ }
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ads_dns_query_srv(
+ TALLOC_CTX *mem_ctx,
+ uint32_t async_dns_timeout,
+ const char *sitename,
+ const char *query,
+ struct dns_rr_srv **srvs,
+ size_t *num_srvs)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = ads_dns_query_srv_send(
+ frame, ev, async_dns_timeout, sitename, query);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = ads_dns_query_srv_recv(req, mem_ctx, srvs, num_srvs);
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+char *ads_dns_query_string_dcs(TALLOC_CTX *mem_ctx, const char *realm)
+{
+ char *ret = talloc_asprintf(mem_ctx, "_ldap._tcp.dc._msdcs.%s", realm);
+ return ret;
+}
+
+char *ads_dns_query_string_gcs(TALLOC_CTX *mem_ctx, const char *realm)
+{
+ char *ret = talloc_asprintf(mem_ctx, "_ldap._tcp.gc._msdcs.%s", realm);
+ return ret;
+}
+
+char *ads_dns_query_string_kdcs(TALLOC_CTX *mem_ctx, const char *realm)
+{
+ char *ret = talloc_asprintf(
+ mem_ctx, "_kerberos._tcp.dc._msdcs.%s", realm);
+ return ret;
+}
+
+char *ads_dns_query_string_pdc(TALLOC_CTX *mem_ctx, const char *realm)
+{
+ char *ret = talloc_asprintf(
+ mem_ctx, "_ldap._tcp.pdc._msdcs.%s", realm);
+ return ret;
+}
+
+char *ads_dns_query_string_dcs_guid(
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *domain_guid,
+ const char *realm)
+{
+ struct GUID_txt_buf buf;
+ char *ret = NULL;
+
+ talloc_asprintf(
+ mem_ctx,
+ "_ldap._tcp.%s.domains._msdcs.%s",
+ GUID_buf_string(domain_guid, &buf),
+ realm);
+ return ret;
+}
diff --git a/lib/addns/dnsquery_srv.h b/lib/addns/dnsquery_srv.h
new file mode 100644
index 0000000..d10c74e
--- /dev/null
+++ b/lib/addns/dnsquery_srv.h
@@ -0,0 +1,54 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_ADDNS_DNSQUERY_SRV_H__
+#define __LIB_ADDNS_DNSQUERY_SRV_H__
+
+#include "replace.h"
+#include <tevent.h>
+#include "libcli/util/ntstatus.h"
+#include "libcli/dns/dns.h"
+
+struct tevent_req *ads_dns_query_srv_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t async_dns_timeout,
+ const char *sitename,
+ const char *query);
+NTSTATUS ads_dns_query_srv_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct dns_rr_srv **srvs,
+ size_t *num_srvs);
+NTSTATUS ads_dns_query_srv(
+ TALLOC_CTX *mem_ctx,
+ uint32_t async_dns_timeout,
+ const char *sitename,
+ const char *query,
+ struct dns_rr_srv **srvs,
+ size_t *num_srvs);
+
+char *ads_dns_query_string_dcs(TALLOC_CTX *mem_ctx, const char *realm);
+char *ads_dns_query_string_gcs(TALLOC_CTX *mem_ctx, const char *realm);
+char *ads_dns_query_string_kdcs(TALLOC_CTX *mem_ctx, const char *realm);
+char *ads_dns_query_string_pdc(TALLOC_CTX *mem_ctx, const char *realm);
+
+struct GUID;
+char *ads_dns_query_string_dcs_guid(
+ TALLOC_CTX *mem_ctx,
+ const struct GUID *domain_guid,
+ const char *realm);
+
+#endif /* _ADS_DNS_H */
diff --git a/lib/addns/dnsrecord.c b/lib/addns/dnsrecord.c
new file mode 100644
index 0000000..c1a6595
--- /dev/null
+++ b/lib/addns/dnsrecord.c
@@ -0,0 +1,484 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include "lib/util/genrand.h"
+
+DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
+ uint16_t q_type, uint16_t q_class,
+ struct dns_request **preq )
+{
+ struct dns_request *req = NULL;
+ struct dns_question *q = NULL;
+ DNS_ERROR err;
+
+ if (!(req = talloc_zero(mem_ctx, struct dns_request)) ||
+ !(req->questions = talloc_array(req, struct dns_question *, 1)) ||
+ !(req->questions[0] = talloc(req->questions,
+ struct dns_question))) {
+ TALLOC_FREE(req);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ generate_random_buffer((uint8_t *)&req->id, sizeof(req->id));
+
+ req->num_questions = 1;
+ q = req->questions[0];
+
+ err = dns_domain_name_from_string(q, name, &q->name);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(req);
+ return err;
+ }
+
+ q->q_type = q_type;
+ q->q_class = q_class;
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
+ struct dns_update_request **preq )
+{
+ struct dns_update_request *req = NULL;
+ struct dns_zone *z = NULL;
+ DNS_ERROR err;
+
+ if (!(req = talloc_zero(mem_ctx, struct dns_update_request)) ||
+ !(req->zones = talloc_array(req, struct dns_zone *, 1)) ||
+ !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
+ TALLOC_FREE(req);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ req->id = random();
+ req->flags = 0x2800; /* Dynamic update */
+
+ req->num_zones = 1;
+ z = req->zones[0];
+
+ err = dns_domain_name_from_string(z, name, &z->name);
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(req);
+ return err;
+ }
+
+ z->z_type = QTYPE_SOA;
+ z->z_class = DNS_CLASS_IN;
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
+ uint16_t type, uint16_t r_class, uint32_t ttl,
+ uint16_t data_length, uint8_t *data,
+ struct dns_rrec **prec)
+{
+ struct dns_rrec *rec = NULL;
+ DNS_ERROR err;
+
+ if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(rec, name, &rec->name);
+ if (!(ERR_DNS_IS_OK(err))) {
+ TALLOC_FREE(rec);
+ return err;
+ }
+
+ rec->type = type;
+ rec->r_class = r_class;
+ rec->ttl = ttl;
+ rec->data_length = data_length;
+ rec->data = talloc_move(rec, &data);
+
+ *prec = rec;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32_t ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec)
+{
+ uint8_t *data;
+ DNS_ERROR err;
+ struct in_addr ip;
+
+ if (pss->ss_family != AF_INET) {
+ return ERROR_DNS_INVALID_PARAMETER;
+ }
+
+ ip = ((const struct sockaddr_in *)pss)->sin_addr;
+ if (!(data = (uint8_t *)talloc_memdup(mem_ctx, (const void *)&ip.s_addr,
+ sizeof(ip.s_addr)))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
+ sizeof(ip.s_addr), data, prec);
+
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(data);
+ }
+
+ return err;
+}
+
+DNS_ERROR dns_create_aaaa_record(TALLOC_CTX *mem_ctx, const char *host,
+ uint32_t ttl, const struct sockaddr_storage *pss,
+ struct dns_rrec **prec)
+{
+#ifdef HAVE_IPV6
+ uint8_t *data;
+ DNS_ERROR err;
+ struct in6_addr ip6;
+
+ if (pss->ss_family != AF_INET6) {
+ return ERROR_DNS_INVALID_PARAMETER;
+ }
+
+ ip6 = ((const struct sockaddr_in6 *)pss)->sin6_addr;
+ if (!(data = (uint8_t *)talloc_memdup(mem_ctx, (const void *)&ip6.s6_addr,
+ sizeof(ip6.s6_addr)))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_create_rrec(mem_ctx, host, QTYPE_AAAA, DNS_CLASS_IN, ttl,
+ sizeof(ip6.s6_addr), data, prec);
+
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(data);
+ }
+
+ return err;
+#else
+ return ERROR_DNS_INVALID_PARAMETER;
+#endif
+}
+
+DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct sockaddr_storage *ss,
+ struct dns_rrec **prec)
+{
+ if (ss != NULL) {
+ switch (ss->ss_family) {
+ case AF_INET:
+ return dns_create_a_record(mem_ctx, name, 0, ss, prec);
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return dns_create_aaaa_record(mem_ctx, name, 0, ss, prec);
+#endif
+ default:
+ return ERROR_DNS_INVALID_PARAMETER;
+ }
+ }
+
+ return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
+ NULL, prec);
+}
+
+DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
+ const char *name, uint32_t type,
+ struct dns_rrec **prec)
+{
+ return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
+ 0, NULL, prec);
+}
+
+DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
+ uint16_t type, uint16_t r_class,
+ struct dns_rrec **prec)
+{
+ return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
+}
+
+DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name, time_t inception,
+ time_t expiration, uint16_t mode, uint16_t error,
+ uint16_t key_length, const uint8_t *key,
+ struct dns_rrec **prec)
+{
+ struct dns_buffer *buf = NULL;
+ struct dns_domain_name *algorithm = NULL;
+ DNS_ERROR err;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint32(buf, inception);
+ dns_marshall_uint32(buf, expiration);
+ dns_marshall_uint16(buf, mode);
+ dns_marshall_uint16(buf, error);
+ dns_marshall_uint16(buf, key_length);
+ dns_marshall_buffer(buf, key, key_length);
+ dns_marshall_uint16(buf, 0); /* Other Size */
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
+ buf->offset, buf->data, prec);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ struct dns_tkey_record **ptkey)
+{
+ struct dns_tkey_record *tkey;
+ struct dns_buffer buf;
+ uint32_t tmp_inception, tmp_expiration;
+
+ if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ buf.data = rec->data;
+ buf.size = rec->data_length;
+ buf.offset = 0;
+ buf.error = ERROR_DNS_SUCCESS;
+
+ dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
+ dns_unmarshall_uint32(&buf, &tmp_inception);
+ dns_unmarshall_uint32(&buf, &tmp_expiration);
+ dns_unmarshall_uint16(&buf, &tkey->mode);
+ dns_unmarshall_uint16(&buf, &tkey->error);
+ dns_unmarshall_uint16(&buf, &tkey->key_length);
+
+ if (!ERR_DNS_IS_OK(buf.error)) goto error;
+
+ if (tkey->key_length) {
+ if (!(tkey->key = talloc_array(tkey, uint8_t, tkey->key_length))) {
+ buf.error = ERROR_DNS_NO_MEMORY;
+ goto error;
+ }
+ } else {
+ tkey->key = NULL;
+ }
+
+ dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
+ if (!ERR_DNS_IS_OK(buf.error)) goto error;
+
+ tkey->inception = (time_t)tmp_inception;
+ tkey->expiration = (time_t)tmp_expiration;
+
+ *ptkey = tkey;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(tkey);
+ return buf.error;
+}
+
+DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
+ const char *algorithm_name,
+ time_t time_signed, uint16_t fudge,
+ uint16_t mac_length, const uint8_t *mac,
+ uint16_t original_id, uint16_t error,
+ struct dns_rrec **prec)
+{
+ struct dns_buffer *buf = NULL;
+ struct dns_domain_name *algorithm = NULL;
+ DNS_ERROR err;
+
+ if (!(buf = dns_create_buffer(mem_ctx))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ dns_marshall_domain_name(buf, algorithm);
+ dns_marshall_uint16(buf, 0); /* time prefix */
+ dns_marshall_uint32(buf, time_signed);
+ dns_marshall_uint16(buf, fudge);
+ dns_marshall_uint16(buf, mac_length);
+ dns_marshall_buffer(buf, mac, mac_length);
+ dns_marshall_uint16(buf, original_id);
+ dns_marshall_uint16(buf, error);
+ dns_marshall_uint16(buf, 0); /* Other Size */
+
+ if (!ERR_DNS_IS_OK(buf->error)) {
+ err = buf->error;
+ goto error;
+ }
+
+ err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
+ buf->offset, buf->data, prec);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
+ uint16_t *num_records, struct dns_rrec ***records)
+{
+ struct dns_rrec **new_records;
+
+ if (!(new_records = talloc_realloc(mem_ctx, *records,
+ struct dns_rrec *,
+ (*num_records)+1))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ new_records[*num_records] = talloc_move(new_records, &rec);
+
+ *num_records += 1;
+ *records = new_records;
+ return ERROR_DNS_SUCCESS;
+}
+
+/*
+ * Create a request that probes a server whether the list of IP addresses
+ * provides meets our expectations
+ */
+
+DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
+ const char *host, int num_ips,
+ const struct sockaddr_storage *sslist,
+ struct dns_update_request **preq)
+{
+ struct dns_update_request *req = NULL;
+ struct dns_rrec *rec = NULL;
+ DNS_ERROR err;
+ uint16_t i;
+
+ err = dns_create_update(mem_ctx, zone, &req);
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ for (i=0; i<num_ips; i++) {
+ err = dns_create_name_in_use_record(req, host,
+ &sslist[i], &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(req);
+ return err;
+}
+
+DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
+ const char *domainname,
+ const char *hostname,
+ const struct sockaddr_storage *ss_addrs,
+ size_t num_addrs,
+ uint32_t ttl,
+ struct dns_update_request **preq)
+{
+ struct dns_update_request *req = NULL;
+ struct dns_rrec *rec = NULL;
+ DNS_ERROR err;
+ size_t i;
+
+ err = dns_create_update(mem_ctx, domainname, &req);
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ /*
+ * Use the same prereq as WinXP -- No CNAME records for this host.
+ */
+
+ err = dns_create_rrec(req, hostname, QTYPE_CNAME, DNS_CLASS_NONE,
+ 0, 0, NULL, &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * Delete all existing RRsets from our name
+ */
+
+ err = dns_create_delete_record(req, hostname, QTYPE_ANY, DNS_CLASS_ANY,
+ &rec);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ /*
+ * .. and add our IPs
+ */
+
+ for ( i=0; i<num_addrs; i++ ) {
+
+ switch(ss_addrs[i].ss_family) {
+ case AF_INET:
+ err = dns_create_a_record(req,
+ hostname,
+ ttl,
+ &ss_addrs[i],
+ &rec);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ err = dns_create_aaaa_record(req,
+ hostname,
+ ttl,
+ &ss_addrs[i],
+ &rec);
+ break;
+#endif
+ default:
+ continue;
+ }
+ if (!ERR_DNS_IS_OK(err))
+ goto error;
+
+ err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
+ if (!ERR_DNS_IS_OK(err))
+ goto error;
+ }
+
+ *preq = req;
+ return ERROR_DNS_SUCCESS;
+
+ error:
+ TALLOC_FREE(req);
+ return err;
+}
diff --git a/lib/addns/dnssock.c b/lib/addns/dnssock.c
new file mode 100644
index 0000000..11f2e00
--- /dev/null
+++ b/lib/addns/dnssock.c
@@ -0,0 +1,420 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "dns.h"
+#include <sys/time.h>
+#include <unistd.h>
+#include "system/select.h"
+#include "../lib/util/debug.h"
+
+static int destroy_dns_connection(struct dns_connection *conn)
+{
+ return close(conn->s);
+}
+
+/********************************************************************
+********************************************************************/
+
+static DNS_ERROR dns_open_helper(const char *nameserver,
+ const char *service,
+ struct addrinfo *hints,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **ret_conn)
+{
+ int ret;
+ struct addrinfo *rp;
+ struct addrinfo *ai_result = NULL;
+ struct dns_connection *conn = NULL;
+
+ if (!(conn = talloc(mem_ctx, struct dns_connection))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ ret = getaddrinfo(nameserver, service, hints, &ai_result);
+ if (ret != 0) {
+ DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
+ TALLOC_FREE(conn);
+ return ERROR_DNS_INVALID_NAME_SERVER;
+ }
+
+ for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
+ conn->s = socket(rp->ai_family,
+ rp->ai_socktype,
+ rp->ai_protocol);
+ if (conn->s == -1) {
+ continue;
+ }
+ do {
+ ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
+ } while ((ret == -1) && (errno == EINTR));
+ if (ret != -1) {
+ /* Successful connect */
+ break;
+ }
+ close(conn->s);
+ }
+
+ freeaddrinfo(ai_result);
+
+ if (rp == NULL) {
+ TALLOC_FREE(conn);
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ talloc_set_destructor(conn, destroy_dns_connection);
+
+ *ret_conn = conn;
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_tcp_open( const char *nameserver,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **result )
+{
+ struct addrinfo hints;
+ struct dns_connection *conn;
+ DNS_ERROR dns_ret;
+ char service[16];
+
+ snprintf(service, sizeof(service), "%d", DNS_TCP_PORT);
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
+ if (!ERR_DNS_IS_OK(dns_ret)) {
+ return dns_ret;
+ }
+
+ conn->hType = DNS_TCP;
+ *result = conn;
+ return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+ * ********************************************************************/
+
+static DNS_ERROR dns_udp_open( const char *nameserver,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **result )
+{
+ struct addrinfo hints;
+ struct sockaddr_storage RecvAddr;
+ struct dns_connection *conn = NULL;
+ DNS_ERROR dns_ret;
+ socklen_t RecvAddrLen;
+ char service[16];
+
+ snprintf(service, sizeof(service), "%d", DNS_UDP_PORT);
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
+ if (!ERR_DNS_IS_OK(dns_ret)) {
+ TALLOC_FREE(conn);
+ return dns_ret;
+ }
+
+ /* Set up the RecvAddr structure with the IP address of
+ the receiver and the specified port number. */
+
+ RecvAddrLen = sizeof(RecvAddr);
+ if (getpeername(conn->s,
+ (struct sockaddr *)&RecvAddr,
+ &RecvAddrLen) == -1) {
+ return ERROR_DNS_CONNECTION_FAILED;
+ }
+
+ conn->hType = DNS_UDP;
+ memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage));
+
+ *result = conn;
+ return ERROR_DNS_SUCCESS;
+}
+
+/********************************************************************
+********************************************************************/
+
+DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
+ TALLOC_CTX *mem_ctx,
+ struct dns_connection **conn )
+{
+ switch ( dwType ) {
+ case DNS_TCP:
+ return dns_tcp_open( nameserver, mem_ctx, conn );
+ case DNS_UDP:
+ return dns_udp_open( nameserver, mem_ctx, conn );
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
+{
+ size_t total = 0;
+
+ while (total < len) {
+
+ ssize_t ret;
+
+ do {
+ ret = write(fd, data + total, len - total);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret <= 0) {
+ /*
+ * EOF or error
+ */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ total += ret;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
+ const struct dns_buffer *buf)
+{
+ uint16_t len = htons(buf->offset);
+ DNS_ERROR err;
+
+ err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ return write_all(conn->s, buf->data, buf->offset);
+}
+
+static DNS_ERROR dns_send_udp(struct dns_connection *conn,
+ const struct dns_buffer *buf)
+{
+ ssize_t ret;
+
+ do {
+ ret = send(conn->s, buf->data, buf->offset, 0);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret != buf->offset) {
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
+{
+ if (conn->hType == DNS_TCP) {
+ return dns_send_tcp(conn, buf);
+ }
+
+ if (conn->hType == DNS_UDP) {
+ return dns_send_udp(conn, buf);
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
+{
+ size_t total = 0;
+
+ while (total < len) {
+ struct pollfd pfd;
+ ssize_t ret;
+ int fd_ready;
+
+ ZERO_STRUCT(pfd);
+ pfd.fd = fd;
+ pfd.events = POLLIN|POLLHUP;
+
+ fd_ready = poll(&pfd, 1, 10000);
+ if (fd_ready == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+ if ( fd_ready == 0 ) {
+ /* read timeout */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ do {
+ ret = read(fd, data + total, len - total);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret <= 0) {
+ /* EOF or error */
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ total += ret;
+ }
+
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ struct dns_buffer *buf;
+ DNS_ERROR err;
+ uint16_t len;
+
+ if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
+ if (!ERR_DNS_IS_OK(err)) {
+ return err;
+ }
+
+ buf->size = ntohs(len);
+
+ if (buf->size == 0) {
+ *presult = buf;
+ return ERROR_DNS_SUCCESS;
+ }
+
+ if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = read_all(conn->s, buf->data, talloc_get_size(buf->data));
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(buf);
+ return err;
+ }
+
+ *presult = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ struct dns_buffer *buf;
+ ssize_t received;
+
+ if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ /*
+ * UDP based DNS can only be 512 bytes
+ */
+
+ if (!(buf->data = talloc_array(buf, uint8_t, 512))) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ do {
+ received = recv(conn->s, (void *)buf->data, 512, 0);
+ } while ((received == -1) && (errno == EINTR));
+
+ if (received == -1) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_SOCKET_ERROR;
+ }
+
+ if (received > 512) {
+ TALLOC_FREE(buf);
+ return ERROR_DNS_BAD_RESPONSE;
+ }
+
+ buf->size = received;
+ buf->offset = 0;
+
+ *presult = buf;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ struct dns_buffer **presult)
+{
+ if (conn->hType == DNS_TCP) {
+ return dns_receive_tcp(mem_ctx, conn, presult);
+ }
+
+ if (conn->hType == DNS_UDP) {
+ return dns_receive_udp(mem_ctx, conn, presult);
+ }
+
+ return ERROR_DNS_INVALID_PARAMETER;
+}
+
+DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
+ const struct dns_request *req,
+ struct dns_request **resp)
+{
+ struct dns_buffer *buf = NULL;
+ DNS_ERROR err;
+
+ err = dns_marshall_request(mem_ctx, req, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_send(conn, buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+ TALLOC_FREE(buf);
+
+ err = dns_receive(mem_ctx, conn, &buf);
+ if (!ERR_DNS_IS_OK(err)) goto error;
+
+ err = dns_unmarshall_request(mem_ctx, buf, resp);
+
+ error:
+ TALLOC_FREE(buf);
+ return err;
+}
+
+DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
+ struct dns_connection *conn,
+ struct dns_update_request *up_req,
+ struct dns_update_request **up_resp)
+{
+ struct dns_request *resp;
+ DNS_ERROR err;
+
+ err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
+ &resp);
+
+ if (!ERR_DNS_IS_OK(err)) return err;
+
+ *up_resp = dns_request2update(resp);
+ return ERROR_DNS_SUCCESS;
+}
diff --git a/lib/addns/dnsutils.c b/lib/addns/dnsutils.c
new file mode 100644
index 0000000..d1a3173
--- /dev/null
+++ b/lib/addns/dnsutils.c
@@ -0,0 +1,149 @@
+/*
+ Linux DNS client library implementation
+
+ Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
+ Copyright (C) 2006 Gerald Carter <jerry@samba.org>
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+
+#include "dns.h"
+#include <ctype.h>
+
+
+static DNS_ERROR LabelList( TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct dns_domain_label **presult )
+{
+ struct dns_domain_label *result;
+ const char *dot;
+
+ for (dot = name; *dot != '\0'; dot += 1) {
+ char c = *dot;
+
+ if (c == '.')
+ break;
+
+ if (c == '-') continue;
+ if ((c >= 'a') && (c <= 'z')) continue;
+ if ((c >= 'A') && (c <= 'Z')) continue;
+ if ((c >= '0') && (c <= '9')) continue;
+
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if ((dot - name) > 63) {
+ /*
+ * DNS labels can only be 63 chars long
+ */
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if (!(result = talloc_zero(mem_ctx, struct dns_domain_label))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ if (*dot == '\0') {
+ /*
+ * No dot around, so this is the last component
+ */
+
+ if (!(result->label = talloc_strdup(result, name))) {
+ TALLOC_FREE(result);
+ return ERROR_DNS_NO_MEMORY;
+ }
+ result->len = strlen(result->label);
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+ }
+
+ if (dot[1] == '.') {
+ /*
+ * Two dots in a row, reject
+ */
+
+ TALLOC_FREE(result);
+ return ERROR_DNS_INVALID_NAME;
+ }
+
+ if (dot[1] != '\0') {
+ /*
+ * Something follows, get the rest
+ */
+
+ DNS_ERROR err = LabelList(result, dot+1, &result->next);
+
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(result);
+ return err;
+ }
+ }
+
+ result->len = (dot - name);
+
+ if (!(result->label = talloc_strndup(result, name, result->len))) {
+ TALLOC_FREE(result);
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+}
+
+DNS_ERROR dns_domain_name_from_string( TALLOC_CTX *mem_ctx,
+ const char *pszDomainName,
+ struct dns_domain_name **presult )
+{
+ struct dns_domain_name *result;
+ DNS_ERROR err;
+
+ if (!(result = talloc(mem_ctx, struct dns_domain_name))) {
+ return ERROR_DNS_NO_MEMORY;
+ }
+
+ err = LabelList( result, pszDomainName, &result->pLabelList );
+ if (!ERR_DNS_IS_OK(err)) {
+ TALLOC_FREE(result);
+ return err;
+ }
+
+ *presult = result;
+ return ERROR_DNS_SUCCESS;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+char *dns_generate_keyname( TALLOC_CTX *mem_ctx )
+{
+ char *result = NULL;
+#if defined(HAVE_KRB5)
+
+ struct GUID guid;
+
+ guid = GUID_random();
+ result = GUID_string(mem_ctx, &guid);
+
+#endif
+
+ return result;
+}
diff --git a/lib/addns/error.c b/lib/addns/error.c
new file mode 100644
index 0000000..361388c
--- /dev/null
+++ b/lib/addns/error.c
@@ -0,0 +1,59 @@
+/*
+ Linux DNS client library implementation
+ Copyright (C) 2010 Guenther Deschner
+
+ ** NOTE! The following LGPL license applies to the libaddns
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dns.h"
+#include "dnserr.h"
+
+typedef struct {
+ const char *dns_errstr;
+ DNS_ERROR dns_errcode;
+} dns_err_code_struct;
+
+static const dns_err_code_struct dns_errs[] =
+{
+ { "ERROR_DNS_SUCCESS", ERROR_DNS_SUCCESS },
+ { "ERROR_DNS_RECORD_NOT_FOUND", ERROR_DNS_RECORD_NOT_FOUND },
+ { "ERROR_DNS_BAD_RESPONSE", ERROR_DNS_BAD_RESPONSE },
+ { "ERROR_DNS_INVALID_PARAMETER", ERROR_DNS_INVALID_PARAMETER },
+ { "ERROR_DNS_NO_MEMORY", ERROR_DNS_NO_MEMORY },
+ { "ERROR_DNS_INVALID_NAME_SERVER", ERROR_DNS_INVALID_NAME_SERVER },
+ { "ERROR_DNS_CONNECTION_FAILED", ERROR_DNS_CONNECTION_FAILED },
+ { "ERROR_DNS_GSS_ERROR", ERROR_DNS_GSS_ERROR },
+ { "ERROR_DNS_INVALID_NAME", ERROR_DNS_INVALID_NAME },
+ { "ERROR_DNS_INVALID_MESSAGE", ERROR_DNS_INVALID_MESSAGE },
+ { "ERROR_DNS_SOCKET_ERROR", ERROR_DNS_SOCKET_ERROR },
+ { "ERROR_DNS_UPDATE_FAILED", ERROR_DNS_UPDATE_FAILED },
+ { NULL, ERROR_DNS_SUCCESS },
+};
+
+const char *dns_errstr(DNS_ERROR err)
+{
+ int i;
+
+ for (i=0; dns_errs[i].dns_errstr != NULL; i++) {
+ if (ERR_DNS_EQUAL(err, dns_errs[i].dns_errcode)) {
+ return dns_errs[i].dns_errstr;
+ }
+ }
+
+ return NULL;
+}
diff --git a/lib/addns/wscript_build b/lib/addns/wscript_build
new file mode 100644
index 0000000..cc72b35
--- /dev/null
+++ b/lib/addns/wscript_build
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('addns',
+ source='''
+ dnsquery.c
+ dnsrecord.c
+ dnsutils.c
+ dnssock.c
+ dnsgss.c
+ dnsmarshall.c
+ error.c
+ dnsquery_srv.c
+ ''',
+ public_deps='samba-util gssapi ndr resolv dns_lookup',
+ private_library=True,
+ vars=locals())
diff --git a/lib/afs/afs_funcs.c b/lib/afs/afs_funcs.c
new file mode 100644
index 0000000..4360f54
--- /dev/null
+++ b/lib/afs/afs_funcs.c
@@ -0,0 +1,313 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generate AFS tickets
+ * Copyright (C) Volker Lendecke 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/afs/afs_funcs.h"
+
+#ifdef WITH_FAKE_KASERVER
+
+#define NO_ASN1_TYPEDEFS 1
+
+#include "secrets.h"
+#include "passdb.h"
+#include "auth.h"
+#include "../librpc/gen_ndr/ndr_netlogon.h"
+#include "lib/afs/afs_settoken.h"
+
+#include <afs/param.h>
+#include <afs/stds.h>
+#include <afs/auth.h>
+#include <afs/venus.h>
+#include <asm/unistd.h>
+#include <openssl/des.h>
+
+struct ClearToken {
+ uint32 AuthHandle;
+ char HandShakeKey[8];
+ uint32 ViceId;
+ uint32 BeginTimestamp;
+ uint32 EndTimestamp;
+};
+
+static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
+ const struct ClearToken *ct)
+{
+ char *base64_ticket;
+ char *result = NULL;
+
+ DATA_BLOB key = data_blob(ct->HandShakeKey, 8);
+ char *base64_key;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_stackframe();
+ if (mem_ctx == NULL)
+ goto done;
+
+ base64_ticket = base64_encode_data_blob(mem_ctx, ticket);
+ if (base64_ticket == NULL)
+ goto done;
+
+ base64_key = base64_encode_data_blob(mem_ctx, key);
+ if (base64_key == NULL)
+ goto done;
+
+ asprintf(&result, "%s\n%u\n%s\n%u\n%u\n%u\n%s\n", cell,
+ ct->AuthHandle, base64_key, ct->ViceId, ct->BeginTimestamp,
+ ct->EndTimestamp, base64_ticket);
+
+ DEBUG(10, ("Got ticket string:\n%s\n", result));
+
+done:
+ TALLOC_FREE(mem_ctx);
+
+ return result;
+}
+
+/* Create a ClearToken and an encrypted ticket. ClearToken has not yet the
+ * ViceId set, this should be set by the caller. */
+
+static bool afs_createtoken(const char *username, const char *cell,
+ DATA_BLOB *ticket, struct ClearToken *ct)
+{
+ fstring clear_ticket;
+ char *p = clear_ticket;
+ uint32 len;
+ uint32 now;
+
+ struct afs_key key;
+ des_key_schedule key_schedule;
+
+ if (!secrets_init())
+ return false;
+
+ if (!secrets_fetch_afs_key(cell, &key)) {
+ DEBUG(1, ("Could not fetch AFS service key\n"));
+ return false;
+ }
+
+ ct->AuthHandle = key.kvno;
+
+ /* Build the ticket. This is going to be encrypted, so in our
+ way we fill in ct while we still have the unencrypted
+ form. */
+
+ p = clear_ticket;
+
+ /* The byte-order */
+ *p = 1;
+ p += 1;
+
+ /* "Alice", the client username */
+ strncpy(p, username, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, cell, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+
+ /* Alice's network layer address. At least Openafs-1.2.10
+ ignores this, so we fill in a dummy value here. */
+ SIVAL(p, 0, 0);
+ p += 4;
+
+ /* We need to create a session key */
+ generate_random_buffer((uint8_t *)p, 8);
+
+ /* Our client code needs the the key in the clear, it does not
+ know the server-key ... */
+ memcpy(ct->HandShakeKey, p, 8);
+
+ p += 8;
+
+ /* This is a kerberos 4 life time. The life time is expressed
+ * in units of 5 minute intervals up to 38400 seconds, after
+ * that a table is used up to lifetime 0xBF. Values between
+ * 0xC0 and 0xFF is undefined. 0xFF is defined to be the
+ * infinite time that never expire.
+ *
+ * So here we cheat and use the infinite time */
+ *p = 255;
+ p += 1;
+
+ /* Ticket creation time */
+ now = time(NULL);
+ SIVAL(p, 0, now);
+ ct->BeginTimestamp = now;
+
+ if(lp_afs_token_lifetime() == 0)
+ ct->EndTimestamp = NEVERDATE;
+ else
+ ct->EndTimestamp = now + lp_afs_token_lifetime();
+
+ if (((ct->EndTimestamp - ct->BeginTimestamp) & 1) == 1) {
+ ct->BeginTimestamp += 1; /* Lifetime must be even */
+ }
+ p += 4;
+
+ /* And here comes Bob's name and instance, in this case the
+ AFS server. */
+ strncpy(p, "afs", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1);
+ p += strlen(p)+1;
+
+ /* And zero-pad to a multiple of 8 bytes */
+ len = PTR_DIFF(p, clear_ticket);
+ if (len & 7) {
+ uint32 extra_space = 8-(len & 7);
+ memset(p, 0, extra_space);
+ p+=extra_space;
+ }
+ len = PTR_DIFF(p, clear_ticket);
+
+ des_key_sched((const_des_cblock *)key.key, key_schedule);
+ des_pcbc_encrypt((const unsigned char*) clear_ticket,
+ (unsigned char*) clear_ticket,
+ len, key_schedule, (C_Block *)key.key, 1);
+
+ ZERO_STRUCT(key);
+
+ *ticket = data_blob(clear_ticket, len);
+
+ return true;
+}
+
+char *afs_createtoken_str(const char *username, const char *cell)
+{
+ DATA_BLOB ticket;
+ struct ClearToken ct;
+ char *result;
+
+ if (!afs_createtoken(username, cell, &ticket, &ct))
+ return NULL;
+
+ result = afs_encode_token(cell, ticket, &ct);
+
+ data_blob_free(&ticket);
+
+ return result;
+}
+
+/*
+ This routine takes a radical approach completely bypassing the
+ Kerberos idea of security and using AFS simply as an intelligent
+ file backend. Samba has persuaded itself somehow that the user is
+ actually correctly identified and then we create a ticket that the
+ AFS server hopefully accepts using its KeyFile that the admin has
+ kindly stored to our secrets.tdb.
+
+ Thanks to the book "Network Security -- PRIVATE Communication in a
+ PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner
+ Kerberos 4 tickets are not really hard to construct.
+
+ For the comments "Alice" is the User to be auth'ed, and "Bob" is the
+ AFS server. */
+
+bool afs_login(connection_struct *conn)
+{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ DATA_BLOB ticket;
+ char *afs_username = NULL;
+ char *cell = NULL;
+ bool result;
+ char *ticket_str = NULL;
+ const struct dom_sid *user_sid;
+ TALLOC_CTX *ctx = talloc_tos();
+ struct dom_sid_buf buf;
+
+ struct ClearToken ct;
+
+ afs_username = talloc_strdup(ctx,
+ lp_afs_username_map());
+ if (!afs_username) {
+ return false;
+ }
+
+ afs_username = talloc_sub_advanced(ctx,
+ lp_servicename(ctx, lp_sub, SNUM(conn)),
+ conn->session_info->unix_info->unix_name,
+ conn->connectpath,
+ conn->session_info->unix_token->gid,
+ conn->session_info->unix_info->sanitized_username,
+ conn->session_info->info->domain_name,
+ afs_username);
+ if (!afs_username) {
+ return false;
+ }
+
+ user_sid = &conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+ afs_username = talloc_string_sub(talloc_tos(),
+ afs_username,
+ "%s",
+ dom_sid_str_buf(user_sid, &buf));
+ if (!afs_username) {
+ return false;
+ }
+
+ /* The pts command always generates completely lower-case user
+ * names. */
+ if (!strlower_m(afs_username)) {
+ return false;
+ }
+
+ cell = strchr(afs_username, '@');
+
+ if (cell == NULL) {
+ DEBUG(1, ("AFS username doesn't contain a @, "
+ "could not find cell\n"));
+ return false;
+ }
+
+ *cell = '\0';
+ cell += 1;
+
+ DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
+ afs_username, cell));
+
+ if (!afs_createtoken(afs_username, cell, &ticket, &ct))
+ return false;
+
+ /* For which Unix-UID do we want to set the token? */
+ ct.ViceId = getuid();
+
+ ticket_str = afs_encode_token(cell, ticket, &ct);
+
+ result = afs_settoken_str(ticket_str);
+
+ SAFE_FREE(ticket_str);
+
+ data_blob_free(&ticket);
+
+ return result;
+}
+
+#else
+
+bool afs_login(connection_struct *conn)
+{
+ return true;
+}
+
+char *afs_createtoken_str(const char *username, const char *cell)
+{
+ return NULL;
+}
+
+#endif /* WITH_FAKE_KASERVER */
diff --git a/lib/afs/afs_funcs.h b/lib/afs/afs_funcs.h
new file mode 100644
index 0000000..95e916b
--- /dev/null
+++ b/lib/afs/afs_funcs.h
@@ -0,0 +1,42 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generate AFS tickets
+ * Copyright (C) Volker Lendecke 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIB_AFS_AFS_FUNCS_H
+#define LIB_AFS_AFS_FUNCS_H 1
+
+char *afs_createtoken_str(const char *username, const char *cell);
+
+/*
+ This routine takes a radical approach completely bypassing the
+ Kerberos idea of security and using AFS simply as an intelligent
+ file backend. Samba has persuaded itself somehow that the user is
+ actually correctly identified and then we create a ticket that the
+ AFS server hopefully accepts using its KeyFile that the admin has
+ kindly stored to our secrets.tdb.
+
+ Thanks to the book "Network Security -- PRIVATE Communication in a
+ PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner
+ Kerberos 4 tickets are not really hard to construct.
+
+ For the comments "Alice" is the User to be auth'ed, and "Bob" is the
+ AFS server. */
+
+bool afs_login(connection_struct *conn);
+
+#endif
diff --git a/lib/afs/afs_settoken.c b/lib/afs/afs_settoken.c
new file mode 100644
index 0000000..d0ffa49
--- /dev/null
+++ b/lib/afs/afs_settoken.c
@@ -0,0 +1,264 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generate AFS tickets
+ * Copyright (C) Volker Lendecke 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/afs/afs_settoken.h"
+
+#ifdef WITH_FAKE_KASERVER
+
+#define NO_ASN1_TYPEDEFS 1
+
+#include "system/filesys.h"
+
+#include <afs/param.h>
+#include <afs/stds.h>
+#include <afs/afs_args.h>
+#include <afs/auth.h>
+#include <afs/venus.h>
+#include <asm/unistd.h>
+#include <openssl/des.h>
+#include <sys/syscall.h>
+
+int afs_syscall(int subcall, const char *path, int cmd, char *cmarg, int follow)
+{
+/*
+ return( syscall( SYS_afs_syscall, subcall, path, cmd, cmarg, follow));
+*/
+ int errcode;
+ int proc_afs_file;
+ struct afsprocdata afs_syscall_data;
+ afs_syscall_data.syscall = subcall;
+ afs_syscall_data.param1 = (long)path;
+ afs_syscall_data.param2 = cmd;
+ afs_syscall_data.param3 = (long)cmarg;
+ afs_syscall_data.param4 = follow;
+ proc_afs_file = open(PROC_SYSCALL_FNAME, O_RDWR);
+ if (proc_afs_file < 0)
+ proc_afs_file = open(PROC_SYSCALL_ARLA_FNAME, O_RDWR);
+ if (proc_afs_file < 0)
+ return -1;
+ errcode = ioctl(proc_afs_file, VIOC_SYSCALL, &afs_syscall_data);
+ close(proc_afs_file);
+ return errcode;
+}
+
+struct ClearToken {
+ uint32 AuthHandle;
+ char HandShakeKey[8];
+ uint32 ViceId;
+ uint32 BeginTimestamp;
+ uint32 EndTimestamp;
+};
+
+static bool afs_decode_token(const char *string, char **cell,
+ DATA_BLOB *ticket, struct ClearToken *ct)
+{
+ DATA_BLOB blob;
+ struct ClearToken result_ct;
+ char *saveptr;
+
+ char *s = SMB_STRDUP(string);
+
+ char *t;
+
+ if ((t = strtok_r(s, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return false;
+ }
+
+ *cell = SMB_STRDUP(t);
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return false;
+ }
+
+ if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) {
+ DEBUG(10, ("sscanf AuthHandle failed\n"));
+ return false;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return false;
+ }
+
+ blob = base64_decode_data_blob(t);
+
+ if ( (blob.data == NULL) ||
+ (blob.length != sizeof(result_ct.HandShakeKey) )) {
+ DEBUG(10, ("invalid key: %x/%lu\n", (uint8_t)*blob.data,
+ (unsigned long) blob.length));
+ return false;
+ }
+
+ memcpy(result_ct.HandShakeKey, blob.data, blob.length);
+
+ data_blob_free(&blob);
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return false;
+ }
+
+ if (sscanf(t, "%u", &result_ct.ViceId) != 1) {
+ DEBUG(10, ("sscanf ViceId failed\n"));
+ return false;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return false;
+ }
+
+ if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) {
+ DEBUG(10, ("sscanf BeginTimestamp failed\n"));
+ return false;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return false;
+ }
+
+ if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) {
+ DEBUG(10, ("sscanf EndTimestamp failed\n"));
+ return false;
+ }
+
+ if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
+ DEBUG(10, ("strtok_r failed\n"));
+ return false;
+ }
+
+ blob = base64_decode_data_blob(t);
+
+ if (blob.data == NULL) {
+ DEBUG(10, ("Could not get ticket\n"));
+ return false;
+ }
+
+ *ticket = blob;
+ *ct = result_ct;
+
+ return true;
+}
+
+/*
+ Put an AFS token into the Kernel so that it can authenticate against
+ the AFS server. This assumes correct local uid settings.
+
+ This is currently highly Linux and OpenAFS-specific. The correct API
+ call for this would be ktc_SetToken. But to do that we would have to
+ import a REALLY big bunch of libraries which I would currently like
+ to avoid.
+*/
+
+static bool afs_settoken(const char *cell,
+ const struct ClearToken *ctok,
+ DATA_BLOB ticket)
+{
+ int ret;
+ struct {
+ char *in, *out;
+ uint16 in_size, out_size;
+ } iob;
+
+ char buf[1024];
+ char *p = buf;
+ int tmp;
+
+ memcpy(p, &ticket.length, sizeof(uint32));
+ p += sizeof(uint32);
+ memcpy(p, ticket.data, ticket.length);
+ p += ticket.length;
+
+ tmp = sizeof(struct ClearToken);
+ memcpy(p, &tmp, sizeof(uint32));
+ p += sizeof(uint32);
+ memcpy(p, ctok, tmp);
+ p += tmp;
+
+ tmp = 0;
+
+ memcpy(p, &tmp, sizeof(uint32));
+ p += sizeof(uint32);
+
+ tmp = strlen(cell);
+ if (tmp >= MAXKTCREALMLEN) {
+ DEBUG(1, ("Realm too long\n"));
+ return false;
+ }
+
+ strncpy(p, cell, tmp);
+ p += tmp;
+ *p = 0;
+ p +=1;
+
+ iob.in = buf;
+ iob.in_size = PTR_DIFF(p,buf);
+ iob.out = buf;
+ iob.out_size = sizeof(buf);
+
+#if 0
+ file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
+#endif
+
+ ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
+
+ DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
+ return (ret == 0);
+}
+
+bool afs_settoken_str(const char *token_string)
+{
+ DATA_BLOB ticket;
+ struct ClearToken ct;
+ bool result;
+ char *cell;
+
+ if (!afs_decode_token(token_string, &cell, &ticket, &ct))
+ return false;
+
+ if (geteuid() != 0) {
+ ct.ViceId = geteuid();
+ }
+
+ result = afs_settoken(cell, &ct, ticket);
+
+ SAFE_FREE(cell);
+ data_blob_free(&ticket);
+
+ return result;
+}
+
+#else
+
+int afs_syscall(int subcall, const char *path, int cmd, char *cmarg, int follow)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+bool afs_settoken_str(const char *token_string)
+{
+ return false;
+}
+
+#endif
diff --git a/lib/afs/afs_settoken.h b/lib/afs/afs_settoken.h
new file mode 100644
index 0000000..d6cc462
--- /dev/null
+++ b/lib/afs/afs_settoken.h
@@ -0,0 +1,21 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Generate AFS tickets
+ * Copyright (C) Volker Lendecke 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+int afs_syscall(int subcall, const char *path, int cmd, char *cmarg, int follow);
+bool afs_settoken_str(const char *token_string);
diff --git a/lib/afs/wscript_build b/lib/afs/wscript_build
new file mode 100644
index 0000000..d584a17
--- /dev/null
+++ b/lib/afs/wscript_build
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+bld.SAMBA3_SUBSYSTEM('LIBAFS',
+ source='afs_funcs.c',
+ deps='samba-util crypto LIBAFS_SETTOKEN')
+
+bld.SAMBA3_SUBSYSTEM('LIBAFS_SETTOKEN',
+ source='afs_settoken.c',
+ deps='samba-util')
+
diff --git a/lib/async_req/async_connect_send_test.c b/lib/async_req/async_connect_send_test.c
new file mode 100644
index 0000000..d570c60
--- /dev/null
+++ b/lib/async_req/async_connect_send_test.c
@@ -0,0 +1,130 @@
+/*
+ * Test async connect
+ * Copyright (C) Ralph Boehme 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <tevent.h>
+#include "lib/async_req/async_sock.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int main(int argc, const char *argv[])
+{
+ int result, listen_sock, status, exit_status;
+ uint16_t port;
+ struct sockaddr_in addr = { 0 };
+ pid_t pid;
+
+ listen_sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (listen_sock == -1) {
+ perror("socket() failed");
+ exit(1);
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ for (port = 1024; port < UINT16_MAX; port++) {
+ addr.sin_port = htons(port);
+ result = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
+ if (result == 0) {
+ break;
+ }
+ }
+
+ if (port == UINT16_MAX) {
+ printf("Huh, no free port?\n");
+ return 1;
+ }
+
+ result = listen(listen_sock, 1);
+ if (result == -1) {
+ perror("listen() failed");
+ close(listen_sock);
+ return 1;
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ return 1;
+ }
+
+ if (pid == 0) {
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ int fd;
+
+ ev = tevent_context_init(NULL);
+ if (ev == NULL) {
+ fprintf(stderr, "tevent_context_init failed\n");
+ return 1;
+ }
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd == -1) {
+ perror("socket");
+ return 1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ req = async_connect_send(ev, ev, fd,
+ (struct sockaddr *)&addr,
+ sizeof(struct sockaddr_in),
+ NULL, NULL, NULL);
+
+ if (!tevent_req_poll(req, ev)) {
+ perror("tevent_req_poll() failed");
+ return 1;
+ }
+
+ status = 0;
+ result = async_connect_recv(req, &status);
+ if (result != 0) {
+ return status;
+ }
+ return 0;
+ }
+
+ result = waitpid(pid, &status, 0);
+ if (result == -1) {
+ perror("waitpid");
+ return 1;
+ }
+
+ if (!WIFEXITED(status)) {
+ printf("child status: %d\n", status);
+ return 2;
+ }
+
+ exit_status = WEXITSTATUS(status);
+ printf("test done: status=%d\n", exit_status);
+
+ if (exit_status != 0) {
+ return exit_status;
+ }
+
+ return 0;
+}
diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
new file mode 100644
index 0000000..bdbefd1
--- /dev/null
+++ b/lib/async_req/async_sock.c
@@ -0,0 +1,774 @@
+/*
+ Unix SMB/CIFS implementation.
+ async socket syscalls
+ Copyright (C) Volker Lendecke 2008
+
+ ** NOTE! The following LGPL license applies to the async_sock
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include <talloc.h>
+#include <tevent.h>
+#include "lib/async_req/async_sock.h"
+#include "lib/util/iov_buf.h"
+#include "lib/util/util_net.h"
+
+/* Note: lib/util/ is currently GPL */
+#include "lib/util/tevent_unix.h"
+#include "lib/util/samba_util.h"
+
+struct async_connect_state {
+ int fd;
+ struct tevent_fd *fde;
+ int result;
+ long old_sockflags;
+ socklen_t address_len;
+ struct sockaddr_storage address;
+
+ void (*before_connect)(void *private_data);
+ void (*after_connect)(void *private_data);
+ void *private_data;
+};
+
+static void async_connect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+static void async_connect_connected(struct tevent_context *ev,
+ struct tevent_fd *fde, uint16_t flags,
+ void *priv);
+
+/**
+ * @brief async version of connect(2)
+ * @param[in] mem_ctx The memory context to hang the result off
+ * @param[in] ev The event context to work from
+ * @param[in] fd The socket to recv from
+ * @param[in] address Where to connect?
+ * @param[in] address_len Length of *address
+ * @retval The async request
+ *
+ * This function sets the socket into non-blocking state to be able to call
+ * connect in an async state. This will be reset when the request is finished.
+ */
+
+struct tevent_req *async_connect_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
+ const struct sockaddr *address, socklen_t address_len,
+ void (*before_connect)(void *private_data),
+ void (*after_connect)(void *private_data),
+ void *private_data)
+{
+ struct tevent_req *req;
+ struct async_connect_state *state;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /**
+ * We have to set the socket to nonblocking for async connect(2). Keep
+ * the old sockflags around.
+ */
+
+ state->fd = fd;
+ state->before_connect = before_connect;
+ state->after_connect = after_connect;
+ state->private_data = private_data;
+
+ state->old_sockflags = fcntl(fd, F_GETFL, 0);
+ if (state->old_sockflags == -1) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_cleanup_fn(req, async_connect_cleanup);
+
+ state->address_len = address_len;
+ if (address_len > sizeof(state->address)) {
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
+ }
+ memcpy(&state->address, address, address_len);
+
+ ret = set_blocking(fd, false);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ if (state->before_connect != NULL) {
+ state->before_connect(state->private_data);
+ }
+
+ state->result = connect(fd, address, address_len);
+
+ if (state->after_connect != NULL) {
+ state->after_connect(state->private_data);
+ }
+
+ if (state->result == 0) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * The only errno indicating that an initial connect is still
+ * in flight is EINPROGRESS.
+ *
+ * This allows callers like open_socket_out_send() to reuse
+ * fds and call us with an fd for which the connect is still
+ * in flight. The proper thing to do for callers would be
+ * closing the fd and starting from scratch with a fresh
+ * socket.
+ */
+
+ if (errno != EINPROGRESS) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * Note for historic reasons TEVENT_FD_WRITE is not enough
+ * to get notified for POLLERR or EPOLLHUP even if they
+ * come together with POLLOUT. That means we need to
+ * use TEVENT_FD_READ in addition until we have
+ * TEVENT_FD_ERROR.
+ */
+ state->fde = tevent_add_fd(ev, state, fd,
+ TEVENT_FD_ERROR|TEVENT_FD_WRITE,
+ async_connect_connected, req);
+ if (state->fde == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void async_connect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct async_connect_state *state =
+ tevent_req_data(req, struct async_connect_state);
+
+ TALLOC_FREE(state->fde);
+ if (state->fd != -1) {
+ int ret;
+
+ ret = fcntl(state->fd, F_SETFL, state->old_sockflags);
+ if (ret == -1) {
+ abort();
+ }
+
+ state->fd = -1;
+ }
+}
+
+/**
+ * fde event handler for connect(2)
+ * @param[in] ev The event context that sent us here
+ * @param[in] fde The file descriptor event associated with the connect
+ * @param[in] flags Indicate read/writeability of the socket
+ * @param[in] priv private data, "struct async_req *" in this case
+ */
+
+static void async_connect_connected(struct tevent_context *ev,
+ struct tevent_fd *fde, uint16_t flags,
+ void *priv)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ priv, struct tevent_req);
+ struct async_connect_state *state =
+ tevent_req_data(req, struct async_connect_state);
+ int ret;
+ int socket_error = 0;
+ socklen_t slen = sizeof(socket_error);
+
+ ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
+ &socket_error, &slen);
+
+ if (ret != 0) {
+ /*
+ * According to Stevens this is the Solaris behaviour
+ * in case the connection encountered an error:
+ * getsockopt() fails, error is in errno
+ */
+ tevent_req_error(req, errno);
+ return;
+ }
+
+ if (socket_error != 0) {
+ /*
+ * Berkeley derived implementations (including) Linux
+ * return the pending error via socket_error.
+ */
+ tevent_req_error(req, socket_error);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+int async_connect_recv(struct tevent_req *req, int *perrno)
+{
+ int err = tevent_req_simple_recv_unix(req);
+
+ if (err != 0) {
+ *perrno = err;
+ return -1;
+ }
+
+ return 0;
+}
+
+struct writev_state {
+ struct tevent_context *ev;
+ struct tevent_queue_entry *queue_entry;
+ int fd;
+ struct tevent_fd *fde;
+ struct iovec *iov;
+ int count;
+ size_t total_size;
+ uint16_t flags;
+ bool err_on_readability;
+};
+
+static void writev_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+static bool writev_cancel(struct tevent_req *req);
+static void writev_trigger(struct tevent_req *req, void *private_data);
+static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data);
+
+struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct tevent_queue *queue, int fd,
+ bool err_on_readability,
+ struct iovec *iov, int count)
+{
+ struct tevent_req *req;
+ struct writev_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct writev_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->fd = fd;
+ state->total_size = 0;
+ state->count = count;
+ state->iov = (struct iovec *)talloc_memdup(
+ state, iov, sizeof(struct iovec) * count);
+ if (tevent_req_nomem(state->iov, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->flags = TEVENT_FD_WRITE | TEVENT_FD_ERROR;
+ if (err_on_readability) {
+ state->flags |= TEVENT_FD_READ;
+ }
+
+ tevent_req_set_cleanup_fn(req, writev_cleanup);
+ tevent_req_set_cancel_fn(req, writev_cancel);
+
+ if (queue == NULL) {
+ state->fde = tevent_add_fd(state->ev, state, state->fd,
+ state->flags, writev_handler, req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+ }
+
+ /*
+ * writev_trigger tries a nonblocking write. If that succeeds,
+ * we can't directly notify the callback to call
+ * writev_recv. The callback would TALLOC_FREE(req) after
+ * calling writev_recv even before writev_trigger can inspect
+ * it for success.
+ */
+ tevent_req_defer_callback(req, ev);
+
+ state->queue_entry = tevent_queue_add_optimize_empty(
+ queue, ev, req, writev_trigger, NULL);
+ if (tevent_req_nomem(state->queue_entry, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void writev_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct writev_state *state = tevent_req_data(req, struct writev_state);
+
+ TALLOC_FREE(state->queue_entry);
+ TALLOC_FREE(state->fde);
+}
+
+static bool writev_cancel(struct tevent_req *req)
+{
+ struct writev_state *state = tevent_req_data(req, struct writev_state);
+
+ if (state->total_size > 0) {
+ /*
+ * We've already started to write :-(
+ */
+ return false;
+ }
+
+ TALLOC_FREE(state->queue_entry);
+ TALLOC_FREE(state->fde);
+
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_error(req, ECANCELED);
+ return true;
+}
+
+static void writev_do(struct tevent_req *req, struct writev_state *state)
+{
+ ssize_t written;
+ bool ok;
+
+ written = writev(state->fd, state->iov, state->count);
+ if ((written == -1) &&
+ ((errno == EINTR) ||
+ (errno == EAGAIN) ||
+ (errno == EWOULDBLOCK))) {
+ /* retry after going through the tevent loop */
+ return;
+ }
+ if (written == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ if (written == 0) {
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+ state->total_size += written;
+
+ ok = iov_advance(&state->iov, &state->count, written);
+ if (!ok) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ return;
+ }
+}
+
+static void writev_trigger(struct tevent_req *req, void *private_data)
+{
+ struct writev_state *state = tevent_req_data(req, struct writev_state);
+
+ state->queue_entry = NULL;
+
+ writev_do(req, state);
+ if (!tevent_req_is_in_progress(req)) {
+ return;
+ }
+
+ state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
+ writev_handler, req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return;
+ }
+}
+
+static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ private_data, struct tevent_req);
+ struct writev_state *state =
+ tevent_req_data(req, struct writev_state);
+
+ if (flags & TEVENT_FD_ERROR) {
+ /*
+ * There's an error, for legacy reasons
+ * we just use EPIPE instead of a more
+ * detailed error using
+ * samba_socket_poll_or_sock_error().
+ */
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+
+ if (flags & TEVENT_FD_READ) {
+ /* Readable and the caller wants an error on read. */
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+
+ writev_do(req, state);
+}
+
+ssize_t writev_recv(struct tevent_req *req, int *perrno)
+{
+ struct writev_state *state =
+ tevent_req_data(req, struct writev_state);
+ ssize_t ret;
+
+ if (tevent_req_is_unix_error(req, perrno)) {
+ tevent_req_received(req);
+ return -1;
+ }
+ ret = state->total_size;
+ tevent_req_received(req);
+ return ret;
+}
+
+struct read_packet_state {
+ int fd;
+ struct tevent_fd *fde;
+ uint8_t *buf;
+ size_t nread;
+ ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
+ void *private_data;
+};
+
+static void read_packet_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+static void read_packet_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags, void *private_data);
+
+struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd, size_t initial,
+ ssize_t (*more)(uint8_t *buf,
+ size_t buflen,
+ void *private_data),
+ void *private_data)
+{
+ struct tevent_req *req;
+ struct read_packet_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->fd = fd;
+ state->nread = 0;
+ state->more = more;
+ state->private_data = private_data;
+
+ tevent_req_set_cleanup_fn(req, read_packet_cleanup);
+
+ state->buf = talloc_array(state, uint8_t, initial);
+ if (tevent_req_nomem(state->buf, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->fde = tevent_add_fd(ev, state, fd,
+ TEVENT_FD_READ, read_packet_handler,
+ req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void read_packet_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct read_packet_state *state =
+ tevent_req_data(req, struct read_packet_state);
+
+ TALLOC_FREE(state->fde);
+}
+
+static void read_packet_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ private_data, struct tevent_req);
+ struct read_packet_state *state =
+ tevent_req_data(req, struct read_packet_state);
+ size_t total = talloc_get_size(state->buf);
+ ssize_t nread, more;
+ uint8_t *tmp;
+
+ nread = recv(state->fd, state->buf+state->nread, total-state->nread,
+ 0);
+ if ((nread == -1) && (errno == ENOTSOCK)) {
+ nread = read(state->fd, state->buf+state->nread,
+ total-state->nread);
+ }
+ if ((nread == -1) && (errno == EINTR)) {
+ /* retry */
+ return;
+ }
+ if (nread == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ if (nread == 0) {
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+
+ state->nread += nread;
+ if (state->nread < total) {
+ /* Come back later */
+ return;
+ }
+
+ /*
+ * We got what was initially requested. See if "more" asks for -- more.
+ */
+ if (state->more == NULL) {
+ /* Nobody to ask, this is a async read_data */
+ tevent_req_done(req);
+ return;
+ }
+
+ more = state->more(state->buf, total, state->private_data);
+ if (more == -1) {
+ /* We got an invalid packet, tell the caller */
+ tevent_req_error(req, EIO);
+ return;
+ }
+ if (more == 0) {
+ /* We're done, full packet received */
+ tevent_req_done(req);
+ return;
+ }
+
+ if (total + more < total) {
+ tevent_req_error(req, EMSGSIZE);
+ return;
+ }
+
+ tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
+ if (tevent_req_nomem(tmp, req)) {
+ return;
+ }
+ state->buf = tmp;
+}
+
+ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **pbuf, int *perrno)
+{
+ struct read_packet_state *state =
+ tevent_req_data(req, struct read_packet_state);
+
+ if (tevent_req_is_unix_error(req, perrno)) {
+ tevent_req_received(req);
+ return -1;
+ }
+ *pbuf = talloc_move(mem_ctx, &state->buf);
+ tevent_req_received(req);
+ return talloc_get_size(*pbuf);
+}
+
+struct wait_for_read_state {
+ struct tevent_fd *fde;
+ int fd;
+ bool check_errors;
+};
+
+static void wait_for_read_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+static void wait_for_read_done(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev, int fd,
+ bool check_errors)
+{
+ struct tevent_req *req;
+ struct wait_for_read_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ tevent_req_set_cleanup_fn(req, wait_for_read_cleanup);
+
+ state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
+ wait_for_read_done, req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->fd = fd;
+ state->check_errors = check_errors;
+ return req;
+}
+
+static void wait_for_read_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct wait_for_read_state *state =
+ tevent_req_data(req, struct wait_for_read_state);
+
+ TALLOC_FREE(state->fde);
+}
+
+static void wait_for_read_done(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ private_data, struct tevent_req);
+ struct wait_for_read_state *state =
+ tevent_req_data(req, struct wait_for_read_state);
+ int ret, available;
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ return;
+ }
+
+ if (!state->check_errors) {
+ tevent_req_done(req);
+ return;
+ }
+
+ ret = ioctl(state->fd, FIONREAD, &available);
+
+ if ((ret == -1) && (errno == EINTR)) {
+ /* come back later */
+ return;
+ }
+
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+
+ if (available == 0) {
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+bool wait_for_read_recv(struct tevent_req *req, int *perr)
+{
+ int err = tevent_req_simple_recv_unix(req);
+
+ if (err != 0) {
+ *perr = err;
+ return false;
+ }
+
+ return true;
+}
+
+struct accept_state {
+ struct tevent_fd *fde;
+ int listen_sock;
+ struct samba_sockaddr addr;
+ int sock;
+};
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data);
+
+struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ int listen_sock)
+{
+ struct tevent_req *req;
+ struct accept_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct accept_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->listen_sock = listen_sock;
+
+ state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
+ accept_handler, req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ private_data, struct tevent_req);
+ struct accept_state *state = tevent_req_data(req, struct accept_state);
+ int ret;
+
+ TALLOC_FREE(state->fde);
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ state->addr.sa_socklen = sizeof(state->addr.u);
+
+ ret = accept(state->listen_sock,
+ &state->addr.u.sa,
+ &state->addr.sa_socklen);
+ if ((ret == -1) && (errno == EINTR)) {
+ /* retry */
+ return;
+ }
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ smb_set_close_on_exec(ret);
+ state->sock = ret;
+ tevent_req_done(req);
+}
+
+int accept_recv(struct tevent_req *req,
+ int *listen_sock,
+ struct samba_sockaddr *paddr,
+ int *perr)
+{
+ struct accept_state *state = tevent_req_data(req, struct accept_state);
+ int sock = state->sock;
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ if (perr != NULL) {
+ *perr = err;
+ }
+ tevent_req_received(req);
+ return -1;
+ }
+ if (listen_sock != NULL) {
+ *listen_sock = state->listen_sock;
+ }
+ if (paddr != NULL) {
+ *paddr = state->addr;
+ }
+ tevent_req_received(req);
+ return sock;
+}
diff --git a/lib/async_req/async_sock.h b/lib/async_req/async_sock.h
new file mode 100644
index 0000000..780195e
--- /dev/null
+++ b/lib/async_req/async_sock.h
@@ -0,0 +1,68 @@
+/*
+ Unix SMB/CIFS implementation.
+ async socket operations
+ Copyright (C) Volker Lendecke 2008
+
+ ** NOTE! The following LGPL license applies to the async_sock
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ASYNC_SOCK_H__
+#define __ASYNC_SOCK_H__
+
+#include <talloc.h>
+#include <tevent.h>
+#include "system/network.h"
+
+struct tevent_req *async_connect_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
+ const struct sockaddr *address, socklen_t address_len,
+ void (*before_connect)(void *private_data),
+ void (*after_connect)(void *private_data),
+ void *private_data);
+int async_connect_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct tevent_queue *queue, int fd,
+ bool err_on_readability,
+ struct iovec *iov, int count);
+ssize_t writev_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd, size_t initial,
+ ssize_t (*more)(uint8_t *buf,
+ size_t buflen,
+ void *private_data),
+ void *private_data);
+ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **pbuf, int *perrno);
+
+struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev, int fd,
+ bool check_errors);
+bool wait_for_read_recv(struct tevent_req *req, int *perr);
+
+struct samba_sockaddr;
+struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ int listen_sock);
+int accept_recv(struct tevent_req *req,
+ int *listen_sock,
+ struct samba_sockaddr *paddr,
+ int *perr);
+
+#endif
diff --git a/lib/async_req/wscript_build b/lib/async_req/wscript_build
new file mode 100644
index 0000000..4486a5b
--- /dev/null
+++ b/lib/async_req/wscript_build
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_SUBSYSTEM('LIBASYNC_REQ',
+ source='async_sock.c',
+ public_deps='talloc tevent iov_buf',
+ deps='tevent-util socket-blocking'
+ )
+
+bld.SAMBA_BINARY('async_connect_send_test',
+ source='async_connect_send_test.c',
+ deps='LIBASYNC_REQ',
+ for_selftest=True
+)
diff --git a/lib/audit_logging/audit_logging.c b/lib/audit_logging/audit_logging.c
new file mode 100644
index 0000000..8ed15ed
--- /dev/null
+++ b/lib/audit_logging/audit_logging.c
@@ -0,0 +1,1356 @@
+/*
+ common routines for audit logging
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Error handling:
+ *
+ */
+
+#include "includes.h"
+
+#include "librpc/ndr/libndr.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/security_token.h"
+#include "lib/messaging/messaging.h"
+#include "auth/common_auth.h"
+#include "audit_logging.h"
+#include "auth/authn_policy.h"
+
+/*
+ * @brief Get a human readable timestamp.
+ *
+ * Returns the current time formatted as
+ * "Tue, 14 Mar 2017 08:38:42.209028 NZDT"
+ *
+ * The returned string is allocated by talloc in the supplied context.
+ * It is the callers responsibility to free it.
+ *
+ * @param mem_ctx talloc memory context that owns the returned string.
+ *
+ * @return a human readable time stamp, or NULL in the event of an error.
+ *
+ */
+char* audit_get_timestamp(TALLOC_CTX *frame)
+{
+ char buffer[40]; /* formatted time less usec and timezone */
+ char tz[10]; /* formatted time zone */
+ struct tm* tm_info; /* current local time */
+ struct timeval tv; /* current system time */
+ int ret; /* response code */
+ char * ts; /* formatted time stamp */
+
+ ret = gettimeofday(&tv, NULL);
+ if (ret != 0) {
+ DBG_ERR("Unable to get time of day: (%d) %s\n",
+ errno,
+ strerror(errno));
+ return NULL;
+ }
+
+ tm_info = localtime(&tv.tv_sec);
+ if (tm_info == NULL) {
+ DBG_ERR("Unable to determine local time\n");
+ return NULL;
+ }
+
+ strftime(buffer, sizeof(buffer)-1, "%a, %d %b %Y %H:%M:%S", tm_info);
+ strftime(tz, sizeof(tz)-1, "%Z", tm_info);
+ ts = talloc_asprintf(frame, "%s.%06ld %s", buffer, (long)tv.tv_usec, tz);
+ if (ts == NULL) {
+ DBG_ERR("Out of memory formatting time stamp\n");
+ }
+ return ts;
+}
+
+/*
+ * @brief write an audit message to the audit logs.
+ *
+ * Write a human readable text audit message to the samba logs.
+ *
+ * @param prefix Text to be printed at the start of the log line
+ * @param message The content of the log line.
+ * @param debub_class The debug class to log the message with.
+ * @param debug_level The debug level to log the message with.
+ */
+void audit_log_human_text(const char* prefix,
+ const char* message,
+ int debug_class,
+ int debug_level)
+{
+ DEBUGC(debug_class, debug_level, ("%s %s\n", prefix, message));
+}
+
+#ifdef HAVE_JANSSON
+/*
+ * Constant for empty json object initialisation
+ */
+const struct json_object json_empty_object = {.valid = false, .root = NULL};
+/*
+ * @brief write a json object to the samba audit logs.
+ *
+ * Write the json object to the audit logs as a formatted string
+ *
+ * @param message The content of the log line.
+ * @param debub_class The debug class to log the message with.
+ * @param debug_level The debug level to log the message with.
+ */
+void audit_log_json(struct json_object* message,
+ int debug_class,
+ int debug_level)
+{
+ TALLOC_CTX *frame = NULL;
+ char *s = NULL;
+
+ if (json_is_invalid(message)) {
+ DBG_ERR("Invalid JSON object, unable to log\n");
+ return;
+ }
+
+ frame = talloc_stackframe();
+ s = json_to_string(frame, message);
+ if (s == NULL) {
+ DBG_ERR("json_to_string returned NULL, "
+ "JSON audit message could not written\n");
+ TALLOC_FREE(frame);
+ return;
+ }
+ /*
+ * This is very strange, but we call this routine to get a log
+ * output without the header. JSON logs all have timestamps
+ * so this only makes parsing harder.
+ *
+ * We push out the raw JSON blob without a prefix, consumers
+ * can find such lines by the leading {
+ */
+ DEBUGADDC(debug_class, debug_level, ("%s\n", s));
+ TALLOC_FREE(frame);
+}
+
+/*
+ * @brief get a connection to the messaging event server.
+ *
+ * Get a connection to the messaging event server registered by server_name.
+ *
+ * @param msg_ctx a valid imessaging_context.
+ * @param server_name name of messaging event server to connect to.
+ * @param server_id The event server details to populate
+ *
+ * @return NTSTATUS
+ */
+static NTSTATUS get_event_server(
+ struct imessaging_context *msg_ctx,
+ const char *server_name,
+ struct server_id *event_server)
+{
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ unsigned num_servers, i;
+ struct server_id *servers;
+
+ status = irpc_servers_byname(
+ msg_ctx,
+ frame,
+ server_name,
+ &num_servers,
+ &servers);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("Failed to find the target '%s' on the message bus "
+ "to send JSON audit events to: %s\n",
+ server_name,
+ nt_errstr(status));
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ /*
+ * Select the first server that is listening, because we get
+ * connection refused as NT_STATUS_OBJECT_NAME_NOT_FOUND
+ * without waiting
+ */
+ for (i = 0; i < num_servers; i++) {
+ status = imessaging_send(
+ msg_ctx,
+ servers[i],
+ MSG_PING,
+ &data_blob_null);
+ if (NT_STATUS_IS_OK(status)) {
+ *event_server = servers[i];
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+ }
+ DBG_NOTICE(
+ "Failed to find '%s' registered on the message bus to "
+ "send JSON audit events to: %s\n",
+ server_name,
+ nt_errstr(status));
+ TALLOC_FREE(frame);
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+/*
+ * @brief send an audit message to a messaging event server.
+ *
+ * Send the message to a registered and listening event server.
+ * Note: Any errors are logged, and the message is not sent. This is to ensure
+ * that a poorly behaved event server does not impact Samba.
+ *
+ * As it is possible to lose messages, especially during server
+ * shut down, currently this function is primarily intended for use
+ * in integration tests.
+ *
+ * @param msg_ctx an imessaging_context, can be NULL in which case no message
+ * will be sent.
+ * @param server_name the naname of the event server to send the message to.
+ * @param messag_type A message type defined in librpc/idl/messaging.idl
+ * @param message The message to send.
+ *
+ */
+void audit_message_send(
+ struct imessaging_context *msg_ctx,
+ const char *server_name,
+ uint32_t message_type,
+ struct json_object *message)
+{
+ struct server_id event_server = {
+ .pid = 0,
+ };
+ NTSTATUS status;
+
+ const char *message_string = NULL;
+ DATA_BLOB message_blob = data_blob_null;
+ TALLOC_CTX *ctx = NULL;
+
+ if (json_is_invalid(message)) {
+ DBG_ERR("Invalid JSON object, unable to send\n");
+ return;
+ }
+ if (msg_ctx == NULL) {
+ DBG_DEBUG("No messaging context\n");
+ return;
+ }
+
+ ctx = talloc_new(NULL);
+ if (ctx == NULL) {
+ DBG_ERR("Out of memory creating temporary context\n");
+ return;
+ }
+
+ /* Need to refetch the address each time as the destination server may
+ * have disconnected and reconnected in the interim, in which case
+ * messages may get lost
+ */
+ status = get_event_server(msg_ctx, server_name, &event_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ message_string = json_to_string(ctx, message);
+ message_blob = data_blob_string_const(message_string);
+ status = imessaging_send(
+ msg_ctx,
+ event_server,
+ message_type,
+ &message_blob);
+
+ /*
+ * If the server crashed, try to find it again
+ */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ status = get_event_server(msg_ctx, server_name, &event_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+ imessaging_send(
+ msg_ctx,
+ event_server,
+ message_type,
+ &message_blob);
+ }
+ TALLOC_FREE(ctx);
+}
+
+/*
+ * @brief Create a new struct json_object, wrapping a JSON Object.
+ *
+ * Create a new json object, the json_object wraps the underlying json
+ * implementations JSON Object representation.
+ *
+ * Free with a call to json_free_object, note that the jansson implementation
+ * allocates memory with malloc and not talloc.
+ *
+ * @return a struct json_object, valid will be set to false if the object
+ * could not be created.
+ *
+ */
+struct json_object json_new_object(void) {
+
+ struct json_object object = json_empty_object;
+
+ object.root = json_object();
+ if (object.root == NULL) {
+ object.valid = false;
+ DBG_ERR("Unable to create JSON object\n");
+ return object;
+ }
+ object.valid = true;
+ return object;
+}
+
+/*
+ * @brief Create a new struct json_object wrapping a JSON Array.
+ *
+ * Create a new json object, the json_object wraps the underlying json
+ * implementations JSON Array representation.
+ *
+ * Free with a call to json_free_object, note that the jansson implementation
+ * allocates memory with malloc and not talloc.
+ *
+ * @return a struct json_object, error will be set to true if the array
+ * could not be created.
+ *
+ */
+struct json_object json_new_array(void) {
+
+ struct json_object array = json_empty_object;
+
+ array.root = json_array();
+ if (array.root == NULL) {
+ array.valid = false;
+ DBG_ERR("Unable to create JSON array\n");
+ return array;
+ }
+ array.valid = true;
+ return array;
+}
+
+
+/*
+ * @brief free and invalidate a previously created JSON object.
+ *
+ * Release any resources owned by a json_object, and then mark the structure
+ * as invalid. It is safe to call this multiple times on an object.
+ *
+ */
+void json_free(struct json_object *object)
+{
+ if (object->root != NULL) {
+ json_decref(object->root);
+ }
+ object->root = NULL;
+ object->valid = false;
+}
+
+/*
+ * @brief is the current JSON object invalid?
+ *
+ * Check the state of the object to determine if it is invalid.
+ *
+ * @return is the object valid?
+ *
+ */
+bool json_is_invalid(const struct json_object *object)
+{
+ return !object->valid;
+}
+
+/*
+ * @brief Add an integer value to a JSON object.
+ *
+ * Add an integer value named 'name' to the json object.
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name of the value.
+ * @param value the value.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_int(struct json_object *object, const char *name, const json_int_t value)
+{
+ int ret = 0;
+ json_t *integer = NULL;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add int [%s] value [%jd], "
+ "target object is invalid\n",
+ name,
+ (intmax_t)value);
+ return JSON_ERROR;
+ }
+
+ integer = json_integer(value);
+ if (integer == NULL) {
+ DBG_ERR("Unable to create integer value [%s] value [%jd]\n",
+ name,
+ (intmax_t)value);
+ return JSON_ERROR;
+ }
+
+ ret = json_object_set_new(object->root, name, integer);
+ if (ret != 0) {
+ json_decref(integer);
+ DBG_ERR("Unable to add int [%s] value [%jd]\n",
+ name,
+ (intmax_t)value);
+ }
+ return ret;
+}
+
+/*
+ * @brief Add a boolean value to a JSON object.
+ *
+ * Add a boolean value named 'name' to the json object.
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param value the value.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_bool(struct json_object *object,
+ const char *name,
+ const bool value)
+{
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add boolean [%s] value [%d], "
+ "target object is invalid\n",
+ name,
+ value);
+ return JSON_ERROR;
+ }
+
+ ret = json_object_set_new(object->root, name, json_boolean(value));
+ if (ret != 0) {
+ DBG_ERR("Unable to add boolean [%s] value [%d]\n", name, value);
+ }
+ return ret;
+}
+
+/*
+ * @brief Add an optional boolean value to a JSON object.
+ *
+ * Add an optional boolean value named 'name' to the json object.
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param value the value.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_optional_bool(struct json_object *object,
+ const char *name,
+ const bool *value)
+{
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add boolean [%s] value [%d], "
+ "target object is invalid\n",
+ name,
+ *value);
+ return JSON_ERROR;
+ }
+
+ if (value != NULL) {
+ ret = json_object_set_new(object->root, name, json_boolean(*value));
+ if (ret != 0) {
+ DBG_ERR("Unable to add boolean [%s] value [%d]\n", name, *value);
+ return ret;
+ }
+ } else {
+ ret = json_object_set_new(object->root, name, json_null());
+ if (ret != 0) {
+ DBG_ERR("Unable to add null boolean [%s]\n", name);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * @brief Add a string value to a JSON object.
+ *
+ * Add a string value named 'name' to the json object.
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param value the value.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_string(struct json_object *object,
+ const char *name,
+ const char *value)
+{
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add string [%s], target object is invalid\n",
+ name);
+ return JSON_ERROR;
+ }
+ if (value) {
+ json_t *string = json_string(value);
+ if (string == NULL) {
+ DBG_ERR("Unable to add string [%s], "
+ "could not create string object\n",
+ name);
+ return JSON_ERROR;
+ }
+ ret = json_object_set_new(object->root, name, string);
+ if (ret != 0) {
+ json_decref(string);
+ DBG_ERR("Unable to add string [%s]\n", name);
+ return ret;
+ }
+ } else {
+ ret = json_object_set_new(object->root, name, json_null());
+ if (ret != 0) {
+ DBG_ERR("Unable to add null string [%s]\n", name);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+/*
+ * @brief Assert that the current JSON object is an array.
+ *
+ * Check that the current object is a JSON array, and if not
+ * invalidate the object. We also log an error message as this indicates
+ * bug in the calling code.
+ *
+ * @param object the JSON object to be validated.
+ */
+void json_assert_is_array(struct json_object *array) {
+
+ if (json_is_invalid(array)) {
+ return;
+ }
+
+ if (json_is_array(array->root) == false) {
+ DBG_ERR("JSON object is not an array\n");
+ array->valid = false;
+ return;
+ }
+}
+
+/*
+ * @brief Add a JSON object to a JSON object.
+ *
+ * Add a JSON object named 'name' to the json object.
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param value the value.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_object(struct json_object *object,
+ const char *name,
+ struct json_object *value)
+{
+ int ret = 0;
+ json_t *jv = NULL;
+
+ if (value != NULL && json_is_invalid(value)) {
+ DBG_ERR("Invalid JSON object [%s] supplied\n", name);
+ return JSON_ERROR;
+ }
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add object [%s], target object is invalid\n",
+ name);
+ return JSON_ERROR;
+ }
+
+ jv = value == NULL ? json_null() : value->root;
+
+ if (json_is_array(object->root)) {
+ ret = json_array_append_new(object->root, jv);
+ } else if (json_is_object(object->root)) {
+ ret = json_object_set_new(object->root, name, jv);
+ } else {
+ DBG_ERR("Invalid JSON object type\n");
+ ret = JSON_ERROR;
+ }
+ if (ret != 0) {
+ DBG_ERR("Unable to add object [%s]\n", name);
+ }
+ return ret;
+}
+
+/*
+ * @brief Add a string to a JSON object, truncating if necessary.
+ *
+ *
+ * Add a string value named 'name' to the json object, the string will be
+ * truncated if it is more than len characters long. If len is 0 the value
+ * is encoded as a JSON null.
+ *
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param value the value.
+ * @param len the maximum number of characters to be copied.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_stringn(struct json_object *object,
+ const char *name,
+ const char *value,
+ const size_t len)
+{
+
+ int ret = 0;
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add string [%s], target object is invalid\n",
+ name);
+ return JSON_ERROR;
+ }
+
+ if (value != NULL && len > 0) {
+ json_t *string = json_stringn(value, len);
+ if (string == NULL) {
+ DBG_ERR("Unable to add string [%s], "
+ "could not create string object\n",
+ name);
+ return JSON_ERROR;
+ }
+ ret = json_object_set_new(object->root, name, string);
+ if (ret != 0) {
+ json_decref(string);
+ DBG_ERR("Unable to add string [%s]\n", name);
+ return ret;
+ }
+ } else {
+ ret = json_object_set_new(object->root, name, json_null());
+ if (ret != 0) {
+ DBG_ERR("Unable to add null string [%s]\n", name);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+/*
+ * @brief Add a version object to a JSON object
+ *
+ * Add a version object to the JSON object
+ * "version":{"major":1, "minor":0}
+ *
+ * The version tag is intended to aid the processing of the JSON messages
+ * The major version number should change when an attribute is:
+ * - renamed
+ * - removed
+ * - its meaning changes
+ * - its contents change format
+ * The minor version should change whenever a new attribute is added and for
+ * minor bug fixes to an attributes content.
+ *
+ *
+ * @param object the JSON object to be updated.
+ * @param major the major version number
+ * @param minor the minor version number
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ */
+int json_add_version(struct json_object *object, int major, int minor)
+{
+ int ret = 0;
+ struct json_object version;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add version, target object is invalid\n");
+ return JSON_ERROR;
+ }
+
+ version = json_new_object();
+ if (json_is_invalid(&version)) {
+ DBG_ERR("Unable to add version, failed to create object\n");
+ return JSON_ERROR;
+ }
+ ret = json_add_int(&version, "major", major);
+ if (ret != 0) {
+ json_free(&version);
+ return ret;
+ }
+ ret = json_add_int(&version, "minor", minor);
+ if (ret != 0) {
+ json_free(&version);
+ return ret;
+ }
+ ret = json_add_object(object, "version", &version);
+ if (ret != 0) {
+ json_free(&version);
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ * @brief add an ISO 8601 timestamp to the object.
+ *
+ * Add a date and time as a timestamp in ISO 8601 format to a JSON object
+ *
+ * "time":"2017-03-06T17:18:04.455081+1300"
+ *
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param time the value to set.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ */
+int json_add_time(struct json_object *object, const char *name, const struct timeval tv)
+{
+ char buffer[40]; /* formatted time less usec and timezone */
+ char timestamp[65]; /* the formatted ISO 8601 time stamp */
+ char tz[10]; /* formatted time zone */
+ struct tm* tm_info; /* current local time */
+ int ret; /* return code from json operations */
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add time, target object is invalid\n");
+ return JSON_ERROR;
+ }
+
+ tm_info = localtime(&tv.tv_sec);
+ if (tm_info == NULL) {
+ DBG_ERR("Unable to determine local time\n");
+ return JSON_ERROR;
+ }
+
+ strftime(buffer, sizeof(buffer)-1, "%Y-%m-%dT%T", tm_info);
+ strftime(tz, sizeof(tz)-1, "%z", tm_info);
+ snprintf(
+ timestamp,
+ sizeof(timestamp),
+ "%s.%06ld%s",
+ buffer,
+ tv.tv_usec,
+ tz);
+ ret = json_add_string(object, name, timestamp);
+ if (ret != 0) {
+ DBG_ERR("Unable to add time to JSON object\n");
+ }
+ return ret;
+}
+
+/*
+ * @brief add an ISO 8601 timestamp to the object.
+ *
+ * Add the current date and time as a timestamp in ISO 8601 format
+ * to a JSON object
+ *
+ * "timestamp":"2017-03-06T17:18:04.455081+1300"
+ *
+ *
+ * @param object the JSON object to be updated.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ */
+int json_add_timestamp(struct json_object *object)
+{
+ struct timeval tv; /* current system time */
+ int r; /* response code from gettimeofday */
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add time stamp, target object is invalid\n");
+ return JSON_ERROR;
+ }
+
+ r = gettimeofday(&tv, NULL);
+ if (r) {
+ DBG_ERR("Unable to get time of day: (%d) %s\n",
+ errno,
+ strerror(errno));
+ return JSON_ERROR;
+ }
+
+ return json_add_time(object, "timestamp", tv);
+}
+
+/*
+ *@brief Add a tsocket_address to a JSON object
+ *
+ * Add the string representation of a Samba tsocket_address to the object.
+ *
+ * "localAddress":"ipv6::::0"
+ *
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param address the tsocket_address.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_address(struct json_object *object,
+ const char *name,
+ const struct tsocket_address *address)
+{
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add address [%s], "
+ "target object is invalid\n",
+ name);
+ return JSON_ERROR;
+ }
+
+ if (address == NULL) {
+ ret = json_object_set_new(object->root, name, json_null());
+ if (ret != 0) {
+ DBG_ERR("Unable to add null address [%s]\n", name);
+ return JSON_ERROR;
+ }
+ } else {
+ TALLOC_CTX *ctx = talloc_new(NULL);
+ char *s = NULL;
+
+ if (ctx == NULL) {
+ DBG_ERR("Out of memory adding address [%s]\n", name);
+ return JSON_ERROR;
+ }
+
+ s = tsocket_address_string(address, ctx);
+ if (s == NULL) {
+ DBG_ERR("Out of memory adding address [%s]\n", name);
+ TALLOC_FREE(ctx);
+ return JSON_ERROR;
+ }
+ ret = json_add_string(object, name, s);
+ if (ret != 0) {
+ DBG_ERR(
+ "Unable to add address [%s] value [%s]\n", name, s);
+ TALLOC_FREE(ctx);
+ return JSON_ERROR;
+ }
+ TALLOC_FREE(ctx);
+ }
+ return ret;
+}
+
+/*
+ * @brief Add a formatted string representation of a sid to a json object.
+ *
+ * Add the string representation of a Samba sid to the object.
+ *
+ * "sid":"S-1-5-18"
+ *
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param sid the sid
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ */
+int json_add_sid(struct json_object *object,
+ const char *name,
+ const struct dom_sid *sid)
+{
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add SID [%s], "
+ "target object is invalid\n",
+ name);
+ return JSON_ERROR;
+ }
+
+ if (sid == NULL) {
+ ret = json_object_set_new(object->root, name, json_null());
+ if (ret != 0) {
+ DBG_ERR("Unable to add null SID [%s]\n", name);
+ return ret;
+ }
+ } else {
+ struct dom_sid_buf sid_buf;
+
+ ret = json_add_string(
+ object, name, dom_sid_str_buf(sid, &sid_buf));
+ if (ret != 0) {
+ DBG_ERR("Unable to add SID [%s] value [%s]\n",
+ name,
+ sid_buf.buf);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+/*
+ * @brief Add a formatted string representation of a guid to a json object.
+ *
+ * Add the string representation of a Samba GUID to the object.
+ *
+ * "guid":"1fb9f2ee-2a4d-4bf8-af8b-cb9d4529a9ab"
+ *
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param guid the guid.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ *
+ */
+int json_add_guid(struct json_object *object,
+ const char *name,
+ const struct GUID *guid)
+{
+
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add GUID [%s], "
+ "target object is invalid\n",
+ name);
+ return JSON_ERROR;
+ }
+
+ if (guid == NULL) {
+ ret = json_object_set_new(object->root, name, json_null());
+ if (ret != 0) {
+ DBG_ERR("Unable to add null GUID [%s]\n", name);
+ return ret;
+ }
+ } else {
+ char *guid_str;
+ struct GUID_txt_buf guid_buff;
+
+ guid_str = GUID_buf_string(guid, &guid_buff);
+ ret = json_add_string(object, name, guid_str);
+ if (ret != 0) {
+ DBG_ERR("Unable to add GUID [%s] value [%s]\n",
+ name,
+ guid_str);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+/*
+ * @brief Add a hex-formatted string representation of a 32-bit integer to a
+ * json object.
+ *
+ * Add a hex-formatted string representation of a 32-bit flags integer to the
+ * object.
+ *
+ * "accountFlags":"0x12345678"
+ *
+ *
+ * @param object the JSON object to be updated.
+ * @param name the name.
+ * @param flags the flags.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed
+ *
+ *
+ */
+int json_add_flags32(struct json_object *object,
+ const char *name,
+ const uint32_t flags)
+{
+ int ret = 0;
+ char buf[sizeof("0x12345678")];
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to add flags [%s], "
+ "target object is invalid\n",
+ name);
+ return JSON_ERROR;
+ }
+
+ ret = snprintf(buf, sizeof (buf), "0x%08X", flags);
+ if (ret != sizeof (buf) - 1) {
+ DBG_ERR("Unable to format flags [%s] value [0x%08X]\n",
+ name,
+ flags);
+ return JSON_ERROR;
+ }
+
+ ret = json_add_string(object, name, buf);
+ if (ret != 0) {
+ DBG_ERR("Unable to add flags [%s] value [%s]\n",
+ name,
+ buf);
+ }
+
+ return ret;
+}
+
+/*
+ * @brief Replaces the object for a given key with a given json object.
+ *
+ * If key already exists, the value will be replaced. Otherwise the given
+ * value will be added under the given key.
+ *
+ * @param object the JSON object to be updated.
+ * @param key the key which will be updated.
+ * @param new_obj the new value object to be inserted.
+ *
+ * @return 0 the operation was successful
+ * -1 the operation failed (e.j. if one of the parameters is invalid)
+ */
+int json_update_object(struct json_object *object,
+ const char *key,
+ struct json_object *new_obj)
+{
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Unable to update key [%s], "
+ "target object is invalid\n",
+ key);
+ return JSON_ERROR;
+ }
+ if (json_is_invalid(new_obj)) {
+ DBG_ERR("Unable to update key [%s], "
+ "new object is invalid\n",
+ key);
+ return JSON_ERROR;
+ }
+
+ if (key == NULL) {
+ DBG_ERR("Unable to add null String as key\n");
+ return JSON_ERROR;
+ }
+
+ ret = json_object_set(object->root, key, new_obj->root);
+ if (ret != 0) {
+ DBG_ERR("Unable to update object\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * @brief Convert a JSON object into a string
+ *
+ * Convert the json object into a string suitable for printing on a log line,
+ * i.e. with no embedded line breaks.
+ *
+ * If the object is invalid it logs an error and returns NULL.
+ *
+ * @param mem_ctx the talloc memory context owning the returned string
+ * @param object the json object.
+ *
+ * @return A string representation of the object or NULL if the object
+ * is invalid.
+ */
+char *json_to_string(TALLOC_CTX *mem_ctx, const struct json_object *object)
+{
+ char *json = NULL;
+ char *json_string = NULL;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Invalid JSON object, unable to convert to string\n");
+ return NULL;
+ }
+
+ if (object->root == NULL) {
+ return NULL;
+ }
+
+ /*
+ * json_dumps uses malloc, so need to call free(json) to release
+ * the memory
+ */
+ json = json_dumps(object->root, 0);
+ if (json == NULL) {
+ DBG_ERR("Unable to convert JSON object to string\n");
+ return NULL;
+ }
+
+ json_string = talloc_strdup(mem_ctx, json);
+ if (json_string == NULL) {
+ free(json);
+ DBG_ERR("Unable to copy JSON object string to talloc string\n");
+ return NULL;
+ }
+ free(json);
+
+ return json_string;
+}
+
+/*
+ * @brief get a json array named "name" from the json object.
+ *
+ * Get the array attribute named name, creating it if it does not exist.
+ *
+ * @param object the json object.
+ * @param name the name of the array attribute
+ *
+ * @return The array object, will be created if it did not exist.
+ */
+struct json_object json_get_array(struct json_object *object, const char *name)
+{
+
+ struct json_object array = json_empty_object;
+ json_t *a = NULL;
+ int ret = 0;
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Invalid JSON object, unable to get array [%s]\n",
+ name);
+ json_free(&array);
+ return array;
+ }
+
+ array = json_new_array();
+ if (json_is_invalid(&array)) {
+ DBG_ERR("Unable to create new array for [%s]\n", name);
+ return array;
+ }
+
+ a = json_object_get(object->root, name);
+ if (a == NULL) {
+ return array;
+ }
+
+ ret = json_array_extend(array.root, a);
+ if (ret != 0) {
+ DBG_ERR("Unable to get array [%s]\n", name);
+ json_free(&array);
+ return array;
+ }
+
+ return array;
+}
+
+/*
+ * @brief get a json object named "name" from the json object.
+ *
+ * Get the object attribute named name, creating it if it does not exist.
+ *
+ * @param object the json object.
+ * @param name the name of the object attribute
+ *
+ * @return The object, will be created if it did not exist.
+ */
+struct json_object json_get_object(struct json_object *object, const char *name)
+{
+
+ struct json_object o = json_new_object();
+ json_t *v = NULL;
+ int ret = 0;
+
+ if (json_is_invalid(&o)) {
+ DBG_ERR("Unable to get object [%s]\n", name);
+ json_free(&o);
+ return o;
+ }
+
+ if (json_is_invalid(object)) {
+ DBG_ERR("Invalid JSON object, unable to get object [%s]\n",
+ name);
+ json_free(&o);
+ return o;
+ }
+
+ v = json_object_get(object->root, name);
+ if (v == NULL) {
+ return o;
+ }
+ ret = json_object_update(o.root, v);
+ if (ret != 0) {
+ DBG_ERR("Unable to get object [%s]\n", name);
+ json_free(&o);
+ return o;
+ }
+ return o;
+}
+
+/*
+ * @brief Return the JSON null object.
+ *
+ * @return the JSON null object.
+ */
+_WARN_UNUSED_RESULT_ struct json_object json_null_object(void)
+{
+ struct json_object object = json_empty_object;
+
+ object.root = json_null();
+ if (object.root != NULL) {
+ object.valid = true;
+ }
+
+ return object;
+}
+
+/*
+ * @brief Create a JSON object from a structure containing audit information.
+ *
+ * @param audit_info the audit information from which to create a JSON object.
+ *
+ * @return the JSON object (which may be valid or not)
+ *
+ *
+ */
+struct json_object json_from_audit_info(const struct authn_audit_info *audit_info)
+{
+ struct json_object object = json_new_object();
+ enum auth_event_id_type auth_event_id;
+ const struct auth_user_info_dc *client_info = NULL;
+ const char *policy_name = NULL;
+ const char *silo_name = NULL;
+ const bool *policy_enforced = NULL;
+ NTSTATUS policy_status;
+ struct authn_int64_optional tgt_lifetime_mins;
+ const char *location = NULL;
+ const char *audit_event = NULL;
+ const char *audit_reason = NULL;
+ int rc = 0;
+
+ if (json_is_invalid(&object)) {
+ goto failure;
+ }
+
+ auth_event_id = authn_audit_info_event_id(audit_info);
+ rc = json_add_int(&object, "eventId", auth_event_id);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ policy_name = authn_audit_info_policy_name(audit_info);
+ rc = json_add_string(&object, "policyName", policy_name);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ silo_name = authn_audit_info_silo_name(audit_info);
+ rc = json_add_string(&object, "siloName", silo_name);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ policy_enforced = authn_audit_info_policy_enforced(audit_info);
+ rc = json_add_optional_bool(&object, "policyEnforced", policy_enforced);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ policy_status = authn_audit_info_policy_status(audit_info);
+ rc = json_add_string(&object, "status", nt_errstr(policy_status));
+ if (rc != 0) {
+ goto failure;
+ }
+
+ tgt_lifetime_mins = authn_audit_info_policy_tgt_lifetime_mins(audit_info);
+ if (tgt_lifetime_mins.is_present) {
+ rc = json_add_int(&object, "tgtLifetime", tgt_lifetime_mins.val);
+ if (rc != 0) {
+ goto failure;
+ }
+ }
+
+ location = authn_audit_info_location(audit_info);
+ rc = json_add_string(&object, "location", location);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ audit_event = authn_audit_info_event(audit_info);
+ rc = json_add_string(&object, "auditEvent", audit_event);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ audit_reason = authn_audit_info_reason(audit_info);
+ rc = json_add_string(&object, "reason", audit_reason);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ client_info = authn_audit_info_client_info(audit_info);
+ if (client_info != NULL) {
+ const struct auth_user_info *client_user_info = NULL;
+
+ client_user_info = client_info->info;
+ if (client_user_info != NULL) {
+ rc = json_add_string(&object, "checkedDomain", client_user_info->domain_name);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ rc = json_add_string(&object, "checkedAccount", client_user_info->account_name);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ rc = json_add_string(&object, "checkedLogonServer", client_user_info->logon_server);
+ if (rc != 0) {
+ goto failure;
+ }
+
+ rc = json_add_flags32(&object, "checkedAccountFlags", client_user_info->acct_flags);
+ if (rc != 0) {
+ goto failure;
+ }
+ }
+
+ if (client_info->num_sids) {
+ const struct dom_sid *policy_checked_sid = NULL;
+
+ policy_checked_sid = &client_info->sids[PRIMARY_USER_SID_INDEX].sid;
+ rc = json_add_sid(&object, "checkedSid", policy_checked_sid);
+ if (rc != 0) {
+ goto failure;
+ }
+ }
+ }
+
+ return object;
+
+failure:
+ json_free(&object);
+ return object;
+}
+
+#endif
diff --git a/lib/audit_logging/audit_logging.h b/lib/audit_logging/audit_logging.h
new file mode 100644
index 0000000..a8bcf6f
--- /dev/null
+++ b/lib/audit_logging/audit_logging.h
@@ -0,0 +1,113 @@
+/*
+ common routines for audit logging
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef _AUDIT_LOGGING_H_
+#define _AUDIT_LOGGING_H_
+#include <talloc.h>
+#include "lib/messaging/irpc.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/attr.h"
+
+_WARN_UNUSED_RESULT_ char *audit_get_timestamp(TALLOC_CTX *frame);
+void audit_log_human_text(const char *prefix,
+ const char *message,
+ int debug_class,
+ int debug_level);
+
+#ifdef HAVE_JANSSON
+#include <jansson.h>
+/*
+ * Wrapper for jannson JSON object
+ *
+ */
+struct json_object {
+ json_t *root;
+ bool valid;
+};
+extern const struct json_object json_empty_object;
+
+#define JSON_ERROR -1
+
+void audit_log_json(struct json_object *message,
+ int debug_class,
+ int debug_level);
+void audit_message_send(struct imessaging_context *msg_ctx,
+ const char *server_name,
+ uint32_t message_type,
+ struct json_object *message);
+_WARN_UNUSED_RESULT_ struct json_object json_new_object(void);
+_WARN_UNUSED_RESULT_ struct json_object json_new_array(void);
+void json_free(struct json_object *object);
+void json_assert_is_array(struct json_object *array);
+_WARN_UNUSED_RESULT_ bool json_is_invalid(const struct json_object *object);
+
+_WARN_UNUSED_RESULT_ int json_add_int(struct json_object *object,
+ const char *name,
+ const json_int_t value);
+_WARN_UNUSED_RESULT_ int json_add_bool(struct json_object *object,
+ const char *name,
+ const bool value);
+_WARN_UNUSED_RESULT_ int json_add_optional_bool(struct json_object *object,
+ const char *name,
+ const bool *value);
+_WARN_UNUSED_RESULT_ int json_add_string(struct json_object *object,
+ const char *name,
+ const char *value);
+_WARN_UNUSED_RESULT_ int json_add_object(struct json_object *object,
+ const char *name,
+ struct json_object *value);
+_WARN_UNUSED_RESULT_ int json_add_stringn(struct json_object *object,
+ const char *name,
+ const char *value,
+ const size_t len);
+_WARN_UNUSED_RESULT_ int json_add_version(struct json_object *object,
+ int major,
+ int minor);
+_WARN_UNUSED_RESULT_ int json_add_time(struct json_object *object, const char *name, struct timeval tv);
+_WARN_UNUSED_RESULT_ int json_add_timestamp(struct json_object *object);
+_WARN_UNUSED_RESULT_ int json_add_address(
+ struct json_object *object,
+ const char *name,
+ const struct tsocket_address *address);
+_WARN_UNUSED_RESULT_ int json_add_sid(struct json_object *object,
+ const char *name,
+ const struct dom_sid *sid);
+_WARN_UNUSED_RESULT_ int json_add_guid(struct json_object *object,
+ const char *name,
+ const struct GUID *guid);
+
+_WARN_UNUSED_RESULT_ int json_add_flags32(struct json_object *object,
+ const char *name,
+ uint32_t flags);
+
+_WARN_UNUSED_RESULT_ int json_update_object(struct json_object *object,
+ const char *key,
+ struct json_object *new_obj);
+
+_WARN_UNUSED_RESULT_ struct json_object json_get_array(
+ struct json_object *object, const char *name);
+_WARN_UNUSED_RESULT_ struct json_object json_get_object(
+ struct json_object *object, const char *name);
+_WARN_UNUSED_RESULT_ char *json_to_string(TALLOC_CTX *mem_ctx,
+ const struct json_object *object);
+_WARN_UNUSED_RESULT_ struct json_object json_null_object(void);
+struct authn_audit_info;
+_WARN_UNUSED_RESULT_ struct json_object json_from_audit_info(
+ const struct authn_audit_info *audit_info);
+#endif
+#endif
diff --git a/lib/audit_logging/tests/audit_logging_error_test.c b/lib/audit_logging/tests/audit_logging_error_test.c
new file mode 100644
index 0000000..12a81ff
--- /dev/null
+++ b/lib/audit_logging/tests/audit_logging_error_test.c
@@ -0,0 +1,901 @@
+/*
+ * Unit tests for the audit_logging library.
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+/*
+ * Unit tests for lib/audit_logging/audit_logging.c
+ *
+ * These tests exercise the error handling code and mock the jannson functions
+ * to trigger errors.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+
+#include "librpc/ndr/libndr.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/security/dom_sid.h"
+#include "lib/messaging/messaging.h"
+#include "auth/common_auth.h"
+
+#include "lib/audit_logging/audit_logging.h"
+
+const int JANSSON_FAILURE = -1;
+const int CALL_ORIG = -2;
+
+/*
+ * cmocka wrappers for json_object
+ */
+json_t *__wrap_json_object(void);
+json_t *__real_json_object(void);
+json_t *__wrap_json_object(void)
+{
+
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_json_object();
+}
+
+/*
+ * cmocka wrappers for json_array
+ */
+json_t *__wrap_json_array(void);
+json_t *__real_json_array(void);
+json_t *__wrap_json_array(void)
+{
+
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_json_array();
+}
+
+/*
+ * cmoka wrappers for json_integer
+ */
+json_t *__wrap_json_integer(json_int_t value);
+json_t *__real_json_integer(json_int_t value);
+json_t *__wrap_json_integer(json_int_t value)
+{
+
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_json_integer(value);
+}
+
+/*
+ * cmocka wrappers for json_string
+ */
+json_t *__wrap_json_string(const char *value);
+json_t *__real_json_string(const char *value);
+json_t *__wrap_json_string(const char *value)
+{
+
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_json_string(value);
+}
+
+/*
+ * cmocka wrappers for json_stringn
+ */
+json_t *__wrap_json_stringn(const char *value, size_t len);
+json_t *__real_json_stringn(const char *value, size_t len);
+json_t *__wrap_json_stringn(const char *value, size_t len)
+{
+
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_json_stringn(value, len);
+}
+
+/*
+ * cmocka wrappers for json_dumps
+ */
+char *__wrap_json_dumps(const json_t *json, size_t flags);
+char *__real_json_dumps(const json_t *json, size_t flags);
+char *__wrap_json_dumps(const json_t *json, size_t flags)
+{
+
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_json_dumps(json, flags);
+}
+
+/*
+ * cmocka wrappers for json_object_set_new
+ */
+int __wrap_json_object_set_new(json_t *object, const char *key, json_t *value);
+int __real_json_object_set_new(json_t *object, const char *key, json_t *value);
+int __wrap_json_object_set_new(json_t *object, const char *key, json_t *value)
+{
+ int rc = (int)mock();
+ if (rc != CALL_ORIG) {
+ return rc;
+ }
+ return __real_json_object_set_new(object, key, value);
+}
+
+/*
+ * cmocka wrappers for json_array_append_new
+ */
+int __wrap_json_array_append_new(json_t *object,
+ const char *key,
+ json_t *value);
+int __real_json_array_append_new(json_t *object,
+ const char *key,
+ json_t *value);
+int __wrap_json_array_append_new(json_t *object, const char *key, json_t *value)
+{
+ int rc = (int)mock();
+ if (rc != CALL_ORIG) {
+ return rc;
+ }
+ return __real_json_array_append_new(object, key, value);
+}
+
+/*
+ * cmocka wrappers for json_array_extend
+ */
+int __wrap_json_array_extend(json_t *array, json_t *other_array);
+int __real_json_array_extend(json_t *array, json_t *other_array);
+int __wrap_json_array_extend(json_t *array, json_t *other_array)
+{
+
+ int rc = (int)mock();
+ if (rc != CALL_ORIG) {
+ return rc;
+ }
+ return __real_json_array_extend(array, other_array);
+}
+
+/*
+ * cmocka wrappers for json_object_update
+ */
+int __wrap_json_object_update(json_t *object, json_t *other_object);
+int __real_json_object_update(json_t *object, json_t *other_object);
+int __wrap_json_object_update(json_t *object, json_t *other_object)
+{
+
+ int rc = (int)mock();
+ if (rc != CALL_ORIG) {
+ return rc;
+ }
+ return __real_json_array_extend(object, other_object);
+}
+
+/*
+ * cmocka wrappers for gettimeofday
+ */
+int __wrap_gettimeofday(struct timeval *tv, struct timezone *tz);
+int __real_gettimeofday(struct timeval *tv, struct timezone *tz);
+int __wrap_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+
+ int rc = (int)mock();
+ if (rc != 0) {
+ return rc;
+ }
+ return __real_gettimeofday(tv, tz);
+}
+
+/*
+ * cmocka wrappers for localtime
+ */
+struct tm *__wrap_localtime(const time_t *timep);
+struct tm *__real_localtime(const time_t *timep);
+struct tm *__wrap_localtime(const time_t *timep)
+{
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_localtime(timep);
+}
+
+/*
+ * cmocka wrappers for talloc_named_const
+ */
+static const void *REAL_TALLOC = "Here";
+
+void *__wrap_talloc_named_const(const void *context,
+ size_t size,
+ const char *name);
+void *__real_talloc_named_const(const void *context,
+ size_t size,
+ const char *name);
+void *__wrap_talloc_named_const(const void *context,
+ size_t size,
+ const char *name)
+{
+
+ void *ret = (void *)mock();
+
+ if (ret == NULL) {
+ return NULL;
+ }
+ return __real_talloc_named_const(context, size, name);
+}
+
+/*
+ * cmocka wrappers for talloc_strdup
+ */
+char *__wrap_talloc_strdup(const void *t, const char *p);
+char *__real_talloc_strdup(const void *t, const char *p);
+char *__wrap_talloc_strdup(const void *t, const char *p)
+{
+
+ void *ret = (void *)mock();
+
+ if (ret == NULL) {
+ return NULL;
+ }
+ return __real_talloc_strdup(t, p);
+}
+
+char *__wrap_tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+char *__real_tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+char *__wrap_tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+
+ bool fail = (bool)mock();
+ if (fail) {
+ return NULL;
+ }
+ return __real_tsocket_address_string(addr, mem_ctx);
+}
+
+static void test_json_add_int(_UNUSED_ void **state)
+{
+ struct json_object object;
+ int rc = 0;
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ /*
+ * Test json integer failure
+ */
+ will_return(__wrap_json_integer, true);
+ rc = json_add_int(&object, "name", 2);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json object set new failure
+ */
+ will_return(__wrap_json_integer, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_int(&object, "name", 2);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+ json_free(&object);
+}
+
+static void test_json_add_bool(_UNUSED_ void **state)
+{
+ struct json_object object;
+ int rc = 0;
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ /*
+ * json_boolean does not return an error code.
+ * Test json object set new failure
+ */
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_bool(&object, "name", true);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+}
+
+static void test_json_add_string(_UNUSED_ void **state)
+{
+ struct json_object object;
+ int rc = 0;
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ /*
+ * Test json string failure
+ */
+ will_return(__wrap_json_string, true);
+ rc = json_add_string(&object, "name", "value");
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json object set new failure
+ */
+ will_return(__wrap_json_string, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_string(&object, "name", "value");
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json object set new failure for a NULL string
+ */
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_string(&object, "null", NULL);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+}
+
+static void test_json_add_object(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_object value;
+ int rc = 0;
+
+ will_return(__wrap_json_object, false);
+ will_return(__wrap_json_object, false);
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ value = json_new_object();
+ assert_false(json_is_invalid(&value));
+
+ /*
+ * Test json object set new failure
+ */
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_object(&object, "name", &value);
+
+ assert_false(json_is_invalid(&object));
+ assert_false(json_is_invalid(&value));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json object set new failure for a NULL value
+ */
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_object(&object, "null", NULL);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+ json_free(&value);
+}
+
+static void test_json_add_to_array(_UNUSED_ void **state)
+{
+ struct json_object array;
+ struct json_object value;
+ int rc = 0;
+
+ will_return(__wrap_json_array, false);
+ will_return(__wrap_json_object, false);
+
+ array = json_new_array();
+ assert_false(json_is_invalid(&array));
+
+ value = json_new_object();
+ assert_false(json_is_invalid(&value));
+
+ /*
+ * Test json array append new failure
+ */
+ will_return(__wrap_json_array_append_new, JANSSON_FAILURE);
+ rc = json_add_object(&array, "name", &value);
+
+ assert_false(json_is_invalid(&array));
+ assert_false(json_is_invalid(&value));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json append new failure with a NULL value
+ */
+ will_return(__wrap_json_array_append_new, JANSSON_FAILURE);
+ rc = json_add_object(&array, "null", NULL);
+
+ assert_false(json_is_invalid(&array));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&array);
+ json_free(&value);
+}
+
+static void test_json_add_timestamp(_UNUSED_ void **state)
+{
+ struct json_object object;
+ int rc = 0;
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ /*
+ * Test json string failure
+ */
+ will_return(__wrap_gettimeofday, 0);
+ will_return(__wrap_localtime, false);
+ will_return(__wrap_json_string, true);
+ rc = json_add_timestamp(&object);
+
+ /*
+ * Test json_object_set_new failure
+ */
+ will_return(__wrap_gettimeofday, 0);
+ will_return(__wrap_localtime, false);
+ will_return(__wrap_json_string, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_timestamp(&object);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test gettimeofday failure
+ */
+ will_return(__wrap_gettimeofday, -1);
+ rc = json_add_timestamp(&object);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test local time failure
+ */
+ will_return(__wrap_gettimeofday, 0);
+ will_return(__wrap_localtime, true);
+ rc = json_add_timestamp(&object);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+}
+
+static void test_json_add_stringn(_UNUSED_ void **state)
+{
+ struct json_object object;
+ int rc = 0;
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ /*
+ * Test json string failure
+ */
+ will_return(__wrap_json_stringn, true);
+ rc = json_add_stringn(&object, "name", "value", 3);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json object set new failure
+ */
+ will_return(__wrap_json_stringn, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_stringn(&object, "name", "value", 3);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json object set new failure for a NULL string
+ */
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_stringn(&object, "null", NULL, 2);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Test json object set new failure for a zero string size
+ */
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_stringn(&object, "zero", "no value", 0);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+ json_free(&object);
+}
+
+static void test_json_add_version(_UNUSED_ void **state)
+{
+ struct json_object object;
+ int rc = 0;
+
+ /*
+ * Fail creating the version object
+ */
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object, true);
+ rc = json_add_version(&object, 1, 11);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ /*
+ * Fail adding the major version
+ */
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object, false);
+ will_return(__wrap_json_integer, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_version(&object, 2, 12);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ /*
+ * Fail adding the minor version
+ */
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object, false);
+ will_return(__wrap_json_integer, false);
+ will_return(__wrap_json_object_set_new, CALL_ORIG);
+ will_return(__wrap_json_integer, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_version(&object, 3, 13);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ /*
+ * Fail adding the version object
+ */
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object, false);
+ will_return(__wrap_json_integer, false);
+ will_return(__wrap_json_object_set_new, CALL_ORIG);
+ will_return(__wrap_json_integer, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_version(&object, 4, 14);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+}
+
+static void test_json_add_address(_UNUSED_ void **state)
+{
+ struct json_object object;
+ int rc = 0;
+ struct tsocket_address *ip = NULL;
+
+ TALLOC_CTX *ctx = NULL;
+
+ will_return(__wrap_talloc_named_const, REAL_TALLOC);
+ ctx = talloc_new(NULL);
+
+ /*
+ * Add a null address
+ */
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_address(&object, "name", NULL);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Add a non null address, json_object_set_new failure
+ */
+ rc = tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 21, &ip);
+ assert_int_equal(0, rc);
+
+ will_return(__wrap_talloc_named_const, REAL_TALLOC);
+ will_return(__wrap_tsocket_address_string, false);
+ will_return(__wrap_json_string, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_address(&object, "name", ip);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Add a non null address, with a talloc failure
+ */
+ rc = tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 21, &ip);
+ assert_int_equal(0, rc);
+
+ will_return(__wrap_talloc_named_const, NULL);
+ rc = json_add_address(&object, "name", ip);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Add a non null address, tsocket_address_string failure
+ */
+ rc = tsocket_address_inet_from_strings(ctx, "ip", "127.0.0.1", 21, &ip);
+ assert_int_equal(0, rc);
+
+ will_return(__wrap_talloc_named_const, REAL_TALLOC);
+ will_return(__wrap_tsocket_address_string, true);
+ rc = json_add_address(&object, "name", ip);
+
+ assert_false(json_is_invalid(&object));
+ assert_int_equal(JSON_ERROR, rc);
+
+ TALLOC_FREE(ctx);
+ json_free(&object);
+}
+
+static void test_json_add_sid(void **state)
+{
+ struct json_object object;
+ const char *SID = "S-1-5-21-2470180966-3899876309-2637894779";
+ struct dom_sid sid;
+ int rc;
+
+ /*
+ * Add a null SID
+ */
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_sid(&object, "null", NULL);
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Add a non null SID
+ */
+ assert_true(string_to_sid(&sid, SID));
+ will_return(__wrap_json_string, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_sid(&object, "sid", &sid);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+}
+
+static void test_json_add_guid(void **state)
+{
+ struct json_object object;
+ const char *GUID = "3ab88633-1e57-4c1a-856c-d1bc4b15bbb1";
+ struct GUID guid;
+ NTSTATUS status;
+ int rc;
+
+ /*
+ * Add a null GUID
+ */
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_guid(&object, "null", NULL);
+ assert_int_equal(JSON_ERROR, rc);
+
+ /*
+ * Add a non null GUID
+ */
+ status = GUID_from_string(GUID, &guid);
+ assert_true(NT_STATUS_IS_OK(status));
+ will_return(__wrap_json_string, false);
+ will_return(__wrap_json_object_set_new, JANSSON_FAILURE);
+ rc = json_add_guid(&object, "guid", &guid);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+}
+
+static void test_json_to_string(_UNUSED_ void **state)
+{
+ struct json_object object;
+ char *s = NULL;
+ TALLOC_CTX *ctx = NULL;
+
+ will_return(__wrap_talloc_named_const, REAL_TALLOC);
+ ctx = talloc_new(NULL);
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ /*
+ * json_dumps failure
+ */
+ will_return(__wrap_json_dumps, true);
+ s = json_to_string(ctx, &object);
+ assert_null(s);
+
+ /*
+ * talloc failure
+ */
+ will_return(__wrap_json_dumps, false);
+ will_return(__wrap_talloc_strdup, NULL);
+ s = json_to_string(ctx, &object);
+ assert_null(s);
+ TALLOC_FREE(ctx);
+ json_free(&object);
+}
+
+static void test_json_get_array(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_object stored_array;
+ struct json_object array;
+
+ int rc;
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_array, false);
+ stored_array = json_new_array();
+ assert_false(json_is_invalid(&stored_array));
+
+ will_return(__wrap_json_object_set_new, CALL_ORIG);
+ rc = json_add_object(&object, "array", &stored_array);
+ assert_int_equal(0, rc);
+
+ /*
+ * json array failure
+ */
+ will_return(__wrap_json_array, true);
+ array = json_get_array(&object, "array");
+ assert_true(json_is_invalid(&array));
+
+ /*
+ * json array extend failure
+ */
+ will_return(__wrap_json_array, false);
+ will_return(__wrap_json_array_extend, true);
+ array = json_get_array(&object, "array");
+ assert_true(json_is_invalid(&array));
+
+ json_free(&stored_array);
+ json_free(&object);
+}
+
+static void test_json_get_object(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_object stored;
+ struct json_object retrieved;
+
+ int rc;
+
+ will_return(__wrap_json_object, false);
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ will_return(__wrap_json_object, false);
+ stored = json_new_object();
+ assert_false(json_is_invalid(&stored));
+
+ will_return(__wrap_json_object_set_new, CALL_ORIG);
+ rc = json_add_object(&object, "stored", &stored);
+ assert_int_equal(0, rc);
+
+ /*
+ * json object update failure
+ */
+ will_return(__wrap_json_object, false);
+ will_return(__wrap_json_object_update, true);
+ retrieved = json_get_object(&object, "stored");
+ assert_true(json_is_invalid(&retrieved));
+
+ json_free(&object);
+}
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_json_add_int),
+ cmocka_unit_test(test_json_add_bool),
+ cmocka_unit_test(test_json_add_string),
+ cmocka_unit_test(test_json_add_object),
+ cmocka_unit_test(test_json_add_to_array),
+ cmocka_unit_test(test_json_add_timestamp),
+ cmocka_unit_test(test_json_add_stringn),
+ cmocka_unit_test(test_json_add_version),
+ cmocka_unit_test(test_json_add_address),
+ cmocka_unit_test(test_json_add_sid),
+ cmocka_unit_test(test_json_add_guid),
+ cmocka_unit_test(test_json_to_string),
+ cmocka_unit_test(test_json_get_array),
+ cmocka_unit_test(test_json_get_object),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/audit_logging/tests/audit_logging_test.c b/lib/audit_logging/tests/audit_logging_test.c
new file mode 100644
index 0000000..0923882
--- /dev/null
+++ b/lib/audit_logging/tests/audit_logging_test.c
@@ -0,0 +1,919 @@
+/*
+ * Unit tests for the audit_logging library.
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+/*
+ * Note that the messaging routines (audit_message_send and get_event_server)
+ * are not tested by these unit tests. Currently they are for integration
+ * test support, and as such are exercised by the integration tests.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <string.h>
+#include <time.h>
+#include <tevent.h>
+#include <config.h>
+#include <talloc.h>
+#include "lib/util/talloc_stack.h"
+
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "libcli/util/werror.h"
+#include "lib/param/loadparm.h"
+#include "libcli/security/dom_sid.h"
+#include "librpc/ndr/libndr.h"
+
+#include "lib/audit_logging/audit_logging.h"
+
+static void test_json_add_int(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *value = NULL;
+ json_int_t m;
+ double n;
+ int rc = 0;
+ intmax_t big_int = ((intmax_t)1)<<33;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+ rc = json_add_int(&object, "positive_one", 1);
+ assert_int_equal(0, rc);
+ rc = json_add_int(&object, "zero", 0);
+ assert_int_equal(0, rc);
+ rc = json_add_int(&object, "negative_one", -1);
+ assert_int_equal(0, rc);
+ rc = json_add_int(&object, "big_int", big_int);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(4, json_object_size(object.root));
+
+ value = json_object_get(object.root, "positive_one");
+ assert_true(json_is_integer(value));
+ n = json_number_value(value);
+ assert_true(n == 1.0);
+
+ value = json_object_get(object.root, "zero");
+ assert_true(json_is_integer(value));
+ n = json_number_value(value);
+ assert_true(n == 0.0);
+
+ value = json_object_get(object.root, "negative_one");
+ assert_true(json_is_integer(value));
+ n = json_number_value(value);
+ assert_true(n == -1.0);
+
+ value = json_object_get(object.root, "big_int");
+ assert_true(json_is_integer(value));
+ m = json_integer_value(value);
+ assert_int_equal(m, big_int);
+
+ object.valid = false;
+ rc = json_add_int(&object, "should fail 1", 0xf1);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_int(&object, "should fail 2", 0xf2);
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_add_bool(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *value = NULL;
+ int rc = 0;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+ rc = json_add_bool(&object, "true", true);
+ assert_int_equal(0, rc);
+ rc = json_add_bool(&object, "false", false);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(2, json_object_size(object.root));
+
+ value = json_object_get(object.root, "true");
+ assert_true(json_is_boolean(value));
+ assert_true(value == json_true());
+
+ value = json_object_get(object.root, "false");
+ assert_true(json_is_boolean(value));
+ assert_true(value == json_false());
+
+ object.valid = false;
+ rc = json_add_bool(&object, "should fail 1", true);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_bool(&object, "should fail 2", false);
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_add_string(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *value = NULL;
+ const char *s = NULL;
+ int rc = 0;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+ rc = json_add_string(&object, "null", NULL);
+ assert_int_equal(0, rc);
+ rc = json_add_string(&object, "empty", "");
+ assert_int_equal(0, rc);
+ rc = json_add_string(&object, "name", "value");
+ assert_int_equal(0, rc);
+
+ assert_int_equal(3, json_object_size(object.root));
+
+ value = json_object_get(object.root, "null");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "empty");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("", s);
+
+ value = json_object_get(object.root, "name");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("value", s);
+
+ object.valid = false;
+ rc = json_add_string(&object, "should fail 1", "A value");
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_string(&object, "should fail 2", "Another value");
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_add_object(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_object other;
+ struct json_object after;
+ struct json_object invalid = json_empty_object;
+ struct json_t *value = NULL;
+ int rc = 0;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+ other = json_new_object();
+ assert_false(json_is_invalid(&other));
+ rc = json_add_object(&object, "null", NULL);
+ assert_int_equal(0, rc);
+ rc = json_add_object(&object, "other", &other);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(2, json_object_size(object.root));
+
+ value = json_object_get(object.root, "null");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "other");
+ assert_true(json_is_object(value));
+ assert_ptr_equal(other.root, value);
+
+ rc = json_add_object(&object, "invalid", &invalid);
+ assert_int_equal(JSON_ERROR, rc);
+
+ object.valid = false;
+ after = json_new_object();
+ assert_false(json_is_invalid(&after));
+ rc = json_add_object(&object, "after", &after);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_object(&object, "after", &after);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&after);
+}
+
+static void test_json_add_to_array(_UNUSED_ void **state)
+{
+ struct json_object array;
+ struct json_object o1;
+ struct json_object o2;
+ struct json_object o3;
+ struct json_object after;
+ struct json_object invalid = json_empty_object;
+ struct json_t *value = NULL;
+ int rc = 0;
+
+ array = json_new_array();
+ assert_false(json_is_invalid(&array));
+ assert_true(json_is_array(array.root));
+
+ o1 = json_new_object();
+ assert_false(json_is_invalid(&o1));
+ o2 = json_new_object();
+ assert_false(json_is_invalid(&o2));
+ o3 = json_new_object();
+ assert_false(json_is_invalid(&o3));
+
+ rc = json_add_object(&array, NULL, &o3);
+ assert_int_equal(0, rc);
+ rc = json_add_object(&array, "", &o2);
+ assert_int_equal(0, rc);
+ rc = json_add_object(&array, "will-be-ignored", &o1);
+ assert_int_equal(0, rc);
+ rc = json_add_object(&array, NULL, NULL);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(4, json_array_size(array.root));
+
+ value = json_array_get(array.root, 0);
+ assert_ptr_equal(o3.root, value);
+
+ value = json_array_get(array.root, 1);
+ assert_ptr_equal(o2.root, value);
+
+ value = json_array_get(array.root, 2);
+ assert_ptr_equal(o1.root, value);
+
+ value = json_array_get(array.root, 3);
+ assert_true(json_is_null(value));
+
+ rc = json_add_object(&array, "invalid", &invalid);
+ assert_int_equal(JSON_ERROR, rc);
+
+ array.valid = false;
+ after = json_new_object();
+ assert_false(json_is_invalid(&after));
+ rc = json_add_object(&array, "after", &after);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&array);
+
+ rc = json_add_object(&array, "after", &after);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&after);
+}
+
+static void test_json_add_timestamp(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *ts = NULL;
+ const char *t = NULL;
+ int rc;
+ int usec, tz;
+ char c[2];
+ struct tm tm;
+ time_t before;
+ time_t after;
+ time_t actual;
+ struct timeval tv;
+ int ret;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ ret = gettimeofday(&tv, NULL);
+ assert_int_equal(0, ret);
+ before = tv.tv_sec;
+
+ rc = json_add_timestamp(&object);
+ assert_int_equal(0, rc);
+
+ ret = gettimeofday(&tv, NULL);
+ assert_int_equal(0, ret);
+ after = tv.tv_sec;
+
+ ts = json_object_get(object.root, "timestamp");
+ assert_true(json_is_string(ts));
+
+ /*
+ * Convert the returned ISO 8601 timestamp into a time_t
+ * Note for convenience we ignore the value of the microsecond
+ * part of the time stamp.
+ */
+ t = json_string_value(ts);
+ rc = sscanf(
+ t,
+ "%4d-%2d-%2dT%2d:%2d:%2d.%6d%1c%4d",
+ &tm.tm_year,
+ &tm.tm_mon,
+ &tm.tm_mday,
+ &tm.tm_hour,
+ &tm.tm_min,
+ &tm.tm_sec,
+ &usec,
+ c,
+ &tz);
+ assert_int_equal(9, rc);
+ tm.tm_year = tm.tm_year - 1900;
+ tm.tm_mon = tm.tm_mon - 1;
+ tm.tm_isdst = -1;
+ actual = mktime(&tm);
+
+ /*
+ * The timestamp should be before <= actual <= after
+ */
+ assert_true(difftime(actual, before) >= 0);
+ assert_true(difftime(after, actual) >= 0);
+
+ object.valid = false;
+ rc = json_add_timestamp(&object);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_timestamp(&object);
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_add_stringn(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *value = NULL;
+ const char *s = NULL;
+ int rc = 0;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+ rc = json_add_stringn(&object, "null", NULL, 10);
+ assert_int_equal(0, rc);
+ rc = json_add_stringn(&object, "null-zero-len", NULL, 0);
+ assert_int_equal(0, rc);
+ rc = json_add_stringn(&object, "empty", "", 1);
+ assert_int_equal(0, rc);
+ rc = json_add_stringn(&object, "empty-zero-len", "", 0);
+ assert_int_equal(0, rc);
+ rc = json_add_stringn(&object, "value-less-than-len", "123456", 7);
+ assert_int_equal(0, rc);
+ rc = json_add_stringn(&object, "value-greater-than-len", "abcd", 3);
+ assert_int_equal(0, rc);
+ rc = json_add_stringn(&object, "value-equal-len", "ZYX", 3);
+ assert_int_equal(0, rc);
+ rc = json_add_stringn(
+ &object, "value-len-is-zero", "this will be null", 0);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(8, json_object_size(object.root));
+
+ value = json_object_get(object.root, "null");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "null-zero-len");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "empty");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("", s);
+
+ value = json_object_get(object.root, "empty-zero-len");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "value-greater-than-len");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("abc", s);
+ assert_int_equal(3, strlen(s));
+
+ value = json_object_get(object.root, "value-equal-len");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("ZYX", s);
+ assert_int_equal(3, strlen(s));
+
+ value = json_object_get(object.root, "value-len-is-zero");
+ assert_true(json_is_null(value));
+
+ object.valid = false;
+ rc = json_add_stringn(&object, "fail-01", "xxxxxxx", 1);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_stringn(&object, "fail-02", "xxxxxxx", 1);
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_add_version(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *version = NULL;
+ struct json_t *v = NULL;
+ double n;
+ int rc;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+ rc = json_add_version(&object, 3, 1);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(1, json_object_size(object.root));
+
+ version = json_object_get(object.root, "version");
+ assert_true(json_is_object(version));
+ assert_int_equal(2, json_object_size(version));
+
+ v = json_object_get(version, "major");
+ assert_true(json_is_integer(v));
+ n = json_number_value(v);
+ assert_true(n == 3.0);
+
+ v = json_object_get(version, "minor");
+ assert_true(json_is_integer(v));
+ n = json_number_value(v);
+ assert_true(n == 1.0);
+
+ object.valid = false;
+ rc = json_add_version(&object, 3, 1);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_version(&object, 3, 1);
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_add_address(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *value = NULL;
+ struct tsocket_address *ip4 = NULL;
+ struct tsocket_address *ip6 = NULL;
+ struct tsocket_address *pipe = NULL;
+
+ struct tsocket_address *after = NULL;
+ const char *s = NULL;
+ int rc;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ rc = json_add_address(&object, "null", NULL);
+ assert_int_equal(0, rc);
+
+ rc = tsocket_address_inet_from_strings(
+ ctx,
+ "ip",
+ "127.0.0.1",
+ 21,
+ &ip4);
+ assert_int_equal(0, rc);
+ rc = json_add_address(&object, "ip4", ip4);
+ assert_int_equal(0, rc);
+
+ rc = tsocket_address_inet_from_strings(
+ ctx,
+ "ip",
+ "2001:db8:0:0:1:0:0:1",
+ 42,
+ &ip6);
+ assert_int_equal(0, rc);
+ rc = json_add_address(&object, "ip6", ip6);
+ assert_int_equal(0, rc);
+
+ rc = tsocket_address_unix_from_path(ctx, "/samba/pipe", &pipe);
+ assert_int_equal(0, rc);
+ rc = json_add_address(&object, "pipe", pipe);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(4, json_object_size(object.root));
+
+ value = json_object_get(object.root, "null");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "ip4");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("ipv4:127.0.0.1:21", s);
+
+ value = json_object_get(object.root, "ip6");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("ipv6:2001:db8::1:0:0:1:42", s);
+
+ value = json_object_get(object.root, "pipe");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal("unix:/samba/pipe", s);
+
+ object.valid = false;
+ rc = tsocket_address_inet_from_strings(
+ ctx, "ip", "127.0.0.11", 23, &after);
+ assert_int_equal(0, rc);
+ rc = json_add_address(&object, "invalid_object", after);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_address(&object, "freed object", after);
+ assert_int_equal(JSON_ERROR, rc);
+
+ TALLOC_FREE(ctx);
+}
+
+static void test_json_add_sid(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *value = NULL;
+ const char *SID = "S-1-5-21-2470180966-3899876309-2637894779";
+ struct dom_sid sid;
+ const char *s = NULL;
+ int rc;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ rc = json_add_sid(&object, "null", NULL);
+ assert_int_equal(0, rc);
+
+ assert_true(string_to_sid(&sid, SID));
+ rc = json_add_sid(&object, "sid", &sid);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(2, json_object_size(object.root));
+
+ value = json_object_get(object.root, "null");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "sid");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal(SID, s);
+
+ object.valid = false;
+ rc = json_add_sid(&object, "invalid_object", &sid);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_sid(&object, "freed_object", &sid);
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_add_guid(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_t *value = NULL;
+ const char *GUID = "3ab88633-1e57-4c1a-856c-d1bc4b15bbb1";
+ struct GUID guid;
+ const char *s = NULL;
+ NTSTATUS status;
+ int rc;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ rc = json_add_guid(&object, "null", NULL);
+ assert_int_equal(0, rc);
+
+ status = GUID_from_string(GUID, &guid);
+ assert_true(NT_STATUS_IS_OK(status));
+ rc = json_add_guid(&object, "guid", &guid);
+ assert_int_equal(0, rc);
+
+ assert_int_equal(2, json_object_size(object.root));
+
+ value = json_object_get(object.root, "null");
+ assert_true(json_is_null(value));
+
+ value = json_object_get(object.root, "guid");
+ assert_true(json_is_string(value));
+ s = json_string_value(value);
+ assert_string_equal(GUID, s);
+
+ object.valid = false;
+ rc = json_add_guid(&object, "invalid_object", &guid);
+ assert_int_equal(JSON_ERROR, rc);
+
+ json_free(&object);
+
+ rc = json_add_guid(&object, "freed_object", &guid);
+ assert_int_equal(JSON_ERROR, rc);
+}
+
+static void test_json_to_string(_UNUSED_ void **state)
+{
+ struct json_object object;
+ char *s = NULL;
+ int rc;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ s = json_to_string(ctx, &object);
+ assert_string_equal("{}", s);
+ TALLOC_FREE(s);
+
+ rc = json_add_string(&object, "name", "value");
+ assert_int_equal(0, rc);
+ s = json_to_string(ctx, &object);
+ assert_string_equal("{\"name\": \"value\"}", s);
+ TALLOC_FREE(s);
+
+ object.valid = false;
+ s = json_to_string(ctx, &object);
+ assert_null(s);
+
+ json_free(&object);
+
+ object.valid = true;
+ object.root = NULL;
+
+ s = json_to_string(ctx, &object);
+ assert_null(s);
+ TALLOC_FREE(ctx);
+}
+
+static void test_json_get_array(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_object array;
+ struct json_object stored_array = json_new_array();
+ json_t *value = NULL;
+ json_t *o = NULL;
+ struct json_object o1;
+ struct json_object o2;
+ int rc;
+
+ assert_false(json_is_invalid(&stored_array));
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ array = json_get_array(&object, "not-there");
+ assert_true(array.valid);
+ assert_non_null(array.root);
+ assert_true(json_is_array(array.root));
+ json_free(&array);
+
+ o1 = json_new_object();
+ assert_false(json_is_invalid(&o1));
+ rc = json_add_string(&o1, "value", "value-one");
+ assert_int_equal(0, rc);
+ rc = json_add_object(&stored_array, NULL, &o1);
+ assert_int_equal(0, rc);
+ rc = json_add_object(&object, "stored_array", &stored_array);
+ assert_int_equal(0, rc);
+
+ array = json_get_array(&object, "stored_array");
+ assert_true(array.valid);
+ assert_non_null(array.root);
+ assert_true(json_is_array(array.root));
+
+ assert_int_equal(1, json_array_size(array.root));
+
+ o = json_array_get(array.root, 0);
+ assert_non_null(o);
+ assert_true(json_is_object(o));
+
+ value = json_object_get(o, "value");
+ assert_non_null(value);
+ assert_true(json_is_string(value));
+
+ assert_string_equal("value-one", json_string_value(value));
+ json_free(&array);
+
+ /*
+ * Now update the array and add it back to the object
+ */
+ array = json_get_array(&object, "stored_array");
+ assert_true(json_is_array(array.root));
+ o2 = json_new_object();
+ assert_false(json_is_invalid(&o2));
+ rc = json_add_string(&o2, "value", "value-two");
+ assert_int_equal(0, rc);
+ assert_true(o2.valid);
+ rc = json_add_object(&array, NULL, &o2);
+ assert_int_equal(0, rc);
+ assert_true(json_is_array(array.root));
+ rc = json_add_object(&object, "stored_array", &array);
+ assert_int_equal(0, rc);
+ assert_true(json_is_array(array.root));
+
+ array = json_get_array(&object, "stored_array");
+ assert_non_null(array.root);
+ assert_true(json_is_array(array.root));
+ assert_true(array.valid);
+ assert_true(json_is_array(array.root));
+
+ assert_int_equal(2, json_array_size(array.root));
+
+ o = json_array_get(array.root, 0);
+ assert_non_null(o);
+ assert_true(json_is_object(o));
+
+ assert_non_null(value);
+ assert_true(json_is_string(value));
+
+ assert_string_equal("value-one", json_string_value(value));
+
+ o = json_array_get(array.root, 1);
+ assert_non_null(o);
+ assert_true(json_is_object(o));
+
+ value = json_object_get(o, "value");
+ assert_non_null(value);
+ assert_true(json_is_string(value));
+
+ assert_string_equal("value-two", json_string_value(value));
+
+ json_free(&array);
+ json_free(&object);
+
+ array = json_get_array(&object, "stored_array");
+ assert_false(array.valid);
+ json_free(&array);
+}
+
+static void test_json_get_object(_UNUSED_ void **state)
+{
+ struct json_object object;
+ struct json_object o1;
+ struct json_object o2;
+ struct json_object o3;
+ json_t *value = NULL;
+ int rc;
+
+ object = json_new_object();
+ assert_false(json_is_invalid(&object));
+
+ o1 = json_get_object(&object, "not-there");
+ assert_true(o1.valid);
+ assert_non_null(o1.root);
+ assert_true(json_is_object(o1.root));
+ json_free(&o1);
+
+ o1 = json_new_object();
+ assert_false(json_is_invalid(&o1));
+ rc = json_add_string(&o1, "value", "value-one");
+ assert_int_equal(0, rc);
+ rc = json_add_object(&object, "stored_object", &o1);
+ assert_int_equal(0, rc);
+
+ o2 = json_get_object(&object, "stored_object");
+ assert_true(o2.valid);
+ assert_non_null(o2.root);
+ assert_true(json_is_object(o2.root));
+
+ value = json_object_get(o2.root, "value");
+ assert_non_null(value);
+ assert_true(json_is_string(value));
+
+ assert_string_equal("value-one", json_string_value(value));
+
+ rc = json_add_string(&o2, "value", "value-two");
+ assert_int_equal(0, rc);
+ rc = json_add_object(&object, "stored_object", &o2);
+ assert_int_equal(0, rc);
+
+ o3 = json_get_object(&object, "stored_object");
+ assert_true(o3.valid);
+ assert_non_null(o3.root);
+ assert_true(json_is_object(o3.root));
+
+ value = json_object_get(o3.root, "value");
+ assert_non_null(value);
+ assert_true(json_is_string(value));
+
+ assert_string_equal("value-two", json_string_value(value));
+
+ json_free(&o3);
+ json_free(&object);
+
+ o3 = json_get_object(&object, "stored_object");
+ assert_false(o3.valid);
+ json_free(&o3);
+}
+
+static void test_audit_get_timestamp(_UNUSED_ void **state)
+{
+ const char *t = NULL;
+ char *c;
+ struct tm tm = {};
+ time_t before;
+ time_t after;
+ time_t actual;
+ struct timeval tv;
+ int ret;
+ char *env_tz = NULL;
+ char *orig_tz = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ /*
+ * Explicitly set the time zone to UTC to make the test easier
+ */
+ env_tz = getenv("TZ");
+ if (env_tz != NULL) {
+ orig_tz = talloc_strdup(ctx, env_tz);
+ }
+ setenv("TZ", "UTC", 1);
+
+ ret = gettimeofday(&tv, NULL);
+ assert_int_equal(0, ret);
+ before = tv.tv_sec;
+
+ t = audit_get_timestamp(ctx);
+
+ ret = gettimeofday(&tv, NULL);
+ assert_int_equal(0, ret);
+ after = tv.tv_sec;
+
+ c = strptime(t, "%a, %d %b %Y %H:%M:%S", &tm);
+
+ /*
+ * Restore the time zone if we changed it
+ */
+ if (orig_tz != NULL) {
+ setenv("TZ", orig_tz, 1);
+ TALLOC_FREE(orig_tz);
+ }
+
+ assert_non_null(c);
+ tm.tm_isdst = -1;
+ if (c != NULL && *c == '.') {
+ char *e;
+ strtod(c, &e);
+ c = e;
+ }
+ if (c != NULL && *c == ' ') {
+ assert_string_equal(" UTC", c);
+ c += 4;
+ }
+ assert_int_equal(0, strlen(c));
+
+ actual = mktime(&tm);
+
+ /*
+ * The timestamp should be before <= actual <= after
+ */
+ assert_true(difftime(actual, before) >= 0);
+ assert_true(difftime(after, actual) >= 0);
+
+ TALLOC_FREE(ctx);
+}
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_json_add_int),
+ cmocka_unit_test(test_json_add_bool),
+ cmocka_unit_test(test_json_add_string),
+ cmocka_unit_test(test_json_add_object),
+ cmocka_unit_test(test_json_add_to_array),
+ cmocka_unit_test(test_json_add_timestamp),
+ cmocka_unit_test(test_json_add_stringn),
+ cmocka_unit_test(test_json_add_version),
+ cmocka_unit_test(test_json_add_address),
+ cmocka_unit_test(test_json_add_sid),
+ cmocka_unit_test(test_json_add_guid),
+ cmocka_unit_test(test_json_to_string),
+ cmocka_unit_test(test_json_get_array),
+ cmocka_unit_test(test_json_get_object),
+ cmocka_unit_test(test_audit_get_timestamp),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/audit_logging/wscript_build b/lib/audit_logging/wscript_build
new file mode 100644
index 0000000..90c48ee
--- /dev/null
+++ b/lib/audit_logging/wscript_build
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM(
+ 'audit_logging',
+ deps='''MESSAGING_SEND
+ jansson
+ samba-debug
+ LIBTSOCKET
+ authn_policy''',
+ source='audit_logging.c'
+)
+
+if bld.AD_DC_BUILD_IS_ENABLED():
+ bld.SAMBA_BINARY(
+ 'audit_logging_test',
+ source='tests/audit_logging_test.c',
+ deps='''
+ audit_logging
+ jansson
+ cmocka
+ talloc
+ samba-util
+ LIBTSOCKET
+ authn_policy
+ ''',
+ for_selftest=True
+ )
+
+if bld.AD_DC_BUILD_IS_ENABLED():
+ bld.SAMBA_BINARY(
+ 'audit_logging_error_test',
+ source='tests/audit_logging_error_test.c',
+ deps='''
+ audit_logging
+ jansson
+ cmocka
+ talloc
+ samba-util
+ LIBTSOCKET
+ authn_policy
+ ''',
+ for_selftest=True,
+ ldflags='''
+ -Wl,--wrap,json_object_set_new
+ -Wl,--wrap,json_object_update
+ -Wl,--wrap,json_array_append_new
+ -Wl,--wrap,json_array_extend
+ -Wl,--wrap,json_object
+ -Wl,--wrap,json_string
+ -Wl,--wrap,json_stringn
+ -Wl,--wrap,json_integer
+ -Wl,--wrap,json_array
+ -Wl,--wrap,json_dumps
+ -Wl,--wrap,gettimeofday
+ -Wl,--wrap,localtime
+ -Wl,--wrap,talloc_named_const
+ -Wl,--wrap,talloc_strdup
+ -Wl,--wrap,tsocket_address_string
+ '''
+ )
diff --git a/lib/cmdline/closefrom_except.c b/lib/cmdline/closefrom_except.c
new file mode 100644
index 0000000..fe4e0cc
--- /dev/null
+++ b/lib/cmdline/closefrom_except.c
@@ -0,0 +1,93 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "closefrom_except.h"
+#include <popt.h>
+
+int closefrom_except(int lower, int *fds, size_t num_fds)
+{
+ size_t i;
+ int max_keep = -1;
+ int fd, ret;
+
+ for (i=0; i<num_fds; i++) {
+ max_keep = MAX(max_keep, fds[i]);
+ }
+ if (max_keep == -1) {
+ return 0;
+ }
+
+ for (fd = lower; fd < max_keep; fd++) {
+ bool keep = false;
+
+ /*
+ * O(num_fds*max_keep), but we expect the number of
+ * fds to keep to be very small, typically 0,1,2 and
+ * very few more.
+ */
+ for (i=0; i<num_fds; i++) {
+ if (fd == fds[i]) {
+ keep = true;
+ break;
+ }
+ }
+ if (keep) {
+ continue;
+ }
+ ret = close(fd);
+ if ((ret == -1) && (errno != EBADF)) {
+ return errno;
+ }
+ }
+
+ closefrom(MAX(lower, max_keep+1));
+ return 0;
+}
+
+int closefrom_except_fd_params(
+ int lower,
+ size_t num_fd_params,
+ const char *fd_params[],
+ int argc,
+ const char *argv[])
+{
+ int fds[num_fd_params];
+ size_t i;
+ struct poptOption long_options[num_fd_params + 1];
+ poptContext pc;
+ int ret;
+
+ for (i=0; i<num_fd_params; i++) {
+ fds[i] = -1;
+ long_options[i] = (struct poptOption) {
+ .longName = fd_params[i],
+ .argInfo = POPT_ARG_INT,
+ .arg = &fds[i],
+ };
+ }
+ long_options[num_fd_params] = (struct poptOption) { .longName=NULL, };
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+
+ while ((ret = poptGetNextOpt(pc)) != -1) {
+ /* do nothing */
+ }
+
+ poptFreeContext(pc);
+
+ ret = closefrom_except(lower, fds, ARRAY_SIZE(fds));
+ return ret;
+}
diff --git a/lib/cmdline/closefrom_except.h b/lib/cmdline/closefrom_except.h
new file mode 100644
index 0000000..d696ebf
--- /dev/null
+++ b/lib/cmdline/closefrom_except.h
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_CLOSEFROM_EXCEPT_H__
+#define __LIB_CLOSEFROM_EXCEPT_H__
+
+#include "replace.h"
+
+int closefrom_except(int lower, int *fds, size_t num_fds);
+int closefrom_except_fd_params(
+ int lower,
+ size_t num_fd_params,
+ const char *fd_params[],
+ int argc,
+ const char *argv[]);
+
+#endif
diff --git a/lib/cmdline/cmdline.c b/lib/cmdline/cmdline.c
new file mode 100644
index 0000000..db96214
--- /dev/null
+++ b/lib/cmdline/cmdline.c
@@ -0,0 +1,1415 @@
+/*
+ * Copyright (c) 2020 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/param/param.h"
+#include "dynconfig/dynconfig.h"
+#include "auth/gensec/gensec.h"
+#include "libcli/smb/smb_util.h"
+#include "cmdline_private.h"
+#include "lib/util/util_process.h"
+
+#include <samba/version.h>
+
+static TALLOC_CTX *cmdline_mem_ctx;
+static struct loadparm_context *cmdline_lp_ctx;
+static struct cli_credentials *cmdline_creds;
+static samba_cmdline_load_config cmdline_load_config_fn;
+static struct samba_cmdline_daemon_cfg cmdline_daemon_cfg;
+
+static NTSTATUS (*cli_credentials_set_machine_account_fn)(
+ struct cli_credentials *cred,
+ struct loadparm_context *lp_ctx) =
+ cli_credentials_set_machine_account;
+
+/* PRIVATE */
+bool samba_cmdline_set_talloc_ctx(TALLOC_CTX *mem_ctx)
+{
+ if (cmdline_mem_ctx != NULL) {
+ return false;
+ }
+
+ cmdline_mem_ctx = mem_ctx;
+ return true;
+}
+
+TALLOC_CTX *samba_cmdline_get_talloc_ctx(void)
+{
+ return cmdline_mem_ctx;
+}
+
+static void _samba_cmdline_talloc_log(const char *message)
+{
+ D_ERR("%s", message);
+}
+
+bool samba_cmdline_init_common(TALLOC_CTX *mem_ctx)
+{
+ bool ok;
+
+ ok = samba_cmdline_set_talloc_ctx(mem_ctx);
+ if (!ok) {
+ return false;
+ }
+
+ cmdline_daemon_cfg = (struct samba_cmdline_daemon_cfg) {
+ .fork = true,
+ };
+
+ fault_setup();
+
+ /*
+ * Log to stderr by default.
+ * This can be changed to stdout using the option: --debug-stdout
+ */
+ setup_logging(getprogname(), DEBUG_DEFAULT_STDERR);
+
+ talloc_set_log_fn(_samba_cmdline_talloc_log);
+ talloc_set_abort_fn(smb_panic);
+
+ return true;
+}
+
+bool samba_cmdline_set_load_config_fn(samba_cmdline_load_config fn)
+{
+ cmdline_load_config_fn = fn;
+ return true;
+}
+
+/* PUBLIC */
+bool samba_cmdline_set_lp_ctx(struct loadparm_context *lp_ctx)
+{
+ if (lp_ctx == NULL) {
+ return false;
+ }
+ cmdline_lp_ctx = lp_ctx;
+
+ return true;
+}
+
+struct loadparm_context *samba_cmdline_get_lp_ctx(void)
+{
+ return cmdline_lp_ctx;
+}
+
+bool samba_cmdline_set_creds(struct cli_credentials *creds)
+{
+ if (creds == NULL) {
+ return false;
+ }
+
+ TALLOC_FREE(cmdline_creds);
+ cmdline_creds = creds;
+
+ return true;
+}
+
+struct cli_credentials *samba_cmdline_get_creds(void)
+{
+ return cmdline_creds;
+}
+
+struct samba_cmdline_daemon_cfg *samba_cmdline_get_daemon_cfg(void)
+{
+ return &cmdline_daemon_cfg;
+}
+
+void samba_cmdline_set_machine_account_fn(
+ NTSTATUS (*fn) (struct cli_credentials *cred,
+ struct loadparm_context *lp_ctx))
+{
+ cli_credentials_set_machine_account_fn = fn;
+}
+
+bool samba_cmdline_burn(int argc, char *argv[])
+{
+ bool burnt = false;
+ bool found = false;
+ bool is_user = false;
+ char *p = NULL;
+ int i;
+ size_t ulen = 0;
+
+ for (i = 0; i < argc; i++) {
+ p = argv[i];
+ if (p == NULL) {
+ return false;
+ }
+
+ /*
+ * Take care that this list must be in longest-match
+ * first order
+ */
+ if (strncmp(p, "-U", 2) == 0) {
+ ulen = 2;
+ found = true;
+ is_user = true;
+ } else if (strncmp(p, "--user", 6) == 0) {
+ ulen = 6;
+ found = true;
+ is_user = true;
+ } else if (strncmp(p, "--password2", 11) == 0) {
+ ulen = 11;
+ found = true;
+ } else if (strncmp(p, "--password", 10) == 0) {
+ ulen = 10;
+ found = true;
+ } else if (strncmp(p, "--newpassword", 13) == 0) {
+ ulen = 13;
+ found = true;
+ }
+
+ if (found) {
+ char *q = NULL;
+
+ if (strlen(p) == ulen) {
+ continue;
+ }
+
+ if (is_user) {
+ q = strchr_m(p, '%');
+ if (q != NULL) {
+ p = q;
+ }
+ } else {
+ p += ulen;
+ }
+
+ memset_s(p, strlen(p), '\0', strlen(p));
+ found = false;
+ is_user = false;
+ burnt = true;
+ }
+ }
+ return burnt;
+}
+
+static bool is_popt_table_end(const struct poptOption *o)
+{
+ if (o->longName == NULL &&
+ o->shortName == 0 &&
+ o->argInfo == 0 &&
+ o->arg == NULL &&
+ o->val == 0 &&
+ o->descrip == NULL &&
+ o->argDescrip == NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+static void find_duplicates(const struct poptOption *needle,
+ const struct poptOption *haystack,
+ size_t *count)
+{
+ for(;
+ !is_popt_table_end(haystack);
+ haystack++) {
+ switch (haystack->argInfo) {
+ case POPT_ARG_INCLUDE_TABLE:
+ if (haystack->arg != NULL) {
+ find_duplicates(needle, haystack->arg, count);
+ }
+
+ break;
+ default:
+ if (needle->shortName != 0 &&
+ needle->shortName == haystack->shortName) {
+ (*count)++;
+ break;
+ }
+
+ if (needle->longName != NULL &&
+ haystack->longName != NULL &&
+ strequal(needle->longName, haystack->longName)) {
+ (*count)++;
+ break;
+ }
+ break;
+ }
+
+ if (*count > 1) {
+ return;
+ }
+ }
+}
+
+static bool cmdline_sanity_checker(const struct poptOption *current_opts,
+ const struct poptOption *full_opts)
+{
+ const struct poptOption *o = current_opts;
+
+ for(;
+ !is_popt_table_end(o);
+ o++) {
+ bool ok;
+
+ switch (o->argInfo) {
+ case POPT_ARG_INCLUDE_TABLE:
+ if (o->arg != NULL) {
+ ok = cmdline_sanity_checker(o->arg, full_opts);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ break;
+ default:
+ if (o->longName != NULL || o->shortName != 0) {
+ size_t count = 0;
+
+ find_duplicates(o, full_opts, &count);
+ if (count > 1) {
+ DBG_ERR("Duplicate option '--%s|-%c' "
+ "detected!\n",
+ o->longName,
+ o->shortName != 0 ?
+ o->shortName :
+ '-');
+ return false;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool samba_cmdline_sanity_check(const struct poptOption *opts)
+{
+ return cmdline_sanity_checker(opts, opts);
+}
+
+poptContext samba_popt_get_context(const char * name,
+ int argc, const char ** argv,
+ const struct poptOption * options,
+ unsigned int flags)
+{
+#ifdef DEVELOPER
+ bool ok;
+
+ ok = samba_cmdline_sanity_check(options);
+ if (!ok) {
+ return NULL;
+ }
+#endif
+ process_save_binary_name(name);
+ return poptGetContext(name, argc, argv, options, flags);
+}
+
+/**********************************************************
+ * COMMON SAMBA POPT
+ **********************************************************/
+
+static bool log_to_file;
+
+static bool set_logfile(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *log_basename,
+ const char *process_name,
+ bool from_cmdline)
+{
+ bool ok = false;
+ char *new_logfile = talloc_asprintf(mem_ctx,
+ "%s/log.%s",
+ log_basename,
+ process_name);
+ if (new_logfile == NULL) {
+ return false;
+ }
+
+ if (from_cmdline) {
+ ok = lpcfg_set_cmdline(lp_ctx,
+ "log file",
+ new_logfile);
+ } else {
+ ok = lpcfg_do_global_parameter(lp_ctx,
+ "log file",
+ new_logfile);
+ }
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set log to %s\n",
+ new_logfile);
+ TALLOC_FREE(new_logfile);
+ return false;
+ }
+ debug_set_logfile(new_logfile);
+ TALLOC_FREE(new_logfile);
+
+ return true;
+}
+
+static void popt_samba_callback(poptContext popt_ctx,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg, const void *data)
+{
+ TALLOC_CTX *mem_ctx = samba_cmdline_get_talloc_ctx();
+ struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
+ const char *pname = NULL;
+ bool ok;
+
+ /* Find out basename of current program */
+ pname = getprogname();
+
+ if (reason == POPT_CALLBACK_REASON_PRE) {
+ if (lp_ctx == NULL) {
+ fprintf(stderr,
+ "Command line parsing not initialized!\n");
+ exit(1);
+ }
+ ok = set_logfile(mem_ctx,
+ lp_ctx,
+ get_dyn_LOGFILEBASE(),
+ pname,
+ false);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set log file for %s\n",
+ pname);
+ exit(1);
+ }
+ return;
+ }
+
+ if (reason == POPT_CALLBACK_REASON_POST) {
+ ok = cmdline_load_config_fn();
+ if (!ok) {
+ fprintf(stderr,
+ "%s - Failed to load config file!\n",
+ getprogname());
+ exit(1);
+ }
+
+ if (log_to_file) {
+ const struct loadparm_substitution *lp_sub =
+ lpcfg_noop_substitution();
+ char *logfile = NULL;
+
+ logfile = lpcfg_logfile(lp_ctx, lp_sub, mem_ctx);
+ if (logfile == NULL) {
+ fprintf(stderr,
+ "Failed to setup logging to file!");
+ exit(1);
+ }
+ debug_set_logfile(logfile);
+ setup_logging(logfile, DEBUG_FILE);
+ TALLOC_FREE(logfile);
+ }
+
+ return;
+ }
+
+ switch(opt->val) {
+ case OPT_LEAK_REPORT:
+ talloc_enable_leak_report();
+ break;
+ case OPT_LEAK_REPORT_FULL:
+ talloc_enable_leak_report_full();
+ break;
+ case OPT_OPTION:
+ if (arg != NULL) {
+ ok = lpcfg_set_option(lp_ctx, arg);
+ if (!ok) {
+ fprintf(stderr, "Error setting option '%s'\n", arg);
+ exit(1);
+ }
+ }
+ break;
+ case 'd':
+ if (arg != NULL) {
+ ok = lpcfg_set_cmdline(lp_ctx, "log level", arg);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set debug level to: %s\n",
+ arg);
+ exit(1);
+ }
+ }
+ break;
+ case OPT_DEBUG_STDOUT:
+ setup_logging(pname, DEBUG_STDOUT);
+ break;
+ case OPT_CONFIGFILE:
+ if (arg != NULL) {
+ set_dyn_CONFIGFILE(arg);
+ }
+ break;
+ case 'l':
+ if (arg != NULL) {
+ ok = set_logfile(mem_ctx, lp_ctx, arg, pname, true);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set log file for %s\n",
+ arg);
+ exit(1);
+ }
+ log_to_file = true;
+
+ set_dyn_LOGFILEBASE(arg);
+ }
+ break;
+ }
+}
+
+static struct poptOption popt_common_debug[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
+ .arg = (void *)popt_samba_callback,
+ },
+ {
+ .longName = "debuglevel",
+ .shortName = 'd',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'd',
+ .descrip = "Set debug level",
+ .argDescrip = "DEBUGLEVEL",
+ },
+ {
+ .longName = "debug-stdout",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_DEBUG_STDOUT,
+ .descrip = "Send debug output to standard output",
+ },
+ POPT_TABLEEND
+};
+
+static struct poptOption popt_common_option[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
+ .arg = (void *)popt_samba_callback,
+ },
+ {
+ .longName = "option",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_OPTION,
+ .descrip = "Set smb.conf option from command line",
+ .argDescrip = "name=value",
+ },
+ POPT_TABLEEND
+};
+
+static struct poptOption popt_common_config[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
+ .arg = (void *)popt_samba_callback,
+ },
+ {
+ .longName = "configfile",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_CONFIGFILE,
+ .descrip = "Use alternative configuration file",
+ .argDescrip = "CONFIGFILE",
+ },
+ POPT_TABLEEND
+};
+
+static struct poptOption popt_common_samba[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
+ .arg = (void *)popt_samba_callback,
+ },
+ {
+ .longName = "debuglevel",
+ .shortName = 'd',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'd',
+ .descrip = "Set debug level",
+ .argDescrip = "DEBUGLEVEL",
+ },
+ {
+ .longName = "debug-stdout",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_DEBUG_STDOUT,
+ .descrip = "Send debug output to standard output",
+ },
+ {
+ .longName = "configfile",
+ .shortName = 's',
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_CONFIGFILE,
+ .descrip = "Use alternative configuration file",
+ .argDescrip = "CONFIGFILE",
+ },
+ {
+ .longName = "option",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_OPTION,
+ .descrip = "Set smb.conf option from command line",
+ .argDescrip = "name=value",
+ },
+ {
+ .longName = "log-basename",
+ .shortName = 'l',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'l',
+ .descrip = "Basename for log/debug files",
+ .argDescrip = "LOGFILEBASE",
+ },
+ {
+ .longName = "leak-report",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_LEAK_REPORT,
+ .descrip = "enable talloc leak reporting on exit",
+ },
+ {
+ .longName = "leak-report-full",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_LEAK_REPORT_FULL,
+ .descrip = "enable full talloc leak reporting on exit",
+ },
+ POPT_TABLEEND
+};
+
+static struct poptOption popt_common_samba_ldb[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
+ .arg = (void *)popt_samba_callback,
+ },
+ {
+ .longName = "debuglevel",
+ .shortName = 'd',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'd',
+ .descrip = "Set debug level",
+ .argDescrip = "DEBUGLEVEL",
+ },
+ {
+ .longName = "debug-stdout",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_DEBUG_STDOUT,
+ .descrip = "Send debug output to standard output",
+ },
+ {
+ .longName = "configfile",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_CONFIGFILE,
+ .descrip = "Use alternative configuration file",
+ .argDescrip = "CONFIGFILE",
+ },
+ {
+ .longName = "option",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_OPTION,
+ .descrip = "Set smb.conf option from command line",
+ .argDescrip = "name=value",
+ },
+ {
+ .longName = "log-basename",
+ .shortName = 'l',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'l',
+ .descrip = "Basename for log/debug files",
+ .argDescrip = "LOGFILEBASE",
+ },
+ {
+ .longName = "leak-report",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_LEAK_REPORT,
+ .descrip = "enable talloc leak reporting on exit",
+ },
+ {
+ .longName = "leak-report-full",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_LEAK_REPORT_FULL,
+ .descrip = "enable full talloc leak reporting on exit",
+ },
+ POPT_TABLEEND
+};
+
+/**********************************************************
+ * CONNECTION POPT
+ **********************************************************/
+
+static void popt_connection_callback(poptContext popt_ctx,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg,
+ const void *data)
+{
+ struct loadparm_context *lp_ctx = cmdline_lp_ctx;
+
+ if (reason == POPT_CALLBACK_REASON_PRE) {
+ if (lp_ctx == NULL) {
+ fprintf(stderr,
+ "Command line parsing not initialized!\n");
+ exit(1);
+ }
+ return;
+ }
+
+ switch(opt->val) {
+ case 'O':
+ if (arg != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "socket options", arg);
+ }
+ break;
+ case 'R':
+ if (arg != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "name resolve order", arg);
+ }
+ break;
+ case 'm':
+ if (arg != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "client max protocol", arg);
+ }
+ break;
+ case OPT_NETBIOS_SCOPE:
+ if (arg != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "netbios scope", arg);
+ }
+ break;
+ case 'n':
+ if (arg != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "netbios name", arg);
+ }
+ break;
+ case 'W':
+ if (arg != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "workgroup", arg);
+ }
+ break;
+ case 'r':
+ if (arg != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "realm", arg);
+ }
+ break;
+ }
+}
+
+static struct poptOption popt_common_connection[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE,
+ .arg = (void *)popt_connection_callback,
+ },
+ {
+ .longName = "name-resolve",
+ .shortName = 'R',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'R',
+ .descrip = "Use these name resolution services only",
+ .argDescrip = "NAME-RESOLVE-ORDER",
+ },
+ {
+ .longName = "socket-options",
+ .shortName = 'O',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'O',
+ .descrip = "socket options to use",
+ .argDescrip = "SOCKETOPTIONS",
+ },
+ {
+ .longName = "max-protocol",
+ .shortName = 'm',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'm',
+ .descrip = "Set max protocol level",
+ .argDescrip = "MAXPROTOCOL",
+ },
+ {
+ .longName = "netbiosname",
+ .shortName = 'n',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'n',
+ .descrip = "Primary netbios name",
+ .argDescrip = "NETBIOSNAME",
+ },
+ {
+ .longName = "netbios-scope",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_NETBIOS_SCOPE,
+ .descrip = "Use this Netbios scope",
+ .argDescrip = "SCOPE",
+ },
+ {
+ .longName = "workgroup",
+ .shortName = 'W',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'W',
+ .descrip = "Set the workgroup name",
+ .argDescrip = "WORKGROUP",
+ },
+ {
+ .longName = "realm",
+ .argInfo = POPT_ARG_STRING,
+ .val = 'r',
+ .descrip = "Set the realm name",
+ .argDescrip = "REALM",
+ },
+ POPT_TABLEEND
+};
+
+/**********************************************************
+ * CREDENTIALS POPT
+ **********************************************************/
+
+static bool skip_password_callback;
+static bool machine_account_pending;
+
+static void popt_common_credentials_callback(poptContext popt_ctx,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg,
+ const void *data)
+{
+ struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+ bool ok;
+
+ if (reason == POPT_CALLBACK_REASON_PRE) {
+ if (creds == NULL) {
+ fprintf(stderr,
+ "Command line parsing not initialized!\n");
+ exit(1);
+ }
+ return;
+ }
+
+ if (reason == POPT_CALLBACK_REASON_POST) {
+ const char *username = NULL;
+ enum credentials_obtained username_obtained =
+ CRED_UNINITIALISED;
+ enum credentials_obtained password_obtained =
+ CRED_UNINITIALISED;
+
+ /*
+ * This calls cli_credentials_set_conf() to get the defaults
+ * form smb.conf and set the winbind separator.
+ *
+ * Just warn that we can't read the smb.conf. There might not be
+ * one available or we want to ignore it.
+ */
+ ok = cli_credentials_guess(creds, lp_ctx);
+ if (!ok) {
+ fprintf(stderr,
+ "Unable to read defaults from smb.conf\n");
+ }
+
+ (void)cli_credentials_get_password_and_obtained(creds,
+ &password_obtained);
+ if (!skip_password_callback &&
+ password_obtained < CRED_CALLBACK) {
+ ok = cli_credentials_set_cmdline_callbacks(creds);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set cmdline password "
+ "callback\n");
+ exit(1);
+ }
+ }
+
+ if (machine_account_pending) {
+ NTSTATUS status;
+
+ status = cli_credentials_set_machine_account_fn(
+ creds, lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ fprintf(stderr,
+ "Failed to set machine account: %s\n",
+ nt_errstr(status));
+ exit(1);
+ }
+ }
+
+ /*
+ * When we set the username during the handling of the options
+ * passed to the binary we haven't loaded the config yet. This
+ * means that we didn't take the 'winbind separator' into
+ * account.
+ *
+ * The username might contain the domain name and thus it
+ * hasn't been correctly parsed yet. If we have a username we
+ * need to set it again to run the string parser for the
+ * username correctly.
+ */
+ username =
+ cli_credentials_get_username_and_obtained(
+ creds, &username_obtained);
+ if (username_obtained == CRED_SPECIFIED &&
+ username != NULL && username[0] != '\0') {
+ cli_credentials_parse_string(creds,
+ username,
+ CRED_SPECIFIED);
+ }
+
+ return;
+ }
+
+ switch(opt->val) {
+ case 'U':
+ if (arg != NULL) {
+ cli_credentials_parse_string(creds,
+ arg,
+ CRED_SPECIFIED);
+ }
+ break;
+ case OPT_PASSWORD:
+ if (arg != NULL) {
+ ok = cli_credentials_set_password(creds,
+ arg,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set password!\n");
+ exit(1);
+ }
+
+ skip_password_callback = true;
+ }
+ break;
+ case OPT_NT_HASH:
+ cli_credentials_set_password_will_be_nt_hash(creds, true);
+ break;
+ case 'A':
+ if (arg != NULL) {
+ ok = cli_credentials_parse_file(creds,
+ arg,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set parse authentication file!\n");
+ exit(1);
+ }
+ skip_password_callback = true;
+ }
+ break;
+ case 'N':
+ ok = cli_credentials_set_password(creds,
+ NULL,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set password!\n");
+ exit(1);
+ }
+ skip_password_callback = true;
+ break;
+ case 'P':
+ /*
+ * Later, after this is all over, get the machine account
+ * details from the secrets.(l|t)db.
+ */
+ machine_account_pending = true;
+ break;
+ case OPT_SIMPLE_BIND_DN:
+ if (arg != NULL) {
+ ok = cli_credentials_set_bind_dn(creds, arg);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set bind DN!\n");
+ exit(1);
+ }
+ }
+ break;
+ case OPT_USE_KERBEROS: {
+ int32_t use_kerberos = INT_MIN;
+ if (arg == NULL) {
+ fprintf(stderr,
+ "Failed to parse "
+ "--use-kerberos=desired|required|off: "
+ "Missing argument\n");
+ exit(1);
+ }
+
+ use_kerberos = lpcfg_parse_enum_vals("client use kerberos",
+ arg);
+ if (use_kerberos == INT_MIN) {
+ fprintf(stderr,
+ "Failed to parse "
+ "--use-kerberos=desired|required|off: "
+ "Invalid argument\n");
+ exit(1);
+ }
+
+ ok = cli_credentials_set_kerberos_state(creds,
+ use_kerberos,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set Kerberos state to %s!\n", arg);
+ exit(1);
+ }
+ break;
+ }
+ case OPT_USE_KERBEROS_CCACHE: {
+ const char *error_string = NULL;
+ int rc;
+
+ if (arg == NULL) {
+ fprintf(stderr,
+ "Failed to parse --use-krb5-ccache=CCACHE: "
+ "Missing argument\n");
+ exit(1);
+ }
+
+ ok = cli_credentials_set_kerberos_state(creds,
+ CRED_USE_KERBEROS_REQUIRED,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set Kerberos state to %s!\n", arg);
+ exit(1);
+ }
+
+ rc = cli_credentials_set_ccache(creds,
+ lp_ctx,
+ arg,
+ CRED_SPECIFIED,
+ &error_string);
+ if (rc != 0) {
+ fprintf(stderr,
+ "Error reading krb5 credentials cache: '%s'"
+ " - %s\n",
+ arg,
+ error_string);
+ exit(1);
+ }
+
+ skip_password_callback = true;
+ break;
+ }
+ case OPT_USE_WINBIND_CCACHE:
+ {
+ uint32_t gensec_features;
+
+ gensec_features = cli_credentials_get_gensec_features(creds);
+ gensec_features |= GENSEC_FEATURE_NTLM_CCACHE;
+
+ ok = cli_credentials_set_gensec_features(creds,
+ gensec_features,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set gensec feature!\n");
+ exit(1);
+ }
+
+ skip_password_callback = true;
+ break;
+ }
+ case OPT_CLIENT_PROTECTION: {
+ uint32_t gensec_features;
+ enum smb_signing_setting signing_state =
+ SMB_SIGNING_OFF;
+ enum smb_encryption_setting encryption_state =
+ SMB_ENCRYPTION_OFF;
+
+ if (arg == NULL) {
+ fprintf(stderr,
+ "Failed to parse "
+ "--client-protection=sign|encrypt|off: "
+ "Missing argument\n");
+ exit(1);
+ }
+
+ gensec_features =
+ cli_credentials_get_gensec_features(
+ creds);
+
+ if (strequal(arg, "off")) {
+ gensec_features &=
+ ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL);
+
+ signing_state = SMB_SIGNING_OFF;
+ encryption_state = SMB_ENCRYPTION_OFF;
+ } else if (strequal(arg, "sign")) {
+ gensec_features |= GENSEC_FEATURE_SIGN;
+
+ signing_state = SMB_SIGNING_REQUIRED;
+ encryption_state = SMB_ENCRYPTION_OFF;
+ } else if (strequal(arg, "encrypt")) {
+ gensec_features |= GENSEC_FEATURE_SEAL;
+
+ signing_state = SMB_SIGNING_REQUIRED;
+ encryption_state = SMB_ENCRYPTION_REQUIRED;
+ } else {
+ fprintf(stderr,
+ "Failed to parse --client-protection\n");
+ exit(1);
+ }
+
+ ok = cli_credentials_set_gensec_features(creds,
+ gensec_features,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set gensec feature!\n");
+ exit(1);
+ }
+
+ ok = cli_credentials_set_smb_signing(creds,
+ signing_state,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set smb signing!\n");
+ exit(1);
+ }
+
+ ok = cli_credentials_set_smb_encryption(creds,
+ encryption_state,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set smb encryption!\n");
+ exit(1);
+ }
+ break;
+ }
+ } /* switch */
+}
+
+static struct poptOption popt_common_credentials[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
+ .arg = (void *)popt_common_credentials_callback,
+ },
+ {
+ .longName = "user",
+ .shortName = 'U',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'U',
+ .descrip = "Set the network username",
+ .argDescrip = "[DOMAIN/]USERNAME[%PASSWORD]",
+ },
+ {
+ .longName = "no-pass",
+ .shortName = 'N',
+ .argInfo = POPT_ARG_NONE,
+ .val = 'N',
+ .descrip = "Don't ask for a password",
+ },
+ {
+ .longName = "password",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_PASSWORD,
+ .descrip = "Password",
+ },
+ {
+ .longName = "pw-nt-hash",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_NT_HASH,
+ .descrip = "The supplied password is the NT hash",
+ },
+ {
+ .longName = "authentication-file",
+ .shortName = 'A',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'A',
+ .descrip = "Get the credentials from a file",
+ .argDescrip = "FILE",
+ },
+ {
+ .longName = "machine-pass",
+ .shortName = 'P',
+ .argInfo = POPT_ARG_NONE,
+ .val = 'P',
+ .descrip = "Use stored machine account password",
+ },
+ {
+ .longName = "simple-bind-dn",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_SIMPLE_BIND_DN,
+ .descrip = "DN to use for a simple bind",
+ .argDescrip = "DN",
+ },
+ {
+ .longName = "use-kerberos",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_USE_KERBEROS,
+ .descrip = "Use Kerberos authentication",
+ .argDescrip = "desired|required|off",
+ },
+ {
+ .longName = "use-krb5-ccache",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_USE_KERBEROS_CCACHE,
+ .descrip = "Credentials cache location for Kerberos",
+ .argDescrip = "CCACHE",
+ },
+ {
+ .longName = "use-winbind-ccache",
+ .argInfo = POPT_ARG_NONE,
+ .val = OPT_USE_WINBIND_CCACHE,
+ .descrip = "Use the winbind ccache for authentication",
+ },
+ {
+ .longName = "client-protection",
+ .argInfo = POPT_ARG_STRING,
+ .val = OPT_CLIENT_PROTECTION,
+ .descrip = "Configure used protection for client connections",
+ .argDescrip = "sign|encrypt|off",
+ },
+ POPT_TABLEEND
+};
+
+/**********************************************************
+ * VERSION POPT
+ **********************************************************/
+
+static void popt_version_callback(poptContext ctx,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg,
+ const void *data)
+{
+ switch(opt->val) {
+ case 'V':
+ printf("Version %s\n", SAMBA_VERSION_STRING);
+ exit(0);
+ }
+}
+
+static struct poptOption popt_common_version[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK,
+ .arg = (void *)popt_version_callback,
+ },
+ {
+ .longName = "version",
+ .shortName = 'V',
+ .argInfo = POPT_ARG_NONE,
+ .val = 'V',
+ .descrip = "Print version",
+ },
+ POPT_TABLEEND
+};
+
+/**********************************************************
+ * DAEMON POPT
+ **********************************************************/
+
+static void popt_daemon_callback(poptContext ctx,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg,
+ const void *data)
+{
+ switch(opt->val) {
+ case OPT_DAEMON:
+ cmdline_daemon_cfg.daemon = true;
+ break;
+ case OPT_INTERACTIVE:
+ cmdline_daemon_cfg.interactive = true;
+ cmdline_daemon_cfg.fork = false;
+ break;
+ case OPT_FORK:
+ cmdline_daemon_cfg.fork = false;
+ break;
+ case OPT_NO_PROCESS_GROUP:
+ cmdline_daemon_cfg.no_process_group = true;
+ break;
+ }
+}
+
+static struct poptOption popt_common_daemon[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK,
+ .arg = (void *)popt_daemon_callback
+ },
+ {
+ .longName = "daemon",
+ .shortName = 'D',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_DAEMON,
+ .descrip = "Become a daemon (default)" ,
+ },
+ {
+ .longName = "interactive",
+ .shortName = 'i',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_INTERACTIVE,
+ .descrip = "Run interactive (not a daemon) and log to stdout",
+ },
+ {
+ .longName = "foreground",
+ .shortName = 'F',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_FORK,
+ .descrip = "Run daemon in foreground (for daemontools, etc.)",
+ },
+ {
+ .longName = "no-process-group",
+ .shortName = '\0',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_NO_PROCESS_GROUP,
+ .descrip = "Don't create a new process group" ,
+ },
+ POPT_TABLEEND
+};
+
+/**********************************************************
+ * LEGACY S3 POPT
+ **********************************************************/
+
+static void popt_legacy_s3_callback(poptContext ctx,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg,
+ const void *data)
+{
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+ bool ok;
+
+ switch(opt->val) {
+ case 'k':
+ fprintf(stderr,
+ "WARNING: The option -k|--kerberos is deprecated!\n");
+
+ ok = cli_credentials_set_kerberos_state(creds,
+ CRED_USE_KERBEROS_REQUIRED,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set Kerberos state to %s!\n", arg);
+ exit(1);
+ }
+
+ skip_password_callback = true;
+ break;
+ }
+}
+
+/* We allow '-k yes' too. */
+static struct poptOption popt_legacy_s3[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK,
+ .arg = (void *)popt_legacy_s3_callback,
+ },
+ {
+ .longName = "kerberos",
+ .shortName = 'k',
+ .argInfo = POPT_ARG_NONE,
+ .val = 'k',
+ .descrip = "DEPRECATED: Migrate to --use-kerberos",
+ },
+ POPT_TABLEEND
+};
+
+/**********************************************************
+ * LEGACY S4 POPT
+ **********************************************************/
+
+static void popt_legacy_s4_callback(poptContext ctx,
+ enum poptCallbackReason reason,
+ const struct poptOption *opt,
+ const char *arg,
+ const void *data)
+{
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+ bool ok;
+
+ switch(opt->val) {
+ case 'k': {
+ enum credentials_use_kerberos use_kerberos =
+ CRED_USE_KERBEROS_REQUIRED;
+
+ fprintf(stderr,
+ "WARNING: The option -k|--kerberos is deprecated!\n");
+
+ if (arg != NULL) {
+ if (strcasecmp_m(arg, "yes") == 0) {
+ use_kerberos = CRED_USE_KERBEROS_REQUIRED;
+ } else if (strcasecmp_m(arg, "no") == 0) {
+ use_kerberos = CRED_USE_KERBEROS_DISABLED;
+ } else {
+ fprintf(stderr,
+ "Error parsing -k %s. Should be "
+ "-k [yes|no]\n",
+ arg);
+ exit(1);
+ }
+ }
+
+ ok = cli_credentials_set_kerberos_state(creds,
+ use_kerberos,
+ CRED_SPECIFIED);
+ if (!ok) {
+ fprintf(stderr,
+ "Failed to set Kerberos state to %s!\n", arg);
+ exit(1);
+ }
+
+ break;
+ }
+ }
+}
+
+static struct poptOption popt_legacy_s4[] = {
+ {
+ .argInfo = POPT_ARG_CALLBACK,
+ .arg = (void *)popt_legacy_s4_callback,
+ },
+ {
+ .longName = "kerberos",
+ .shortName = 'k',
+ .argInfo = POPT_ARG_STRING,
+ .val = 'k',
+ .descrip = "DEPRECATED: Migrate to --use-kerberos",
+ },
+ POPT_TABLEEND
+};
+
+struct poptOption *samba_cmdline_get_popt(enum smb_cmdline_popt_options opt)
+{
+ switch (opt) {
+ case SAMBA_CMDLINE_POPT_OPT_DEBUG_ONLY:
+ return popt_common_debug;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_OPTION_ONLY:
+ return popt_common_option;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_CONFIG_ONLY:
+ return popt_common_config;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_SAMBA:
+ return popt_common_samba;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_CONNECTION:
+ return popt_common_connection;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_CREDENTIALS:
+ return popt_common_credentials;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_VERSION:
+ return popt_common_version;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_DAEMON:
+ return popt_common_daemon;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_SAMBA_LDB:
+ return popt_common_samba_ldb;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_LEGACY_S3:
+ return popt_legacy_s3;
+ break;
+ case SAMBA_CMDLINE_POPT_OPT_LEGACY_S4:
+ return popt_legacy_s4;
+ break;
+ }
+
+ /* Never reached */
+ return NULL;
+}
diff --git a/lib/cmdline/cmdline.h b/lib/cmdline/cmdline.h
new file mode 100644
index 0000000..ce5dd23
--- /dev/null
+++ b/lib/cmdline/cmdline.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2020 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CMDLINE_H
+#define _CMDLINE_H
+
+#include "auth/credentials/credentials.h"
+#include <popt.h>
+
+#ifndef POPT_TABLEEND
+#define POPT_TABLEEND { \
+ .longName = NULL, \
+ .shortName = 0, \
+ .argInfo = 0, \
+ .arg = NULL, \
+ .val = 0, \
+ .descrip = NULL, \
+ .argDescrip = NULL }
+#endif
+
+enum samba_cmdline_config_type {
+ SAMBA_CMDLINE_CONFIG_NONE = 0,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ SAMBA_CMDLINE_CONFIG_SERVER,
+};
+
+enum smb_cmdline_popt_options {
+ SAMBA_CMDLINE_POPT_OPT_DEBUG_ONLY = 1,
+ SAMBA_CMDLINE_POPT_OPT_OPTION_ONLY,
+ SAMBA_CMDLINE_POPT_OPT_CONFIG_ONLY,
+ SAMBA_CMDLINE_POPT_OPT_SAMBA,
+ SAMBA_CMDLINE_POPT_OPT_CONNECTION,
+ SAMBA_CMDLINE_POPT_OPT_CREDENTIALS,
+ SAMBA_CMDLINE_POPT_OPT_VERSION,
+ SAMBA_CMDLINE_POPT_OPT_DAEMON,
+ SAMBA_CMDLINE_POPT_OPT_SAMBA_LDB,
+ SAMBA_CMDLINE_POPT_OPT_LEGACY_S3,
+ SAMBA_CMDLINE_POPT_OPT_LEGACY_S4,
+};
+
+struct samba_cmdline_daemon_cfg {
+ bool daemon;
+ bool interactive;
+ bool fork;
+ bool no_process_group;
+};
+
+/**
+ * @brief Initialize the commandline interface for parsing options.
+ *
+ * This initializes the interface for parsing options given on the command
+ * line. It sets up the loadparm and client credentials contexts.
+ * The function will also setup fault handler, set logging to STDERR by
+ * default, setup talloc logging and the panic handler.
+ *
+ * The function also setups a callback for loading the smb.conf file, the
+ * config file will be parsed after the commandline options have been parsed
+ * by popt. This is done by one of the following options parser:
+ *
+ * POPT_COMMON_DEBUG_ONLY
+ * POPT_COMMON_OPTION_ONLY
+ * POPT_COMMON_CONFIG_ONLY
+ * POPT_COMMON_SAMBA
+ *
+ * @param[in] mem_ctx The talloc memory context to use for allocating memory.
+ * This should be a long living context till the client
+ * exits.
+ *
+ * @param[in] require_smbconf Whether the smb.conf file is required to be
+ * present or not?
+ *
+ * @return true on success, false if an error occurred.
+ */
+bool samba_cmdline_init(TALLOC_CTX *mem_ctx,
+ enum samba_cmdline_config_type config_type,
+ bool require_smbconf);
+
+/**
+ * @brief Get a pointer of loadparm context used for the command line interface.
+ *
+ * @return The loadparm context.
+ */
+struct loadparm_context *samba_cmdline_get_lp_ctx(void);
+
+/**
+ * @brief Get the client credentials of the command line interface.
+ *
+ * @return A pointer to the client credentials.
+ */
+struct cli_credentials *samba_cmdline_get_creds(void);
+
+/**
+ * @brief Get a pointer to the poptOption for the given option section.
+ *
+ * You should not directly use this function, but the macros.
+ *
+ * @param[in] opt The options to retrieve.
+ *
+ * @return A pointer to the poptOption array.
+ *
+ * @see POPT_COMMON_DEBUG_ONLY
+ * @see POPT_COMMON_OPTION_ONLY
+ * @see POPT_COMMON_CONFIG_ONLY
+ * @see POPT_COMMON_SAMBA
+ * @see POPT_COMMON_CONNECTION
+ * @see POPT_COMMON_CREDENTIALS
+ * @see POPT_COMMON_VERSION
+ */
+struct poptOption *samba_cmdline_get_popt(enum smb_cmdline_popt_options opt);
+
+/**
+ * @brief Get a pointer to the poptOptions for daemons
+ *
+ * @return A pointer to the daemon options
+ *
+ * @see POPT_COMMON_DAEMON
+ */
+struct samba_cmdline_daemon_cfg *samba_cmdline_get_daemon_cfg(void);
+
+void samba_cmdline_set_machine_account_fn(
+ NTSTATUS (*fn) (struct cli_credentials *cred,
+ struct loadparm_context *lp_ctx));
+
+/**
+ * @brief Burn secrets on the command line.
+ *
+ * This function removes secrets from the command line so we don't leak e.g.
+ * passwords on 'ps aux' output.
+ *
+ * It should be called after processing the options and you should pass down
+ * argv from main().
+ *
+ * @param[in] argc The number of arguments.
+ *
+ * @param[in] argv[] The argument array we should remove secrets from.
+ *
+ * @return true if a password was removed, false otherwise.
+ */
+bool samba_cmdline_burn(int argc, char *argv[]);
+
+/**
+ * @brief Sanity check the command line options.
+ *
+ * This checks for duplicates in short and long options.
+ *
+ * @param[in] opts The options array to check.
+ *
+ * @return true if valid, false otherwise.
+ */
+bool samba_cmdline_sanity_check(const struct poptOption *opts);
+
+/**
+ * @brief This is a wrapper for the poptGetContext() which initializes the popt
+ * context.
+ *
+ * If Samba is build in developer mode, this will call
+ * samba_cmdline_sanity_check() before poptGetContext().
+ *
+ * @param[in] name The context name (usually argv[0] program name or
+ * getprogname())
+ *
+ * @param[in] argc Number of arguments
+ *
+ * @param[in] argv The argument array
+ *
+ * @param[in] options The address of popt option table
+ *
+ * @param[in] flags The OR'd POPT_CONTEXT_* bits
+ *
+ * @return The initialized popt context or NULL on error.
+ */
+poptContext samba_popt_get_context(const char * name,
+ int argc, const char ** argv,
+ const struct poptOption * options,
+ unsigned int flags);
+
+/**
+ * @brief A popt structure for common debug options only.
+ */
+#define POPT_COMMON_DEBUG_ONLY { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_DEBUG_ONLY), \
+ .val = 0, \
+ .descrip = "Common debug options:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for --option only.
+ */
+#define POPT_COMMON_OPTION_ONLY { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_OPTION_ONLY), \
+ .val = 0, \
+ .descrip = "Options:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for --configfile only.
+ */
+#define POPT_COMMON_CONFIG_ONLY { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_CONFIG_ONLY), \
+ .val = 0, \
+ .descrip = "Config file:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for common samba options.
+ */
+#define POPT_COMMON_SAMBA { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_SAMBA), \
+ .val = 0, \
+ .descrip = "Common Samba options:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for connection options.
+ */
+#define POPT_COMMON_CONNECTION { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_CONNECTION), \
+ .val = 0, \
+ .descrip = "Connection options:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for credential options.
+ */
+#define POPT_COMMON_CREDENTIALS { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_CREDENTIALS), \
+ .val = 0, \
+ .descrip = "Credential options:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for version options.
+ */
+#define POPT_COMMON_VERSION { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_VERSION), \
+ .val = 0, \
+ .descrip = "Version options:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for daemon options.
+ */
+#define POPT_COMMON_DAEMON { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_DAEMON), \
+ .val = 0, \
+ .descrip = "Daemon options:", \
+ .argDescrip = NULL },
+
+/**
+ * @brief A popt structure for common samba options.
+ */
+#define POPT_COMMON_SAMBA_LDB { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_SAMBA_LDB), \
+ .val = 0, \
+ .descrip = "Common Samba options:", \
+ .argDescrip = NULL },
+
+/* TODO Get rid of me! */
+#define POPT_LEGACY_S3 { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_LEGACY_S3), \
+ .val = 0, \
+ .descrip = "Deprecated legacy options:", \
+ .argDescrip = NULL },
+
+/* TODO Get rid of me! */
+#define POPT_LEGACY_S4 { \
+ .longName = NULL, \
+ .shortName = '\0', \
+ .argInfo = POPT_ARG_INCLUDE_TABLE, \
+ .arg = samba_cmdline_get_popt(SAMBA_CMDLINE_POPT_OPT_LEGACY_S4), \
+ .val = 0, \
+ .descrip = "Deprecated legacy options:", \
+ .argDescrip = NULL },
+
+#endif /* _CMDLINE_H */
diff --git a/lib/cmdline/cmdline_private.h b/lib/cmdline/cmdline_private.h
new file mode 100644
index 0000000..e2d4e95
--- /dev/null
+++ b/lib/cmdline/cmdline_private.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2020 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CMDLINE_PRIVATE_H
+#define _CMDLINE_PRIVATE_H
+
+#include "lib/cmdline/cmdline.h"
+
+enum {
+ OPT_OPTION = 0x1000000,
+ OPT_NETBIOS_SCOPE,
+ OPT_LEAK_REPORT,
+ OPT_LEAK_REPORT_FULL,
+ OPT_DEBUG_STDOUT,
+ OPT_CONFIGFILE,
+ OPT_SIMPLE_BIND_DN,
+ OPT_PASSWORD,
+ OPT_NT_HASH,
+ OPT_USE_KERBEROS,
+ OPT_USE_KERBEROS_CCACHE,
+ OPT_USE_WINBIND_CCACHE,
+ OPT_CLIENT_PROTECTION,
+ OPT_DAEMON,
+ OPT_INTERACTIVE,
+ OPT_FORK,
+ OPT_NO_PROCESS_GROUP,
+};
+
+typedef bool (*samba_cmdline_load_config)(void);
+
+/**
+ * @internal
+ *
+ * @brief Initialize the commandline interface for parsing options.
+ *
+ * This the common function to initialize the command line interface. This
+ * initializes:
+ *
+ * - Crash setup
+ * - logging system sending logs to stdout
+ * - talloc leak reporting
+ *
+ * @param[in] mem_ctx The talloc memory context to use for allocating memory.
+ * This should be a long living context till the client
+ * exits.
+ *
+ * @return true on success, false if an error occurred.
+ */
+bool samba_cmdline_init_common(TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Set the callback for loading the smb.conf file.
+ *
+ * This is needed as sourc3 and source4 have different code for loading the
+ * smb.conf file.
+ *
+ * @param[in] fn The callback to load the smb.conf file.
+ *
+ * @return true on success, false if an error occurred.
+ */
+bool samba_cmdline_set_load_config_fn(samba_cmdline_load_config fn);
+
+/**
+ * @internal
+ *
+ * @brief Set the talloc context for the command line interface.
+ *
+ * This is stored as a static pointer.
+ *
+ * @param[in] mem_ctx The talloc memory context.
+ *
+ * @return true on success, false if an error occurred.
+ */
+bool samba_cmdline_set_talloc_ctx(TALLOC_CTX *mem_ctx);
+
+/**
+ * @internal
+ *
+ * @brief Get the talloc context for the cmdline interface.
+ *
+ * @return A talloc context.
+ */
+TALLOC_CTX *samba_cmdline_get_talloc_ctx(void);
+
+/**
+ * @internal
+ *
+ * @brief Set the loadparm context for the command line interface.
+ *
+ * @param[in] lp_ctx The loadparm context to use.
+ *
+ * @return true on success, false if an error occurred.
+ */
+bool samba_cmdline_set_lp_ctx(struct loadparm_context *lp_ctx);
+
+/**
+ * @internal
+ *
+ * @brief Set the client credentials for the commandline interface.
+ *
+ * @param[in] creds The client credentials to use.
+ *
+ * @return true on success, false if an error occurred.
+ */
+bool samba_cmdline_set_creds(struct cli_credentials *creds);
+
+#endif /* _CMDLINE_PRIVATE_H */
diff --git a/lib/cmdline/cmdline_s3.c b/lib/cmdline/cmdline_s3.c
new file mode 100644
index 0000000..6e2c154
--- /dev/null
+++ b/lib/cmdline/cmdline_s3.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2020 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lib/replace/replace.h"
+#include <talloc.h>
+#include "lib/param/param.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "source3/param/loadparm.h"
+#include "dynconfig/dynconfig.h"
+#include "source3/lib/interface.h"
+#include "auth/credentials/credentials.h"
+#include "dynconfig/dynconfig.h"
+#include "cmdline_private.h"
+#include "source3/include/secrets.h"
+
+static bool _require_smbconf;
+static enum samba_cmdline_config_type _config_type;
+
+static bool _samba_cmdline_load_config_s3(void)
+{
+ struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
+ const char *config_file = NULL;
+ bool ok = false;
+
+ /* Load smb conf */
+ config_file = lpcfg_configfile(lp_ctx);
+ if (config_file == NULL) {
+ if (is_default_dyn_CONFIGFILE()) {
+ const char *env = getenv("SMB_CONF_PATH");
+ if (env != NULL && strlen(env) > 0) {
+ set_dyn_CONFIGFILE(env);
+ }
+ }
+ }
+
+ config_file = get_dyn_CONFIGFILE();
+
+ switch (_config_type) {
+ case SAMBA_CMDLINE_CONFIG_NONE:
+ return true;
+ case SAMBA_CMDLINE_CONFIG_CLIENT:
+ ok = lp_load_client(config_file);
+ break;
+ case SAMBA_CMDLINE_CONFIG_SERVER:
+ {
+ const struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg =
+ samba_cmdline_get_daemon_cfg();
+
+ if (!cmdline_daemon_cfg->interactive) {
+ setup_logging(getprogname(), DEBUG_FILE);
+ }
+
+ ok = lp_load_global(config_file);
+ break;
+ }
+ }
+
+ if (!ok) {
+ fprintf(stderr,
+ "Can't load %s - run testparm to debug it\n",
+ config_file);
+
+ if (_require_smbconf) {
+ return false;
+ }
+ }
+
+ load_interfaces();
+
+ return true;
+}
+
+static NTSTATUS _samba_cmd_set_machine_account_s3(
+ struct cli_credentials *cred,
+ struct loadparm_context *lp_ctx)
+{
+ struct db_context *db_ctx = secrets_db_ctx();
+ NTSTATUS status;
+
+ if (db_ctx == NULL) {
+ DBG_WARNING("failed to open secrets.tdb to obtain our "
+ "trust credentials for %s\n",
+ lpcfg_workgroup(lp_ctx));;
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = cli_credentials_set_machine_account_db_ctx(
+ cred, lp_ctx, db_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("cli_credentials_set_machine_account_db_ctx "
+ "failed: %s\n",
+ nt_errstr(status));
+ }
+
+ return status;
+}
+
+bool samba_cmdline_init(TALLOC_CTX *mem_ctx,
+ enum samba_cmdline_config_type config_type,
+ bool require_smbconf)
+{
+ struct loadparm_context *lp_ctx = NULL;
+ struct cli_credentials *creds = NULL;
+ bool ok;
+
+ ok = samba_cmdline_init_common(mem_ctx);
+ if (!ok) {
+ return false;
+ }
+
+ lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
+ if (lp_ctx == NULL) {
+ return false;
+ }
+ ok = samba_cmdline_set_lp_ctx(lp_ctx);
+ if (!ok) {
+ return false;
+ }
+
+ _require_smbconf = require_smbconf;
+ _config_type = config_type;
+
+ creds = cli_credentials_init(mem_ctx);
+ if (creds == NULL) {
+ return false;
+ }
+ ok = samba_cmdline_set_creds(creds);
+ if (!ok) {
+ return false;
+ }
+
+ samba_cmdline_set_load_config_fn(_samba_cmdline_load_config_s3);
+ samba_cmdline_set_machine_account_fn(
+ _samba_cmd_set_machine_account_s3);
+
+ return true;
+}
diff --git a/lib/cmdline/cmdline_s4.c b/lib/cmdline/cmdline_s4.c
new file mode 100644
index 0000000..f8be4ed
--- /dev/null
+++ b/lib/cmdline/cmdline_s4.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2020 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lib/replace/replace.h"
+#include <talloc.h>
+#include "lib/param/param.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "auth/credentials/credentials.h"
+#include "dynconfig/dynconfig.h"
+#include "cmdline_private.h"
+
+static bool _require_smbconf;
+static enum samba_cmdline_config_type _config_type;
+
+static bool _samba_cmdline_load_config_s4(void)
+{
+ struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
+ const char *config_file = NULL;
+ const struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg = \
+ samba_cmdline_get_daemon_cfg();
+ bool ok;
+
+ /* Load smb conf */
+ config_file = lpcfg_configfile(lp_ctx);
+ if (config_file == NULL) {
+ if (is_default_dyn_CONFIGFILE()) {
+ const char *env = getenv("SMB_CONF_PATH");
+ if (env != NULL && strlen(env) > 0) {
+ set_dyn_CONFIGFILE(env);
+ }
+ }
+ }
+
+ switch (_config_type) {
+ case SAMBA_CMDLINE_CONFIG_SERVER:
+ if (!cmdline_daemon_cfg->interactive) {
+ setup_logging(getprogname(), DEBUG_FILE);
+ }
+ break;
+ default:
+ break;
+ }
+
+ config_file = get_dyn_CONFIGFILE();
+ ok = lpcfg_load(lp_ctx, config_file);
+ if (!ok) {
+ fprintf(stderr,
+ "Can't load %s - run testparm to debug it\n",
+ config_file);
+
+ if (_require_smbconf) {
+ return false;
+ }
+ }
+
+ switch (_config_type) {
+ case SAMBA_CMDLINE_CONFIG_SERVER:
+ /*
+ * We need to setup_logging *again* to ensure multi-file
+ * logging is set up as specified in smb.conf.
+ */
+ if (!cmdline_daemon_cfg->interactive) {
+ setup_logging(getprogname(), DEBUG_FILE);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool samba_cmdline_init(TALLOC_CTX *mem_ctx,
+ enum samba_cmdline_config_type config_type,
+ bool require_smbconf)
+{
+ struct loadparm_context *lp_ctx = NULL;
+ struct cli_credentials *creds = NULL;
+ bool ok;
+
+ ok = samba_cmdline_init_common(mem_ctx);
+ if (!ok) {
+ return false;
+ }
+
+ lp_ctx = loadparm_init_global(false);
+ if (lp_ctx == NULL) {
+ return false;
+ }
+
+ ok = samba_cmdline_set_lp_ctx(lp_ctx);
+ if (!ok) {
+ return false;
+ }
+ _require_smbconf = require_smbconf;
+ _config_type = config_type;
+
+ creds = cli_credentials_init(mem_ctx);
+ if (creds == NULL) {
+ return false;
+ }
+ ok = samba_cmdline_set_creds(creds);
+ if (!ok) {
+ return false;
+ }
+
+ samba_cmdline_set_load_config_fn(_samba_cmdline_load_config_s4);
+
+ return true;
+}
diff --git a/lib/cmdline/tests/test_cmdline.c b/lib/cmdline/tests/test_cmdline.c
new file mode 100644
index 0000000..16dd09c
--- /dev/null
+++ b/lib/cmdline/tests/test_cmdline.c
@@ -0,0 +1,97 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018-2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "lib/cmdline/cmdline.h"
+
+static void torture_cmdline_sanity_check_good(void **state)
+{
+ bool ok;
+ struct poptOption long_options_good[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
+ POPT_LEGACY_S3
+ POPT_TABLEEND
+ };
+
+ ok = samba_cmdline_sanity_check(long_options_good);
+ assert_true(ok);
+}
+
+static void torture_cmdline_sanity_check_bad(void **state)
+{
+ bool ok;
+
+ struct poptOption long_options_bad[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_SAMBA
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+
+ ok = samba_cmdline_sanity_check(long_options_bad);
+ assert_false(ok);
+}
+
+static void torture_cmdline_burn(void **state)
+{
+ char arg1[] = "-U Administrator%secret";
+ char arg2[] = "--user=Administrator%secret";
+ char arg3[] = "--user=Administrator%super%secret";
+ char arg4[] = "--password=super%secret";
+
+ char *argv[] = { arg1, arg2, arg3, arg4, NULL };
+ int argc = 4;
+
+ samba_cmdline_burn(argc, argv);
+
+ assert_string_equal(arg1, "-U Administrator");
+ assert_string_equal(arg2, "--user=Administrator");
+ assert_string_equal(arg3, "--user=Administrator");
+ assert_string_equal(arg4, "--password");
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_cmdline_sanity_check_good),
+ cmocka_unit_test(torture_cmdline_sanity_check_bad),
+ cmocka_unit_test(torture_cmdline_burn),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/lib/cmdline/wscript b/lib/cmdline/wscript
new file mode 100644
index 0000000..01ead85
--- /dev/null
+++ b/lib/cmdline/wscript
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+import os
+import sys
+from waflib import Logs
+
+def build(bld):
+ bld.SAMBA_LIBRARY('cmdline',
+ source='''
+ cmdline.c
+ closefrom_except.c
+ ''',
+ deps='''
+ talloc
+ cli_smb_common
+ samba-hostconfig
+ samba-credentials
+ CREDENTIALS_CMDLINE
+ popt
+ ''',
+ private_library=True)
+
+ bld.SAMBA_SUBSYSTEM('CMDLINE_S3',
+ source='cmdline_s3.c',
+ deps='cmdline secrets3')
+
+ bld.SAMBA_SUBSYSTEM('CMDLINE_S4',
+ source='cmdline_s4.c',
+ deps='cmdline')
+
+ bld.SAMBA_BINARY('test_cmdline',
+ source='tests/test_cmdline.c',
+ deps='cmocka CMDLINE_S3 LOADPARM_CTX',
+ local_include=False,
+ for_selftest=True)
diff --git a/lib/compression/lzxpress.c b/lib/compression/lzxpress.c
new file mode 100644
index 0000000..5e5e5ba
--- /dev/null
+++ b/lib/compression/lzxpress.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) Matthieu Suiche 2008
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR CONTRIBUTORS 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.
+ *
+ */
+
+#include "replace.h"
+#include "lzxpress.h"
+#include "../lib/util/byteorder.h"
+
+
+#define __CHECK_BYTES(__size, __index, __needed) do { \
+ if (unlikely(__index >= __size)) { \
+ return -1; \
+ } else { \
+ uint32_t __avail = __size - __index; \
+ if (unlikely(__needed > __avail)) { \
+ return -1; \
+ } \
+ } \
+} while(0)
+
+
+/*
+ * LZX_PLAIN_COMP_HASH_BITS determines how big the hash table for finding
+ * matches will be.
+ *
+ * The window in which we look for matches is 8192 bytes. That means with
+ * random data a value of 13 is getting close to no collisions, while a 12
+ * will miss about half the possible matches. With compressible data there
+ * will generally be fewer and less diverse entries, so collisions are rarer.
+ *
+ * In the testsuite, bith 12 and 13 give better compression than Windows, but
+ * 12 is faster. 11 does not save time and costs accuracy. Thus we prefer 12.
+ */
+#define LZX_PLAIN_COMP_HASH_BITS 12
+/*
+ * LZX_PLAIN_COMP_HASH_SEARCH_ATTEMPTS is how far ahead to search in the
+ * circular hash table for a match, before we give up. A bigger number will
+ * generally lead to better but slower compression, but a stupidly big number
+ * will just be worse.
+ */
+#define LZX_PLAIN_COMP_HASH_SEARCH_ATTEMPTS 5
+#define HASH_MASK ((1 << LZX_PLAIN_COMP_HASH_BITS) - 1)
+
+static inline uint16_t three_byte_hash(const uint8_t *bytes)
+{
+ uint16_t a = bytes[0];
+ uint16_t b = bytes[1] ^ 0x2e;
+ uint16_t c = bytes[2] ^ 0x55;
+ uint16_t ca = c - a;
+ uint16_t d = ((a + b) << 8) ^ (ca << 5) ^ (c + b) ^ (0xcab + a);
+ return d & HASH_MASK;
+}
+
+
+static inline void store_match(uint32_t *hash_table,
+ uint16_t h,
+ uint32_t offset)
+{
+ int i;
+ uint32_t o = hash_table[h];
+ uint16_t h2;
+ uint16_t worst_h;
+ int worst_score;
+
+ if (o >= offset) {
+ /* there is nothing there yet */
+ hash_table[h] = offset;
+ return;
+ }
+ for (i = 1; i < LZX_PLAIN_COMP_HASH_SEARCH_ATTEMPTS; i++) {
+ h2 = (h + i) & HASH_MASK;
+ if (hash_table[h2] >= offset) {
+ hash_table[h2] = offset;
+ return;
+ }
+ }
+ /*
+ * There are no slots, but we really want to store this, so we'll kick
+ * out the one with the longest distance.
+ */
+ worst_h = h;
+ worst_score = offset - o;
+ for (i = 1; i < LZX_PLAIN_COMP_HASH_SEARCH_ATTEMPTS; i++) {
+ int score;
+ h2 = (h + i) & HASH_MASK;
+ o = hash_table[h2];
+ score = offset - o;
+ if (score > worst_score) {
+ worst_score = score;
+ worst_h = h2;
+ }
+ }
+ hash_table[worst_h] = offset;
+}
+
+
+struct match {
+ const uint8_t *there;
+ uint32_t length;
+};
+
+
+static inline struct match lookup_match(uint32_t *hash_table,
+ uint16_t h,
+ const uint8_t *data,
+ uint32_t offset,
+ size_t max_len)
+{
+ int i;
+ uint32_t o;
+ uint16_t h2;
+ size_t len;
+ const uint8_t *there = NULL;
+ const uint8_t *here = data + offset;
+ struct match best = {0};
+
+ for (i = 0; i < LZX_PLAIN_COMP_HASH_SEARCH_ATTEMPTS; i++) {
+ h2 = (h + i) & HASH_MASK;
+ o = hash_table[h2];
+ if (o >= offset) {
+ /*
+ * Either this is 0xffffffff, or something is really
+ * wrong.
+ *
+ * In setting this, we would never have stepped over
+ * an 0xffffffff, so we won't now.
+ */
+ break;
+ }
+ if (offset - o > 8192) {
+ /* Too far away to use */
+ continue;
+ }
+ there = data + o;
+ /*
+ * When we already have a long match, we can try to avoid
+ * measuring out another long, but shorter match.
+ */
+ if (best.length > 1000 &&
+ there[best.length - 1] != best.there[best.length - 1]) {
+ continue;
+ }
+
+ for (len = 0;
+ len < max_len && here[len] == there[len];
+ len++) {
+ /* counting */
+ }
+ if (len > 2) {
+ if (len > best.length) {
+ best.length = len;
+ best.there = there;
+ }
+ }
+ }
+ return best;
+}
+
+struct write_context {
+ uint8_t *compressed;
+ uint32_t compressed_pos;
+ uint32_t max_compressed_size;
+ uint32_t indic;
+ uint32_t indic_bit;
+ uint32_t indic_pos;
+ uint32_t nibble_index;
+};
+
+
+#define CHECK_INPUT_BYTES(__needed) \
+ __CHECK_BYTES(uncompressed_size, uncompressed_pos, __needed)
+#define CHECK_OUTPUT_BYTES(__needed) \
+ __CHECK_BYTES(wc->max_compressed_size, wc->compressed_pos, __needed)
+
+
+static inline ssize_t push_indicator_bit(struct write_context *wc, uint32_t bit)
+{
+ wc->indic = (wc->indic << 1) | bit;
+ wc->indic_bit += 1;
+
+ if (wc->indic_bit == 32) {
+ PUSH_LE_U32(wc->compressed, wc->indic_pos, wc->indic);
+ wc->indic_bit = 0;
+ CHECK_OUTPUT_BYTES(sizeof(uint32_t));
+ wc->indic_pos = wc->compressed_pos;
+ wc->compressed_pos += sizeof(uint32_t);
+ }
+ return wc->indic_pos;
+}
+
+
+static ssize_t encode_match(struct write_context *wc,
+ struct match match,
+ const uint8_t *here)
+{
+ uint32_t match_len = match.length - 3;
+ uint32_t best_offset = here - match.there - 1;
+ uint16_t metadata;
+
+ if (best_offset > 8191) {
+ return -1;
+ }
+
+ CHECK_OUTPUT_BYTES(sizeof(uint16_t));
+ metadata = (uint16_t)((best_offset << 3) | MIN(match_len, 7));
+ PUSH_LE_U16(wc->compressed, wc->compressed_pos, metadata);
+ wc->compressed_pos += sizeof(uint16_t);
+
+ if (match_len >= 7) {
+ match_len -= 7;
+
+ if (wc->nibble_index == 0) {
+ wc->nibble_index = wc->compressed_pos;
+
+ CHECK_OUTPUT_BYTES(sizeof(uint8_t));
+ wc->compressed[wc->nibble_index] = MIN(match_len, 15);
+ wc->compressed_pos += sizeof(uint8_t);
+ } else {
+ wc->compressed[wc->nibble_index] |= MIN(match_len, 15) << 4;
+ wc->nibble_index = 0;
+ }
+
+ if (match_len >= 15) {
+ match_len -= 15;
+
+ CHECK_OUTPUT_BYTES(sizeof(uint8_t));
+ wc->compressed[wc->compressed_pos] = MIN(match_len, 255);
+ wc->compressed_pos += sizeof(uint8_t);
+
+ if (match_len >= 255) {
+ /* Additional match_len */
+
+ match_len += 7 + 15;
+
+ if (match_len < (1 << 16)) {
+ CHECK_OUTPUT_BYTES(sizeof(uint16_t));
+ PUSH_LE_U16(wc->compressed, wc->compressed_pos,
+ match_len);
+ wc->compressed_pos += sizeof(uint16_t);
+ } else {
+ CHECK_OUTPUT_BYTES(sizeof(uint16_t) +
+ sizeof(uint32_t));
+ PUSH_LE_U16(wc->compressed,
+ wc->compressed_pos, 0);
+ wc->compressed_pos += sizeof(uint16_t);
+
+ PUSH_LE_U32(wc->compressed,
+ wc->compressed_pos,
+ match_len);
+ wc->compressed_pos += sizeof(uint32_t);
+ }
+ }
+ }
+ }
+ return push_indicator_bit(wc, 1);
+}
+
+#undef CHECK_OUTPUT_BYTES
+#define CHECK_OUTPUT_BYTES(__needed) \
+ __CHECK_BYTES(wc.max_compressed_size, wc.compressed_pos, __needed)
+
+
+ssize_t lzxpress_compress(const uint8_t *uncompressed,
+ uint32_t uncompressed_size,
+ uint8_t *compressed,
+ uint32_t max_compressed_size)
+{
+ /*
+ * This is the algorithm in [MS-XCA] 2.3 "Plain LZ77 Compression".
+ *
+ * It avoids Huffman encoding by including literal bytes inline when a
+ * match is not found. Every so often it includes a uint32 bit map
+ * flagging which positions contain matches and which contain
+ * literals. The encoding of matches is of variable size, depending on
+ * the match length; they are always at least 16 bits long, and can
+ * implicitly use unused half-bytes from earlier in the stream.
+ */
+ ssize_t ret;
+ uint32_t uncompressed_pos;
+ struct write_context wc = {
+ .indic = 0,
+ .indic_pos = 0,
+ .indic_bit = 0,
+ .nibble_index = 0,
+ .compressed = compressed,
+ .compressed_pos = 0,
+ .max_compressed_size = max_compressed_size
+ };
+ uint32_t hash_table[1 << LZX_PLAIN_COMP_HASH_BITS];
+ memset(hash_table, 0xff, sizeof(hash_table));
+
+ if (!uncompressed_size) {
+ return 0;
+ }
+
+ uncompressed_pos = 0;
+ CHECK_OUTPUT_BYTES(sizeof(uint32_t));
+ PUSH_LE_U32(wc.compressed, wc.compressed_pos, 0);
+ wc.compressed_pos += sizeof(uint32_t);
+
+ while ((uncompressed_pos < uncompressed_size) &&
+ (wc.compressed_pos < wc.max_compressed_size)) {
+
+ /* maximum len we can encode into metadata */
+ const uint32_t max_len = MIN(0xFFFF + 3,
+ uncompressed_size - uncompressed_pos);
+ const uint8_t *here = uncompressed + uncompressed_pos;
+ uint16_t h;
+ struct match match = {0};
+
+ if (max_len >= 3) {
+ h = three_byte_hash(here);
+ match = lookup_match(hash_table,
+ h,
+ uncompressed,
+ uncompressed_pos,
+ max_len);
+
+ store_match(hash_table, h, uncompressed_pos);
+ } else {
+ match.there = NULL;
+ match.length = 0;
+ }
+
+ if (match.there == NULL) {
+ /*
+ * This is going to be a literal byte, which we flag
+ * by setting a bit in an indicator field somewhere
+ * earlier in the stream.
+ */
+ CHECK_INPUT_BYTES(sizeof(uint8_t));
+ CHECK_OUTPUT_BYTES(sizeof(uint8_t));
+ wc.compressed[wc.compressed_pos++] = *here;
+ uncompressed_pos++;
+
+ ret = push_indicator_bit(&wc, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ } else {
+ ret = encode_match(&wc, match, here);
+ if (ret < 0) {
+ return ret;
+ }
+ uncompressed_pos += match.length;
+ }
+ }
+
+ if (wc.indic_bit != 0) {
+ wc.indic <<= 32 - wc.indic_bit;
+ }
+ wc.indic |= UINT32_MAX >> wc.indic_bit;
+ PUSH_LE_U32(wc.compressed, wc.indic_pos, wc.indic);
+
+ return wc.compressed_pos;
+}
+
+ssize_t lzxpress_decompress(const uint8_t *input,
+ uint32_t input_size,
+ uint8_t *output,
+ uint32_t max_output_size)
+{
+ /*
+ * This is the algorithm in [MS-XCA] 2.4 "Plain LZ77 Decompression
+ * Algorithm Details".
+ */
+ uint32_t output_index, input_index;
+ uint32_t indicator, indicator_bit;
+ uint32_t nibble_index;
+
+ if (input_size == 0) {
+ return 0;
+ }
+
+ output_index = 0;
+ input_index = 0;
+ indicator = 0;
+ indicator_bit = 0;
+ nibble_index = 0;
+
+#undef CHECK_INPUT_BYTES
+#define CHECK_INPUT_BYTES(__needed) \
+ __CHECK_BYTES(input_size, input_index, __needed)
+#undef CHECK_OUTPUT_BYTES
+#define CHECK_OUTPUT_BYTES(__needed) \
+ __CHECK_BYTES(max_output_size, output_index, __needed)
+
+ do {
+ if (indicator_bit == 0) {
+ CHECK_INPUT_BYTES(sizeof(uint32_t));
+ indicator = PULL_LE_U32(input, input_index);
+ input_index += sizeof(uint32_t);
+ if (input_index == input_size) {
+ /*
+ * The compressor left room for indicator
+ * flags for data that doesn't exist.
+ */
+ break;
+ }
+ indicator_bit = 32;
+ }
+ indicator_bit--;
+
+ /*
+ * check whether the bit specified by indicator_bit is set or not
+ * set in indicator. For example, if indicator_bit has value 4
+ * check whether the 4th bit of the value in indicator is set
+ */
+ if (((indicator >> indicator_bit) & 1) == 0) {
+ CHECK_INPUT_BYTES(sizeof(uint8_t));
+ CHECK_OUTPUT_BYTES(sizeof(uint8_t));
+ output[output_index] = input[input_index];
+ input_index += sizeof(uint8_t);
+ output_index += sizeof(uint8_t);
+ } else {
+ uint32_t length;
+ uint32_t offset;
+
+ CHECK_INPUT_BYTES(sizeof(uint16_t));
+ length = PULL_LE_U16(input, input_index);
+ input_index += sizeof(uint16_t);
+ offset = (length >> 3) + 1;
+ length &= 7;
+
+ if (length == 7) {
+ if (nibble_index == 0) {
+ CHECK_INPUT_BYTES(sizeof(uint8_t));
+ nibble_index = input_index;
+ length = input[input_index] & 0xf;
+ input_index += sizeof(uint8_t);
+ } else {
+ length = input[nibble_index] >> 4;
+ nibble_index = 0;
+ }
+
+ if (length == 15) {
+ CHECK_INPUT_BYTES(sizeof(uint8_t));
+ length = input[input_index];
+ input_index += sizeof(uint8_t);
+ if (length == 255) {
+ CHECK_INPUT_BYTES(sizeof(uint16_t));
+ length = PULL_LE_U16(input, input_index);
+ input_index += sizeof(uint16_t);
+ if (length == 0) {
+ CHECK_INPUT_BYTES(sizeof(uint32_t));
+ length = PULL_LE_U32(input, input_index);
+ input_index += sizeof(uint32_t);
+ }
+
+ if (length < (15 + 7)) {
+ return -1;
+ }
+ length -= (15 + 7);
+ }
+ length += 15;
+ }
+ length += 7;
+ }
+ length += 3;
+
+ if (length == 0) {
+ return -1;
+ }
+
+ for (; length > 0; --length) {
+ if (offset > output_index) {
+ return -1;
+ }
+ CHECK_OUTPUT_BYTES(sizeof(uint8_t));
+ output[output_index] = output[output_index - offset];
+ output_index += sizeof(uint8_t);
+ }
+ }
+ } while ((output_index < max_output_size) && (input_index < (input_size)));
+
+ return output_index;
+}
diff --git a/lib/compression/lzxpress.h b/lib/compression/lzxpress.h
new file mode 100644
index 0000000..df0ee59
--- /dev/null
+++ b/lib/compression/lzxpress.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) Matthieu Suiche 2008
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR CONTRIBUTORS 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.
+ *
+ */
+
+#ifndef _LZXPRESS_H
+#define _LZXPRESS_H
+
+#define XPRESS_BLOCK_SIZE 0x10000
+
+ssize_t lzxpress_compress(const uint8_t *uncompressed,
+ uint32_t uncompressed_size,
+ uint8_t *compressed,
+ uint32_t max_compressed_size);
+
+ssize_t lzxpress_decompress(const uint8_t *input,
+ uint32_t input_size,
+ uint8_t *output,
+ uint32_t max_output_size);
+
+#endif /* _LZXPRESS_H */
diff --git a/lib/compression/lzxpress_huffman.c b/lib/compression/lzxpress_huffman.c
new file mode 100644
index 0000000..e14419c
--- /dev/null
+++ b/lib/compression/lzxpress_huffman.c
@@ -0,0 +1,2045 @@
+/*
+ * Samba compression library - LGPLv3
+ *
+ * Copyright © Catalyst IT 2022
+ *
+ * Written by Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+ * and Joseph Sutton <josephsutton@catalyst.net.nz>
+ *
+ * ** NOTE! The following LGPL license applies to this file.
+ * ** It does NOT imply that all of Samba is released under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <talloc.h>
+
+#include "replace.h"
+#include "lzxpress_huffman.h"
+#include "lib/util/stable_sort.h"
+#include "lib/util/debug.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/bytearray.h"
+
+/*
+ * DEBUG_NO_LZ77_MATCHES toggles the encoding of matches as matches. If it is
+ * false the potential match is written as a series of literals, which is a
+ * valid but usually inefficient encoding. This is useful for isolating a
+ * problem to either the LZ77 or the Huffman stage.
+ */
+#ifndef DEBUG_NO_LZ77_MATCHES
+#define DEBUG_NO_LZ77_MATCHES false
+#endif
+
+/*
+ * DEBUG_HUFFMAN_TREE forces the drawing of ascii art huffman trees during
+ * compression and decompression.
+ *
+ * These trees will also be drawn at DEBUG level 10, but that doesn't work
+ * with cmocka tests.
+ */
+#ifndef DEBUG_HUFFMAN_TREE
+#define DEBUG_HUFFMAN_TREE false
+#endif
+
+#if DEBUG_HUFFMAN_TREE
+#define DBG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DBG(...) DBG_INFO(__VA_ARGS__)
+#endif
+
+
+#define LZXPRESS_ERROR -1LL
+
+/*
+ * We won't encode a match length longer than MAX_MATCH_LENGTH.
+ *
+ * Reports are that Windows has a limit at 64M.
+ */
+#define MAX_MATCH_LENGTH (64 * 1024 * 1024)
+
+
+struct bitstream {
+ const uint8_t *bytes;
+ size_t byte_pos;
+ size_t byte_size;
+ uint32_t bits;
+ int remaining_bits;
+ uint16_t *table;
+};
+
+
+#if ! defined __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+/*
+ * bitlen_nonzero_16() returns the bit number of the most significant bit, or
+ * put another way, the integer log base 2. Log(0) is undefined; the argument
+ * has to be non-zero!
+ * 1 -> 0
+ * 2,3 -> 1
+ * 4-7 -> 2
+ * 1024 -> 10, etc
+ *
+ * Probably this is handled by a compiler intrinsic function that maps to a
+ * dedicated machine instruction.
+ */
+
+static inline int bitlen_nonzero_16(uint16_t x)
+{
+#if __has_builtin(__builtin_clz)
+
+ /* __builtin_clz returns the number of leading zeros */
+ return (sizeof(unsigned int) * CHAR_BIT) - 1
+ - __builtin_clz((unsigned int) x);
+
+#else
+
+ int count = -1;
+ while(x) {
+ x >>= 1;
+ count++;
+ }
+ return count;
+
+#endif
+}
+
+
+struct lzxhuff_compressor_context {
+ const uint8_t *input_bytes;
+ size_t input_size;
+ size_t input_pos;
+ size_t prev_block_pos;
+ uint8_t *output;
+ size_t available_size;
+ size_t output_pos;
+};
+
+static int compare_huffman_node_count(struct huffman_node *a,
+ struct huffman_node *b)
+{
+ return a->count - b->count;
+}
+
+static int compare_huffman_node_depth(struct huffman_node *a,
+ struct huffman_node *b)
+{
+ int c = a->depth - b->depth;
+ if (c != 0) {
+ return c;
+ }
+ return (int)a->symbol - (int)b->symbol;
+}
+
+
+#define HASH_MASK ((1 << LZX_HUFF_COMP_HASH_BITS) - 1)
+
+static inline uint16_t three_byte_hash(const uint8_t *bytes)
+{
+ /*
+ * MS-XCA says "three byte hash", but does not specify it.
+ *
+ * This one is just cobbled together, but has quite good distribution
+ * in the 12-14 bit forms, which is what we care about most.
+ * e.g: 13 bit: median 2048, min 2022, max 2074, stddev 6.0
+ */
+ uint16_t a = bytes[0];
+ uint16_t b = bytes[1] ^ 0x2e;
+ uint16_t c = bytes[2] ^ 0x55;
+ uint16_t ca = c - a;
+ uint16_t d = ((a + b) << 8) ^ (ca << 5) ^ (c + b) ^ (0xcab + a);
+ return d & HASH_MASK;
+}
+
+
+static inline uint16_t encode_match(size_t len, size_t offset)
+{
+ uint16_t code = 256;
+ code |= MIN(len - 3, 15);
+ code |= bitlen_nonzero_16(offset) << 4;
+ return code;
+}
+
+/*
+ * debug_huffman_tree() uses debug_huffman_tree_print() to draw the Huffman
+ * tree in ascii art.
+ *
+ * Note that the Huffman tree is probably not the same as that implied by the
+ * canonical Huffman encoding that is finally used. That tree would be the
+ * same shape, but with the left and right toggled to sort the branches by
+ * length, after which the symbols for each length sorted by value.
+ */
+
+static void debug_huffman_tree_print(struct huffman_node *node,
+ int *trail, int depth)
+{
+ if (node->left == NULL) {
+ /* time to print a row */
+ int j;
+ bool branched = false;
+ int row[17];
+ char c[100];
+ int s = node->symbol;
+ char code[17];
+ if (depth > 15) {
+ fprintf(stderr,
+ " \033[1;31m Max depth exceeded! (%d)\033[0m "
+ " symbol %#3x claimed depth %d count %d\n",
+ depth, node->symbol, node->depth, node->count);
+ return;
+ }
+ for (j = depth - 1; j >= 0; j--) {
+ if (branched) {
+ if (trail[j] == -1) {
+ row[j] = -3;
+ } else {
+ row[j] = -2;
+ }
+ } else if (trail[j] == -1) {
+ row[j] = -1;
+ branched = true;
+ } else {
+ row[j] = trail[j];
+ }
+ }
+ for (j = 0; j < depth; j++) {
+ switch (row[j]) {
+ case -3:
+ code[j] = '1';
+ fprintf(stderr, " ");
+ break;
+ case -2:
+ code[j] = '0';
+ fprintf(stderr, " │ ");
+ break;
+ case -1:
+ code[j] = '1';
+ fprintf(stderr, " ╰─");
+ break;
+ default:
+ code[j] = '0';
+ fprintf(stderr, "%5d─┬─", row[j]);
+ break;
+ }
+ }
+ code[depth] = 0;
+ if (s < 32) {
+ snprintf(c, sizeof(c),
+ "\033[1;32m%02x\033[0m \033[1;33m%c%c%c\033[0m",
+ s,
+ 0xE2, 0x90, 0x80 + s); /* utf-8 for symbol */
+ } else if (s < 127) {
+ snprintf(c, sizeof(c),
+ "\033[1;32m%2x\033[0m '\033[10;32m%c\033[0m'",
+ s, s);
+ } else if (s < 256) {
+ snprintf(c, sizeof(c), "\033[1;32m%2x\033[0m", s);
+ } else {
+ uint16_t len = (s & 15) + 3;
+ uint16_t dbits = ((s >> 4) & 15) + 1;
+ snprintf(c, sizeof(c),
+ " \033[0;33mlen:%2d%s, "
+ "dist:%d-%d \033[0m \033[1;32m%3x\033[0m%s",
+ len,
+ len == 18 ? "+" : "",
+ 1 << (dbits - 1),
+ (1 << dbits) - 1,
+ s,
+ s == 256 ? " \033[1;31mEOF\033[0m" : "");
+
+ }
+
+ fprintf(stderr, "──%5d %s \033[2;37m%s\033[0m\n",
+ node->count, c, code);
+ return;
+ }
+ trail[depth] = node->count;
+ debug_huffman_tree_print(node->left, trail, depth + 1);
+ trail[depth] = -1;
+ debug_huffman_tree_print(node->right, trail, depth + 1);
+}
+
+
+/*
+ * If DEBUG_HUFFMAN_TREE is defined true, debug_huffman_tree()
+ * will print a tree looking something like this:
+ *
+ * 7─┬─── 3 len:18+, dist:1-1 10f 0
+ * ╰─ 4─┬─ 2─┬─── 1 61 'a' 100
+ * │ ╰─── 1 62 'b' 101
+ * ╰─ 2─┬─── 1 63 'c' 110
+ * ╰─── 1 len: 3, dist:1-1 100 EOF 111
+ *
+ * This is based off a Huffman root node, and the tree may not be the same as
+ * the canonical tree.
+ */
+static void debug_huffman_tree(struct huffman_node *root)
+{
+ int trail[17];
+ debug_huffman_tree_print(root, trail, 0);
+}
+
+
+/*
+ * If DEBUG_HUFFMAN_TREE is defined true, debug_huffman_tree_from_table()
+ * will print something like this based on a decoding symbol table.
+ *
+ * Tree from decoding table 9 nodes → 5 codes
+ * 10000─┬─── 5000 len:18+, dist:1-1 10f 0
+ * ╰─ 5000─┬─ 2500─┬─── 1250 61 'a' 100
+ * │ ╰─── 1250 62 'b' 101
+ * ╰─ 2500─┬─── 1250 63 'c' 110
+ * ╰─── 1250 len: 3, dist:1-1 100 EOF 111
+ *
+ * This is the canonical form of the Huffman tree where the actual counts
+ * aren't known (we use "10000" to help indicate relative frequencies).
+ */
+static void debug_huffman_tree_from_table(uint16_t *table)
+{
+ int trail[17];
+ struct huffman_node nodes[1024] = {{0}};
+ uint16_t codes[1024];
+ size_t n = 1;
+ size_t i = 0;
+ codes[0] = 0;
+ nodes[0].count = 10000;
+
+ while (i < n) {
+ uint16_t index = codes[i];
+ struct huffman_node *node = &nodes[i];
+ if (table[index] == 0xffff) {
+ /* internal node */
+ index <<= 1;
+ /* left */
+ index++;
+ codes[n] = index;
+ node->left = nodes + n;
+ nodes[n].count = node->count >> 1;
+ n++;
+ /*right*/
+ index++;
+ codes[n] = index;
+ node->right = nodes + n;
+ nodes[n].count = node->count >> 1;
+ n++;
+ } else {
+ /* leaf node */
+ node->symbol = table[index] & 511;
+ }
+ i++;
+ }
+
+ fprintf(stderr,
+ "\033[1;34m Tree from decoding table\033[0m "
+ "%zu nodes → %zu codes\n",
+ n, (n + 1) / 2);
+ debug_huffman_tree_print(nodes, trail, 0);
+}
+
+
+static bool depth_walk(struct huffman_node *n, uint32_t depth)
+{
+ bool ok;
+ if (n->left == NULL) {
+ /* this is a leaf, record the depth */
+ n->depth = depth;
+ return true;
+ }
+ if (depth > 14) {
+ return false;
+ }
+ ok = (depth_walk(n->left, depth + 1) &&
+ depth_walk(n->right, depth + 1));
+
+ return ok;
+}
+
+
+static bool check_and_record_depths(struct huffman_node *root)
+{
+ return depth_walk(root, 0);
+}
+
+
+static bool encode_values(struct huffman_node *leaves,
+ size_t n_leaves,
+ uint16_t symbol_values[512])
+{
+ size_t i;
+ /*
+ * See, we have a leading 1 in our internal code representation, which
+ * indicates the code length.
+ */
+ uint32_t code = 1;
+ uint32_t code_len = 0;
+ memset(symbol_values, 0, sizeof(uint16_t) * 512);
+ for (i = 0; i < n_leaves; i++) {
+ code <<= leaves[i].depth - code_len;
+ code_len = leaves[i].depth;
+
+ symbol_values[leaves[i].symbol] = code;
+ code++;
+ }
+ /*
+ * The last code should be 11111... with code_len + 1 ones. The final
+ * code++ will wrap this round to 1000... with code_len + 1 zeroes.
+ */
+
+ if (code != 2 << code_len) {
+ return false;
+ }
+ return true;
+}
+
+
+static int generate_huffman_codes(struct huffman_node *leaf_nodes,
+ struct huffman_node *internal_nodes,
+ uint16_t symbol_values[512])
+{
+ size_t head_leaf = 0;
+ size_t head_branch = 0;
+ size_t tail_branch = 0;
+ struct huffman_node *huffman_root = NULL;
+ size_t i, j;
+ size_t n_leaves = 0;
+
+ /*
+ * Before we sort the nodes, we can eliminate the unused ones.
+ */
+ for (i = 0; i < 512; i++) {
+ if (leaf_nodes[i].count) {
+ leaf_nodes[n_leaves] = leaf_nodes[i];
+ n_leaves++;
+ }
+ }
+ if (n_leaves == 0) {
+ return LZXPRESS_ERROR;
+ }
+ if (n_leaves == 1) {
+ /*
+ * There is *almost* no way this should happen, and it would
+ * ruin the tree (because the shortest possible codes are 1
+ * bit long, and there are two of them).
+ *
+ * The only way to get here is in an internal block in a
+ * 3-or-more block message (i.e. > 128k), which consists
+ * entirely of a match starting in the previous block (if it
+ * was the end block, it would have the EOF symbol).
+ *
+ * What we do is add a dummy symbol which is this one XOR 256.
+ * It won't be used in the stream but will balance the tree.
+ */
+ leaf_nodes[1] = leaf_nodes[0];
+ leaf_nodes[1].symbol ^= 0x100;
+ n_leaves = 2;
+ }
+
+ /* note, in sort we're using internal_nodes as auxiliary space */
+ stable_sort(leaf_nodes,
+ internal_nodes,
+ n_leaves,
+ sizeof(struct huffman_node),
+ (samba_compare_fn_t)compare_huffman_node_count);
+
+ /*
+ * This outer loop is for re-quantizing the counts if the tree is too
+ * tall (>15), which we need to do because the final encoding can't
+ * express a tree that deep.
+ *
+ * In theory, this should be a 'while (true)' loop, but we chicken
+ * out with 10 iterations, just in case.
+ *
+ * In practice it will almost always resolve in the first round; if
+ * not then, in the second or third. Remember we'll looking at 64k or
+ * less, so the rarest we can have is 1 in 64k; each round of
+ * quantization effectively doubles its frequency to 1 in 32k, 1 in
+ * 16k, etc, until we're treating the rare symbol as actually quite
+ * common.
+ */
+ for (j = 0; j < 10; j++) {
+ bool less_than_15_bits;
+ while (true) {
+ struct huffman_node *a = NULL;
+ struct huffman_node *b = NULL;
+ size_t leaf_len = n_leaves - head_leaf;
+ size_t internal_len = tail_branch - head_branch;
+
+ if (leaf_len + internal_len == 1) {
+ /*
+ * We have the complete tree. The root will be
+ * an internal node unless there is just one
+ * symbol, which is already impossible.
+ */
+ if (unlikely(leaf_len == 1)) {
+ return LZXPRESS_ERROR;
+ } else {
+ huffman_root = \
+ &internal_nodes[head_branch];
+ }
+ break;
+ }
+ /*
+ * We know here we have at least two nodes, and we
+ * want to select the two lowest scoring ones. Those
+ * have to be either a) the head of each queue, or b)
+ * the first two nodes of either queue.
+ *
+ * The complicating factors are: a) we need to check
+ * the length of each queue, and b) in the case of
+ * ties, we prefer to pair leaves with leaves.
+ *
+ * Note a complication we don't have: the leaf node
+ * queue never grows, and the subtree queue starts
+ * empty and cannot grow beyond n - 1. It feeds on
+ * itself. We don't need to think about overflow.
+ */
+ if (leaf_len == 0) {
+ /* two from subtrees */
+ a = &internal_nodes[head_branch];
+ b = &internal_nodes[head_branch + 1];
+ head_branch += 2;
+ } else if (internal_len == 0) {
+ /* two from nodes */
+ a = &leaf_nodes[head_leaf];
+ b = &leaf_nodes[head_leaf + 1];
+ head_leaf += 2;
+ } else if (leaf_len == 1 && internal_len == 1) {
+ /* one of each */
+ a = &leaf_nodes[head_leaf];
+ b = &internal_nodes[head_branch];
+ head_branch++;
+ head_leaf++;
+ } else {
+ /*
+ * Take the lowest head, twice, checking for
+ * length after taking the first one.
+ */
+ if (leaf_nodes[head_leaf].count >
+ internal_nodes[head_branch].count) {
+ a = &internal_nodes[head_branch];
+ head_branch++;
+ if (internal_len == 1) {
+ b = &leaf_nodes[head_leaf];
+ head_leaf++;
+ goto done;
+ }
+ } else {
+ a = &leaf_nodes[head_leaf];
+ head_leaf++;
+ if (leaf_len == 1) {
+ b = &internal_nodes[head_branch];
+ head_branch++;
+ goto done;
+ }
+ }
+ /* the other node */
+ if (leaf_nodes[head_leaf].count >
+ internal_nodes[head_branch].count) {
+ b = &internal_nodes[head_branch];
+ head_branch++;
+ } else {
+ b = &leaf_nodes[head_leaf];
+ head_leaf++;
+ }
+ }
+ done:
+ /*
+ * Now we add a new node to the subtrees list that
+ * combines the score of node_a and node_b, and points
+ * to them as children.
+ */
+ internal_nodes[tail_branch].count = a->count + b->count;
+ internal_nodes[tail_branch].left = a;
+ internal_nodes[tail_branch].right = b;
+ tail_branch++;
+ if (tail_branch == n_leaves) {
+ /*
+ * We're not getting here, no way, never ever.
+ * Unless we made a terrible mistake.
+ *
+ * That is, in a binary tree with n leaves,
+ * there are ALWAYS n-1 internal nodes.
+ */
+ return LZXPRESS_ERROR;
+ }
+ }
+ if (CHECK_DEBUGLVL(10) || DEBUG_HUFFMAN_TREE) {
+ debug_huffman_tree(huffman_root);
+ }
+ /*
+ * We have a tree, and need to turn it into a lookup table,
+ * and see if it is shallow enough (<= 15).
+ */
+ less_than_15_bits = check_and_record_depths(huffman_root);
+ if (less_than_15_bits) {
+ /*
+ * Now the leaf nodes know how deep they are, and we
+ * no longer need the internal nodes.
+ *
+ * We need to sort the nodes of equal depth, so that
+ * they are sorted by depth first, and symbol value
+ * second. The internal_nodes can again be auxiliary
+ * memory.
+ */
+ stable_sort(
+ leaf_nodes,
+ internal_nodes,
+ n_leaves,
+ sizeof(struct huffman_node),
+ (samba_compare_fn_t)compare_huffman_node_depth);
+
+ encode_values(leaf_nodes, n_leaves, symbol_values);
+
+ return n_leaves;
+ }
+
+ /*
+ * requantize by halving and rounding up, so that small counts
+ * become relatively bigger. This will lead to a flatter tree.
+ */
+ for (i = 0; i < n_leaves; i++) {
+ leaf_nodes[i].count >>= 1;
+ leaf_nodes[i].count += 1;
+ }
+ head_leaf = 0;
+ head_branch = 0;
+ tail_branch = 0;
+ }
+ return LZXPRESS_ERROR;
+}
+
+/*
+ * LZX_HUFF_COMP_HASH_SEARCH_ATTEMPTS is how far ahead to search in the
+ * circular hash table for a match, before we give up. A bigger number will
+ * generally lead to better but slower compression, but a stupidly big number
+ * will just be worse.
+ *
+ * If you're fiddling with this, consider also fiddling with
+ * LZX_HUFF_COMP_HASH_BITS.
+ */
+#define LZX_HUFF_COMP_HASH_SEARCH_ATTEMPTS 5
+
+static inline void store_match(uint16_t *hash_table,
+ uint16_t h,
+ uint16_t offset)
+{
+ int i;
+ uint16_t o = hash_table[h];
+ uint16_t h2;
+ uint16_t worst_h;
+ int worst_score;
+
+ if (o == 0xffff) {
+ /* there is nothing there yet */
+ hash_table[h] = offset;
+ return;
+ }
+ for (i = 1; i < LZX_HUFF_COMP_HASH_SEARCH_ATTEMPTS; i++) {
+ h2 = (h + i) & HASH_MASK;
+ if (hash_table[h2] == 0xffff) {
+ hash_table[h2] = offset;
+ return;
+ }
+ }
+ /*
+ * There are no slots, but we really want to store this, so we'll kick
+ * out the one with the longest distance.
+ */
+ worst_h = h;
+ worst_score = offset - o;
+ for (i = 1; i < LZX_HUFF_COMP_HASH_SEARCH_ATTEMPTS; i++) {
+ int score;
+ h2 = (h + i) & HASH_MASK;
+ o = hash_table[h2];
+ score = offset - o;
+ if (score > worst_score) {
+ worst_score = score;
+ worst_h = h2;
+ }
+ }
+ hash_table[worst_h] = offset;
+}
+
+
+/*
+ * Yes, struct match looks a lot like a DATA_BLOB.
+ */
+struct match {
+ const uint8_t *there;
+ size_t length;
+};
+
+
+static inline struct match lookup_match(uint16_t *hash_table,
+ uint16_t h,
+ const uint8_t *data,
+ const uint8_t *here,
+ size_t max_len)
+{
+ int i;
+ uint16_t o = hash_table[h];
+ uint16_t h2;
+ size_t len;
+ const uint8_t *there = NULL;
+ struct match best = {0};
+
+ for (i = 0; i < LZX_HUFF_COMP_HASH_SEARCH_ATTEMPTS; i++) {
+ h2 = (h + i) & HASH_MASK;
+ o = hash_table[h2];
+ if (o == 0xffff) {
+ /*
+ * in setting this, we would never have stepped over
+ * an 0xffff, so we won't now.
+ */
+ break;
+ }
+ there = data + o;
+ if (here - there > 65534 || there > here) {
+ continue;
+ }
+
+ /*
+ * When we already have a long match, we can try to avoid
+ * measuring out another long, but shorter match.
+ */
+ if (best.length > 1000 &&
+ there[best.length - 1] != best.there[best.length - 1]) {
+ continue;
+ }
+
+ for (len = 0;
+ len < max_len && here[len] == there[len];
+ len++) {
+ /* counting */
+ }
+ if (len > 2) {
+ /*
+ * As a tiebreaker, we prefer the closer match which
+ * is likely to encode smaller (and certainly no worse).
+ */
+ if (len > best.length ||
+ (len == best.length && there > best.there)) {
+ best.length = len;
+ best.there = there;
+ }
+ }
+ }
+ return best;
+}
+
+
+
+static ssize_t lz77_encode_block(struct lzxhuff_compressor_context *cmp_ctx,
+ struct lzxhuff_compressor_mem *cmp_mem,
+ uint16_t *hash_table,
+ uint16_t *prev_hash_table)
+{
+ uint16_t *intermediate = cmp_mem->intermediate;
+ struct huffman_node *leaf_nodes = cmp_mem->leaf_nodes;
+ uint16_t *symbol_values = cmp_mem->symbol_values;
+ size_t i, j, intermediate_len;
+ const uint8_t *data = cmp_ctx->input_bytes + cmp_ctx->input_pos;
+ const uint8_t *prev_block = NULL;
+ size_t remaining_size = cmp_ctx->input_size - cmp_ctx->input_pos;
+ size_t block_end = MIN(65536, remaining_size);
+ struct match match;
+ int n_symbols;
+
+ if (cmp_ctx->input_size < cmp_ctx->input_pos) {
+ return LZXPRESS_ERROR;
+ }
+
+ if (cmp_ctx->prev_block_pos != cmp_ctx->input_pos) {
+ prev_block = cmp_ctx->input_bytes + cmp_ctx->prev_block_pos;
+ } else if (prev_hash_table != NULL) {
+ /* we've got confused! hash and block should go together */
+ return LZXPRESS_ERROR;
+ }
+
+ /*
+ * leaf_nodes is used to count the symbols seen, for later Huffman
+ * encoding.
+ */
+ for (i = 0; i < 512; i++) {
+ leaf_nodes[i] = (struct huffman_node) {
+ .symbol = i
+ };
+ }
+
+ j = 0;
+
+ if (remaining_size < 41 || DEBUG_NO_LZ77_MATCHES) {
+ /*
+ * There is no point doing a hash table and looking for
+ * matches in this tiny block (remembering we are committed to
+ * using 32 bits, so there's a good chance we wouldn't even
+ * save a byte). The threshold of 41 matches Windows.
+ * If remaining_size < 3, we *can't* do the hash.
+ */
+ i = 0;
+ } else {
+ /*
+ * We use 0xffff as the unset value for table, because it is
+ * not a valid match offset (and 0x0 is).
+ */
+ memset(hash_table, 0xff, sizeof(cmp_mem->hash_table1));
+
+ for (i = 0; i <= block_end - 3; i++) {
+ uint16_t code;
+ const uint8_t *here = data + i;
+ uint16_t h = three_byte_hash(here);
+ size_t max_len = MIN(remaining_size - i, MAX_MATCH_LENGTH);
+ match = lookup_match(hash_table,
+ h,
+ data,
+ here,
+ max_len);
+
+ if (match.there == NULL && prev_hash_table != NULL) {
+ /*
+ * If this is not the first block,
+ * backreferences can look into the previous
+ * block (but only as far as 65535 bytes, so
+ * the end of this block cannot see the start
+ * of the last one).
+ */
+ match = lookup_match(prev_hash_table,
+ h,
+ prev_block,
+ here,
+ remaining_size - i);
+ }
+
+ store_match(hash_table, h, i);
+
+ if (match.there == NULL) {
+ /* add a literal and move on. */
+ uint8_t c = data[i];
+ leaf_nodes[c].count++;
+ intermediate[j] = c;
+ j++;
+ continue;
+ }
+
+ /* a real match */
+ if (match.length <= 65538) {
+ intermediate[j] = 0xffff;
+ intermediate[j + 1] = match.length - 3;
+ intermediate[j + 2] = here - match.there;
+ j += 3;
+ } else {
+ size_t m = match.length - 3;
+ intermediate[j] = 0xfffe;
+ intermediate[j + 1] = m & 0xffff;
+ intermediate[j + 2] = m >> 16;
+ intermediate[j + 3] = here - match.there;
+ j += 4;
+ }
+ code = encode_match(match.length, here - match.there);
+ leaf_nodes[code].count++;
+ i += match.length - 1; /* `- 1` for the loop i++ */
+ /*
+ * A match can take us past the intended block length,
+ * extending the block. We don't need to do anything
+ * special for this case -- the loops will naturally
+ * do the right thing.
+ */
+ }
+ }
+
+ /*
+ * There might be some bytes at the end.
+ */
+ for (; i < block_end; i++) {
+ leaf_nodes[data[i]].count++;
+ intermediate[j] = data[i];
+ j++;
+ }
+
+ if (i == remaining_size) {
+ /* add a trailing EOF marker (256) */
+ intermediate[j] = 0xffff;
+ intermediate[j + 1] = 0;
+ intermediate[j + 2] = 1;
+ j += 3;
+ leaf_nodes[256].count++;
+ }
+
+ intermediate_len = j;
+
+ cmp_ctx->prev_block_pos = cmp_ctx->input_pos;
+ cmp_ctx->input_pos += i;
+
+ /* fill in the symbols table */
+ n_symbols = generate_huffman_codes(leaf_nodes,
+ cmp_mem->internal_nodes,
+ symbol_values);
+ if (n_symbols < 0) {
+ return n_symbols;
+ }
+
+ return intermediate_len;
+}
+
+
+
+static ssize_t write_huffman_table(uint16_t symbol_values[512],
+ uint8_t *output,
+ size_t available_size)
+{
+ size_t i;
+
+ if (available_size < 256) {
+ return LZXPRESS_ERROR;
+ }
+
+ for (i = 0; i < 256; i++) {
+ uint8_t b = 0;
+ uint16_t even = symbol_values[i * 2];
+ uint16_t odd = symbol_values[i * 2 + 1];
+ if (even != 0) {
+ b = bitlen_nonzero_16(even);
+ }
+ if (odd != 0) {
+ b |= bitlen_nonzero_16(odd) << 4;
+ }
+ output[i] = b;
+ }
+ return i;
+}
+
+
+struct write_context {
+ uint8_t *dest;
+ size_t dest_len;
+ size_t head; /* where lengths go */
+ size_t next_code; /* where symbol stream goes */
+ size_t pending_next_code; /* will be next_code */
+ unsigned bit_len;
+ uint32_t bits;
+};
+
+/*
+ * Write out 16 bits, little-endian, for write_huffman_codes()
+ *
+ * As you'll notice, there's a bit to do.
+ *
+ * We are collecting up bits in a uint32_t, then when there are 16 of them we
+ * write out a word into the stream, using a trio of offsets (wc->next_code,
+ * wc->pending_next_code, and wc->head) which dance around ensuring that the
+ * bitstream and the interspersed lengths are in the right places relative to
+ * each other.
+ */
+
+static inline bool write_bits(struct write_context *wc,
+ uint16_t code, uint16_t length)
+{
+ wc->bits <<= length;
+ wc->bits |= code;
+ wc->bit_len += length;
+ if (wc->bit_len > 16) {
+ uint32_t w = wc->bits >> (wc->bit_len - 16);
+ wc->bit_len -= 16;
+ if (wc->next_code + 2 > wc->dest_len ||
+ unlikely(wc->bit_len > 16)) {
+ return false;
+ }
+ wc->dest[wc->next_code] = w & 0xff;
+ wc->dest[wc->next_code + 1] = (w >> 8) & 0xff;
+ wc->next_code = wc->pending_next_code;
+ wc->pending_next_code = wc->head;
+ wc->head += 2;
+ }
+ return true;
+}
+
+
+static inline bool write_code(struct write_context *wc, uint16_t code)
+{
+ int code_bit_len = bitlen_nonzero_16(code);
+ if (unlikely(code == 0)) {
+ return false;
+ }
+ code &= (1 << code_bit_len) - 1;
+ return write_bits(wc, code, code_bit_len);
+}
+
+static inline bool write_byte(struct write_context *wc, uint8_t byte)
+{
+ if (wc->head + 1 > wc->dest_len) {
+ return false;
+ }
+ wc->dest[wc->head] = byte;
+ wc->head++;
+ return true;
+}
+
+
+static inline bool write_long_len(struct write_context *wc, size_t len)
+{
+ if (len < 65535) {
+ if (wc->head + 3 > wc->dest_len) {
+ return false;
+ }
+ wc->dest[wc->head] = 255;
+ wc->dest[wc->head + 1] = len & 255;
+ wc->dest[wc->head + 2] = len >> 8;
+ wc->head += 3;
+ } else {
+ if (wc->head + 7 > wc->dest_len) {
+ return false;
+ }
+ wc->dest[wc->head] = 255;
+ wc->dest[wc->head + 1] = 0;
+ wc->dest[wc->head + 2] = 0;
+ wc->dest[wc->head + 3] = len & 255;
+ wc->dest[wc->head + 4] = (len >> 8) & 255;
+ wc->dest[wc->head + 5] = (len >> 16) & 255;
+ wc->dest[wc->head + 6] = (len >> 24) & 255;
+ wc->head += 7;
+ }
+ return true;
+}
+
+static ssize_t write_compressed_bytes(uint16_t symbol_values[512],
+ uint16_t *intermediate,
+ size_t intermediate_len,
+ uint8_t *dest,
+ size_t dest_len)
+{
+ bool ok;
+ size_t i;
+ size_t end;
+ struct write_context wc = {
+ .head = 4,
+ .pending_next_code = 2,
+ .dest = dest,
+ .dest_len = dest_len
+ };
+ for (i = 0; i < intermediate_len; i++) {
+ uint16_t c = intermediate[i];
+ size_t len;
+ uint16_t distance;
+ uint16_t code_len = 0;
+ uint16_t code_dist = 0;
+ if (c < 256) {
+ ok = write_code(&wc, symbol_values[c]);
+ if (!ok) {
+ return LZXPRESS_ERROR;
+ }
+ continue;
+ }
+
+ if (c == 0xfffe) {
+ if (i > intermediate_len - 4) {
+ return LZXPRESS_ERROR;
+ }
+
+ len = intermediate[i + 1];
+ len |= (uint32_t)intermediate[i + 2] << 16;
+ distance = intermediate[i + 3];
+ i += 3;
+ } else if (c == 0xffff) {
+ if (i > intermediate_len - 3) {
+ return LZXPRESS_ERROR;
+ }
+ len = intermediate[i + 1];
+ distance = intermediate[i + 2];
+ i += 2;
+ } else {
+ return LZXPRESS_ERROR;
+ }
+ if (unlikely(distance == 0)) {
+ return LZXPRESS_ERROR;
+ }
+ /* len has already had 3 subtracted */
+ if (len >= 15) {
+ /*
+ * We are going to need to write extra length
+ * bytes into the stream, but we don't do it
+ * now, we do it after the code has been
+ * written (and before the distance bits).
+ */
+ code_len = 15;
+ } else {
+ code_len = len;
+ }
+ code_dist = bitlen_nonzero_16(distance);
+ c = 256 | (code_dist << 4) | code_len;
+ if (c > 511) {
+ return LZXPRESS_ERROR;
+ }
+
+ ok = write_code(&wc, symbol_values[c]);
+ if (!ok) {
+ return LZXPRESS_ERROR;
+ }
+
+ if (code_len == 15) {
+ if (len >= 270) {
+ ok = write_long_len(&wc, len);
+ } else {
+ ok = write_byte(&wc, len - 15);
+ }
+ if (! ok) {
+ return LZXPRESS_ERROR;
+ }
+ }
+ if (code_dist != 0) {
+ uint16_t dist_bits = distance - (1 << code_dist);
+ ok = write_bits(&wc, dist_bits, code_dist);
+ if (!ok) {
+ return LZXPRESS_ERROR;
+ }
+ }
+ }
+ /*
+ * There are some intricacies around flushing the bits and returning
+ * the length.
+ *
+ * If the returned length is not exactly right and there is another
+ * block, that block will read its huffman table from the wrong place,
+ * and have all the symbol codes out by a multiple of 4.
+ */
+ end = wc.head;
+ if (wc.bit_len == 0) {
+ end -= 2;
+ }
+ ok = write_bits(&wc, 0, 16 - wc.bit_len);
+ if (!ok) {
+ return LZXPRESS_ERROR;
+ }
+ for (i = 0; i < 2; i++) {
+ /*
+ * Flush out the bits with zeroes. It doesn't matter if we do
+ * a round too many, as we have buffer space, and have already
+ * determined the returned length (end).
+ */
+ ok = write_bits(&wc, 0, 16);
+ if (!ok) {
+ return LZXPRESS_ERROR;
+ }
+ }
+ return end;
+}
+
+
+static ssize_t lzx_huffman_compress_block(struct lzxhuff_compressor_context *cmp_ctx,
+ struct lzxhuff_compressor_mem *cmp_mem,
+ size_t block_no)
+{
+ ssize_t intermediate_size;
+ uint16_t *hash_table = NULL;
+ uint16_t *back_window_hash_table = NULL;
+ ssize_t bytes_written;
+
+ if (cmp_ctx->available_size - cmp_ctx->output_pos < 260) {
+ /* huffman block + 4 bytes */
+ return LZXPRESS_ERROR;
+ }
+
+ /*
+ * For LZ77 compression, we keep a hash table for the previous block,
+ * via alternation after the first block.
+ *
+ * LZ77 writes into the intermediate buffer in the cmp_mem context.
+ */
+ if (block_no == 0) {
+ hash_table = cmp_mem->hash_table1;
+ back_window_hash_table = NULL;
+ } else if (block_no & 1) {
+ hash_table = cmp_mem->hash_table2;
+ back_window_hash_table = cmp_mem->hash_table1;
+ } else {
+ hash_table = cmp_mem->hash_table1;
+ back_window_hash_table = cmp_mem->hash_table2;
+ }
+
+ intermediate_size = lz77_encode_block(cmp_ctx,
+ cmp_mem,
+ hash_table,
+ back_window_hash_table);
+
+ if (intermediate_size < 0) {
+ return intermediate_size;
+ }
+
+ /*
+ * Write the 256 byte Huffman table, based on the counts gained in
+ * LZ77 phase.
+ */
+ bytes_written = write_huffman_table(
+ cmp_mem->symbol_values,
+ cmp_ctx->output + cmp_ctx->output_pos,
+ cmp_ctx->available_size - cmp_ctx->output_pos);
+
+ if (bytes_written != 256) {
+ return LZXPRESS_ERROR;
+ }
+ cmp_ctx->output_pos += 256;
+
+ /*
+ * Write the compressed bytes using the LZ77 matches and Huffman codes
+ * worked out in the previous steps.
+ */
+ bytes_written = write_compressed_bytes(
+ cmp_mem->symbol_values,
+ cmp_mem->intermediate,
+ intermediate_size,
+ cmp_ctx->output + cmp_ctx->output_pos,
+ cmp_ctx->available_size - cmp_ctx->output_pos);
+
+ if (bytes_written < 0) {
+ return bytes_written;
+ }
+
+ cmp_ctx->output_pos += bytes_written;
+ return bytes_written;
+}
+
+/*
+ * lzxpress_huffman_max_compressed_size()
+ *
+ * Return the most bytes the compression can take, to allow
+ * pre-allocation.
+ */
+size_t lzxpress_huffman_max_compressed_size(size_t input_size)
+{
+ /*
+ * In the worst case, the output size should be about the same as the
+ * input size, plus the 256 byte header per 64k block. We aim for
+ * ample, but within the order of magnitude.
+ */
+ return input_size + (input_size / 8) + 270;
+}
+
+/*
+ * lzxpress_huffman_compress_talloc()
+ *
+ * This is the convenience function that allocates the compressor context and
+ * output memory for you. The return value is the number of bytes written to
+ * the location indicated by the output pointer.
+ *
+ * The maximum input_size is effectively around 227MB due to the need to guess
+ * an upper bound on the output size that hits an internal limitation in
+ * talloc.
+ *
+ * @param mem_ctx TALLOC_CTX parent for the compressed buffer.
+ * @param input_bytes memory to be compressed.
+ * @param input_size length of the input buffer.
+ * @param output destination pointer for the compressed data.
+ *
+ * @return the number of bytes written or -1 on error.
+ */
+
+ssize_t lzxpress_huffman_compress_talloc(TALLOC_CTX *mem_ctx,
+ const uint8_t *input_bytes,
+ size_t input_size,
+ uint8_t **output)
+{
+ struct lzxhuff_compressor_mem *cmp = NULL;
+ size_t alloc_size = lzxpress_huffman_max_compressed_size(input_size);
+
+ ssize_t output_size;
+
+ *output = talloc_array(mem_ctx, uint8_t, alloc_size);
+ if (*output == NULL) {
+ return LZXPRESS_ERROR;
+ }
+
+ cmp = talloc(mem_ctx, struct lzxhuff_compressor_mem);
+ if (cmp == NULL) {
+ TALLOC_FREE(*output);
+ return LZXPRESS_ERROR;
+ }
+
+ output_size = lzxpress_huffman_compress(cmp,
+ input_bytes,
+ input_size,
+ *output,
+ alloc_size);
+
+ talloc_free(cmp);
+
+ if (output_size < 0) {
+ TALLOC_FREE(*output);
+ return LZXPRESS_ERROR;
+ }
+
+ *output = talloc_realloc(mem_ctx, *output, uint8_t, output_size);
+ if (*output == NULL) {
+ return LZXPRESS_ERROR;
+ }
+
+ return output_size;
+}
+
+/*
+ * lzxpress_huffman_compress()
+ *
+ * This is the inconvenience function, slightly faster and fiddlier than
+ * lzxpress_huffman_compress_talloc().
+ *
+ * To use this, you need to have allocated (but not initialised) a `struct
+ * lzxhuff_compressor_mem`, and an output buffer. If the buffer is not big
+ * enough (per `output_size`), you'll get a negative return value, otherwise
+ * the number of bytes actually consumed, which will always be at least 260.
+ *
+ * The `struct lzxhuff_compressor_mem` is reusable -- it is basically a
+ * collection of uninitialised memory buffers. The total size is less than
+ * 150k, so stack allocation is plausible.
+ *
+ * input_size and available_size are limited to the minimum of UINT32_MAX and
+ * SSIZE_MAX. On 64 bit machines that will be UINT32_MAX, or 4GB.
+ *
+ * @param cmp_mem a struct lzxhuff_compressor_mem.
+ * @param input_bytes memory to be compressed.
+ * @param input_size length of the input buffer.
+ * @param output destination for the compressed data.
+ * @param available_size allocated output bytes.
+ *
+ * @return the number of bytes written or -1 on error.
+ */
+ssize_t lzxpress_huffman_compress(struct lzxhuff_compressor_mem *cmp_mem,
+ const uint8_t *input_bytes,
+ size_t input_size,
+ uint8_t *output,
+ size_t available_size)
+{
+ size_t i = 0;
+ struct lzxhuff_compressor_context cmp_ctx = {
+ .input_bytes = input_bytes,
+ .input_size = input_size,
+ .input_pos = 0,
+ .prev_block_pos = 0,
+ .output = output,
+ .available_size = available_size,
+ .output_pos = 0
+ };
+
+ if (input_size == 0) {
+ /*
+ * We can't deal with this for a number of reasons (e.g. it
+ * breaks the Huffman tree), and the output will be infinitely
+ * bigger than the input. The caller needs to go and think
+ * about what they're trying to do here.
+ */
+ return LZXPRESS_ERROR;
+ }
+
+ if (input_size > SSIZE_MAX ||
+ input_size > UINT32_MAX ||
+ available_size > SSIZE_MAX ||
+ available_size > UINT32_MAX ||
+ available_size == 0) {
+ /*
+ * We use negative ssize_t to return errors, which is limiting
+ * on 32 bit machines; otherwise we adhere to Microsoft's 4GB
+ * limit.
+ *
+ * lzxpress_huffman_compress_talloc() will not get this far,
+ * having already have failed on talloc's 256 MB limit.
+ */
+ return LZXPRESS_ERROR;
+ }
+
+ if (cmp_mem == NULL ||
+ output == NULL ||
+ input_bytes == NULL) {
+ return LZXPRESS_ERROR;
+ }
+
+ while (cmp_ctx.input_pos < cmp_ctx.input_size) {
+ ssize_t ret;
+ ret = lzx_huffman_compress_block(&cmp_ctx,
+ cmp_mem,
+ i);
+ if (ret < 0) {
+ return ret;
+ }
+ i++;
+ }
+
+ return cmp_ctx.output_pos;
+}
+
+static void debug_tree_codes(struct bitstream *input)
+{
+ /*
+ */
+ size_t head = 0;
+ size_t tail = 2;
+ size_t ffff_count = 0;
+ struct q {
+ uint16_t tree_code;
+ uint16_t code_code;
+ };
+ struct q queue[65536];
+ char bits[17];
+ uint16_t *t = input->table;
+ queue[0].tree_code = 1;
+ queue[0].code_code = 2;
+ queue[1].tree_code = 2;
+ queue[1].code_code = 3;
+ while (head < tail) {
+ struct q q = queue[head];
+ uint16_t x = t[q.tree_code];
+ if (x != 0xffff) {
+ int k;
+ uint16_t j = q.code_code;
+ size_t offset = bitlen_nonzero_16(j) - 1;
+ if (unlikely(j == 0)) {
+ DBG("BROKEN code is 0!\n");
+ return;
+ }
+
+ for (k = 0; k <= offset; k++) {
+ bool b = (j >> (offset - k)) & 1;
+ bits[k] = b ? '1' : '0';
+ }
+ bits[k] = 0;
+ DBG("%03x %s\n", x & 511, bits);
+ head++;
+ continue;
+ }
+ ffff_count++;
+ queue[tail].tree_code = q.tree_code * 2 + 1;
+ queue[tail].code_code = q.code_code * 2;
+ tail++;
+ queue[tail].tree_code = q.tree_code * 2 + 1 + 1;
+ queue[tail].code_code = q.code_code * 2 + 1;
+ tail++;
+ head++;
+ }
+ DBG("0xffff count: %zu\n", ffff_count);
+}
+
+/**
+ * Determines the sort order of one prefix_code_symbol relative to another
+ */
+static int compare_uint16(const uint16_t *a, const uint16_t *b)
+{
+ if (*a < *b) {
+ return -1;
+ }
+ if (*a > *b) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static bool fill_decomp_table(struct bitstream *input)
+{
+ /*
+ * There are 512 symbols, each encoded in 4 bits, which indicates
+ * their depth in the Huffman tree. The even numbers get the lower
+ * nibble of each byte, so that the byte hex values look backwards
+ * (i.e. 0xab encodes b then a). These are allocated Huffman codes in
+ * order of appearance, per depth.
+ *
+ * For example, if the first two bytes were:
+ *
+ * 0x23 0x53
+ *
+ * the first four codes have the lengths 3, 2, 3, 5.
+ * Let's call them A, B, C, D.
+ *
+ * Suppose there is no other codeword with length 1 (which is
+ * necessarily true in this example) or 2, but there might be others
+ * of length 3 or 4. Then we can say this about the codes:
+ *
+ * _ --*--_
+ * / \
+ * 0 1
+ * / \ / \
+ * 0 1 0 1
+ * B |\ / \ |\
+ * 0 1 0 1 0 1
+ * A C |\ /| | |\
+ *
+ * pos bits code
+ * A 3 010
+ * B 2 00
+ * C 3 011
+ * D 5 1????
+ *
+ * B has the shortest code, so takes the leftmost branch, 00. That
+ * ends the branch -- nothing else can start with 00. There are no
+ * more 2s, so we look at the 3s, starting as far left as possible. So
+ * A takes 010 and C takes 011. That means everything else has to
+ * start with 1xx. We don't know how many codewords of length 3 or 4
+ * there are; if there are none, D would end up with 10000, the
+ * leftmost available code of length 5. If the compressor is any good,
+ * there should be no unused leaf nodes left dangling at the end.
+ *
+ * (this is "Canonical Huffman Coding").
+ *
+ *
+ * But what symbols do these codes actually stand for?
+ * --------------------------------------------------
+ *
+ * Good question. The first 256 codes stand for the corresponding
+ * literal bytes. The codes from 256 to 511 stand for LZ77 matches,
+ * which have a distance and a length, encoded in a strange way that
+ * isn't entirely the purview of this function.
+ *
+ * What does the value 0 mean?
+ * ---------------------------
+ *
+ * The code does not occur. For example, if the next byte in the
+ * example above was 0x07, that would give the byte 0x04 a 7-long
+ * code, and no code to the 0x05 byte, which means we there is no way
+ * we going to see a 5 in the decoded stream.
+ *
+ * Isn't LZ77 + Huffman what zip/gzip/zlib do?
+ * -------------------------------------------
+ *
+ * Yes, DEFLATE is LZ77 + Huffman, but the details are quite different.
+ */
+ uint16_t symbols[512];
+ uint16_t sort_mem[512];
+ size_t i, n_symbols;
+ ssize_t code;
+ uint16_t len = 0, prev_len;
+ const uint8_t *table_bytes = input->bytes + input->byte_pos;
+
+ if (input->byte_pos + 260 > input->byte_size) {
+ return false;
+ }
+
+ n_symbols = 0;
+ for (i = 0; i < 256; i++) {
+ uint16_t even = table_bytes[i] & 15;
+ uint16_t odd = table_bytes[i] >> 4;
+ if (even != 0) {
+ symbols[n_symbols] = (even << 9) + i * 2;
+ n_symbols++;
+ }
+ if (odd != 0) {
+ symbols[n_symbols] = (odd << 9) + i * 2 + 1;
+ n_symbols++;
+ }
+ }
+ input->byte_pos += 256;
+ if (n_symbols == 0) {
+ return false;
+ }
+
+ stable_sort(symbols, sort_mem, n_symbols, sizeof(uint16_t),
+ (samba_compare_fn_t)compare_uint16);
+
+ /*
+ * we're using an implicit binary tree, as you'd see in a heap.
+ * table[0] = unused
+ * table[1] = '0'
+ * table[2] = '1'
+ * table[3] = '00' <-- '00' and '01' are children of '0'
+ * table[4] = '01' <-- '0' is [0], children are [0 * 2 + {1,2}]
+ * table[5] = '10'
+ * table[6] = '11'
+ * table[7] = '000'
+ * table[8] = '001'
+ * table[9] = '010'
+ * table[10]= '011'
+ * table[11]= '100
+ *'
+ * table[1 << n - 1] = '0' * n
+ * table[1 << n - 1 + x] = n-bit wide x (left padded with '0')
+ * table[1 << n - 2] = '1' * (n - 1)
+ *
+ * table[i]->left = table[i*2 + 1]
+ * table[i]->right = table[i*2 + 2]
+ * table[0xffff] = unused (16 '0's, max len is 15)
+ *
+ * therefore e.g. table[70] = table[64 - 1 + 7]
+ * = table[1 << 6 - 1 + 7]
+ * = '000111' (binary 7, widened to 6 bits)
+ *
+ * and if '000111' is a code,
+ * '00011', '0001', '000', '00', '0' are unavailable prefixes.
+ * 34 16 7 3 1 are their indices
+ * and (i - 1) >> 1 is the path back from 70 through these.
+ *
+ * the lookup is
+ *
+ * 1 start with i = 0
+ * 2 extract a symbol bit (i = (i << 1) + bit + 1)
+ * 3 is table[i] == 0xffff?
+ * 4 yes -- goto 2
+ * 4 table[i] & 511 is the symbol, stop
+ *
+ * and the construction (here) is sort of the reverse.
+ *
+ * Most of this table is free space that can never be reached, and
+ * most of the activity is at the beginning (since all codes start
+ * there, and by design the shortest codes are the most common).
+ */
+ for (i = 0; i < 32; i++) {
+ /* prefill the table head */
+ input->table[i] = 0xffff;
+ }
+ code = -1;
+ prev_len = 0;
+ for (i = 0; i < n_symbols; i++) {
+ uint16_t s = symbols[i];
+ uint16_t prefix;
+ len = (s >> 9) & 15;
+ s &= 511;
+ code++;
+ while (len != prev_len) {
+ code <<= 1;
+ code++;
+ prev_len++;
+ }
+
+ if (code >= 65535) {
+ return false;
+ }
+ input->table[code] = s;
+ for(prefix = (code - 1) >> 1;
+ prefix > 31;
+ prefix = (prefix - 1) >> 1) {
+ input->table[prefix] = 0xffff;
+ }
+ }
+ if (CHECK_DEBUGLVL(10)) {
+ debug_tree_codes(input);
+ }
+
+ /*
+ * check that the last code encodes 11111..., with right number of
+ * ones, pointing to the right symbol -- otherwise we have a dangling
+ * uninitialised symbol.
+ */
+ if (code != (1 << (len + 1)) - 2) {
+ return false;
+ }
+ return true;
+}
+
+
+#define CHECK_READ_32(dest) \
+ do { \
+ if (input->byte_pos + 4 > input->byte_size) { \
+ return LZXPRESS_ERROR; \
+ } \
+ dest = PULL_LE_U32(input->bytes, input->byte_pos); \
+ input->byte_pos += 4; \
+ } while (0)
+
+#define CHECK_READ_16(dest) \
+ do { \
+ if (input->byte_pos + 2 > input->byte_size) { \
+ return LZXPRESS_ERROR; \
+ } \
+ dest = PULL_LE_U16(input->bytes, input->byte_pos); \
+ input->byte_pos += 2; \
+ } while (0)
+
+#define CHECK_READ_8(dest) \
+ do { \
+ if (input->byte_pos >= input->byte_size) { \
+ return LZXPRESS_ERROR; \
+ } \
+ dest = PULL_LE_U8(input->bytes, input->byte_pos); \
+ input->byte_pos++; \
+ } while(0)
+
+
+static inline ssize_t pull_bits(struct bitstream *input)
+{
+ if (input->byte_pos + 1 < input->byte_size) {
+ uint16_t tmp;
+ CHECK_READ_16(tmp);
+ input->remaining_bits += 16;
+ input->bits <<= 16;
+ input->bits |= tmp;
+ } else if (input->byte_pos < input->byte_size) {
+ uint8_t tmp;
+ CHECK_READ_8(tmp);
+ input->remaining_bits += 8;
+ input->bits <<= 8;
+ input->bits |= tmp;
+ } else {
+ return LZXPRESS_ERROR;
+ }
+ return 0;
+}
+
+
+/*
+ * Decompress a block. The actual decompressed size is returned (or -1 on
+ * error). The putative block length is 64k (or shorter, if the message ends
+ * first), but a match can run over the end, extending the block. That's why
+ * we need the overall output size as well as the block size. A match encoded
+ * in this block can point back to previous blocks, but not before the
+ * beginning of the message, so we also need the previously decoded size.
+ *
+ * The compressed block will have 256 bytes for the Huffman table, and at
+ * least 4 bytes of (possibly padded) encoded values.
+ */
+static ssize_t lzx_huffman_decompress_block(struct bitstream *input,
+ uint8_t *output,
+ size_t block_size,
+ size_t output_size,
+ size_t previous_size)
+{
+ size_t output_pos = 0;
+ uint16_t symbol;
+ size_t index;
+ uint16_t distance_bits_wanted = 0;
+ size_t distance = 0;
+ size_t length = 0;
+ bool ok;
+ uint32_t tmp;
+ bool seen_eof_marker = false;
+
+ ok = fill_decomp_table(input);
+ if (! ok) {
+ return LZXPRESS_ERROR;
+ }
+ if (CHECK_DEBUGLVL(10) || DEBUG_HUFFMAN_TREE) {
+ debug_huffman_tree_from_table(input->table);
+ }
+ /*
+ * Always read 32 bits at the start, even if we don't need them.
+ */
+ CHECK_READ_16(tmp);
+ CHECK_READ_16(input->bits);
+ input->bits |= tmp << 16;
+ input->remaining_bits = 32;
+
+ /*
+ * This loop iterates over individual *bits*. These are read from
+ * little-endian 16 bit words, most significant bit first.
+ *
+ * At points in the bitstream, the following are possible:
+ *
+ * # the source word is empty and needs to be refilled from the input
+ * stream.
+ * # an incomplete codeword is being extended.
+ * # a codeword is resolved, either as a literal or a match.
+ * # a literal is written.
+ * # a match is collecting distance bits.
+ * # the output stream is copied, as specified by a match.
+ * # input bytes are read for match lengths.
+ *
+ * Note that we *don't* specifically check for the EOF marker (symbol
+ * 256) in this loop, because the precondition for stopping for the
+ * EOF marker is that the output buffer is full (otherwise, you
+ * wouldn't know which 256 is EOF, rather than an actual symbol), and
+ * we *always* want to stop when the buffer is full. So we work out if
+ * there is an EOF in another loop after we stop writing.
+ */
+
+ index = 0;
+ while (output_pos < block_size) {
+ uint16_t b;
+ if (input->remaining_bits == 16) {
+ ssize_t ret = pull_bits(input);
+ if (ret) {
+ return ret;
+ }
+ }
+ input->remaining_bits--;
+
+ b = (input->bits >> input->remaining_bits) & 1;
+ if (length == 0) {
+ /* not in a match; pulling a codeword */
+ index <<= 1;
+ index += b + 1;
+ if (input->table[index] == 0xffff) {
+ /* incomplete codeword, the common case */
+ continue;
+ }
+ /* found the symbol, reset the code string */
+ symbol = input->table[index] & 511;
+ index = 0;
+ if (symbol < 256) {
+ /* a literal, the easy case */
+ output[output_pos] = symbol;
+ output_pos++;
+ continue;
+ }
+
+ /* the beginning of a match */
+ distance_bits_wanted = (symbol >> 4) & 15;
+ distance = 1 << distance_bits_wanted;
+ length = symbol & 15;
+ if (length == 15) {
+ CHECK_READ_8(tmp);
+ length += tmp;
+ if (length == 255 + 15) {
+ /*
+ * note, we discard (don't add) the
+ * length so far.
+ */
+ CHECK_READ_16(length);
+ if (length == 0) {
+ CHECK_READ_32(length);
+ }
+ }
+ }
+ length += 3;
+ } else {
+ /* we are pulling extra distance bits */
+ distance_bits_wanted--;
+ distance |= b << distance_bits_wanted;
+ }
+
+ if (distance_bits_wanted == 0) {
+ /*
+ * We have a complete match, and it is time to do the
+ * copy (byte by byte, because the ranges can overlap,
+ * and we might need to copy bytes we just copied in).
+ *
+ * It is possible that this match will extend beyond
+ * the end of the expected block. That's fine, so long
+ * as it doesn't extend past the total output size.
+ */
+ size_t i;
+ size_t end = output_pos + length;
+ uint8_t *here = output + output_pos;
+ uint8_t *there = here - distance;
+ if (end > output_size ||
+ previous_size + output_pos < distance ||
+ unlikely(end < output_pos || there > here)) {
+ return LZXPRESS_ERROR;
+ }
+ for (i = 0; i < length; i++) {
+ here[i] = there[i];
+ }
+ output_pos += length;
+ distance = 0;
+ length = 0;
+ }
+ }
+
+ if (length != 0 || index != 0) {
+ /* it seems like we've hit an early end, mid-code */
+ return LZXPRESS_ERROR;
+ }
+
+ if (input->byte_pos + 256 < input->byte_size) {
+ /*
+ * This block is over, but it clearly isn't the last block, so
+ * we don't want to look for the EOF.
+ */
+ return output_pos;
+ }
+ /*
+ * We won't write any more, but we try to read some more to make sure
+ * we're finishing in a good place. That means we want to see a 256
+ * symbol and then some number of zeroes, possibly zero, but as many
+ * as 32.
+ *
+ * In this we are perhaps a bit stricter than Windows, which
+ * apparently does not insist on the EOF marker, nor on a lack of
+ * trailing bytes.
+ */
+ while (true) {
+ uint16_t b;
+ if (input->remaining_bits == 16) {
+ ssize_t ret;
+ if (input->byte_pos == input->byte_size) {
+ /* FIN */
+ break;
+ }
+ ret = pull_bits(input);
+ if (ret) {
+ return ret;
+ }
+ }
+ input->remaining_bits--;
+ b = (input->bits >> input->remaining_bits) & 1;
+ if (seen_eof_marker) {
+ /*
+ * we have read an EOF symbols. Now we just want to
+ * see zeroes.
+ */
+ if (b != 0) {
+ return LZXPRESS_ERROR;
+ }
+ continue;
+ }
+
+ /* we're pulling in a symbol, which had better be 256 */
+ index <<= 1;
+ index += b + 1;
+ if (input->table[index] == 0xffff) {
+ continue;
+ }
+
+ symbol = input->table[index] & 511;
+ if (symbol != 256) {
+ return LZXPRESS_ERROR;
+ }
+ seen_eof_marker = true;
+ continue;
+ }
+
+ if (! seen_eof_marker) {
+ return LZXPRESS_ERROR;
+ }
+
+ return output_pos;
+}
+
+static ssize_t lzxpress_huffman_decompress_internal(struct bitstream *input,
+ uint8_t *output,
+ size_t output_size)
+{
+ size_t output_pos = 0;
+
+ if (input->byte_size < 260) {
+ return LZXPRESS_ERROR;
+ }
+
+ while (input->byte_pos < input->byte_size) {
+ ssize_t block_output_pos;
+ ssize_t block_output_size;
+ size_t remaining_output_size = output_size - output_pos;
+
+ block_output_size = MIN(65536, remaining_output_size);
+
+ block_output_pos = lzx_huffman_decompress_block(
+ input,
+ output + output_pos,
+ block_output_size,
+ remaining_output_size,
+ output_pos);
+
+ if (block_output_pos < block_output_size) {
+ return LZXPRESS_ERROR;
+ }
+ output_pos += block_output_pos;
+ if (output_pos > output_size) {
+ /* not expecting to get here. */
+ return LZXPRESS_ERROR;
+ }
+ }
+
+ if (input->byte_pos != input->byte_size) {
+ return LZXPRESS_ERROR;
+ }
+
+ return output_pos;
+}
+
+
+/*
+ * lzxpress_huffman_decompress()
+ *
+ * output_size must be the expected length of the decompressed data.
+ * input_size and output_size are limited to the minimum of UINT32_MAX and
+ * SSIZE_MAX. On 64 bit machines that will be UINT32_MAX, or 4GB.
+ *
+ * @param input_bytes memory to be decompressed.
+ * @param input_size length of the compressed buffer.
+ * @param output destination for the decompressed data.
+ * @param output_size exact expected length of the decompressed data.
+ *
+ * @return the number of bytes written or -1 on error.
+ */
+
+ssize_t lzxpress_huffman_decompress(const uint8_t *input_bytes,
+ size_t input_size,
+ uint8_t *output,
+ size_t output_size)
+{
+ uint16_t table[65536];
+ struct bitstream input = {
+ .bytes = input_bytes,
+ .byte_size = input_size,
+ .byte_pos = 0,
+ .bits = 0,
+ .remaining_bits = 0,
+ .table = table
+ };
+
+ if (input_size > SSIZE_MAX ||
+ input_size > UINT32_MAX ||
+ output_size > SSIZE_MAX ||
+ output_size > UINT32_MAX ||
+ input_size == 0 ||
+ output_size == 0 ||
+ input_bytes == NULL ||
+ output == NULL) {
+ /*
+ * We use negative ssize_t to return errors, which is limiting
+ * on 32 bit machines, and the 4GB limit exists on Windows.
+ */
+ return LZXPRESS_ERROR;
+ }
+
+ return lzxpress_huffman_decompress_internal(&input,
+ output,
+ output_size);
+}
+
+
+/**
+ * lzxpress_huffman_decompress_talloc()
+ *
+ * The caller must provide the exact size of the expected output.
+ *
+ * The input_size is limited to the minimum of UINT32_MAX and SSIZE_MAX, but
+ * output_size is limited to 256MB due to a limit in talloc. This effectively
+ * limits input_size too, as non-crafted compressed data will not exceed the
+ * decompressed size by very much.
+ *
+ * @param mem_ctx TALLOC_CTX parent for the decompressed buffer.
+ * @param input_bytes memory to be decompressed.
+ * @param input_size length of the compressed buffer.
+ * @param output_size expected decompressed size.
+ *
+ * @return a talloc'ed buffer exactly output_size in length, or NULL.
+ */
+
+uint8_t *lzxpress_huffman_decompress_talloc(TALLOC_CTX *mem_ctx,
+ const uint8_t *input_bytes,
+ size_t input_size,
+ size_t output_size)
+{
+ ssize_t result;
+ uint8_t *output = NULL;
+ struct bitstream input = {
+ .bytes = input_bytes,
+ .byte_size = input_size
+ };
+
+ output = talloc_array(mem_ctx, uint8_t, output_size);
+ if (output == NULL) {
+ return NULL;
+ }
+
+ input.table = talloc_array(mem_ctx, uint16_t, 65536);
+ if (input.table == NULL) {
+ talloc_free(output);
+ return NULL;
+ }
+ result = lzxpress_huffman_decompress_internal(&input,
+ output,
+ output_size);
+ talloc_free(input.table);
+
+ if (result != output_size) {
+ talloc_free(output);
+ return NULL;
+ }
+ return output;
+}
diff --git a/lib/compression/lzxpress_huffman.h b/lib/compression/lzxpress_huffman.h
new file mode 100644
index 0000000..41cca5c
--- /dev/null
+++ b/lib/compression/lzxpress_huffman.h
@@ -0,0 +1,95 @@
+/*
+ * Samba compression library - LGPLv3
+ *
+ * Copyright © Catalyst IT 2022
+ *
+ * ** NOTE! The following LGPL license applies to this file.
+ * ** It does NOT imply that all of Samba is released under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HAVE_LZXPRESS_HUFFMAN_H
+#define HAVE_LZXPRESS_HUFFMAN_H
+
+
+struct huffman_node {
+ struct huffman_node *left;
+ struct huffman_node *right;
+ uint32_t count;
+ uint16_t symbol;
+ int8_t depth;
+};
+
+
+/*
+ * LZX_HUFF_COMP_HASH_BITS is how big to make the hash tables
+ * (12 means 4096, etc).
+ *
+ * A larger number (up to 16) will be faster on long messages (fewer
+ * collisions), but probably slower on short ones (more prep).
+ */
+#define LZX_HUFF_COMP_HASH_BITS 14
+
+
+/*
+ * This struct just coalesces all the memory you need for LZ77 + Huffman
+ * compression together in one bundle.
+ *
+ * There are a few different things you want, you usually want them all, so
+ * this makes it easy to allocate them all at once.
+ */
+
+struct lzxhuff_compressor_mem {
+ struct huffman_node leaf_nodes[512];
+ struct huffman_node internal_nodes[512];
+ uint16_t symbol_values[512];
+ uint16_t intermediate[65536 + 6];
+ uint16_t hash_table1[1 << LZX_HUFF_COMP_HASH_BITS];
+ uint16_t hash_table2[1 << LZX_HUFF_COMP_HASH_BITS];
+};
+
+
+ssize_t lzxpress_huffman_compress(struct lzxhuff_compressor_mem *cmp,
+ const uint8_t *input_bytes,
+ size_t input_size,
+ uint8_t *output,
+ size_t available_size);
+
+
+ssize_t lzxpress_huffman_compress_talloc(TALLOC_CTX *mem_ctx,
+ const uint8_t *input_bytes,
+ size_t input_size,
+ uint8_t **output);
+
+ssize_t lzxpress_huffman_decompress(const uint8_t *input,
+ size_t input_size,
+ uint8_t *output,
+ size_t max_output_size);
+
+uint8_t *lzxpress_huffman_decompress_talloc(TALLOC_CTX *mem_ctx,
+ const uint8_t *input_bytes,
+ size_t input_size,
+ size_t output_size);
+
+/*
+ * lzxpress_huffman_max_compressed_size()
+ *
+ * Return the most bytes the compression can take, to allow
+ * pre-allocation.
+ */
+size_t lzxpress_huffman_max_compressed_size(size_t input_size);
+
+
+#endif /* HAVE_LZXPRESS_HUFFMAN_H */
diff --git a/lib/compression/pycompression.c b/lib/compression/pycompression.c
new file mode 100644
index 0000000..5c3fd82
--- /dev/null
+++ b/lib/compression/pycompression.c
@@ -0,0 +1,304 @@
+/*
+ Samba Unix SMB/CIFS implementation.
+
+ Python bindings for compression functions.
+
+ Copyright (C) Petr Viktorin 2015
+ Copyright (C) Douglas Bagnall 2022
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <talloc.h>
+#include "lib/replace/system/python.h"
+#include "lzxpress.h"
+#include "lzxpress_huffman.h"
+
+/* CompressionError is filled out in module init */
+static PyObject *CompressionError = NULL;
+
+static PyObject *plain_compress(PyObject *mod, PyObject *args)
+{
+ uint8_t *src = NULL;
+ Py_ssize_t src_len;
+ char *dest = NULL;
+ Py_ssize_t dest_len;
+ PyObject *dest_obj = NULL;
+ size_t alloc_len;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "s#", &src, &src_len)) {
+ return NULL;
+ }
+
+ /*
+ * 9/8 + 4 is the worst case growth, but we add room.
+ *
+ * alloc_len can't overflow as src_len is ssize_t while alloc_len is
+ * size_t.
+ */
+ alloc_len = src_len + src_len / 8 + 500;
+
+ dest_obj = PyBytes_FromStringAndSize(NULL, alloc_len);
+ if (dest_obj == NULL) {
+ return NULL;
+ }
+ dest = PyBytes_AS_STRING(dest_obj);
+
+ dest_len = lzxpress_compress(src,
+ src_len,
+ (uint8_t *)dest,
+ alloc_len);
+ if (dest_len < 0) {
+ PyErr_SetString(CompressionError, "unable to compress data");
+ Py_DECREF(dest_obj);
+ return NULL;
+ }
+
+ ret = _PyBytes_Resize(&dest_obj, dest_len);
+ if (ret != 0) {
+ /*
+ * Don't try to free dest_obj, as we're in deep MemoryError
+ * territory here.
+ */
+ return NULL;
+ }
+ return dest_obj;
+}
+
+
+static PyObject *plain_decompress(PyObject *mod, PyObject *args)
+{
+ uint8_t *src = NULL;
+ Py_ssize_t src_len;
+ char *dest = NULL;
+ Py_ssize_t dest_len;
+ PyObject *dest_obj = NULL;
+ Py_ssize_t alloc_len = 0;
+ Py_ssize_t given_len = 0;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "s#|n", &src, &src_len, &given_len)) {
+ return NULL;
+ }
+ if (given_len != 0) {
+ /*
+ * With plain decompression, we don't *need* the exact output
+ * size (as we do with LZ77+Huffman), but it certainly helps
+ * when guessing the size.
+ */
+ alloc_len = given_len;
+ } else if (src_len > UINT32_MAX) {
+ /*
+ * The underlying decompress function will reject this, but by
+ * checking here we can give a better message and be clearer
+ * about overflow risks.
+ *
+ * Note, the limit is actually the smallest of UINT32_MAX and
+ * SSIZE_MAX, but src_len is ssize_t so it already can't
+ * exceed that.
+ */
+ PyErr_Format(CompressionError,
+ "The maximum size for compressed data is 4GB "
+ "cannot decompress %zu bytes.", src_len);
+ } else {
+ /*
+ * The data can expand massively (though not beyond the
+ * 4GB limit) so we guess a big number for small inputs
+ * (we expect small inputs), and a relatively conservative
+ * number for big inputs.
+ */
+ if (src_len <= 3333333) {
+ alloc_len = 10000000;
+ } else if (src_len > UINT32_MAX / 3) {
+ alloc_len = UINT32_MAX;
+ } else {
+ alloc_len = src_len * 3;
+ }
+ }
+
+ dest_obj = PyBytes_FromStringAndSize(NULL, alloc_len);
+ if (dest_obj == NULL) {
+ return NULL;
+ }
+ dest = PyBytes_AS_STRING(dest_obj);
+
+ dest_len = lzxpress_decompress(src,
+ src_len,
+ (uint8_t *)dest,
+ alloc_len);
+ if (dest_len < 0) {
+ if (alloc_len == given_len) {
+ PyErr_Format(CompressionError,
+ "unable to decompress data into a buffer "
+ "of %zd bytes.", alloc_len);
+ } else {
+ PyErr_Format(CompressionError,
+ "unable to decompress data into a buffer "
+ "of %zd bytes. If you know the length, "
+ "supply it as the second argument.",
+ alloc_len);
+ }
+ Py_DECREF(dest_obj);
+ return NULL;
+ }
+
+ ret = _PyBytes_Resize(&dest_obj, dest_len);
+ if (ret != 0) {
+ /*
+ * Don't try to free dest_obj, as we're in deep MemoryError
+ * territory here.
+ */
+ return NULL;
+ }
+ return dest_obj;
+}
+
+
+
+static PyObject *huffman_compress(PyObject *mod, PyObject *args)
+{
+ uint8_t *src = NULL;
+ Py_ssize_t src_len;
+ char *dest = NULL;
+ Py_ssize_t dest_len;
+ PyObject *dest_obj = NULL;
+ size_t alloc_len;
+ int ret;
+ struct lzxhuff_compressor_mem cmp_mem;
+
+ if (!PyArg_ParseTuple(args, "s#", &src, &src_len)) {
+ return NULL;
+ }
+ /*
+ * worst case is roughly 256 per 64k or less.
+ *
+ * alloc_len won't overflow as src_len is ssize_t while alloc_len is
+ * size_t.
+ */
+ alloc_len = src_len + src_len / 8 + 500;
+
+ dest_obj = PyBytes_FromStringAndSize(NULL, alloc_len);
+ if (dest_obj == NULL) {
+ return NULL;
+ }
+ dest = PyBytes_AS_STRING(dest_obj);
+
+ dest_len = lzxpress_huffman_compress(&cmp_mem,
+ src,
+ src_len,
+ (uint8_t *)dest,
+ alloc_len);
+ if (dest_len < 0) {
+ PyErr_SetString(CompressionError, "unable to compress data");
+ Py_DECREF(dest_obj);
+ return NULL;
+ }
+
+ ret = _PyBytes_Resize(&dest_obj, dest_len);
+ if (ret != 0) {
+ return NULL;
+ }
+ return dest_obj;
+}
+
+
+static PyObject *huffman_decompress(PyObject *mod, PyObject *args)
+{
+ uint8_t *src = NULL;
+ Py_ssize_t src_len;
+ char *dest = NULL;
+ Py_ssize_t dest_len;
+ PyObject *dest_obj = NULL;
+ Py_ssize_t given_len = 0;
+ /*
+ * Here it is always necessary to supply the exact length.
+ */
+
+ if (!PyArg_ParseTuple(args, "s#n", &src, &src_len, &given_len)) {
+ return NULL;
+ }
+
+ dest_obj = PyBytes_FromStringAndSize(NULL, given_len);
+ if (dest_obj == NULL) {
+ return NULL;
+ }
+ dest = PyBytes_AS_STRING(dest_obj);
+
+ dest_len = lzxpress_huffman_decompress(src,
+ src_len,
+ (uint8_t *)dest,
+ given_len);
+ if (dest_len != given_len) {
+ PyErr_Format(CompressionError,
+ "unable to decompress data into a %zd bytes.",
+ given_len);
+ Py_DECREF(dest_obj);
+ return NULL;
+ }
+ /* no resize here */
+ return dest_obj;
+}
+
+
+static PyMethodDef mod_methods[] = {
+ { "plain_compress", (PyCFunction)plain_compress, METH_VARARGS,
+ "compress bytes using lzxpress plain compression"},
+ { "plain_decompress", (PyCFunction)plain_decompress, METH_VARARGS,
+ "decompress lzxpress plain compressed bytes"},
+ { "huffman_compress", (PyCFunction)huffman_compress, METH_VARARGS,
+ "compress bytes using lzxpress plain compression"},
+ { "huffman_decompress", (PyCFunction)huffman_decompress, METH_VARARGS,
+ "decompress lzxpress plain compressed bytes"},
+ {0}
+};
+
+
+#define MODULE_DOC PyDoc_STR("LZXpress compression/decompression bindings")
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "compression",
+ .m_doc = MODULE_DOC,
+ .m_size = -1,
+ .m_methods = mod_methods,
+};
+
+
+static PyObject *module_init(void)
+{
+ PyObject *m = PyModule_Create(&moduledef);
+ if (m == NULL) {
+ return NULL;
+ }
+
+ CompressionError = PyErr_NewException(
+ "compression.CompressionError",
+ PyExc_Exception,
+ NULL);
+ PyModule_AddObject(m, "CompressionError", CompressionError);
+
+ return m;
+}
+
+PyMODINIT_FUNC PyInit_compression(void);
+PyMODINIT_FUNC PyInit_compression(void)
+{
+ return module_init();
+}
diff --git a/lib/compression/tests/scripts/README b/lib/compression/tests/scripts/README
new file mode 100644
index 0000000..aff1047
--- /dev/null
+++ b/lib/compression/tests/scripts/README
@@ -0,0 +1,19 @@
+Tools used in the development and testing the LZ77 + Huffman code.
+
+These might not be of use to anyone ever, but here they are.
+
+make-fuzz-examples
+encodes compressed files for decompression fuzzer.
+
+decode-huffman-header
+print Huffman codes and validate first header in a compressed file.
+
+three-byte-hash
+check that a three byte hash works.
+
+make-test-vectors
+make files with randomly unbalanced symbol distributions.
+
+generate-windows-test-vectors.c
+if compiled under Cygwin or similar on Windows, this can be used to
+generate and verify test vectors.
diff --git a/lib/compression/tests/scripts/decode-huffman-header b/lib/compression/tests/scripts/decode-huffman-header
new file mode 100755
index 0000000..9c1279b
--- /dev/null
+++ b/lib/compression/tests/scripts/decode-huffman-header
@@ -0,0 +1,54 @@
+#!/usr/bin/python3
+"""Print the codes in the first Huffman tree header in the given file.
+
+USAGE: decode-huffman-header FILE
+
+The number of codes of different length is printed first, followed by
+the implied total frequency of codes, followed by the deduced codes.
+
+If the total is not 1.0, the header is invalid.
+"""
+
+import sys
+
+
+if '--help' in sys.argv or '-h' in sys.argv or len(sys.argv) != 2:
+ print(__doc__)
+ exit(len(sys.argv) != 2)
+
+
+def read_table(data):
+ lengths = [[] for x in range(16)]
+ for i, b in enumerate(data):
+ even = b & 15
+ odd = b >> 4
+ lengths[even].append(i * 2)
+ lengths[odd].append(i * 2 + 1)
+
+ code = 0
+
+ total = 0.0
+ for i, bucket in enumerate(lengths):
+ if bucket and i:
+ portion = 1.0 / (1 << i) * len(bucket)
+ total += portion
+ print(f"length {i:2}: {len(bucket):4} ({portion})")
+ print(f"total {total}")
+
+ for i, bucket in enumerate(lengths):
+ if i == 0:
+ continue
+ code <<= 1
+ for c in bucket:
+ print(f'{c:03x} {code:0{i}b}')
+ code += 1
+
+
+def main():
+ fn = sys.argv[1]
+ with open(fn, 'rb') as f:
+ data = f.read(256)
+ read_table(data)
+
+
+main()
diff --git a/lib/compression/tests/scripts/generate-windows-test-vectors.c b/lib/compression/tests/scripts/generate-windows-test-vectors.c
new file mode 100644
index 0000000..28724d2
--- /dev/null
+++ b/lib/compression/tests/scripts/generate-windows-test-vectors.c
@@ -0,0 +1,206 @@
+/*
+ * Generate test vectorsa for Windows LZ77 Huffman compression.
+ *
+ * Copyright (c) 2022 Douglas Bagnall <dbagnall@samba.org>
+ *
+ * GPLv3+.
+ *
+ * Can be compiled on Windows 2012r2 under Cygwin
+ *
+ * gcc -o generate-windows-test-vectors \
+ * generate-windows-test-vectors.c \
+ * C:\Windows\SysWOW64\cabinet.dll \
+ * -lcabinet
+ *
+ * There might be better ways.
+ *
+ * See https://learn.microsoft.com/en-us/windows/win32/cmpapi/-compression-portal
+ */
+
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* compressapi.h is in the Windows API. mingw-w64 has a copy. */
+#include <compressapi.h>
+#include <errhandlingapi.h>
+
+struct blob {
+ uint8_t *data;
+ size_t length;
+};
+
+/* Windows size_t is different than Cygwin size_t (though still 64 bit) */
+typedef unsigned long long wsize_t;
+
+
+#define compression_flags (COMPRESS_ALGORITHM_XPRESS_HUFF | COMPRESS_RAW)
+
+int32_t compression_level = 0;
+
+static struct blob compress(struct blob input)
+{
+ COMPRESSOR_HANDLE handle;
+ struct blob output;
+ bool ok;
+ wsize_t used;
+
+ ok = CreateCompressor(compression_flags, NULL, &handle);
+
+ if (! ok) {
+ fprintf(stderr, "CreateCompressor failed\n");
+ exit(1);
+ }
+
+ output.length = input.length * 3 + 256;
+ output.data = malloc(output.length);
+ if (output.data == NULL) {
+ fprintf(stderr, "output allocation failed (estimated %zu)\n",
+ output.length);
+ exit(1);
+ }
+
+
+ ok = SetCompressorInformation(handle,
+ COMPRESS_INFORMATION_CLASS_LEVEL,
+ &compression_level,
+ sizeof(compression_level));
+
+ if (! ok) {
+ fprintf(stderr, "SetCompressorInformation failed: %d\n",
+ GetLastError());
+ //exit(1);
+ }
+
+ ok = Compress(handle,
+ input.data,
+ input.length,
+ output.data,
+ output.length,
+ &used);
+ if (! ok) {
+ fprintf(stderr, "Compress failed\n");
+ exit(1);
+ }
+ output.data = realloc(output.data, used);
+ if (output.data == NULL) {
+ fprintf(stderr,
+ "failed to shrinkwrap output! (from %zu to %llu)\n",
+ output.length, used);
+ exit(1);
+ }
+ output.length = used;
+ CloseCompressor(handle);
+ return output;
+}
+
+
+struct blob decompress(struct blob input,
+ size_t expected_size)
+{
+ DECOMPRESSOR_HANDLE handle;
+ struct blob output;
+ bool ok;
+ wsize_t used;
+
+ ok = CreateDecompressor(compression_flags, NULL, &handle);
+
+ if (! ok) {
+ fprintf(stderr, "CreateDecompressor failed\n");
+ exit(1);
+ }
+
+ output.length = expected_size;
+ output.data = malloc(output.length);
+ if (output.data == NULL) {
+ fprintf(stderr, "output allocation failed (%zu)\n",
+ output.length);
+ exit(1);
+ }
+
+ ok = Decompress(handle,
+ input.data,
+ input.length,
+ output.data,
+ output.length,
+ &used);
+ if (! ok) {
+ fprintf(stderr, "Decompress failed\n");
+ exit(1);
+ }
+ CloseDecompressor(handle);
+ return output;
+}
+
+
+static void __attribute__((noreturn)) usage(int ret)
+{
+ fprintf(stderr,
+ "USAGE: test-win-vectors {c,d} filename [length|level] > DEST\n\n");
+ fprintf(stderr, "c for< compression, d for decompression\n");
+ fprintf(stderr, "decompressed length is required for decompression\n");
+ fprintf(stderr, "compression level flag is optional [default 0]\n");
+ exit(ret);
+}
+
+int main(int argc, const char *argv[])
+{
+ FILE *fh;
+ const char *filename;
+ struct stat s;
+ int ret;
+ struct blob input = {0};
+ struct blob output = {0};
+
+ if (argc < 3 || argc > 4) {
+ usage(1);
+ }
+ filename = argv[2];
+
+ fh = fopen(filename, "rb");
+ if (fh == NULL) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ usage(1);
+ }
+
+ ret = fstat(fileno(fh), &s);
+ if (ret != 0) {
+ fprintf(stderr, "Could not stat %s: %d\n", filename, ret);
+ usage(1);
+ }
+ input.length = s.st_size;
+ input.data = malloc(input.length);
+ if (input.data == NULL) {
+ fprintf(stderr, "input too big for memory?! (%zu)\n",
+ s.st_size);
+ exit(1);
+ }
+
+ fread(input.data, 1, input.length, fh);
+
+ if (strcmp(argv[1], "c") == 0) {
+ if (argc == 4 && strcmp(argv[3], "0")) {
+ compression_level = 1;
+ }
+ output = compress(input);
+ } else if (strcmp(argv[1], "d") == 0) {
+ size_t decomp_size;
+ if (argc != 4) {
+ fprintf(stderr, "no length given\n");
+ usage(1);
+ }
+ decomp_size = atoi(argv[3]);
+ output = decompress(input, decomp_size);
+ } else {
+ usage(1);
+ }
+ fwrite(output.data, 1, output.length, stdout);
+ free(output.data);
+ return 0;
+}
diff --git a/lib/compression/tests/scripts/make-fuzz-examples b/lib/compression/tests/scripts/make-fuzz-examples
new file mode 100755
index 0000000..09200fb
--- /dev/null
+++ b/lib/compression/tests/scripts/make-fuzz-examples
@@ -0,0 +1,45 @@
+#!/usr/bin/python3
+#
+"""Pack the compressed files created by test_lzx_huffman.c (with
+LZXHUFF_DEBUG_FILES) into the format used by the decompression fuzzer.
+
+That is, the first 3 bytes are the length of the decompressed file,
+and the rest of the file is the compressed data.
+
+USAGE: make-fuzz-examples DIR
+
+where DIR is probably '/tmp'.
+"""
+import os
+import sys
+
+
+if '--help' in sys.argv or '-h' in sys.argv or len(sys.argv) != 2:
+ print(__doc__)
+ exit(len(sys.argv) != 2)
+
+
+def main():
+ files = set(os.listdir(sys.argv[1]))
+
+ for fn in files:
+ if fn.endswith('-compressed'):
+ fn2 = fn.replace('-compressed', '-decompressed')
+ if fn2 not in files:
+ print(f"skipping {fn}, no {fn2}")
+ continue
+ cfn = '/tmp/' + fn
+ dfn = '/tmp/' + fn2
+ wfn = '/tmp/' + fn.replace('-compressed', '.fuzz')
+
+ size = os.stat(dfn).st_size
+ sbytes = bytes([(size & 0xff), (size >> 8) & 0xff, (size >> 16) & 0xff])
+
+ with open(cfn, 'rb') as f:
+ s = f.read()
+
+ with open(wfn, 'wb') as f:
+ s = f.write(sbytes + s)
+
+
+main()
diff --git a/lib/compression/tests/scripts/make-test-vectors b/lib/compression/tests/scripts/make-test-vectors
new file mode 100755
index 0000000..6f25866
--- /dev/null
+++ b/lib/compression/tests/scripts/make-test-vectors
@@ -0,0 +1,185 @@
+#!/usr/bin/python3
+"""Generate a few strings with unbalanced distributions to test the
+regeneration of the Huffman tree when it gets too deep.
+
+USAGE: make-test-vectors DIR
+
+This will fill up DIR with test files.
+"""
+import sys
+import random
+from collections import defaultdict
+
+
+if '--help' in sys.argv or '-h' in sys.argv or len(sys.argv) != 2:
+ print(__doc__)
+ exit(len(sys.argv) != 2)
+
+
+DIR = sys.argv[1]
+
+SIZE = (1 << 17) + (23) # two and a bit blocks
+SIZE_NAME = "128k+"
+# SIZE = (1 << 16)
+# SIZE_NAME = "64"
+
+
+random.seed(1)
+
+
+def squares(n):
+ array = []
+ for i in range(n):
+ a = random.random()
+ b = random.random()
+ array.append(int(a * b * 256))
+ return bytes(array)
+
+
+def skewed_choices(n):
+ b = list(range(256))
+ array = random.choices(b, weights=b, k=n)
+ return bytes(array)
+
+
+def fib_shuffle(n):
+ array = []
+ a, b = 1, 1
+ for i in range(100):
+ array.extend([i] * a)
+ a, b = a + b, a
+ if len(array) > 1000000:
+ break
+ random.shuffle(array)
+ return bytes(array[:n])
+
+
+def exp_shuffle(n):
+ array = []
+ for i in range(256):
+ array.extend([i] * int(1.04 ** i))
+ if len(array) > 1000000:
+ break
+ random.shuffle(array)
+ return bytes(array[:n])
+
+
+def and_rand(n):
+ array = []
+ for i in range(n):
+ a = random.randrange(256)
+ b = random.randrange(256)
+ array.append(a & b)
+ return bytes(array)
+
+
+def betavar(n, a, b):
+ array = []
+ for i in range(n):
+ x = random.betavariate(a, b)
+ array.append(int(x * 255.999999999999))
+ return bytes(array)
+
+
+def repeated_alphabet(n):
+ a = b'abcdefghijklmnopqrstuvwxyz'
+ na = n // len(a) + 1
+ s = a * na
+ return s[:n]
+
+
+def decayed_alphabet(n):
+ s = list(repeated_alphabet(n))
+ for i in range(256):
+ j = random.randrange(n)
+ s[j] = i
+
+ return bytes(s)
+
+
+def trigram_model(n):
+ with open(__file__, 'rb') as f:
+ data = f.read()
+ lut = defaultdict(list)
+ for a, b, c in zip(data, data[1:], data[2:]):
+ k = bytes([a, b])
+ lut[k].append(c)
+
+ k = random.choice(list(lut.keys()))
+ s = []
+ p = k[1]
+ for i in range(n + 10):
+ c = random.choice(lut[k])
+ s.append(c)
+ k = bytes([p, c])
+ p = c
+
+ return bytes(s[10:])
+
+
+def trigram_sum_model(n):
+ with open(__file__, 'rb') as f:
+ data = f.read()
+ lut = [[random.randrange(256)] for i in range(512)]
+ for a, b, c in zip(data, data[1:], data[2:]):
+ lut[a + b].append(c)
+
+ s = []
+ i = random.randrange(len(data) - 1)
+ a = data[i]
+ b = data[i + 1]
+
+ for i in range(n + 10):
+ x = lut[a + b]
+ c = random.choice(x)
+ s.append(c)
+ a = b
+ b = c
+
+ return bytes(s[10:])
+
+
+def the_classics():
+ # this used to be main()
+ sq = squares(SIZE)
+ ch = skewed_choices(SIZE)
+ fs = fib_shuffle(SIZE)
+ es = exp_shuffle(SIZE)
+ ar = and_rand(SIZE)
+ bv1 = betavar(SIZE, 0.1, 1.5)
+ bv2 = betavar(SIZE, 0.5, 2.0)
+ bv3 = betavar(SIZE, 0.05, 0.05)
+
+ print("n sq ch fs es")
+ for i in range(256):
+ print(f"{i:3} {sq.count(i):5} {ch.count(i):5} "
+ f"{fs.count(i):5} {es.count(i):5}"
+ f"{ar.count(i):5} {bv1.count(i):5}"
+ f"{bv2.count(i):5} {bv3.count(i):5}"
+ )
+
+ for series, fn in ((sq, "square_series"),
+ (ch, "skewed_choices"),
+ (fs, "fib_shuffle"),
+ (es, "exp_shuffle"),
+ (ar, "and_rand"),
+ (bv1, "beta-variate1"),
+ (bv2, "beta-variate2"),
+ (bv3, "beta-variate3"),
+ ):
+ with open(f"{DIR}/{fn}-{SIZE_NAME}", "wb") as f:
+ f.write(series)
+
+
+def main():
+ if True:
+ the_classics()
+ for series, fn in ((decayed_alphabet(SIZE), "decayed_alphabet"),
+ (trigram_model(SIZE), "trigram"),
+ (trigram_sum_model(SIZE), "trigram_sum"),
+ ):
+ with open(f"{DIR}/{fn}_{SIZE_NAME}", "wb") as f:
+ f.write(series)
+
+
+main()
diff --git a/lib/compression/tests/scripts/three-byte-hash b/lib/compression/tests/scripts/three-byte-hash
new file mode 100755
index 0000000..100d0bc
--- /dev/null
+++ b/lib/compression/tests/scripts/three-byte-hash
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+"""Print statistics about a certain three byte hash.
+
+USAGE: three_byte_hash
+"""
+import sys
+
+if '--help' in sys.argv or '-h' in sys.argv or len(sys.argv) > 1:
+ print(__doc__)
+ exit(not ('--help' in sys.argv or '-h' in sys.argv))
+
+
+from statistics import mean, pstdev, median
+
+
+def h(*args, bits=12):
+ a = args[0]
+ b = args[1] ^ 0x2e
+ c = args[2] ^ 0x55
+ d = ((a + b) << 8) ^ (((c - a) & 0xffff) << 5) ^ (c + b) ^ (0xcab + a)
+ return d & ((1 << bits) - 1)
+
+
+def count(fn, bits, filter=None):
+ counts = [0] * (1 << bits)
+ for i in range(256 ** 3):
+ a, b, c = i & 255, (i >> 8) & 255, i >> 16
+ if filter and not (filter(a) and filter(b) and filter(c)):
+ continue
+
+ h = fn(a, b, c, bits=bits)
+ counts[h] += 1
+
+ print(f" {bits} bits; {len(counts)} buckets, "
+ f"expected {(1<<24) / len(counts)}")
+ print(f"median {median(counts)}")
+ print(f"mean {mean(counts)}")
+ print(f"min {min(counts)}")
+ print(f"max {max(counts)}")
+ print(f"stddev {pstdev(counts)}")
+
+
+for b in (12, 13, 14):
+ count(h, b)
+
+ print("With ASCII filter")
+ letters = set(range(32, 127))
+ letters |= set(b'\r\n\t\0')
+ count(h, b, filter=letters.__contains__)
diff --git a/lib/compression/tests/test_lzx_huffman.c b/lib/compression/tests/test_lzx_huffman.c
new file mode 100644
index 0000000..7770535
--- /dev/null
+++ b/lib/compression/tests/test_lzx_huffman.c
@@ -0,0 +1,1255 @@
+/*
+ * Samba compression library - LGPLv3
+ *
+ * Copyright © Catalyst IT 2022
+ *
+ * Written by Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+ *
+ * ** NOTE! The following LGPL license applies to this file.
+ * ** It does NOT imply that all of Samba is released under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include "replace.h"
+#include <talloc.h>
+#include "lzxpress_huffman.h"
+#include "lib/util/stable_sort.h"
+#include "lib/util/data_blob.h"
+
+/* set LZXHUFF_DEBUG_FILES to true to save round-trip files in /tmp. */
+#define LZXHUFF_DEBUG_FILES false
+
+/* set LZXHUFF_DEBUG_VERBOSE to true to print more. */
+#define LZXHUFF_DEBUG_VERBOSE false
+
+
+#if LZXHUFF_DEBUG_VERBOSE
+#define debug_message(...) print_message(__VA_ARGS__)
+
+#include <time.h>
+
+struct timespec start = {0};
+struct timespec end = {0};
+static void debug_start_timer(void)
+{
+ clock_gettime(CLOCK_MONOTONIC, &start);
+}
+
+static void debug_end_timer(const char *name, size_t len)
+{
+ uint64_t ns;
+ double secs;
+ double rate;
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ ns = end.tv_nsec;
+ ns += end.tv_sec * 1000 * 1000 * 1000;
+ ns -= start.tv_nsec;
+ ns -= start.tv_sec * 1000 * 1000 * 1000;
+ secs = ns / 1e9;
+ rate = len / (secs * 1024 * 1024);
+ debug_message("%s %zu bytes in %.2g: \033[1;35m%.2f\033[0m MB per second\n",
+ name, len, secs, rate);
+}
+
+#else
+#define debug_message(...) /* debug_message */
+#define debug_start_timer(...) /* debug_start_timer */
+#define debug_end_timer(...) /* debug_end_timer */
+#endif
+
+
+struct lzx_pair {
+ const char *name;
+ DATA_BLOB compressed;
+ DATA_BLOB decompressed;
+};
+
+struct lzx_file_pair {
+ const char *name;
+ const char *compressed_file;
+ const char *decompressed_file;
+};
+
+
+#define DECOMP_DIR "testdata/compression/decompressed"
+#define COMP_DIR "testdata/compression/compressed-huffman"
+#define MORE_COMP_DIR "testdata/compression/compressed-more-huffman"
+
+
+#define VARRGH(...) __VA_ARGS__
+
+#define BLOB_FROM_ARRAY(...) \
+ { \
+ .data = (uint8_t[]){__VA_ARGS__}, \
+ .length = sizeof((uint8_t[]){__VA_ARGS__}) \
+ }
+
+#define BLOB_FROM_STRING(s) \
+ { \
+ .data = discard_const_p(uint8_t, s), \
+ .length = (sizeof(s) - 1) \
+ }
+
+
+const char * file_names[] = {
+ "27826-8.txt",
+ "5d049b4cb1bd933f5e8ex19",
+ "638e61e96d54279981c3x5",
+ "64k-minus-one-zeros",
+ "64k-plus-one-zeros",
+ "64k-zeros",
+ "96f696a4e5ce56c61a3dx10",
+ "9e0b6a12febf38e98f13",
+ "abc-times-101",
+ "abc-times-105",
+ "abc-times-200",
+ "and_rand",
+ "and_rand-128k+",
+ "b63289ccc7f218c0d56b",
+ "beta-variate1-128k+",
+ "beta-variate2-128k+",
+ "beta-variate3-128k+",
+ "decayed_alphabet_128k+",
+ "decayed_alphabet_64k",
+ "exp_shuffle",
+ "exp_shuffle-128k+",
+ "f00842317dc6d5695b02",
+ "fib_shuffle",
+ "fib_shuffle-128k+",
+ "fuzzing-0fc2d461b56cd8103c91",
+ "fuzzing-17c961778538cc10ab7c",
+ "fuzzing-3591f9dc02bb00a54b60",
+ "fuzzing-3ec3bca27bb9eb40c128",
+ "fuzzing-80b4fa18ff5f8dd04862",
+ "fuzzing-a3115a81d1ac500318f9",
+ "generate-windows-test-vectors.c",
+ "midsummer-nights-dream.txt",
+ "notes-on-the-underground.txt",
+ "pg22009.txt",
+ "repeating",
+ "repeating-exactly-64k",
+ "setup.log",
+ "skewed_choices",
+ "skewed_choices-128k+",
+ /* These ones were deathly slow in fuzzing at one point */
+ "slow-015ddc36a71412ccc50d",
+ "slow-100e9f966a7feb9ca40a",
+ "slow-2a671c3cff4f1574cbab",
+ "slow-33d90a24e70515b14cd0",
+ "slow-49d8c05261e3f412fc72",
+ "slow-50a249d2fe56873e56a0",
+ "slow-63e9f0b52235fb0129fa",
+ "slow-73b7f971d65908ac0095",
+ "slow-8b61e3dd267908544531",
+ "slow-9d1c5a079b0462986f1f",
+ "slow-aa7262a821dabdcf04a6",
+ "slow-b8a91d142b0d2af7f5ca",
+ "slow-c79142457734bbc8d575",
+ "slow-d736544545b90d83fe75",
+ "slow-e3b9bdfaed7d1a606fdb",
+ "slow-f3f1c02a9d006e5e1703",
+ "square_series",
+ "square_series-128k+",
+ "trigram_128k+",
+ "trigram_64k",
+ "trigram_sum_128k+",
+ "trigram_sum_64k",
+ NULL
+};
+
+struct lzx_pair bidirectional_pairs[] = {
+
+ {.name = "abc__100_repeats", /* [MS-XCA] 3.2 example 2. */
+ .decompressed = BLOB_FROM_STRING(
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ ),
+ .compressed = BLOB_FROM_ARRAY(
+ /*
+ * The 'a', 'b', and 'c' bytes are 0x61, 0x62, 0x63. No other
+ * symbols occur. That means we need 48 0x00 bytes for the
+ * first 96 symbol-nybbles, then some short codes, then zeros
+ * again for the rest of the literals.
+ */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,
+ 0x30, 0x23, /* a_ cb */
+ 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, /* 100 bytes */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0, /* here end the 0-255 literals (128 bytes) */
+ 0x02, /* 'EOF' symbol 256 (byte 128 low) */
+ 0,0,0,0,0, 0,0,0,0,0, 0, /* 140 bytes */
+ 0,0,0,
+ 0x20, /* codepoint 287 (byte 143 high) */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0, /* 160 bytes */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, /* 240 bytes */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,
+ /*
+ * So that's the tree.
+ *
+ * length 2 codes for 'c', EOF, 287
+ * length 3 for 'a', 'b'.
+ *
+ * c: 00
+ * EOF: 01
+ * 287: 10
+ * a: 110
+ * b: 111
+ *
+ * thus the literal string "abc" is 110-111-00.
+ *
+ * Now for the lz77 match definitions for EOF and 287.
+ *
+ * Why 287? It encodes the match distance and offset.
+ *
+ * 287 - 256 = 31
+ *
+ * _length = 31 % 16 = 15
+ * _distance = 31 / 16 = 1
+ *
+ * (it's easier to look at the hex, 0x11f:
+ * 1xx means a match; x1x is _distance; xxf is _length)
+ *
+ * _distance 1 means a two bit distance (10 or 11; 2 or 3).
+ * That means the next bit will be the least significant bit
+ * of distance (1 in this case, meaning distance 3).
+ *
+ * if _length is 15, real length is included inline.
+ *
+ * 'EOF' == 256 means _length = 0, _distance = 0.
+ *
+ * _distance 0 means 1, so no further bits needed.
+ * _length 0 means length 3.
+ *
+ * but when used as EOF, this doesn't matter.
+ */
+ 0xa8, 0xdc, 0x00, 0x00, 0xff, 0x26, 0x01
+ /* These remaining bytes are:
+ *
+ * 10101000 11011100 00000000 00000000 11111111
+ * 00100110 00000001
+ *
+ * and we read them as 16 chunks (i.e. flipping odd/even order)
+ *
+ * 110-111-00 10-1-01-000
+ * a b c 287 | EOF
+ * |
+ * this is the 287 distance low bit.
+ *
+ * The last 3 bits are not used. The 287 length is sort of
+ * out of band, coming up soon (because 287 encodes length
+ * 15; most codes do not do this).
+ *
+ * 00000000 00000000
+ *
+ * This padding is there because the first 32 bits are read
+ * at the beginning of decoding. If there were more things to
+ * be encoded, they would be in here.
+ *
+ * 11111111
+ *
+ * This byte is pulled as the length for the 287 match.
+ * Because it is 0xff, we pull a further 2 bytes for the
+ * actual length, i.e. a 16 bit number greater than 270.
+ *
+ * 00000001 00100110
+ *
+ * that is 0x126 = 294 = the match length - 3 (because we're
+ * encoding ["abc", <copy from 3 back, 297 chars>, EOF]).
+ *
+ */
+ )
+ },
+ {.name = "abcdefghijklmnopqrstuvwxyz", /* [MS-XCA] 3.2 example 1. */
+ .decompressed = BLOB_FROM_STRING("abcdefghijklmnopqrstuvwxyz"),
+ .compressed = BLOB_FROM_ARRAY(
+ /*
+ * In this case there are no matches encoded as there are no
+ * repeated symbols. Including the EOF, there are 27 symbols
+ * all occurring exactly as frequently as each other (once).
+ * From that we would expect the codes to be mostly 5 bits
+ * long, because 27 < 2^5 (32), but greater than 2^4. And
+ * that's what we see.
+ */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,
+ /* 14 non-zero bytes for 26 letters/nibbles */
+ 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x45, 0x44, 0x04,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0, /* 80 */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,
+ 0x04, /* 0x100 EOF */
+ /* no matches */
+ 0,0,0,0,0, 0,0,0,0,0, 0, /* 140 */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, /* 240 */
+ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,
+
+ 0xd8, 0x52, 0x3e, 0xd7, 0x94, 0x11, 0x5b, 0xe9,
+ 0x19, 0x5f, 0xf9, 0xd6, 0x7c, 0xdf, 0x8d, 0x04,
+ 0x00, 0x00, 0x00, 0x00)
+ },
+ {0}
+};
+
+
+static void test_lzxpress_huffman_decompress(void **state)
+{
+ size_t i;
+ ssize_t written;
+ uint8_t *dest = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; bidirectional_pairs[i].name != NULL; i++) {
+ struct lzx_pair p = bidirectional_pairs[i];
+ dest = talloc_array(mem_ctx, uint8_t, p.decompressed.length);
+
+ debug_message("%s compressed %zu decomp %zu\n", p.name,
+ p.compressed.length,
+ p.decompressed.length);
+
+ written = lzxpress_huffman_decompress(p.compressed.data,
+ p.compressed.length,
+ dest,
+ p.decompressed.length);
+ assert_int_not_equal(written, -1);
+ assert_int_equal(written, p.decompressed.length);
+
+ assert_memory_equal(dest, p.decompressed.data, p.decompressed.length);
+ talloc_free(dest);
+ }
+}
+
+static void test_lzxpress_huffman_compress(void **state)
+{
+ size_t i;
+ ssize_t written;
+ uint8_t *dest = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; bidirectional_pairs[i].name != NULL; i++) {
+ struct lzx_pair p = bidirectional_pairs[i];
+ debug_message("%s compressed %zu decomp %zu\n", p.name,
+ p.compressed.length,
+ p.decompressed.length);
+
+ written = lzxpress_huffman_compress_talloc(mem_ctx,
+ p.decompressed.data,
+ p.decompressed.length,
+ &dest);
+
+ assert_int_not_equal(written, -1);
+ assert_int_equal(written, p.compressed.length);
+ assert_memory_equal(dest, p.compressed.data, p.compressed.length);
+ talloc_free(dest);
+ }
+}
+
+
+static DATA_BLOB datablob_from_file(TALLOC_CTX *mem_ctx,
+ const char *filename)
+{
+ DATA_BLOB b = {0};
+ FILE *fh = fopen(filename, "rb");
+ int ret;
+ struct stat s;
+ size_t len;
+ if (fh == NULL) {
+ debug_message("could not open '%s'\n", filename);
+ return b;
+ }
+ ret = fstat(fileno(fh), &s);
+ if (ret != 0) {
+ fclose(fh);
+ return b;
+ }
+ b.data = talloc_array(mem_ctx, uint8_t, s.st_size);
+ if (b.data == NULL) {
+ fclose(fh);
+ return b;
+ }
+ len = fread(b.data, 1, s.st_size, fh);
+ if (ferror(fh) || len != s.st_size) {
+ TALLOC_FREE(b.data);
+ } else {
+ b.length = len;
+ }
+ fclose(fh);
+ return b;
+}
+
+
+
+static void test_lzxpress_huffman_decompress_files(void **state)
+{
+ size_t i;
+ int score = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; file_names[i] != NULL; i++) {
+ char filename[200];
+ uint8_t *dest = NULL;
+ ssize_t written;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct lzx_pair p = {
+ .name = file_names[i]
+ };
+
+ debug_message("%s\n", p.name);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.decomp", DECOMP_DIR, p.name);
+
+ p.decompressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.decompressed.data);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.lzhuff", COMP_DIR, p.name);
+
+ p.compressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.compressed.data);
+
+ dest = talloc_array(tmp_ctx, uint8_t, p.decompressed.length);
+ debug_start_timer();
+ written = lzxpress_huffman_decompress(p.compressed.data,
+ p.compressed.length,
+ dest,
+ p.decompressed.length);
+ debug_end_timer("decompress", p.decompressed.length);
+ if (written != -1 &&
+ written == p.decompressed.length &&
+ memcmp(dest, p.decompressed.data, p.decompressed.length) == 0) {
+ debug_message("\033[1;32mdecompressed %s!\033[0m\n", p.name);
+ score++;
+ } else {
+ debug_message("\033[1;31mfailed to decompress %s!\033[0m\n",
+ p.name);
+ debug_message("size %zd vs reference %zu\n",
+ written, p.decompressed.length);
+ }
+ talloc_free(tmp_ctx);
+ }
+ debug_message("%d/%zu correct\n", score, i);
+ assert_int_equal(score, i);
+}
+
+
+static void test_lzxpress_huffman_decompress_more_compressed_files(void **state)
+{
+ /*
+ * This tests the decompression of files that have been compressed on
+ * Windows with the level turned up (to 1, default for MS-XCA is 0).
+ *
+ * The format is identical, but it will have tried harder to find
+ * matches.
+ */
+ size_t i;
+ int score = 0;
+ int found = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; file_names[i] != NULL; i++) {
+ char filename[200];
+ uint8_t *dest = NULL;
+ ssize_t written;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct lzx_pair p = {
+ .name = file_names[i]
+ };
+
+ debug_message("%s\n", p.name);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.decomp", DECOMP_DIR, p.name);
+
+ p.decompressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.decompressed.data);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.lzhuff", MORE_COMP_DIR, p.name);
+
+ p.compressed = datablob_from_file(tmp_ctx, filename);
+ if (p.compressed.data == NULL) {
+ /*
+ * We don't have all the vectors in the
+ * more-compressed directory, which is OK, we skip
+ * them.
+ */
+ continue;
+ }
+ found++;
+ dest = talloc_array(tmp_ctx, uint8_t, p.decompressed.length);
+ debug_start_timer();
+ written = lzxpress_huffman_decompress(p.compressed.data,
+ p.compressed.length,
+ dest,
+ p.decompressed.length);
+ debug_end_timer("decompress", p.decompressed.length);
+ if (written == p.decompressed.length &&
+ memcmp(dest, p.decompressed.data, p.decompressed.length) == 0) {
+ debug_message("\033[1;32mdecompressed %s!\033[0m\n", p.name);
+ score++;
+ } else {
+ debug_message("\033[1;31mfailed to decompress %s!\033[0m\n",
+ p.name);
+ debug_message("size %zd vs reference %zu\n",
+ written, p.decompressed.length);
+ }
+ talloc_free(tmp_ctx);
+ }
+ debug_message("%d/%d correct\n", score, found);
+ assert_int_equal(score, found);
+}
+
+
+/*
+ * attempt_round_trip() tests whether a data blob can survive a compression
+ * and decompression cycle. If save_name is not NULL and LZXHUFF_DEBUG_FILES
+ * evals to true, the various stages are saved in files with that name and the
+ * '-original', '-compressed', and '-decompressed' suffixes. If ref_compressed
+ * has data, it'll print a message saying whether the compressed data matches
+ * that.
+ */
+
+static ssize_t attempt_round_trip(TALLOC_CTX *mem_ctx,
+ DATA_BLOB original,
+ const char *save_name,
+ DATA_BLOB ref_compressed)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ DATA_BLOB compressed = data_blob_talloc(tmp_ctx, NULL,
+ original.length * 4 / 3 + 260);
+ DATA_BLOB decompressed = data_blob_talloc(tmp_ctx, NULL,
+ original.length);
+ ssize_t comp_written, decomp_written;
+ debug_start_timer();
+ comp_written = lzxpress_huffman_compress_talloc(tmp_ctx,
+ original.data,
+ original.length,
+ &compressed.data);
+ debug_end_timer("compress", original.length);
+ if (comp_written <= 0) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ if (ref_compressed.data != NULL) {
+ /*
+ * This is informational, not an assertion; there are
+ * ~infinite legitimate ways to compress the data, many as
+ * good as each other (think of compression as a language, not
+ * a format).
+ */
+ debug_message("compressed size %zd vs reference %zu\n",
+ comp_written, ref_compressed.length);
+
+ if (comp_written == compressed.length &&
+ memcmp(compressed.data, ref_compressed.data, comp_written) == 0) {
+ debug_message("\033[1;32mbyte identical!\033[0m\n");
+ }
+ }
+ debug_start_timer();
+ decomp_written = lzxpress_huffman_decompress(compressed.data,
+ comp_written,
+ decompressed.data,
+ original.length);
+ debug_end_timer("decompress", original.length);
+ if (save_name != NULL && LZXHUFF_DEBUG_FILES) {
+ char s[300];
+ FILE *fh = NULL;
+
+ snprintf(s, sizeof(s), "%s-original", save_name);
+ fprintf(stderr, "Saving %zu bytes to %s\n", original.length, s);
+ fh = fopen(s, "w");
+ fwrite(original.data, 1, original.length, fh);
+ fclose(fh);
+
+ snprintf(s, sizeof(s), "%s-compressed", save_name);
+ fprintf(stderr, "Saving %zu bytes to %s\n", comp_written, s);
+ fh = fopen(s, "w");
+ fwrite(compressed.data, 1, comp_written, fh);
+ fclose(fh);
+ /*
+ * We save the decompressed file using original.length, not
+ * the returned size. If these differ, the returned size will
+ * be -1. By saving the whole buffer we can see at what point
+ * it went haywire.
+ */
+ snprintf(s, sizeof(s), "%s-decompressed", save_name);
+ fprintf(stderr, "Saving %zu bytes to %s\n", original.length, s);
+ fh = fopen(s, "w");
+ fwrite(decompressed.data, 1, original.length, fh);
+ fclose(fh);
+ }
+
+ if (original.length != decomp_written ||
+ memcmp(decompressed.data,
+ original.data,
+ original.length) != 0) {
+ debug_message("\033[1;31mgot %zd, expected %zu\033[0m\n",
+ decomp_written,
+ original.length);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ talloc_free(tmp_ctx);
+ return comp_written;
+}
+
+
+static void test_lzxpress_huffman_round_trip(void **state)
+{
+ size_t i;
+ int score = 0;
+ ssize_t compressed_total = 0;
+ ssize_t reference_total = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; file_names[i] != NULL; i++) {
+ char filename[200];
+ char *debug_files = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ ssize_t comp_size;
+ struct lzx_pair p = {
+ .name = file_names[i]
+ };
+ debug_message("-------------------\n");
+ debug_message("%s\n", p.name);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.decomp", DECOMP_DIR, p.name);
+
+ p.decompressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.decompressed.data);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.lzhuff", COMP_DIR, p.name);
+
+ p.compressed = datablob_from_file(tmp_ctx, filename);
+ if (p.compressed.data == NULL) {
+ debug_message(
+ "Could not load %s reference file %s\n",
+ p.name, filename);
+ debug_message("%s decompressed %zu\n", p.name,
+ p.decompressed.length);
+ } else {
+ debug_message("%s: reference compressed %zu decomp %zu\n",
+ p.name,
+ p.compressed.length,
+ p.decompressed.length);
+ }
+ if (1) {
+ /*
+ * We're going to save copies in /tmp.
+ */
+ snprintf(filename, sizeof(filename),
+ "/tmp/lzxhuffman-%s", p.name);
+ debug_files = filename;
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, p.decompressed,
+ debug_files,
+ p.compressed);
+ if (comp_size > 0) {
+ debug_message("\033[1;32mround trip!\033[0m\n");
+ score++;
+ if (p.compressed.length) {
+ compressed_total += comp_size;
+ reference_total += p.compressed.length;
+ }
+ }
+ talloc_free(tmp_ctx);
+ }
+ debug_message("%d/%zu correct\n", score, i);
+ print_message("\033[1;34mtotal compressed size: %zu\033[0m\n",
+ compressed_total);
+ print_message("total reference size: %zd \n", reference_total);
+ print_message("diff: %7zd \n",
+ reference_total - compressed_total);
+ assert_true(reference_total != 0);
+ print_message("ratio: \033[1;3%dm%.2f\033[0m \n",
+ 2 + (compressed_total >= reference_total),
+ ((double)compressed_total) / reference_total);
+ /*
+ * Assert that the compression is *about* as good as Windows. Of course
+ * it doesn't matter if we do better, but mysteriously getting better
+ * is usually a sign that something is wrong.
+ *
+ * At the time of writing, compressed_total is 2674004, or 10686 more
+ * than the Windows reference total. That's < 0.5% difference, we're
+ * asserting at 2%.
+ */
+ assert_true(labs(compressed_total - reference_total) <
+ compressed_total / 50);
+
+ assert_int_equal(score, i);
+ talloc_free(mem_ctx);
+}
+
+/*
+ * Bob Jenkins' Small Fast RNG.
+ *
+ * We don't need it to be this good, but we do need it to be reproduceable
+ * across platforms, which rand() etc aren't.
+ *
+ * http://burtleburtle.net/bob/rand/smallprng.html
+ */
+
+struct jsf_rng {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+};
+
+#define ROTATE32(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+static uint32_t jsf32(struct jsf_rng *x) {
+ uint32_t e = x->a - ROTATE32(x->b, 27);
+ x->a = x->b ^ ROTATE32(x->c, 17);
+ x->b = x->c + x->d;
+ x->c = x->d + e;
+ x->d = e + x->a;
+ return x->d;
+}
+
+static void jsf32_init(struct jsf_rng *x, uint32_t seed) {
+ size_t i;
+ x->a = 0xf1ea5eed;
+ x->b = x->c = x->d = seed;
+ for (i = 0; i < 20; ++i) {
+ jsf32(x);
+ }
+}
+
+
+static void test_lzxpress_huffman_long_gpl_round_trip(void **state)
+{
+ /*
+ * We use a kind of model-free Markov model to generate a massively
+ * extended pastiche of the GPLv3 (chosen because it is right there in
+ * "COPYING" and won't change often).
+ *
+ * The point is to check a round trip of a very long message with
+ * multiple repetitions on many scales, without having to add a very
+ * large file.
+ */
+ size_t i, j, k;
+ uint8_t c;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB gpl = datablob_from_file(mem_ctx, "COPYING");
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+ if (gpl.data == NULL) {
+ print_message("could not read COPYING\n");
+ fail();
+ }
+
+ jsf32_init(&rng, 1);
+
+ j = 1;
+ original.data[0] = gpl.data[0];
+ for (i = 1; i < original.length; i++) {
+ size_t m;
+ char p = original.data[i - 1];
+ c = gpl.data[j];
+ original.data[i] = c;
+ j++;
+ m = (j + jsf32(&rng)) % (gpl.length - 50);
+ for (k = m; k < m + 30; k++) {
+ if (p == gpl.data[k] &&
+ c == gpl.data[k + 1]) {
+ j = k + 2;
+ break;
+ }
+ }
+ if (j == gpl.length) {
+ j = 1;
+ }
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/gpl", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_long_random_graph_round_trip(void **state)
+{
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ /*
+ * There's a random trigram graph, with each pair of sequential bytes
+ * pointing to a successor. This would probably fall into a fairly
+ * simple loop, but we introduce damage into the system, randomly
+ * flipping about 1 bit in 64.
+ *
+ * The result is semi-structured and compressible.
+ */
+ uint8_t *d = original.data;
+ uint8_t *table = talloc_array(mem_ctx, uint8_t, 65536);
+ uint32_t *table32 = (void*)table;
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+ jsf32_init(&rng, 1);
+ for (i = 0; i < (65536 / 4); i++) {
+ table32[i] = jsf32(&rng);
+ }
+
+ d[0] = 'a';
+ d[1] = 'b';
+
+ for (i = 2; i < original.length; i++) {
+ uint16_t k = (d[i - 2] << 8) | d[i - 1];
+ uint32_t damage = jsf32(&rng) & jsf32(&rng) & jsf32(&rng);
+ damage &= (damage >> 16);
+ k ^= damage & 0xffff;
+ d[i] = table[k];
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/random-graph", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_chaos_graph_round_trip(void **state)
+{
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ /*
+ * There's a random trigram graph, with each pair of sequential bytes
+ * pointing to a successor. This would probably fall into a fairly
+ * simple loop, but we keep changing the graph. The result is long
+ * periods of stability separatd by bursts of noise.
+ */
+ uint8_t *d = original.data;
+ uint8_t *table = talloc_array(mem_ctx, uint8_t, 65536);
+ uint32_t *table32 = (void*)table;
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+ jsf32_init(&rng, 1);
+ for (i = 0; i < (65536 / 4); i++) {
+ table32[i] = jsf32(&rng);
+ }
+
+ d[0] = 'a';
+ d[1] = 'b';
+
+ for (i = 2; i < original.length; i++) {
+ uint16_t k = (d[i - 2] << 8) | d[i - 1];
+ uint32_t damage = jsf32(&rng);
+ d[i] = table[k];
+ if ((damage >> 29) == 0) {
+ uint16_t index = damage & 0xffff;
+ uint8_t value = (damage >> 16) & 0xff;
+ table[index] = value;
+ }
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/chaos-graph", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_sparse_random_graph_round_trip(void **state)
+{
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ /*
+ * There's a random trigram graph, with each pair of sequential bytes
+ * pointing to a successor. This will fall into a fairly simple loops,
+ * but we introduce damage into the system, randomly mangling about 1
+ * byte in 65536.
+ *
+ * The result has very long repetitive runs, which should lead to
+ * oversized blocks.
+ */
+ uint8_t *d = original.data;
+ uint8_t *table = talloc_array(mem_ctx, uint8_t, 65536);
+ uint32_t *table32 = (void*)table;
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+ jsf32_init(&rng, 3);
+ for (i = 0; i < (65536 / 4); i++) {
+ table32[i] = jsf32(&rng);
+ }
+
+ d[0] = 'a';
+ d[1] = 'b';
+
+ for (i = 2; i < original.length; i++) {
+ uint16_t k = (d[i - 2] << 8) | d[i - 1];
+ uint32_t damage = jsf32(&rng);
+ if ((damage & 0xffff0000) == 0) {
+ k ^= damage & 0xffff;
+ }
+ d[i] = table[k];
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/sparse-random-graph", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_random_noise_round_trip(void **state)
+{
+ size_t i;
+ size_t len = 1024 * 1024;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, len);
+ DATA_BLOB ref = {0};
+ ssize_t comp_size;
+ /*
+ * We are filling this up with incompressible noise, but we can assert
+ * quite tight bounds on how badly it will fail to compress.
+ *
+ * Specifically, with randomly distributed codes, the Huffman table
+ * should come out as roughly even, averaging 8 bit codes. Then there
+ * will be a 256 byte table every 64k, which is a 1/256 overhead (i.e.
+ * the compressed length will be 257/256 the original *on average*).
+ * We assert it is less than 1 in 200 but more than 1 in 300.
+ */
+ uint32_t *d32 = (uint32_t*)((void*)original.data);
+ struct jsf_rng rng;
+ jsf32_init(&rng, 2);
+
+ for (i = 0; i < (len / 4); i++) {
+ d32[i] = jsf32(&rng);
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/random-noise", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size > original.length + original.length / 300);
+ assert_true(comp_size < original.length + original.length / 200);
+ debug_message("original size %zu; compressed size %zd; ratio %.3f\n",
+ len, comp_size, ((double)comp_size) / len);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_overlong_matches(void **state)
+{
+ size_t i, j = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 1024 * 1024);
+ DATA_BLOB ref = {0};
+ uint8_t *d = original.data;
+ char filename[300];
+ /*
+ * We are testing with something like "aaaaaaaaaaaaaaaaaaaaaaabbbbb"
+ * where typically the number of "a"s is > 65536, and the number of
+ * "b"s is < 42.
+ */
+ ssize_t na[] = {65535, 65536, 65537, 65559, 65575, 200000, -1};
+ ssize_t nb[] = {1, 2, 20, 39, 40, 41, 42, -1};
+ int score = 0;
+ ssize_t comp_size;
+
+ for (i = 0; na[i] >= 0; i++) {
+ ssize_t a = na[i];
+ memset(d, 'a', a);
+ for (j = 0; nb[j] >= 0; j++) {
+ ssize_t b = nb[j];
+ memset(d + a, 'b', b);
+ original.length = a + b;
+ snprintf(filename, sizeof(filename),
+ "/tmp/overlong-%zd-%zd", a, b);
+ comp_size = attempt_round_trip(mem_ctx,
+ original,
+ filename, ref);
+ if (comp_size > 0) {
+ score++;
+ }
+ }
+ }
+ debug_message("%d/%zu correct\n", score, i * j);
+ assert_int_equal(score, i * j);
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_overlong_matches_abc(void **state)
+{
+ size_t i, j = 0, k = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 1024 * 1024);
+ DATA_BLOB ref = {0};
+ uint8_t *d = original.data;
+ char filename[300];
+ /*
+ * We are testing with something like "aaaabbbbcc" where typically
+ * the number of "a"s + "b"s is around 65536, and the number of "c"s
+ * is < 43.
+ */
+ ssize_t nab[] = {1, 21, 32767, 32768, 32769, -1};
+ ssize_t nc[] = {1, 2, 20, 39, 40, 41, 42, -1};
+ int score = 0;
+ ssize_t comp_size;
+
+ for (i = 0; nab[i] >= 0; i++) {
+ ssize_t a = nab[i];
+ memset(d, 'a', a);
+ for (j = 0; nab[j] >= 0; j++) {
+ ssize_t b = nab[j];
+ memset(d + a, 'b', b);
+ for (k = 0; nc[k] >= 0; k++) {
+ ssize_t c = nc[k];
+ memset(d + a + b, 'c', c);
+ original.length = a + b + c;
+ snprintf(filename, sizeof(filename),
+ "/tmp/overlong-abc-%zd-%zd-%zd",
+ a, b, c);
+ comp_size = attempt_round_trip(mem_ctx,
+ original,
+ filename, ref);
+ if (comp_size > 0) {
+ score++;
+ }
+ }
+ }
+ }
+ debug_message("%d/%zu correct\n", score, i * j * k);
+ assert_int_equal(score, i * j * k);
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_extremely_compressible_middle(void **state)
+{
+ size_t len = 192 * 1024;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, len);
+ DATA_BLOB ref = {0};
+ ssize_t comp_size;
+ /*
+ * When a middle block (i.e. not the first and not the last of >= 3),
+ * can be entirely expressed as a match starting in the previous
+ * block, the Huffman tree would end up with 1 element, which does not
+ * work for the code construction. It really wants to use both bits.
+ * So we need to ensure we have some way of dealing with this.
+ */
+ memset(original.data, 'a', 0x10000 - 1);
+ memset(original.data + 0x10000 - 1, 'b', 0x10000 + 1);
+ memset(original.data + 0x20000, 'a', 0x10000);
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/compressible-middle", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < 1024);
+ debug_message("original size %zu; compressed size %zd; ratio %.3f\n",
+ len, comp_size, ((double)comp_size) / len);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_max_length_limit(void **state)
+{
+ size_t len = 65 * 1024 * 1024;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc_zero(mem_ctx, len);
+ DATA_BLOB ref = {0};
+ ssize_t comp_size;
+ /*
+ * Reputedly Windows has a 64MB limit in the maximum match length it
+ * will encode. We follow this, and test that here with nearly 65 MB
+ * of zeros between two letters; this should be encoded in three
+ * blocks:
+ *
+ * 1. 'a', 64M × '\0'
+ * 2. (1M - 2) × '\0' -- finishing off what would have been the same match
+ * 3. 'b' EOF
+ *
+ * Which we can assert by saying the length is > 768, < 1024.
+ */
+ original.data[0] = 'a';
+ original.data[len - 1] = 'b';
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/max-length-limit", ref);
+ assert_true(comp_size > 0x300);
+ assert_true(comp_size < 0x400);
+ debug_message("original size %zu; compressed size %zd; ratio %.3f\n",
+ len, comp_size, ((double)comp_size) / len);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_short_boring_strings(void **state)
+{
+ size_t len = 64 * 1024;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, len);
+ DATA_BLOB ref = {0};
+ ssize_t comp_size;
+ ssize_t lengths[] = {
+ 1, 2, 20, 39, 40, 41, 42, 256, 270, 273, 274, 1000, 64000, -1};
+ char filename[300];
+ size_t i;
+ /*
+ * How do short repetitive strings work? We're poking at the limit
+ * around which LZ77 comprssion is turned on.
+ *
+ * For this test we don't change the blob memory between runs, just
+ * the declared length.
+ */
+ memset(original.data, 'a', len);
+ for (i = 0; lengths[i] >= 0; i++) {
+ original.length = lengths[i];
+ snprintf(filename, sizeof(filename),
+ "/tmp/short-boring-%zu",
+ original.length);
+ comp_size = attempt_round_trip(mem_ctx, original, filename, ref);
+ if (original.length < 41) {
+ assert_true(comp_size > 256 + original.length / 8);
+ } else if (original.length < 274) {
+ assert_true(comp_size == 261);
+ } else {
+ assert_true(comp_size == 263);
+ }
+ assert_true(comp_size < 261 + original.length / 8);
+ }
+ /* let's just show we didn't change the original */
+ for (i = 0; i < len; i++) {
+ if (original.data[i] != 'a') {
+ fail_msg("input data[%zu] was changed! (%2x, expected %2x)\n",
+ i, original.data[i], 'a');
+ }
+ }
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_huffman_compress_empty_or_null(void **state)
+{
+ /*
+ * We expect these to fail with a -1, except the last one, which does
+ * the real thing.
+ */
+ ssize_t ret;
+ const uint8_t *input = bidirectional_pairs[0].decompressed.data;
+ size_t ilen = bidirectional_pairs[0].decompressed.length;
+ size_t olen = bidirectional_pairs[0].compressed.length;
+ uint8_t output[olen];
+ struct lzxhuff_compressor_mem cmp_mem;
+
+ ret = lzxpress_huffman_compress(&cmp_mem, input, 0, output, olen);
+ assert_int_equal(ret, -1LL);
+ ret = lzxpress_huffman_compress(&cmp_mem, input, ilen, output, 0);
+ assert_int_equal(ret, -1LL);
+
+ ret = lzxpress_huffman_compress(&cmp_mem, NULL, ilen, output, olen);
+ assert_int_equal(ret, -1LL);
+ ret = lzxpress_huffman_compress(&cmp_mem, input, ilen, NULL, olen);
+ assert_int_equal(ret, -1LL);
+ ret = lzxpress_huffman_compress(NULL, input, ilen, output, olen);
+ assert_int_equal(ret, -1LL);
+
+ ret = lzxpress_huffman_compress(&cmp_mem, input, ilen, output, olen);
+ assert_int_equal(ret, olen);
+}
+
+
+static void test_lzxpress_huffman_decompress_empty_or_null(void **state)
+{
+ /*
+ * We expect these to fail with a -1, except the last one.
+ */
+ ssize_t ret;
+ const uint8_t *input = bidirectional_pairs[0].compressed.data;
+ size_t ilen = bidirectional_pairs[0].compressed.length;
+ size_t olen = bidirectional_pairs[0].decompressed.length;
+ uint8_t output[olen];
+
+ ret = lzxpress_huffman_decompress(input, 0, output, olen);
+ assert_int_equal(ret, -1LL);
+ ret = lzxpress_huffman_decompress(input, ilen, output, 0);
+ assert_int_equal(ret, -1LL);
+
+ ret = lzxpress_huffman_decompress(NULL, ilen, output, olen);
+ assert_int_equal(ret, -1LL);
+ ret = lzxpress_huffman_decompress(input, ilen, NULL, olen);
+ assert_int_equal(ret, -1LL);
+
+ ret = lzxpress_huffman_decompress(input, ilen, output, olen);
+ assert_int_equal(ret, olen);
+}
+
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_lzxpress_huffman_short_boring_strings),
+ cmocka_unit_test(test_lzxpress_huffman_max_length_limit),
+ cmocka_unit_test(test_lzxpress_huffman_extremely_compressible_middle),
+ cmocka_unit_test(test_lzxpress_huffman_long_random_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_huffman_chaos_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_huffman_sparse_random_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_huffman_round_trip),
+ cmocka_unit_test(test_lzxpress_huffman_decompress_files),
+ cmocka_unit_test(test_lzxpress_huffman_decompress_more_compressed_files),
+ cmocka_unit_test(test_lzxpress_huffman_compress),
+ cmocka_unit_test(test_lzxpress_huffman_decompress),
+ cmocka_unit_test(test_lzxpress_huffman_long_gpl_round_trip),
+ cmocka_unit_test(test_lzxpress_huffman_long_random_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_huffman_random_noise_round_trip),
+ cmocka_unit_test(test_lzxpress_huffman_overlong_matches_abc),
+ cmocka_unit_test(test_lzxpress_huffman_overlong_matches),
+ cmocka_unit_test(test_lzxpress_huffman_decompress_empty_or_null),
+ cmocka_unit_test(test_lzxpress_huffman_compress_empty_or_null),
+ };
+ if (!isatty(1)) {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/compression/tests/test_lzxpress_plain.c b/lib/compression/tests/test_lzxpress_plain.c
new file mode 100644
index 0000000..1c14793
--- /dev/null
+++ b/lib/compression/tests/test_lzxpress_plain.c
@@ -0,0 +1,1194 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for the compression functions
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+#include <cmocka.h>
+#include "includes.h"
+#include "talloc.h"
+#include "lzxpress.h"
+#include "lib/util/base64.h"
+
+
+/* set LZX_DEBUG_FILES to true to save round-trip files in /tmp. */
+#define LZX_DEBUG_FILES false
+
+/* set LZX_DEBUG_VERBOSE to true to print more. */
+#define LZX_DEBUG_VERBOSE false
+
+
+#if LZX_DEBUG_VERBOSE
+#define debug_message(...) print_message(__VA_ARGS__)
+
+#include <time.h>
+
+struct timespec start = {0};
+struct timespec end = {0};
+static void debug_start_timer(void)
+{
+ clock_gettime(CLOCK_MONOTONIC, &start);
+}
+
+static void debug_end_timer(const char *name, size_t len)
+{
+ uint64_t ns;
+ double secs;
+ double rate;
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ ns = end.tv_nsec;
+ ns += end.tv_sec * 1000 * 1000 * 1000;
+ ns -= start.tv_nsec;
+ ns -= start.tv_sec * 1000 * 1000 * 1000;
+ secs = ns / 1e9;
+ rate = len / (secs * 1024 * 1024);
+ debug_message("%s %zu bytes in %.2g: \033[1;35m%.2f\033[0m MB per second\n",
+ name, len, secs, rate);
+}
+
+#else
+#define debug_message(...) /* debug_message */
+#define debug_start_timer(...) /* debug_start_timer */
+#define debug_end_timer(...) /* debug_end_timer */
+#endif
+
+
+struct lzx_pair {
+ const char *name;
+ DATA_BLOB compressed;
+ DATA_BLOB decompressed;
+};
+
+struct lzx_file_pair {
+ const char *name;
+ const char *compressed_file;
+ const char *decompressed_file;
+};
+
+
+#define DECOMP_DIR "testdata/compression/decompressed"
+#define COMP_DIR "testdata/compression/compressed-plain"
+#define MORE_COMP_DIR "testdata/compression/compressed-more-plain"
+
+
+#define BLOB_FROM_ARRAY(...) \
+ { \
+ .data = (uint8_t[]){__VA_ARGS__}, \
+ .length = sizeof((uint8_t[]){__VA_ARGS__}) \
+ }
+
+#define BLOB_FROM_STRING(s) \
+ { \
+ .data = discard_const_p(uint8_t, s), \
+ .length = (sizeof(s) - 1) \
+ }
+
+
+const char * file_names[] = {
+ "generate-windows-test-vectors.c",
+ "fib_shuffle-128k+",
+ "fuzzing-0fc2d461b56cd8103c91",
+ "fuzzing-3ec3bca27bb9eb40c128",
+ "fuzzing-a3115a81d1ac500318f9",
+ "fuzzing-3591f9dc02bb00a54b60",
+ "27826-8.txt",
+ "5d049b4cb1bd933f5e8ex19",
+ "638e61e96d54279981c3x5",
+ "64k-minus-one-zeros",
+ "64k-plus-one-zeros",
+ "64k-zeros",
+ "96f696a4e5ce56c61a3dx10",
+ "9e0b6a12febf38e98f13",
+ "abc-times-101",
+ "abc-times-105",
+ "abc-times-200",
+ "b63289ccc7f218c0d56b",
+ "beta-variate1-128k+",
+ "beta-variate3-128k+",
+ "decayed_alphabet_128k+",
+ "decayed_alphabet_64k",
+ "f00842317dc6d5695b02",
+ "fib_shuffle",
+ "midsummer-nights-dream.txt",
+ "notes-on-the-underground.txt",
+ "pg22009.txt",
+ "repeating",
+ "repeating-exactly-64k",
+ "setup.log",
+ "slow-015ddc36a71412ccc50d",
+ "slow-100e9f966a7feb9ca40a",
+ "slow-2a671c3cff4f1574cbab",
+ "slow-33d90a24e70515b14cd0",
+ "slow-49d8c05261e3f412fc72",
+ "slow-50a249d2fe56873e56a0",
+ "slow-63e9f0b52235fb0129fa",
+ "slow-73b7f971d65908ac0095",
+ "slow-8b61e3dd267908544531",
+ "slow-9d1c5a079b0462986f1f",
+ "slow-aa7262a821dabdcf04a6",
+ "slow-b8a91d142b0d2af7f5ca",
+ "slow-c79142457734bbc8d575",
+ "slow-d736544545b90d83fe75",
+ "slow-e3b9bdfaed7d1a606fdb",
+ "slow-f3f1c02a9d006e5e1703",
+ "trigram_128k+",
+ "trigram_64k",
+ "trigram_sum_128k+",
+ "trigram_sum_64k",
+ NULL
+};
+
+
+
+static DATA_BLOB datablob_from_file(TALLOC_CTX *mem_ctx,
+ const char *filename)
+{
+ DATA_BLOB b = {0};
+ FILE *fh = fopen(filename, "rb");
+ int ret;
+ struct stat s;
+ size_t len;
+ if (fh == NULL) {
+ debug_message("could not open '%s'\n", filename);
+ return b;
+ }
+ ret = fstat(fileno(fh), &s);
+ if (ret != 0) {
+ fclose(fh);
+ return b;
+ }
+ b.data = talloc_array(mem_ctx, uint8_t, s.st_size);
+ if (b.data == NULL) {
+ fclose(fh);
+ return b;
+ }
+ len = fread(b.data, 1, s.st_size, fh);
+ if (ferror(fh) || len != s.st_size) {
+ TALLOC_FREE(b.data);
+ } else {
+ b.length = len;
+ }
+ fclose(fh);
+ return b;
+}
+
+
+
+static void test_lzxpress_plain_decompress_files(void **state)
+{
+ size_t i;
+ int score = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; file_names[i] != NULL; i++) {
+ char filename[200];
+ uint8_t *dest = NULL;
+ ssize_t written;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct lzx_pair p = {
+ .name = file_names[i]
+ };
+
+ debug_message("%s\n", p.name);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.decomp", DECOMP_DIR, p.name);
+
+ p.decompressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.decompressed.data);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.lzplain", COMP_DIR, p.name);
+
+ p.compressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.compressed.data);
+
+ dest = talloc_array(tmp_ctx, uint8_t, p.decompressed.length);
+ debug_start_timer();
+ written = lzxpress_decompress(p.compressed.data,
+ p.compressed.length,
+ dest,
+ p.decompressed.length);
+ debug_end_timer("decompress", p.decompressed.length);
+ if (written == p.decompressed.length &&
+ memcmp(dest, p.decompressed.data, p.decompressed.length) == 0) {
+ debug_message("\033[1;32mdecompressed %s!\033[0m\n", p.name);
+ score++;
+ } else {
+ debug_message("\033[1;31mfailed to decompress %s!\033[0m\n",
+ p.name);
+ debug_message("size %zd vs reference %zu\n",
+ written, p.decompressed.length);
+ }
+ talloc_free(tmp_ctx);
+ }
+ debug_message("%d/%zu correct\n", score, i);
+ assert_int_equal(score, i);
+}
+
+
+static void test_lzxpress_plain_decompress_more_compressed_files(void **state)
+{
+ /*
+ * This tests the decompression of files that have been compressed on
+ * Windows with the level turned up (to 1, default for MS-XCA is 0).
+ *
+ * The format is identical, but it will have tried harder to find
+ * matches.
+ */
+ size_t i;
+ int score = 0;
+ int found = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; file_names[i] != NULL; i++) {
+ char filename[200];
+ uint8_t *dest = NULL;
+ ssize_t written;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct lzx_pair p = {
+ .name = file_names[i]
+ };
+
+ debug_message("%s\n", p.name);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.decomp", DECOMP_DIR, p.name);
+
+ p.decompressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.decompressed.data);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.lzplain", MORE_COMP_DIR, p.name);
+
+ p.compressed = datablob_from_file(tmp_ctx, filename);
+ if (p.compressed.data == NULL) {
+ /*
+ * We don't have all the vectors in the
+ * more-compressed directory, which is OK, we skip
+ * them.
+ */
+ continue;
+ }
+ found++;
+ dest = talloc_array(tmp_ctx, uint8_t, p.decompressed.length);
+ debug_start_timer();
+ written = lzxpress_decompress(p.compressed.data,
+ p.compressed.length,
+ dest,
+ p.decompressed.length);
+ debug_end_timer("decompress", p.decompressed.length);
+ if (written != -1 &&
+ written == p.decompressed.length &&
+ memcmp(dest, p.decompressed.data, p.decompressed.length) == 0) {
+ debug_message("\033[1;32mdecompressed %s!\033[0m\n", p.name);
+ score++;
+ } else {
+ debug_message("\033[1;31mfailed to decompress %s!\033[0m\n",
+ p.name);
+ debug_message("size %zd vs reference %zu\n",
+ written, p.decompressed.length);
+ }
+ talloc_free(tmp_ctx);
+ }
+ debug_message("%d/%d correct\n", score, found);
+ assert_int_equal(score, found);
+}
+
+
+/*
+ * attempt_round_trip() tests whether a data blob can survive a compression
+ * and decompression cycle. If save_name is not NULL and LZX_DEBUG_FILES
+ * evals to true, the various stages are saved in files with that name and the
+ * '-original', '-compressed', and '-decompressed' suffixes. If ref_compressed
+ * has data, it'll print a message saying whether the compressed data matches
+ * that.
+ */
+
+static ssize_t attempt_round_trip(TALLOC_CTX *mem_ctx,
+ DATA_BLOB original,
+ const char *save_name,
+ DATA_BLOB ref_compressed)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ DATA_BLOB compressed = data_blob_talloc(tmp_ctx, NULL,
+ original.length * 8 / 7 + 8);
+ DATA_BLOB decompressed = data_blob_talloc(tmp_ctx, NULL,
+ original.length);
+ ssize_t comp_written, decomp_written;
+ debug_start_timer();
+ comp_written = lzxpress_compress(original.data,
+ original.length,
+ compressed.data,
+ compressed.length);
+ debug_end_timer("compress", original.length);
+ if (comp_written <= 0) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ if (ref_compressed.data != NULL) {
+ /*
+ * This is informational, not an assertion; there are
+ * ~infinite legitimate ways to compress the data, many as
+ * good as each other (think of compression as a language, not
+ * a format).
+ */
+ debug_message("compressed size %zd vs reference %zu\n",
+ comp_written, ref_compressed.length);
+
+ if (comp_written == compressed.length &&
+ memcmp(compressed.data, ref_compressed.data, comp_written) == 0) {
+ debug_message("\033[1;32mbyte identical!\033[0m\n");
+ }
+ }
+ debug_start_timer();
+ decomp_written = lzxpress_decompress(compressed.data,
+ comp_written,
+ decompressed.data,
+ decompressed.length);
+ debug_end_timer("decompress", original.length);
+ if (save_name != NULL && LZX_DEBUG_FILES) {
+ char s[300];
+ FILE *fh = NULL;
+
+ snprintf(s, sizeof(s), "%s-original", save_name);
+ fprintf(stderr, "Saving %zu bytes to %s\n", original.length, s);
+ fh = fopen(s, "w");
+ fwrite(original.data, 1, original.length, fh);
+ fclose(fh);
+
+ snprintf(s, sizeof(s), "%s-compressed", save_name);
+ fprintf(stderr, "Saving %zu bytes to %s\n", comp_written, s);
+ fh = fopen(s, "w");
+ fwrite(compressed.data, 1, comp_written, fh);
+ fclose(fh);
+ /*
+ * We save the decompressed file using original.length, not
+ * the returned size. If these differ, the returned size will
+ * be -1. By saving the whole buffer we can see at what point
+ * it went haywire.
+ */
+ snprintf(s, sizeof(s), "%s-decompressed", save_name);
+ fprintf(stderr, "Saving %zu bytes to %s\n", original.length, s);
+ fh = fopen(s, "w");
+ fwrite(decompressed.data, 1, original.length, fh);
+ fclose(fh);
+ }
+
+ if (original.length != decomp_written ||
+ memcmp(decompressed.data,
+ original.data,
+ original.length) != 0) {
+ debug_message("\033[1;31mgot %zd, expected %zu\033[0m\n",
+ decomp_written,
+ original.length);
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ talloc_free(tmp_ctx);
+ return comp_written;
+}
+
+
+static void test_lzxpress_plain_round_trip_files(void **state)
+{
+ size_t i;
+ int score = 0;
+ ssize_t compressed_total = 0;
+ ssize_t reference_total = 0;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ for (i = 0; file_names[i] != NULL; i++) {
+ char filename[200];
+ char *debug_files = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ ssize_t comp_size;
+ struct lzx_pair p = {
+ .name = file_names[i]
+ };
+ debug_message("-------------------\n");
+ debug_message("%s\n", p.name);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.decomp", DECOMP_DIR, p.name);
+
+ p.decompressed = datablob_from_file(tmp_ctx, filename);
+ assert_non_null(p.decompressed.data);
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s.lzplain", COMP_DIR, p.name);
+
+ p.compressed = datablob_from_file(tmp_ctx, filename);
+ if (p.compressed.data == NULL) {
+ debug_message(
+ "Could not load %s reference file %s\n",
+ p.name, filename);
+ debug_message("%s decompressed %zu\n", p.name,
+ p.decompressed.length);
+ } else {
+ debug_message("%s: reference compressed %zu decomp %zu\n",
+ p.name,
+ p.compressed.length,
+ p.decompressed.length);
+ }
+ if (1) {
+ /*
+ * We're going to save copies in /tmp.
+ */
+ snprintf(filename, sizeof(filename),
+ "/tmp/lzxplain-%s", p.name);
+ debug_files = filename;
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, p.decompressed,
+ debug_files,
+ p.compressed);
+ if (comp_size > 0) {
+ debug_message("\033[1;32mround trip!\033[0m\n");
+ score++;
+ if (p.compressed.length) {
+ compressed_total += comp_size;
+ reference_total += p.compressed.length;
+ }
+ }
+ talloc_free(tmp_ctx);
+ }
+ debug_message("%d/%zu correct\n", score, i);
+ print_message("\033[1;34mtotal compressed size: %zu\033[0m\n",
+ compressed_total);
+ print_message("total reference size: %zd \n", reference_total);
+ print_message("diff: %7zd \n",
+ reference_total - compressed_total);
+ assert_true(reference_total != 0);
+ print_message("ratio: \033[1;3%dm%.2f\033[0m \n",
+ 2 + (compressed_total >= reference_total),
+ ((double)compressed_total) / reference_total);
+ /*
+ * Assert that the compression is better than Windows. Unlike the
+ * Huffman variant, where things are very even, here we do much better
+ * than Windows without especially trying.
+ */
+ assert_true(compressed_total <= reference_total);
+
+ assert_int_equal(score, i);
+ talloc_free(mem_ctx);
+}
+
+
+/*
+ * Bob Jenkins' Small Fast RNG.
+ *
+ * We don't need it to be this good, but we do need it to be reproduceable
+ * across platforms, which rand() etc aren't.
+ *
+ * http://burtleburtle.net/bob/rand/smallprng.html
+ */
+
+struct jsf_rng {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+};
+
+#define ROTATE32(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+static uint32_t jsf32(struct jsf_rng *x) {
+ uint32_t e = x->a - ROTATE32(x->b, 27);
+ x->a = x->b ^ ROTATE32(x->c, 17);
+ x->b = x->c + x->d;
+ x->c = x->d + e;
+ x->d = e + x->a;
+ return x->d;
+}
+
+static void jsf32_init(struct jsf_rng *x, uint32_t seed) {
+ size_t i;
+ x->a = 0xf1ea5eed;
+ x->b = x->c = x->d = seed;
+ for (i = 0; i < 20; ++i) {
+ jsf32(x);
+ }
+}
+
+
+static void test_lzxpress_plain_long_gpl_round_trip(void **state)
+{
+ /*
+ * We use a kind of model-free Markov model to generate a massively
+ * extended pastiche of the GPLv3 (chosen because it is right there in
+ * "COPYING" and won't change often).
+ *
+ * The point is to check a round trip of a very long message with
+ * multiple repetitions on many scales, without having to add a very
+ * large file.
+ */
+ size_t i, j, k;
+ uint8_t c;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB gpl = datablob_from_file(mem_ctx, "COPYING");
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+
+ jsf32_init(&rng, 1);
+
+ j = 1;
+ original.data[0] = gpl.data[0];
+ for (i = 1; i < original.length; i++) {
+ size_t m;
+ char p = original.data[i - 1];
+ c = gpl.data[j];
+ original.data[i] = c;
+ j++;
+ m = (j + jsf32(&rng)) % (gpl.length - 50);
+ for (k = m; k < m + 30; k++) {
+ if (p == gpl.data[k] &&
+ c == gpl.data[k + 1]) {
+ j = k + 2;
+ break;
+ }
+ }
+ if (j == gpl.length) {
+ j = 1;
+ }
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/gpl", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_plain_long_random_graph_round_trip(void **state)
+{
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ /*
+ * There's a random trigram graph, with each pair of sequential bytes
+ * pointing to a successor. This would probably fall into a fairly
+ * simple loop, but we introduce damage into the system, randomly
+ * flipping about 1 bit in 64.
+ *
+ * The result is semi-structured and compressible.
+ */
+ uint8_t *d = original.data;
+ uint8_t *table = talloc_array(mem_ctx, uint8_t, 65536);
+ uint32_t *table32 = (void*)table;
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+ jsf32_init(&rng, 1);
+ for (i = 0; i < (65536 / 4); i++) {
+ table32[i] = jsf32(&rng);
+ }
+
+ d[0] = 'a';
+ d[1] = 'b';
+
+ for (i = 2; i < original.length; i++) {
+ uint16_t k = (d[i - 2] << 8) | d[i - 1];
+ uint32_t damage = jsf32(&rng) & jsf32(&rng) & jsf32(&rng);
+ damage &= (damage >> 16);
+ k ^= damage & 0xffff;
+ d[i] = table[k];
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/random-graph", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_plain_chaos_graph_round_trip(void **state)
+{
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ /*
+ * There's a random trigram graph, with each pair of sequential bytes
+ * pointing to a successor. This would probably fall into a fairly
+ * simple loop, but we keep changing the graph. The result is long
+ * periods of stability separatd by bursts of noise.
+ */
+ uint8_t *d = original.data;
+ uint8_t *table = talloc_array(mem_ctx, uint8_t, 65536);
+ uint32_t *table32 = (void*)table;
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+ jsf32_init(&rng, 1);
+ for (i = 0; i < (65536 / 4); i++) {
+ table32[i] = jsf32(&rng);
+ }
+
+ d[0] = 'a';
+ d[1] = 'b';
+
+ for (i = 2; i < original.length; i++) {
+ uint16_t k = (d[i - 2] << 8) | d[i - 1];
+ uint32_t damage = jsf32(&rng);
+ d[i] = table[k];
+ if ((damage >> 29) == 0) {
+ uint16_t index = damage & 0xffff;
+ uint8_t value = (damage >> 16) & 0xff;
+ table[index] = value;
+ }
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/chaos-graph", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_plain_sparse_random_graph_round_trip(void **state)
+{
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, 5 * 1024 * 1024);
+ DATA_BLOB ref = {0};
+ /*
+ * There's a random trigram graph, with each pair of sequential bytes
+ * pointing to a successor. This will fall into a fairly simple loops,
+ * but we introduce damage into the system, randomly mangling about 1
+ * byte in 65536.
+ *
+ * The result has very long repetitive runs, which should lead to
+ * oversized blocks.
+ */
+ uint8_t *d = original.data;
+ uint8_t *table = talloc_array(mem_ctx, uint8_t, 65536);
+ uint32_t *table32 = (void*)table;
+ ssize_t comp_size;
+ struct jsf_rng rng;
+
+ jsf32_init(&rng, 3);
+ for (i = 0; i < (65536 / 4); i++) {
+ table32[i] = jsf32(&rng);
+ }
+
+ d[0] = 'a';
+ d[1] = 'b';
+
+ for (i = 2; i < original.length; i++) {
+ uint16_t k = (d[i - 2] << 8) | d[i - 1];
+ uint32_t damage = jsf32(&rng);
+ if ((damage & 0xffff0000) == 0) {
+ k ^= damage & 0xffff;
+ }
+ d[i] = table[k];
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/sparse-random-graph", ref);
+ assert_true(comp_size > 0);
+ assert_true(comp_size < original.length);
+
+ talloc_free(mem_ctx);
+}
+
+
+static void test_lzxpress_plain_random_noise_round_trip(void **state)
+{
+ size_t i;
+ size_t len = 10 * 1024 * 1024;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DATA_BLOB original = data_blob_talloc(mem_ctx, NULL, len);
+ DATA_BLOB ref = {0};
+ ssize_t comp_size;
+ /*
+ * We are filling this up with incompressible noise, but we can assert
+ * quite tight bounds on how badly it will fail to compress.
+ *
+ * There is one additional bit for each code, which says whether the
+ * code is a literal byte or a match. If *all* codes are literal
+ * bytes, the length should be 9/8 the original (with rounding
+ * issues regarding the indicator bit blocks).
+ *
+ * If some matches are found the length will be a bit less. We would
+ * expect one 3 byte match per 1 << 24 tries, but we try 8192 times
+ * per position. That means there'll a match 1/2048 of the time at
+ * best. 255 times out of 256 this will be exactly a 3 byte match,
+ * encoded as two bytes, so we could get a 1 / 2048 saving on top of
+ * the 1/8 cost. There'll be a smattering of longer matches too, and
+ * the potential for complicated maths to account for those, but we'll
+ * skimp on that by allowing for a 1/1500 saving.
+ *
+ * With the hash table, we take a shortcut in the "8192 tries", and
+ * the size of the table makes a difference in how we perform, with 13
+ * bits (8192 slots) naturally being luckier than 12. Ultimately,
+ * either way, the compressed file is still 12.5% bigger than the
+ * original.
+ */
+ size_t limit = len * 9 / 8 + 4;
+
+ uint32_t *d32 = (uint32_t*)((void*)original.data);
+ struct jsf_rng rng;
+ jsf32_init(&rng, 2);
+
+ for (i = 0; i < (len / 4); i++) {
+ d32[i] = jsf32(&rng);
+ }
+
+ comp_size = attempt_round_trip(mem_ctx, original, "/tmp/random-noise", ref);
+ debug_message("original size %zu; compressed size %zd; ratio %.5f\n",
+ len, comp_size, ((double)comp_size) / len);
+ debug_message("expected range %zu - %zu\n",
+ limit - limit / 1500, limit);
+
+ assert_true(comp_size > 0);
+ assert_true(comp_size < limit);
+ assert_true(comp_size >= limit - limit / 1500);
+ talloc_free(mem_ctx);
+}
+
+
+/* Tests based on [MS-XCA] 3.1 Examples */
+static void test_msft_data1(void **state)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+ const char *fixed_data = "abcdefghijklmnopqrstuvwxyz";
+ const uint8_t fixed_out[] = {
+ 0x3f, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a };
+
+ ssize_t c_size;
+ uint8_t *out, *out2;
+
+ out = talloc_size(tmp_ctx, 2048);
+ memset(out, 0x42, talloc_get_size(out));
+
+ c_size = lzxpress_compress((const uint8_t *)fixed_data,
+ strlen(fixed_data),
+ out,
+ talloc_get_size(out));
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, sizeof(fixed_out));
+ assert_memory_equal(out, fixed_out, c_size);
+ out2 = talloc_size(tmp_ctx, strlen(fixed_data));
+ c_size = lzxpress_decompress(out,
+ sizeof(fixed_out),
+ out2,
+ talloc_get_size(out2));
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, strlen(fixed_data));
+ assert_memory_equal(out2, fixed_data, c_size);
+
+ talloc_free(tmp_ctx);
+}
+
+
+static void test_msft_data2(void **state)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+ const char *fixed_data =
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+ "abcabcabcabcabcabcabcabc";
+ const uint8_t fixed_out[] = {
+ 0xff, 0xff, 0xff, 0x1f, 0x61, 0x62, 0x63, 0x17,
+ 0x00, 0x0f, 0xff, 0x26, 0x01};
+
+ ssize_t c_size;
+ uint8_t *out, *out2;
+
+ out = talloc_size(tmp_ctx, 2048);
+ memset(out, 0x42, talloc_get_size(out));
+
+ c_size = lzxpress_compress((const uint8_t *)fixed_data,
+ strlen(fixed_data),
+ out,
+ talloc_get_size(out));
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, sizeof(fixed_out));
+ assert_memory_equal(out, fixed_out, c_size);
+
+ out2 = talloc_size(tmp_ctx, strlen(fixed_data));
+ c_size = lzxpress_decompress(out,
+ sizeof(fixed_out),
+ out2,
+ talloc_get_size(out2));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, strlen(fixed_data));
+ assert_memory_equal(out2, fixed_data, c_size);
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ test lzxpress
+ */
+static void test_lzxpress(void **state)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ const char *fixed_data = "this is a test. and this is a test too";
+ const uint8_t fixed_out[] = {
+ 0xff, 0x21, 0x00, 0x04, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x10, 0x00, 0x61, 0x20, 0x74, 0x65, 0x73,
+ 0x74, 0x2E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x9F,
+ 0x00, 0x04, 0x20, 0x74, 0x6F, 0x6F };
+
+ const uint8_t fixed_out_old_version[] = {
+ 0x00, 0x20, 0x00, 0x04, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x10, 0x00, 0x61, 0x20, 0x74, 0x65, 0x73,
+ 0x74, 0x2E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x9F,
+ 0x00, 0x04, 0x20, 0x74, 0x6F, 0x6F, 0x00, 0x00,
+ 0x00, 0x00 };
+
+ ssize_t c_size;
+ uint8_t *out, *out2, *out3;
+
+ out = talloc_size(tmp_ctx, 2048);
+ memset(out, 0x42, talloc_get_size(out));
+
+ c_size = lzxpress_compress((const uint8_t *)fixed_data,
+ strlen(fixed_data),
+ out,
+ talloc_get_size(out));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, sizeof(fixed_out));
+ assert_memory_equal(out, fixed_out, c_size);
+
+ out2 = talloc_size(tmp_ctx, strlen(fixed_data));
+ c_size = lzxpress_decompress(out,
+ sizeof(fixed_out),
+ out2,
+ talloc_get_size(out2));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, strlen(fixed_data));
+ assert_memory_equal(out2, fixed_data, c_size);
+
+ out3 = talloc_size(tmp_ctx, strlen(fixed_data));
+ c_size = lzxpress_decompress(fixed_out_old_version,
+ sizeof(fixed_out_old_version),
+ out3,
+ talloc_get_size(out3));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, strlen(fixed_data));
+ assert_memory_equal(out3, fixed_data, c_size);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_lzxpress2(void **state)
+{
+ /*
+ * Use two matches, separated by a literal, and each with a length
+ * greater than 10, to test the use of nibble_index. Both length values
+ * (less ten) should be stored as adjacent nibbles to form the 0x21
+ * byte.
+ */
+
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ const char *fixed_data = "aaaaaaaaaaaabaaaaaaaaaaaa";
+ const uint8_t fixed_out[] = {
+ 0xff, 0xff, 0xff, 0x5f, 0x61, 0x07, 0x00, 0x21,
+ 0x62, 0x67, 0x00};
+
+ ssize_t c_size;
+ uint8_t *out, *out2;
+
+ out = talloc_size(tmp_ctx, 2048);
+ memset(out, 0x42, talloc_get_size(out));
+
+ c_size = lzxpress_compress((const uint8_t *)fixed_data,
+ strlen(fixed_data),
+ out,
+ talloc_get_size(out));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, sizeof(fixed_out));
+ assert_memory_equal(out, fixed_out, c_size);
+
+ out2 = talloc_size(tmp_ctx, strlen(fixed_data));
+ c_size = lzxpress_decompress(out,
+ sizeof(fixed_out),
+ out2,
+ talloc_get_size(out2));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, strlen(fixed_data));
+ assert_memory_equal(out2, fixed_data, c_size);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_lzxpress3(void **state)
+{
+ /*
+ * Use a series of 31 literals, followed by a single minimum-length
+ * match (and a terminating literal), to test setting indic_pos when the
+ * 32-bit flags value overflows after a match.
+ */
+
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ const char *fixed_data = "abcdefghijklmnopqrstuvwxyz01234abca";
+ const uint8_t fixed_out[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31,
+ 0x32, 0x33, 0x34, 0xf0, 0x00, 0xff, 0xff, 0xff,
+ 0x7f, 0x61};
+
+ ssize_t c_size;
+ uint8_t *out, *out2;
+
+ out = talloc_size(tmp_ctx, 2048);
+ memset(out, 0x42, talloc_get_size(out));
+
+ c_size = lzxpress_compress((const uint8_t *)fixed_data,
+ strlen(fixed_data),
+ out,
+ talloc_get_size(out));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, sizeof(fixed_out));
+ assert_memory_equal(out, fixed_out, c_size);
+
+ out2 = talloc_size(tmp_ctx, strlen(fixed_data));
+ c_size = lzxpress_decompress(out,
+ sizeof(fixed_out),
+ out2,
+ talloc_get_size(out2));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, strlen(fixed_data));
+ assert_memory_equal(out2, fixed_data, c_size);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_lzxpress4(void **state)
+{
+ /*
+ * Use a series of 31 literals, followed by a single minimum-length
+ * match, to test that the final set of 32-bit flags is written
+ * correctly when it is empty.
+ */
+
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ const char *fixed_data = "abcdefghijklmnopqrstuvwxyz01234abc";
+ const uint8_t fixed_out[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31,
+ 0x32, 0x33, 0x34, 0xf0, 0x00, 0xff, 0xff, 0xff,
+ 0xff};
+
+ ssize_t c_size;
+ uint8_t *out, *out2;
+
+ out = talloc_size(tmp_ctx, 2048);
+ memset(out, 0x42, talloc_get_size(out));
+
+ c_size = lzxpress_compress((const uint8_t *)fixed_data,
+ strlen(fixed_data),
+ out,
+ talloc_get_size(out));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, sizeof(fixed_out));
+ assert_memory_equal(out, fixed_out, c_size);
+
+ out2 = talloc_size(tmp_ctx, strlen(fixed_data));
+ c_size = lzxpress_decompress(out,
+ sizeof(fixed_out),
+ out2,
+ talloc_get_size(out2));
+
+ assert_int_not_equal(c_size, -1);
+ assert_int_equal(c_size, strlen(fixed_data));
+ assert_memory_equal(out2, fixed_data, c_size);
+
+ talloc_free(tmp_ctx);
+}
+
+
+static void test_lzxpress_many_zeros(void **state)
+{
+ /*
+ * Repeated values (zero is convenient but not special) will lead to
+ * very long substring searches in compression, which can be very slow
+ * if we're not careful.
+ *
+ * This test makes a very loose assertion about how long it should
+ * take to compress a million zeros.
+ *
+ * Wall clock time *should* be < 0.1 seconds with the fix and around a
+ * minute without it. We try for CLOCK_THREAD_CPUTIME_ID which should
+ * filter out some noise on the machine, and set the threshold at 5
+ * seconds.
+ */
+
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ const size_t N_ZEROS = 1000000;
+ const uint8_t *zeros = talloc_zero_size(tmp_ctx, N_ZEROS);
+ const ssize_t expected_c_size_max = 120;
+ const ssize_t expected_c_size_min = 93;
+ ssize_t c_size;
+ uint8_t *comp, *decomp;
+ static struct timespec t_start, t_end;
+ uint64_t elapsed_ns;
+
+ if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_start) != 0) {
+ if (clock_gettime(CUSTOM_CLOCK_MONOTONIC, &t_start) != 0) {
+ clock_gettime(CLOCK_REALTIME, &t_start);
+ }
+ }
+
+ comp = talloc_zero_size(tmp_ctx, 2048);
+
+ c_size = lzxpress_compress(zeros,
+ N_ZEROS,
+ comp,
+ talloc_get_size(comp));
+ /*
+ * Because our compression depends on heuristics, we don't insist on
+ * an exact size in this case.
+ */
+
+ assert_true(c_size <= expected_c_size_max);
+ assert_true(c_size >= expected_c_size_min);
+
+ decomp = talloc_size(tmp_ctx, N_ZEROS * 2);
+ c_size = lzxpress_decompress(comp,
+ c_size,
+ decomp,
+ N_ZEROS * 2);
+
+ if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_end) != 0) {
+ if (clock_gettime(CUSTOM_CLOCK_MONOTONIC, &t_end) != 0) {
+ clock_gettime(CLOCK_REALTIME, &t_end);
+ }
+ }
+ elapsed_ns = (
+ (t_end.tv_sec - t_start.tv_sec) * 1000U * 1000U * 1000U) +
+ (t_end.tv_nsec - t_start.tv_nsec);
+ print_message("round-trip time: %"PRIu64" ns\n", elapsed_ns);
+ assert_true(elapsed_ns < 3 * 1000U * 1000U * 1000U);
+ assert_memory_equal(decomp, zeros, N_ZEROS);
+
+ talloc_free(tmp_ctx);
+}
+
+
+static void test_lzxpress_round_trip(void **state)
+{
+ /*
+ * Examples found using via fuzzing.
+ */
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ size_t i;
+ struct b64_pair {
+ const char *uncompressed;
+ const char *compressed;
+ } pairs[] = {
+ { /* this results in a trailing flags block */
+ "AAICAmq/EKdP785YU2Ddh7d4vUtdlQyLeHV09LHpUBw=",
+ "AAAAAAACAgJqvxCnT+/OWFNg3Ye3eL1LXZUMi3h1dPSx6VAc/////w==",
+ },
+ { /* empty string compresses to empty string */
+ "", ""
+ },
+ };
+ const size_t alloc_size = 1000;
+ uint8_t *data = talloc_array(tmp_ctx, uint8_t, alloc_size);
+
+ for (i = 0; i < ARRAY_SIZE(pairs); i++) {
+ ssize_t len;
+ DATA_BLOB uncomp = base64_decode_data_blob_talloc(
+ tmp_ctx,
+ pairs[i].uncompressed);
+ DATA_BLOB comp = base64_decode_data_blob_talloc(
+ tmp_ctx,
+ pairs[i].compressed);
+
+ len = lzxpress_compress(uncomp.data,
+ uncomp.length,
+ data,
+ alloc_size);
+
+ assert_int_not_equal(len, -1);
+ assert_int_equal(len, comp.length);
+
+ assert_memory_equal(comp.data, data, len);
+
+ len = lzxpress_decompress(comp.data,
+ comp.length,
+ data,
+ alloc_size);
+
+ assert_int_not_equal(len, -1);
+ assert_int_equal(len, uncomp.length);
+
+ assert_memory_equal(uncomp.data, data, len);
+ }
+ talloc_free(tmp_ctx);
+}
+
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_lzxpress_plain_decompress_files),
+ cmocka_unit_test(test_lzxpress_plain_decompress_more_compressed_files),
+ cmocka_unit_test(test_lzxpress_plain_round_trip_files),
+ cmocka_unit_test(test_lzxpress_plain_long_gpl_round_trip),
+ cmocka_unit_test(test_lzxpress_plain_long_random_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_plain_chaos_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_plain_sparse_random_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_plain_long_random_graph_round_trip),
+ cmocka_unit_test(test_lzxpress_plain_random_noise_round_trip),
+ cmocka_unit_test(test_lzxpress),
+ cmocka_unit_test(test_msft_data1),
+ cmocka_unit_test(test_msft_data2),
+ cmocka_unit_test(test_lzxpress2),
+ cmocka_unit_test(test_lzxpress3),
+ cmocka_unit_test(test_lzxpress4),
+ cmocka_unit_test(test_lzxpress_many_zeros),
+ cmocka_unit_test(test_lzxpress_round_trip),
+ };
+ if (!isatty(1)) {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/compression/wscript_build b/lib/compression/wscript_build
new file mode 100644
index 0000000..61fe4a9
--- /dev/null
+++ b/lib/compression/wscript_build
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LZXPRESS',
+ deps='replace talloc stable_sort samba-debug',
+ source='lzxpress.c lzxpress_huffman.c'
+ )
+
+bld.SAMBA_BINARY('test_lzx_huffman',
+ source='tests/test_lzx_huffman.c',
+ deps=('cmocka replace LZXPRESS'
+ ' samba-util'),
+ local_include=False,
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_lzxpress_plain',
+ source='tests/test_lzxpress_plain.c',
+ deps=('cmocka replace LZXPRESS'
+ ' samba-util'),
+ local_include=False,
+ for_selftest=True)
+
+bld.SAMBA_PYTHON('pycompression',
+ 'pycompression.c',
+ deps='LZXPRESS',
+ realname='samba/compression.so')
diff --git a/lib/crypto/REQUIREMENTS b/lib/crypto/REQUIREMENTS
new file mode 100644
index 0000000..5ebf3ba
--- /dev/null
+++ b/lib/crypto/REQUIREMENTS
@@ -0,0 +1,139 @@
+A list of the crypto operations that we require, and what uses them.
+
+This list is to allow research into using external crypto libraries.
+Those possibly supported in the git version of GnuTLS are indicated as '# GNUTLS'
+Those possibly supported in the git version of nettle are indicated as '# NETTLE'
+
+Samba in general gnutls >= 3.4.7 is required
+Samba FS with MS Catalog support will require gnutls >= 3.5.6
+
+GnuTLS Milestone for Samba support:
+ - https://gitlab.com/gnutls/gnutls/milestones/14
+
+ARCFOUR (RC4)
+ - the old SamOEMHash
+ - Password encryption on SAMR for password set/get
+ - NETLOGON SamLogon session keys
+ - Schannel
+ - DRSUAPI replication replicated secrets
+
+ # GNUTLS >= 3.0.0
+ # NETTLE
+
+DES
+ - NTLM challenge-response
+ - LSA QuerySecret et al
+ - NETLOGON SamLogon session keys
+ - ServerGetTrustInfo returned passwords
+ - RID encryption of passwords
+
+ # No support in gnutls, it cannot be a certified use of crypto
+ # NETTLE (any version)
+
+3DES
+ - NETLOGON Credentials (can't find any use in Samba)
+
+3DES-CBC
+ - backupkey (uses heimdal lib or gnutls with mit krb5)
+
+ # gnutls >= 3.4.7 (3des cbc with 192 bit key is supported); can no longer be a certified use of crypto
+ # NETTLE
+
+CRC32
+ - DRSUAPI replication replicated secrets
+
+This is no crypto
+
+AES 128 in 8-bit CFB mode
+ - SCHANNEL
+ - NETLOGON SamLogon session keys
+
+ # Missing in GNUTLS -> Bug opened
+ # NETTLE 3.4 contains CFB - possibly 128-bit mode (AES-NI available)
+
+AES128 CCM
+ - SMB2 2.24 SMB encryption
+
+ # GNUTLS >= 3.4.0
+ # NETTLE (AES-NI available)
+
+AES128 GCM
+ - SMB2 3.10 SMB encryption
+ - encrypted_secrets ldb module (encrypt secrets within sam.ldb)
+
+ # GNUTLS >= 3.0.0
+ # NETTLE (AES-NI available)
+
+AES128 CMAC
+ - SMB2 0x224 SMB Signing
+
+ # Missing in GNUTLS - > Bug opened
+ # Missing in NETTLE -> Bug opened
+
+MD4
+ - NTLM password hash
+
+ # Cannot be certified; considered non-crypto
+ # NETTLE
+
+MD5
+ - NTLM2 (can be considered non-crypto use of MD5)
+ - SCHANNEL (it's ok to fail in FIPS140 mode, as there are alternatives)
+ - NTLMSSP (it's ok to fail in FIPS140 mode, replaced by kerberos)
+ - NETLOGON computer credentials (it's ok to fail in FIPS140 mode, as there are alternatives)
+ - DRSUAPI blob encryption (can be considered non-crypto use as it is over DC-RPC which is encrypted)
+ - SAMR/wkssvc password change/set encryption
+ - vfs_fruit
+ - vfs_streams_xattr
+ - passdb old password history format
+ - dsdb password_hash module
+ - SMB1 SMB signing
+ - NTP ntp_signd
+
+maybe use gnutls_fips140_mode_enabled() and enable only SMB2/3 when in fips mode?
+
+ # GNUTLS >= 3.0.0 (Will fail in FIPS mode, for non-crypto -> https://gitlab.com/gnutls/gnutls/merge_requests/572 , open bug for RC4, MD5 being available for non-crypto use )
+ # NETTLE
+
+HMAC-MD5
+ - NTLMv2
+
+ # GNUTLS >= 3.0.0 (non-crypto)
+ # NETTLE
+
+HMAC-SHA256
+ - SMB2 < 2.24 SMB signing
+ - SMB2 Key derivation
+
+ # GNUTLS (>= 3.0.0)
+ # NETTLE
+
+HMAC-SHA1
+ - BackupKey ServerWrap
+
+ # GNUTLS (>= 3.0.0)
+ # NETTLE
+
+SHA256
+ - Security Descriptor hash for vfs_acl_xattr
+ - oLschema2ldif
+
+ # GNUTLS (>= 3.0.0)
+ # NETTLE
+
+SHA512
+ - SMB2 Pre-auth integrity verification
+ - BackupKey ClientWrap
+
+ # GNUTLS (>= 3.0.0)
+ # NETTLE
+
+RSA
+ - BackupKey ClientWrap
+
+ # GNUTLS (>= 3.0.0)
+ # NETTLE
+
+
+GNUTLS
+Use gnutls_rnd() in generate_random_buffer() to increase speed
diff --git a/lib/crypto/aes.h b/lib/crypto/aes.h
new file mode 100644
index 0000000..21c1eda
--- /dev/null
+++ b/lib/crypto/aes.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 INSTITUTE OR CONTRIBUTORS 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.
+ */
+
+/* $Id$ */
+
+#ifndef LIB_CRYPTO_AES_H
+#define LIB_CRYPTO_AES_H 1
+
+/*
+ *
+ */
+
+#define AES_BLOCK_SIZE 16
+#endif /* LIB_CRYPTO_AES_H */
diff --git a/lib/crypto/crypto.h b/lib/crypto/crypto.h
new file mode 100644
index 0000000..026fb20
--- /dev/null
+++ b/lib/crypto/crypto.h
@@ -0,0 +1,26 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_CRYPTO_H_
+#define _SAMBA_CRYPTO_H_
+
+#include "../lib/crypto/md4.h"
+#include "../lib/crypto/aes.h"
+
+#endif /* _SAMBA_CRYPTO_H_ */
diff --git a/lib/crypto/gkdi.c b/lib/crypto/gkdi.c
new file mode 100644
index 0000000..6799dcf
--- /dev/null
+++ b/lib/crypto/gkdi.c
@@ -0,0 +1,396 @@
+/*
+ Unix SMB/CIFS implementation.
+ Group Key Distribution Protocol functions
+
+ Copyright (C) Catalyst.Net Ltd 2023
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#include "lib/crypto/gnutls_helpers.h"
+
+#include "lib/util/bytearray.h"
+
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/gkdi.h"
+#include "librpc/gen_ndr/ndr_gkdi.h"
+
+#include "lib/crypto/gkdi.h"
+
+static const uint8_t kds_service[] = {
+ /* “KDS service” as a NULL‐terminated UTF‐16LE string. */
+ 'K', 0, 'D', 0, 'S', 0, ' ', 0, 's', 0, 'e', 0,
+ 'r', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 0, 0,
+};
+
+struct GkdiContextShort {
+ uint8_t buf[sizeof((struct GUID_ndr_buf){}.buf) + sizeof(int32_t) +
+ sizeof(int32_t) + sizeof(int32_t)];
+};
+
+static NTSTATUS make_gkdi_context(const struct GkdiDerivationCtx *ctx,
+ struct GkdiContextShort *out_ctx)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB b = {.data = out_ctx->buf, .length = sizeof out_ctx->buf};
+
+ if (ctx->target_security_descriptor.length) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ndr_err = ndr_push_struct_into_fixed_blob(
+ &b, ctx, (ndr_push_flags_fn_t)ndr_push_GkdiDerivationCtx);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS make_gkdi_context_security_descriptor(
+ TALLOC_CTX *mem_ctx,
+ const struct GkdiDerivationCtx *ctx,
+ const DATA_BLOB security_descriptor,
+ DATA_BLOB *out_ctx)
+{
+ enum ndr_err_code ndr_err;
+ struct GkdiDerivationCtx ctx_with_sd = *ctx;
+
+ if (ctx_with_sd.target_security_descriptor.length) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ctx_with_sd.target_security_descriptor = security_descriptor;
+
+ ndr_err = ndr_push_struct_blob(out_ctx,
+ mem_ctx,
+ &ctx_with_sd,
+ (ndr_push_flags_fn_t)
+ ndr_push_GkdiDerivationCtx);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct GkdiContext {
+ struct GkdiDerivationCtx ctx;
+ gnutls_mac_algorithm_t algorithm;
+};
+
+gnutls_mac_algorithm_t get_sp800_108_mac_algorithm(
+ const struct KdfAlgorithm kdf_algorithm)
+{
+ switch (kdf_algorithm.id) {
+ case KDF_ALGORITHM_SP800_108_CTR_HMAC:
+ switch (kdf_algorithm.param.sp800_108) {
+ case KDF_PARAM_SHA1:
+ return GNUTLS_MAC_SHA1;
+ case KDF_PARAM_SHA256:
+ return GNUTLS_MAC_SHA256;
+ case KDF_PARAM_SHA384:
+ return GNUTLS_MAC_SHA384;
+ case KDF_PARAM_SHA512:
+ return GNUTLS_MAC_SHA512;
+ }
+ break;
+ }
+
+ return GNUTLS_MAC_UNKNOWN;
+}
+
+static NTSTATUS GkdiContext(const struct ProvRootKey *const root_key,
+ struct GkdiContext *const ctx)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ gnutls_mac_algorithm_t algorithm = GNUTLS_MAC_UNKNOWN;
+
+ if (ctx == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (root_key == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (root_key->version != root_key_version_1) {
+ status = NT_STATUS_NOT_SUPPORTED;
+ goto out;
+ }
+
+ if (root_key->data.length != GKDI_KEY_LEN) {
+ status = NT_STATUS_NOT_SUPPORTED;
+ goto out;
+ }
+
+ algorithm = get_sp800_108_mac_algorithm(root_key->kdf_algorithm);
+ if (algorithm == GNUTLS_MAC_UNKNOWN) {
+ status = NT_STATUS_NOT_SUPPORTED;
+ goto out;
+ }
+
+ /*
+ * The context comprises the GUID corresponding to the root key, the
+ * GKID (which we shall initialize to zero), and the encoded target
+ * security descriptor (which will initially be empty).
+ */
+ *ctx = (struct GkdiContext){
+ .ctx = {.guid = root_key->id,
+ .l0_idx = 0,
+ .l1_idx = 0,
+ .l2_idx = 0,
+ .target_security_descriptor = {}},
+ .algorithm = algorithm,
+ };
+out:
+ return status;
+}
+
+static NTSTATUS compute_l1_seed_key(
+ TALLOC_CTX *mem_ctx,
+ struct GkdiContext *ctx,
+ const DATA_BLOB security_descriptor,
+ const struct ProvRootKey *const root_key,
+ const struct Gkid gkid,
+ uint8_t key[static const GKDI_KEY_LEN])
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct GkdiContextShort short_ctx;
+ int8_t n;
+
+ ctx->ctx.l0_idx = gkid.l0_idx;
+ ctx->ctx.l1_idx = -1;
+ ctx->ctx.l2_idx = -1;
+
+ status = make_gkdi_context(&ctx->ctx, &short_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ /* Derive an L0 seed key with GKID = (L0, −1, −1). */
+
+ status = samba_gnutls_sp800_108_derive_key(root_key->data.data,
+ root_key->data.length,
+ NULL,
+ 0,
+ kds_service,
+ sizeof kds_service,
+ short_ctx.buf,
+ sizeof short_ctx.buf,
+ ctx->algorithm,
+ key,
+ GKDI_KEY_LEN);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ /* Derive an L1 seed key with GKID = (L0, 31, −1). */
+
+ ctx->ctx.l1_idx = 31;
+
+ {
+ DATA_BLOB security_descriptor_ctx;
+
+ status = make_gkdi_context_security_descriptor(
+ mem_ctx,
+ &ctx->ctx,
+ security_descriptor,
+ &security_descriptor_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ status = samba_gnutls_sp800_108_derive_key(
+ key,
+ GKDI_KEY_LEN,
+ NULL,
+ 0,
+ kds_service,
+ sizeof kds_service,
+ security_descriptor_ctx.data,
+ security_descriptor_ctx.length,
+ ctx->algorithm,
+ key,
+ GKDI_KEY_LEN);
+ data_blob_free(&security_descriptor_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+ for (n = 30; n >= gkid.l1_idx; --n) {
+ /* Derive an L1 seed key with GKID = (L0, n, −1). */
+
+ ctx->ctx.l1_idx = n;
+
+ status = make_gkdi_context(&ctx->ctx, &short_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ status = samba_gnutls_sp800_108_derive_key(key,
+ GKDI_KEY_LEN,
+ NULL,
+ 0,
+ kds_service,
+ sizeof kds_service,
+ short_ctx.buf,
+ sizeof short_ctx.buf,
+ ctx->algorithm,
+ key,
+ GKDI_KEY_LEN);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+out:
+ return status;
+}
+
+static NTSTATUS derive_l2_seed_key(struct GkdiContext *ctx,
+ const struct Gkid gkid,
+ uint8_t key[static const GKDI_KEY_LEN])
+{
+ NTSTATUS status = NT_STATUS_OK;
+ int8_t n;
+
+ ctx->ctx.l0_idx = gkid.l0_idx;
+ ctx->ctx.l1_idx = gkid.l1_idx;
+
+ for (n = 31; n >= gkid.l2_idx; --n) {
+ struct GkdiContextShort short_ctx;
+
+ /* Derive an L2 seed key with GKID = (L0, L1, n). */
+
+ ctx->ctx.l2_idx = n;
+
+ status = make_gkdi_context(&ctx->ctx, &short_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ status = samba_gnutls_sp800_108_derive_key(key,
+ GKDI_KEY_LEN,
+ NULL,
+ 0,
+ kds_service,
+ sizeof kds_service,
+ short_ctx.buf,
+ sizeof short_ctx.buf,
+ ctx->algorithm,
+ key,
+ GKDI_KEY_LEN);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+out:
+ return status;
+}
+
+static enum GkidType gkid_key_type(const struct Gkid gkid)
+{
+ if (gkid.l0_idx == -1) {
+ return GKID_DEFAULT;
+ }
+
+ if (gkid.l1_idx == -1) {
+ return GKID_L0_SEED_KEY;
+ }
+
+ if (gkid.l2_idx == -1) {
+ return GKID_L1_SEED_KEY;
+ }
+
+ return GKID_L2_SEED_KEY;
+}
+
+static bool gkid_is_valid(const struct Gkid gkid)
+{
+ if (gkid.l0_idx < -1) {
+ return false;
+ }
+
+ if (gkid.l1_idx < -1 || gkid.l1_idx >= gkdi_l1_key_iteration) {
+ return false;
+ }
+
+ if (gkid.l2_idx < -1 || gkid.l2_idx >= gkdi_l2_key_iteration) {
+ return false;
+ }
+
+ if (gkid.l0_idx == -1 && gkid.l1_idx != -1) {
+ return false;
+ }
+
+ if (gkid.l1_idx == -1 && gkid.l2_idx != -1) {
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS compute_seed_key(
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB target_security_descriptor,
+ const struct ProvRootKey *const root_key,
+ const struct Gkid gkid,
+ uint8_t key[static const GKDI_KEY_LEN])
+{
+ NTSTATUS status = NT_STATUS_OK;
+ enum GkidType gkid_type;
+ struct GkdiContext ctx;
+
+ if (!gkid_is_valid(gkid)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ gkid_type = gkid_key_type(gkid);
+ if (gkid_type < GKID_L1_SEED_KEY) {
+ /* Don’t allow derivation of L0 seed keys. */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ status = GkdiContext(root_key, &ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ status = compute_l1_seed_key(
+ mem_ctx, &ctx, target_security_descriptor, root_key, gkid, key);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ if (gkid_type == GKID_L2_SEED_KEY) {
+ status = derive_l2_seed_key(&ctx, gkid, key);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+out:
+ return status;
+}
diff --git a/lib/crypto/gkdi.h b/lib/crypto/gkdi.h
new file mode 100644
index 0000000..892bcc4
--- /dev/null
+++ b/lib/crypto/gkdi.h
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/CIFS implementation.
+ Group Key Distribution Protocol functions
+
+ Copyright (C) Catalyst.Net Ltd 2023
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef LIB_CRYPTO_GKDI_H
+#define LIB_CRYPTO_GKDI_H
+
+#include <stdint.h>
+
+#include <gnutls/gnutls.h>
+
+#include "lib/util/data_blob.h"
+
+#include "libcli/util/ntstatus.h"
+
+#include "librpc/gen_ndr/misc.h"
+#include "lib/util/time.h"
+#include "talloc.h"
+
+enum KdfAlgorithmId {
+ KDF_ALGORITHM_SP800_108_CTR_HMAC,
+};
+
+enum KdfSp800_108Param {
+ KDF_PARAM_SHA1,
+ KDF_PARAM_SHA256,
+ KDF_PARAM_SHA384,
+ KDF_PARAM_SHA512,
+};
+
+struct KdfAlgorithm {
+ union {
+ enum KdfSp800_108Param sp800_108;
+ } param;
+ enum KdfAlgorithmId id;
+};
+
+enum {
+ root_key_version_1 = 1,
+};
+
+struct ProvRootKey {
+ struct GUID id;
+ DATA_BLOB data;
+ NTTIME create_time;
+ NTTIME use_start_time;
+ const char *domain_id;
+ struct KdfAlgorithm kdf_algorithm;
+ int32_t version;
+};
+
+struct Gkid {
+ int32_t l0_idx;
+ int8_t l1_idx; /* [range(0, 31)] */
+ int8_t l2_idx; /* [range(0, 31)] */
+};
+
+enum GkidType {
+ GKID_DEFAULT = -1,
+ GKID_L0_SEED_KEY = 0,
+ GKID_L1_SEED_KEY = 1,
+ GKID_L2_SEED_KEY = 2,
+};
+
+static const int gkdi_l1_key_iteration = 32;
+static const int gkdi_l2_key_iteration = 32;
+
+static const int64_t gkdi_key_cycle_duration = 360000000000;
+static const int64_t gkdi_max_clock_skew = 3000000000;
+
+#define GKDI_KEY_LEN 64
+
+gnutls_mac_algorithm_t get_sp800_108_mac_algorithm(
+ const struct KdfAlgorithm kdf_algorithm);
+
+NTSTATUS compute_seed_key(
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB target_security_descriptor,
+ const struct ProvRootKey *const root_key,
+ const struct Gkid gkid,
+ uint8_t out[static const GKDI_KEY_LEN]);
+
+#endif /* LIB_CRYPTO_GKDI_H */
diff --git a/lib/crypto/gnutls_aead_aes_256_cbc_hmac_sha512.c b/lib/crypto/gnutls_aead_aes_256_cbc_hmac_sha512.c
new file mode 100644
index 0000000..2e37dcd
--- /dev/null
+++ b/lib/crypto/gnutls_aead_aes_256_cbc_hmac_sha512.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2021-2022 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/util/data_blob.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include "gnutls_helpers.h"
+
+#define SAMR_AES_VERSION_BYTE 0x01
+#define SAMR_AES_VERSION_BYTE_LEN 1
+
+static NTSTATUS calculate_enc_key(const DATA_BLOB *cek,
+ const DATA_BLOB *key_salt,
+ uint8_t enc_key[32])
+{
+ gnutls_mac_algorithm_t hash_algo = GNUTLS_MAC_SHA512;
+ size_t hmac_size = gnutls_hmac_get_len(hash_algo);
+ uint8_t enc_key_data[hmac_size];
+ int rc;
+
+ rc = gnutls_hmac_fast(hash_algo,
+ cek->data,
+ cek->length,
+ key_salt->data,
+ key_salt->length,
+ enc_key_data);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ /* The key gets truncated to 32 byte */
+ memcpy(enc_key, enc_key_data, 32);
+ BURN_DATA(enc_key_data);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS calculate_mac_key(const DATA_BLOB *cek,
+ const DATA_BLOB *mac_salt,
+ uint8_t mac_key[64])
+{
+ int rc;
+
+ rc = gnutls_hmac_fast(GNUTLS_MAC_SHA512,
+ cek->data,
+ cek->length,
+ mac_salt->data,
+ mac_salt->length,
+ mac_key);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* This is an implementation of [MS-SAMR] 3.2.2.4 AES Cipher Usage */
+
+NTSTATUS
+samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *plaintext,
+ const DATA_BLOB *cek,
+ const DATA_BLOB *key_salt,
+ const DATA_BLOB *mac_salt,
+ const DATA_BLOB *iv,
+ DATA_BLOB *pciphertext,
+ uint8_t pauth_tag[64])
+{
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ gnutls_mac_algorithm_t hmac_algo = GNUTLS_MAC_SHA512;
+ size_t hmac_size = gnutls_hmac_get_len(hmac_algo);
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_cipher_algorithm_t cipher_algo = GNUTLS_CIPHER_AES_256_CBC;
+ uint32_t aes_block_size = gnutls_cipher_get_block_size(cipher_algo);
+ gnutls_datum_t iv_datum = {
+ .data = iv->data,
+ .size = iv->length,
+ };
+ uint8_t enc_key_data[32] = {0};
+ gnutls_datum_t enc_key = {
+ .data = enc_key_data,
+ .size = sizeof(enc_key_data),
+ };
+ uint8_t *cipher_text = NULL;
+ size_t cipher_text_len = 0;
+ uint8_t mac_key_data[64] = {0};
+ gnutls_datum_t mac_key = {
+ .data = mac_key_data,
+ .size = sizeof(mac_key_data),
+ };
+ uint8_t version_byte = SAMR_AES_VERSION_BYTE;
+ uint8_t version_byte_len = SAMR_AES_VERSION_BYTE_LEN;
+ uint8_t auth_data[hmac_size];
+ DATA_BLOB padded_plaintext;
+ size_t padding;
+ NTSTATUS status;
+ int rc;
+
+ /*
+ * We don't want to overflow 'pauth_tag', which is 64 bytes in
+ * size.
+ */
+ SMB_ASSERT(hmac_size == 64);
+
+ if (plaintext->length == 0 || cek->length == 0 ||
+ key_salt->length == 0 || mac_salt->length == 0 || iv->length == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * PKCS#7 padding
+ *
+ * TODO: Use gnutls_cipher_encrypt3()
+ */
+
+ if (plaintext->length + aes_block_size < plaintext->length) {
+ return NT_STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ padded_plaintext.length =
+ aes_block_size * (plaintext->length / aes_block_size) +
+ aes_block_size;
+
+ padding = padded_plaintext.length - plaintext->length;
+
+ padded_plaintext =
+ data_blob_talloc(mem_ctx, NULL, padded_plaintext.length);
+ if (padded_plaintext.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Allocate buffer for cipher text */
+ cipher_text_len = padded_plaintext.length;
+ cipher_text = talloc_size(mem_ctx, cipher_text_len);
+ if (cipher_text == NULL) {
+ data_blob_free(&padded_plaintext);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(padded_plaintext.data, plaintext->data, plaintext->length);
+ memset(padded_plaintext.data + plaintext->length, padding, padding);
+
+ status = calculate_enc_key(cek, key_salt, enc_key_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_clear_free(&padded_plaintext);
+ return status;
+ }
+
+ /* Encrypt plaintext */
+ rc = gnutls_cipher_init(&cipher_hnd, cipher_algo, &enc_key, &iv_datum);
+ if (rc < 0) {
+ data_blob_clear_free(&padded_plaintext);
+ BURN_DATA(enc_key_data);
+ TALLOC_FREE(cipher_text);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ rc = gnutls_cipher_encrypt2(cipher_hnd,
+ padded_plaintext.data,
+ padded_plaintext.length,
+ cipher_text,
+ cipher_text_len);
+ gnutls_cipher_deinit(cipher_hnd);
+ data_blob_clear_free(&padded_plaintext);
+ BURN_DATA(enc_key_data);
+ if (rc < 0) {
+ TALLOC_FREE(cipher_text);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ /* Calculate mac key */
+ status = calculate_mac_key(cek, mac_salt, mac_key_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(cipher_text);
+ return status;
+ }
+
+ /* Generate auth tag */
+ rc = gnutls_hmac_init(&hmac_hnd, hmac_algo, mac_key.data, mac_key.size);
+ BURN_DATA(mac_key_data);
+ if (rc < 0) {
+ TALLOC_FREE(cipher_text);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, &version_byte, sizeof(uint8_t));
+ if (rc < 0) {
+ TALLOC_FREE(cipher_text);
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, iv->data, iv->length);
+ if (rc < 0) {
+ TALLOC_FREE(cipher_text);
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, cipher_text, cipher_text_len);
+ if (rc < 0) {
+ TALLOC_FREE(cipher_text);
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, &version_byte_len, sizeof(uint8_t));
+ if (rc < 0) {
+ TALLOC_FREE(cipher_text);
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ENCRYPTION_FAILED);
+ }
+ gnutls_hmac_deinit(hmac_hnd, auth_data);
+
+ if (pciphertext != NULL) {
+ pciphertext->length = cipher_text_len;
+ pciphertext->data = cipher_text;
+ }
+ (void)memcpy(pauth_tag, auth_data, hmac_size);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS
+samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *ciphertext,
+ const DATA_BLOB *cdk,
+ const DATA_BLOB *key_salt,
+ const DATA_BLOB *mac_salt,
+ const DATA_BLOB *iv,
+ const uint8_t auth_tag[64],
+ DATA_BLOB *pplaintext)
+{
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ gnutls_mac_algorithm_t hash_algo = GNUTLS_MAC_SHA512;
+ size_t hmac_size = gnutls_hmac_get_len(hash_algo);
+ uint8_t dec_key_data[32];
+ uint8_t mac_key_data[64];
+ gnutls_datum_t mac_key = {
+ .data = mac_key_data,
+ .size = sizeof(mac_key_data),
+ };
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_cipher_algorithm_t cipher_algo = GNUTLS_CIPHER_AES_256_CBC;
+ gnutls_datum_t dec_key = {
+ .data = dec_key_data,
+ .size = sizeof(dec_key_data),
+ };
+ gnutls_datum_t iv_datum = {
+ .data = iv->data,
+ .size = iv->length,
+ };
+ uint8_t version_byte = SAMR_AES_VERSION_BYTE;
+ uint8_t version_byte_len = SAMR_AES_VERSION_BYTE_LEN;
+ uint8_t auth_data[hmac_size];
+ uint8_t padding;
+ size_t i;
+ NTSTATUS status;
+ bool equal;
+ int rc;
+
+ if (cdk->length == 0 || ciphertext->length == 0 ||
+ key_salt->length == 0 || mac_salt->length == 0 || iv->length == 0 ||
+ pplaintext == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Calculate mac key */
+ status = calculate_mac_key(cdk, mac_salt, mac_key_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ rc = gnutls_hmac_init(&hmac_hnd, hash_algo, mac_key.data, mac_key.size);
+ BURN_DATA(mac_key_data);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_DECRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, &version_byte, sizeof(uint8_t));
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_DECRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, iv->data, iv->length);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_DECRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, ciphertext->data, ciphertext->length);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_DECRYPTION_FAILED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, &version_byte_len, sizeof(uint8_t));
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_DECRYPTION_FAILED);
+ }
+ gnutls_hmac_deinit(hmac_hnd, auth_data);
+
+ equal = mem_equal_const_time(auth_data, auth_tag, sizeof(auth_data));
+ if (!equal) {
+ return NT_STATUS_DECRYPTION_FAILED;
+ }
+
+ *pplaintext = data_blob_talloc_zero(mem_ctx, ciphertext->length);
+ if (pplaintext->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Calculate decryption key */
+ status = calculate_enc_key(cdk, key_salt, dec_key_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ rc = gnutls_cipher_init(&cipher_hnd, cipher_algo, &dec_key, &iv_datum);
+ BURN_DATA(dec_key_data);
+ if (rc < 0) {
+ data_blob_free(pplaintext);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_DECRYPTION_FAILED);
+ }
+
+ rc = gnutls_cipher_decrypt2(cipher_hnd,
+ ciphertext->data,
+ ciphertext->length,
+ pplaintext->data,
+ pplaintext->length);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ data_blob_clear_free(pplaintext);
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_DECRYPTION_FAILED);
+ }
+
+ /*
+ * PKCS#7 padding
+ *
+ * TODO: Use gnutls_cipher_decrypt3()
+ */
+
+ /*
+ * The plaintext is always padded.
+ *
+ * We already checked for ciphertext->length == 0 above and the
+ * pplaintext->length is equal to ciphertext->length here. We need to
+ * remove the padding from the plaintext size.
+ */
+ padding = pplaintext->data[pplaintext->length - 1];
+ if (padding == 0 || padding > 16) {
+ data_blob_clear_free(pplaintext);
+ return NT_STATUS_DECRYPTION_FAILED;
+ }
+
+ for (i = pplaintext->length - padding; i < pplaintext->length; i++) {
+ if (pplaintext->data[i] != padding) {
+ data_blob_clear_free(pplaintext);
+ return NT_STATUS_DECRYPTION_FAILED;
+ }
+ }
+
+ pplaintext->length -= padding;
+
+ return NT_STATUS_OK;
+}
diff --git a/lib/crypto/gnutls_arcfour_confounded_md5.c b/lib/crypto/gnutls_arcfour_confounded_md5.c
new file mode 100644
index 0000000..7f1bf94
--- /dev/null
+++ b/lib/crypto/gnutls_arcfour_confounded_md5.c
@@ -0,0 +1,93 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrapper for gnutls hash and encryption functions
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009-2019
+ Copyright (c) Andreas Schneider <asn@samba.org> 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+ * This (arcfour over data with a key combined from two inputs, one
+ * the key another the confounder), is a common pattern in pre-AES
+ * windows cryptography
+ *
+ * Some protocols put the confounder first, others second so both
+ * parameters are named key_input here.
+ *
+ */
+
+#include "includes.h"
+#include "lib/util/data_blob.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include "gnutls_helpers.h"
+#include "lib/util/memory.h"
+
+int samba_gnutls_arcfour_confounded_md5(const DATA_BLOB *key_input1,
+ const DATA_BLOB *key_input2,
+ DATA_BLOB *data,
+ enum samba_gnutls_direction encrypt)
+{
+ int rc;
+ gnutls_hash_hd_t hash_hnd = NULL;
+ uint8_t confounded_key[16];
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t confounded_key_datum = {
+ .data = confounded_key,
+ .size = sizeof(confounded_key),
+ };
+
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
+ if (rc < 0) {
+ return rc;
+ }
+ rc = gnutls_hash(hash_hnd, key_input1->data, key_input1->length);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return rc;
+ }
+ rc = gnutls_hash(hash_hnd, key_input2->data, key_input2->length);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return rc;
+ }
+
+ gnutls_hash_deinit(hash_hnd, confounded_key);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &confounded_key_datum,
+ NULL);
+ if (rc < 0) {
+ return rc;
+ }
+
+ if (encrypt == SAMBA_GNUTLS_ENCRYPT) {
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ data->data,
+ data->length);
+ } else {
+ rc = gnutls_cipher_decrypt(cipher_hnd,
+ data->data,
+ data->length);
+ }
+ gnutls_cipher_deinit(cipher_hnd);
+ ZERO_ARRAY(confounded_key);
+
+ return rc;
+}
diff --git a/lib/crypto/gnutls_error.c b/lib/crypto/gnutls_error.c
new file mode 100644
index 0000000..764e217
--- /dev/null
+++ b/lib/crypto/gnutls_error.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "gnutls_helpers.h"
+
+#include <gnutls/gnutls.h>
+
+NTSTATUS _gnutls_error_to_ntstatus(int gnutls_rc,
+ NTSTATUS blocked_status,
+ const char *function,
+ const char *location)
+{
+ NTSTATUS status;
+
+ if (gnutls_rc == GNUTLS_E_SUCCESS) {
+ return NT_STATUS_OK;
+ }
+
+ switch (gnutls_rc) {
+ case GNUTLS_E_UNWANTED_ALGORITHM:
+ status = blocked_status;
+ break;
+ case GNUTLS_E_MEMORY_ERROR:
+ status = NT_STATUS_NO_MEMORY;
+ break;
+ case GNUTLS_E_INVALID_REQUEST:
+ status = NT_STATUS_INVALID_VARIANT;
+ break;
+ case GNUTLS_E_DECRYPTION_FAILED:
+ status = NT_STATUS_DECRYPTION_FAILED;
+ break;
+ case GNUTLS_E_ENCRYPTION_FAILED:
+ status = NT_STATUS_ENCRYPTION_FAILED;
+ break;
+ case GNUTLS_E_SHORT_MEMORY_BUFFER:
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ case GNUTLS_E_BASE64_DECODING_ERROR:
+ case GNUTLS_E_HASH_FAILED:
+ case GNUTLS_E_LIB_IN_ERROR_STATE:
+ case GNUTLS_E_INTERNAL_ERROR:
+ default:
+ status = NT_STATUS_INTERNAL_ERROR;
+ break;
+ }
+
+ D_WARNING("%s: GNUTLS ERROR: %s, NTSTATUS: %s at %s\n",
+ function,
+ gnutls_strerror_name(gnutls_rc),
+ nt_errstr(status),
+ location);
+
+ return status;
+}
+
+WERROR _gnutls_error_to_werror(int gnutls_rc,
+ WERROR blocked_werr,
+ const char *function,
+ const char *location)
+{
+ WERROR werr;
+
+ if (gnutls_rc == GNUTLS_E_SUCCESS) {
+ return WERR_OK;
+ }
+
+ switch (gnutls_rc) {
+ case GNUTLS_E_UNWANTED_ALGORITHM:
+ werr = blocked_werr;
+ break;
+ case GNUTLS_E_MEMORY_ERROR:
+ werr = WERR_NOT_ENOUGH_MEMORY;
+ break;
+ case GNUTLS_E_INVALID_REQUEST:
+ werr = WERR_INVALID_VARIANT;
+ break;
+ case GNUTLS_E_DECRYPTION_FAILED:
+ werr = WERR_DECRYPTION_FAILED;
+ break;
+ case GNUTLS_E_ENCRYPTION_FAILED:
+ werr = WERR_ENCRYPTION_FAILED;
+ break;
+ case GNUTLS_E_SHORT_MEMORY_BUFFER:
+ werr = WERR_INVALID_PARAMETER;
+ break;
+ case GNUTLS_E_BASE64_DECODING_ERROR:
+ case GNUTLS_E_HASH_FAILED:
+ case GNUTLS_E_LIB_IN_ERROR_STATE:
+ case GNUTLS_E_INTERNAL_ERROR:
+ default:
+ werr = WERR_INTERNAL_ERROR;
+ break;
+ }
+
+ D_WARNING("%s: GNUTLS ERROR: %s, WERROR: %s at %s\n",
+ function,
+ gnutls_strerror_name(gnutls_rc),
+ win_errstr(werr),
+ location);
+
+ return werr;
+}
diff --git a/lib/crypto/gnutls_helpers.h b/lib/crypto/gnutls_helpers.h
new file mode 100644
index 0000000..0362d5e
--- /dev/null
+++ b/lib/crypto/gnutls_helpers.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GNUTLS_HELPERS_H
+#define _GNUTLS_HELPERS_H
+
+#include <gnutls/gnutls.h>
+
+#include "libcli/util/ntstatus.h"
+#include "libcli/util/werror.h"
+#include "lib/util/data_blob.h"
+
+/* Those macros are only available in GnuTLS >= 3.6.4 */
+#ifndef GNUTLS_FIPS140_SET_LAX_MODE
+#define GNUTLS_FIPS140_SET_LAX_MODE()
+#endif
+
+#ifndef GNUTLS_FIPS140_SET_STRICT_MODE
+#define GNUTLS_FIPS140_SET_STRICT_MODE()
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Convert a gnutls error code to a corresponding NTSTATUS.
+ *
+ * @param[in] gnutls_rc The GnuTLS return code.
+ *
+ * @param[in] blocked_status The NTSTATUS return code which should be returned
+ * in case the e.g. the cipher might be blocked due
+ * to FIPS mode.
+ *
+ * @return A corresponding NTSTATUS code.
+ */
+NTSTATUS gnutls_error_to_ntstatus(int gnutls_rc, NTSTATUS blocked_status);
+#else
+NTSTATUS _gnutls_error_to_ntstatus(int gnutls_rc,
+ NTSTATUS blocked_status,
+ const char *function,
+ const char *location);
+#define gnutls_error_to_ntstatus(gnutls_rc, blocked_status) \
+ _gnutls_error_to_ntstatus(gnutls_rc, \
+ blocked_status, \
+ __FUNCTION__, \
+ __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Convert a gnutls error code to a corresponding WERROR.
+ *
+ * @param[in] gnutls_rc The GnuTLS return code.
+ *
+ * @param[in] blocked_werr The WERROR code which should be returned if e.g
+ * the cipher we want to used it not allowed to be
+ * used because of FIPS mode.
+ *
+ * @return A corresponding WERROR code.
+ */
+WERROR gnutls_error_to_werror(int gnutls_rc, WERROR blocked_werr);
+#else
+WERROR _gnutls_error_to_werror(int gnutls_rc,
+ WERROR blocked_werr,
+ const char *function,
+ const char *location);
+#define gnutls_error_to_werror(gnutls_rc, blocked_werr) \
+ _gnutls_error_to_werror(gnutls_rc, \
+ blocked_werr, \
+ __FUNCTION__, \
+ __location__)
+#endif
+
+enum samba_gnutls_direction { SAMBA_GNUTLS_ENCRYPT, SAMBA_GNUTLS_DECRYPT };
+
+/**
+ * @brief Encrypt or decrypt a data blob using RC4 with a key and salt.
+ *
+ * One of the key input should be a session key and the other a confounder
+ * (aka salt). Which one depends on the implementation details of the
+ * protocol.
+ *
+ * @param[in] key_input1 Either a session_key or a confounder.
+ *
+ * @param[in] key_input2 Either a session_key or a confounder.
+ *
+ * @param[in] data The data blob to either encrypt or decrypt. The data
+ * will be encrypted or decrypted in place.
+ *
+ * @param[in] encrypt The encryption direction.
+ *
+ * @return A gnutls error code.
+ */
+int samba_gnutls_arcfour_confounded_md5(const DATA_BLOB *key_input1,
+ const DATA_BLOB *key_input2,
+ DATA_BLOB *data,
+ enum samba_gnutls_direction encrypt);
+
+/**
+ * @brief Encrypted a secret plaintext using AEAD_AES_256_CBC_HMAC_SHA512 and
+ * the session key.
+ *
+ * This encrypts a secret plaintext using AEAD_AES_256_CBC_HMAC_SHA512 with a
+ * key (can be the session key or PBKDF2 password). This is used in SAMR and
+ * LSA.
+ *
+ * @param mem_ctx The memory context to allocate the cipher text pointer.
+ *
+ * @param plaintext The secret to encrypt
+ *
+ * @param cek The content encryption key to encrypt the secret.
+ *
+ * @param key_salt The salt used to calculate the encryption key.
+ *
+ * @param key_salt The salt used to calculate the mac key.
+
+ * @param iv The initialization vector used for the encryption.
+ *
+ * @param pciphertext A pointer to store the cipher text.
+ *
+ * @param pauth_tag[64] An array to store the auth tag.
+ *
+ * @return NT_STATUS_OK on success, an nt status error code otherwise.
+ */
+NTSTATUS
+samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *plaintext,
+ const DATA_BLOB *cek,
+ const DATA_BLOB *key_salt,
+ const DATA_BLOB *mac_salt,
+ const DATA_BLOB *iv,
+ DATA_BLOB *pciphertext,
+ uint8_t pauth_tag[64]);
+
+/**
+ * @brief Decypt cipher text using AEAD_AES_256_CBC_HMAC_SHA512 and the session
+ * key.
+ *
+ * This decrypts the cipher text using AEAD_AES_256_CBC_HMAC_SHA512 with the
+ * given content decryption key key. The plaintext will be zeroed as soon as the
+ * data blob is freed.
+ *
+ * @param mem_ctx The memory context to allocate the plaintext on.
+ *
+ * @param ciphertext The cipher text to decrypt.
+ *
+ * @param cdk The content decryption key.
+ *
+ * @param key_salt The salt used to calculate the encryption key.
+ *
+ * @param key_salt The salt used to calculate the mac key.
+
+ * @param iv The initialization vector used for the encryption.
+ *
+ * @param auth_tag[64] The authentication blob to be verified.
+ *
+ * @param pplaintext A pointer to a DATA_BLOB to store the plaintext.
+ *
+ * @return NT_STATUS_OK on success, an nt status error code otherwise.
+ */
+NTSTATUS
+samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *ciphertext,
+ const DATA_BLOB *cdk,
+ const DATA_BLOB *key_salt,
+ const DATA_BLOB *mac_salt,
+ const DATA_BLOB *iv,
+ const uint8_t auth_tag[64],
+ DATA_BLOB *pplaintext);
+
+/**
+ * @brief Check if weak crypto is allowed.
+ *
+ * @return true if weak crypo is allowed, false otherwise.
+ */
+bool samba_gnutls_weak_crypto_allowed(void);
+
+/**
+ * @brief Derive a key using the NIST SP 800‐108 algorithm.
+ *
+ * The details of the algorithm can be found at
+ * https://csrc.nist.gov/pubs/sp/800/108/r1/final.
+ *
+ * @param KI The key‐derivation key used as input.
+ *
+ * @param KI_len The length of the key‐derivation key.
+ *
+ * @param FixedData If non‐NULL, specifies fixed data to be used in place of
+ * that constructed from the Label and Context parameters.
+ *
+ * @param FixedData_len The length of the fixed data, if it is present.
+ *
+ * @param Label A label that identifies the purpose for the derived key.
+ * Ignored if FixedData is non‐NULL.
+ *
+ * @param Label_len The length of the label.
+ *
+ * @param Context Information related to the derived key. Ignored if
+ * FixedData is non‐NULL.
+ *
+ * @param Context_len The length of the context data.
+ *
+ * @param algorithm The HMAC algorithm to use.
+ *
+ * @param KO A buffer to receive the derived key.
+ *
+ * @param KO_len The length of the key to be derived.
+ *
+ * @return NT_STATUS_OK on success, an NT status error code otherwise.
+ */
+NTSTATUS samba_gnutls_sp800_108_derive_key(
+ const uint8_t *KI,
+ size_t KI_len,
+ const uint8_t *FixedData,
+ size_t FixedData_len,
+ const uint8_t *Label,
+ size_t Label_len,
+ const uint8_t *Context,
+ size_t Context_len,
+ const gnutls_mac_algorithm_t algorithm,
+ uint8_t *KO,
+ size_t KO_len);
+
+#endif /* _GNUTLS_HELPERS_H */
diff --git a/lib/crypto/gnutls_sp800_108.c b/lib/crypto/gnutls_sp800_108.c
new file mode 100644
index 0000000..fb0aa03
--- /dev/null
+++ b/lib/crypto/gnutls_sp800_108.c
@@ -0,0 +1,230 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrapper for gnutls key derivation functions
+
+ Copyright (C) Stefan Metzmacher 2009
+ Copyright (C) Catalyst.Net Ltd 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include "gnutls_helpers.h"
+
+static NTSTATUS samba_gnutls_sp800_108_derive_key_part(
+ const gnutls_hmac_hd_t hmac_hnd,
+ const uint8_t *FixedData,
+ const size_t FixedData_len,
+ const uint8_t *Label,
+ const size_t Label_len,
+ const uint8_t *Context,
+ const size_t Context_len,
+ const uint32_t L,
+ const uint32_t i,
+ uint8_t *digest)
+{
+ uint8_t buf[4];
+ static const uint8_t zero = 0;
+ int rc;
+
+ PUSH_BE_U32(buf, 0, i);
+ rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ if (FixedData != NULL) {
+ rc = gnutls_hmac(hmac_hnd, FixedData, FixedData_len);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(
+ rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ } else {
+ rc = gnutls_hmac(hmac_hnd, Label, Label_len);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(
+ rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(hmac_hnd, &zero, 1);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(
+ rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(hmac_hnd, Context, Context_len);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(
+ rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ PUSH_BE_U32(buf, 0, L);
+ rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(
+ rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ }
+
+ gnutls_hmac_output(hmac_hnd, digest);
+
+ return NT_STATUS_OK;
+}
+
+static size_t ceiling_div(const size_t a, const size_t b)
+{
+ return a / b + (a % b != 0);
+}
+
+/**
+ * @brief Derive a key using the NIST SP 800‐108 algorithm.
+ *
+ * The details of the algorithm can be found at
+ * https://csrc.nist.gov/pubs/sp/800/108/r1/final.
+ *
+ * @param KI The key‐derivation key used as input.
+ *
+ * @param KI_len The length of the key‐derivation key.
+ *
+ * @param FixedData If non‐NULL, specifies fixed data to be used in place of
+ * that constructed from the Label and Context parameters.
+ *
+ * @param FixedData_len The length of the fixed data, if it is present.
+ *
+ * @param Label A label that identifies the purpose for the derived key.
+ * Ignored if FixedData is non‐NULL.
+ *
+ * @param Label_len The length of the label.
+ *
+ * @param Context Information related to the derived key. Ignored if
+ * FixedData is non‐NULL.
+ *
+ * @param Context_len The length of the context data.
+ *
+ * @param algorithm The HMAC algorithm to use.
+ *
+ * @param KO A buffer to receive the derived key.
+ *
+ * @param KO_len The length of the key to be derived.
+ *
+ * @return NT_STATUS_OK on success, an NT status error code otherwise.
+ */
+NTSTATUS samba_gnutls_sp800_108_derive_key(
+ const uint8_t *KI,
+ size_t KI_len,
+ const uint8_t *FixedData,
+ size_t FixedData_len,
+ const uint8_t *Label,
+ size_t Label_len,
+ const uint8_t *Context,
+ size_t Context_len,
+ const gnutls_mac_algorithm_t algorithm,
+ uint8_t *KO,
+ size_t KO_len)
+{
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ const size_t digest_len = gnutls_hmac_get_len(algorithm);
+ uint32_t i;
+ uint32_t L = KO_len * 8;
+ size_t KO_idx;
+ NTSTATUS status = NT_STATUS_OK;
+ int rc;
+
+ if (KO_len > UINT32_MAX / 8) {
+ /* The calculation of L has overflowed. */
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (digest_len == 0) {
+ return NT_STATUS_HMAC_NOT_SUPPORTED;
+ }
+
+ {
+ const size_t n_iterations = ceiling_div(KO_len, digest_len);
+ /*
+ * To ensure that the counter values are distinct, n shall not
+ * be larger than 2ʳ−1, where r = 32. We have made sure that
+ * |KO| × 8 < 2³², and we know that n ≤ |KO| from its
+ * definition. Thus n ≤ |KO| ≤ |KO| × 8 < 2³², and so the
+ * requirement n ≤ 2³² − 1 must always hold.
+ */
+ SMB_ASSERT(n_iterations <= UINT32_MAX);
+ }
+
+ /*
+ * a simplified version of
+ * "NIST Special Publication 800-108" section 5.1.
+ */
+ rc = gnutls_hmac_init(&hmac_hnd,
+ algorithm,
+ KI,
+ KI_len);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ /* (This loop would make an excellent candidate for parallelization.) */
+
+ for (KO_idx = 0, i = 1; KO_len - KO_idx >= digest_len;
+ KO_idx += digest_len, ++i)
+ {
+ status = samba_gnutls_sp800_108_derive_key_part(hmac_hnd,
+ FixedData,
+ FixedData_len,
+ Label,
+ Label_len,
+ Context,
+ Context_len,
+ L,
+ i,
+ KO + KO_idx);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ }
+
+ if (KO_idx < KO_len) {
+ /* Get the last little bit. */
+ uint8_t digest[digest_len];
+ status = samba_gnutls_sp800_108_derive_key_part(hmac_hnd,
+ FixedData,
+ FixedData_len,
+ Label,
+ Label_len,
+ Context,
+ Context_len,
+ L,
+ i,
+ digest);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ memcpy(KO + KO_idx, digest, KO_len - KO_idx);
+
+ ZERO_ARRAY(digest);
+ }
+
+out:
+ if (hmac_hnd != NULL) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Hide the evidence. */
+ memset_s(KO, KO_len, 0, KO_idx);
+ }
+
+ return status;
+}
diff --git a/lib/crypto/gnutls_weak_crypto.c b/lib/crypto/gnutls_weak_crypto.c
new file mode 100644
index 0000000..dcc53bb
--- /dev/null
+++ b/lib/crypto/gnutls_weak_crypto.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/crypto/gnutls_helpers.h"
+
+#include <gnutls/crypto.h>
+#include <gnutls/gnutls.h>
+
+bool samba_gnutls_weak_crypto_allowed(void)
+{
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t key = {
+ .data = discard_const_p(unsigned char, "SystemLibraryDTC"),
+ .size = 16,
+ };
+ int rc;
+
+ /*
+ * If we can't initialize RC4 then weak crypto is not allowed.
+ */
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &key,
+ NULL);
+ if (rc == GNUTLS_E_UNWANTED_ALGORITHM) {
+ return false;
+ }
+
+ gnutls_cipher_deinit(cipher_hnd);
+
+ return true;
+}
diff --git a/lib/crypto/md4.c b/lib/crypto/md4.c
new file mode 100644
index 0000000..831fe32
--- /dev/null
+++ b/lib/crypto/md4.c
@@ -0,0 +1,179 @@
+/*
+ Unix SMB/CIFS implementation.
+ a implementation of MD4 designed for use in the SMB authentication protocol
+ Copyright (C) Andrew Tridgell 1997-1998.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "../lib/crypto/md4.h"
+
+/* NOTE: This code makes no attempt to be fast!
+
+ It assumes that a int is at least 32 bits long
+*/
+
+struct mdfour_state {
+ uint32_t A, B, C, D;
+};
+
+static uint32_t F(uint32_t X, uint32_t Y, uint32_t Z)
+{
+ return (X&Y) | ((~X)&Z);
+}
+
+static uint32_t G(uint32_t X, uint32_t Y, uint32_t Z)
+{
+ return (X&Y) | (X&Z) | (Y&Z);
+}
+
+static uint32_t H(uint32_t X, uint32_t Y, uint32_t Z)
+{
+ return X^Y^Z;
+}
+
+static uint32_t lshift(uint32_t x, int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32_t)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32_t)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64(struct mdfour_state *s, uint32_t *M)
+{
+ int j;
+ uint32_t AA, BB, CC, DD;
+ uint32_t X[16];
+
+ for (j=0;j<16;j++)
+ X[j] = M[j];
+
+ AA = s->A; BB = s->B; CC = s->C; DD = s->D;
+
+ ROUND1(s->A,s->B,s->C,s->D, 0, 3); ROUND1(s->D,s->A,s->B,s->C, 1, 7);
+ ROUND1(s->C,s->D,s->A,s->B, 2, 11); ROUND1(s->B,s->C,s->D,s->A, 3, 19);
+ ROUND1(s->A,s->B,s->C,s->D, 4, 3); ROUND1(s->D,s->A,s->B,s->C, 5, 7);
+ ROUND1(s->C,s->D,s->A,s->B, 6, 11); ROUND1(s->B,s->C,s->D,s->A, 7, 19);
+ ROUND1(s->A,s->B,s->C,s->D, 8, 3); ROUND1(s->D,s->A,s->B,s->C, 9, 7);
+ ROUND1(s->C,s->D,s->A,s->B, 10, 11); ROUND1(s->B,s->C,s->D,s->A, 11, 19);
+ ROUND1(s->A,s->B,s->C,s->D, 12, 3); ROUND1(s->D,s->A,s->B,s->C, 13, 7);
+ ROUND1(s->C,s->D,s->A,s->B, 14, 11); ROUND1(s->B,s->C,s->D,s->A, 15, 19);
+
+ ROUND2(s->A,s->B,s->C,s->D, 0, 3); ROUND2(s->D,s->A,s->B,s->C, 4, 5);
+ ROUND2(s->C,s->D,s->A,s->B, 8, 9); ROUND2(s->B,s->C,s->D,s->A, 12, 13);
+ ROUND2(s->A,s->B,s->C,s->D, 1, 3); ROUND2(s->D,s->A,s->B,s->C, 5, 5);
+ ROUND2(s->C,s->D,s->A,s->B, 9, 9); ROUND2(s->B,s->C,s->D,s->A, 13, 13);
+ ROUND2(s->A,s->B,s->C,s->D, 2, 3); ROUND2(s->D,s->A,s->B,s->C, 6, 5);
+ ROUND2(s->C,s->D,s->A,s->B, 10, 9); ROUND2(s->B,s->C,s->D,s->A, 14, 13);
+ ROUND2(s->A,s->B,s->C,s->D, 3, 3); ROUND2(s->D,s->A,s->B,s->C, 7, 5);
+ ROUND2(s->C,s->D,s->A,s->B, 11, 9); ROUND2(s->B,s->C,s->D,s->A, 15, 13);
+
+ ROUND3(s->A,s->B,s->C,s->D, 0, 3); ROUND3(s->D,s->A,s->B,s->C, 8, 9);
+ ROUND3(s->C,s->D,s->A,s->B, 4, 11); ROUND3(s->B,s->C,s->D,s->A, 12, 15);
+ ROUND3(s->A,s->B,s->C,s->D, 2, 3); ROUND3(s->D,s->A,s->B,s->C, 10, 9);
+ ROUND3(s->C,s->D,s->A,s->B, 6, 11); ROUND3(s->B,s->C,s->D,s->A, 14, 15);
+ ROUND3(s->A,s->B,s->C,s->D, 1, 3); ROUND3(s->D,s->A,s->B,s->C, 9, 9);
+ ROUND3(s->C,s->D,s->A,s->B, 5, 11); ROUND3(s->B,s->C,s->D,s->A, 13, 15);
+ ROUND3(s->A,s->B,s->C,s->D, 3, 3); ROUND3(s->D,s->A,s->B,s->C, 11, 9);
+ ROUND3(s->C,s->D,s->A,s->B, 7, 11); ROUND3(s->B,s->C,s->D,s->A, 15, 15);
+
+ s->A += AA;
+ s->B += BB;
+ s->C += CC;
+ s->D += DD;
+
+ s->A &= 0xFFFFFFFF;
+ s->B &= 0xFFFFFFFF;
+ s->C &= 0xFFFFFFFF;
+ s->D &= 0xFFFFFFFF;
+
+ for (j=0;j<16;j++)
+ X[j] = 0;
+}
+
+static void copy64(uint32_t *M, const uint8_t *in)
+{
+ int i;
+
+ for (i=0;i<16;i++)
+ M[i] = ((uint32_t)in[i*4+3] << 24) |
+ ((uint32_t)in[i*4+2] << 16) |
+ ((uint32_t)in[i*4+1] << 8) |
+ ((uint32_t)in[i*4+0] << 0);
+}
+
+static void copy4(uint8_t *out, uint32_t x)
+{
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+}
+
+/**
+ * produce a md4 message digest from data of length n bytes
+ */
+_PUBLIC_ void mdfour(uint8_t *out, const uint8_t *in, int n)
+{
+ uint8_t buf[128];
+ uint32_t M[16];
+ uint32_t b = n * 8;
+ int i;
+ struct mdfour_state state;
+
+ state.A = 0x67452301;
+ state.B = 0xefcdab89;
+ state.C = 0x98badcfe;
+ state.D = 0x10325476;
+
+ while (n > 64) {
+ copy64(M, in);
+ mdfour64(&state, M);
+ in += 64;
+ n -= 64;
+ }
+
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ memcpy(buf, in, n);
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf+56, b);
+ copy64(M, buf);
+ mdfour64(&state, M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(&state, M);
+ copy64(M, buf+64);
+ mdfour64(&state, M);
+ }
+
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ copy64(M, buf);
+
+ copy4(out, state.A);
+ copy4(out+4, state.B);
+ copy4(out+8, state.C);
+ copy4(out+12, state.D);
+}
+
+
diff --git a/lib/crypto/md4.h b/lib/crypto/md4.h
new file mode 100644
index 0000000..234e488
--- /dev/null
+++ b/lib/crypto/md4.h
@@ -0,0 +1 @@
+void mdfour(uint8_t *out, const uint8_t *in, int n);
diff --git a/lib/crypto/md4test.c b/lib/crypto/md4test.c
new file mode 100644
index 0000000..1899dcd
--- /dev/null
+++ b/lib/crypto/md4test.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+ MD4 tests
+ Copyright (C) Stefan Metzmacher 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "../lib/util/samba_util.h"
+#include "lib/crypto/md4.h"
+
+struct torture_context;
+bool torture_local_crypto_md4(struct torture_context *torture);
+
+/*
+ This uses the test values from rfc1320
+*/
+bool torture_local_crypto_md4(struct torture_context *torture)
+{
+ bool ret = true;
+ uint32_t i;
+ struct {
+ const char *data;
+ const char *md4;
+ } testarray[] = {
+ {
+ .data = "",
+ .md4 = "31d6cfe0d16ae931b73c59d7e0c089c0"
+ },{
+ .data = "a",
+ .md4 = "bde52cb31de33e46245e05fbdbd6fb24"
+ },{
+ .data = "abc",
+ .md4 = "a448017aaf21d8525fc10ae87aa6729d"
+ },{
+ .data = "message digest",
+ .md4 = "d9130a8164549fe818874806e1c7014b"
+ },{
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ .md4 = "d79e1c308aa5bbcdeea8ed63df412da9"
+ },{
+ .data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .md4 = "043f8582f241db351ce627e153e7f0e4"
+ },{
+ .data = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .md4 = "e33b4ddc9c38f2199c3e7b164fcc0536"
+ }
+ };
+
+ for (i=0; i < ARRAY_SIZE(testarray); i++) {
+ uint8_t md4[16];
+ int e;
+ DATA_BLOB data;
+ DATA_BLOB md4blob;
+
+ data = data_blob_string_const(testarray[i].data);
+ md4blob = strhex_to_data_blob(NULL, testarray[i].md4);
+
+ mdfour(md4, data.data, data.length);
+
+ e = memcmp(md4blob.data, md4, MIN(md4blob.length, sizeof(md4)));
+ if (e != 0) {
+ printf("md4 test[%u]: failed\n", i);
+ dump_data(0, data.data, data.length);
+ dump_data(0, md4blob.data, md4blob.length);
+ dump_data(0, md4, sizeof(md4));
+ ret = false;
+ }
+ talloc_free(md4blob.data);
+ }
+
+ return ret;
+}
diff --git a/lib/crypto/py_crypto.c b/lib/crypto/py_crypto.c
new file mode 100644
index 0000000..26a0a09
--- /dev/null
+++ b/lib/crypto/py_crypto.c
@@ -0,0 +1,444 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba crypto functions
+
+ Copyright (C) Alexander Bokovoy <ab@samba.org> 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include "includes.h"
+#include "python/py3compat.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include "lib/crypto/gnutls_helpers.h"
+#include "lib/crypto/md4.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/util/pyerrors.h"
+
+static bool samba_gnutls_datum_from_PyObject(PyObject *py_obj,
+ gnutls_datum_t *datum)
+{
+ uint8_t *data = NULL;
+ Py_ssize_t size;
+
+ int ret;
+
+ ret = PyBytes_AsStringAndSize(py_obj,
+ (char **)&data,
+ &size);
+ if (ret != 0) {
+ return false;
+ }
+
+ datum->data = data;
+ datum->size = size;
+
+ return true;
+}
+
+static bool samba_DATA_BLOB_from_PyObject(PyObject *py_obj,
+ DATA_BLOB *blob)
+{
+ uint8_t *data = NULL;
+ Py_ssize_t size;
+
+ int ret;
+
+ ret = PyBytes_AsStringAndSize(py_obj,
+ (char **)&data,
+ &size);
+ if (ret != 0) {
+ return false;
+ }
+
+ blob->data = data;
+ blob->length = size;
+
+ return true;
+}
+
+static PyObject *py_crypto_arcfour_crypt_blob(PyObject *module, PyObject *args)
+{
+ DATA_BLOB data;
+ PyObject *py_data, *py_key, *result;
+ TALLOC_CTX *ctx;
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t key;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "OO", &py_data, &py_key))
+ return NULL;
+
+ if (!PyBytes_Check(py_data)) {
+ PyErr_Format(PyExc_TypeError, "bytes expected");
+ return NULL;
+ }
+
+ if (!PyBytes_Check(py_key)) {
+ PyErr_Format(PyExc_TypeError, "bytes expected");
+ return NULL;
+ }
+
+ ctx = talloc_new(NULL);
+
+ data.length = PyBytes_Size(py_data);
+ data.data = talloc_memdup(ctx, PyBytes_AsString(py_data), data.length);
+ if (!data.data) {
+ talloc_free(ctx);
+ return PyErr_NoMemory();
+ }
+
+ key = (gnutls_datum_t) {
+ .data = (uint8_t *)PyBytes_AsString(py_key),
+ .size = PyBytes_Size(py_key),
+ };
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &key,
+ NULL);
+ if (rc < 0) {
+ talloc_free(ctx);
+ PyErr_Format(PyExc_OSError, "encryption failed");
+ return NULL;
+ }
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ data.data,
+ data.length);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ talloc_free(ctx);
+ PyErr_Format(PyExc_OSError, "encryption failed");
+ return NULL;
+ }
+
+ result = PyBytes_FromStringAndSize((const char*) data.data, data.length);
+ talloc_free(ctx);
+ return result;
+}
+
+static PyObject *py_crypto_set_relax_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ GNUTLS_FIPS140_SET_LAX_MODE();
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_crypto_set_strict_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ GNUTLS_FIPS140_SET_STRICT_MODE();
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_crypto_des_crypt_blob_16(PyObject *self, PyObject *args)
+{
+ PyObject *py_data = NULL;
+ uint8_t *data = NULL;
+ Py_ssize_t data_size;
+
+ PyObject *py_key = NULL;
+ uint8_t *key = NULL;
+ Py_ssize_t key_size;
+
+ uint8_t result[16];
+
+ bool ok;
+ int ret;
+
+ ok = PyArg_ParseTuple(args, "SS",
+ &py_data, &py_key);
+ if (!ok) {
+ return NULL;
+ }
+
+ ret = PyBytes_AsStringAndSize(py_data,
+ (char **)&data,
+ &data_size);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ ret = PyBytes_AsStringAndSize(py_key,
+ (char **)&key,
+ &key_size);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ if (data_size != 16) {
+ return PyErr_Format(PyExc_ValueError,
+ "Expected data size of 16 bytes; got %zd",
+ data_size);
+ }
+
+ if (key_size != 14) {
+ return PyErr_Format(PyExc_ValueError,
+ "Expected key size of 14 bytes; got %zd",
+ key_size);
+ }
+
+ ret = des_crypt112_16(result, data, key,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return PyErr_Format(PyExc_RuntimeError,
+ "des_crypt112_16() failed: %d",
+ ret);
+ }
+
+ return PyBytes_FromStringAndSize((const char *)result,
+ sizeof(result));
+}
+
+static PyObject *py_crypto_md4_hash_blob(PyObject *self, PyObject *args)
+{
+ PyObject *py_data = NULL;
+ uint8_t *data = NULL;
+ Py_ssize_t data_size;
+
+ uint8_t result[16];
+
+ bool ok;
+ int ret;
+
+ ok = PyArg_ParseTuple(args, "S",
+ &py_data);
+ if (!ok) {
+ return NULL;
+ }
+
+ ret = PyBytes_AsStringAndSize(py_data,
+ (char **)&data,
+ &data_size);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ mdfour(result, data, data_size);
+
+ return PyBytes_FromStringAndSize((const char *)result,
+ sizeof(result));
+}
+
+static PyObject *py_crypto_sha512_pbkdf2(PyObject *self, PyObject *args)
+{
+ PyObject *py_key = NULL;
+ uint8_t *key = NULL;
+ gnutls_datum_t key_datum = {0};
+
+ PyObject *py_salt = NULL;
+ gnutls_datum_t salt_datum = {0};
+
+ uint8_t result[16];
+
+ unsigned iterations = 0;
+
+ bool ok;
+ int ret;
+ NTSTATUS status;
+
+ ok = PyArg_ParseTuple(args, "SSI",
+ &py_key, &py_salt, &iterations);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = samba_gnutls_datum_from_PyObject(py_key, &key_datum);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = samba_gnutls_datum_from_PyObject(py_salt, &salt_datum);
+ if (!ok) {
+ return NULL;
+ }
+
+ ret = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
+ &key_datum,
+ &salt_datum,
+ iterations,
+ result,
+ sizeof(result));
+ BURN_DATA(key);
+ if (ret < 0) {
+ status = gnutls_error_to_ntstatus(ret, NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ return PyBytes_FromStringAndSize((const char *)result,
+ sizeof(result));
+}
+
+static PyObject *py_crypto_aead_aes_256_cbc_hmac_sha512_blob(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *ctx = NULL;
+
+ PyObject *py_ciphertext = NULL;
+ DATA_BLOB ciphertext_blob = {0};
+
+ PyObject *py_auth_data = NULL;
+ PyObject *py_result = NULL;
+
+ PyObject *py_plaintext = NULL;
+ DATA_BLOB plaintext_blob = {0};
+ PyObject *py_cek = NULL;
+ DATA_BLOB cek_blob = {0};
+ PyObject *py_key_salt = NULL;
+ DATA_BLOB key_salt_blob = {0};
+ PyObject *py_mac_salt = NULL;
+ DATA_BLOB mac_salt_blob = {0};
+ PyObject *py_iv = NULL;
+ DATA_BLOB iv_blob = {0};
+
+ uint8_t auth_data[64];
+
+ bool ok;
+ NTSTATUS status;
+
+ ok = PyArg_ParseTuple(args, "SSSSS",
+ &py_plaintext,
+ &py_cek,
+ &py_key_salt,
+ &py_mac_salt,
+ &py_iv);
+ if (!ok) {
+ return NULL;
+ }
+
+ /* Create data blobs from the contents of the function parameters. */
+
+ ok = samba_DATA_BLOB_from_PyObject(py_plaintext, &plaintext_blob);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = samba_DATA_BLOB_from_PyObject(py_cek, &cek_blob);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = samba_DATA_BLOB_from_PyObject(py_key_salt, &key_salt_blob);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = samba_DATA_BLOB_from_PyObject(py_mac_salt, &mac_salt_blob);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = samba_DATA_BLOB_from_PyObject(py_iv, &iv_blob);
+ if (!ok) {
+ return NULL;
+ }
+
+ ctx = talloc_new(NULL);
+ if (ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ /* Encrypt the plaintext. */
+ status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(ctx,
+ &plaintext_blob,
+ &cek_blob,
+ &key_salt_blob,
+ &mac_salt_blob,
+ &iv_blob,
+ &ciphertext_blob,
+ auth_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetNTSTATUS(status);
+ talloc_free(ctx);
+ return NULL;
+ }
+
+ /* Convert the output into Python 'bytes' objects. */
+ py_ciphertext = PyBytes_FromStringAndSize((const char *)ciphertext_blob.data,
+ ciphertext_blob.length);
+ talloc_free(ctx);
+ if (py_ciphertext == NULL) {
+ return NULL;
+ }
+ py_auth_data = PyBytes_FromStringAndSize((const char *)auth_data,
+ sizeof(auth_data));
+ if (py_auth_data == NULL) {
+ return NULL;
+ }
+
+ /* Steal ciphertext and auth_data into a new tuple. */
+ py_result = Py_BuildValue("(NN)", py_ciphertext, py_auth_data);
+
+ return py_result;
+}
+
+
+
+static const char py_crypto_arcfour_crypt_blob_doc[] = "arcfour_crypt_blob(data, key)\n"
+ "Encrypt the data with RC4 algorithm using the key";
+
+static const char py_crypto_des_crypt_blob_16_doc[] = "des_crypt_blob_16(data, key) -> bytes\n"
+ "Encrypt the 16-byte data with DES using "
+ "the 14-byte key";
+
+static const char py_crypto_md4_hash_blob_doc[] = "md4_hash_blob(data) -> bytes\n"
+ "Hash the data with MD4 algorithm";
+
+static const char py_crypto_sha512_pbkdf2_doc[] = "sha512_pbkdf2(key, salt, iterations) -> bytes\n"
+ "Derive a key from an existing one with SHA512 "
+ "algorithm";
+
+static const char py_crypto_aead_aes_256_cbc_hmac_sha512_blob_doc[] =
+ "aead_aes_256_cbc_hmac_sha512_blob(plaintext, cek, key_salt, "
+ "mac_salt, iv) -> ciphertext, auth_data\n"
+ "Encrypt the plaintext with AES256 as specified in "
+ "[MS-SAMR] 3.2.2.4 AES Cipher Usage";
+
+static PyMethodDef py_crypto_methods[] = {
+ { "arcfour_crypt_blob", (PyCFunction)py_crypto_arcfour_crypt_blob, METH_VARARGS, py_crypto_arcfour_crypt_blob_doc },
+ { "set_relax_mode", (PyCFunction)py_crypto_set_relax_mode, METH_NOARGS, "Set fips to relax mode" },
+ { "set_strict_mode", (PyCFunction)py_crypto_set_strict_mode, METH_NOARGS, "Set fips to strict mode" },
+ { "des_crypt_blob_16", (PyCFunction)py_crypto_des_crypt_blob_16, METH_VARARGS, py_crypto_des_crypt_blob_16_doc },
+ { "md4_hash_blob", (PyCFunction)py_crypto_md4_hash_blob, METH_VARARGS, py_crypto_md4_hash_blob_doc },
+ { "sha512_pbkdf2", (PyCFunction)py_crypto_sha512_pbkdf2, METH_VARARGS, py_crypto_sha512_pbkdf2_doc },
+ {
+ "aead_aes_256_cbc_hmac_sha512_blob",
+ (PyCFunction)py_crypto_aead_aes_256_cbc_hmac_sha512_blob,
+ METH_VARARGS,
+ py_crypto_aead_aes_256_cbc_hmac_sha512_blob_doc
+ },
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "crypto",
+ .m_doc = "Crypto functions required for SMB",
+ .m_size = -1,
+ .m_methods = py_crypto_methods,
+};
+
+MODULE_INIT_FUNC(crypto)
+{
+ PyObject *m;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ return m;
+}
diff --git a/lib/crypto/test_gkdi_key_derivation.c b/lib/crypto/test_gkdi_key_derivation.c
new file mode 100644
index 0000000..22f3356
--- /dev/null
+++ b/lib/crypto/test_gkdi_key_derivation.c
@@ -0,0 +1,492 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Catalyst.Net Ltd 2023
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "replace.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+#include "lib/crypto/gkdi.h"
+
+static const uint8_t gmsa_security_descriptor[] = {
+ /* O:SYD:(A;;FRFW;;;S-1-5-9) */
+ 0x01, 0x00, 0x04, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1c, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x9f, 0x01, 0x12, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00};
+
+#define GKID(l0_idx_, l1_idx_, l2_idx_) \
+ ((struct Gkid){.l0_idx = l0_idx_, .l1_idx = l1_idx_, .l2_idx = l2_idx_})
+
+#define GUID_LITERAL( \
+ time_low_, time_mid_, time_hi_and_version_, clock_seq_, node_) \
+ ((struct GUID){.time_low = (0x##time_low_), \
+ .time_mid = (0x##time_mid_), \
+ .time_hi_and_version = (0x##time_hi_and_version_), \
+ .clock_seq = {(uint32_t)(0x##clock_seq_) >> 8, \
+ (uint8_t)(0x##clock_seq_)}, \
+ .node = {(uint64_t)(0x##node_) >> 40, \
+ (uint8_t)((uint64_t)(0x##node_) >> 32), \
+ (uint8_t)((uint64_t)(0x##node_) >> 24), \
+ (uint8_t)((uint64_t)(0x##node_) >> 16), \
+ (uint8_t)((uint64_t)(0x##node_) >> 8), \
+ (uint8_t)(0x##node_)}})
+
+struct test_vector {
+ const char *name; /* The name of the test scenario. */
+ struct Gkid gkid; /* The GKID of the key to derive. */
+ struct ProvRootKey root_key;
+ NTSTATUS expected_status;
+ uint8_t expected_key[GKDI_KEY_LEN]; /* The expected derived key. */
+};
+
+#define DATA_BLOB_CONST(data_, length_) \
+ ((DATA_BLOB){.data = (discard_const_p(uint8_t, data_)), \
+ .length = (length_)})
+
+#define ARRAY(...) ((const uint8_t[]){__VA_ARGS__})
+#define ROOT_KEY_DATA(...) \
+ DATA_BLOB_CONST(ARRAY(__VA_ARGS__), sizeof(ARRAY(__VA_ARGS__)))
+#define EXPECTED_KEY(...) {__VA_ARGS__}
+#define ROOT_KEY_VERSION(version) (version)
+
+#define ARBITRARY_ROOT_KEY_DATA \
+ ROOT_KEY_DATA(72, 159, 53, 49, 197, 55, 119, 77, 67, 45, 107, \
+ 151, 227, 188, 31, 67, 210, 232, 198, 220, 23, 235, \
+ 14, 79, 217, 160, 135, 13, 47, 30, 191, 146, 226, \
+ 73, 102, 104, 168, 181, 189, 17, 174, 162, 211, 45, \
+ 10, 171, 113, 111, 72, 254, 86, 159, 92, 155, 80, \
+ 255, 63, 155, 245, 222, 174, 165, 114, 251)
+
+#define ARBITRARY_GUID GUID_LITERAL(4cdf4285, c46a, 62a3, 2f7d, 95f97342685b)
+
+#define SUCCESS_VECTOR( \
+ name_, root_key_id, algorithm, gkid_, root_key_data, expected_key_) \
+ { \
+ .name = (name_), .gkid = (gkid_), \
+ .root_key = {.version = root_key_version_1, \
+ .id = (root_key_id), \
+ .data = (root_key_data), \
+ .kdf_algorithm = \
+ {.id = KDF_ALGORITHM_SP800_108_CTR_HMAC, \
+ .param.sp800_108 = (algorithm)}}, \
+ .expected_status = NT_STATUS_OK, \
+ .expected_key = expected_key_, \
+ }
+
+#define FAILURE_VECTOR_VERSION(name_, \
+ root_key_id, \
+ algorithm, \
+ gkid_, \
+ root_key_version, \
+ root_key_data, \
+ expected_status_) \
+ { \
+ .name = (name_), .gkid = (gkid_), \
+ .root_key = {.version = (root_key_version), \
+ .id = (root_key_id), \
+ .data = (root_key_data), \
+ .kdf_algorithm = \
+ {.id = KDF_ALGORITHM_SP800_108_CTR_HMAC, \
+ .param.sp800_108 = (algorithm)}}, \
+ .expected_status = (expected_status_), .expected_key = {}, \
+ }
+
+#define FAILURE_VECTOR( \
+ name_, root_key_id, algorithm, gkid_, root_key_data, expected_status_) \
+ FAILURE_VECTOR_VERSION(name_, \
+ root_key_id, \
+ algorithm, \
+ gkid_, \
+ root_key_version_1, \
+ root_key_data, \
+ expected_status_)
+
+/* Test vectors derived from samba.tests.krb5.gkdi_tests Python tests. */
+static const struct test_vector gkdi_vectors[] = {
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_current_l0_idx_"
+ "l1_seed_key",
+ GUID_LITERAL(89f70521, 9d66, 441f, c314, 1b462f9b1052),
+ KDF_PARAM_SHA512,
+ GKID(255, 24, -1),
+ ROOT_KEY_DATA(166, 239, 135, 219, 187, 248, 107, 107, 190, 85,
+ 117, 11, 148, 31, 19, 202, 153, 239, 229, 24,
+ 94, 46, 43, 222, 213, 184, 56, 216, 160, 231,
+ 118, 71, 5, 55, 230, 140, 174, 69, 167, 160,
+ 244, 177, 214, 201, 191, 84, 148, 195, 248, 121,
+ 225, 114, 227, 38, 85, 124, 219, 182, 165, 110,
+ 135, 153, 167, 34),
+ EXPECTED_KEY(189, 83, 138, 7, 52, 144, 243, 207, 148, 81,
+ 201, 51, 2, 93, 233, 178, 44, 151, 234, 221,
+ 175, 250, 148, 179, 121, 226, 185, 25, 164, 190,
+ 209, 71, 91, 198, 127, 106, 145, 117, 177, 57,
+ 198, 146, 4, 197, 125, 67, 0, 160, 20, 31,
+ 254, 52, 209, 44, 237, 132, 97, 69, 147, 177,
+ 170, 19, 175, 28)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_current_l0_idx_"
+ "l2_seed_key",
+ GUID_LITERAL(1a3d6c30, aa81, cb7f, d3fe, 80775d135dfe),
+ KDF_PARAM_SHA512,
+ GKID(321, 0, 12),
+ ROOT_KEY_DATA(223, 217, 91, 227, 21, 58, 8, 5, 198, 86,
+ 148, 231, 210, 132, 170, 206, 90, 176, 170, 73,
+ 51, 80, 2, 94, 184, 219, 198, 223, 11, 78,
+ 146, 86, 251, 76, 191, 190, 98, 55, 206, 55,
+ 50, 105, 78, 38, 8, 118, 0, 118, 182, 112,
+ 130, 211, 154, 189, 60, 15, 237, 186, 27, 136,
+ 115, 100, 80, 100),
+ EXPECTED_KEY(187, 189, 147, 118, 205, 22, 194, 71, 237, 64,
+ 245, 145, 45, 25, 8, 33, 140, 8, 240, 145,
+ 91, 174, 2, 254, 2, 203, 251, 55, 83, 189,
+ 228, 6, 249, 197, 83, 172, 217, 81, 67, 207,
+ 99, 144, 106, 4, 64, 227, 207, 35, 125, 35,
+ 53, 174, 78, 75, 156, 210, 217, 70, 167, 19,
+ 81, 235, 203, 123)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_current_l0_idx_"
+ "both_seed_keys (next older L1)",
+ GUID_LITERAL(09de0b38, c743, 7abf, 44ea, 7a3c3e404314),
+ KDF_PARAM_SHA512,
+ GKID(123, 20, -1),
+ ROOT_KEY_DATA(213, 145, 45, 14, 179, 189, 96, 225, 55, 27,
+ 30, 82, 93, 216, 59, 231, 252, 91, 175, 119,
+ 1, 139, 13, 186, 107, 217, 72, 183, 169, 142,
+ 190, 90, 243, 118, 116, 51, 37, 6, 164, 108,
+ 82, 193, 8, 166, 47, 42, 62, 137, 37, 26,
+ 209, 189, 230, 213, 57, 0, 70, 121, 192, 101,
+ 136, 83, 187, 104),
+ EXPECTED_KEY(177, 247, 197, 137, 110, 125, 199, 145, 217, 192,
+ 170, 248, 202, 125, 186, 184, 193, 114, 164, 248,
+ 184, 115, 219, 72, 138, 60, 76, 189, 15, 85,
+ 155, 17, 82, 255, 186, 57, 212, 175, 242, 217,
+ 232, 170, 218, 144, 178, 122, 60, 148, 165, 175,
+ 153, 111, 75, 143, 88, 74, 79, 55, 204, 171,
+ 77, 80, 93, 61)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_current_l0_idx_"
+ "both_seed_keys (L2)",
+ GUID_LITERAL(09de0b38, c743, 7abf, 44ea, 7a3c3e404314),
+ KDF_PARAM_SHA512,
+ GKID(123, 21, 0),
+ ROOT_KEY_DATA(213, 145, 45, 14, 179, 189, 96, 225, 55, 27,
+ 30, 82, 93, 216, 59, 231, 252, 91, 175, 119,
+ 1, 139, 13, 186, 107, 217, 72, 183, 169, 142,
+ 190, 90, 243, 118, 116, 51, 37, 6, 164, 108,
+ 82, 193, 8, 166, 47, 42, 62, 137, 37, 26,
+ 209, 189, 230, 213, 57, 0, 70, 121, 192, 101,
+ 136, 83, 187, 104),
+ EXPECTED_KEY(19, 60, 155, 189, 32, 217, 34, 122, 235, 56,
+ 223, 205, 59, 230, 188, 191, 197, 152, 59, 163,
+ 114, 2, 8, 143, 245, 200, 167, 5, 17, 33,
+ 69, 6, 166, 156, 25, 90, 136, 7, 205, 132,
+ 75, 203, 149, 94, 149, 105, 200, 228, 209, 151,
+ 117, 159, 40, 87, 124, 193, 38, 209, 95, 22,
+ 167, 218, 78, 224)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_previous_l0_"
+ "idx",
+ GUID_LITERAL(27136e8f, e093, 6fe3, e57f, 1d915b102e1c),
+ KDF_PARAM_SHA512,
+ GKID(100, 31, -1),
+ ROOT_KEY_DATA(180, 17, 24, 198, 10, 25, 202, 250, 94, 207,
+ 133, 141, 26, 42, 34, 22, 82, 123, 45, 174,
+ 223, 56, 110, 157, 89, 158, 66, 164, 106, 221,
+ 108, 125, 201, 56, 104, 97, 151, 97, 200, 128,
+ 255, 54, 116, 167, 124, 110, 95, 191, 52, 52,
+ 209, 48, 169, 114, 123, 178, 205, 42, 37, 87,
+ 189, 207, 199, 82),
+ EXPECTED_KEY(147, 92, 189, 192, 97, 152, 235, 40, 250, 68,
+ 184, 216, 39, 143, 81, 7, 44, 70, 19, 153,
+ 146, 54, 88, 80, 65, 237, 232, 231, 45, 2,
+ 254, 149, 227, 69, 79, 4, 99, 130, 203, 192,
+ 167, 0, 119, 155, 121, 71, 77, 215, 224, 128,
+ 80, 157, 118, 48, 45, 41, 55, 64, 126, 150,
+ 227, 211, 208, 34)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_sha1 (next "
+ "older L1)",
+ GUID_LITERAL(970abad6, fe55, 073a, caf1, b801d3f26bd3),
+ KDF_PARAM_SHA1,
+ GKID(1, 1, -1),
+ ROOT_KEY_DATA(59, 237, 3, 191, 15, 183, 212, 1, 49, 73,
+ 21, 79, 36, 202, 45, 89, 185, 141, 182, 213,
+ 136, 203, 31, 84, 236, 160, 131, 133, 94, 37,
+ 235, 40, 211, 86, 42, 1, 173, 199, 140, 75,
+ 112, 224, 183, 42, 89, 81, 88, 99, 231, 115,
+ 43, 133, 63, 186, 2, 221, 118, 70, 230, 49,
+ 8, 68, 18, 17),
+ EXPECTED_KEY(87, 108, 182, 143, 46, 82, 235, 115, 159, 129,
+ 123, 72, 140, 53, 144, 216, 111, 28, 44, 54,
+ 95, 63, 201, 32, 29, 156, 127, 238, 116, 148,
+ 133, 61, 88, 116, 110, 225, 62, 72, 241, 138,
+ 166, 250, 105, 247, 21, 125, 227, 208, 125, 227,
+ 78, 19, 131, 103, 146, 183, 192, 136, 255, 182,
+ 145, 74, 137, 194)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_sha1 (L2)",
+ GUID_LITERAL(970abad6, fe55, 073a, caf1, b801d3f26bd3),
+ KDF_PARAM_SHA1,
+ GKID(1, 2, 3),
+ ROOT_KEY_DATA(59, 237, 3, 191, 15, 183, 212, 1, 49, 73,
+ 21, 79, 36, 202, 45, 89, 185, 141, 182, 213,
+ 136, 203, 31, 84, 236, 160, 131, 133, 94, 37,
+ 235, 40, 211, 86, 42, 1, 173, 199, 140, 75,
+ 112, 224, 183, 42, 89, 81, 88, 99, 231, 115,
+ 43, 133, 63, 186, 2, 221, 118, 70, 230, 49,
+ 8, 68, 18, 17),
+ EXPECTED_KEY(63, 251, 130, 90, 218, 241, 22, 182, 83, 50,
+ 7, 213, 104, 163, 14, 211, 211, 242, 28, 104,
+ 132, 9, 65, 201, 69, 102, 132, 249, 175, 161,
+ 27, 5, 110, 12, 89, 57, 27, 77, 136, 196,
+ 149, 217, 132, 195, 214, 128, 2, 156, 197, 197,
+ 148, 99, 15, 52, 23, 145, 25, 193, 197, 172,
+ 170, 229, 233, 14)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_sha256 (next "
+ "older L1)",
+ GUID_LITERAL(45e26207, ed33, dcd5, 925a, 518a0deef69e),
+ KDF_PARAM_SHA256,
+ GKID(222, 21, -1),
+ ROOT_KEY_DATA(40, 181, 182, 80, 61, 60, 29, 36, 129, 77,
+ 231, 129, 187, 123, 252, 227, 239, 105, 238, 209,
+ 206, 72, 9, 55, 43, 238, 44, 80, 98, 112,
+ 197, 240, 181, 198, 223, 89, 116, 114, 98, 63,
+ 37, 108, 134, 218, 160, 153, 30, 138, 17, 161,
+ 112, 95, 33, 178, 207, 220, 11, 185, 219, 75,
+ 162, 50, 70, 162),
+ EXPECTED_KEY(87, 172, 237, 110, 117, 248, 63, 58, 244, 248,
+ 121, 179, 139, 96, 240, 144, 180, 46, 75, 250,
+ 2, 47, 174, 62, 111, 217, 66, 128, 180, 105,
+ 176, 236, 21, 216, 184, 83, 168, 112, 181, 251,
+ 223, 40, 112, 140, 206, 25, 39, 59, 116, 165,
+ 115, 172, 190, 13, 237, 168, 239, 81, 93, 180,
+ 105, 30, 45, 203)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_sha256 (L2)",
+ GUID_LITERAL(45e26207, ed33, dcd5, 925a, 518a0deef69e),
+ KDF_PARAM_SHA256,
+ GKID(222, 22, 22),
+ ROOT_KEY_DATA(40, 181, 182, 80, 61, 60, 29, 36, 129, 77,
+ 231, 129, 187, 123, 252, 227, 239, 105, 238, 209,
+ 206, 72, 9, 55, 43, 238, 44, 80, 98, 112,
+ 197, 240, 181, 198, 223, 89, 116, 114, 98, 63,
+ 37, 108, 134, 218, 160, 153, 30, 138, 17, 161,
+ 112, 95, 33, 178, 207, 220, 11, 185, 219, 75,
+ 162, 50, 70, 162),
+ EXPECTED_KEY(117, 42, 8, 121, 174, 36, 36, 192, 80, 76,
+ 116, 147, 89, 159, 19, 229, 136, 225, 187, 220,
+ 37, 47, 131, 50, 90, 213, 177, 251, 145, 194,
+ 76, 137, 1, 212, 64, 243, 255, 159, 251, 165,
+ 159, 205, 101, 187, 151, 87, 50, 217, 243, 131,
+ 221, 80, 184, 152, 23, 75, 185, 57, 62, 56,
+ 61, 37, 213, 64)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_sha384 (next "
+ "older L1)",
+ GUID_LITERAL(66e6d9f7, 4924, f3fc, fe34, 605634d42ebd),
+ KDF_PARAM_SHA384,
+ GKID(287, 27, -1),
+ ROOT_KEY_DATA(35, 229, 186, 134, 203, 216, 143, 123, 67, 46,
+ 230, 109, 187, 3, 191, 78, 235, 244, 1, 203,
+ 252, 61, 247, 53, 212, 215, 40, 181, 3, 200,
+ 127, 132, 50, 7, 198, 246, 21, 63, 25, 13,
+ 254, 133, 168, 108, 184, 216, 183, 77, 241, 59,
+ 37, 48, 89, 129, 190, 141, 126, 41, 201, 110,
+ 229, 76, 150, 48),
+ EXPECTED_KEY(250, 186, 221, 122, 154, 99, 223, 87, 214, 131,
+ 45, 247, 167, 53, 174, 187, 110, 24, 24, 136,
+ 178, 234, 243, 1, 162, 228, 255, 154, 112, 36,
+ 109, 56, 171, 29, 36, 22, 50, 91, 243, 235,
+ 114, 106, 2, 103, 186, 180, 189, 149, 12, 114,
+ 145, 240, 94, 165, 241, 113, 151, 236, 229, 105,
+ 146, 175, 62, 184)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_sha384 (L2)",
+ GUID_LITERAL(66e6d9f7, 4924, f3fc, fe34, 605634d42ebd),
+ KDF_PARAM_SHA384,
+ GKID(287, 28, 27),
+ ROOT_KEY_DATA(35, 229, 186, 134, 203, 216, 143, 123, 67, 46,
+ 230, 109, 187, 3, 191, 78, 235, 244, 1, 203,
+ 252, 61, 247, 53, 212, 215, 40, 181, 3, 200,
+ 127, 132, 50, 7, 198, 246, 21, 63, 25, 13,
+ 254, 133, 168, 108, 184, 216, 183, 77, 241, 59,
+ 37, 48, 89, 129, 190, 141, 126, 41, 201, 110,
+ 229, 76, 150, 48),
+ EXPECTED_KEY(236, 28, 101, 99, 75, 86, 148, 129, 142, 29,
+ 52, 29, 169, 153, 109, 184, 242, 161, 239, 106,
+ 44, 119, 106, 113, 38, 167, 235, 209, 139, 55,
+ 160, 115, 175, 218, 196, 76, 65, 177, 103, 177,
+ 78, 75, 135, 45, 72, 91, 187, 109, 123, 112,
+ 150, 66, 21, 208, 232, 74, 47, 241, 66, 169,
+ 217, 67, 242, 5)),
+ SUCCESS_VECTOR(
+ "samba.tests.krb5.gkdi_tests.GkdiSelfTests.test_derive_key_"
+ "exact",
+ GUID_LITERAL(d95fb06f, 5a9c, 1829, e20d, 27f3f2ecfbeb),
+ KDF_PARAM_SHA512,
+ GKID(333, 22, 11),
+ ROOT_KEY_DATA(72, 159, 53, 49, 197, 55, 119, 77, 67, 45,
+ 107, 151, 227, 188, 31, 67, 210, 232, 198, 220,
+ 23, 235, 14, 79, 217, 160, 135, 13, 47, 30,
+ 191, 146, 226, 73, 102, 104, 168, 181, 189, 17,
+ 174, 162, 211, 45, 10, 171, 113, 111, 72, 254,
+ 86, 159, 92, 155, 80, 255, 63, 155, 245, 222,
+ 174, 165, 114, 251),
+ EXPECTED_KEY(214, 171, 59, 20, 244, 244, 200, 144, 138, 163,
+ 70, 64, 17, 179, 159, 16, 168, 191, 173, 185,
+ 151, 74, 249, 15, 125, 154, 159, 237, 226, 253,
+ 198, 229, 246, 138, 98, 142, 192, 15, 153, 148,
+ 163, 171, 216, 165, 42, 233, 226, 219, 79, 104,
+ 232, 54, 72, 49, 30, 157, 119, 101, 242, 83,
+ 85, 21, 181, 226)),
+ FAILURE_VECTOR_VERSION("unsupported root key version (0)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(0, 0, 0),
+ ROOT_KEY_VERSION(0),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_NOT_SUPPORTED),
+ FAILURE_VECTOR_VERSION("unsupported root key version (2)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(0, 0, 0),
+ ROOT_KEY_VERSION(2),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_NOT_SUPPORTED),
+ FAILURE_VECTOR("unsupported algorithm (−1)",
+ ARBITRARY_GUID,
+ -1 /* an unsupported algorithm */,
+ GKID(0, 0, 0),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_NOT_SUPPORTED),
+ FAILURE_VECTOR("wrong length (32 bytes short) for root key data",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(0, 0, 0),
+ ROOT_KEY_DATA(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31),
+ NT_STATUS_NOT_SUPPORTED),
+ FAILURE_VECTOR("default GKID (−1, −1, −1)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(-1, -1, -1),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("invalid GKID (−2, −1, −1)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(-2, -1, -1),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("invalid GKID (−1, 0, 0)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(-1, 0, 0),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("invalid GKID (0, −1, 0)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(0, -1, 0),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("invalid GKID (0, −2, −1)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(0, -2, -1),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("invalid GKID (0, 0, −2)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(0, 0, -2),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("invalid GKID (123, 0, 32)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(123, 0, 32),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("invalid GKID (456, 32, 0)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(456, 32, 0),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+ FAILURE_VECTOR("try to derive L0 seed key (333, −1, −1)",
+ ARBITRARY_GUID,
+ KDF_PARAM_SHA512,
+ GKID(333, -1, -1),
+ ARBITRARY_ROOT_KEY_DATA,
+ NT_STATUS_INVALID_PARAMETER),
+};
+
+static void test_gkdi_key_derivation(void **state)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ size_t n;
+
+ mem_ctx = talloc_new(NULL);
+ assert_non_null(mem_ctx);
+
+ for (n = 0; n < ARRAY_SIZE(gkdi_vectors); ++n) {
+ const struct test_vector *test_vector = &gkdi_vectors[n];
+ uint8_t out[GKDI_KEY_LEN] = {};
+ NTSTATUS status;
+
+ print_message("Running: %s\n", test_vector->name);
+
+ status = compute_seed_key(
+ mem_ctx,
+ DATA_BLOB_CONST(gmsa_security_descriptor,
+ sizeof gmsa_security_descriptor),
+ &test_vector->root_key,
+ test_vector->gkid,
+ out);
+ assert_int_equal(NT_STATUS_V(test_vector->expected_status),
+ NT_STATUS_V(status));
+ assert_memory_equal(test_vector->expected_key,
+ out,
+ GKDI_KEY_LEN);
+ }
+
+ talloc_free(mem_ctx);
+}
+
+int main(int argc, char *argv[])
+{
+ static const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_gkdi_key_derivation),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/crypto/tests/test_gnutls_aead_aes_256_cbc_hmac_sha512.c b/lib/crypto/tests/test_gnutls_aead_aes_256_cbc_hmac_sha512.c
new file mode 100644
index 0000000..1b6b75f
--- /dev/null
+++ b/lib/crypto/tests/test_gnutls_aead_aes_256_cbc_hmac_sha512.c
@@ -0,0 +1,320 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2021-2022 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <talloc.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/discard.h"
+#include "lib/util/genrand.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/crypto/gnutls_helpers.h"
+#include "librpc/rpc/dcerpc_samr.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#include "lib/crypto/gnutls_aead_aes_256_cbc_hmac_sha512.c"
+
+/* The following hexdumps are from a Windows Server 2022 time trace */
+static const uint8_t session_key[] = {
+ 0x96, 0x17, 0x39, 0x9c, 0xa7, 0x54, 0x9e, 0x41,
+ 0xc4, 0x79, 0x71, 0x4b, 0xa0, 0x89, 0x5b, 0x0a
+};
+
+static const uint8_t salt_data[] = {
+ 0xac, 0x9c, 0xad, 0xcb, 0x66, 0xed, 0x2d, 0x05,
+ 0x55, 0x13, 0x18, 0xa9, 0xa5, 0x6b, 0xf9, 0x6f
+};
+
+static const uint8_t plaintext_data[] = {
+ 0x14, 0x00, 0x50, 0x00, 0x61, 0x00, 0x24, 0x00,
+ 0x24, 0x00, 0x77, 0x00, 0x30, 0x00, 0x72, 0x00,
+ 0x64, 0x00, 0x40, 0x00, 0x32, 0x00, 0xc2, 0x34,
+ 0x7d, 0x21, 0x79, 0x05, 0xef, 0x88, 0xd7, 0x11,
+ 0xec, 0xe2, 0xce, 0xb5, 0xd4, 0x4d, 0x64, 0x2d,
+ 0x15, 0x79, 0x01, 0x39, 0xb8, 0xb9, 0x89, 0x5c,
+ 0x4e, 0x71, 0xbd, 0xf0, 0x14, 0x0c, 0x87, 0x72,
+ 0xa5, 0xfa, 0x90, 0xbe, 0x62, 0x55, 0xad, 0x7f,
+ 0xe9, 0x7f, 0x0d, 0x20, 0x19, 0x3a, 0x76, 0xbe,
+ 0xb2, 0x14, 0x6d, 0x5b, 0x25, 0x1c, 0x67, 0x3a,
+ 0x23, 0x45, 0x1f, 0x7e, 0x36, 0xa0, 0x95, 0xb7,
+ 0xa7, 0xb1, 0x33, 0xe1, 0xc4, 0xb6, 0xe6, 0x2d,
+ 0xd8, 0x2f, 0xe7, 0xdf, 0x01, 0xe8, 0xba, 0x02,
+ 0x54, 0x36, 0xe9, 0xb6, 0x5e, 0x00, 0x52, 0x9e,
+ 0x64, 0x00, 0xcb, 0x3c, 0x6d, 0x05, 0x43, 0x7d,
+ 0x01, 0x9c, 0x22, 0x18, 0x92, 0xe7, 0xa3, 0x55,
+ 0x65, 0x6d, 0x2e, 0xa3, 0x53, 0x6e, 0xc0, 0x67,
+ 0x26, 0xac, 0xaa, 0x98, 0xa4, 0xcb, 0xb4, 0x49,
+ 0x13, 0x60, 0xd4, 0x33, 0x2c, 0x77, 0x58, 0x5e,
+ 0x50, 0x45, 0xaa, 0x1e, 0x05, 0x15, 0x18, 0x59,
+ 0x55, 0xca, 0x14, 0x37, 0x31, 0xac, 0x63, 0xfc,
+ 0x63, 0xa8, 0x2a, 0xa9, 0x99, 0xec, 0x49, 0x87,
+ 0x64, 0x1d, 0x4e, 0xdd, 0xa3, 0xd0, 0xdc, 0x08,
+ 0x00, 0x17, 0xf4, 0x2f, 0x9c, 0x4a, 0x17, 0xc7,
+ 0xbd, 0x30, 0xb7, 0x0e, 0x81, 0xe4, 0xd5, 0x94,
+ 0x31, 0xff, 0xd6, 0xcc, 0xc6, 0xbb, 0x39, 0xcd,
+ 0x72, 0xfe, 0xa6, 0x3d, 0x0d, 0x88, 0x68, 0x40,
+ 0xf8, 0x51, 0x2b, 0xe6, 0xc9, 0xaa, 0x84, 0xf3,
+ 0xf4, 0x6e, 0x55, 0x37, 0xbf, 0x5d, 0x87, 0xce,
+ 0xa6, 0x80, 0x4f, 0x8f, 0x8f, 0x7b, 0xe8, 0x30,
+ 0xc3, 0x2e, 0x24, 0xc7, 0x3e, 0xf1, 0x9f, 0xa6,
+ 0x77, 0xca, 0x04, 0xbe, 0xb5, 0xe1, 0x40, 0x59,
+ 0x43, 0xc5, 0x30, 0xc8, 0xe7, 0xbf, 0xab, 0xfa,
+ 0x86, 0x62, 0xd9, 0x3a, 0x8e, 0xa9, 0x34, 0x73,
+ 0x20, 0x7b, 0x61, 0x1b, 0x0e, 0xca, 0x98, 0xec,
+ 0xa1, 0xc1, 0x78, 0xa9, 0xa7, 0x6c, 0x8c, 0xe3,
+ 0x21, 0x7d, 0xb9, 0x90, 0xe2, 0x73, 0x1a, 0x99,
+ 0x1d, 0x44, 0xa8, 0xd5, 0x7f, 0x0a, 0x59, 0x47,
+ 0xd0, 0xf5, 0x6c, 0x14, 0xff, 0x4a, 0x29, 0x20,
+ 0xb5, 0xfc, 0xe9, 0xf0, 0xa5, 0x35, 0x9e, 0x1c,
+ 0xa1, 0x4c, 0xec, 0xb5, 0x7d, 0x2d, 0x27, 0xff,
+ 0x7a, 0x42, 0x18, 0xb8, 0x53, 0x4e, 0xfb, 0xec,
+ 0xb1, 0xc1, 0x65, 0x2d, 0xa4, 0x69, 0x85, 0x56,
+ 0x61, 0x6d, 0x21, 0x66, 0x88, 0x31, 0xdf, 0xba,
+ 0x28, 0xc6, 0x9a, 0xf8, 0xb7, 0xf6, 0x2a, 0x43,
+ 0xba, 0x9b, 0x84, 0x14, 0xce, 0xa9, 0xc9, 0xf5,
+ 0x85, 0x6f, 0x31, 0x89, 0x8d, 0xfc, 0x25, 0x2e,
+ 0x98, 0x25, 0x5a, 0x03, 0xf0, 0xb8, 0x5d, 0x4a,
+ 0xd4, 0x4c, 0xc8, 0x62, 0x4e, 0xeb, 0x07, 0xc8,
+ 0x5c, 0x9e, 0x63, 0x30, 0xfe, 0x9f, 0x0f, 0x96,
+ 0xd0, 0xd7, 0x70, 0xad, 0xcd, 0x84, 0xbc, 0x1e,
+ 0x48, 0xa0, 0x20, 0x14, 0x10, 0xa4, 0xb1, 0x5b,
+ 0x05, 0x36, 0x9a, 0x6d, 0xb0, 0x10, 0x98, 0xbd,
+ 0x8d, 0xa2, 0xd1, 0xb2, 0xfa, 0x23, 0x37, 0xeb,
+ 0xb0, 0x04, 0x53, 0xcb, 0xa1, 0xa9, 0xc4, 0x88,
+ 0xdd, 0xf9, 0x80, 0xf5, 0xa9, 0xcd, 0x7b, 0xf8,
+ 0x77, 0x0b, 0x19, 0x84, 0x4c, 0xef, 0x2c, 0x14,
+ 0xa1, 0xdc, 0x9f, 0x2f, 0x41, 0xd0, 0xd0, 0x33,
+ 0x29, 0x8a, 0xb9, 0x39, 0x7e, 0xc9, 0x7f, 0xe7,
+ 0x63, 0x64, 0xa4, 0x7b, 0x4a, 0x6a, 0x33, 0xa7,
+ 0xaa, 0xf6, 0xca, 0x98, 0xc4, 0x9b, 0x62, 0x5b,
+ 0xcd, 0x53, 0x82, 0xbf, 0xf0, 0x0b, 0x9c, 0xe7,
+ 0xb2, 0x44, 0x1b, 0x88, 0x71, 0x61, 0xa1, 0x36,
+ 0x9e, 0x7a, 0x0a, 0x3c, 0x20, 0xd8, 0xff, 0xa1,
+ 0x23, 0x66
+};
+
+static const uint8_t expected_enc_key[] = {
+ 0xd9, 0xb2, 0x8b, 0xa1, 0x15, 0x74, 0xf6, 0x5a,
+ 0x73, 0xea, 0x82, 0xba, 0x99, 0x37, 0x54, 0x25,
+ 0x1b, 0x27, 0x20, 0xaa, 0xa3, 0xf7, 0xd5, 0x23,
+ 0x8f, 0x02, 0xe6, 0xe7, 0x21, 0x5b, 0xd2, 0xa9
+};
+
+static const uint8_t expected_mac_key[] = {
+ 0x8a, 0x04, 0x46, 0x6d, 0x5e, 0xe6, 0x2d, 0xb8,
+ 0x32, 0x9e, 0xab, 0xbe, 0xa4, 0x8b, 0x3f, 0x6c,
+ 0x3c, 0x1c, 0xa1, 0xaa, 0xb8, 0xec, 0x9c, 0x43,
+ 0xbc, 0x4b, 0x91, 0x35, 0x6f, 0x3a, 0xc4, 0xe2,
+ 0x62, 0x9b, 0xe8, 0x12, 0x63, 0x73, 0x94, 0x2a,
+ 0x59, 0x47, 0xfc, 0xd8, 0x78, 0x5d, 0x6d, 0x68,
+ 0x1b, 0x9f, 0x35, 0x31, 0x90, 0x27, 0xc8, 0xab,
+ 0x88, 0x8d, 0x80, 0xad, 0x7b, 0xea, 0xcd, 0xf5
+};
+
+static const uint8_t expected_auth_tag[] = {
+ 0x0a, 0x7a, 0xaf, 0x9e, 0xc1, 0x6e, 0x03, 0x12,
+ 0x51, 0x76, 0x04, 0xb2, 0x01, 0x17, 0xeb, 0x04,
+ 0xf3, 0xdd, 0xe3, 0xa7, 0x90, 0xfd, 0xc0, 0xca,
+ 0x96, 0x31, 0xbf, 0x30, 0x9e, 0xc5, 0x05, 0x5a,
+ 0xbc, 0xa8, 0xc1, 0xba, 0x56, 0x8f, 0x97, 0x5a,
+ 0x4e, 0x2a, 0x14, 0x0e, 0x4b, 0xf3, 0x6d, 0x9a,
+ 0x2a, 0x6e, 0xc3, 0x5e, 0x9d, 0x51, 0x0a, 0xf6,
+ 0xb2, 0x1b, 0xee, 0xe7, 0xf3, 0x09, 0x30, 0xc9,
+};
+
+static void torture_enc_key(void **state)
+{
+ DATA_BLOB key = data_blob_const(session_key, sizeof(session_key));
+ uint8_t enc_key[32] = {0};
+ NTSTATUS status;
+
+ status = calculate_enc_key(&key, &samr_aes256_enc_key_salt, enc_key);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ assert_memory_equal(expected_enc_key, enc_key, sizeof(enc_key));
+}
+
+static void torture_mac_key(void **state)
+{
+ DATA_BLOB key = data_blob_const(session_key, sizeof(session_key));
+ uint8_t mac_key[64] = {0};
+ NTSTATUS status;
+
+ status = calculate_mac_key(&key, &samr_aes256_mac_key_salt, mac_key);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ assert_memory_equal(expected_mac_key, mac_key, sizeof(mac_key));
+}
+
+static void torture_encrypt(void **state)
+{
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ DATA_BLOB cek = {
+ .data = discard_const_p(uint8_t, session_key),
+ .length = sizeof(session_key),
+ };
+ const DATA_BLOB plaintext = {
+ .data = discard_const_p(uint8_t, plaintext_data),
+ .length = sizeof(plaintext_data),
+ };
+ DATA_BLOB iv = {
+ .data = discard_const_p(uint8_t, salt_data),
+ .length = sizeof(salt_data),
+ };
+ DATA_BLOB ctext;
+ uint8_t auth_tag[64] = {0};
+
+ assert_int_equal(iv.length, 16);
+
+ status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(
+ frame,
+ &plaintext,
+ &cek,
+ &samr_aes256_enc_key_salt,
+ &samr_aes256_mac_key_salt,
+ &iv,
+ &ctext,
+ auth_tag);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_int_equal(ctext.length, 528);
+ assert_non_null(ctext.data);
+
+ assert_memory_equal(expected_auth_tag, auth_tag, sizeof(auth_tag));
+
+ TALLOC_FREE(frame);
+}
+
+static void torture_encrypt_decrypt(void **state)
+{
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ DATA_BLOB cek = data_blob_const(session_key, sizeof(session_key));
+ const DATA_BLOB plaintext =
+ data_blob_const(plaintext_data, sizeof(plaintext_data));
+ DATA_BLOB iv = data_blob_const(salt_data, sizeof(salt_data));
+ DATA_BLOB cipher_text;
+ uint8_t auth_tag[64] = {0};
+ DATA_BLOB plaintext_decrypted;
+
+ status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(
+ frame,
+ &plaintext,
+ &cek,
+ &samr_aes256_enc_key_salt,
+ &samr_aes256_mac_key_salt,
+ &iv,
+ &cipher_text,
+ auth_tag);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_int_equal(cipher_text.length, 528);
+ assert_in_range(cipher_text.length,
+ plaintext.length,
+ plaintext.length + 16);
+ assert_non_null(cipher_text.data);
+
+ status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
+ frame,
+ &cipher_text,
+ &cek,
+ &samr_aes256_enc_key_salt,
+ &samr_aes256_mac_key_salt,
+ &iv,
+ auth_tag,
+ &plaintext_decrypted);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_non_null(plaintext_decrypted.data);
+ assert_int_equal(plaintext_decrypted.length, plaintext.length);
+ assert_memory_equal(plaintext_decrypted.data,
+ plaintext.data,
+ plaintext.length);
+
+ TALLOC_FREE(frame);
+}
+
+/* The following hexdumps are from a Windows Server 2022 time trace */
+static uint8_t pbkdf2_nt_hash[] = {
+ 0xf8, 0x48, 0x54, 0xde, 0xb8, 0x36, 0x10, 0x33,
+ 0xca, 0xea, 0x5c, 0x95, 0x96, 0x66, 0x99, 0x38
+};
+
+static uint8_t pbkdf2_iv[] = {
+ 0xd5, 0xbe, 0x4f, 0xd7, 0xb6, 0x85, 0xd1, 0xea,
+ 0xfd, 0x3b, 0xf4, 0x29, 0x83, 0xce, 0x10, 0x44
+};
+
+static uint8_t expected_pbkdf2_derived_key[] = {
+ 0xf1, 0xe6, 0xb2, 0x6a, 0x78, 0x28, 0x63, 0x05,
+ 0x77, 0x38, 0xc9, 0x71, 0xd2, 0x05, 0x88, 0x58
+};
+
+static void torture_pbkdf2(void **state)
+{
+ gnutls_datum_t nt_key = {
+ .data = pbkdf2_nt_hash,
+ .size = sizeof(pbkdf2_nt_hash),
+ };
+ gnutls_datum_t iv_datum = {
+ .data = pbkdf2_iv,
+ .size = sizeof(pbkdf2_iv),
+ };
+ uint64_t pbkdf2_iterations = 23533;
+ uint8_t derived_key[16] = {0};
+ int rc;
+
+ rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
+ &nt_key,
+ &iv_datum,
+ pbkdf2_iterations,
+ derived_key,
+ sizeof(derived_key));
+ assert_int_equal(rc, 0);
+ assert_memory_equal(derived_key,
+ expected_pbkdf2_derived_key,
+ sizeof(derived_key));
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_enc_key),
+ cmocka_unit_test(torture_mac_key),
+ cmocka_unit_test(torture_encrypt),
+ cmocka_unit_test(torture_encrypt_decrypt),
+ cmocka_unit_test(torture_pbkdf2),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/lib/crypto/tests/test_gnutls_sp800_108.c b/lib/crypto/tests/test_gnutls_sp800_108.c
new file mode 100644
index 0000000..c11af1e
--- /dev/null
+++ b/lib/crypto/tests/test_gnutls_sp800_108.c
@@ -0,0 +1,394 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Catalyst.Net Ltd 2023
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <talloc.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/genrand.h"
+#include "lib/crypto/gnutls_helpers.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#include "lib/crypto/gnutls_helpers.h"
+
+struct test_vector {
+ const uint8_t *KI; /* The key‐derivation key used as input. */
+ size_t KI_len;
+ const uint8_t *input; /* Other data used as input. */
+ size_t input_len;
+ const uint8_t *KO; /* The expected derived key. */
+ size_t KO_len;
+ gnutls_mac_algorithm_t prf_algorithm;
+};
+
+#define TEST_VECTOR_ARRAY(...) (const uint8_t[]){__VA_ARGS__}
+#define TEST_VECTOR(key_in, data, key_out, algorithm) { \
+ .KI = TEST_VECTOR_ARRAY key_in, \
+ .KI_len = sizeof (TEST_VECTOR_ARRAY key_in), \
+ .input = TEST_VECTOR_ARRAY data, \
+ .input_len = sizeof (TEST_VECTOR_ARRAY data), \
+ .KO = TEST_VECTOR_ARRAY key_out, \
+ .KO_len = sizeof (TEST_VECTOR_ARRAY key_out), \
+ .prf_algorithm = (algorithm), \
+}
+
+/*
+ * A subset of the test vectors provided at
+ * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/KBKDF800-108/CounterMode.zip,
+ * and released into the public domain as per
+ * https://www.nist.gov/oism/copyrights.
+ *
+ * These cover SHA1, SHA224, SHA256, SHA384, and SHA512; with the counter
+ * located before the input data, an r length of 32, and various values for L.
+ */
+static const struct test_vector nist_vectors[] = {
+ TEST_VECTOR((247, 89, 23, 51, 200, 86, 89, 53, 101, 19, 9, 117, 53, 25, 84, 208, 21, 90, 191, 60), (142, 52, 126, 245, 93, 95, 94, 153, 234, 182, 222, 112, 107, 81, 222, 124, 224, 4, 243, 136, 40, 137, 226, 89, 255, 78, 92, 255, 16, 33, 103, 165, 164, 189, 113, 21, 120, 212, 206, 23, 221, 154, 190, 86, 229, 28, 31, 45, 249, 80, 226, 252, 129, 46, 193, 178, 23, 202, 8, 214), (52, 254, 68, 176, 216, 196, 27, 147, 245, 250, 100, 251, 150, 240, 14, 91), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((71, 234, 93, 0, 130, 111, 17, 27, 250, 70, 142, 137, 155, 12, 163, 253, 167, 200, 51, 109), (219, 237, 20, 21, 110, 24, 38, 170, 29, 77, 102, 70, 156, 100, 163, 37, 113, 112, 17, 49, 178, 122, 140, 89, 94, 140, 5, 149, 102, 84, 120, 252, 241, 185, 92, 118, 174, 153, 125, 230, 24, 76, 145, 159, 75, 129, 13, 88, 133, 72, 80, 140, 212, 196, 87, 165, 65, 38, 7, 37), (125, 227, 116, 181, 239, 114, 64, 253, 66, 91, 124, 247, 197, 76, 41, 244), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((59, 22, 101, 78, 46, 137, 255, 74, 204, 87, 166, 197, 200, 175, 128, 100, 128, 120, 4, 166), (5, 225, 110, 209, 181, 96, 196, 201, 196, 50, 103, 241, 46, 228, 84, 218, 252, 1, 97, 190, 220, 225, 167, 211, 113, 236, 23, 66, 109, 8, 30, 254, 84, 175, 140, 47, 37, 102, 212, 238, 163, 138, 171, 171, 145, 251, 152, 253, 190, 22, 204, 182, 177, 20, 214, 119, 188, 176, 12, 102), (29, 41, 163, 210, 73, 158, 148, 115, 220, 98, 84, 77, 131, 11, 167, 115), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((87, 233, 253, 110, 12, 84, 201, 0, 101, 89, 59, 68, 72, 35, 66, 242, 234, 114, 193, 40), (187, 187, 239, 212, 124, 153, 118, 9, 196, 82, 47, 100, 188, 148, 160, 40, 165, 197, 92, 71, 17, 129, 199, 79, 239, 90, 83, 155, 163, 190, 119, 103, 75, 78, 237, 155, 181, 234, 9, 149, 177, 98, 2, 113, 100, 227, 141, 198, 60, 238, 176, 206, 111, 94, 119, 48, 235, 227, 71, 26), (150, 145, 249, 155, 148, 242, 15, 156, 84, 130, 118, 222, 78, 175, 6, 101), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((247, 202, 82, 65, 121, 75, 126, 107, 178, 66, 65, 68, 49, 176, 76, 112, 79, 0, 224, 24), (18, 70, 144, 235, 250, 211, 72, 105, 137, 160, 174, 6, 160, 128, 32, 130, 115, 176, 162, 63, 213, 183, 6, 180, 8, 74, 5, 154, 199, 105, 231, 102, 142, 108, 122, 101, 46, 21, 91, 94, 188, 74, 131, 37, 215, 12, 37, 199, 56, 5, 52, 111, 210, 105, 250, 236, 137, 55, 72, 59), (129, 54, 159, 109, 114, 114, 107, 229, 139, 230, 66, 157, 238, 216, 164, 203), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((178, 121, 242, 9, 138, 33, 241, 93, 52, 178, 237, 212, 82, 172, 236, 147, 152, 87, 81, 227), (150, 164, 202, 162, 36, 75, 85, 214, 84, 72, 193, 183, 1, 211, 161, 166, 182, 255, 125, 221, 228, 87, 119, 208, 75, 132, 148, 64, 53, 228, 166, 195, 123, 21, 107, 141, 80, 76, 139, 3, 159, 104, 231, 142, 185, 141, 46, 26, 231, 189, 154, 19, 126, 53, 118, 32, 104, 131, 228, 39), (79, 148, 67, 206, 124, 118, 184, 183, 117, 42, 203, 24, 178, 249, 176, 96), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((90, 114, 13, 158, 146, 231, 110, 71, 215, 166, 59, 148, 189, 204, 231, 10, 30, 46, 69, 173), (235, 123, 230, 244, 49, 196, 12, 158, 154, 74, 195, 178, 213, 17, 215, 187, 219, 155, 14, 66, 171, 105, 136, 162, 141, 35, 51, 38, 62, 184, 101, 135, 253, 232, 215, 229, 247, 51, 226, 4, 98, 122, 174, 197, 206, 92, 122, 131, 96, 54, 18, 52, 27, 112, 108, 15, 107, 30, 169, 95), (129, 100, 180, 82, 27, 201, 240, 155, 143, 70, 99, 118, 44, 245, 91, 126), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((67, 59, 126, 103, 66, 187, 216, 4, 15, 123, 170, 167, 136, 46, 179, 189, 158, 148, 8, 184), (103, 232, 74, 203, 220, 12, 188, 169, 193, 118, 161, 28, 230, 175, 95, 132, 154, 161, 126, 207, 151, 52, 157, 239, 107, 105, 247, 156, 20, 159, 164, 9, 70, 48, 218, 252, 118, 188, 105, 166, 111, 28, 104, 235, 36, 156, 29, 226, 103, 74, 104, 26, 192, 226, 82, 43, 245, 231, 96, 194), (132, 210, 201, 94, 238, 237, 154, 224, 152, 128, 15, 51, 115, 22, 226, 165), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((198, 123, 200, 96, 248, 215, 117, 219, 222, 72, 43, 2, 145, 143, 203, 169, 194, 29, 218, 208), (38, 215, 62, 11, 206, 251, 126, 30, 246, 43, 103, 92, 38, 59, 121, 5, 184, 107, 61, 232, 233, 35, 228, 13, 222, 155, 168, 160, 93, 222, 103, 201, 99, 167, 50, 164, 34, 129, 218, 169, 60, 187, 118, 174, 198, 254, 141, 88, 60, 10, 125, 240, 53, 248, 32, 126, 46, 114, 8, 47), (152, 229, 58, 236, 244, 45, 103, 233, 40, 97, 194, 149, 29, 157, 79, 103), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((136, 162, 179, 155, 67, 106, 69, 114, 136, 56, 1, 77, 68, 95, 22, 47, 169, 253, 123, 10), (246, 100, 120, 118, 191, 97, 113, 50, 160, 124, 92, 27, 73, 162, 142, 236, 60, 43, 106, 16, 116, 253, 81, 66, 170, 225, 50, 213, 51, 228, 161, 114, 203, 22, 110, 168, 155, 124, 177, 205, 209, 100, 198, 252, 127, 37, 74, 6, 3, 91, 43, 29, 40, 172, 69, 255, 8, 113, 174, 4), (55, 128, 142, 180, 10, 243, 68, 84, 173, 77, 214, 117, 11, 220, 142, 115), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((193, 239, 184, 210, 90, 255, 198, 30, 208, 96, 217, 148, 252, 213, 1, 124, 42, 223, 195, 136), (185, 47, 192, 85, 5, 127, 236, 113, 185, 197, 62, 124, 68, 135, 36, 35, 165, 126, 209, 134, 214, 186, 102, 217, 128, 254, 205, 18, 83, 191, 113, 71, 147, 32, 183, 191, 56, 213, 5, 239, 121, 202, 77, 98, 215, 140, 166, 98, 100, 44, 220, 237, 185, 149, 3, 234, 4, 193, 219, 232), (141, 183, 132, 207, 144, 181, 115, 176, 111, 155, 124, 125, 202, 99, 161, 234, 22, 217, 62, 231, 215, 15, 249, 216, 127, 162, 85, 142, 131, 220, 78, 170), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((126, 146, 92, 220, 188, 47, 213, 179, 33, 60, 186, 119, 20, 203, 113, 211, 89, 147, 97, 9), (31, 149, 165, 119, 149, 137, 129, 183, 71, 124, 162, 167, 29, 68, 230, 101, 100, 229, 165, 109, 129, 137, 84, 39, 24, 235, 26, 206, 129, 67, 110, 22, 244, 21, 135, 137, 164, 109, 25, 212, 56, 78, 21, 85, 91, 195, 180, 255, 161, 11, 84, 113, 172, 51, 191, 144, 73, 130, 244, 158), (85, 123, 94, 31, 231, 112, 180, 199, 110, 160, 204, 211, 31, 92, 29, 212, 255, 160, 70, 58, 140, 233, 250, 4, 247, 245, 209, 170, 83, 56, 0, 67), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((152, 182, 240, 180, 183, 168, 34, 232, 245, 103, 163, 45, 39, 254, 189, 169, 228, 98, 23, 211), (224, 138, 97, 35, 135, 25, 178, 31, 181, 246, 54, 31, 33, 94, 181, 165, 96, 50, 51, 191, 115, 161, 1, 243, 47, 9, 99, 151, 76, 1, 23, 252, 34, 208, 36, 216, 25, 63, 25, 254, 9, 92, 200, 115, 175, 199, 184, 152, 136, 203, 228, 23, 98, 231, 171, 110, 139, 120, 58, 0), (85, 4, 121, 58, 98, 151, 110, 119, 177, 243, 248, 187, 235, 197, 133, 78, 21, 56, 250, 0, 42, 152, 175, 91, 147, 93, 152, 80, 182, 95, 154, 97), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((186, 62, 97, 49, 207, 146, 76, 14, 103, 190, 1, 32, 93, 224, 124, 200, 199, 124, 185, 77), (157, 19, 178, 63, 237, 177, 139, 174, 77, 252, 248, 195, 246, 7, 14, 131, 234, 135, 161, 237, 32, 164, 1, 55, 55, 34, 158, 5, 246, 193, 248, 242, 107, 56, 74, 44, 237, 163, 125, 99, 37, 149, 21, 106, 188, 178, 18, 11, 222, 3, 204, 58, 233, 243, 229, 139, 205, 154, 229, 37), (90, 72, 65, 161, 74, 18, 240, 76, 101, 173, 94, 96, 201, 241, 14, 76, 237, 58, 254, 158, 225, 10, 168, 174, 214, 107, 166, 41, 216, 110, 33, 60), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((90, 59, 85, 212, 164, 137, 122, 31, 90, 212, 163, 165, 226, 37, 156, 205, 123, 47, 246, 47), (240, 46, 246, 25, 97, 190, 45, 239, 195, 203, 144, 100, 243, 15, 159, 215, 202, 128, 23, 74, 211, 246, 14, 2, 221, 123, 100, 82, 139, 111, 64, 24, 2, 152, 100, 85, 93, 58, 192, 62, 66, 21, 203, 221, 191, 180, 242, 88, 162, 107, 236, 70, 80, 122, 156, 254, 5, 84, 55, 247), (203, 9, 130, 105, 22, 233, 183, 59, 221, 182, 191, 37, 230, 202, 245, 182, 133, 111, 136, 213, 29, 179, 81, 253, 131, 21, 226, 144, 136, 152, 89, 33), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((123, 145, 103, 226, 246, 47, 55, 150, 89, 172, 4, 79, 69, 10, 239, 123, 213, 233, 56, 198), (244, 51, 232, 241, 119, 216, 253, 87, 67, 237, 89, 144, 168, 160, 237, 161, 154, 174, 8, 219, 17, 219, 111, 130, 228, 225, 222, 230, 125, 105, 159, 158, 17, 210, 157, 109, 125, 168, 240, 110, 183, 233, 115, 243, 161, 51, 253, 84, 192, 228, 10, 68, 91, 88, 3, 213, 171, 54, 101, 55), (68, 187, 182, 151, 134, 148, 177, 7, 113, 99, 71, 214, 198, 116, 166, 52, 89, 124, 252, 81, 168, 37, 177, 156, 35, 109, 246, 140, 63, 64, 152, 132), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((111, 157, 30, 146, 168, 241, 85, 194, 199, 28, 169, 214, 134, 15, 164, 222, 211, 181, 224, 28), (210, 235, 142, 103, 179, 17, 133, 105, 22, 40, 80, 205, 132, 151, 50, 36, 44, 41, 24, 85, 76, 76, 248, 97, 148, 129, 104, 184, 219, 120, 61, 69, 188, 253, 206, 219, 85, 186, 154, 201, 14, 57, 20, 50, 131, 51, 181, 241, 44, 213, 84, 142, 220, 177, 30, 139, 251, 63, 64, 95), (207, 78, 136, 187, 50, 49, 249, 5, 228, 3, 101, 63, 233, 102, 24, 54, 163, 37, 160, 10, 57, 20, 235, 225, 146, 53, 98, 80, 90, 31, 0, 174), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((139, 32, 209, 242, 89, 197, 44, 229, 174, 176, 106, 130, 73, 102, 149, 81, 16, 20, 90, 143), (67, 217, 219, 191, 8, 84, 20, 190, 187, 202, 232, 170, 248, 144, 171, 20, 169, 15, 217, 37, 165, 130, 176, 16, 249, 195, 160, 138, 62, 16, 168, 151, 203, 90, 232, 9, 152, 44, 85, 139, 101, 247, 193, 95, 231, 163, 22, 213, 65, 127, 38, 194, 115, 7, 92, 173, 87, 1, 209, 93), (78, 35, 56, 151, 110, 120, 50, 241, 111, 205, 240, 111, 211, 220, 75, 215, 119, 209, 112, 207, 86, 246, 168, 226, 17, 116, 53, 207, 5, 210, 181, 248), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((105, 59, 85, 124, 143, 212, 5, 74, 129, 118, 207, 195, 27, 104, 24, 21, 219, 224, 113, 128), (142, 148, 138, 52, 81, 175, 216, 59, 96, 65, 87, 109, 149, 148, 86, 186, 201, 123, 159, 147, 163, 209, 51, 25, 140, 218, 39, 61, 132, 111, 123, 139, 201, 175, 209, 155, 131, 32, 195, 197, 8, 89, 194, 146, 235, 249, 103, 216, 142, 160, 145, 36, 179, 51, 177, 68, 49, 99, 241, 140), (53, 155, 33, 56, 132, 176, 170, 86, 80, 53, 58, 83, 252, 191, 190, 91, 14, 0, 20, 243, 103, 204, 45, 67, 13, 124, 67, 122, 60, 9, 50, 108), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((255, 240, 254, 226, 54, 75, 85, 150, 247, 56, 142, 192, 2, 29, 219, 168, 202, 148, 251, 32), (94, 64, 206, 175, 237, 151, 71, 84, 84, 245, 129, 236, 184, 72, 186, 208, 16, 175, 13, 103, 131, 179, 44, 232, 107, 236, 87, 175, 110, 95, 5, 214, 199, 49, 145, 31, 82, 106, 186, 244, 149, 150, 213, 255, 11, 41, 194, 11, 191, 123, 132, 158, 202, 5, 139, 30, 171, 198, 13, 100), (75, 247, 73, 81, 46, 132, 147, 242, 186, 236, 96, 43, 209, 251, 29, 248, 65, 204, 146, 73, 107, 178, 140, 5, 54, 63, 119, 164, 242, 165, 75, 168), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((224, 43, 165, 213, 196, 16, 232, 85, 187, 209, 63, 132, 1, 36, 39, 62, 107, 134, 66, 55), (177, 78, 34, 123, 68, 56, 249, 115, 214, 113, 20, 28, 98, 70, 172, 220, 121, 78, 238, 145, 188, 126, 253, 29, 95, 240, 42, 123, 143, 176, 68, 0, 159, 182, 241, 240, 246, 79, 53, 54, 95, 177, 9, 142, 25, 149, 163, 79, 139, 112, 167, 30, 208, 38, 94, 209, 122, 231, 174, 64), (240, 119, 194, 213, 211, 106, 101, 128, 49, 199, 78, 245, 166, 106, 164, 139, 68, 86, 83, 10), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((209, 188, 223, 2, 137, 96, 25, 92, 236, 244, 120, 185, 232, 97, 234, 36, 57, 98, 235, 233), (236, 75, 18, 97, 15, 70, 247, 254, 68, 17, 227, 154, 178, 134, 25, 235, 255, 238, 109, 252, 99, 142, 78, 147, 142, 241, 224, 67, 66, 215, 93, 238, 18, 27, 55, 91, 226, 146, 41, 87, 4, 192, 144, 138, 166, 27, 72, 143, 106, 41, 171, 16, 100, 104, 19, 78, 113, 181, 67, 158), (9, 215, 29, 138, 239, 45, 52, 229, 82, 249, 190, 37, 252, 250, 96, 248, 127, 93, 182, 171), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((209, 210, 169, 16, 214, 137, 132, 143, 210, 32, 255, 48, 23, 124, 105, 3, 149, 132, 44, 105), (232, 206, 254, 230, 94, 184, 128, 149, 182, 252, 129, 217, 49, 62, 53, 180, 144, 148, 111, 159, 17, 74, 254, 35, 109, 93, 137, 39, 119, 64, 229, 0, 254, 80, 194, 185, 0, 182, 201, 19, 155, 10, 217, 63, 57, 136, 1, 112, 113, 137, 171, 243, 188, 115, 119, 157, 70, 251, 192, 18), (96, 216, 32, 108, 226, 142, 51, 198, 122, 136, 79, 13, 203, 138, 183, 12, 245, 93, 167, 95), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((136, 123, 116, 178, 200, 166, 235, 136, 143, 195, 137, 204, 45, 161, 135, 15, 4, 4, 116, 114), (201, 95, 228, 145, 183, 83, 138, 157, 105, 228, 206, 63, 255, 198, 199, 154, 216, 187, 20, 204, 181, 251, 191, 176, 163, 113, 237, 108, 1, 134, 64, 185, 99, 130, 165, 123, 35, 186, 174, 63, 77, 120, 58, 61, 33, 213, 185, 217, 225, 17, 162, 68, 201, 96, 17, 138, 34, 38, 156, 221), (246, 96, 45, 227, 223, 206, 7, 79, 227, 34, 210, 103, 201, 154, 80, 138, 70, 207, 37, 98), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((246, 175, 164, 69, 4, 28, 112, 115, 167, 76, 31, 185, 46, 145, 81, 67, 242, 248, 11, 188), (7, 81, 28, 137, 198, 138, 158, 208, 109, 82, 93, 250, 248, 78, 81, 21, 230, 7, 137, 32, 15, 134, 146, 235, 19, 178, 6, 153, 0, 194, 248, 138, 175, 203, 176, 183, 89, 161, 19, 231, 253, 101, 247, 239, 87, 145, 52, 25, 181, 77, 253, 252, 191, 180, 138, 157, 215, 177, 77, 25), (35, 38, 76, 67, 15, 238, 152, 198, 119, 150, 72, 58, 32, 56, 97, 173, 187, 156, 65, 143), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((238, 95, 35, 54, 62, 116, 167, 244, 104, 17, 189, 120, 227, 6, 223, 109, 13, 84, 106, 65), (39, 147, 181, 169, 202, 71, 35, 9, 57, 68, 185, 213, 133, 116, 74, 65, 212, 224, 55, 246, 183, 116, 169, 78, 141, 148, 234, 67, 201, 44, 255, 228, 225, 66, 190, 21, 57, 239, 155, 48, 118, 91, 227, 184, 172, 168, 84, 188, 196, 243, 0, 222, 64, 12, 79, 239, 52, 91, 95, 23), (154, 186, 74, 132, 122, 65, 20, 131, 190, 110, 208, 50, 177, 2, 19, 241, 5, 138, 46, 133), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((210, 15, 214, 92, 42, 21, 185, 158, 24, 146, 116, 222, 86, 57, 179, 13, 157, 157, 180, 183), (82, 211, 47, 193, 125, 195, 130, 123, 49, 111, 174, 219, 139, 143, 222, 144, 27, 53, 87, 111, 220, 135, 102, 154, 104, 95, 32, 177, 248, 178, 222, 5, 159, 117, 99, 78, 215, 176, 123, 253, 227, 144, 252, 151, 11, 109, 29, 104, 109, 251, 96, 227, 186, 150, 138, 132, 241, 97, 253, 184), (233, 181, 52, 197, 50, 96, 19, 120, 190, 70, 136, 7, 22, 247, 151, 21, 107, 148, 150, 242), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((128, 37, 179, 89, 12, 213, 20, 194, 249, 93, 233, 204, 144, 3, 255, 130, 86, 34, 238, 48), (23, 15, 8, 251, 116, 218, 99, 29, 42, 137, 53, 234, 194, 224, 205, 89, 255, 131, 247, 51, 210, 152, 147, 11, 108, 69, 143, 127, 136, 34, 253, 98, 19, 86, 134, 29, 11, 152, 208, 168, 177, 55, 161, 152, 124, 115, 17, 153, 255, 212, 239, 190, 171, 201, 156, 42, 101, 129, 15, 132), (88, 126, 88, 29, 158, 89, 65, 141, 87, 234, 192, 171, 249, 61, 148, 5, 207, 67, 53, 177), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((155, 233, 118, 48, 25, 63, 9, 77, 236, 38, 13, 76, 216, 124, 206, 114, 246, 109, 206, 88), (197, 223, 161, 77, 244, 114, 180, 114, 164, 188, 162, 8, 198, 216, 34, 231, 253, 70, 113, 110, 209, 174, 35, 44, 243, 53, 246, 103, 35, 53, 225, 252, 212, 2, 41, 248, 201, 14, 66, 228, 131, 61, 160, 172, 156, 163, 112, 46, 121, 87, 96, 121, 5, 14, 23, 98, 194, 169, 64, 167), (80, 225, 107, 193, 107, 84, 200, 105, 59, 145, 166, 173, 54, 43, 37, 92, 42, 124, 104, 74), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((168, 251, 21, 40, 47, 144, 244, 153, 55, 181, 237, 100, 39, 102, 12, 55, 179, 6, 149, 131), (101, 112, 172, 45, 192, 205, 120, 70, 88, 3, 52, 28, 41, 215, 63, 190, 90, 184, 4, 178, 31, 103, 127, 172, 83, 50, 24, 173, 150, 119, 73, 252, 221, 221, 131, 247, 74, 67, 131, 156, 100, 176, 115, 218, 211, 180, 48, 164, 209, 153, 82, 122, 121, 79, 15, 86, 152, 126, 169, 23), (125, 191, 38, 251, 58, 7, 170, 62, 196, 181, 115, 159, 62, 8, 253, 43, 45, 29, 130, 11), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((105, 58, 219, 144, 55, 24, 70, 39, 173, 48, 15, 23, 105, 133, 189, 55, 159, 56, 138, 149), (127, 9, 87, 12, 45, 147, 4, 236, 116, 58, 184, 69, 168, 118, 28, 18, 108, 24, 245, 207, 114, 53, 142, 173, 162, 181, 209, 222, 180, 61, 198, 160, 244, 255, 143, 147, 59, 239, 122, 240, 188, 250, 203, 51, 250, 7, 248, 202, 4, 160, 106, 254, 35, 24, 53, 213, 7, 89, 150, 190), (82, 245, 95, 81, 1, 14, 155, 215, 142, 79, 88, 202, 178, 116, 236, 175, 165, 97, 189, 78, 15, 32, 218, 132, 240, 48, 58, 30, 95, 249, 190, 188, 81, 67, 97, 236, 109, 245, 199, 126), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((112, 234, 15, 254, 28, 215, 109, 248, 107, 120, 21, 9, 147, 171, 207, 95, 134, 226, 222, 238), (175, 120, 11, 31, 76, 0, 181, 85, 118, 25, 55, 252, 86, 149, 51, 113, 13, 198, 198, 183, 108, 27, 149, 108, 155, 2, 172, 248, 114, 118, 119, 211, 108, 57, 110, 209, 243, 170, 102, 113, 16, 92, 143, 22, 200, 220, 117, 193, 247, 38, 43, 251, 61, 222, 184, 11, 150, 179, 223, 129), (120, 11, 180, 10, 56, 122, 191, 84, 169, 42, 185, 29, 36, 243, 21, 18, 54, 233, 175, 184, 232, 38, 134, 111, 68, 51, 195, 47, 12, 107, 228, 234, 52, 122, 120, 226, 51, 95, 40, 45), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((238, 167, 132, 195, 227, 24, 26, 248, 52, 131, 133, 69, 104, 120, 167, 117, 195, 164, 23, 8), (81, 214, 1, 236, 185, 202, 187, 76, 92, 198, 52, 137, 131, 161, 210, 67, 68, 131, 24, 18, 246, 211, 85, 147, 153, 57, 100, 24, 255, 136, 36, 183, 234, 227, 99, 80, 187, 64, 221, 102, 236, 6, 119, 244, 155, 95, 90, 185, 128, 92, 178, 114, 86, 46, 213, 199, 206, 11, 48, 201), (47, 214, 220, 33, 227, 28, 238, 129, 42, 227, 115, 140, 234, 159, 124, 42, 18, 28, 10, 15, 75, 152, 91, 29, 80, 110, 255, 114, 253, 231, 251, 111, 9, 72, 201, 42, 134, 180, 181, 37), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((59, 230, 232, 163, 238, 50, 249, 147, 19, 165, 184, 165, 30, 35, 227, 85, 129, 42, 71, 121), (48, 195, 246, 142, 230, 226, 250, 121, 232, 146, 104, 10, 105, 152, 49, 19, 78, 4, 9, 159, 153, 172, 183, 110, 53, 67, 124, 205, 241, 149, 14, 254, 243, 231, 189, 205, 209, 95, 93, 255, 223, 72, 37, 226, 136, 50, 63, 183, 120, 158, 177, 197, 75, 56, 166, 216, 181, 14, 229, 188), (0, 89, 254, 54, 80, 103, 60, 33, 146, 168, 215, 116, 107, 110, 252, 142, 6, 158, 66, 204, 106, 217, 161, 12, 70, 182, 183, 65, 204, 125, 29, 240, 75, 231, 224, 255, 128, 95, 12, 38), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((158, 202, 83, 24, 9, 22, 20, 182, 10, 62, 68, 246, 155, 162, 143, 65, 30, 169, 144, 232), (16, 121, 4, 63, 111, 109, 210, 31, 114, 105, 163, 196, 33, 74, 180, 215, 82, 130, 238, 100, 249, 19, 233, 236, 198, 104, 25, 43, 98, 20, 251, 18, 116, 62, 169, 182, 135, 236, 218, 121, 212, 205, 151, 194, 247, 141, 146, 103, 165, 8, 255, 70, 185, 91, 12, 143, 31, 49, 174, 251), (216, 87, 91, 129, 120, 135, 24, 61, 149, 233, 47, 244, 237, 136, 126, 82, 238, 21, 189, 117, 130, 13, 193, 169, 174, 117, 61, 166, 185, 127, 205, 109, 130, 232, 244, 87, 194, 3, 103, 112), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((249, 223, 193, 63, 4, 19, 196, 105, 240, 65, 53, 250, 198, 48, 131, 15, 49, 237, 130, 169), (182, 99, 198, 205, 224, 227, 181, 176, 52, 31, 25, 5, 209, 157, 88, 238, 46, 141, 169, 153, 215, 136, 211, 77, 75, 139, 76, 9, 29, 151, 220, 199, 60, 16, 147, 22, 156, 193, 211, 121, 72, 119, 79, 236, 44, 240, 137, 100, 210, 239, 216, 47, 113, 164, 64, 114, 136, 162, 156, 36), (76, 163, 144, 204, 175, 233, 214, 109, 75, 67, 160, 44, 195, 55, 195, 221, 116, 215, 190, 92, 73, 190, 255, 94, 196, 225, 57, 178, 221, 56, 202, 105, 90, 168, 123, 17, 185, 96, 49, 206), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((235, 10, 69, 152, 255, 9, 24, 154, 145, 54, 169, 123, 191, 135, 24, 160, 205, 103, 51, 134), (23, 211, 136, 174, 28, 161, 246, 3, 66, 46, 94, 33, 142, 26, 170, 158, 40, 191, 36, 167, 148, 240, 115, 102, 19, 39, 65, 34, 6, 242, 162, 166, 238, 94, 192, 218, 27, 255, 2, 222, 232, 118, 153, 26, 185, 219, 198, 158, 48, 231, 242, 89, 103, 80, 183, 217, 116, 226, 28, 178), (10, 185, 253, 97, 2, 144, 77, 2, 209, 204, 58, 49, 255, 216, 148, 116, 68, 209, 161, 86, 105, 132, 113, 132, 84, 11, 64, 140, 7, 32, 82, 80, 78, 6, 110, 76, 153, 90, 56, 140), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((24, 165, 83, 61, 243, 5, 224, 33, 123, 98, 44, 209, 219, 72, 133, 116, 216, 53, 255, 115), (255, 46, 44, 62, 40, 187, 249, 21, 177, 94, 88, 229, 158, 95, 194, 164, 151, 5, 215, 235, 23, 168, 77, 155, 65, 10, 132, 242, 191, 190, 73, 61, 231, 5, 236, 67, 73, 29, 87, 10, 203, 185, 88, 174, 252, 75, 235, 196, 122, 231, 178, 188, 24, 157, 66, 238, 163, 199, 24, 141), (40, 48, 128, 12, 9, 44, 64, 156, 220, 199, 52, 36, 160, 50, 69, 109, 5, 56, 111, 239, 161, 1, 240, 29, 105, 213, 65, 79, 210, 44, 170, 207, 178, 59, 156, 207, 119, 48, 80, 78), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((37, 201, 153, 194, 188, 101, 243, 174, 160, 58, 48, 157, 200, 204, 140, 0, 10, 17, 237, 150), (250, 124, 61, 34, 241, 188, 142, 165, 145, 143, 167, 26, 218, 122, 197, 46, 236, 13, 60, 25, 242, 93, 23, 122, 61, 187, 20, 251, 63, 54, 159, 82, 221, 53, 245, 67, 6, 0, 200, 119, 133, 8, 112, 162, 2, 27, 21, 228, 38, 116, 69, 105, 19, 110, 58, 7, 84, 25, 195, 223), (27, 164, 236, 50, 26, 220, 241, 147, 193, 11, 61, 9, 190, 201, 53, 224, 40, 102, 52, 198, 87, 154, 149, 239, 212, 146, 232, 18, 208, 133, 204, 147, 197, 58, 210, 149, 130, 36, 124, 69), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((90, 37, 74, 13, 173, 168, 75, 211, 170, 165, 17, 26, 17, 145, 230, 84, 219, 249, 231, 40), (53, 131, 208, 177, 208, 215, 15, 38, 219, 221, 170, 29, 234, 116, 228, 152, 98, 133, 24, 95, 242, 19, 51, 173, 68, 147, 91, 207, 104, 149, 63, 29, 109, 180, 104, 108, 83, 189, 101, 33, 197, 144, 206, 144, 130, 226, 130, 201, 73, 59, 44, 123, 193, 249, 157, 159, 137, 211, 238, 188), (38, 63, 230, 42, 4, 66, 223, 130, 48, 210, 158, 248, 96, 39, 109, 58, 26, 63, 126, 114, 22, 206, 235, 56, 19, 205, 82, 46, 162, 250, 129, 179, 228, 170, 75, 8, 215, 17, 121, 117), GNUTLS_MAC_SHA1),
+ TEST_VECTOR((245, 203, 124, 198, 32, 127, 89, 32, 221, 96, 21, 93, 219, 104, 195, 251, 189, 245, 16, 67, 101, 48, 93, 44, 26, 188, 211, 17), (78, 90, 199, 83, 152, 3, 218, 137, 88, 30, 224, 136, 199, 209, 2, 53, 161, 5, 54, 54, 0, 84, 183, 43, 142, 159, 24, 247, 124, 37, 175, 1, 1, 155, 41, 6, 86, 182, 4, 40, 2, 76, 224, 31, 204, 244, 144, 34, 216, 49, 148, 20, 7, 230, 189, 39, 255, 158, 45, 40), (10, 219, 170, 180, 62, 221, 83, 43, 86, 10, 50, 44, 132, 172, 84, 14), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((58, 76, 49, 161, 87, 203, 181, 130, 233, 221, 7, 128, 217, 74, 187, 64, 12, 17, 44, 161, 225, 180, 17, 87, 33, 99, 239, 60), (153, 115, 23, 115, 114, 30, 152, 57, 244, 210, 179, 102, 75, 149, 187, 241, 166, 129, 81, 108, 42, 150, 89, 24, 247, 74, 53, 185, 132, 83, 182, 118, 250, 187, 125, 224, 59, 89, 192, 164, 115, 174, 203, 130, 177, 254, 183, 103, 210, 67, 72, 151, 96, 201, 199, 197, 140, 74, 48, 70), (6, 51, 149, 12, 245, 124, 15, 49, 113, 122, 98, 135, 135, 45, 29, 46), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((52, 11, 216, 187, 233, 14, 124, 28, 27, 77, 93, 130, 95, 152, 43, 89, 157, 163, 213, 170, 152, 132, 152, 171, 88, 39, 153, 137), (213, 210, 35, 130, 73, 18, 25, 117, 163, 252, 179, 112, 0, 75, 126, 60, 142, 50, 85, 80, 170, 14, 35, 153, 32, 170, 181, 63, 222, 131, 185, 229, 175, 195, 74, 229, 19, 74, 78, 253, 117, 25, 126, 163, 145, 72, 103, 165, 120, 27, 130, 252, 250, 183, 67, 127, 137, 95, 228, 239), (29, 19, 87, 60, 253, 241, 15, 59, 10, 49, 45, 151, 70, 247, 103, 14), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((243, 55, 29, 98, 56, 200, 137, 145, 129, 92, 138, 205, 228, 254, 109, 230, 33, 75, 224, 162, 255, 40, 57, 236, 189, 104, 23, 70), (55, 2, 63, 131, 130, 136, 17, 104, 91, 84, 142, 66, 128, 192, 198, 187, 248, 206, 181, 215, 135, 101, 239, 81, 73, 100, 92, 187, 169, 63, 104, 235, 29, 221, 4, 179, 95, 199, 122, 197, 120, 242, 231, 96, 198, 213, 101, 34, 8, 172, 204, 172, 230, 50, 45, 152, 217, 168, 66, 242), (233, 200, 119, 181, 163, 205, 1, 106, 211, 200, 77, 31, 248, 11, 48, 196), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((28, 14, 172, 219, 166, 71, 38, 243, 72, 100, 245, 187, 160, 22, 14, 202, 219, 182, 195, 88, 254, 56, 235, 61, 225, 137, 223, 253), (43, 209, 144, 87, 201, 204, 99, 43, 217, 221, 58, 42, 254, 6, 216, 18, 61, 106, 148, 90, 7, 83, 126, 142, 117, 89, 180, 88, 104, 32, 64, 236, 156, 129, 16, 237, 16, 46, 100, 190, 159, 156, 31, 235, 14, 108, 19, 201, 196, 60, 70, 8, 208, 215, 232, 17, 215, 40, 190, 245), (231, 245, 216, 251, 119, 143, 238, 148, 7, 128, 86, 69, 95, 121, 4, 134), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((95, 32, 17, 138, 134, 6, 231, 10, 235, 188, 250, 27, 192, 122, 57, 85, 229, 68, 204, 236, 21, 114, 87, 174, 51, 127, 221, 135), (184, 189, 171, 31, 17, 178, 136, 3, 148, 253, 217, 134, 0, 128, 110, 34, 133, 126, 148, 210, 38, 33, 29, 84, 242, 67, 151, 93, 200, 171, 233, 13, 215, 228, 151, 9, 9, 183, 90, 216, 46, 57, 182, 104, 142, 240, 108, 144, 0, 246, 122, 73, 140, 180, 5, 178, 25, 161, 84, 149), (36, 153, 127, 65, 62, 78, 220, 93, 109, 108, 10, 99, 23, 10, 96, 222), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((153, 152, 189, 102, 158, 4, 52, 158, 122, 18, 10, 42, 58, 63, 123, 197, 76, 212, 40, 159, 185, 249, 65, 46, 18, 15, 176, 27), (10, 146, 159, 60, 155, 130, 125, 81, 181, 118, 60, 253, 24, 6, 54, 125, 171, 173, 2, 52, 121, 252, 11, 174, 192, 60, 165, 116, 182, 253, 115, 210, 53, 242, 134, 9, 45, 202, 217, 9, 37, 236, 111, 254, 146, 239, 54, 54, 165, 196, 208, 13, 171, 237, 34, 114, 134, 33, 177, 40), (168, 230, 112, 255, 205, 38, 6, 169, 114, 47, 27, 67, 238, 130, 244, 122), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((49, 253, 25, 83, 148, 228, 8, 0, 136, 179, 132, 49, 58, 28, 122, 181, 209, 102, 10, 137, 124, 176, 48, 166, 226, 233, 191, 54), (242, 151, 30, 242, 125, 82, 46, 172, 83, 95, 172, 153, 89, 4, 255, 169, 58, 33, 39, 49, 122, 161, 141, 211, 108, 221, 29, 100, 52, 189, 103, 41, 209, 219, 225, 45, 120, 23, 164, 246, 172, 205, 192, 195, 77, 90, 82, 124, 154, 200, 89, 84, 163, 92, 120, 15, 204, 141, 190, 97), (242, 103, 161, 172, 39, 230, 0, 23, 64, 156, 131, 162, 100, 223, 81, 83), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((186, 109, 105, 219, 59, 202, 224, 221, 194, 72, 204, 160, 23, 182, 201, 239, 99, 165, 22, 241, 219, 77, 232, 66, 6, 145, 198, 43), (123, 109, 37, 156, 169, 74, 18, 237, 87, 239, 226, 181, 13, 42, 200, 242, 179, 30, 216, 75, 72, 97, 239, 115, 82, 175, 105, 218, 31, 117, 143, 186, 166, 151, 130, 59, 94, 102, 109, 221, 151, 107, 173, 170, 44, 179, 45, 128, 123, 81, 12, 185, 125, 254, 130, 204, 83, 160, 217, 191), (190, 150, 103, 242, 111, 141, 36, 155, 30, 59, 217, 144, 190, 159, 184, 82), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((161, 198, 96, 83, 219, 249, 100, 199, 91, 186, 102, 43, 169, 129, 103, 235, 17, 134, 184, 90, 111, 5, 135, 93, 247, 135, 12, 154), (213, 139, 117, 66, 209, 8, 64, 214, 159, 13, 127, 94, 38, 46, 17, 5, 96, 102, 213, 108, 141, 164, 100, 41, 180, 184, 202, 48, 109, 157, 149, 130, 151, 245, 21, 59, 222, 97, 80, 178, 190, 10, 29, 104, 184, 5, 93, 104, 254, 82, 215, 163, 95, 241, 218, 42, 211, 73, 32, 140), (224, 163, 62, 113, 67, 137, 177, 130, 143, 222, 238, 220, 250, 214, 205, 216), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((153, 40, 21, 18, 29, 136, 255, 178, 108, 51, 118, 6, 114, 60, 2, 239, 49, 119, 19, 8, 110, 44, 251, 189, 55, 225, 161, 103), (21, 45, 151, 78, 178, 113, 155, 144, 39, 211, 32, 84, 163, 39, 49, 35, 97, 18, 89, 89, 223, 157, 150, 161, 131, 46, 32, 86, 194, 87, 29, 79, 28, 244, 95, 110, 143, 101, 68, 200, 127, 21, 134, 28, 239, 98, 125, 47, 22, 233, 176, 180, 171, 121, 155, 179, 54, 47, 74, 174), (71, 94, 218, 58, 50, 213, 105, 147, 46, 4, 61, 182, 77, 191, 14, 155, 176, 148, 91, 84, 220, 223, 162, 3, 190, 26, 40, 82, 76, 20, 112, 117), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((204, 252, 133, 156, 17, 163, 224, 158, 27, 4, 11, 112, 31, 216, 185, 98, 169, 38, 160, 144, 17, 123, 170, 168, 12, 131, 226, 236), (137, 31, 7, 134, 138, 182, 166, 197, 73, 142, 123, 232, 91, 30, 61, 91, 175, 60, 65, 92, 245, 224, 174, 183, 201, 64, 57, 83, 175, 100, 146, 165, 215, 136, 96, 253, 192, 246, 27, 162, 196, 175, 85, 188, 61, 80, 79, 161, 199, 180, 10, 208, 119, 143, 99, 247, 155, 22, 75, 100), (173, 183, 216, 27, 163, 218, 100, 163, 196, 158, 48, 177, 232, 102, 228, 139, 13, 0, 9, 174, 143, 56, 80, 74, 74, 89, 37, 72, 76, 17, 86, 20), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((160, 99, 19, 24, 225, 141, 217, 102, 182, 236, 81, 231, 170, 121, 172, 107, 249, 182, 62, 50, 30, 166, 95, 87, 109, 224, 98, 86), (235, 241, 246, 22, 205, 113, 134, 232, 45, 229, 44, 132, 59, 98, 118, 147, 156, 104, 116, 212, 43, 129, 138, 203, 79, 242, 135, 53, 70, 200, 234, 252, 216, 69, 39, 55, 86, 243, 193, 36, 108, 21, 30, 156, 16, 229, 7, 172, 33, 103, 10, 81, 126, 10, 62, 14, 65, 168, 119, 3), (43, 142, 231, 61, 24, 51, 185, 60, 139, 254, 39, 248, 102, 225, 131, 107, 140, 67, 63, 79, 156, 238, 174, 34, 65, 78, 167, 18, 174, 38, 61, 126), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((50, 97, 88, 163, 77, 214, 152, 134, 134, 106, 238, 189, 223, 222, 1, 42, 150, 108, 237, 232, 88, 139, 106, 87, 238, 98, 222, 40), (106, 247, 213, 208, 115, 36, 102, 185, 125, 4, 110, 222, 189, 227, 20, 142, 131, 75, 25, 147, 128, 189, 111, 153, 240, 59, 222, 38, 240, 219, 141, 27, 54, 255, 74, 221, 141, 137, 7, 110, 229, 177, 246, 131, 56, 237, 83, 100, 188, 134, 45, 102, 72, 26, 190, 35, 213, 150, 195, 251), (167, 250, 155, 239, 18, 56, 75, 158, 66, 93, 153, 90, 193, 211, 197, 209, 170, 52, 168, 10, 141, 176, 222, 237, 103, 49, 108, 208, 52, 54, 37, 175), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((69, 97, 233, 66, 87, 40, 130, 253, 247, 131, 16, 96, 60, 62, 158, 166, 11, 243, 54, 246, 132, 24, 97, 169, 82, 198, 200, 203), (11, 165, 78, 112, 121, 185, 179, 239, 85, 203, 223, 220, 89, 222, 154, 182, 8, 55, 101, 65, 150, 193, 126, 202, 220, 60, 71, 180, 201, 255, 22, 26, 34, 108, 76, 222, 181, 173, 241, 65, 182, 113, 181, 10, 131, 88, 88, 182, 66, 59, 253, 201, 194, 228, 28, 81, 195, 207, 64, 125), (25, 111, 0, 168, 97, 198, 196, 15, 220, 188, 200, 78, 117, 148, 172, 227, 45, 145, 95, 126, 168, 55, 2, 236, 229, 99, 93, 134, 87, 212, 201, 57), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((116, 83, 172, 14, 157, 27, 46, 160, 84, 121, 230, 22, 241, 188, 135, 128, 100, 185, 212, 177, 237, 217, 151, 132, 28, 241, 40, 177), (234, 208, 197, 163, 67, 216, 222, 90, 98, 235, 87, 115, 27, 100, 176, 183, 233, 52, 215, 92, 91, 98, 236, 104, 60, 191, 97, 119, 107, 250, 119, 242, 13, 168, 220, 110, 40, 123, 31, 73, 24, 177, 223, 191, 64, 42, 249, 53, 37, 139, 17, 3, 30, 161, 7, 126, 90, 119, 91, 247), (74, 104, 200, 39, 103, 158, 181, 196, 91, 97, 161, 18, 128, 13, 156, 215, 91, 64, 232, 151, 94, 58, 54, 196, 81, 54, 65, 142, 32, 194, 254, 220), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((107, 63, 132, 194, 201, 169, 118, 34, 157, 83, 49, 114, 54, 11, 250, 74, 50, 130, 181, 123, 95, 97, 230, 76, 96, 1, 207, 55), (213, 242, 220, 142, 164, 227, 73, 219, 4, 7, 91, 147, 107, 5, 106, 153, 90, 246, 161, 11, 245, 108, 138, 16, 177, 255, 156, 191, 216, 32, 35, 253, 116, 30, 215, 228, 71, 20, 82, 107, 13, 140, 207, 78, 108, 87, 133, 73, 17, 135, 17, 84, 163, 173, 224, 109, 213, 168, 192, 254), (168, 171, 186, 169, 128, 201, 227, 194, 68, 119, 21, 94, 194, 167, 144, 87, 139, 30, 58, 92, 143, 7, 203, 178, 181, 44, 170, 96, 87, 212, 115, 119), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((1, 190, 172, 81, 27, 4, 117, 219, 238, 76, 209, 245, 229, 232, 223, 49, 17, 36, 196, 90, 218, 194, 23, 204, 242, 153, 109, 171), (148, 93, 168, 242, 142, 56, 203, 9, 231, 182, 19, 14, 140, 68, 219, 79, 196, 22, 30, 172, 51, 207, 42, 250, 32, 235, 123, 21, 224, 114, 65, 157, 250, 225, 182, 149, 120, 140, 3, 206, 133, 24, 185, 233, 215, 186, 62, 250, 210, 26, 169, 253, 51, 58, 109, 37, 233, 180, 219, 231), (162, 67, 76, 12, 10, 226, 30, 122, 191, 125, 86, 228, 117, 235, 73, 196, 59, 83, 254, 189, 32, 35, 24, 95, 133, 31, 196, 104, 204, 159, 108, 188), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((102, 10, 1, 196, 68, 13, 209, 201, 135, 88, 189, 0, 173, 157, 169, 91, 221, 162, 96, 106, 186, 3, 43, 208, 80, 235, 40, 70), (84, 172, 200, 120, 2, 153, 59, 176, 103, 207, 233, 147, 181, 235, 129, 23, 213, 214, 53, 42, 226, 12, 213, 135, 194, 84, 33, 93, 230, 73, 220, 16, 10, 138, 30, 194, 245, 141, 211, 94, 144, 116, 237, 89, 47, 73, 170, 246, 127, 151, 26, 73, 34, 64, 220, 218, 181, 210, 91, 131), (226, 126, 33, 235, 131, 63, 54, 83, 45, 22, 194, 112, 186, 50, 252, 213, 219, 90, 236, 215, 27, 155, 93, 116, 128, 93, 169, 65, 12, 189, 160, 162), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((7, 113, 55, 43, 169, 141, 231, 230, 214, 242, 11, 69, 194, 19, 107, 232, 248, 236, 100, 163, 109, 6, 77, 243, 72, 199, 109, 175), (222, 71, 118, 5, 141, 235, 142, 24, 40, 91, 63, 213, 116, 90, 206, 152, 238, 172, 74, 28, 248, 139, 195, 67, 132, 178, 153, 22, 138, 57, 71, 132, 184, 242, 205, 76, 146, 203, 92, 7, 234, 50, 105, 91, 145, 254, 64, 50, 132, 141, 104, 19, 27, 0, 166, 204, 9, 134, 206, 119), (181, 246, 182, 64, 69, 134, 91, 96, 253, 240, 28, 66, 157, 187, 50, 118, 54, 204, 62, 215, 42, 168, 191, 169, 160, 175, 162, 245, 138, 74, 127, 147), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((46, 171, 182, 185, 34, 194, 67, 38, 239, 154, 227, 193, 146, 223, 211, 65, 202, 245, 126, 254, 21, 221, 100, 151, 114, 162, 172, 59), (199, 95, 111, 90, 21, 97, 170, 179, 158, 160, 226, 39, 2, 166, 207, 125, 186, 60, 164, 221, 159, 4, 107, 176, 171, 234, 45, 50, 132, 22, 143, 217, 251, 57, 255, 114, 85, 35, 166, 96, 210, 31, 140, 42, 222, 3, 209, 141, 66, 115, 197, 47, 182, 242, 44, 158, 57, 214, 188, 46), (174, 80, 172, 235, 227, 8, 161, 207, 23, 71, 185, 177, 120, 160, 114, 7, 72, 250, 95, 229), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((90, 172, 206, 27, 112, 92, 73, 162, 14, 46, 51, 150, 177, 241, 143, 68, 33, 224, 119, 81, 117, 52, 221, 63, 81, 133, 246, 4), (136, 169, 98, 207, 214, 204, 128, 130, 142, 183, 16, 56, 134, 48, 160, 24, 2, 47, 223, 137, 21, 72, 227, 82, 137, 124, 114, 13, 166, 82, 35, 251, 42, 97, 78, 105, 44, 91, 208, 48, 218, 29, 0, 201, 198, 186, 209, 154, 186, 248, 121, 240, 93, 107, 92, 45, 220, 223, 206, 205), (169, 74, 159, 161, 238, 242, 248, 33, 28, 49, 38, 1, 91, 44, 185, 184, 15, 119, 239, 191), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((60, 22, 159, 185, 94, 242, 122, 65, 241, 159, 145, 64, 115, 2, 34, 251, 239, 57, 88, 72, 247, 171, 250, 24, 255, 208, 11, 230), (5, 79, 125, 25, 214, 11, 39, 197, 23, 113, 204, 210, 12, 62, 137, 65, 11, 84, 246, 163, 119, 243, 226, 235, 85, 60, 71, 199, 63, 98, 43, 72, 12, 96, 135, 51, 94, 153, 35, 133, 121, 210, 244, 32, 192, 109, 97, 236, 183, 205, 202, 49, 71, 218, 77, 241, 169, 199, 78, 10), (124, 135, 8, 211, 123, 107, 205, 143, 172, 230, 244, 60, 223, 169, 41, 72, 191, 15, 34, 163), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((155, 111, 157, 66, 186, 39, 28, 248, 8, 181, 233, 126, 169, 243, 159, 33, 194, 11, 162, 232, 45, 22, 134, 145, 172, 206, 59, 126), (187, 150, 215, 156, 62, 129, 32, 119, 172, 184, 91, 122, 174, 212, 31, 157, 33, 19, 224, 31, 251, 184, 10, 198, 211, 170, 162, 42, 144, 115, 5, 240, 236, 48, 158, 125, 210, 21, 91, 81, 21, 75, 138, 152, 95, 219, 65, 171, 40, 144, 205, 92, 140, 36, 145, 173, 94, 80, 78, 18), (155, 248, 92, 3, 89, 96, 153, 210, 60, 137, 249, 205, 223, 158, 130, 53, 77, 194, 101, 118), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((7, 84, 7, 192, 89, 224, 205, 73, 47, 26, 21, 119, 190, 166, 196, 233, 209, 164, 60, 232, 201, 103, 213, 47, 1, 239, 197, 12), (254, 120, 159, 253, 205, 132, 249, 56, 76, 208, 168, 137, 52, 98, 169, 15, 66, 53, 221, 188, 246, 83, 244, 91, 250, 218, 171, 199, 187, 95, 105, 234, 107, 228, 209, 175, 134, 114, 137, 8, 127, 61, 194, 225, 158, 197, 3, 245, 46, 217, 55, 181, 78, 158, 138, 245, 191, 111, 18, 142), (18, 182, 202, 77, 191, 133, 151, 31, 226, 8, 85, 235, 233, 88, 105, 254, 246, 19, 193, 172), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((80, 101, 183, 139, 253, 172, 84, 36, 107, 133, 15, 218, 189, 249, 43, 203, 249, 29, 70, 114, 134, 172, 179, 63, 158, 176, 129, 128), (244, 92, 16, 217, 57, 143, 0, 95, 135, 255, 28, 72, 63, 139, 158, 87, 40, 12, 192, 159, 100, 96, 59, 204, 94, 204, 112, 116, 237, 195, 76, 94, 188, 10, 211, 167, 236, 205, 81, 246, 94, 62, 196, 237, 158, 79, 176, 212, 203, 72, 204, 234, 152, 172, 27, 94, 39, 86, 167, 229), (66, 13, 81, 47, 134, 72, 121, 93, 47, 154, 168, 132, 76, 53, 33, 28, 94, 99, 153, 64), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((209, 166, 85, 147, 197, 225, 7, 162, 196, 79, 169, 167, 110, 223, 74, 30, 175, 139, 149, 70, 196, 0, 164, 173, 223, 31, 212, 78), (251, 220, 27, 69, 223, 204, 0, 238, 71, 184, 35, 234, 31, 175, 245, 105, 172, 129, 232, 157, 86, 165, 156, 153, 36, 94, 143, 195, 89, 75, 120, 64, 164, 68, 64, 168, 76, 251, 21, 112, 85, 33, 157, 152, 122, 27, 124, 151, 211, 207, 132, 99, 112, 80, 31, 216, 90, 86, 84, 130), (4, 188, 187, 160, 129, 164, 77, 160, 82, 96, 23, 29, 18, 164, 199, 11, 97, 151, 169, 37), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((140, 9, 255, 88, 185, 164, 80, 180, 185, 55, 122, 13, 197, 185, 37, 154, 153, 147, 226, 16, 187, 151, 223, 209, 176, 94, 201, 67), (76, 19, 176, 166, 238, 8, 224, 226, 136, 244, 25, 110, 153, 103, 41, 112, 28, 8, 223, 183, 232, 41, 27, 162, 234, 237, 247, 252, 254, 2, 26, 130, 198, 146, 56, 155, 25, 48, 183, 222, 15, 15, 131, 133, 242, 20, 216, 21, 176, 252, 122, 173, 54, 232, 9, 251, 174, 24, 28, 255), (73, 134, 6, 233, 153, 171, 237, 28, 172, 115, 36, 78, 28, 147, 88, 30, 225, 222, 123, 172), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((231, 220, 195, 208, 15, 63, 166, 138, 174, 99, 103, 57, 71, 249, 85, 25, 157, 21, 220, 60, 39, 209, 98, 202, 247, 161, 3, 79), (126, 200, 174, 219, 77, 110, 43, 116, 113, 49, 141, 115, 35, 22, 158, 20, 47, 208, 89, 25, 184, 126, 43, 198, 61, 255, 150, 30, 16, 60, 32, 253, 34, 34, 245, 58, 144, 215, 10, 227, 147, 122, 110, 113, 155, 10, 37, 137, 230, 190, 83, 84, 239, 40, 245, 60, 185, 39, 94, 178), (247, 200, 71, 187, 199, 240, 142, 233, 85, 38, 202, 208, 43, 170, 37, 111, 182, 231, 101, 245), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((198, 196, 25, 182, 68, 22, 44, 124, 79, 111, 66, 93, 193, 169, 152, 72, 111, 160, 187, 255, 160, 199, 158, 186, 253, 183, 27, 244), (21, 228, 118, 107, 113, 67, 102, 70, 238, 174, 45, 27, 192, 0, 182, 63, 192, 225, 93, 48, 184, 203, 148, 56, 64, 22, 196, 196, 124, 7, 46, 42, 236, 248, 120, 127, 21, 176, 112, 85, 255, 177, 240, 121, 193, 69, 11, 46, 71, 108, 140, 13, 77, 45, 22, 113, 137, 193, 128, 79), (52, 170, 203, 83, 46, 59, 128, 215, 101, 204, 80, 116, 107, 211, 158, 181, 196, 116, 186, 89), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((155, 117, 231, 250, 33, 108, 136, 64, 55, 199, 214, 149, 48, 146, 237, 51, 92, 78, 253, 136, 202, 87, 167, 66, 214, 172, 50, 33), (18, 190, 169, 120, 101, 223, 153, 49, 82, 89, 255, 98, 3, 2, 67, 46, 202, 252, 157, 206, 38, 25, 232, 125, 251, 73, 121, 65, 4, 86, 165, 36, 67, 67, 21, 221, 57, 32, 226, 177, 170, 28, 121, 213, 224, 113, 50, 167, 88, 167, 183, 183, 30, 241, 11, 207, 27, 184, 119, 243), (96, 7, 27, 208, 206, 234, 15, 224, 248, 121, 34, 59, 148, 13, 61, 231, 221, 224, 44, 166, 133, 143, 132, 80, 251, 156, 0, 50, 228, 159, 150, 142, 249, 205, 155, 87, 3, 22, 61, 188), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((218, 100, 168, 83, 66, 57, 113, 149, 216, 43, 128, 203, 151, 228, 206, 171, 191, 198, 157, 165, 149, 80, 192, 81, 12, 170, 44, 17), (68, 205, 12, 219, 105, 227, 174, 89, 36, 234, 122, 35, 55, 111, 53, 234, 147, 208, 237, 61, 71, 218, 189, 238, 30, 217, 135, 242, 88, 81, 174, 237, 44, 87, 239, 134, 99, 199, 89, 107, 174, 226, 24, 201, 199, 70, 91, 152, 6, 73, 184, 54, 117, 135, 103, 78, 56, 100, 68, 62), (18, 252, 194, 211, 108, 49, 171, 73, 85, 79, 127, 21, 0, 219, 16, 251, 228, 25, 50, 130, 226, 217, 124, 151, 103, 15, 245, 14, 59, 194, 41, 133, 7, 219, 147, 51, 60, 174, 122, 66), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((25, 129, 150, 17, 153, 78, 136, 169, 22, 132, 81, 109, 221, 161, 28, 142, 237, 179, 169, 105, 36, 8, 168, 80, 44, 225, 194, 96), (241, 217, 191, 254, 180, 161, 108, 164, 205, 144, 2, 242, 242, 113, 196, 59, 219, 66, 240, 251, 162, 81, 4, 93, 138, 119, 104, 173, 221, 227, 156, 109, 96, 82, 184, 125, 14, 225, 66, 217, 110, 82, 221, 61, 126, 205, 88, 155, 62, 78, 182, 61, 58, 173, 87, 144, 20, 165, 185, 145), (169, 74, 204, 195, 225, 196, 204, 56, 212, 197, 93, 201, 241, 135, 182, 149, 65, 26, 170, 50, 20, 107, 71, 88, 5, 134, 185, 214, 54, 172, 180, 227, 61, 136, 17, 167, 255, 77, 77, 147), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((91, 240, 222, 64, 119, 191, 133, 37, 99, 32, 60, 150, 166, 93, 223, 78, 100, 138, 223, 160, 15, 181, 33, 71, 18, 210, 245, 62), (70, 227, 218, 3, 68, 232, 61, 11, 255, 127, 67, 82, 126, 192, 158, 135, 63, 0, 176, 71, 129, 157, 18, 80, 240, 134, 92, 77, 249, 146, 236, 63, 226, 90, 0, 254, 169, 225, 210, 227, 1, 186, 143, 158, 70, 95, 20, 111, 9, 135, 73, 66, 123, 60, 137, 72, 139, 195, 245, 173), (128, 36, 114, 84, 119, 178, 69, 191, 203, 243, 174, 37, 135, 11, 162, 210, 10, 192, 36, 44, 215, 152, 198, 20, 158, 156, 215, 203, 81, 96, 200, 245, 87, 175, 192, 230, 181, 80, 40, 1), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((100, 176, 2, 126, 209, 151, 162, 124, 101, 182, 36, 86, 67, 174, 225, 40, 168, 59, 170, 155, 176, 173, 149, 72, 113, 11, 87, 29), (46, 26, 111, 88, 224, 58, 184, 83, 200, 211, 81, 156, 180, 30, 75, 195, 97, 56, 222, 133, 180, 223, 26, 48, 203, 153, 122, 36, 38, 17, 133, 150, 183, 194, 196, 1, 13, 168, 178, 41, 114, 159, 104, 170, 111, 166, 158, 135, 130, 148, 218, 142, 171, 3, 25, 140, 151, 193, 99, 90), (237, 86, 192, 73, 108, 205, 166, 15, 27, 107, 94, 167, 166, 25, 85, 164, 152, 161, 127, 14, 50, 104, 183, 83, 162, 43, 139, 219, 110, 142, 89, 87, 173, 164, 191, 163, 22, 223, 183, 4), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((14, 225, 111, 149, 202, 200, 49, 19, 210, 17, 232, 213, 105, 213, 177, 118, 66, 77, 192, 147, 251, 134, 81, 195, 151, 127, 226, 235), (160, 5, 215, 216, 222, 250, 246, 214, 195, 150, 211, 171, 103, 155, 57, 205, 79, 169, 42, 174, 133, 211, 114, 12, 25, 200, 101, 22, 102, 8, 179, 33, 141, 202, 201, 226, 85, 88, 65, 159, 150, 130, 128, 78, 240, 238, 134, 239, 63, 0, 44, 179, 203, 207, 197, 69, 122, 191, 16, 19), (170, 84, 238, 183, 204, 86, 79, 238, 91, 33, 24, 136, 34, 221, 58, 165, 25, 181, 53, 61, 209, 188, 215, 6, 216, 211, 184, 176, 94, 96, 13, 10, 88, 26, 64, 105, 88, 46, 187, 40), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((133, 54, 39, 116, 89, 236, 130, 21, 118, 70, 235, 147, 183, 234, 152, 12, 203, 152, 38, 145, 233, 168, 124, 205, 57, 65, 155, 31), (249, 87, 246, 245, 19, 198, 193, 18, 208, 47, 191, 171, 107, 142, 11, 122, 162, 246, 57, 71, 187, 206, 124, 220, 38, 22, 152, 200, 177, 75, 59, 188, 179, 5, 107, 215, 28, 158, 147, 194, 229, 31, 22, 207, 39, 93, 225, 21, 236, 82, 46, 123, 88, 226, 82, 24, 87, 69, 128, 242), (53, 205, 212, 154, 136, 180, 59, 205, 160, 101, 130, 239, 107, 40, 37, 88, 48, 112, 69, 92, 49, 81, 199, 228, 143, 202, 69, 121, 223, 76, 115, 254, 223, 115, 46, 245, 212, 39, 216, 205), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((36, 81, 170, 13, 77, 49, 35, 209, 228, 223, 86, 248, 242, 180, 105, 113, 198, 59, 73, 167, 181, 85, 117, 116, 69, 218, 175, 53), (20, 244, 92, 203, 141, 212, 22, 10, 241, 150, 205, 216, 57, 110, 126, 192, 28, 45, 188, 88, 149, 62, 155, 158, 196, 204, 133, 67, 181, 62, 1, 113, 201, 217, 79, 157, 89, 162, 14, 141, 113, 17, 100, 72, 246, 177, 49, 67, 23, 148, 94, 51, 134, 15, 169, 124, 160, 175, 153, 80), (80, 244, 183, 94, 145, 166, 57, 243, 99, 114, 249, 51, 41, 34, 6, 37, 59, 134, 134, 45, 216, 27, 174, 52, 152, 195, 179, 51, 202, 186, 114, 41, 174, 120, 205, 90, 26, 22, 141, 68), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((20, 86, 61, 152, 218, 182, 166, 90, 230, 215, 225, 192, 143, 133, 238, 21, 21, 213, 33, 57, 251, 164, 105, 157, 63, 159, 120, 57), (88, 73, 104, 105, 176, 241, 172, 13, 145, 186, 235, 65, 161, 233, 31, 73, 211, 78, 188, 215, 183, 127, 35, 177, 8, 44, 154, 92, 249, 184, 197, 118, 3, 133, 175, 45, 105, 70, 182, 19, 172, 59, 76, 9, 225, 220, 65, 232, 214, 135, 15, 237, 37, 226, 165, 137, 243, 45, 161, 246), (161, 249, 41, 115, 133, 122, 19, 218, 127, 214, 193, 246, 76, 135, 133, 126, 4, 46, 206, 197, 63, 225, 73, 98, 112, 199, 112, 253, 234, 167, 239, 235, 119, 238, 30, 130, 66, 174, 94, 32), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((109, 68, 17, 204, 254, 202, 120, 47, 252, 135, 237, 159, 201, 22, 57, 146, 217, 225, 202, 178, 77, 234, 105, 11, 150, 107, 50, 49), (238, 121, 103, 221, 202, 166, 221, 178, 66, 187, 178, 206, 225, 251, 247, 134, 50, 23, 45, 116, 249, 188, 11, 230, 69, 213, 44, 25, 199, 238, 91, 150, 31, 246, 118, 84, 50, 1, 51, 114, 246, 147, 183, 202, 127, 68, 137, 2, 95, 171, 110, 89, 153, 133, 198, 62, 85, 30, 55, 51), (34, 27, 177, 143, 8, 108, 115, 150, 183, 62, 203, 104, 178, 12, 232, 239, 97, 115, 154, 109, 185, 123, 42, 184, 163, 57, 103, 34, 169, 59, 225, 199, 89, 133, 90, 149, 222, 134, 212, 105), GNUTLS_MAC_SHA224),
+ TEST_VECTOR((221, 29, 145, 183, 217, 11, 43, 211, 19, 133, 51, 206, 146, 178, 114, 251, 248, 163, 105, 49, 106, 239, 226, 66, 230, 89, 204, 10, 226, 56, 175, 224), (1, 50, 43, 150, 179, 10, 205, 25, 121, 121, 68, 78, 70, 142, 28, 92, 104, 89, 191, 27, 28, 249, 81, 183, 231, 37, 48, 62, 35, 126, 70, 184, 100, 161, 69, 250, 178, 94, 81, 123, 8, 248, 104, 61, 3, 21, 187, 41, 17, 216, 10, 14, 138, 186, 23, 243, 180, 19, 250, 172), (16, 98, 19, 66, 191, 176, 253, 64, 4, 108, 14, 41, 242, 207, 219, 240), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((50, 196, 0, 56, 114, 161, 70, 25, 64, 35, 234, 193, 189, 167, 77, 223, 43, 102, 151, 125, 173, 138, 85, 75, 151, 76, 162, 166, 47, 126, 79, 67), (51, 216, 207, 109, 12, 117, 159, 182, 34, 216, 103, 234, 140, 241, 40, 93, 228, 2, 10, 248, 28, 194, 135, 173, 223, 56, 204, 45, 164, 100, 62, 109, 179, 178, 21, 173, 62, 51, 191, 196, 120, 119, 195, 98, 14, 51, 104, 135, 195, 201, 173, 74, 28, 108, 4, 118, 176, 249, 10, 51), (245, 147, 175, 14, 26, 73, 42, 123, 144, 74, 38, 98, 137, 127, 161, 193), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((60, 135, 233, 204, 152, 87, 155, 39, 73, 255, 146, 200, 184, 35, 162, 173, 107, 54, 122, 194, 102, 34, 231, 181, 184, 10, 44, 230, 244, 80, 227, 97), (119, 125, 102, 162, 76, 45, 60, 195, 41, 156, 160, 113, 143, 79, 109, 205, 17, 97, 236, 190, 246, 235, 60, 113, 240, 188, 20, 91, 78, 118, 90, 110, 236, 232, 7, 167, 76, 167, 166, 152, 213, 91, 46, 176, 211, 13, 141, 62, 92, 215, 31, 210, 160, 43, 86, 8, 39, 76, 149, 195), (234, 100, 37, 240, 56, 3, 242, 240, 108, 66, 216, 186, 17, 206, 78, 233), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((222, 31, 74, 191, 231, 140, 77, 214, 240, 35, 49, 192, 87, 239, 169, 57, 174, 45, 177, 241, 231, 231, 198, 80, 224, 117, 55, 210, 89, 177, 234, 114), (76, 31, 0, 25, 141, 118, 243, 99, 13, 50, 96, 245, 109, 148, 245, 37, 7, 57, 79, 74, 152, 205, 194, 147, 125, 74, 186, 167, 110, 187, 63, 212, 9, 168, 118, 157, 240, 116, 220, 0, 41, 23, 239, 129, 138, 72, 82, 207, 0, 79, 2, 37, 239, 196, 102, 50, 17, 160, 140, 93), (116, 24, 42, 232, 30, 232, 140, 106, 22, 52, 255, 73, 145, 190, 185, 238), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((140, 41, 155, 238, 174, 160, 95, 68, 93, 89, 245, 195, 84, 219, 208, 200, 180, 205, 0, 159, 25, 122, 53, 54, 159, 179, 184, 97, 43, 117, 2, 107), (26, 115, 252, 225, 20, 203, 66, 125, 250, 166, 166, 153, 171, 39, 81, 191, 113, 54, 250, 3, 210, 56, 218, 73, 45, 154, 3, 97, 67, 20, 131, 52, 41, 77, 11, 219, 228, 133, 44, 143, 243, 119, 6, 187, 39, 215, 34, 221, 249, 9, 188, 139, 239, 145, 172, 114, 225, 132, 28, 173), (22, 97, 79, 62, 132, 133, 21, 203, 229, 38, 253, 43, 27, 90, 11, 195), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((250, 31, 76, 108, 164, 38, 132, 128, 82, 123, 55, 204, 22, 53, 182, 157, 74, 7, 17, 143, 114, 12, 96, 189, 19, 206, 220, 134, 125, 252, 39, 84), (70, 69, 22, 214, 248, 187, 101, 137, 146, 136, 73, 185, 132, 190, 166, 220, 58, 69, 163, 227, 203, 233, 178, 122, 149, 233, 72, 1, 199, 24, 144, 23, 100, 215, 137, 16, 231, 46, 95, 230, 152, 96, 231, 110, 143, 43, 187, 169, 41, 134, 118, 232, 168, 107, 61, 99, 86, 59, 69, 162), (103, 80, 123, 143, 188, 129, 61, 35, 135, 246, 155, 196, 211, 189, 164, 74), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((171, 18, 202, 71, 9, 202, 56, 53, 12, 175, 86, 2, 238, 229, 33, 142, 201, 80, 53, 61, 25, 230, 93, 233, 239, 196, 220, 45, 25, 254, 48, 23), (168, 218, 91, 37, 228, 242, 146, 193, 73, 200, 143, 146, 3, 197, 55, 8, 34, 25, 60, 218, 193, 53, 251, 205, 107, 3, 244, 35, 0, 184, 195, 114, 246, 133, 32, 221, 59, 82, 92, 121, 170, 37, 242, 80, 183, 134, 230, 222, 127, 93, 115, 181, 251, 70, 201, 135, 103, 28, 127, 118), (167, 244, 65, 135, 212, 235, 231, 89, 185, 163, 126, 72, 74, 132, 78, 43), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((18, 169, 196, 179, 146, 27, 78, 194, 117, 78, 28, 240, 147, 163, 138, 152, 112, 42, 207, 11, 142, 179, 15, 75, 246, 84, 184, 227, 161, 13, 57, 144), (197, 23, 14, 110, 103, 204, 239, 235, 232, 65, 94, 226, 251, 100, 41, 223, 55, 214, 194, 238, 143, 189, 214, 185, 112, 195, 169, 141, 72, 110, 135, 24, 194, 32, 47, 127, 192, 159, 228, 56, 213, 61, 253, 174, 235, 8, 116, 239, 15, 215, 180, 223, 162, 9, 204, 156, 92, 81, 43, 170), (157, 26, 49, 33, 118, 11, 23, 234, 120, 126, 15, 100, 201, 11, 241, 9), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((33, 139, 15, 118, 152, 9, 84, 204, 56, 31, 38, 70, 99, 105, 7, 231, 2, 7, 143, 121, 2, 161, 137, 73, 82, 150, 101, 71, 172, 233, 27, 25), (22, 203, 139, 237, 179, 99, 180, 121, 81, 83, 161, 5, 198, 4, 146, 145, 241, 151, 142, 123, 42, 171, 1, 171, 100, 226, 156, 155, 181, 98, 65, 140, 243, 171, 79, 30, 230, 17, 29, 94, 210, 229, 142, 190, 58, 217, 102, 85, 136, 224, 228, 217, 222, 174, 133, 36, 181, 183, 158, 216), (128, 23, 95, 213, 201, 202, 37, 44, 82, 189, 203, 83, 2, 222, 61, 177), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((52, 51, 242, 197, 56, 36, 214, 238, 190, 17, 225, 30, 182, 86, 218, 151, 64, 197, 163, 66, 245, 118, 157, 247, 254, 23, 196, 196, 128, 17, 50, 202), (7, 227, 248, 255, 3, 230, 175, 90, 173, 80, 60, 172, 177, 219, 17, 157, 49, 120, 187, 211, 226, 55, 120, 136, 214, 245, 230, 183, 191, 123, 143, 124, 86, 58, 136, 170, 138, 119, 136, 72, 244, 220, 1, 178, 156, 175, 133, 163, 178, 48, 126, 60, 223, 227, 222, 30, 112, 67, 221, 239), (174, 129, 145, 108, 211, 100, 28, 89, 137, 117, 18, 100, 155, 101, 114, 82), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((226, 4, 214, 212, 102, 170, 213, 7, 255, 175, 109, 109, 171, 10, 91, 38, 21, 44, 158, 33, 231, 100, 55, 4, 100, 227, 96, 200, 251, 199, 101, 198), (123, 3, 185, 141, 159, 148, 184, 153, 229, 145, 243, 239, 38, 75, 113, 177, 147, 251, 167, 4, 60, 126, 149, 60, 222, 35, 188, 83, 132, 188, 26, 98, 147, 88, 1, 21, 250, 227, 73, 95, 216, 69, 218, 219, 208, 43, 214, 69, 92, 244, 141, 15, 98, 179, 62, 98, 54, 74, 58, 128), (119, 13, 250, 182, 166, 164, 164, 190, 224, 37, 127, 243, 53, 33, 63, 120, 216, 40, 123, 79, 213, 55, 213, 193, 255, 250, 149, 105, 16, 231, 199, 121), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((174, 238, 202, 96, 246, 137, 164, 65, 177, 59, 12, 188, 212, 65, 216, 45, 240, 207, 135, 218, 194, 54, 41, 13, 236, 232, 147, 29, 248, 215, 3, 23), (88, 142, 192, 65, 229, 115, 59, 112, 49, 33, 44, 85, 56, 239, 228, 246, 170, 250, 76, 218, 139, 146, 93, 38, 31, 90, 38, 136, 240, 7, 179, 172, 36, 14, 225, 41, 145, 231, 123, 140, 184, 83, 134, 120, 97, 89, 102, 22, 74, 129, 135, 43, 209, 207, 203, 251, 57, 164, 244, 80), (62, 129, 214, 17, 60, 238, 60, 82, 158, 206, 223, 248, 154, 105, 153, 206, 37, 182, 24, 193, 94, 225, 209, 157, 69, 203, 55, 106, 28, 142, 35, 116), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((149, 200, 247, 110, 17, 54, 126, 181, 85, 38, 162, 179, 147, 174, 144, 101, 131, 209, 203, 221, 71, 150, 33, 70, 245, 6, 204, 124, 172, 18, 244, 100), (202, 214, 14, 144, 75, 158, 156, 139, 254, 180, 168, 26, 127, 103, 211, 189, 220, 192, 94, 100, 37, 88, 112, 64, 55, 112, 243, 83, 58, 230, 221, 99, 76, 234, 165, 108, 83, 230, 136, 189, 19, 122, 230, 1, 137, 53, 243, 75, 159, 176, 132, 234, 72, 228, 198, 136, 246, 187, 179, 136), (202, 250, 92, 160, 63, 95, 190, 42, 36, 32, 4, 171, 203, 211, 222, 16, 89, 199, 64, 123, 30, 229, 121, 37, 81, 36, 175, 24, 155, 224, 181, 86), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((77, 5, 57, 31, 214, 251, 30, 41, 46, 120, 171, 150, 25, 177, 183, 42, 125, 99, 238, 89, 215, 67, 93, 215, 24, 151, 185, 255, 126, 231, 174, 112), (240, 120, 230, 249, 183, 248, 45, 100, 85, 79, 166, 182, 4, 200, 8, 241, 155, 31, 106, 214, 114, 125, 183, 170, 111, 28, 134, 105, 78, 16, 75, 82, 86, 200, 180, 3, 153, 25, 100, 100, 129, 215, 234, 36, 82, 199, 44, 23, 163, 232, 215, 211, 145, 98, 133, 70, 10, 165, 235, 129), (107, 22, 232, 245, 59, 131, 26, 165, 232, 107, 249, 122, 92, 79, 163, 125, 8, 155, 193, 114, 218, 90, 30, 127, 102, 45, 212, 165, 149, 51, 154, 183), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((15, 104, 168, 47, 241, 103, 22, 52, 204, 145, 54, 197, 100, 169, 224, 42, 118, 118, 33, 221, 116, 161, 191, 92, 36, 18, 155, 128, 130, 20, 183, 82), (100, 133, 153, 128, 156, 44, 78, 124, 106, 94, 108, 68, 159, 0, 49, 235, 245, 92, 54, 97, 168, 149, 180, 77, 176, 87, 46, 232, 128, 131, 177, 244, 177, 38, 2, 170, 85, 252, 29, 241, 80, 166, 90, 109, 110, 237, 160, 170, 121, 164, 52, 161, 3, 155, 145, 181, 165, 143, 199, 241), (226, 151, 100, 15, 119, 104, 72, 93, 74, 110, 124, 254, 36, 95, 139, 250, 132, 112, 13, 153, 118, 38, 146, 234, 26, 66, 92, 204, 2, 117, 232, 245), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((67, 238, 246, 216, 36, 253, 130, 4, 5, 98, 106, 185, 182, 215, 159, 31, 208, 78, 18, 106, 184, 225, 119, 41, 227, 175, 199, 203, 90, 247, 148, 248), (94, 38, 155, 90, 123, 222, 220, 195, 232, 117, 226, 114, 86, 147, 162, 87, 252, 96, 1, 26, 247, 220, 214, 138, 51, 88, 80, 127, 226, 155, 6, 89, 202, 102, 149, 29, 170, 5, 161, 80, 50, 3, 54, 80, 188, 88, 162, 120, 64, 248, 251, 233, 244, 8, 139, 144, 48, 115, 143, 104), (240, 163, 57, 236, 188, 174, 106, 221, 26, 251, 39, 218, 59, 164, 10, 19, 32, 198, 66, 122, 88, 175, 185, 220, 54, 107, 33, 155, 126, 178, 158, 207), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((229, 243, 29, 152, 161, 63, 35, 144, 179, 84, 219, 160, 142, 30, 133, 17, 111, 153, 165, 108, 46, 135, 97, 211, 134, 149, 138, 13, 10, 136, 138, 41), (2, 17, 63, 69, 21, 27, 99, 243, 116, 207, 205, 177, 190, 222, 65, 206, 242, 34, 106, 66, 182, 192, 44, 159, 9, 15, 159, 61, 179, 157, 78, 152, 168, 37, 140, 66, 226, 114, 36, 39, 156, 212, 92, 37, 1, 202, 69, 160, 8, 216, 243, 137, 21, 229, 180, 91, 139, 153, 95, 91), (152, 231, 160, 35, 9, 42, 48, 100, 5, 9, 2, 200, 185, 12, 116, 157, 114, 0, 86, 38, 224, 41, 110, 29, 251, 40, 193, 14, 69, 11, 45, 211), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((230, 207, 164, 134, 77, 49, 254, 9, 150, 15, 255, 150, 138, 198, 47, 3, 182, 246, 59, 90, 34, 28, 201, 92, 58, 16, 88, 180, 182, 15, 233, 188), (70, 112, 167, 194, 200, 245, 100, 59, 117, 234, 76, 238, 216, 126, 37, 62, 88, 255, 170, 135, 71, 34, 153, 22, 13, 53, 36, 7, 83, 243, 22, 76, 8, 32, 55, 75, 31, 75, 237, 178, 220, 52, 105, 44, 139, 126, 6, 199, 149, 30, 231, 63, 22, 69, 177, 14, 63, 39, 45, 23), (79, 32, 142, 115, 6, 176, 118, 191, 6, 19, 63, 67, 154, 102, 23, 163, 214, 80, 37, 60, 248, 119, 117, 195, 214, 215, 254, 222, 50, 19, 159, 79), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((47, 24, 11, 26, 16, 68, 93, 61, 41, 104, 59, 63, 172, 184, 86, 128, 118, 137, 198, 222, 84, 199, 96, 246, 5, 12, 51, 41, 164, 161, 222, 78), (77, 72, 202, 73, 162, 121, 167, 155, 249, 179, 169, 227, 70, 195, 175, 116, 146, 111, 171, 106, 216, 129, 2, 125, 238, 106, 111, 64, 220, 246, 122, 221, 4, 239, 236, 77, 134, 223, 49, 187, 252, 25, 13, 67, 227, 167, 174, 234, 155, 171, 206, 186, 234, 211, 176, 123, 105, 221, 61, 110), (119, 101, 210, 69, 253, 241, 67, 182, 202, 67, 89, 162, 80, 58, 209, 216, 234, 140, 170, 125, 168, 213, 86, 177, 254, 142, 37, 196, 76, 112, 219, 225), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((46, 176, 164, 159, 211, 25, 154, 87, 38, 79, 116, 107, 28, 138, 203, 199, 111, 124, 229, 18, 35, 247, 33, 52, 89, 15, 187, 235, 49, 118, 38, 75), (152, 10, 144, 142, 211, 139, 110, 105, 157, 243, 244, 78, 101, 31, 10, 211, 169, 210, 9, 211, 134, 124, 73, 94, 82, 103, 56, 85, 208, 158, 79, 26, 88, 251, 71, 112, 103, 196, 0, 202, 204, 169, 171, 146, 96, 226, 5, 196, 85, 105, 5, 242, 114, 121, 37, 86, 18, 128, 99, 156), (6, 213, 173, 194, 213, 197, 23, 191, 64, 64, 108, 198, 187, 86, 85, 59, 34, 47, 112, 171, 242, 187, 80, 85, 132, 0, 14, 136, 98, 139, 175, 23), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((220, 96, 51, 141, 136, 78, 236, 183, 41, 117, 198, 3, 194, 123, 54, 6, 5, 1, 23, 86, 198, 151, 196, 252, 56, 143, 81, 118, 239, 129, 239, 177), (68, 215, 170, 8, 254, 186, 38, 9, 60, 20, 151, 156, 18, 44, 36, 55, 195, 17, 123, 99, 183, 136, 65, 205, 16, 164, 188, 94, 213, 92, 86, 88, 106, 216, 152, 109, 85, 48, 125, 202, 29, 25, 142, 220, 255, 188, 81, 106, 143, 190, 97, 82, 170, 66, 140, 221, 128, 12, 6, 45), (41, 172, 7, 220, 207, 31, 40, 213, 6, 205, 98, 62, 110, 63, 194, 250, 37, 91, 214, 11), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((122, 126, 206, 228, 240, 76, 31, 84, 83, 242, 155, 140, 101, 190, 233, 9, 246, 115, 196, 79, 101, 232, 249, 204, 24, 195, 28, 50, 233, 188, 252, 90), (14, 43, 83, 221, 99, 0, 142, 6, 99, 150, 42, 37, 218, 156, 213, 95, 194, 234, 55, 113, 72, 120, 61, 162, 41, 255, 126, 59, 214, 20, 42, 67, 200, 84, 182, 181, 208, 109, 135, 181, 53, 147, 111, 30, 220, 124, 208, 103, 232, 219, 186, 34, 10, 31, 154, 89, 50, 179, 42, 100), (150, 251, 142, 249, 56, 10, 201, 222, 39, 17, 239, 90, 131, 36, 158, 96, 141, 199, 191, 252), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((222, 113, 41, 93, 197, 10, 199, 110, 181, 87, 148, 16, 134, 158, 145, 139, 123, 231, 87, 175, 166, 6, 197, 9, 190, 67, 120, 189, 152, 237, 166, 134), (51, 202, 151, 79, 138, 26, 6, 91, 117, 9, 12, 52, 201, 72, 68, 153, 16, 73, 86, 17, 226, 142, 204, 98, 206, 210, 158, 91, 58, 231, 98, 23, 225, 57, 38, 112, 65, 186, 64, 190, 35, 93, 225, 48, 67, 140, 27, 20, 170, 131, 50, 150, 235, 142, 75, 171, 226, 16, 16, 16), (56, 93, 96, 83, 128, 144, 164, 90, 43, 37, 68, 39, 89, 5, 196, 193, 110, 159, 35, 226), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((56, 157, 224, 185, 20, 102, 28, 138, 201, 170, 241, 29, 38, 31, 98, 97, 186, 244, 101, 40, 134, 207, 32, 210, 177, 61, 246, 123, 226, 227, 177, 133), (146, 179, 212, 126, 160, 66, 89, 29, 181, 181, 49, 144, 126, 9, 164, 90, 96, 169, 197, 197, 254, 2, 81, 128, 107, 120, 5, 182, 65, 197, 179, 235, 205, 225, 77, 108, 181, 66, 180, 203, 36, 43, 4, 245, 169, 182, 11, 44, 102, 209, 162, 76, 102, 20, 31, 224, 184, 24, 233, 60), (177, 42, 78, 32, 1, 128, 210, 13, 164, 4, 180, 76, 149, 38, 57, 169, 85, 221, 131, 208), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((49, 26, 247, 56, 116, 225, 58, 138, 202, 217, 129, 73, 1, 19, 147, 64, 101, 179, 189, 93, 68, 142, 43, 184, 223, 166, 139, 112, 198, 157, 125, 69), (234, 32, 252, 157, 50, 205, 220, 120, 220, 188, 162, 234, 214, 197, 198, 103, 68, 218, 133, 217, 91, 100, 61, 63, 250, 178, 208, 226, 213, 103, 125, 211, 162, 115, 19, 21, 59, 1, 156, 252, 211, 59, 62, 48, 94, 214, 100, 4, 4, 43, 45, 176, 227, 222, 34, 103, 203, 85, 127, 216), (198, 232, 109, 16, 67, 51, 63, 182, 144, 173, 35, 39, 74, 144, 130, 4, 214, 188, 187, 172), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((117, 111, 153, 128, 203, 239, 234, 57, 131, 80, 184, 134, 202, 76, 27, 41, 16, 112, 139, 91, 129, 84, 160, 236, 75, 150, 72, 172, 119, 185, 215, 220), (63, 9, 170, 21, 210, 250, 118, 156, 110, 138, 51, 128, 188, 85, 132, 72, 39, 186, 62, 166, 76, 207, 23, 123, 235, 75, 251, 213, 20, 43, 57, 99, 191, 105, 104, 3, 168, 153, 116, 170, 125, 90, 240, 25, 44, 213, 37, 168, 59, 113, 205, 142, 231, 176, 188, 146, 240, 123, 149, 21), (227, 188, 98, 179, 138, 123, 60, 126, 127, 203, 158, 240, 7, 170, 74, 214, 169, 187, 81, 156), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((174, 129, 91, 254, 34, 4, 7, 188, 230, 99, 143, 32, 174, 250, 16, 155, 99, 199, 56, 46, 145, 215, 187, 139, 1, 14, 215, 198, 216, 211, 117, 125), (162, 33, 241, 163, 98, 62, 202, 95, 99, 133, 181, 126, 122, 254, 103, 209, 52, 1, 28, 96, 88, 227, 151, 125, 249, 119, 189, 240, 199, 171, 14, 20, 182, 213, 192, 89, 243, 153, 72, 152, 41, 18, 176, 71, 208, 1, 3, 220, 72, 54, 229, 155, 122, 71, 2, 34, 219, 174, 114, 202), (237, 94, 135, 109, 118, 34, 125, 10, 127, 26, 207, 92, 160, 140, 129, 41, 149, 48, 63, 178), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((213, 17, 12, 128, 138, 149, 28, 95, 227, 106, 164, 133, 47, 189, 231, 224, 188, 55, 42, 44, 105, 163, 90, 207, 200, 144, 204, 159, 247, 142, 64, 251), (244, 81, 135, 7, 42, 125, 120, 254, 145, 40, 47, 88, 37, 218, 235, 37, 106, 40, 168, 24, 199, 10, 40, 82, 98, 176, 128, 205, 62, 226, 236, 120, 81, 37, 178, 126, 64, 38, 172, 150, 136, 165, 234, 230, 87, 219, 87, 140, 210, 7, 149, 98, 73, 240, 74, 6, 72, 112, 214, 119), (14, 125, 226, 95, 197, 89, 150, 156, 8, 217, 115, 171, 64, 121, 93, 247, 78, 81, 150, 93), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((74, 162, 90, 97, 248, 179, 31, 6, 30, 15, 193, 213, 65, 222, 178, 14, 9, 118, 99, 204, 87, 5, 78, 31, 154, 52, 121, 137, 216, 23, 45, 98), (228, 115, 254, 88, 119, 250, 19, 124, 80, 190, 173, 194, 41, 81, 135, 241, 182, 110, 53, 200, 11, 120, 100, 191, 1, 193, 198, 32, 252, 9, 137, 57, 145, 80, 14, 154, 147, 133, 26, 225, 34, 23, 9, 17, 86, 43, 246, 238, 60, 117, 213, 221, 234, 222, 210, 120, 20, 98, 61, 44), (226, 53, 255, 114, 217, 192, 166, 74, 128, 205, 134, 253, 178, 111, 28, 216, 116, 14, 39, 4), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((38, 178, 149, 86, 16, 108, 6, 168, 92, 105, 80, 170, 242, 11, 94, 8, 165, 35, 232, 14, 25, 138, 114, 91, 105, 226, 63, 233, 59, 210, 225, 109), (189, 151, 63, 155, 198, 255, 2, 38, 178, 172, 198, 130, 224, 8, 75, 140, 103, 178, 133, 234, 155, 139, 131, 137, 56, 209, 143, 150, 222, 132, 82, 31, 228, 125, 86, 3, 55, 17, 95, 130, 50, 215, 101, 22, 103, 81, 241, 183, 2, 110, 96, 141, 37, 236, 101, 4, 52, 109, 16, 109), (226, 59, 25, 125, 77, 95, 216, 8, 28, 165, 77, 216, 106, 29, 69, 156, 202, 124, 105, 176), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((196, 190, 219, 221, 182, 100, 147, 231, 199, 37, 154, 59, 187, 194, 95, 140, 126, 12, 167, 254, 40, 77, 146, 212, 49, 217, 205, 153, 160, 210, 20, 172), (28, 105, 197, 71, 102, 121, 30, 49, 92, 44, 197, 196, 126, 205, 63, 250, 184, 125, 13, 39, 61, 217, 32, 231, 9, 85, 129, 76, 34, 14, 172, 172, 230, 165, 148, 101, 66, 218, 61, 254, 36, 255, 98, 107, 72, 151, 137, 140, 175, 183, 219, 131, 189, 255, 60, 20, 250, 70, 253, 75), (29, 164, 118, 56, 214, 201, 196, 208, 77, 116, 212, 100, 11, 189, 66, 171, 129, 77, 158, 140, 194, 47, 67, 38, 105, 82, 57, 249, 107, 6, 147, 241, 45, 13, 209, 21, 44, 244, 68, 48), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((34, 37, 108, 165, 113, 213, 200, 150, 219, 128, 168, 117, 143, 248, 28, 248, 99, 29, 43, 195, 140, 126, 118, 243, 186, 251, 12, 42, 245, 64, 163, 86), (157, 210, 220, 217, 123, 146, 98, 81, 181, 12, 97, 17, 217, 136, 226, 149, 27, 2, 172, 204, 20, 55, 2, 200, 137, 32, 207, 54, 132, 143, 124, 115, 23, 86, 171, 5, 55, 203, 38, 226, 39, 37, 241, 29, 224, 105, 229, 51, 88, 2, 176, 203, 86, 193, 88, 221, 117, 1, 71, 145), (161, 26, 163, 177, 169, 61, 44, 225, 23, 85, 8, 102, 194, 141, 105, 116, 207, 98, 103, 25, 56, 91, 136, 104, 16, 26, 113, 165, 210, 170, 121, 59, 194, 60, 60, 253, 235, 229, 46, 201), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((128, 102, 224, 87, 231, 50, 150, 21, 142, 213, 71, 152, 72, 49, 122, 213, 230, 78, 232, 251, 46, 84, 212, 239, 133, 183, 121, 47, 87, 246, 248, 135), (22, 218, 6, 231, 54, 14, 76, 39, 65, 155, 95, 105, 126, 76, 133, 72, 146, 92, 229, 91, 83, 173, 158, 94, 133, 185, 76, 127, 142, 87, 173, 20, 42, 26, 10, 3, 132, 51, 123, 26, 223, 100, 16, 237, 206, 206, 169, 33, 21, 43, 148, 214, 178, 58, 25, 44, 230, 246, 2, 215), (110, 190, 246, 75, 53, 128, 80, 237, 195, 200, 65, 245, 33, 136, 197, 228, 66, 203, 105, 99, 15, 236, 11, 229, 17, 72, 22, 175, 97, 106, 51, 63, 10, 172, 81, 83, 233, 38, 90, 166), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((86, 240, 108, 192, 188, 57, 42, 177, 8, 105, 108, 125, 247, 20, 149, 181, 165, 205, 54, 56, 224, 169, 32, 69, 175, 124, 189, 48, 118, 246, 221, 24), (79, 202, 232, 243, 43, 8, 184, 251, 116, 97, 33, 162, 219, 43, 201, 159, 187, 36, 185, 255, 17, 198, 10, 29, 201, 31, 20, 173, 154, 96, 198, 186, 254, 74, 219, 77, 193, 96, 233, 144, 30, 238, 235, 33, 42, 20, 126, 224, 167, 231, 109, 74, 239, 164, 39, 246, 106, 32, 92, 134), (204, 218, 130, 49, 250, 92, 7, 2, 186, 40, 42, 143, 24, 160, 193, 222, 198, 186, 239, 48, 134, 37, 251, 143, 80, 68, 16, 82, 44, 63, 59, 109, 100, 124, 23, 112, 84, 49, 122, 7), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((97, 127, 27, 104, 16, 197, 81, 170, 92, 33, 135, 139, 0, 101, 99, 81, 70, 96, 105, 212, 26, 220, 127, 238, 28, 237, 63, 47, 52, 50, 67, 92), (33, 19, 247, 0, 92, 88, 11, 119, 6, 9, 144, 194, 163, 249, 232, 200, 130, 95, 13, 126, 147, 163, 246, 159, 32, 142, 187, 91, 151, 196, 136, 218, 189, 13, 231, 199, 240, 14, 8, 180, 81, 93, 178, 192, 46, 24, 36, 249, 110, 113, 201, 162, 26, 24, 7, 156, 75, 100, 157, 129), (3, 37, 177, 200, 95, 61, 37, 173, 94, 188, 46, 123, 56, 12, 254, 222, 107, 60, 138, 218, 26, 240, 208, 213, 188, 217, 210, 179, 76, 41, 8, 49, 21, 22, 139, 138, 239, 84, 197, 132), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((101, 158, 219, 154, 13, 245, 26, 56, 103, 212, 170, 1, 247, 79, 96, 183, 177, 81, 176, 26, 52, 55, 194, 247, 116, 253, 55, 182, 136, 26, 156, 164), (63, 182, 8, 112, 165, 129, 59, 173, 253, 122, 249, 72, 195, 201, 36, 190, 192, 92, 146, 213, 64, 20, 11, 242, 143, 37, 70, 130, 92, 95, 189, 64, 241, 87, 20, 147, 161, 120, 70, 127, 218, 151, 147, 242, 247, 238, 212, 91, 64, 239, 104, 224, 16, 123, 141, 116, 192, 207, 50, 228), (92, 18, 199, 182, 236, 56, 245, 22, 247, 46, 118, 104, 156, 49, 6, 238, 0, 238, 140, 47, 80, 134, 44, 191, 127, 203, 116, 191, 135, 152, 235, 118, 26, 51, 131, 135, 136, 226, 118, 163), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((87, 3, 197, 86, 227, 165, 59, 141, 43, 243, 197, 202, 119, 61, 12, 110, 210, 193, 182, 106, 132, 230, 104, 4, 117, 168, 40, 105, 65, 178, 70, 179), (17, 158, 55, 214, 75, 90, 215, 2, 202, 89, 247, 149, 46, 88, 34, 205, 175, 183, 35, 192, 249, 44, 215, 3, 56, 161, 126, 36, 211, 175, 98, 103, 175, 121, 43, 24, 154, 1, 168, 163, 53, 58, 205, 122, 133, 180, 214, 59, 247, 228, 178, 47, 115, 215, 153, 46, 142, 78, 115, 137), (227, 2, 193, 193, 229, 200, 246, 136, 167, 88, 9, 151, 57, 148, 51, 251, 170, 228, 153, 64, 11, 138, 72, 144, 29, 128, 136, 57, 193, 235, 73, 223, 223, 99, 36, 20, 95, 30, 240, 30), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((154, 110, 131, 185, 27, 217, 153, 115, 126, 87, 126, 68, 145, 66, 218, 224, 89, 104, 231, 116, 178, 35, 193, 24, 93, 197, 116, 218, 120, 92, 147, 204), (75, 88, 69, 198, 115, 114, 2, 99, 43, 41, 70, 195, 87, 157, 157, 69, 130, 180, 117, 223, 163, 115, 148, 91, 10, 188, 104, 200, 240, 218, 163, 101, 32, 23, 148, 57, 8, 108, 104, 9, 170, 24, 32, 148, 69, 59, 192, 191, 254, 240, 220, 40, 136, 185, 98, 149, 252, 214, 228, 66), (233, 14, 62, 217, 2, 168, 235, 31, 198, 120, 35, 175, 83, 74, 43, 72, 70, 107, 242, 197, 135, 125, 173, 10, 173, 199, 214, 255, 116, 29, 143, 67, 123, 46, 109, 0, 49, 132, 105, 96), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((155, 235, 244, 101, 0, 58, 133, 188, 37, 237, 52, 12, 96, 149, 217, 99, 136, 85, 4, 211, 207, 2, 102, 175, 37, 46, 255, 210, 42, 211, 45, 111), (23, 80, 109, 180, 89, 220, 161, 72, 64, 145, 125, 173, 35, 38, 67, 3, 171, 28, 131, 227, 80, 24, 167, 34, 88, 9, 157, 32, 212, 248, 171, 133, 197, 34, 116, 4, 178, 58, 237, 106, 225, 8, 189, 18, 130, 229, 10, 0, 209, 96, 229, 52, 38, 71, 112, 161, 27, 79, 204, 117), (26, 50, 234, 48, 138, 166, 220, 111, 27, 124, 119, 241, 217, 170, 228, 6, 114, 252, 174, 34, 67, 139, 187, 5, 40, 226, 128, 7, 59, 49, 121, 120, 134, 182, 168, 0, 54, 160, 14, 25), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((29, 146, 9, 24, 62, 85, 125, 58, 172, 126, 42, 181, 61, 38, 236, 101, 157, 242, 167, 69, 254, 86, 165, 56, 24, 239, 88, 83, 164, 44, 225, 148), (192, 26, 67, 26, 50, 131, 57, 48, 162, 42, 190, 229, 198, 234, 52, 219, 69, 147, 22, 222, 243, 178, 65, 82, 158, 206, 126, 57, 226, 6, 154, 30, 107, 148, 41, 70, 19, 46, 235, 201, 103, 152, 1, 210, 206, 254, 244, 187, 182, 161, 184, 78, 248, 83, 50, 91, 123, 196, 152, 253), (218, 188, 255, 161, 106, 117, 137, 222, 238, 108, 118, 138, 175, 1, 224, 129, 61, 233, 9, 0, 85, 38, 218, 84, 112, 0, 131, 239, 6, 143, 133, 77, 73, 148, 18, 121, 104, 154, 23, 38), GNUTLS_MAC_SHA256),
+ TEST_VECTOR((33, 110, 208, 68, 118, 156, 76, 57, 8, 24, 142, 206, 97, 96, 26, 248, 129, 156, 48, 245, 1, 209, 41, 149, 223, 96, 142, 6, 245, 224, 230, 7, 171, 84, 245, 66, 238, 45, 164, 25, 6, 223, 219, 73, 113, 242, 15, 157), (99, 142, 149, 6, 162, 199, 190, 105, 234, 52, 107, 132, 98, 154, 1, 12, 14, 34, 91, 117, 72, 245, 8, 22, 44, 137, 242, 156, 29, 219, 253, 112, 71, 44, 43, 88, 231, 220, 138, 166, 165, 176, 102, 2, 241, 200, 237, 73, 72, 205, 167, 156, 98, 112, 130, 24, 226, 106, 192, 226), (212, 177, 68, 187, 64, 199, 202, 190, 209, 57, 99, 215, 212, 49, 142, 114), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((145, 33, 65, 240, 78, 43, 207, 121, 254, 75, 175, 228, 111, 68, 220, 144, 130, 202, 57, 220, 249, 100, 217, 64, 156, 72, 97, 57, 120, 116, 103, 234, 200, 112, 149, 168, 242, 226, 86, 28, 25, 212, 24, 238, 111, 61, 131, 107), (203, 167, 40, 195, 203, 66, 246, 43, 159, 222, 101, 152, 200, 98, 142, 15, 136, 247, 99, 159, 214, 5, 179, 157, 129, 41, 106, 7, 73, 242, 124, 139, 117, 131, 6, 134, 222, 171, 148, 157, 225, 187, 208, 6, 46, 70, 82, 75, 31, 48, 116, 108, 28, 186, 2, 80, 143, 180, 194, 159), (21, 139, 49, 60, 109, 40, 176, 59, 40, 138, 226, 21, 78, 171, 33, 64), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((67, 200, 4, 38, 103, 113, 128, 188, 7, 61, 9, 58, 128, 148, 54, 225, 109, 86, 8, 38, 71, 206, 23, 148, 135, 101, 213, 96, 182, 204, 240, 68, 33, 41, 235, 85, 52, 19, 112, 118, 129, 151, 186, 220, 117, 75, 9, 93), (253, 113, 151, 76, 159, 45, 64, 192, 77, 98, 183, 58, 237, 182, 163, 128, 171, 101, 232, 71, 18, 231, 199, 220, 60, 16, 154, 227, 3, 17, 243, 237, 231, 124, 126, 206, 65, 61, 213, 118, 159, 215, 76, 188, 203, 2, 12, 146, 247, 184, 124, 55, 98, 5, 255, 148, 144, 182, 137, 195), (226, 65, 226, 197, 56, 253, 2, 147, 222, 29, 95, 110, 124, 213, 108, 124), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((6, 242, 154, 93, 104, 74, 46, 235, 98, 53, 50, 72, 74, 105, 26, 216, 80, 64, 217, 135, 36, 141, 200, 44, 81, 217, 176, 183, 231, 190, 81, 132, 126, 144, 118, 226, 111, 167, 211, 59, 230, 133, 98, 7, 254, 76, 224, 53), (86, 250, 255, 212, 145, 22, 1, 194, 23, 114, 95, 216, 22, 254, 12, 26, 31, 189, 143, 21, 83, 242, 13, 129, 1, 66, 47, 199, 32, 88, 202, 185, 194, 230, 58, 98, 102, 167, 38, 7, 92, 195, 30, 220, 10, 50, 127, 164, 68, 155, 94, 201, 129, 168, 109, 145, 65, 147, 42, 185), (162, 223, 3, 240, 33, 32, 56, 203, 131, 186, 70, 142, 158, 5, 165, 2), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((252, 245, 219, 154, 179, 33, 79, 211, 109, 159, 180, 36, 122, 178, 166, 245, 136, 98, 241, 56, 121, 23, 229, 133, 250, 101, 111, 224, 161, 152, 71, 179, 193, 17, 251, 238, 90, 134, 128, 146, 242, 36, 199, 150, 88, 235, 219, 82), (199, 146, 252, 139, 50, 168, 108, 148, 33, 43, 92, 132, 95, 199, 138, 154, 102, 217, 78, 249, 131, 120, 228, 216, 0, 179, 105, 245, 67, 240, 160, 119, 253, 224, 182, 177, 9, 239, 180, 198, 186, 207, 161, 80, 34, 73, 221, 193, 227, 156, 124, 86, 223, 190, 59, 40, 93, 142, 25, 112), (183, 91, 12, 149, 174, 96, 234, 207, 126, 215, 182, 162, 22, 192, 163, 149), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((65, 121, 163, 76, 172, 137, 222, 5, 60, 192, 225, 85, 125, 65, 186, 150, 194, 174, 164, 227, 90, 13, 48, 77, 254, 45, 69, 145, 223, 213, 222, 237, 206, 148, 255, 199, 186, 106, 186, 139, 23, 220, 218, 14, 156, 248, 196, 32), (59, 250, 185, 95, 34, 252, 68, 110, 14, 54, 130, 238, 25, 127, 52, 219, 8, 95, 242, 64, 136, 251, 106, 38, 41, 152, 120, 163, 9, 234, 225, 18, 238, 50, 191, 72, 130, 226, 24, 173, 10, 97, 139, 48, 98, 214, 133, 112, 126, 18, 97, 193, 93, 98, 209, 76, 92, 233, 88, 208), (73, 162, 89, 5, 193, 46, 249, 254, 206, 88, 192, 162, 134, 16, 120, 198), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((129, 110, 73, 134, 128, 229, 204, 57, 184, 38, 71, 9, 181, 8, 175, 101, 58, 80, 185, 39, 252, 189, 206, 255, 46, 190, 98, 186, 58, 37, 183, 153, 80, 38, 141, 49, 20, 172, 73, 22, 140, 87, 196, 25, 253, 119, 220, 80), (64, 72, 108, 178, 44, 172, 221, 222, 135, 11, 114, 125, 232, 30, 17, 102, 126, 249, 44, 180, 249, 32, 206, 127, 47, 128, 160, 239, 41, 173, 208, 22, 20, 44, 226, 105, 78, 134, 110, 29, 99, 27, 92, 28, 19, 186, 30, 63, 208, 221, 201, 161, 100, 71, 194, 1, 134, 250, 193, 59), (121, 168, 103, 192, 51, 61, 52, 111, 13, 248, 234, 44, 109, 76, 177, 75), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((108, 252, 87, 10, 74, 220, 235, 204, 184, 101, 28, 109, 181, 4, 231, 101, 54, 64, 121, 239, 52, 49, 92, 120, 53, 70, 96, 90, 196, 140, 194, 170, 147, 60, 111, 16, 232, 36, 172, 195, 199, 51, 138, 9, 192, 30, 26, 48), (213, 248, 238, 109, 227, 126, 61, 26, 84, 195, 112, 188, 42, 128, 200, 135, 73, 165, 70, 133, 124, 96, 198, 238, 109, 242, 47, 79, 22, 107, 225, 136, 189, 41, 153, 135, 15, 165, 252, 193, 215, 204, 69, 88, 40, 243, 68, 110, 106, 69, 10, 20, 166, 103, 231, 21, 211, 193, 102, 34), (124, 248, 68, 103, 127, 137, 112, 40, 90, 209, 72, 233, 144, 74, 177, 55), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((214, 212, 84, 151, 94, 223, 21, 152, 252, 85, 50, 197, 195, 217, 250, 14, 205, 53, 126, 165, 135, 176, 96, 28, 144, 199, 81, 87, 41, 168, 75, 226, 140, 12, 147, 19, 166, 236, 117, 123, 140, 42, 245, 193, 126, 153, 70, 117), (92, 62, 223, 77, 133, 105, 49, 216, 63, 137, 57, 190, 154, 36, 94, 243, 70, 56, 244, 6, 222, 228, 122, 174, 81, 98, 167, 31, 15, 104, 196, 108, 149, 206, 222, 70, 250, 69, 42, 131, 208, 105, 30, 125, 6, 218, 154, 178, 0, 253, 95, 178, 247, 197, 242, 140, 138, 18, 44, 65), (11, 20, 5, 92, 251, 132, 26, 70, 82, 89, 184, 13, 195, 232, 125, 144), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((214, 37, 105, 195, 102, 159, 16, 18, 201, 102, 245, 74, 197, 172, 18, 29, 138, 137, 135, 21, 130, 52, 123, 19, 178, 8, 222, 253, 80, 205, 59, 196, 144, 140, 152, 150, 37, 123, 16, 52, 91, 236, 45, 64, 223, 43, 108, 93), (145, 140, 2, 68, 163, 167, 135, 14, 58, 228, 248, 192, 118, 40, 187, 117, 74, 15, 111, 138, 82, 19, 125, 84, 156, 126, 158, 23, 16, 59, 66, 160, 41, 104, 136, 87, 24, 94, 96, 132, 112, 149, 63, 120, 124, 201, 122, 126, 215, 94, 122, 54, 9, 238, 210, 243, 177, 162, 14, 57), (45, 196, 82, 74, 236, 203, 90, 33, 172, 241, 240, 177, 48, 83, 245, 165), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((143, 202, 32, 20, 115, 67, 63, 45, 200, 246, 174, 81, 228, 141, 225, 165, 101, 76, 230, 135, 231, 17, 210, 214, 95, 13, 197, 218, 111, 238, 154, 106, 61, 185, 216, 83, 93, 62, 68, 85, 171, 83, 211, 88, 80, 200, 130, 114), (25, 91, 216, 138, 162, 212, 33, 25, 18, 51, 79, 226, 253, 155, 210, 69, 34, 247, 217, 251, 8, 224, 71, 71, 96, 155, 195, 79, 37, 56, 8, 154, 157, 40, 187, 199, 11, 46, 19, 54, 195, 100, 55, 83, 206, 198, 229, 205, 63, 36, 108, 170, 145, 94, 60, 58, 107, 148, 211, 182), (245, 26, 200, 107, 15, 70, 35, 136, 209, 137, 237, 1, 151, 239, 153, 194, 255, 58, 101, 129, 109, 132, 66, 229, 234, 48, 67, 151, 185, 141, 209, 31), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((150, 196, 93, 206, 121, 160, 45, 43, 252, 42, 16, 168, 231, 68, 201, 116, 129, 46, 106, 155, 131, 71, 76, 229, 55, 67, 252, 179, 52, 184, 125, 130, 111, 65, 27, 173, 131, 109, 224, 23, 121, 12, 254, 7, 8, 127, 139, 2), (128, 105, 140, 217, 136, 224, 43, 27, 187, 13, 2, 193, 187, 43, 218, 245, 68, 255, 219, 53, 39, 237, 230, 33, 210, 242, 245, 234, 180, 164, 150, 78, 245, 48, 55, 142, 148, 174, 154, 183, 72, 77, 30, 239, 133, 72, 50, 213, 187, 32, 74, 139, 255, 33, 101, 26, 158, 60, 231, 88), (142, 241, 224, 252, 38, 211, 153, 127, 152, 90, 181, 86, 112, 102, 57, 28, 13, 140, 237, 84, 241, 205, 171, 206, 87, 181, 172, 202, 190, 33, 239, 120), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((130, 44, 118, 74, 27, 17, 112, 133, 193, 15, 14, 104, 152, 20, 210, 191, 189, 155, 67, 40, 127, 26, 140, 117, 215, 149, 169, 131, 26, 40, 97, 132, 200, 88, 111, 53, 119, 182, 229, 187, 206, 22, 55, 146, 94, 4, 252, 71), (175, 52, 97, 16, 185, 65, 177, 29, 33, 137, 49, 108, 159, 194, 185, 244, 33, 55, 117, 165, 215, 54, 141, 53, 65, 38, 120, 162, 143, 205, 3, 176, 127, 5, 73, 102, 110, 253, 243, 12, 128, 240, 171, 85, 99, 114, 10, 86, 239, 97, 106, 19, 187, 143, 119, 128, 3, 111, 192, 142), (224, 174, 35, 92, 184, 35, 128, 82, 123, 231, 105, 52, 166, 150, 34, 57, 109, 144, 231, 191, 167, 226, 210, 149, 228, 55, 91, 206, 224, 209, 177, 1), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((52, 14, 33, 45, 117, 142, 131, 204, 91, 137, 228, 181, 106, 134, 238, 140, 150, 49, 174, 78, 75, 186, 236, 21, 172, 9, 94, 164, 64, 123, 199, 182, 52, 173, 99, 13, 208, 190, 133, 169, 28, 8, 168, 199, 225, 225, 3, 11), (60, 213, 86, 26, 209, 47, 173, 252, 228, 8, 224, 65, 128, 175, 206, 227, 139, 131, 21, 107, 158, 75, 224, 119, 156, 79, 13, 185, 226, 107, 254, 92, 205, 67, 225, 89, 33, 151, 124, 210, 107, 29, 184, 40, 139, 128, 8, 158, 183, 209, 187, 215, 245, 158, 16, 17, 179, 225, 139, 81), (5, 250, 87, 123, 112, 129, 33, 14, 124, 157, 230, 157, 176, 61, 124, 32, 38, 207, 68, 105, 169, 11, 250, 41, 241, 194, 193, 8, 24, 212, 99, 224), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((190, 183, 219, 222, 126, 10, 138, 204, 162, 243, 235, 248, 195, 122, 30, 156, 49, 142, 68, 123, 149, 146, 249, 63, 201, 2, 30, 105, 8, 136, 57, 26, 53, 72, 16, 185, 103, 62, 30, 36, 0, 240, 80, 96, 211, 170, 184, 81), (86, 11, 226, 156, 98, 236, 163, 56, 85, 189, 28, 199, 10, 223, 175, 78, 126, 171, 164, 254, 85, 7, 93, 70, 110, 145, 70, 122, 196, 244, 185, 190, 182, 120, 225, 178, 201, 97, 81, 26, 177, 42, 250, 40, 211, 74, 17, 205, 46, 226, 177, 81, 96, 155, 200, 81, 3, 109, 24, 69), (99, 249, 109, 51, 57, 227, 85, 72, 112, 145, 40, 112, 18, 216, 212, 98, 128, 56, 117, 103, 175, 182, 117, 23, 172, 97, 109, 52, 15, 163, 100, 102), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((163, 96, 240, 181, 22, 252, 53, 167, 109, 29, 74, 158, 198, 160, 142, 133, 107, 142, 250, 147, 16, 65, 19, 152, 191, 26, 198, 159, 40, 83, 147, 0, 188, 34, 86, 215, 99, 136, 229, 4, 193, 246, 12, 139, 96, 230, 6, 152), (2, 6, 250, 245, 201, 172, 64, 234, 172, 169, 161, 209, 106, 199, 31, 25, 226, 222, 132, 77, 178, 231, 62, 79, 183, 227, 69, 103, 226, 33, 213, 172, 188, 105, 49, 65, 39, 69, 220, 176, 176, 94, 17, 146, 132, 210, 28, 75, 179, 249, 169, 57, 39, 23, 80, 246, 135, 132, 253, 157), (136, 236, 238, 116, 42, 7, 31, 157, 36, 114, 5, 32, 232, 189, 191, 225, 64, 206, 87, 231, 254, 43, 104, 105, 102, 135, 30, 237, 10, 97, 101, 235), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((220, 135, 91, 47, 57, 60, 29, 64, 194, 65, 38, 27, 9, 24, 121, 6, 1, 200, 185, 8, 96, 132, 72, 247, 102, 230, 232, 174, 207, 165, 228, 146, 126, 117, 116, 175, 64, 48, 4, 125, 152, 177, 20, 104, 16, 130, 136, 227), (198, 58, 227, 185, 149, 175, 238, 74, 195, 21, 75, 249, 239, 198, 187, 16, 229, 55, 115, 106, 181, 188, 66, 127, 60, 55, 107, 232, 251, 129, 170, 94, 7, 100, 164, 176, 22, 94, 170, 176, 165, 25, 236, 255, 69, 230, 246, 199, 105, 234, 102, 75, 221, 105, 53, 201, 77, 138, 206, 194), (71, 61, 198, 169, 128, 214, 226, 70, 91, 250, 61, 2, 231, 229, 52, 27, 156, 234, 94, 9, 242, 119, 103, 165, 197, 143, 125, 182, 11, 95, 116, 75), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((73, 219, 118, 49, 163, 80, 127, 2, 214, 185, 4, 142, 38, 175, 206, 72, 176, 94, 145, 181, 15, 236, 59, 124, 207, 46, 139, 222, 154, 169, 215, 156, 11, 102, 115, 248, 20, 216, 206, 57, 121, 94, 121, 35, 156, 188, 57, 103), (201, 8, 58, 53, 41, 155, 37, 20, 28, 220, 96, 180, 204, 124, 36, 38, 54, 147, 241, 94, 122, 241, 168, 198, 209, 33, 215, 152, 254, 11, 153, 72, 168, 51, 56, 220, 44, 189, 199, 88, 118, 239, 200, 63, 211, 57, 140, 160, 223, 34, 59, 16, 91, 15, 19, 236, 32, 51, 186, 212), (179, 80, 66, 83, 71, 151, 156, 111, 28, 16, 13, 177, 246, 222, 145, 145, 0, 255, 113, 55, 101, 193, 222, 161, 70, 198, 42, 105, 137, 98, 53, 166), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((226, 22, 138, 176, 114, 193, 45, 164, 113, 252, 2, 79, 203, 197, 39, 120, 233, 189, 104, 244, 71, 98, 185, 216, 186, 171, 116, 109, 185, 193, 79, 254, 113, 129, 247, 28, 46, 230, 72, 129, 48, 131, 40, 48, 253, 11, 213, 240), (89, 86, 148, 84, 178, 245, 66, 74, 145, 74, 45, 22, 109, 168, 238, 18, 123, 14, 197, 171, 71, 136, 177, 21, 193, 217, 150, 106, 82, 151, 24, 28, 100, 84, 144, 115, 34, 154, 50, 229, 222, 64, 201, 74, 143, 158, 254, 113, 160, 201, 104, 246, 51, 4, 130, 135, 110, 55, 190, 221), (22, 203, 107, 201, 61, 154, 0, 20, 96, 184, 50, 89, 188, 154, 67, 68, 212, 180, 203, 66, 44, 97, 2, 86, 93, 197, 177, 144, 222, 28, 86, 115), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((0, 161, 45, 60, 228, 255, 117, 166, 227, 15, 65, 243, 85, 124, 130, 106, 241, 50, 107, 99, 2, 244, 206, 136, 123, 173, 61, 51, 23, 165, 72, 200, 192, 58, 5, 114, 132, 220, 195, 141, 139, 198, 144, 189, 74, 86, 95, 71), (36, 197, 192, 178, 200, 16, 223, 160, 142, 53, 215, 254, 235, 184, 199, 142, 12, 215, 38, 201, 46, 205, 66, 217, 23, 16, 19, 115, 140, 162, 83, 26, 148, 127, 82, 60, 55, 246, 76, 219, 4, 48, 91, 217, 105, 209, 214, 249, 236, 212, 100, 5, 210, 130, 128, 249, 104, 80, 11, 167), (174, 243, 213, 124, 141, 167, 217, 88, 44, 93, 28, 98, 214, 182, 72, 150, 218, 155, 27, 14, 64, 18, 164, 76, 220, 61, 207, 75, 112, 173, 108, 102), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((188, 49, 87, 184, 147, 46, 136, 209, 177, 207, 142, 70, 34, 19, 112, 16, 162, 66, 211, 82, 123, 29, 35, 214, 217, 192, 219, 156, 201, 237, 252, 32, 229, 19, 93, 232, 35, 151, 123, 244, 222, 250, 250, 228, 77, 108, 218, 182), (180, 42, 142, 67, 204, 45, 78, 92, 105, 238, 94, 79, 107, 25, 255, 107, 128, 113, 210, 107, 171, 77, 254, 69, 101, 11, 146, 177, 244, 118, 82, 210, 81, 98, 212, 182, 20, 65, 216, 68, 140, 84, 145, 138, 229, 104, 174, 47, 181, 48, 145, 198, 36, 219, 255, 250, 206, 229, 29, 136), (145, 49, 75, 223, 84, 33, 98, 3, 22, 67, 36, 125, 101, 7, 131, 142, 171, 165, 15, 26), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((35, 213, 243, 243, 76, 159, 231, 51, 232, 8, 148, 159, 64, 17, 186, 49, 113, 55, 110, 59, 238, 128, 126, 197, 178, 132, 150, 191, 78, 181, 29, 133, 170, 55, 196, 46, 30, 217, 60, 255, 186, 185, 108, 109, 202, 58, 251, 59), (110, 199, 182, 187, 216, 26, 49, 47, 247, 135, 220, 106, 247, 199, 199, 185, 205, 187, 125, 12, 25, 216, 8, 83, 107, 192, 153, 11, 215, 231, 158, 35, 43, 188, 20, 51, 202, 86, 124, 188, 196, 218, 247, 158, 141, 114, 36, 195, 1, 36, 166, 57, 133, 37, 135, 226, 113, 90, 230, 46), (195, 195, 87, 156, 215, 10, 247, 248, 193, 132, 197, 128, 34, 79, 39, 247, 102, 76, 159, 211), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((0, 0, 217, 183, 236, 111, 190, 253, 242, 86, 253, 104, 34, 11, 82, 5, 172, 101, 162, 0, 17, 69, 17, 140, 80, 186, 107, 101, 112, 50, 25, 139, 139, 124, 227, 178, 247, 6, 138, 120, 13, 193, 124, 34, 69, 154, 242, 183), (216, 87, 84, 28, 98, 184, 87, 86, 220, 115, 222, 125, 194, 216, 111, 93, 94, 139, 40, 51, 139, 176, 169, 69, 181, 196, 253, 124, 129, 247, 25, 97, 185, 112, 93, 61, 21, 59, 25, 25, 93, 0, 59, 116, 33, 32, 104, 237, 16, 249, 108, 83, 67, 134, 83, 8, 122, 1, 82, 207), (121, 62, 241, 19, 249, 99, 151, 171, 0, 49, 234, 160, 250, 167, 119, 193, 7, 231, 208, 60), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((79, 61, 116, 77, 62, 68, 158, 6, 39, 191, 68, 152, 116, 56, 40, 248, 110, 99, 143, 96, 98, 10, 126, 212, 167, 201, 181, 176, 115, 105, 28, 158, 201, 71, 40, 197, 136, 34, 232, 39, 240, 246, 204, 248, 109, 188, 28, 174), (48, 31, 238, 178, 94, 108, 168, 80, 62, 205, 130, 31, 29, 55, 135, 174, 191, 179, 208, 236, 81, 139, 179, 17, 116, 245, 32, 155, 42, 193, 242, 142, 211, 230, 152, 115, 107, 173, 16, 161, 142, 60, 189, 181, 220, 39, 187, 209, 45, 5, 139, 54, 219, 8, 146, 249, 207, 208, 131, 0), (133, 239, 149, 5, 178, 48, 86, 94, 204, 242, 166, 74, 179, 222, 83, 229, 169, 28, 123, 81), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((106, 243, 225, 101, 158, 231, 202, 241, 209, 10, 217, 19, 92, 151, 87, 53, 15, 105, 136, 108, 202, 177, 186, 79, 222, 80, 196, 97, 75, 49, 158, 43, 32, 236, 199, 99, 108, 95, 107, 186, 231, 28, 211, 85, 101, 164, 162, 200), (121, 186, 196, 71, 241, 47, 190, 150, 193, 151, 150, 59, 145, 185, 57, 172, 61, 191, 69, 65, 190, 222, 187, 34, 197, 103, 127, 84, 179, 119, 160, 204, 59, 85, 162, 191, 64, 51, 212, 34, 64, 26, 20, 158, 116, 168, 22, 21, 71, 45, 13, 79, 142, 79, 12, 229, 67, 132, 216, 68), (40, 171, 236, 32, 214, 240, 146, 208, 158, 50, 54, 9, 134, 53, 147, 3, 117, 60, 237, 190), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((2, 153, 209, 240, 100, 53, 45, 90, 131, 251, 97, 225, 224, 80, 152, 15, 101, 180, 180, 64, 129, 157, 44, 28, 41, 182, 173, 91, 223, 178, 192, 3, 71, 218, 153, 60, 201, 236, 0, 252, 196, 189, 1, 192, 63, 237, 155, 101), (111, 158, 229, 203, 56, 82, 238, 194, 172, 63, 9, 92, 37, 194, 3, 99, 208, 247, 244, 119, 8, 153, 191, 153, 24, 126, 42, 131, 12, 101, 113, 175, 248, 33, 206, 183, 232, 11, 108, 116, 79, 140, 94, 123, 192, 178, 184, 25, 111, 181, 64, 0, 43, 141, 183, 188, 96, 145, 57, 152), (41, 62, 15, 211, 228, 208, 110, 254, 158, 225, 186, 125, 139, 171, 29, 54, 189, 117, 9, 193), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((30, 220, 127, 233, 173, 51, 167, 246, 241, 47, 53, 12, 18, 142, 40, 147, 236, 27, 229, 156, 10, 119, 250, 88, 150, 242, 226, 118, 191, 158, 177, 156, 229, 177, 193, 204, 47, 242, 95, 147, 145, 218, 48, 77, 38, 3, 123, 227), (254, 52, 131, 84, 3, 65, 23, 79, 173, 214, 191, 169, 249, 100, 115, 234, 189, 150, 74, 213, 136, 174, 20, 96, 115, 157, 235, 59, 245, 18, 71, 92, 109, 87, 224, 23, 220, 70, 225, 17, 87, 51, 221, 129, 250, 106, 93, 170, 156, 31, 157, 35, 192, 175, 187, 179, 105, 88, 205, 172), (60, 25, 35, 71, 206, 115, 19, 233, 229, 66, 145, 195, 124, 65, 44, 249, 10, 245, 138, 101), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((39, 169, 165, 20, 230, 57, 67, 233, 185, 12, 173, 18, 145, 251, 42, 48, 84, 200, 91, 74, 116, 92, 195, 207, 49, 189, 193, 200, 147, 93, 21, 63, 180, 149, 231, 186, 74, 182, 65, 183, 201, 227, 181, 167, 196, 151, 177, 202), (197, 175, 102, 206, 108, 3, 251, 127, 216, 128, 23, 179, 129, 73, 163, 44, 140, 157, 202, 185, 102, 101, 239, 173, 40, 222, 183, 27, 97, 238, 117, 136, 126, 19, 36, 128, 11, 1, 177, 63, 221, 93, 176, 11, 139, 180, 190, 80, 204, 46, 174, 234, 67, 207, 38, 231, 125, 230, 220, 179), (136, 109, 183, 66, 7, 222, 59, 3, 79, 62, 112, 207, 155, 71, 50, 77, 87, 223, 81, 133), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((227, 88, 187, 4, 165, 170, 237, 151, 147, 154, 228, 21, 171, 63, 254, 157, 42, 177, 76, 134, 195, 195, 247, 43, 40, 91, 253, 251, 124, 20, 64, 248, 13, 117, 204, 242, 141, 44, 100, 213, 3, 66, 111, 85, 44, 180, 253, 186), (107, 147, 173, 217, 22, 63, 94, 20, 223, 1, 96, 176, 238, 4, 2, 179, 84, 47, 146, 15, 177, 44, 186, 113, 194, 199, 152, 136, 119, 190, 70, 190, 149, 17, 19, 218, 191, 72, 175, 242, 126, 140, 155, 33, 76, 191, 41, 59, 138, 150, 109, 46, 167, 255, 81, 91, 107, 218, 168, 225), (72, 188, 27, 193, 53, 213, 206, 74, 192, 75, 17, 231, 197, 12, 219, 191, 132, 196, 78, 215), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((110, 58, 183, 66, 34, 202, 163, 127, 115, 45, 227, 120, 153, 43, 167, 92, 55, 177, 193, 75, 63, 90, 44, 43, 180, 44, 39, 13, 111, 33, 62, 235, 173, 60, 53, 36, 164, 179, 84, 247, 83, 188, 229, 237, 124, 168, 101, 219), (121, 211, 144, 151, 177, 155, 198, 23, 42, 219, 68, 92, 249, 65, 137, 121, 185, 67, 130, 82, 40, 48, 127, 47, 58, 168, 165, 145, 224, 51, 28, 119, 186, 1, 174, 220, 162, 192, 148, 57, 12, 4, 105, 77, 172, 144, 123, 225, 237, 32, 193, 36, 192, 193, 229, 178, 120, 246, 58, 60), (98, 147, 84, 250, 218, 251, 7, 125, 115, 68, 245, 36, 184, 43, 125, 20, 165, 206, 171, 34), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((88, 47, 150, 138, 84, 184, 121, 123, 158, 168, 198, 85, 180, 46, 57, 122, 219, 115, 215, 115, 177, 152, 75, 30, 28, 66, 156, 213, 151, 184, 1, 93, 47, 145, 213, 158, 65, 54, 169, 213, 35, 191, 100, 145, 164, 115, 60, 122), (230, 211, 193, 147, 239, 243, 78, 52, 248, 183, 176, 14, 102, 86, 90, 235, 1, 246, 50, 6, 187, 39, 226, 122, 162, 129, 89, 42, 252, 6, 174, 30, 197, 183, 235, 151, 163, 150, 132, 206, 119, 61, 124, 53, 40, 242, 102, 124, 31, 93, 66, 132, 6, 231, 140, 228, 207, 57, 246, 82), (105, 23, 38, 193, 17, 229, 3, 11, 95, 150, 87, 6, 145, 7, 134, 30, 204, 24, 188, 88, 53, 168, 20, 195, 210, 229, 9, 44, 144, 28, 177, 251, 108, 26, 124, 211, 235, 11, 226, 167), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((189, 163, 46, 191, 107, 141, 108, 33, 180, 7, 140, 5, 88, 44, 202, 197, 125, 14, 9, 213, 152, 237, 81, 202, 128, 139, 186, 228, 49, 95, 243, 8, 32, 134, 231, 114, 165, 15, 130, 139, 163, 168, 164, 112, 137, 96, 76, 31), (114, 58, 106, 163, 226, 9, 63, 43, 58, 55, 126, 77, 113, 108, 250, 222, 247, 132, 235, 56, 209, 3, 2, 168, 188, 136, 41, 79, 250, 176, 46, 138, 180, 62, 108, 131, 167, 4, 137, 220, 145, 164, 4, 14, 28, 4, 247, 17, 169, 173, 246, 1, 212, 154, 42, 208, 120, 53, 198, 104), (146, 235, 161, 4, 64, 160, 242, 142, 202, 64, 199, 101, 204, 8, 3, 27, 251, 174, 197, 250, 42, 45, 63, 161, 144, 105, 203, 61, 93, 208, 142, 1, 112, 44, 213, 238, 22, 50, 141, 15), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((188, 141, 97, 5, 51, 231, 253, 129, 243, 246, 172, 47, 147, 135, 107, 226, 89, 232, 140, 111, 35, 74, 189, 8, 128, 118, 45, 18, 205, 125, 33, 52, 242, 82, 190, 204, 57, 92, 196, 139, 136, 235, 100, 93, 114, 37, 20, 199), (41, 165, 234, 13, 194, 98, 6, 38, 128, 149, 121, 26, 44, 11, 24, 25, 7, 156, 136, 248, 93, 208, 37, 155, 200, 234, 116, 214, 191, 80, 79, 252, 33, 198, 205, 95, 146, 247, 74, 2, 40, 61, 228, 227, 57, 69, 57, 62, 100, 202, 75, 15, 105, 24, 133, 228, 242, 118, 46, 39), (110, 58, 27, 98, 51, 216, 224, 138, 28, 254, 73, 201, 249, 232, 96, 95, 163, 102, 246, 16, 128, 197, 241, 167, 80, 178, 33, 19, 22, 141, 54, 0, 29, 170, 198, 215, 187, 140, 153, 212), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((214, 190, 117, 2, 143, 123, 215, 54, 32, 102, 126, 165, 12, 74, 103, 68, 113, 133, 75, 103, 127, 240, 182, 48, 38, 70, 12, 48, 0, 209, 27, 82, 16, 2, 159, 41, 121, 179, 238, 170, 97, 56, 18, 152, 62, 125, 118, 147), (92, 44, 226, 72, 192, 167, 58, 41, 166, 232, 231, 179, 253, 187, 175, 1, 152, 214, 54, 230, 217, 214, 165, 71, 104, 92, 39, 19, 77, 128, 65, 29, 18, 47, 150, 49, 20, 52, 121, 140, 177, 155, 61, 68, 111, 82, 215, 209, 215, 75, 243, 238, 63, 209, 254, 162, 163, 181, 38, 206), (230, 124, 153, 93, 164, 159, 78, 208, 246, 239, 192, 159, 131, 156, 121, 94, 132, 71, 225, 119, 144, 249, 128, 90, 168, 169, 58, 77, 185, 160, 57, 112, 194, 128, 233, 21, 154, 100, 254, 195), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((247, 103, 140, 192, 183, 174, 197, 244, 189, 228, 135, 243, 10, 90, 136, 201, 136, 253, 36, 196, 99, 185, 228, 107, 59, 42, 228, 199, 101, 202, 121, 196, 138, 190, 105, 28, 249, 59, 107, 67, 91, 43, 223, 242, 163, 212, 145, 242), (176, 76, 148, 91, 241, 73, 242, 246, 209, 116, 56, 149, 141, 26, 114, 92, 58, 138, 180, 108, 170, 21, 160, 94, 128, 149, 36, 185, 209, 119, 126, 251, 72, 231, 214, 186, 175, 93, 62, 251, 243, 11, 105, 179, 38, 147, 94, 89, 65, 18, 7, 185, 19, 243, 137, 136, 224, 106, 190, 93), (101, 227, 3, 173, 232, 213, 237, 85, 89, 196, 14, 99, 18, 177, 14, 228, 242, 244, 221, 238, 22, 97, 39, 84, 127, 241, 161, 76, 192, 49, 140, 220, 97, 209, 208, 195, 214, 84, 42, 217), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((213, 215, 142, 235, 209, 47, 130, 243, 152, 35, 92, 167, 42, 244, 39, 125, 180, 117, 168, 13, 168, 67, 243, 110, 30, 217, 90, 102, 30, 30, 97, 10, 44, 125, 204, 67, 62, 96, 2, 156, 102, 137, 152, 9, 97, 243, 89, 15), (9, 76, 93, 124, 116, 87, 197, 28, 135, 122, 11, 234, 3, 251, 196, 65, 101, 193, 6, 53, 164, 230, 75, 133, 86, 200, 236, 242, 9, 20, 230, 33, 239, 52, 34, 68, 150, 72, 157, 118, 246, 123, 38, 57, 96, 136, 32, 173, 167, 65, 55, 145, 107, 251, 49, 91, 213, 8, 114, 237), (161, 110, 158, 193, 190, 26, 227, 180, 10, 169, 6, 200, 225, 142, 154, 118, 151, 204, 52, 18, 75, 123, 4, 149, 124, 225, 73, 188, 57, 189, 242, 112, 22, 245, 131, 158, 33, 234, 121, 118), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((88, 241, 164, 193, 108, 179, 50, 99, 27, 33, 122, 142, 27, 92, 202, 132, 54, 101, 6, 76, 198, 28, 158, 130, 174, 65, 128, 213, 116, 222, 244, 226, 163, 171, 148, 3, 3, 110, 57, 21, 217, 80, 68, 153, 127, 27, 171, 129), (199, 122, 11, 201, 84, 56, 65, 220, 6, 44, 138, 187, 128, 73, 120, 163, 175, 113, 146, 36, 74, 172, 79, 115, 168, 33, 117, 11, 163, 141, 72, 109, 90, 43, 79, 141, 146, 127, 131, 7, 114, 196, 229, 32, 142, 145, 195, 127, 130, 183, 198, 88, 210, 64, 225, 78, 32, 213, 140, 238), (178, 208, 117, 41, 36, 137, 187, 209, 119, 247, 46, 94, 128, 6, 24, 208, 74, 48, 249, 182, 224, 168, 209, 252, 203, 67, 138, 230, 246, 70, 163, 62, 12, 71, 211, 98, 90, 184, 123, 108), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((170, 176, 224, 126, 40, 69, 206, 22, 100, 5, 122, 161, 90, 29, 80, 195, 92, 232, 85, 145, 197, 224, 216, 211, 170, 126, 140, 90, 88, 176, 191, 86, 194, 112, 149, 127, 55, 40, 201, 116, 90, 75, 198, 150, 248, 124, 160, 241), (60, 17, 91, 255, 194, 109, 65, 145, 130, 67, 59, 212, 53, 112, 251, 63, 111, 47, 254, 55, 133, 90, 85, 70, 219, 197, 66, 153, 15, 239, 30, 51, 44, 58, 7, 7, 67, 186, 49, 233, 132, 202, 24, 204, 148, 227, 63, 79, 44, 116, 79, 107, 112, 35, 74, 123, 168, 13, 126, 74), (0, 28, 218, 5, 145, 121, 172, 208, 103, 188, 145, 41, 1, 125, 36, 232, 185, 154, 45, 102, 4, 225, 71, 20, 247, 32, 53, 139, 247, 244, 60, 187, 106, 74, 173, 70, 35, 38, 126, 114), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((12, 86, 32, 243, 74, 167, 2, 159, 101, 90, 158, 185, 176, 81, 241, 50, 81, 214, 91, 223, 153, 211, 144, 184, 246, 120, 152, 235, 34, 22, 236, 16, 186, 203, 41, 53, 139, 137, 85, 41, 219, 100, 251, 252, 148, 47, 208, 255), (109, 139, 140, 223, 123, 105, 156, 2, 5, 198, 254, 180, 172, 24, 57, 211, 196, 54, 207, 150, 47, 133, 117, 238, 103, 255, 32, 214, 145, 3, 196, 170, 147, 187, 54, 157, 54, 9, 128, 24, 30, 56, 196, 66, 21, 6, 92, 153, 160, 102, 148, 103, 51, 237, 226, 49, 133, 24, 54, 23), (40, 87, 199, 180, 34, 26, 2, 182, 113, 122, 28, 103, 177, 238, 182, 77, 205, 168, 22, 34, 132, 250, 174, 136, 70, 100, 20, 179, 23, 228, 84, 87, 181, 170, 239, 91, 80, 137, 114, 47), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((181, 125, 197, 35, 84, 175, 238, 17, 237, 180, 201, 5, 42, 82, 131, 68, 52, 139, 44, 107, 108, 57, 243, 33, 51, 237, 59, 183, 32, 53, 164, 171, 85, 214, 100, 140, 21, 41, 239, 122, 145, 112, 254, 201, 239, 38, 168, 30), (23, 230, 65, 144, 157, 237, 254, 228, 150, 139, 185, 93, 127, 119, 14, 69, 87, 202, 52, 122, 70, 97, 76, 179, 113, 66, 63, 13, 145, 223, 59, 88, 181, 54, 237, 84, 83, 31, 210, 162, 235, 11, 139, 42, 22, 52, 194, 60, 136, 250, 217, 112, 108, 69, 219, 68, 17, 162, 59, 137), (89, 73, 172, 249, 99, 90, 119, 41, 121, 40, 193, 225, 85, 212, 58, 78, 75, 202, 97, 177, 54, 154, 94, 245, 5, 48, 136, 133, 80, 186, 39, 14, 38, 190, 74, 66, 28, 223, 128, 183), GNUTLS_MAC_SHA384),
+ TEST_VECTOR((221, 93, 189, 69, 89, 62, 226, 172, 19, 151, 72, 231, 100, 91, 69, 15, 34, 61, 47, 242, 151, 183, 63, 215, 28, 188, 235, 231, 29, 65, 101, 60, 149, 11, 136, 80, 13, 229, 50, 45, 153, 239, 24, 223, 221, 48, 66, 130, 148, 196, 179, 9, 79, 76, 149, 67, 52, 229, 147, 189, 152, 46, 198, 20), (181, 11, 12, 150, 60, 107, 48, 52, 184, 207, 25, 205, 63, 92, 78, 190, 79, 73, 133, 175, 12, 3, 229, 117, 219, 98, 230, 253, 241, 236, 254, 79, 40, 185, 93, 124, 225, 109, 248, 88, 67, 36, 110, 21, 87, 206, 149, 187, 38, 204, 154, 33, 151, 75, 189, 46, 182, 158, 131, 85), (229, 153, 59, 249, 189, 42, 161, 196, 87, 70, 4, 46, 18, 89, 129, 85), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((96, 36, 189, 200, 36, 64, 71, 59, 175, 121, 134, 83, 188, 184, 70, 248, 80, 61, 115, 182, 237, 245, 206, 188, 17, 99, 116, 83, 139, 98, 86, 172, 138, 138, 213, 250, 140, 127, 173, 123, 63, 8, 153, 51, 185, 199, 50, 109, 107, 128, 87, 38, 53, 201, 245, 246, 179, 134, 67, 151, 29, 7, 91, 159), (20, 114, 169, 107, 200, 24, 129, 118, 127, 97, 84, 178, 187, 121, 244, 218, 133, 120, 212, 71, 172, 73, 93, 126, 222, 49, 69, 72, 52, 190, 61, 100, 48, 52, 178, 225, 96, 52, 186, 135, 122, 132, 110, 110, 110, 34, 178, 132, 182, 216, 148, 57, 95, 51, 180, 190, 165, 241, 205, 123), (172, 189, 118, 30, 151, 101, 118, 177, 137, 105, 109, 38, 231, 69, 166, 128), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((108, 125, 148, 98, 42, 45, 28, 67, 148, 118, 138, 57, 204, 52, 12, 104, 135, 224, 108, 74, 136, 213, 122, 167, 130, 47, 15, 43, 63, 172, 1, 146, 232, 81, 247, 221, 57, 203, 239, 230, 204, 215, 9, 146, 226, 126, 222, 164, 114, 155, 33, 92, 162, 218, 203, 5, 55, 58, 65, 22, 0, 35, 60, 202), (82, 209, 238, 139, 76, 10, 236, 119, 30, 35, 110, 134, 146, 139, 78, 148, 60, 236, 83, 64, 24, 72, 184, 163, 83, 251, 45, 192, 199, 77, 156, 255, 116, 232, 8, 110, 245, 84, 46, 63, 33, 2, 9, 255, 97, 77, 31, 211, 23, 123, 93, 244, 219, 248, 153, 120, 209, 171, 219, 170), (243, 4, 138, 234, 225, 27, 17, 106, 35, 70, 89, 212, 7, 17, 38, 125), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((224, 99, 5, 69, 235, 220, 68, 15, 55, 61, 25, 79, 198, 196, 98, 154, 98, 174, 240, 40, 219, 82, 163, 250, 220, 211, 45, 162, 76, 47, 247, 145, 6, 211, 73, 175, 216, 80, 13, 107, 79, 251, 254, 42, 157, 89, 128, 63, 185, 15, 37, 182, 15, 208, 41, 195, 182, 124, 33, 220, 7, 13, 133, 47), (24, 33, 203, 59, 28, 222, 130, 190, 183, 110, 85, 202, 200, 102, 227, 187, 247, 235, 84, 30, 10, 166, 108, 61, 251, 229, 9, 234, 120, 112, 103, 7, 69, 172, 213, 69, 29, 119, 84, 100, 174, 210, 214, 110, 92, 196, 54, 12, 107, 123, 117, 179, 90, 56, 32, 206, 194, 23, 160, 134), (144, 251, 250, 39, 17, 148, 80, 172, 200, 230, 215, 75, 3, 176, 85, 88), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((123, 48, 136, 240, 254, 134, 160, 199, 28, 192, 38, 96, 227, 171, 4, 211, 120, 149, 0, 171, 149, 81, 221, 89, 240, 48, 132, 125, 218, 14, 20, 221, 168, 214, 162, 5, 19, 121, 208, 245, 145, 38, 156, 61, 255, 48, 60, 191, 160, 132, 36, 244, 33, 145, 59, 59, 249, 195, 192, 118, 1, 42, 216, 252), (133, 36, 253, 62, 115, 235, 148, 118, 81, 62, 49, 0, 93, 41, 223, 230, 146, 125, 135, 123, 116, 115, 78, 221, 140, 43, 136, 111, 253, 63, 5, 48, 0, 210, 131, 68, 238, 159, 217, 52, 11, 68, 140, 41, 251, 23, 37, 101, 123, 49, 77, 185, 60, 99, 159, 152, 215, 86, 205, 157), (81, 34, 166, 26, 221, 88, 153, 147, 17, 23, 57, 244, 100, 62, 228, 6), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((244, 238, 53, 209, 87, 93, 39, 60, 228, 42, 102, 214, 166, 229, 33, 232, 127, 173, 100, 191, 129, 201, 159, 87, 115, 182, 12, 10, 159, 226, 212, 217, 124, 82, 230, 224, 193, 119, 91, 78, 247, 228, 30, 146, 161, 189, 50, 234, 191, 63, 186, 219, 147, 246, 160, 179, 231, 50, 75, 125, 160, 67, 214, 201), (146, 54, 79, 4, 78, 13, 100, 168, 251, 76, 83, 203, 27, 115, 166, 101, 170, 246, 111, 252, 157, 223, 65, 82, 174, 157, 163, 91, 71, 2, 86, 176, 11, 80, 35, 78, 38, 195, 20, 159, 28, 56, 13, 217, 62, 117, 172, 202, 204, 209, 103, 225, 214, 10, 138, 6, 211, 27, 178, 232), (226, 180, 203, 24, 10, 182, 115, 11, 176, 193, 97, 120, 178, 5, 72, 182), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((219, 61, 184, 118, 22, 103, 19, 167, 5, 42, 153, 84, 242, 211, 126, 243, 94, 68, 99, 104, 207, 132, 206, 92, 49, 91, 79, 89, 172, 0, 208, 217, 235, 34, 177, 25, 208, 64, 186, 181, 242, 95, 34, 74, 36, 217, 73, 1, 1, 90, 34, 35, 133, 98, 3, 218, 210, 38, 1, 100, 236, 230, 25, 53), (119, 213, 175, 193, 67, 100, 138, 36, 155, 23, 175, 16, 214, 136, 24, 138, 120, 5, 66, 219, 127, 46, 61, 66, 101, 209, 110, 79, 201, 76, 218, 177, 88, 197, 175, 185, 199, 10, 242, 209, 102, 138, 0, 138, 173, 74, 218, 100, 169, 219, 250, 151, 180, 57, 0, 46, 75, 211, 219, 246), (176, 28, 150, 186, 242, 140, 165, 132, 28, 182, 228, 224, 202, 227, 13, 89), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((124, 151, 123, 116, 205, 248, 119, 33, 163, 124, 111, 94, 157, 124, 145, 209, 225, 23, 68, 81, 77, 81, 166, 141, 18, 209, 131, 125, 38, 183, 150, 17, 232, 106, 5, 164, 104, 93, 190, 232, 235, 11, 48, 150, 43, 25, 185, 111, 55, 63, 90, 190, 146, 255, 2, 53, 164, 174, 124, 53, 56, 7, 148, 165), (141, 163, 114, 228, 213, 52, 65, 109, 156, 79, 236, 249, 210, 45, 197, 118, 248, 137, 188, 111, 39, 69, 60, 167, 84, 88, 204, 216, 248, 138, 134, 0, 186, 3, 212, 209, 148, 128, 210, 239, 137, 157, 199, 45, 240, 115, 47, 206, 232, 237, 153, 127, 234, 79, 45, 82, 107, 236, 68, 243), (178, 45, 182, 172, 58, 136, 170, 26, 160, 147, 192, 254, 85, 226, 99, 159), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((110, 110, 208, 31, 241, 45, 50, 81, 57, 107, 245, 96, 98, 177, 179, 199, 155, 85, 180, 55, 60, 3, 49, 177, 74, 165, 147, 163, 238, 0, 91, 95, 6, 143, 14, 252, 86, 2, 111, 199, 45, 102, 242, 116, 77, 209, 241, 104, 242, 71, 145, 47, 155, 38, 235, 197, 148, 99, 185, 107, 217, 241, 161, 161), (94, 202, 121, 107, 239, 3, 27, 135, 82, 30, 208, 144, 75, 241, 216, 85, 88, 151, 73, 176, 24, 62, 153, 61, 153, 247, 65, 97, 155, 98, 100, 79, 166, 134, 164, 201, 15, 127, 30, 110, 213, 52, 78, 183, 88, 128, 114, 76, 9, 183, 81, 97, 124, 49, 250, 85, 73, 130, 138, 37), (176, 59, 35, 95, 90, 249, 113, 159, 53, 242, 21, 194, 249, 74, 118, 165), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((244, 205, 79, 39, 154, 18, 140, 116, 229, 235, 130, 20, 114, 9, 130, 4, 237, 150, 237, 97, 234, 201, 40, 27, 205, 83, 253, 230, 137, 10, 44, 187, 28, 219, 151, 224, 227, 67, 252, 133, 136, 185, 50, 205, 112, 26, 248, 143, 10, 122, 247, 35, 213, 192, 133, 14, 62, 1, 228, 118, 18, 252, 236, 131), (239, 71, 13, 252, 213, 115, 89, 245, 88, 53, 79, 132, 95, 200, 202, 58, 26, 103, 65, 154, 109, 15, 109, 214, 152, 199, 143, 154, 87, 232, 32, 195, 216, 120, 111, 60, 88, 159, 150, 147, 184, 243, 251, 62, 18, 58, 72, 35, 134, 193, 192, 207, 226, 107, 197, 50, 46, 144, 253, 75), (250, 167, 32, 41, 149, 19, 183, 61, 226, 181, 72, 150, 217, 160, 107, 204), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((91, 226, 191, 127, 94, 37, 39, 225, 95, 230, 92, 222, 69, 7, 217, 139, 165, 84, 87, 0, 104, 103, 222, 158, 79, 54, 100, 91, 207, 244, 202, 56, 117, 79, 146, 137, 139, 28, 85, 68, 113, 129, 2, 89, 59, 140, 38, 212, 93, 31, 206, 174, 162, 125, 151, 237, 233, 222, 139, 158, 191, 232, 128, 147), (0, 75, 19, 193, 246, 40, 203, 122, 0, 217, 73, 137, 55, 191, 67, 123, 113, 254, 25, 108, 201, 22, 196, 125, 41, 143, 162, 150, 198, 184, 97, 136, 7, 53, 67, 187, 198, 107, 117, 53, 235, 23, 181, 207, 67, 195, 121, 68, 182, 202, 18, 37, 41, 138, 158, 86, 52, 19, 229, 187), (206, 224, 193, 27, 226, 216, 17, 11, 128, 143, 115, 133, 35, 231, 24, 68, 125, 120, 88, 120, 187, 183, 131, 251, 8, 26, 5, 81, 96, 89, 0, 114), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((176, 181, 89, 156, 41, 204, 231, 100, 67, 114, 178, 120, 163, 39, 95, 62, 7, 35, 115, 159, 66, 188, 3, 252, 154, 74, 202, 9, 217, 206, 207, 154, 253, 195, 3, 147, 221, 28, 247, 73, 146, 54, 35, 150, 8, 162, 88, 245, 196, 142, 102, 182, 99, 246, 82, 16, 73, 164, 130, 182, 61, 70, 138, 51), (240, 1, 1, 243, 142, 93, 96, 152, 207, 234, 76, 124, 132, 144, 235, 85, 5, 57, 0, 0, 71, 138, 100, 94, 102, 33, 177, 247, 17, 16, 91, 219, 72, 32, 220, 12, 120, 59, 249, 128, 192, 98, 137, 155, 112, 135, 94, 23, 204, 145, 22, 242, 250, 88, 138, 148, 36, 5, 187, 214), (118, 135, 150, 23, 156, 165, 17, 184, 65, 113, 120, 135, 129, 15, 135, 15, 163, 193, 38, 65, 201, 94, 205, 206, 168, 89, 13, 115, 14, 164, 59, 142), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((82, 190, 199, 3, 222, 201, 75, 128, 237, 47, 132, 73, 199, 82, 238, 75, 139, 139, 27, 128, 229, 91, 107, 14, 30, 157, 177, 119, 13, 173, 251, 178, 99, 29, 245, 84, 209, 186, 65, 187, 189, 14, 88, 115, 105, 172, 129, 180, 11, 166, 217, 65, 251, 98, 219, 167, 138, 118, 181, 84, 235, 3, 198, 67), (159, 81, 37, 107, 24, 150, 146, 88, 102, 242, 32, 83, 52, 142, 246, 232, 165, 46, 197, 128, 177, 243, 43, 235, 37, 116, 175, 210, 58, 84, 96, 195, 14, 140, 129, 29, 14, 122, 40, 135, 189, 92, 192, 101, 62, 200, 214, 141, 204, 164, 63, 113, 168, 223, 31, 1, 147, 32, 91, 117), (177, 154, 199, 212, 239, 222, 124, 98, 25, 30, 167, 101, 48, 211, 13, 250, 85, 16, 204, 116, 186, 250, 202, 234, 92, 190, 44, 237, 70, 127, 161, 165), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((140, 71, 40, 73, 193, 33, 83, 213, 164, 115, 96, 238, 208, 67, 134, 137, 208, 86, 192, 132, 150, 210, 133, 161, 121, 41, 122, 147, 223, 245, 0, 112, 253, 60, 44, 45, 136, 241, 196, 162, 91, 119, 193, 165, 239, 180, 123, 184, 248, 129, 200, 159, 36, 212, 100, 188, 35, 196, 242, 0, 41, 29, 98, 81), (242, 211, 23, 240, 32, 178, 18, 6, 110, 247, 200, 105, 201, 197, 102, 153, 193, 212, 223, 219, 116, 207, 103, 155, 151, 215, 24, 231, 1, 228, 66, 177, 23, 166, 209, 22, 43, 248, 37, 239, 73, 31, 166, 40, 235, 36, 154, 28, 226, 128, 24, 184, 165, 189, 11, 27, 41, 110, 77, 146), (255, 130, 180, 208, 252, 158, 23, 192, 83, 159, 162, 254, 102, 242, 225, 160, 123, 123, 89, 58, 19, 66, 205, 11, 72, 22, 47, 218, 104, 183, 216, 10), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((16, 66, 128, 200, 108, 121, 135, 158, 150, 207, 21, 222, 150, 65, 36, 146, 255, 245, 212, 219, 252, 103, 127, 125, 56, 76, 9, 164, 188, 238, 22, 15, 163, 201, 114, 150, 157, 18, 249, 177, 84, 45, 87, 11, 170, 235, 189, 128, 31, 99, 46, 23, 42, 138, 0, 71, 126, 220, 6, 249, 56, 234, 225, 152), (173, 241, 241, 103, 147, 144, 135, 215, 31, 232, 217, 221, 210, 201, 3, 197, 66, 119, 81, 41, 218, 178, 237, 194, 68, 108, 179, 148, 168, 8, 186, 73, 207, 71, 16, 234, 16, 203, 114, 164, 239, 232, 241, 163, 44, 3, 209, 70, 96, 241, 11, 10, 169, 37, 91, 208, 238, 134, 92, 16), (92, 237, 129, 66, 48, 215, 240, 125, 161, 22, 215, 147, 11, 77, 182, 177, 139, 57, 27, 184, 105, 209, 81, 150, 103, 123, 209, 209, 127, 47, 140, 124), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((218, 72, 152, 107, 140, 132, 208, 246, 178, 214, 186, 159, 44, 2, 165, 62, 216, 241, 115, 178, 56, 221, 143, 48, 32, 225, 94, 174, 66, 88, 113, 207, 241, 72, 241, 91, 176, 186, 23, 194, 174, 0, 244, 75, 44, 20, 114, 90, 123, 19, 5, 5, 70, 155, 192, 112, 107, 105, 158, 45, 144, 26, 209, 107), (8, 82, 134, 0, 35, 123, 109, 4, 146, 104, 183, 191, 62, 47, 205, 147, 115, 166, 178, 246, 115, 46, 200, 148, 55, 239, 142, 19, 79, 185, 71, 195, 243, 127, 37, 76, 112, 65, 211, 240, 111, 120, 153, 83, 186, 206, 212, 21, 233, 209, 220, 64, 15, 176, 2, 91, 225, 128, 66, 91), (80, 235, 41, 233, 205, 92, 167, 115, 15, 165, 101, 135, 11, 35, 164, 13, 183, 91, 94, 5, 27, 53, 133, 12, 152, 252, 150, 19, 162, 81, 189, 203), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((25, 94, 49, 179, 219, 70, 48, 169, 230, 108, 222, 52, 119, 22, 245, 2, 39, 248, 168, 28, 57, 122, 114, 227, 13, 39, 170, 194, 127, 139, 159, 47, 43, 69, 62, 104, 250, 188, 157, 32, 157, 68, 61, 149, 34, 99, 219, 12, 52, 28, 134, 109, 150, 110, 180, 219, 143, 138, 207, 142, 175, 231, 162, 39), (43, 40, 21, 38, 52, 83, 81, 215, 151, 190, 10, 125, 188, 81, 123, 185, 201, 194, 32, 181, 25, 76, 236, 56, 71, 246, 250, 196, 171, 16, 48, 134, 125, 24, 81, 203, 141, 70, 86, 29, 182, 5, 80, 101, 103, 220, 47, 57, 221, 219, 244, 113, 228, 167, 213, 27, 35, 116, 85, 146), (174, 255, 136, 77, 203, 220, 0, 42, 95, 122, 135, 122, 52, 247, 59, 66, 171, 173, 32, 137, 212, 227, 155, 114, 30, 179, 112, 179, 216, 118, 39, 244), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((122, 31, 18, 163, 250, 215, 224, 211, 226, 68, 252, 123, 211, 240, 145, 126, 71, 188, 118, 198, 2, 133, 222, 215, 57, 221, 249, 70, 44, 22, 12, 223, 204, 168, 135, 134, 109, 109, 174, 251, 241, 46, 116, 16, 251, 27, 80, 173, 108, 139, 33, 182, 229, 104, 119, 244, 126, 139, 20, 160, 172, 159, 147, 109), (119, 9, 112, 36, 201, 68, 227, 73, 240, 202, 42, 87, 156, 245, 19, 83, 245, 6, 100, 221, 180, 187, 189, 187, 224, 29, 253, 232, 5, 149, 218, 165, 208, 67, 217, 219, 150, 81, 251, 130, 28, 201, 172, 215, 47, 169, 27, 46, 233, 62, 35, 239, 179, 148, 9, 113, 31, 57, 21, 208), (210, 25, 27, 106, 172, 199, 102, 128, 56, 215, 98, 192, 205, 89, 21, 191, 104, 228, 144, 103, 30, 196, 3, 44, 32, 41, 122, 100, 2, 111, 224, 66), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((122, 65, 223, 232, 208, 201, 172, 146, 74, 42, 204, 214, 21, 173, 60, 11, 192, 215, 225, 36, 254, 214, 178, 183, 224, 91, 159, 142, 106, 222, 6, 120, 233, 141, 69, 118, 111, 150, 151, 205, 24, 123, 193, 3, 33, 25, 95, 161, 187, 132, 181, 91, 249, 75, 177, 18, 215, 60, 106, 187, 133, 127, 64, 161), (228, 122, 168, 26, 248, 209, 7, 76, 143, 127, 188, 181, 137, 114, 126, 194, 37, 22, 61, 7, 109, 78, 140, 239, 200, 39, 199, 142, 186, 123, 66, 213, 231, 3, 119, 215, 3, 61, 253, 245, 237, 217, 63, 96, 93, 217, 178, 93, 117, 84, 133, 24, 228, 5, 86, 61, 29, 75, 243, 19), (93, 191, 29, 61, 193, 40, 230, 127, 36, 82, 171, 168, 88, 183, 236, 251, 135, 239, 190, 102, 183, 20, 84, 28, 13, 76, 0, 156, 43, 146, 215, 249), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((178, 123, 227, 35, 238, 9, 68, 0, 252, 157, 172, 174, 238, 3, 101, 224, 192, 197, 40, 17, 166, 8, 21, 81, 221, 70, 221, 134, 48, 44, 99, 150, 252, 232, 11, 182, 14, 48, 108, 151, 133, 190, 161, 39, 3, 86, 161, 194, 180, 219, 118, 52, 213, 192, 72, 145, 232, 84, 23, 251, 114, 205, 250, 178), (110, 237, 234, 76, 124, 42, 210, 34, 137, 196, 230, 106, 150, 231, 167, 161, 202, 231, 211, 64, 250, 228, 18, 166, 231, 118, 151, 194, 8, 26, 39, 86, 10, 159, 12, 176, 228, 18, 41, 127, 153, 16, 58, 35, 58, 121, 152, 101, 5, 144, 197, 167, 226, 134, 23, 56, 190, 215, 201, 253), (208, 101, 98, 48, 184, 110, 77, 195, 234, 43, 219, 141, 98, 180, 82, 38, 36, 98, 238, 214, 18, 41, 209, 226, 185, 39, 88, 181, 124, 84, 196, 52), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((157, 208, 56, 100, 163, 26, 164, 21, 108, 167, 161, 32, 0, 245, 65, 104, 12, 224, 165, 244, 119, 94, 239, 16, 136, 172, 19, 54, 130, 0, 180, 71, 167, 141, 11, 241, 68, 22, 161, 213, 131, 197, 75, 15, 17, 32, 15, 244, 168, 152, 61, 215, 117, 206, 156, 3, 2, 210, 98, 72, 62, 48, 10, 230), (3, 115, 105, 241, 66, 214, 105, 252, 169, 232, 126, 159, 55, 174, 143, 44, 141, 80, 107, 117, 63, 223, 232, 163, 183, 47, 117, 202, 193, 197, 15, 161, 248, 98, 8, 131, 184, 220, 184, 220, 198, 122, 220, 201, 94, 112, 170, 98, 74, 219, 159, 225, 178, 203, 57, 102, 146, 176, 210, 232), (150, 232, 209, 188, 1, 220, 149, 192, 191, 66, 195, 195, 143, 197, 76, 9, 3, 115, 206, 212), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((106, 193, 155, 54, 175, 125, 14, 92, 101, 245, 141, 218, 47, 247, 108, 104, 86, 124, 216, 172, 22, 255, 36, 99, 252, 60, 134, 84, 222, 69, 160, 94, 57, 199, 93, 131, 117, 131, 81, 117, 61, 46, 20, 54, 41, 171, 144, 117, 115, 139, 3, 122, 30, 244, 31, 126, 253, 112, 241, 231, 0, 247, 246, 123), (75, 169, 249, 232, 227, 59, 64, 244, 57, 3, 51, 245, 151, 171, 86, 91, 39, 168, 65, 213, 250, 201, 48, 246, 113, 1, 230, 89, 115, 240, 113, 172, 107, 163, 148, 28, 157, 34, 244, 12, 164, 78, 145, 101, 122, 98, 155, 127, 86, 152, 14, 14, 204, 174, 203, 148, 59, 22, 238, 39), (62, 67, 183, 6, 51, 136, 68, 128, 221, 217, 61, 111, 32, 186, 81, 43, 85, 89, 11, 104), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((46, 206, 123, 201, 235, 82, 73, 245, 23, 159, 37, 40, 160, 98, 208, 220, 48, 73, 102, 4, 187, 118, 242, 110, 22, 13, 54, 51, 20, 15, 198, 237, 172, 113, 126, 181, 64, 45, 15, 206, 86, 183, 107, 124, 251, 10, 175, 71, 182, 175, 196, 16, 254, 6, 239, 176, 73, 250, 40, 149, 61, 126, 73, 66), (30, 225, 239, 227, 174, 36, 136, 25, 197, 179, 61, 235, 120, 105, 195, 84, 12, 216, 171, 183, 221, 82, 44, 95, 10, 183, 22, 24, 21, 156, 208, 210, 61, 216, 5, 241, 78, 226, 126, 1, 34, 64, 207, 248, 95, 87, 199, 47, 136, 213, 239, 110, 33, 150, 238, 222, 140, 247, 183, 134), (45, 244, 250, 82, 210, 133, 135, 0, 8, 85, 112, 144, 31, 95, 133, 115, 20, 225, 224, 45), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((40, 62, 55, 254, 24, 21, 22, 222, 43, 251, 20, 230, 41, 30, 219, 145, 219, 222, 74, 123, 20, 117, 53, 42, 204, 71, 239, 223, 36, 74, 43, 162, 230, 57, 217, 176, 40, 192, 45, 254, 191, 81, 221, 45, 55, 196, 218, 100, 170, 137, 230, 166, 73, 22, 213, 143, 28, 128, 178, 92, 192, 128, 169, 80), (87, 140, 254, 26, 112, 245, 47, 126, 69, 106, 34, 241, 72, 91, 162, 56, 48, 227, 220, 176, 87, 0, 237, 40, 18, 202, 220, 24, 29, 68, 143, 17, 25, 254, 205, 143, 203, 73, 102, 115, 9, 207, 14, 49, 100, 112, 89, 14, 217, 59, 175, 86, 127, 70, 157, 239, 93, 175, 195, 177), (36, 113, 156, 182, 246, 177, 14, 46, 181, 134, 160, 225, 103, 245, 104, 61, 242, 17, 55, 113), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((74, 102, 212, 30, 188, 177, 132, 195, 20, 138, 13, 235, 214, 122, 245, 200, 236, 227, 230, 161, 193, 60, 65, 55, 137, 121, 106, 153, 161, 237, 36, 173, 162, 245, 16, 124, 145, 21, 147, 6, 254, 143, 104, 194, 69, 73, 159, 191, 216, 248, 80, 9, 161, 0, 200, 83, 93, 34, 220, 113, 223, 9, 247, 79), (64, 234, 244, 41, 247, 222, 230, 245, 201, 31, 35, 81, 186, 81, 229, 60, 246, 247, 248, 54, 57, 141, 188, 195, 51, 129, 180, 234, 64, 70, 165, 242, 205, 84, 92, 147, 46, 88, 2, 122, 30, 114, 79, 207, 133, 82, 204, 121, 171, 188, 237, 237, 56, 90, 82, 70, 72, 193, 218, 228), (143, 27, 220, 185, 154, 240, 252, 81, 10, 212, 130, 94, 253, 215, 80, 211, 202, 183, 132, 111), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((149, 165, 59, 63, 149, 58, 185, 13, 79, 133, 231, 232, 67, 115, 37, 190, 26, 2, 53, 168, 147, 17, 250, 28, 116, 5, 195, 192, 188, 97, 241, 78, 246, 231, 202, 211, 33, 101, 174, 234, 42, 215, 24, 190, 241, 68, 214, 99, 2, 233, 137, 226, 241, 163, 35, 229, 18, 120, 13, 40, 182, 218, 116, 172), (55, 73, 82, 22, 193, 19, 239, 210, 204, 174, 243, 88, 58, 135, 176, 103, 214, 92, 22, 93, 186, 206, 169, 224, 78, 227, 68, 17, 234, 166, 97, 111, 206, 83, 72, 171, 189, 18, 17, 134, 242, 158, 7, 28, 70, 123, 96, 217, 41, 28, 162, 235, 102, 78, 188, 42, 126, 229, 14, 171), (113, 165, 177, 234, 180, 17, 175, 186, 101, 8, 29, 77, 4, 113, 213, 50, 191, 14, 198, 95), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((252, 62, 242, 144, 168, 155, 121, 233, 93, 232, 51, 38, 179, 66, 66, 119, 143, 210, 213, 66, 69, 115, 101, 226, 113, 157, 50, 143, 165, 88, 20, 1, 235, 254, 110, 38, 85, 218, 7, 10, 163, 226, 107, 54, 59, 89, 94, 26, 247, 186, 189, 23, 7, 93, 190, 241, 119, 92, 246, 21, 125, 60, 113, 107), (89, 46, 25, 132, 189, 251, 75, 241, 141, 232, 58, 107, 25, 205, 182, 63, 39, 177, 9, 133, 231, 202, 82, 11, 113, 236, 57, 44, 224, 158, 29, 45, 161, 76, 99, 37, 83, 87, 75, 135, 103, 82, 185, 213, 114, 236, 244, 27, 197, 175, 208, 87, 190, 153, 216, 1, 158, 25, 247, 232), (8, 60, 211, 176, 181, 100, 238, 124, 94, 146, 127, 50, 209, 1, 144, 116, 151, 21, 178, 28), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((56, 139, 140, 155, 185, 136, 231, 98, 237, 227, 204, 7, 43, 216, 139, 167, 41, 71, 133, 175, 176, 214, 80, 108, 35, 87, 165, 226, 51, 49, 165, 30, 150, 143, 123, 245, 5, 118, 239, 158, 100, 182, 155, 79, 72, 214, 229, 9, 99, 156, 233, 105, 62, 63, 32, 148, 250, 51, 185, 121, 99, 225, 204, 110), (91, 143, 224, 198, 88, 192, 253, 118, 152, 35, 76, 71, 120, 96, 83, 18, 33, 167, 244, 134, 23, 228, 64, 93, 92, 142, 141, 53, 80, 241, 5, 183, 132, 105, 164, 73, 204, 43, 133, 93, 74, 83, 87, 193, 198, 18, 35, 75, 42, 226, 184, 32, 240, 116, 135, 176, 148, 172, 124, 63), (115, 81, 2, 181, 155, 9, 208, 109, 62, 108, 148, 148, 67, 60, 176, 63, 91, 140, 163, 131), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((241, 227, 157, 157, 9, 132, 100, 31, 36, 112, 47, 139, 55, 251, 249, 168, 250, 251, 209, 127, 194, 53, 105, 233, 64, 195, 19, 132, 205, 165, 140, 2, 116, 177, 103, 177, 175, 201, 255, 68, 71, 61, 32, 214, 162, 60, 146, 37, 2, 227, 27, 61, 173, 19, 39, 75, 34, 2, 79, 244, 234, 237, 102, 142), (200, 128, 112, 120, 4, 167, 100, 80, 1, 150, 50, 195, 47, 3, 127, 151, 255, 44, 231, 251, 21, 65, 169, 173, 188, 9, 45, 150, 18, 44, 222, 25, 213, 254, 129, 205, 18, 166, 15, 73, 28, 88, 119, 182, 1, 228, 236, 190, 15, 186, 235, 103, 180, 70, 196, 187, 42, 158, 214, 14), (84, 64, 195, 69, 10, 195, 50, 208, 168, 245, 199, 36, 100, 121, 98, 172, 130, 246, 89, 225), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((158, 10, 121, 177, 214, 198, 114, 211, 35, 84, 100, 203, 43, 230, 163, 109, 2, 201, 130, 56, 125, 239, 126, 47, 227, 42, 93, 43, 231, 52, 63, 220, 3, 138, 244, 143, 185, 65, 151, 47, 172, 200, 227, 61, 98, 134, 225, 66, 133, 45, 196, 207, 38, 103, 163, 201, 125, 213, 87, 188, 111, 198, 110, 152), (205, 53, 109, 20, 227, 43, 249, 88, 193, 119, 17, 210, 106, 48, 65, 32, 136, 162, 226, 20, 230, 0, 230, 146, 237, 73, 102, 33, 37, 101, 234, 137, 28, 128, 126, 30, 11, 222, 192, 169, 219, 199, 31, 80, 47, 9, 151, 95, 206, 145, 12, 119, 35, 219, 77, 243, 128, 231, 255, 178), (244, 102, 147, 48, 11, 195, 191, 16, 109, 106, 133, 102, 72, 31, 177, 43, 69, 238, 31, 149), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((169, 244, 162, 197, 175, 131, 152, 103, 245, 219, 90, 30, 82, 10, 179, 204, 167, 42, 22, 108, 166, 13, 229, 18, 253, 127, 231, 230, 76, 249, 79, 146, 207, 29, 139, 99, 97, 117, 242, 147, 224, 3, 39, 94, 2, 16, 24, 195, 240, 237, 228, 149, 153, 122, 80, 94, 201, 162, 175, 235, 4, 149, 190, 87), (142, 157, 179, 51, 87, 121, 219, 104, 139, 207, 224, 150, 102, 141, 156, 59, 198, 78, 25, 62, 53, 41, 196, 48, 230, 141, 9, 213, 108, 131, 125, 214, 192, 249, 70, 120, 241, 33, 166, 142, 225, 254, 234, 71, 53, 218, 133, 164, 157, 52, 165, 41, 10, 163, 159, 123, 64, 222, 67, 95), (109, 184, 128, 218, 172, 152, 176, 120, 238, 56, 154, 33, 100, 37, 45, 237, 97, 50, 45, 102, 30, 43, 73, 36, 126, 169, 33, 229, 68, 103, 93, 143, 23, 175, 43, 246, 109, 212, 13, 129), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((36, 67, 86, 190, 155, 50, 121, 100, 115, 46, 180, 167, 192, 155, 4, 180, 32, 113, 35, 150, 235, 87, 247, 43, 201, 73, 36, 6, 108, 104, 126, 135, 142, 121, 142, 10, 3, 58, 30, 225, 164, 216, 205, 194, 218, 4, 67, 236, 215, 116, 1, 208, 70, 12, 217, 6, 234, 171, 2, 101, 108, 30, 220, 152), (216, 6, 226, 223, 140, 133, 211, 186, 245, 214, 126, 156, 151, 183, 70, 238, 107, 187, 27, 193, 13, 205, 246, 199, 166, 7, 92, 49, 28, 243, 71, 82, 172, 190, 96, 230, 143, 35, 199, 248, 144, 181, 234, 115, 0, 161, 173, 50, 23, 130, 84, 136, 82, 70, 240, 73, 57, 135, 166, 232), (240, 181, 188, 116, 158, 179, 0, 202, 33, 124, 168, 47, 223, 254, 216, 155, 27, 242, 200, 175, 194, 179, 110, 226, 180, 134, 149, 229, 8, 91, 137, 58, 109, 170, 213, 71, 79, 116, 239, 15), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((245, 86, 122, 45, 217, 35, 106, 153, 32, 12, 75, 213, 57, 7, 67, 226, 86, 11, 171, 75, 25, 110, 60, 115, 43, 1, 171, 249, 0, 199, 100, 156, 171, 91, 149, 125, 166, 174, 143, 208, 37, 96, 81, 71, 179, 101, 114, 193, 159, 16, 54, 112, 177, 111, 107, 181, 124, 19, 135, 84, 71, 154, 212, 93), (168, 204, 212, 189, 54, 251, 14, 208, 118, 94, 150, 98, 241, 2, 141, 96, 11, 214, 80, 228, 194, 205, 221, 249, 75, 39, 238, 136, 17, 32, 170, 247, 75, 114, 123, 2, 240, 3, 107, 70, 22, 32, 98, 227, 158, 212, 63, 168, 86, 135, 165, 141, 23, 122, 246, 245, 102, 129, 24, 137), (46, 85, 183, 61, 18, 109, 176, 249, 40, 16, 38, 108, 146, 228, 220, 122, 127, 45, 50, 203, 237, 158, 180, 237, 171, 81, 158, 92, 201, 19, 140, 100, 47, 212, 178, 41, 120, 12, 23, 191), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((70, 166, 95, 46, 67, 47, 226, 170, 178, 109, 226, 77, 27, 157, 57, 180, 77, 162, 112, 35, 15, 23, 132, 77, 68, 226, 73, 86, 90, 18, 95, 135, 160, 112, 180, 178, 238, 172, 11, 58, 108, 84, 172, 252, 73, 221, 198, 54, 15, 89, 254, 14, 51, 14, 6, 5, 198, 30, 133, 197, 194, 127, 231, 86), (176, 106, 35, 224, 89, 69, 249, 106, 41, 61, 229, 157, 195, 219, 89, 114, 202, 31, 160, 11, 70, 71, 172, 56, 247, 83, 121, 3, 53, 213, 218, 235, 47, 254, 9, 207, 137, 36, 172, 78, 128, 178, 117, 234, 77, 190, 197, 59, 158, 42, 175, 144, 223, 14, 111, 216, 42, 214, 159, 124), (4, 187, 196, 249, 63, 181, 195, 88, 150, 144, 121, 139, 247, 147, 193, 11, 183, 38, 248, 122, 74, 45, 233, 59, 143, 223, 107, 232, 1, 90, 190, 21, 101, 119, 17, 156, 86, 55, 174, 113), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((141, 55, 21, 82, 22, 75, 206, 230, 7, 113, 232, 118, 206, 84, 108, 75, 2, 119, 185, 120, 224, 150, 62, 35, 18, 102, 111, 237, 95, 170, 243, 64, 165, 94, 0, 100, 76, 179, 100, 116, 70, 74, 76, 39, 117, 244, 128, 216, 142, 45, 59, 65, 243, 30, 7, 6, 32, 158, 184, 229, 21, 149, 185, 46), (245, 112, 33, 45, 178, 211, 243, 20, 175, 174, 81, 248, 56, 117, 228, 218, 125, 188, 19, 7, 62, 206, 131, 166, 114, 126, 1, 29, 208, 247, 72, 245, 105, 113, 75, 89, 244, 73, 48, 6, 123, 137, 98, 184, 50, 137, 180, 65, 186, 101, 176, 226, 35, 122, 173, 163, 104, 0, 249, 85), (149, 101, 181, 66, 89, 252, 92, 97, 167, 247, 68, 142, 107, 223, 190, 72, 25, 28, 45, 214, 202, 97, 206, 53, 234, 243, 113, 127, 251, 254, 28, 70, 123, 61, 224, 128, 250, 238, 184, 180), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((7, 248, 231, 61, 71, 222, 95, 14, 226, 204, 248, 113, 199, 2, 169, 42, 31, 209, 90, 77, 225, 48, 97, 30, 70, 164, 36, 122, 4, 151, 70, 91, 63, 181, 215, 133, 192, 30, 209, 207, 6, 28, 115, 254, 31, 85, 223, 224, 17, 30, 199, 53, 211, 118, 187, 57, 172, 108, 248, 61, 122, 35, 113, 196), (193, 58, 173, 196, 77, 156, 58, 32, 155, 144, 129, 177, 155, 230, 85, 108, 159, 231, 180, 145, 224, 184, 217, 139, 24, 172, 130, 198, 180, 220, 62, 142, 226, 59, 130, 219, 43, 171, 194, 127, 5, 89, 121, 81, 24, 149, 226, 150, 182, 217, 247, 221, 163, 90, 14, 38, 95, 179, 198, 69), (158, 34, 46, 188, 210, 124, 124, 167, 33, 121, 18, 28, 108, 96, 251, 13, 170, 233, 16, 98, 12, 167, 176, 26, 141, 1, 84, 212, 141, 169, 199, 215, 170, 154, 86, 103, 55, 95, 245, 24), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((95, 0, 182, 117, 94, 216, 201, 211, 234, 140, 236, 221, 140, 23, 202, 58, 254, 221, 37, 135, 29, 28, 80, 179, 2, 193, 252, 134, 77, 4, 20, 115, 130, 49, 62, 106, 112, 29, 155, 108, 195, 222, 121, 31, 166, 90, 120, 43, 192, 215, 64, 151, 54, 27, 18, 165, 180, 84, 8, 241, 23, 45, 254, 165), (86, 105, 86, 155, 145, 17, 103, 232, 249, 198, 177, 168, 63, 222, 87, 182, 219, 65, 113, 174, 183, 101, 122, 169, 77, 135, 213, 66, 189, 157, 78, 137, 246, 156, 137, 224, 251, 75, 61, 53, 2, 112, 35, 39, 251, 254, 101, 58, 246, 10, 127, 225, 171, 96, 14, 38, 32, 215, 101, 166), (217, 55, 130, 46, 249, 32, 115, 207, 205, 181, 216, 219, 128, 26, 56, 117, 228, 95, 227, 77, 49, 111, 64, 238, 87, 20, 14, 17, 83, 228, 210, 130, 81, 208, 160, 90, 159, 73, 234, 102), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((190, 117, 90, 183, 111, 253, 143, 46, 179, 242, 70, 224, 54, 188, 192, 109, 243, 158, 131, 164, 113, 244, 104, 194, 158, 168, 188, 239, 244, 125, 40, 34, 38, 55, 193, 202, 207, 47, 219, 210, 51, 84, 92, 200, 136, 71, 74, 123, 33, 49, 204, 199, 53, 34, 80, 39, 197, 23, 196, 132, 32, 209, 10, 204), (78, 57, 209, 43, 179, 6, 245, 209, 225, 133, 148, 132, 33, 80, 72, 206, 111, 240, 3, 59, 49, 153, 207, 23, 50, 208, 8, 140, 65, 135, 212, 152, 132, 254, 48, 87, 18, 67, 178, 166, 67, 188, 86, 212, 152, 109, 218, 149, 142, 213, 194, 121, 191, 122, 155, 226, 227, 117, 103, 227), (48, 46, 95, 129, 16, 125, 24, 108, 5, 65, 115, 188, 112, 94, 17, 166, 72, 165, 220, 235, 132, 53, 81, 12, 60, 220, 128, 201, 152, 76, 185, 201, 195, 98, 132, 13, 68, 38, 94, 126), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((44, 148, 196, 135, 63, 175, 77, 227, 233, 49, 82, 180, 148, 40, 201, 44, 134, 93, 197, 142, 30, 51, 111, 251, 154, 165, 5, 35, 219, 99, 17, 219, 52, 213, 167, 49, 22, 64, 115, 215, 149, 133, 6, 80, 28, 219, 77, 206, 5, 184, 69, 25, 142, 111, 239, 230, 61, 184, 120, 55, 194, 67, 72, 80), (39, 254, 85, 155, 109, 146, 153, 83, 56, 40, 58, 119, 97, 89, 133, 98, 133, 71, 75, 116, 48, 45, 237, 203, 62, 127, 225, 145, 73, 14, 171, 127, 88, 2, 18, 207, 234, 111, 96, 19, 56, 142, 61, 178, 132, 67, 244, 84, 40, 5, 114, 185, 15, 13, 194, 32, 127, 220, 192, 239), (66, 136, 90, 197, 24, 201, 123, 218, 41, 11, 84, 139, 89, 123, 127, 4, 178, 11, 195, 74, 10, 109, 157, 252, 137, 164, 70, 217, 242, 58, 28, 204, 195, 118, 8, 254, 236, 167, 164, 195), GNUTLS_MAC_SHA512),
+ TEST_VECTOR((15, 242, 194, 121, 101, 58, 123, 149, 74, 251, 0, 150, 194, 177, 110, 89, 31, 163, 46, 239, 57, 237, 216, 20, 28, 101, 19, 214, 220, 108, 8, 99, 175, 14, 148, 191, 213, 123, 23, 129, 124, 209, 3, 143, 55, 99, 156, 248, 214, 56, 113, 174, 244, 110, 232, 25, 71, 82, 107, 197, 69, 76, 19, 242), (22, 238, 29, 174, 246, 160, 49, 106, 160, 70, 118, 70, 197, 33, 250, 48, 22, 95, 227, 54, 178, 73, 96, 15, 30, 86, 93, 40, 123, 151, 1, 128, 51, 226, 186, 212, 93, 118, 198, 104, 93, 119, 51, 155, 39, 235, 221, 156, 206, 27, 52, 193, 228, 97, 154, 151, 119, 77, 148, 231), (188, 14, 60, 178, 183, 139, 217, 214, 226, 236, 84, 70, 114, 173, 190, 68, 57, 143, 219, 167, 239, 51, 47, 28, 66, 53, 193, 4, 202, 50, 236, 0, 251, 71, 212, 114, 9, 225, 81, 151), GNUTLS_MAC_SHA512),
+};
+
+static void test_sp800_108_sha256(void **state)
+{
+ NTSTATUS status;
+ static const uint8_t key[] = {152, 203, 215, 84, 113, 216, 118, 177,
+ 81, 128, 50, 160, 148, 132, 82, 244,
+ 65, 179, 164, 219, 209, 14, 33, 131,
+ 178, 193, 80, 248, 126, 23, 66, 227,
+ 45, 221, 171, 12, 247, 15, 62, 179,
+ 164, 217, 123, 179, 106, 118, 228, 74,
+ 12, 2, 241, 229, 139, 55, 237, 155,
+ 220, 122, 200, 245, 129, 222, 37, 15};
+ static const uint8_t context[] = {114, 233, 112, 1, 53, 160, 76,
+ 175, 153, 59, 224, 82, 213, 189,
+ 18, 22, 106, 1, 0, 0, 255,
+ 255, 255, 255, 255, 255, 255, 255};
+ static const uint8_t label[] = {'K', 0, 'D', 0, 'S', 0, ' ', 0,
+ 's', 0, 'e', 0, 'r', 0, 'v', 0,
+ 'i', 0, 'c', 0, 'e', 0, 0, 0};
+ static const uint8_t expected[] = {219, 94, 173, 243, 157, 13, 49,
+ 57, 54, 3, 127, 239, 193, 4,
+ 220, 218, 252, 33, 105, 76, 18,
+ 140, 166, 177, 95, 65, 164, 18,
+ 52, 169, 9, 194};
+ uint8_t out[sizeof expected];
+
+ status = samba_gnutls_sp800_108_derive_key(key,
+ sizeof key,
+ NULL,
+ 0,
+ label,
+ sizeof label,
+ context,
+ sizeof context,
+ GNUTLS_MAC_SHA256,
+ out,
+ sizeof out);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_memory_equal(expected, out, sizeof out);
+}
+
+static void test_sp800_108_sha512(void **state)
+{
+ NTSTATUS status;
+ static const uint8_t key[] = {152, 203, 215, 84, 113, 216, 118, 177,
+ 81, 128, 50, 160, 148, 132, 82, 244,
+ 65, 179, 164, 219, 209, 14, 33, 131,
+ 178, 193, 80, 248, 126, 23, 66, 227,
+ 45, 221, 171, 12, 247, 15, 62, 179,
+ 164, 217, 123, 179, 106, 118, 228, 74,
+ 12, 2, 241, 229, 139, 55, 237, 155,
+ 220, 122, 200, 245, 129, 222, 37, 15};
+ static const uint8_t context[] = {114, 233, 112, 1, 53, 160, 76,
+ 175, 153, 59, 224, 82, 213, 189,
+ 18, 22, 106, 1, 0, 0, 255,
+ 255, 255, 255, 255, 255, 255, 255};
+ static const uint8_t label[] = {'K', 0, 'D', 0, 'S', 0, ' ', 0,
+ 's', 0, 'e', 0, 'r', 0, 'v', 0,
+ 'i', 0, 'c', 0, 'e', 0, 0, 0};
+ static const uint8_t expected[] = {
+ 7, 24, 223, 124, 39, 199, 153, 162, 178, 37, 249, 182, 253,
+ 103, 255, 46, 60, 102, 61, 116, 186, 74, 221, 37, 242, 137,
+ 234, 58, 125, 105, 64, 127, 42, 175, 82, 141, 104, 210, 231,
+ 17, 116, 215, 15, 144, 200, 234, 66, 162, 196, 216, 48, 111,
+ 239, 86, 93, 32, 81, 206, 12, 145, 136, 185, 81, 56};
+ uint8_t out[sizeof expected];
+
+ status = samba_gnutls_sp800_108_derive_key(key,
+ sizeof key,
+ NULL,
+ 0,
+ label,
+ sizeof label,
+ context,
+ sizeof context,
+ GNUTLS_MAC_SHA512,
+ out,
+ sizeof out);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_memory_equal(expected, out, sizeof out);
+}
+
+static void test_sp800_108_nist(void **state)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(nist_vectors); ++i) {
+ NTSTATUS status;
+ const struct test_vector *test_vector = &nist_vectors[i];
+ uint8_t out[test_vector->KO_len];
+
+ status = samba_gnutls_sp800_108_derive_key(
+ test_vector->KI,
+ test_vector->KI_len,
+ test_vector->input,
+ test_vector->input_len,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ test_vector->prf_algorithm,
+ out,
+ sizeof out);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_memory_equal(test_vector->KO, out, sizeof out);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_sp800_108_sha256),
+ cmocka_unit_test(test_sp800_108_sha512),
+ cmocka_unit_test(test_sp800_108_nist),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/lib/crypto/wscript b/lib/crypto/wscript
new file mode 100644
index 0000000..eaa18c5
--- /dev/null
+++ b/lib/crypto/wscript
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+
+def build(bld):
+ bld.SAMBA_SUBSYSTEM("GNUTLS_HELPERS",
+ source='''
+ gnutls_error.c
+ gnutls_aead_aes_256_cbc_hmac_sha512.c
+ gnutls_arcfour_confounded_md5.c
+ gnutls_weak_crypto.c
+ gnutls_sp800_108.c
+ ''',
+ deps="gnutls samba-errors")
+
+ bld.SAMBA_SUBSYSTEM('LIBCRYPTO',
+ source='''
+ md4.c
+ ''',
+ deps='''
+ talloc
+ ''')
+
+ bld.SAMBA_SUBSYSTEM('TORTURE_LIBCRYPTO',
+ source='md4test.c',
+ autoproto='test_proto.h',
+ deps='''
+ LIBCRYPTO
+ ''')
+
+ bld.SAMBA_SUBSYSTEM('gkdi',
+ source='gkdi.c',
+ deps='''
+ talloc
+ GNUTLS_HELPERS
+ NDR_GKDI
+ ''')
+
+ bld.SAMBA_PYTHON('python_crypto',
+ source='py_crypto.c',
+ deps='gnutls talloc LIBCLI_AUTH',
+ realname='samba/crypto.so')
+
+ bld.SAMBA_BINARY('test_gnutls_aead_aes_256_cbc_hmac_sha512',
+ source='''
+ gnutls_error.c
+ tests/test_gnutls_aead_aes_256_cbc_hmac_sha512.c
+ ''',
+ deps='cmocka gnutls samba-util samba-errors',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_gnutls_sp800_108',
+ source='''
+ tests/test_gnutls_sp800_108.c
+ ''',
+ deps='cmocka GNUTLS_HELPERS samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_gkdi_key_derivation',
+ source='test_gkdi_key_derivation.c',
+ deps='cmocka gkdi talloc NDR_GKDI samba-util samba-security',
+ for_selftest=True)
diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
new file mode 100644
index 0000000..19f6c29
--- /dev/null
+++ b/lib/dbwrap/dbwrap.c
@@ -0,0 +1,736 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
+
+ Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "lib/util/talloc_stack.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_private.h"
+#include "lib/util/util_tdb.h"
+#include "lib/util/tevent_ntstatus.h"
+
+/*
+ * Fall back using fetch if no genuine exists operation is provided
+ */
+
+static int dbwrap_fallback_exists(struct db_context *db, TDB_DATA key)
+{
+ NTSTATUS status = dbwrap_parse_record(db, key, NULL, NULL);
+ return NT_STATUS_IS_OK(status) ? 1 : 0;
+}
+
+static int delete_record(struct db_record *rec, void *data)
+{
+ NTSTATUS status = dbwrap_record_delete(rec);
+ return NT_STATUS_IS_OK(status) ? 0 : -1;
+}
+
+/*
+ * Fallback wipe implementation using traverse and delete if no genuine
+ * wipe operation is provided
+ */
+static int dbwrap_fallback_wipe(struct db_context *db)
+{
+ NTSTATUS status = dbwrap_trans_traverse(db, delete_record, NULL);
+ return NT_STATUS_IS_OK(status) ? 0 : -1;
+}
+
+static int do_nothing(struct db_record *rec, void *unused)
+{
+ return 0;
+}
+
+/*
+ * Fallback check operation: just traverse.
+ */
+static int dbwrap_fallback_check(struct db_context *db)
+{
+ NTSTATUS status = dbwrap_traverse_read(db, do_nothing, NULL, NULL);
+ return NT_STATUS_IS_OK(status) ? 0 : -1;
+}
+
+/*
+ * Wrapper functions for the backend methods
+ */
+
+TDB_DATA dbwrap_record_get_key(const struct db_record *rec)
+{
+ return rec->key;
+}
+
+TDB_DATA dbwrap_record_get_value(const struct db_record *rec)
+{
+ SMB_ASSERT(rec->value_valid);
+ return rec->value;
+}
+
+NTSTATUS dbwrap_record_storev(struct db_record *rec,
+ const TDB_DATA *dbufs, int num_dbufs, int flags)
+{
+ NTSTATUS status;
+
+ /*
+ * Invalidate before rec->storev() is called, give
+ * rec->storev() the chance to re-validate rec->value.
+ */
+ rec->value_valid = false;
+
+ status = rec->storev(rec, dbufs, num_dbufs, flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
+{
+ return dbwrap_record_storev(rec, &data, 1, flags);
+}
+
+NTSTATUS dbwrap_record_delete(struct db_record *rec)
+{
+ NTSTATUS status;
+
+ status = rec->delete_rec(rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ rec->value = tdb_null;
+
+ return NT_STATUS_OK;
+}
+
+struct dbwrap_merge_dbs_state {
+ struct db_context *to;
+ int flags;
+};
+
+/* Copy a single record to the db_context passed in private_data */
+static int dbwrap_merge_dbs_copy_record(struct db_record *rec,
+ void *private_data)
+{
+ struct dbwrap_merge_dbs_state *state = private_data;
+
+ TDB_DATA data = dbwrap_record_get_value(rec);
+ TDB_DATA key = dbwrap_record_get_key(rec);
+ NTSTATUS status = dbwrap_store(state->to, key, data, state->flags);
+
+ return NT_STATUS_IS_OK(status) ? 0 : 1;
+}
+
+NTSTATUS
+dbwrap_merge_dbs(struct db_context *to, struct db_context *from, int flags)
+{
+ struct dbwrap_merge_dbs_state state = {.to = to, .flags = flags};
+
+ return dbwrap_traverse(from,
+ dbwrap_merge_dbs_copy_record,
+ &state,
+ NULL);
+}
+
+const char *locked_dbs[DBWRAP_LOCK_ORDER_MAX];
+
+static void debug_lock_order(int level)
+{
+ int i;
+ DEBUG(level, ("lock order:"));
+ for (i=0; i<DBWRAP_LOCK_ORDER_MAX; i++) {
+ DEBUGADD(level,
+ (" %d:%s",
+ i + 1,
+ locked_dbs[i] ? locked_dbs[i] : "<none>"));
+ }
+ DEBUGADD(level, ("\n"));
+}
+
+void dbwrap_lock_order_lock(const char *db_name,
+ enum dbwrap_lock_order lock_order)
+{
+ int idx;
+
+ DBG_INFO("check lock order %d for %s\n",
+ (int)lock_order,
+ db_name);
+
+ if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
+ DBG_ERR("Invalid lock order %d of %s\n",
+ lock_order,
+ db_name);
+ smb_panic("lock order violation");
+ }
+
+ for (idx=lock_order-1; idx<DBWRAP_LOCK_ORDER_MAX; idx++) {
+ if (locked_dbs[idx] != NULL) {
+ DBG_ERR("Lock order violation: Trying %s at %d while "
+ "%s at %d is locked\n",
+ db_name,
+ (int)lock_order,
+ locked_dbs[idx],
+ idx + 1);
+ debug_lock_order(0);
+ smb_panic("lock order violation");
+ }
+ }
+
+ locked_dbs[lock_order-1] = db_name;
+
+ debug_lock_order(10);
+}
+
+void dbwrap_lock_order_unlock(const char *db_name,
+ enum dbwrap_lock_order lock_order)
+{
+ DBG_INFO("release lock order %d for %s\n",
+ (int)lock_order,
+ db_name);
+
+ if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
+ DBG_ERR("Invalid lock order %d of %s\n",
+ lock_order,
+ db_name);
+ smb_panic("lock order violation");
+ }
+
+ if (locked_dbs[lock_order-1] == NULL) {
+ DBG_ERR("db %s at order %d unlocked\n",
+ db_name,
+ (int)lock_order);
+ smb_panic("lock order violation");
+ }
+
+ if (locked_dbs[lock_order-1] != db_name) {
+ DBG_ERR("locked db at lock order %d is %s, expected %s\n",
+ (int)lock_order,
+ locked_dbs[lock_order-1],
+ db_name);
+ smb_panic("lock order violation");
+ }
+
+ locked_dbs[lock_order-1] = NULL;
+}
+
+struct dbwrap_lock_order_state {
+ struct db_context *db;
+};
+
+static int dbwrap_lock_order_state_destructor(
+ struct dbwrap_lock_order_state *s)
+{
+ struct db_context *db = s->db;
+ dbwrap_lock_order_unlock(db->name, db->lock_order);
+ return 0;
+}
+
+static struct dbwrap_lock_order_state *dbwrap_check_lock_order(
+ struct db_context *db, TALLOC_CTX *mem_ctx)
+{
+ struct dbwrap_lock_order_state *state;
+
+ state = talloc(mem_ctx, struct dbwrap_lock_order_state);
+ if (state == NULL) {
+ DBG_WARNING("talloc failed\n");
+ return NULL;
+ }
+ state->db = db;
+
+ dbwrap_lock_order_lock(db->name, db->lock_order);
+ talloc_set_destructor(state, dbwrap_lock_order_state_destructor);
+
+ return state;
+}
+
+static struct db_record *dbwrap_fetch_locked_internal(
+ struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key,
+ struct db_record *(*db_fn)(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key))
+{
+ struct db_record *rec;
+ struct dbwrap_lock_order_state *lock_order = NULL;
+
+ if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
+ lock_order = dbwrap_check_lock_order(db, mem_ctx);
+ if (lock_order == NULL) {
+ return NULL;
+ }
+ }
+ rec = db_fn(db, mem_ctx, key);
+ if (rec == NULL) {
+ TALLOC_FREE(lock_order);
+ return NULL;
+ }
+ (void)talloc_steal(rec, lock_order);
+ rec->db = db;
+ return rec;
+}
+
+struct db_record *dbwrap_fetch_locked(struct db_context *db,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ return dbwrap_fetch_locked_internal(db, mem_ctx, key,
+ db->fetch_locked);
+}
+
+struct db_context *dbwrap_record_get_db(struct db_record *rec)
+{
+ return rec->db;
+}
+
+struct dbwrap_fetch_state {
+ TALLOC_CTX *mem_ctx;
+ TDB_DATA data;
+};
+
+static void dbwrap_fetch_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct dbwrap_fetch_state *state =
+ (struct dbwrap_fetch_state *)private_data;
+
+ state->data.dsize = data.dsize;
+ state->data.dptr = (uint8_t *)talloc_memdup(state->mem_ctx, data.dptr,
+ data.dsize);
+}
+
+NTSTATUS dbwrap_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *value)
+{
+ struct dbwrap_fetch_state state;
+ NTSTATUS status;
+
+ if (value == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ state.mem_ctx = mem_ctx;
+
+ status = dbwrap_parse_record(db, key, dbwrap_fetch_parser, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if ((state.data.dsize != 0) && (state.data.dptr == NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *value = state.data;
+ return NT_STATUS_OK;
+}
+
+bool dbwrap_exists(struct db_context *db, TDB_DATA key)
+{
+ int result;
+ if (db->exists != NULL) {
+ result = db->exists(db, key);
+ } else {
+ result = dbwrap_fallback_exists(db,key);
+ }
+ return (result == 1);
+}
+
+struct dbwrap_store_state {
+ TDB_DATA data;
+ int flags;
+ NTSTATUS status;
+};
+
+static void dbwrap_store_fn(
+ struct db_record *rec,
+ TDB_DATA value,
+ void *private_data)
+{
+ struct dbwrap_store_state *state = private_data;
+ state->status = dbwrap_record_store(rec, state->data, state->flags);
+}
+
+NTSTATUS dbwrap_store(struct db_context *db, TDB_DATA key,
+ TDB_DATA data, int flags)
+{
+ struct dbwrap_store_state state = { .data = data, .flags = flags };
+ NTSTATUS status;
+
+ status = dbwrap_do_locked(db, key, dbwrap_store_fn, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return state.status;
+}
+
+struct dbwrap_delete_state {
+ NTSTATUS status;
+};
+
+static void dbwrap_delete_fn(
+ struct db_record *rec,
+ TDB_DATA value,
+ void *private_data)
+{
+ struct dbwrap_delete_state *state = private_data;
+ state->status = dbwrap_record_delete(rec);
+}
+
+NTSTATUS dbwrap_delete(struct db_context *db, TDB_DATA key)
+{
+ struct dbwrap_delete_state state = { .status = NT_STATUS_NOT_FOUND };
+ NTSTATUS status;
+
+ status = dbwrap_do_locked(db, key, dbwrap_delete_fn, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return state.status;
+}
+
+NTSTATUS dbwrap_traverse(struct db_context *db,
+ int (*f)(struct db_record*, void*),
+ void *private_data,
+ int *count)
+{
+ int ret = db->traverse(db, f, private_data);
+
+ if (ret < 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (count != NULL) {
+ *count = ret;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dbwrap_traverse_read(struct db_context *db,
+ int (*f)(struct db_record*, void*),
+ void *private_data,
+ int *count)
+{
+ int ret = db->traverse_read(db, f, private_data);
+
+ if (ret < 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (count != NULL) {
+ *count = ret;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void dbwrap_null_parser(TDB_DATA key, TDB_DATA val, void* data)
+{
+ return;
+}
+
+NTSTATUS dbwrap_parse_record(struct db_context *db, TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ if (parser == NULL) {
+ parser = dbwrap_null_parser;
+ }
+ return db->parse_record(db, key, parser, private_data);
+}
+
+struct dbwrap_parse_record_state {
+ struct db_context *db;
+ TDB_DATA key;
+ uint8_t _keybuf[64];
+};
+
+static void dbwrap_parse_record_done(struct tevent_req *subreq);
+
+struct tevent_req *dbwrap_parse_record_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct db_context *db,
+ TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
+ void *private_data,
+ enum dbwrap_req_state *req_state)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct dbwrap_parse_record_state *state = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state, struct dbwrap_parse_record_state);
+ if (req == NULL) {
+ *req_state = DBWRAP_REQ_ERROR;
+ return NULL;
+ }
+
+ *state = (struct dbwrap_parse_record_state) {
+ .db = db,
+ };
+
+ if (parser == NULL) {
+ parser = dbwrap_null_parser;
+ }
+
+ *req_state = DBWRAP_REQ_INIT;
+
+ if (db->parse_record_send == NULL) {
+ /*
+ * Backend doesn't implement async version, call sync one
+ */
+ status = db->parse_record(db, key, parser, private_data);
+ if (tevent_req_nterror(req, status)) {
+ *req_state = DBWRAP_REQ_DONE;
+ return tevent_req_post(req, ev);
+ }
+
+ *req_state = DBWRAP_REQ_DONE;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * Copy the key into our state ensuring the key data buffer is always
+ * available to all the dbwrap backends over the entire lifetime of the
+ * async request. Otherwise the caller might have free'd the key buffer.
+ */
+ if (key.dsize > sizeof(state->_keybuf)) {
+ state->key.dptr = talloc_memdup(state, key.dptr, key.dsize);
+ if (tevent_req_nomem(state->key.dptr, req)) {
+ return tevent_req_post(req, ev);
+ }
+ } else {
+ memcpy(state->_keybuf, key.dptr, key.dsize);
+ state->key.dptr = state->_keybuf;
+ }
+ state->key.dsize = key.dsize;
+
+ subreq = db->parse_record_send(state,
+ ev,
+ db,
+ state->key,
+ parser,
+ private_data,
+ req_state);
+ if (tevent_req_nomem(subreq, req)) {
+ *req_state = DBWRAP_REQ_ERROR;
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ dbwrap_parse_record_done,
+ req);
+ return req;
+}
+
+static void dbwrap_parse_record_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dbwrap_parse_record_state *state = tevent_req_data(
+ req, struct dbwrap_parse_record_state);
+ NTSTATUS status;
+
+ status = state->db->parse_record_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
+ void (*fn)(struct db_record *rec,
+ TDB_DATA value,
+ void *private_data),
+ void *private_data)
+{
+ struct db_record *rec;
+
+ if (db->do_locked != NULL) {
+ NTSTATUS status;
+
+ if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
+ dbwrap_lock_order_lock(db->name, db->lock_order);
+ }
+
+ status = db->do_locked(db, key, fn, private_data);
+
+ if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
+ dbwrap_lock_order_unlock(db->name, db->lock_order);
+ }
+
+ return status;
+ }
+
+ rec = dbwrap_fetch_locked(db, db, key);
+ if (rec == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * Invalidate rec->value, nobody shall assume it's set from
+ * within dbwrap_do_locked().
+ */
+ rec->value_valid = false;
+
+ fn(rec, rec->value, private_data);
+
+ TALLOC_FREE(rec);
+
+ return NT_STATUS_OK;
+}
+
+int dbwrap_wipe(struct db_context *db)
+{
+ if (db->wipe == NULL) {
+ return dbwrap_fallback_wipe(db);
+ }
+ return db->wipe(db);
+}
+
+int dbwrap_check(struct db_context *db)
+{
+ if (db->check == NULL) {
+ return dbwrap_fallback_check(db);
+ }
+ return db->check(db);
+}
+
+int dbwrap_get_seqnum(struct db_context *db)
+{
+ return db->get_seqnum(db);
+}
+
+int dbwrap_transaction_start(struct db_context *db)
+{
+ if (!db->persistent) {
+ /*
+ * dbwrap_ctdb has two different data models for persistent
+ * and non-persistent databases. Transactions are supported
+ * only for the persistent databases. This check is here to
+ * prevent breakages of the cluster case, autobuild at this
+ * point only tests non-clustered Samba. Before removing this
+ * check, please make sure that this facility has also been
+ * added to dbwrap_ctdb.
+ *
+ * Thanks, vl
+ */
+ DEBUG(1, ("transactions not supported on non-persistent "
+ "database %s\n", db->name));
+ return -1;
+ }
+ return db->transaction_start(db);
+}
+
+NTSTATUS dbwrap_transaction_start_nonblock(struct db_context *db)
+{
+ if (db->transaction_start_nonblock) {
+ return db->transaction_start_nonblock(db);
+ } else {
+ return dbwrap_transaction_start(db) == 0 ? NT_STATUS_OK
+ : NT_STATUS_UNSUCCESSFUL;
+ }
+}
+
+int dbwrap_transaction_commit(struct db_context *db)
+{
+ return db->transaction_commit(db);
+}
+
+int dbwrap_transaction_cancel(struct db_context *db)
+{
+ return db->transaction_cancel(db);
+}
+
+size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen)
+{
+ return db->id(db, id, idlen);
+}
+
+bool dbwrap_is_persistent(struct db_context *db)
+{
+ return db->persistent;
+}
+
+const char *dbwrap_name(struct db_context *db)
+{
+ return db->name;
+}
+
+static ssize_t tdb_data_buf(const TDB_DATA *dbufs, int num_dbufs,
+ uint8_t *buf, size_t buflen)
+{
+ size_t needed = 0;
+ uint8_t *p = buf;
+ int i;
+
+ for (i=0; i<num_dbufs; i++) {
+ size_t thislen = dbufs[i].dsize;
+
+ needed += thislen;
+ if (needed < thislen) {
+ /* wrap */
+ return -1;
+ }
+
+ if (p != NULL && (thislen != 0) && (needed <= buflen)) {
+ memcpy(p, dbufs[i].dptr, thislen);
+ p += thislen;
+ }
+ }
+
+ return needed;
+}
+
+
+NTSTATUS dbwrap_merge_dbufs(TDB_DATA *buf, TALLOC_CTX *mem_ctx,
+ const TDB_DATA *dbufs, int num_dbufs)
+{
+ ssize_t len = tdb_data_buf(dbufs, num_dbufs, NULL, 0);
+
+ if (len == -1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (buf->dsize != len) {
+ uint8_t *tmp;
+
+ tmp = talloc_realloc(mem_ctx, buf->dptr, uint8_t, len);
+ if (tmp == NULL && len != 0) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ buf->dptr = tmp;
+ buf->dsize = len;
+ }
+
+ tdb_data_buf(dbufs, num_dbufs, buf->dptr, buf->dsize);
+
+ return NT_STATUS_OK;
+}
diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
new file mode 100644
index 0000000..abc5161
--- /dev/null
+++ b/lib/dbwrap/dbwrap.h
@@ -0,0 +1,252 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around tdb
+ Copyright (C) Volker Lendecke 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __DBWRAP_H__
+#define __DBWRAP_H__
+
+#include "replace.h"
+#include <talloc.h>
+#include <tevent.h>
+#include "libcli/util/ntstatus.h"
+#include "tdb.h"
+
+struct db_record;
+struct db_context;
+
+enum dbwrap_lock_order {
+ DBWRAP_LOCK_ORDER_NONE = 0, /* Don't check lock orders for this db. */
+ DBWRAP_LOCK_ORDER_1 = 1,
+ DBWRAP_LOCK_ORDER_2 = 2,
+ DBWRAP_LOCK_ORDER_3 = 3,
+ DBWRAP_LOCK_ORDER_4 = 4
+};
+
+#define DBWRAP_FLAG_NONE 0x0000000000000000ULL
+#define DBWRAP_FLAG_OPTIMIZE_READONLY_ACCESS 0x0000000000000001ULL
+
+enum dbwrap_req_state {
+ /**
+ * We are creating the request
+ */
+ DBWRAP_REQ_INIT,
+ /**
+ * The request is queued and waiting to be dispatched
+ */
+ DBWRAP_REQ_QUEUED,
+ /**
+ * We are waiting to receive the reply
+ */
+ DBWRAP_REQ_DISPATCHED,
+ /**
+ * The request is finished
+ */
+ DBWRAP_REQ_DONE,
+ /**
+ * The request errored out
+ */
+ DBWRAP_REQ_ERROR
+};
+
+/* The following definitions come from lib/dbwrap.c */
+
+TDB_DATA dbwrap_record_get_key(const struct db_record *rec);
+TDB_DATA dbwrap_record_get_value(const struct db_record *rec);
+NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags);
+NTSTATUS dbwrap_record_storev(struct db_record *rec,
+ const TDB_DATA *dbufs, int num_dbufs, int flags);
+NTSTATUS dbwrap_record_delete(struct db_record *rec);
+
+/**
+ * @brief Adds TDB records from one db_context to another
+ *
+ * @param to Destination db_context
+ * @param from Source db_context
+ * @param flags (TDB_INSERT or TDB_REPLACE)
+ *
+ * @return NT_STATUS_OK on success or NT_STATUS_INTERNAL_DB_CORRUPTION
+ */
+NTSTATUS
+dbwrap_merge_dbs(struct db_context *to, struct db_context *from, int flags);
+
+struct db_record *dbwrap_fetch_locked(struct db_context *db,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key);
+struct db_context *dbwrap_record_get_db(struct db_record *rec);
+
+void dbwrap_lock_order_lock(const char *db_name,
+ enum dbwrap_lock_order lock_order);
+void dbwrap_lock_order_unlock(const char *db_name,
+ enum dbwrap_lock_order lock_order);
+
+NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
+ void (*fn)(struct db_record *rec,
+ TDB_DATA value,
+ void *private_data),
+ void *private_data);
+
+NTSTATUS dbwrap_delete(struct db_context *db, TDB_DATA key);
+NTSTATUS dbwrap_store(struct db_context *db, TDB_DATA key,
+ TDB_DATA data, int flags);
+NTSTATUS dbwrap_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
+ TDB_DATA key, TDB_DATA *value);
+bool dbwrap_exists(struct db_context *db, TDB_DATA key);
+NTSTATUS dbwrap_traverse(struct db_context *db,
+ int (*f)(struct db_record*, void*),
+ void *private_data,
+ int *count);
+NTSTATUS dbwrap_traverse_read(struct db_context *db,
+ int (*f)(struct db_record*, void*),
+ void *private_data,
+ int *count);
+NTSTATUS dbwrap_parse_record(struct db_context *db, TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+/**
+ * Async implementation of dbwrap_parse_record
+ *
+ * @param[in] mem_ctx talloc memory context to use.
+ *
+ * @param[in] ev tevent context to use
+ *
+ * @param[in] db Database to query
+ *
+ * @param[in] key Record key, the function makes a copy of this
+ *
+ * @param[in] parser Parser callback function
+ *
+ * @param[in] private_data Private data for the callback function
+ *
+ * @param[out] req_state Pointer to a enum dbwrap_req_state variable
+ *
+ * @note req_state is updated in the send function. To determine the final
+ * result of the request the caller should therefore not rely on req_state. The
+ * primary use case is to give the caller an indication whether the request is
+ * already sent to ctdb (DBWRAP_REQ_DISPATCHED) or if it's still stuck in the
+ * sendqueue (DBWRAP_REQ_QUEUED).
+ **/
+struct tevent_req *dbwrap_parse_record_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct db_context *db,
+ TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
+ void *private_data,
+ enum dbwrap_req_state *req_state);
+NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req);
+int dbwrap_wipe(struct db_context *db);
+int dbwrap_check(struct db_context *db);
+int dbwrap_get_seqnum(struct db_context *db);
+/* Returns 0 if unknown. */
+int dbwrap_transaction_start(struct db_context *db);
+NTSTATUS dbwrap_transaction_start_nonblock(struct db_context *db);
+int dbwrap_transaction_commit(struct db_context *db);
+int dbwrap_transaction_cancel(struct db_context *db);
+size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen);
+bool dbwrap_is_persistent(struct db_context *db);
+const char *dbwrap_name(struct db_context *db);
+
+/* The following definitions come from lib/dbwrap_util.c */
+
+NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key);
+NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key);
+NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key);
+NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags);
+NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
+ const char *key, TDB_DATA *value);
+
+NTSTATUS dbwrap_fetch_int32(struct db_context *db, TDB_DATA key,
+ int32_t *result);
+NTSTATUS dbwrap_fetch_int32_bystring(struct db_context *db, const char *keystr,
+ int32_t *result);
+NTSTATUS dbwrap_store_int32_bystring(struct db_context *db, const char *keystr,
+ int32_t v);
+NTSTATUS dbwrap_fetch_uint32_bystring(struct db_context *db,
+ const char *keystr, uint32_t *val);
+NTSTATUS dbwrap_store_uint32_bystring(struct db_context *db,
+ const char *keystr, uint32_t v);
+NTSTATUS dbwrap_change_uint32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ uint32_t *oldval,
+ uint32_t change_val);
+NTSTATUS dbwrap_trans_change_uint32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ uint32_t *oldval,
+ uint32_t change_val);
+NTSTATUS dbwrap_change_int32_atomic(struct db_context *db,
+ TDB_DATA key,
+ int32_t *oldval,
+ int32_t change_val);
+NTSTATUS dbwrap_change_int32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ int32_t *oldval,
+ int32_t change_val);
+NTSTATUS dbwrap_trans_change_int32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ int32_t *oldval,
+ int32_t change_val);
+NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
+ int flag);
+NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key);
+NTSTATUS dbwrap_trans_store_int32_bystring(struct db_context *db,
+ const char *keystr,
+ int32_t v);
+NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
+ const char *keystr,
+ uint32_t v);
+NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags);
+NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key);
+NTSTATUS dbwrap_trans_do(struct db_context *db,
+ NTSTATUS (*action)(struct db_context *, void *),
+ void *private_data);
+NTSTATUS dbwrap_trans_traverse(struct db_context *db,
+ int (*f)(struct db_record*, void*),
+ void *private_data);
+
+NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key);
+NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
+ TDB_DATA data, int flags);
+NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
+ const char *key, TDB_DATA *value);
+
+size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize);
+NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
+ bool (*fn)(TDB_DATA key, TDB_DATA value,
+ void *private_data),
+ void *private_data);
+NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
+ size_t buflen);
+
+NTSTATUS dbwrap_merge_dbufs(TDB_DATA *buf, TALLOC_CTX *mem_ctx,
+ const TDB_DATA *dbufs, int num_dbufs);
+
+
+/**
+ * This opens a tdb file
+ */
+struct db_context *dbwrap_local_open(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ enum dbwrap_lock_order lock_order,
+ uint64_t dbwrap_flags);
+
+#endif /* __DBWRAP_H__ */
diff --git a/lib/dbwrap/dbwrap_local_open.c b/lib/dbwrap/dbwrap_local_open.c
new file mode 100644
index 0000000..20c5fa0
--- /dev/null
+++ b/lib/dbwrap/dbwrap_local_open.c
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper: local open code.
+
+ Copyright (C) Rusty Russell 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_tdb.h"
+#include "tdb.h"
+
+struct db_context *dbwrap_local_open(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ enum dbwrap_lock_order lock_order,
+ uint64_t dbwrap_flags)
+{
+ struct db_context *db = NULL;
+
+ db = db_open_tdb(
+ mem_ctx,
+ name,
+ hash_size,
+ tdb_flags,
+ open_flags,
+ mode,
+ lock_order,
+ dbwrap_flags);
+
+ return db;
+}
diff --git a/lib/dbwrap/dbwrap_private.h b/lib/dbwrap/dbwrap_private.h
new file mode 100644
index 0000000..3ac5ebf
--- /dev/null
+++ b/lib/dbwrap/dbwrap_private.h
@@ -0,0 +1,93 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around tdb - private header
+
+ Copyright (C) Volker Lendecke 2005-2007
+ Copyright (C) Gregor Beck 2011
+ Copyright (C) Michael Adam 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __DBWRAP_PRIVATE_H__
+#define __DBWRAP_PRIVATE_H__
+
+struct tevent_context;
+struct tevent_req;
+
+struct db_record {
+ struct db_context *db;
+ TDB_DATA key, value;
+ bool value_valid;
+ NTSTATUS (*storev)(struct db_record *rec, const TDB_DATA *dbufs,
+ int num_dbufs, int flag);
+ NTSTATUS (*delete_rec)(struct db_record *rec);
+ void *private_data;
+};
+
+struct db_context {
+ struct db_record *(*fetch_locked)(struct db_context *db,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key);
+ int (*traverse)(struct db_context *db,
+ int (*f)(struct db_record *rec,
+ void *private_data),
+ void *private_data);
+ int (*traverse_read)(struct db_context *db,
+ int (*f)(struct db_record *rec,
+ void *private_data),
+ void *private_data);
+ int (*get_seqnum)(struct db_context *db);
+ int (*transaction_start)(struct db_context *db);
+ NTSTATUS (*transaction_start_nonblock)(struct db_context *db);
+ int (*transaction_commit)(struct db_context *db);
+ int (*transaction_cancel)(struct db_context *db);
+ NTSTATUS (*parse_record)(struct db_context *db, TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+ struct tevent_req *(*parse_record_send)(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct db_context *db,
+ TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
+ void *private_data,
+ enum dbwrap_req_state *req_state);
+ NTSTATUS (*parse_record_recv)(struct tevent_req *req);
+ NTSTATUS (*do_locked)(struct db_context *db, TDB_DATA key,
+ void (*fn)(struct db_record *rec,
+ TDB_DATA value,
+ void *private_data),
+ void *private_data);
+ int (*exists)(struct db_context *db,TDB_DATA key);
+ int (*wipe)(struct db_context *db);
+ int (*check)(struct db_context *db);
+ size_t (*id)(struct db_context *db, uint8_t *id, size_t idlen);
+
+ const char *name;
+ void *private_data;
+ enum dbwrap_lock_order lock_order;
+ bool persistent;
+};
+
+#define DBWRAP_LOCK_ORDER_MIN DBWRAP_LOCK_ORDER_1
+#define DBWRAP_LOCK_ORDER_MAX DBWRAP_LOCK_ORDER_4
+
+#define DBWRAP_LOCK_ORDER_VALID(order) \
+ (((order) >= DBWRAP_LOCK_ORDER_MIN) && \
+ ((order) <= DBWRAP_LOCK_ORDER_MAX))
+
+#endif /* __DBWRAP_PRIVATE_H__ */
+
diff --git a/lib/dbwrap/dbwrap_rbt.c b/lib/dbwrap/dbwrap_rbt.c
new file mode 100644
index 0000000..89d30bb
--- /dev/null
+++ b/lib/dbwrap/dbwrap_rbt.c
@@ -0,0 +1,589 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around red-black trees
+ Copyright (C) Volker Lendecke 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_private.h"
+#include "dbwrap/dbwrap_rbt.h"
+#include "../lib/util/rbtree.h"
+#include "../lib/util/dlinklist.h"
+
+#define DBWRAP_RBT_ALIGN(_size_) (((_size_)+15)&~15)
+
+struct db_rbt_ctx {
+ struct rb_root tree;
+ struct db_rbt_node *nodes;
+ size_t traverse_read;
+ struct db_rbt_node **traverse_nextp;
+};
+
+struct db_rbt_rec {
+ struct db_rbt_node *node;
+};
+
+/* The structure that ends up in the tree */
+
+struct db_rbt_node {
+ struct rb_node rb_node;
+ size_t keysize, valuesize;
+ struct db_rbt_node *prev, *next;
+};
+
+/*
+ * Hide the ugly pointer calculations in a function
+ */
+
+static struct db_rbt_node *db_rbt2node(struct rb_node *node)
+{
+ return (struct db_rbt_node *)
+ ((char *)node - offsetof(struct db_rbt_node, rb_node));
+}
+
+/*
+ * Compare two keys
+ */
+
+static int db_rbt_compare(TDB_DATA a, TDB_DATA b)
+{
+ int res;
+
+ res = memcmp(a.dptr, b.dptr, MIN(a.dsize, b.dsize));
+
+ if ((res < 0) || ((res == 0) && (a.dsize < b.dsize))) {
+ return -1;
+ }
+ if ((res > 0) || ((res == 0) && (a.dsize > b.dsize))) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * dissect a db_rbt_node into its implicit key and value parts
+ */
+
+static void db_rbt_parse_node(struct db_rbt_node *node,
+ TDB_DATA *key, TDB_DATA *value)
+{
+ size_t key_offset, value_offset;
+
+ key_offset = DBWRAP_RBT_ALIGN(sizeof(struct db_rbt_node));
+ key->dptr = ((uint8_t *)node) + key_offset;
+ key->dsize = node->keysize;
+
+ value_offset = DBWRAP_RBT_ALIGN(node->keysize);
+ value->dptr = key->dptr + value_offset;
+ value->dsize = node->valuesize;
+}
+
+static ssize_t db_rbt_reclen(size_t keylen, size_t valuelen)
+{
+ size_t len, tmp;
+
+ len = DBWRAP_RBT_ALIGN(sizeof(struct db_rbt_node));
+
+ tmp = DBWRAP_RBT_ALIGN(keylen);
+ if (tmp < keylen) {
+ goto overflow;
+ }
+
+ len += tmp;
+ if (len < tmp) {
+ goto overflow;
+ }
+
+ len += valuelen;
+ if (len < valuelen) {
+ goto overflow;
+ }
+
+ return len;
+overflow:
+ return -1;
+}
+
+static NTSTATUS db_rbt_storev(struct db_record *rec,
+ const TDB_DATA *dbufs, int num_dbufs, int flag)
+{
+ struct db_rbt_ctx *db_ctx = talloc_get_type_abort(
+ rec->db->private_data, struct db_rbt_ctx);
+ struct db_rbt_rec *rec_priv = (struct db_rbt_rec *)rec->private_data;
+ struct db_rbt_node *node;
+
+ struct rb_node ** p;
+ struct rb_node *parent = NULL;
+ struct db_rbt_node *parent_node = NULL;
+
+ ssize_t reclen;
+ TDB_DATA data, this_key, this_val;
+ void *to_free = NULL;
+
+ if (db_ctx->traverse_read > 0) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ if ((flag == TDB_INSERT) && (rec_priv->node != NULL)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if ((flag == TDB_MODIFY) && (rec_priv->node == NULL)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (num_dbufs == 1) {
+ data = dbufs[0];
+ } else {
+ NTSTATUS status;
+
+ data = (TDB_DATA) {0};
+ status = dbwrap_merge_dbufs(&data, rec, dbufs, num_dbufs);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ to_free = data.dptr;
+ }
+
+ if (rec_priv->node != NULL) {
+
+ /*
+ * The record was around previously
+ */
+
+ db_rbt_parse_node(rec_priv->node, &this_key, &this_val);
+
+ SMB_ASSERT(this_key.dsize == rec->key.dsize);
+ SMB_ASSERT(memcmp(this_key.dptr, rec->key.dptr,
+ this_key.dsize) == 0);
+
+ if (this_val.dsize >= data.dsize) {
+ /*
+ * The new value fits into the old space
+ */
+ memcpy(this_val.dptr, data.dptr, data.dsize);
+ rec_priv->node->valuesize = data.dsize;
+ TALLOC_FREE(to_free);
+ return NT_STATUS_OK;
+ }
+ }
+
+ reclen = db_rbt_reclen(rec->key.dsize, data.dsize);
+ if (reclen == -1) {
+ TALLOC_FREE(to_free);
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ node = talloc_zero_size(db_ctx, reclen);
+ if (node == NULL) {
+ TALLOC_FREE(to_free);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (rec_priv->node != NULL) {
+ if (db_ctx->traverse_nextp != NULL) {
+ if (*db_ctx->traverse_nextp == rec_priv->node) {
+ *db_ctx->traverse_nextp = node;
+ }
+ }
+
+ /*
+ * We need to delete the key from the tree and start fresh,
+ * there's not enough space in the existing record
+ */
+
+ rb_erase(&rec_priv->node->rb_node, &db_ctx->tree);
+ DLIST_REMOVE(db_ctx->nodes, rec_priv->node);
+
+ /*
+ * Keep the existing node around for a while: If the record
+ * existed before, we reference the key data in there.
+ */
+ }
+
+ node->keysize = rec->key.dsize;
+ node->valuesize = data.dsize;
+
+ db_rbt_parse_node(node, &this_key, &this_val);
+
+ memcpy(this_key.dptr, rec->key.dptr, node->keysize);
+ TALLOC_FREE(rec_priv->node);
+ rec_priv->node = node;
+
+ if (node->valuesize > 0) {
+ memcpy(this_val.dptr, data.dptr, node->valuesize);
+ }
+
+ parent = NULL;
+ p = &db_ctx->tree.rb_node;
+
+ while (*p) {
+ struct db_rbt_node *r;
+ TDB_DATA search_key, search_val;
+ int res;
+
+ r = db_rbt2node(*p);
+
+ parent = (*p);
+ parent_node = r;
+
+ db_rbt_parse_node(r, &search_key, &search_val);
+
+ res = db_rbt_compare(this_key, search_key);
+
+ if (res == -1) {
+ p = &(*p)->rb_left;
+ }
+ else if (res == 1) {
+ p = &(*p)->rb_right;
+ }
+ else {
+ smb_panic("someone messed with the tree");
+ }
+ }
+
+ rb_link_node(&node->rb_node, parent, p);
+ DLIST_ADD_AFTER(db_ctx->nodes, node, parent_node);
+ rb_insert_color(&node->rb_node, &db_ctx->tree);
+
+ TALLOC_FREE(to_free);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS db_rbt_delete(struct db_record *rec)
+{
+ struct db_rbt_ctx *db_ctx = talloc_get_type_abort(
+ rec->db->private_data, struct db_rbt_ctx);
+ struct db_rbt_rec *rec_priv = (struct db_rbt_rec *)rec->private_data;
+
+ if (db_ctx->traverse_read > 0) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
+ if (rec_priv->node == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ if (db_ctx->traverse_nextp != NULL) {
+ if (*db_ctx->traverse_nextp == rec_priv->node) {
+ *db_ctx->traverse_nextp = rec_priv->node->next;
+ }
+ }
+
+ rb_erase(&rec_priv->node->rb_node, &db_ctx->tree);
+ DLIST_REMOVE(db_ctx->nodes, rec_priv->node);
+ TALLOC_FREE(rec_priv->node);
+
+ return NT_STATUS_OK;
+}
+
+struct db_rbt_search_result {
+ TDB_DATA key;
+ TDB_DATA val;
+ struct db_rbt_node* node;
+};
+
+static bool db_rbt_search_internal(struct db_context *db, TDB_DATA key,
+ struct db_rbt_search_result *result)
+{
+ struct db_rbt_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_rbt_ctx);
+
+ struct rb_node *n;
+ bool found = false;
+ struct db_rbt_node *r = NULL;
+ TDB_DATA search_key = { 0 };
+ TDB_DATA search_val = { 0 };
+
+ n = ctx->tree.rb_node;
+
+ while (n != NULL) {
+ int res;
+
+ r = db_rbt2node(n);
+
+ db_rbt_parse_node(r, &search_key, &search_val);
+
+ res = db_rbt_compare(key, search_key);
+
+ if (res == -1) {
+ n = n->rb_left;
+ }
+ else if (res == 1) {
+ n = n->rb_right;
+ }
+ else {
+ found = true;
+ break;
+ }
+ }
+ if (result != NULL) {
+ if (found) {
+ result->key = search_key;
+ result->val = search_val;
+ result->node = r;
+ } else {
+ ZERO_STRUCT(*result);
+ }
+ }
+ return found;
+}
+
+static struct db_record *db_rbt_fetch_locked(struct db_context *db_ctx,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ struct db_rbt_rec *rec_priv;
+ struct db_record *result;
+ size_t size;
+ bool found;
+ struct db_rbt_search_result res;
+
+ found = db_rbt_search_internal(db_ctx, key, &res);
+
+ /*
+ * In this low-level routine, play tricks to reduce the number of
+ * tallocs to one. Not recommended for general use, but here it pays
+ * off.
+ */
+
+ size = DBWRAP_RBT_ALIGN(sizeof(struct db_record))
+ + sizeof(struct db_rbt_rec);
+
+ if (!found) {
+ /*
+ * We need to keep the key around for later store
+ */
+ size += key.dsize;
+ }
+
+ result = (struct db_record *)talloc_size(mem_ctx, size);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ rec_priv = (struct db_rbt_rec *)
+ ((char *)result + DBWRAP_RBT_ALIGN(sizeof(struct db_record)));
+
+ result->storev = db_rbt_storev;
+ result->delete_rec = db_rbt_delete;
+ result->private_data = rec_priv;
+
+ rec_priv->node = res.node;
+ result->value = res.val;
+ result->value_valid = true;
+
+ if (found) {
+ result->key = res.key;
+ }
+ else {
+ result->key.dptr = (uint8_t *)
+ ((char *)rec_priv + sizeof(*rec_priv));
+ result->key.dsize = key.dsize;
+ memcpy(result->key.dptr, key.dptr, key.dsize);
+ }
+
+ return result;
+}
+
+static int db_rbt_exists(struct db_context *db, TDB_DATA key)
+{
+ return db_rbt_search_internal(db, key, NULL);
+}
+
+static int db_rbt_wipe(struct db_context *db)
+{
+ struct db_rbt_ctx *old_ctx = talloc_get_type_abort(
+ db->private_data, struct db_rbt_ctx);
+ struct db_rbt_ctx *new_ctx = talloc_zero(db, struct db_rbt_ctx);
+ if (new_ctx == NULL) {
+ return -1;
+ }
+ db->private_data = new_ctx;
+ talloc_free(old_ctx);
+ return 0;
+}
+
+static NTSTATUS db_rbt_parse_record(struct db_context *db, TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ struct db_rbt_search_result res;
+ bool found = db_rbt_search_internal(db, key, &res);
+
+ if (!found) {
+ return NT_STATUS_NOT_FOUND;
+ }
+ parser(res.key, res.val, private_data);
+ return NT_STATUS_OK;
+}
+
+static int db_rbt_traverse_internal(struct db_context *db,
+ int (*f)(struct db_record *db,
+ void *private_data),
+ void *private_data, uint32_t* count,
+ bool rw)
+{
+ struct db_rbt_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_rbt_ctx);
+ struct db_rbt_node *cur = NULL;
+ struct db_rbt_node *next = NULL;
+ int ret;
+
+ for (cur = ctx->nodes; cur != NULL; cur = next) {
+ struct db_record rec;
+ struct db_rbt_rec rec_priv;
+
+ rec_priv.node = cur;
+ next = rec_priv.node->next;
+
+ ZERO_STRUCT(rec);
+ rec.db = db;
+ rec.private_data = &rec_priv;
+ rec.storev = db_rbt_storev;
+ rec.delete_rec = db_rbt_delete;
+ db_rbt_parse_node(rec_priv.node, &rec.key, &rec.value);
+ rec.value_valid = true;
+
+ if (rw) {
+ ctx->traverse_nextp = &next;
+ }
+ ret = f(&rec, private_data);
+ (*count) ++;
+ if (rw) {
+ ctx->traverse_nextp = NULL;
+ }
+ if (ret != 0) {
+ return ret;
+ }
+ if (rec_priv.node != NULL) {
+ next = rec_priv.node->next;
+ }
+ }
+
+ return 0;
+}
+
+static int db_rbt_traverse_read(struct db_context *db,
+ int (*f)(struct db_record *db,
+ void *private_data),
+ void *private_data)
+{
+ struct db_rbt_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_rbt_ctx);
+ uint32_t count = 0;
+ int ret;
+
+ ctx->traverse_read++;
+ ret = db_rbt_traverse_internal(db,
+ f, private_data, &count,
+ false /* rw */);
+ ctx->traverse_read--;
+ if (ret != 0) {
+ return -1;
+ }
+ if (count > INT_MAX) {
+ return -1;
+ }
+ return count;
+}
+
+static int db_rbt_traverse(struct db_context *db,
+ int (*f)(struct db_record *db,
+ void *private_data),
+ void *private_data)
+{
+ struct db_rbt_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_rbt_ctx);
+ uint32_t count = 0;
+ int ret;
+
+ if (ctx->traverse_nextp != NULL) {
+ return -1;
+ };
+
+ if (ctx->traverse_read > 0) {
+ return db_rbt_traverse_read(db, f, private_data);
+ }
+
+ ret = db_rbt_traverse_internal(db,
+ f, private_data, &count,
+ true /* rw */);
+ if (ret != 0) {
+ return -1;
+ }
+ if (count > INT_MAX) {
+ return -1;
+ }
+ return count;
+}
+
+static int db_rbt_get_seqnum(struct db_context *db)
+{
+ return 0;
+}
+
+static int db_rbt_trans_dummy(struct db_context *db)
+{
+ /*
+ * Transactions are pretty pointless in-memory, just return success.
+ */
+ return 0;
+}
+
+static size_t db_rbt_id(struct db_context *db, uint8_t *id, size_t idlen)
+{
+ if (idlen >= sizeof(struct db_context *)) {
+ memcpy(id, &db, sizeof(struct db_context *));
+ }
+ return sizeof(struct db_context *);
+}
+
+struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx)
+{
+ struct db_context *result;
+
+ result = talloc_zero(mem_ctx, struct db_context);
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ result->private_data = talloc_zero(result, struct db_rbt_ctx);
+
+ if (result->private_data == NULL) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ result->fetch_locked = db_rbt_fetch_locked;
+ result->traverse = db_rbt_traverse;
+ result->traverse_read = db_rbt_traverse_read;
+ result->get_seqnum = db_rbt_get_seqnum;
+ result->transaction_start = db_rbt_trans_dummy;
+ result->transaction_commit = db_rbt_trans_dummy;
+ result->transaction_cancel = db_rbt_trans_dummy;
+ result->exists = db_rbt_exists;
+ result->wipe = db_rbt_wipe;
+ result->parse_record = db_rbt_parse_record;
+ result->id = db_rbt_id;
+ result->name = "dbwrap rbt";
+
+ return result;
+}
diff --git a/lib/dbwrap/dbwrap_rbt.h b/lib/dbwrap/dbwrap_rbt.h
new file mode 100644
index 0000000..1716879
--- /dev/null
+++ b/lib/dbwrap/dbwrap_rbt.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around red-black trees
+ Copyright (C) Volker Lendecke 2007, 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __DBWRAP_RBT_H__
+#define __DBWRAP_RBT_H__
+
+#include <talloc.h>
+
+struct db_context;
+
+struct db_context *db_open_rbt(TALLOC_CTX *mem_ctx);
+
+#endif /* __DBWRAP_RBT_H__ */
diff --git a/lib/dbwrap/dbwrap_tdb.c b/lib/dbwrap/dbwrap_tdb.c
new file mode 100644
index 0000000..6cd95fa
--- /dev/null
+++ b/lib/dbwrap/dbwrap_tdb.c
@@ -0,0 +1,518 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around tdb
+ Copyright (C) Volker Lendecke 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_private.h"
+#include "dbwrap/dbwrap_tdb.h"
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/util_tdb.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "system/filesys.h"
+#include "lib/param/param.h"
+#include "libcli/util/error.h"
+
+struct db_tdb_ctx {
+ struct tdb_wrap *wtdb;
+
+ struct {
+ dev_t dev;
+ ino_t ino;
+ } id;
+};
+
+static NTSTATUS db_tdb_storev(struct db_record *rec,
+ const TDB_DATA *dbufs, int num_dbufs, int flag);
+static NTSTATUS db_tdb_delete(struct db_record *rec);
+
+static void db_tdb_log_key(const char *prefix, TDB_DATA key)
+{
+ if (DEBUGLEVEL < 10) {
+ return;
+ }
+ if (DEBUGLEVEL == 10) {
+ /*
+ * Only fully spam at debuglevel > 10
+ */
+ key.dsize = MIN(10, key.dsize);
+ }
+
+ if (key.dsize < 1024) {
+ char keystr[key.dsize*2+1];
+ hex_encode_buf(keystr, key.dptr, key.dsize);
+ DBG_DEBUG("%s key %s\n", prefix, keystr);
+ return;
+ }
+
+ dump_data(DEBUGLEVEL, key.dptr, key.dsize);
+}
+
+static int db_tdb_record_destr(struct db_record* data)
+{
+ struct db_tdb_ctx *ctx =
+ talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
+
+ db_tdb_log_key("Unlocking", data->key);
+ tdb_chainunlock(ctx->wtdb->tdb, data->key);
+ return 0;
+}
+
+struct tdb_fetch_locked_state {
+ TALLOC_CTX *mem_ctx;
+ struct db_record *result;
+};
+
+static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct tdb_fetch_locked_state *state =
+ (struct tdb_fetch_locked_state *)private_data;
+ struct db_record *result;
+
+ result = (struct db_record *)talloc_size(
+ state->mem_ctx,
+ sizeof(struct db_record) + key.dsize + data.dsize);
+
+ if (result == NULL) {
+ return 0;
+ }
+ state->result = result;
+
+ result->key.dsize = key.dsize;
+ result->key.dptr = ((uint8_t *)result) + sizeof(struct db_record);
+ memcpy(result->key.dptr, key.dptr, key.dsize);
+
+ result->value.dsize = data.dsize;
+
+ if (data.dsize > 0) {
+ result->value.dptr = result->key.dptr+key.dsize;
+ memcpy(result->value.dptr, data.dptr, data.dsize);
+ }
+ else {
+ result->value.dptr = NULL;
+ }
+ result->value_valid = true;
+
+ return 0;
+}
+
+static struct db_record *db_tdb_fetch_locked_internal(
+ struct db_context *db,
+ struct db_tdb_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ TDB_DATA key)
+{
+ struct tdb_fetch_locked_state state;
+ int ret;
+
+ state = (struct tdb_fetch_locked_state) {
+ .mem_ctx = mem_ctx,
+ };
+
+ ret = tdb_parse_record(ctx->wtdb->tdb,
+ key,
+ db_tdb_fetchlock_parse,
+ &state);
+ if ((ret < 0) && (tdb_error(ctx->wtdb->tdb) != TDB_ERR_NOEXIST)) {
+ tdb_chainunlock(ctx->wtdb->tdb, key);
+ return NULL;
+ }
+
+ if (state.result == NULL) {
+ db_tdb_fetchlock_parse(key, tdb_null, &state);
+ }
+
+ if (state.result == NULL) {
+ tdb_chainunlock(ctx->wtdb->tdb, key);
+ return NULL;
+ }
+
+ talloc_set_destructor(state.result, db_tdb_record_destr);
+
+ state.result->private_data = ctx;
+ state.result->storev = db_tdb_storev;
+ state.result->delete_rec = db_tdb_delete;
+
+ DBG_DEBUG("Allocated locked data %p\n", state.result);
+
+ return state.result;
+}
+
+static struct db_record *db_tdb_fetch_locked(
+ struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
+ struct db_tdb_ctx);
+
+ db_tdb_log_key("Locking", key);
+ if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
+ DEBUG(3, ("tdb_chainlock failed\n"));
+ return NULL;
+ }
+ return db_tdb_fetch_locked_internal(db, ctx, mem_ctx, key);
+}
+
+static NTSTATUS db_tdb_do_locked(struct db_context *db, TDB_DATA key,
+ void (*fn)(struct db_record *rec,
+ TDB_DATA value,
+ void *private_data),
+ void *private_data)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_tdb_ctx);
+ uint8_t *buf = NULL;
+ struct db_record rec;
+ int ret;
+
+ ret = tdb_chainlock(ctx->wtdb->tdb, key);
+ if (ret == -1) {
+ enum TDB_ERROR err = tdb_error(ctx->wtdb->tdb);
+ DBG_DEBUG("tdb_chainlock failed: %s\n",
+ tdb_errorstr(ctx->wtdb->tdb));
+ return map_nt_error_from_tdb(err);
+ }
+
+ ret = tdb_fetch_talloc(ctx->wtdb->tdb, key, ctx, &buf);
+
+ if ((ret != 0) && (ret != ENOENT)) {
+ DBG_DEBUG("tdb_fetch_talloc failed: %s\n",
+ strerror(errno));
+ tdb_chainunlock(ctx->wtdb->tdb, key);
+ return map_nt_error_from_unix_common(ret);
+ }
+
+ rec = (struct db_record) {
+ .db = db, .key = key,
+ .value_valid = false,
+ .storev = db_tdb_storev, .delete_rec = db_tdb_delete,
+ .private_data = ctx
+ };
+
+ fn(&rec,
+ (TDB_DATA) { .dptr = buf, .dsize = talloc_get_size(buf) },
+ private_data);
+
+ tdb_chainunlock(ctx->wtdb->tdb, key);
+
+ talloc_free(buf);
+
+ return NT_STATUS_OK;
+}
+
+static int db_tdb_exists(struct db_context *db, TDB_DATA key)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_tdb_ctx);
+ return tdb_exists(ctx->wtdb->tdb, key);
+}
+
+static int db_tdb_wipe(struct db_context *db)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_tdb_ctx);
+ return tdb_wipe_all(ctx->wtdb->tdb);
+}
+
+static int db_tdb_check(struct db_context *db)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_tdb_ctx);
+ return tdb_check(ctx->wtdb->tdb, NULL, NULL);
+}
+
+struct db_tdb_parse_state {
+ void (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data);
+ void *private_data;
+};
+
+/*
+ * tdb_parse_record expects a parser returning int, mixing up tdb and
+ * parser errors. Wrap around that by always returning 0 and have
+ * dbwrap_parse_record expect a parser returning void.
+ */
+
+static int db_tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ struct db_tdb_parse_state *state =
+ (struct db_tdb_parse_state *)private_data;
+ state->parser(key, data, state->private_data);
+ return 0;
+}
+
+static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
+ void (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(
+ db->private_data, struct db_tdb_ctx);
+ struct db_tdb_parse_state state;
+ int ret;
+
+ state.parser = parser;
+ state.private_data = private_data;
+
+ ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_parser, &state);
+
+ if (ret != 0) {
+ return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS db_tdb_storev(struct db_record *rec,
+ const TDB_DATA *dbufs, int num_dbufs, int flag)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
+ struct db_tdb_ctx);
+ struct tdb_context *tdb = ctx->wtdb->tdb;
+ NTSTATUS status = NT_STATUS_OK;
+ int ret;
+
+ /*
+ * This has a bug: We need to replace rec->value for correct
+ * operation, but right now brlock and locking don't use the value
+ * anymore after it was stored.
+ */
+
+ ret = tdb_storev(tdb, rec->key, dbufs, num_dbufs, flag);
+ if (ret == -1) {
+ enum TDB_ERROR err = tdb_error(tdb);
+ status = map_nt_error_from_tdb(err);
+ }
+ return status;
+}
+
+static NTSTATUS db_tdb_delete(struct db_record *rec)
+{
+ struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
+ struct db_tdb_ctx);
+
+ if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
+ return NT_STATUS_OK;
+ }
+
+ if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+struct db_tdb_traverse_ctx {
+ struct db_context *db;
+ int (*f)(struct db_record *rec, void *private_data);
+ void *private_data;
+};
+
+static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *private_data)
+{
+ struct db_tdb_traverse_ctx *ctx =
+ (struct db_tdb_traverse_ctx *)private_data;
+ struct db_record rec;
+
+ rec.key = kbuf;
+ rec.value = dbuf;
+ rec.value_valid = true;
+ rec.storev = db_tdb_storev;
+ rec.delete_rec = db_tdb_delete;
+ rec.private_data = ctx->db->private_data;
+ rec.db = ctx->db;
+
+ return ctx->f(&rec, ctx->private_data);
+}
+
+static int db_tdb_traverse(struct db_context *db,
+ int (*f)(struct db_record *rec, void *private_data),
+ void *private_data)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ struct db_tdb_traverse_ctx ctx;
+
+ ctx.db = db;
+ ctx.f = f;
+ ctx.private_data = private_data;
+ return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
+}
+
+static NTSTATUS db_tdb_storev_deny(struct db_record *rec,
+ const TDB_DATA *dbufs, int num_dbufs,
+ int flag)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
+static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
+{
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+}
+
+static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
+ void *private_data)
+{
+ struct db_tdb_traverse_ctx *ctx =
+ (struct db_tdb_traverse_ctx *)private_data;
+ struct db_record rec;
+
+ rec.key = kbuf;
+ rec.value = dbuf;
+ rec.value_valid = true;
+ rec.storev = db_tdb_storev_deny;
+ rec.delete_rec = db_tdb_delete_deny;
+ rec.private_data = ctx->db->private_data;
+ rec.db = ctx->db;
+
+ return ctx->f(&rec, ctx->private_data);
+}
+
+static int db_tdb_traverse_read(struct db_context *db,
+ int (*f)(struct db_record *rec, void *private_data),
+ void *private_data)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ struct db_tdb_traverse_ctx ctx;
+
+ ctx.db = db;
+ ctx.f = f;
+ ctx.private_data = private_data;
+ return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
+}
+
+static int db_tdb_get_seqnum(struct db_context *db)
+
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ return tdb_get_seqnum(db_ctx->wtdb->tdb);
+}
+
+static int db_tdb_transaction_start(struct db_context *db)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
+}
+
+static NTSTATUS db_tdb_transaction_start_nonblock(struct db_context *db)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ int ret;
+
+ ret = tdb_transaction_start_nonblock(db_ctx->wtdb->tdb);
+ if (ret != 0) {
+ return map_nt_error_from_tdb(tdb_error(db_ctx->wtdb->tdb));
+ }
+ return NT_STATUS_OK;
+}
+
+static int db_tdb_transaction_commit(struct db_context *db)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
+}
+
+static int db_tdb_transaction_cancel(struct db_context *db)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+ tdb_transaction_cancel(db_ctx->wtdb->tdb);
+ return 0;
+}
+
+static size_t db_tdb_id(struct db_context *db, uint8_t *id, size_t idlen)
+{
+ struct db_tdb_ctx *db_ctx =
+ talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
+
+ if (idlen >= sizeof(db_ctx->id)) {
+ memcpy(id, &db_ctx->id, sizeof(db_ctx->id));
+ }
+
+ return sizeof(db_ctx->id);
+}
+
+struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ enum dbwrap_lock_order lock_order,
+ uint64_t dbwrap_flags)
+{
+ struct db_context *result = NULL;
+ struct db_tdb_ctx *db_tdb;
+ struct stat st;
+
+ result = talloc_zero(mem_ctx, struct db_context);
+ if (result == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+
+ result->private_data = db_tdb = talloc(result, struct db_tdb_ctx);
+ if (db_tdb == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto fail;
+ }
+ result->lock_order = lock_order;
+
+ db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
+ open_flags, mode);
+ if (db_tdb->wtdb == NULL) {
+ DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
+ goto fail;
+ }
+
+ ZERO_STRUCT(db_tdb->id);
+
+ if (fstat(tdb_fd(db_tdb->wtdb->tdb), &st) == -1) {
+ DEBUG(3, ("fstat failed: %s\n", strerror(errno)));
+ goto fail;
+ }
+ db_tdb->id.dev = st.st_dev;
+ db_tdb->id.ino = st.st_ino;
+
+ result->fetch_locked = db_tdb_fetch_locked;
+ result->do_locked = db_tdb_do_locked;
+ result->traverse = db_tdb_traverse;
+ result->traverse_read = db_tdb_traverse_read;
+ result->parse_record = db_tdb_parse;
+ result->get_seqnum = db_tdb_get_seqnum;
+ result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
+ result->transaction_start = db_tdb_transaction_start;
+ result->transaction_start_nonblock = db_tdb_transaction_start_nonblock;
+ result->transaction_commit = db_tdb_transaction_commit;
+ result->transaction_cancel = db_tdb_transaction_cancel;
+ result->exists = db_tdb_exists;
+ result->wipe = db_tdb_wipe;
+ result->id = db_tdb_id;
+ result->check = db_tdb_check;
+ result->name = tdb_name(db_tdb->wtdb->tdb);
+ return result;
+
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
diff --git a/lib/dbwrap/dbwrap_tdb.h b/lib/dbwrap/dbwrap_tdb.h
new file mode 100644
index 0000000..d5f49c7
--- /dev/null
+++ b/lib/dbwrap/dbwrap_tdb.h
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/CIFS implementation.
+ Database interface wrapper around tdb
+ Copyright (C) Volker Lendecke 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __DBWRAP_TDB_H__
+#define __DBWRAP_TDB_H__
+
+#include <talloc.h>
+
+struct db_context;
+
+struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ enum dbwrap_lock_order lock_order,
+ uint64_t dbwrap_flags);
+
+
+#endif /* __DBWRAP_TDB_H__ */
diff --git a/lib/dbwrap/dbwrap_util.c b/lib/dbwrap/dbwrap_util.c
new file mode 100644
index 0000000..312fb41
--- /dev/null
+++ b/lib/dbwrap/dbwrap_util.c
@@ -0,0 +1,756 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for the dbwrap API
+ Copyright (C) Volker Lendecke 2007
+ Copyright (C) Michael Adam 2009
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
+
+ Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "dbwrap.h"
+#include "lib/util/util_tdb.h"
+
+struct dbwrap_fetch_int32_state {
+ NTSTATUS status;
+ int32_t result;
+};
+
+static void dbwrap_fetch_int32_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct dbwrap_fetch_int32_state *state =
+ (struct dbwrap_fetch_int32_state *)private_data;
+
+ if (data.dsize != sizeof(state->result)) {
+ state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ return;
+ }
+ state->result = IVAL(data.dptr, 0);
+ state->status = NT_STATUS_OK;
+}
+
+NTSTATUS dbwrap_fetch_int32(struct db_context *db, TDB_DATA key,
+ int32_t *result)
+{
+ struct dbwrap_fetch_int32_state state;
+ NTSTATUS status;
+
+ if (result == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ state.status = NT_STATUS_INTERNAL_ERROR;
+
+ status = dbwrap_parse_record(db, key, dbwrap_fetch_int32_parser, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (NT_STATUS_IS_OK(state.status)) {
+ *result = state.result;
+ }
+ return state.status;
+}
+
+NTSTATUS dbwrap_fetch_int32_bystring(struct db_context *db, const char *keystr,
+ int32_t *result)
+{
+ return dbwrap_fetch_int32(db, string_term_tdb_data(keystr), result);
+}
+
+NTSTATUS dbwrap_store_int32_bystring(struct db_context *db, const char *keystr,
+ int32_t v)
+{
+ uint8_t v_store[sizeof(int32_t)];
+ TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
+ NTSTATUS status;
+
+ SIVAL(v_store, 0, v);
+
+ status = dbwrap_store(db, string_term_tdb_data(keystr), data,
+ TDB_REPLACE);
+ return status;
+}
+
+struct dbwrap_fetch_uint32_state {
+ NTSTATUS status;
+ uint32_t result;
+};
+
+static void dbwrap_fetch_uint32_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct dbwrap_fetch_uint32_state *state =
+ (struct dbwrap_fetch_uint32_state *)private_data;
+
+ if (data.dsize != sizeof(state->result)) {
+ state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ return;
+ }
+ state->result = IVAL(data.dptr, 0);
+ state->status = NT_STATUS_OK;
+}
+
+NTSTATUS dbwrap_fetch_uint32_bystring(struct db_context *db,
+ const char *keystr, uint32_t *val)
+{
+ struct dbwrap_fetch_uint32_state state;
+ NTSTATUS status;
+
+ if (val == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ state.status = NT_STATUS_INTERNAL_ERROR;
+
+ status = dbwrap_parse_record(db, string_term_tdb_data(keystr),
+ dbwrap_fetch_uint32_parser, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (NT_STATUS_IS_OK(state.status)) {
+ *val = state.result;
+ }
+ return state.status;
+}
+
+NTSTATUS dbwrap_store_uint32_bystring(struct db_context *db,
+ const char *keystr, uint32_t v)
+{
+ uint8_t v_store[sizeof(uint32_t)];
+ TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
+ NTSTATUS status;
+
+ SIVAL(v_store, 0, v);
+
+ status = dbwrap_store(db, string_term_tdb_data(keystr), data,
+ TDB_REPLACE);
+ return status;
+}
+
+/**
+ * Atomic unsigned integer change (addition):
+ *
+ * if value does not exist yet in the db, use *oldval as initial old value.
+ * return old value in *oldval.
+ * store *oldval + change_val to db.
+ */
+
+struct dbwrap_change_uint32_atomic_context {
+ const char *keystr;
+ uint32_t *oldval;
+ uint32_t change_val;
+ NTSTATUS status;
+};
+
+static void dbwrap_change_uint32_atomic_action_fn(struct db_record *rec,
+ TDB_DATA value,
+ void *private_data)
+{
+ struct dbwrap_change_uint32_atomic_context *state = private_data;
+ uint8_t v_store[4];
+ TDB_DATA data = {
+ .dptr = v_store,
+ .dsize = sizeof(v_store),
+ };
+ uint32_t val = UINT32_MAX;
+
+ if (value.dptr == NULL) {
+ val = *(state->oldval);
+ } else if (value.dsize == sizeof(val)) {
+ val = PULL_LE_U32(value.dptr, 0);
+ *(state->oldval) = val;
+ } else {
+ state->status = NT_STATUS_UNSUCCESSFUL;
+ return;
+ }
+
+ val += state->change_val;
+ PUSH_LE_U32(v_store, 0, val);
+
+ state->status = dbwrap_record_store(rec, data, TDB_REPLACE);
+}
+
+static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
+ void *private_data)
+{
+ struct dbwrap_change_uint32_atomic_context *state = private_data;
+ NTSTATUS status;
+
+ status = dbwrap_do_locked(db,
+ string_term_tdb_data(state->keystr),
+ dbwrap_change_uint32_atomic_action_fn,
+ state);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("dbwrap_do_locked() failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(state->status)) {
+ DBG_DEBUG("dbwrap_change_uint32_atomic_action_fn() "
+ "failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dbwrap_change_uint32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ uint32_t *oldval,
+ uint32_t change_val)
+{
+ NTSTATUS ret;
+ struct dbwrap_change_uint32_atomic_context state;
+
+ state.keystr = keystr;
+ state.oldval = oldval;
+ state.change_val = change_val;
+
+ ret = dbwrap_change_uint32_atomic_action(db, &state);
+
+ return ret;
+}
+
+NTSTATUS dbwrap_trans_change_uint32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ uint32_t *oldval,
+ uint32_t change_val)
+{
+ NTSTATUS ret;
+ struct dbwrap_change_uint32_atomic_context state;
+
+ state.keystr = keystr;
+ state.oldval = oldval;
+ state.change_val = change_val;
+
+ ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
+
+ return ret;
+}
+
+/**
+ * Atomic integer change (addition):
+ *
+ * if value does not exist yet in the db, use *oldval as initial old value.
+ * return old value in *oldval.
+ * store *oldval + change_val to db.
+ */
+
+struct dbwrap_change_int32_atomic_context {
+ TDB_DATA key;
+ int32_t *oldval;
+ int32_t change_val;
+ NTSTATUS status;
+};
+
+static void dbwrap_change_int32_atomic_action_fn(struct db_record *rec,
+ TDB_DATA value,
+ void *private_data)
+{
+ struct dbwrap_change_int32_atomic_context *state = private_data;
+ uint8_t v_store[4];
+ TDB_DATA data = {
+ .dptr = v_store,
+ .dsize = sizeof(v_store),
+ };
+ int32_t val = -1;
+
+ if (value.dptr == NULL) {
+ val = *(state->oldval);
+ } else if (value.dsize == sizeof(val)) {
+ val = PULL_LE_U32(value.dptr, 0);
+ *(state->oldval) = val;
+ } else {
+ state->status = NT_STATUS_UNSUCCESSFUL;
+ return;
+ }
+
+ val += state->change_val;
+ PUSH_LE_U32(v_store, 0, val);
+
+ state->status = dbwrap_record_store(rec, data, TDB_REPLACE);
+}
+
+static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
+ void *private_data)
+{
+ struct dbwrap_change_int32_atomic_context *state = private_data;
+ NTSTATUS status;
+
+ status = dbwrap_do_locked(db,
+ state->key,
+ dbwrap_change_int32_atomic_action_fn,
+ state);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("dbwrap_do_locked() failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(state->status)) {
+ DBG_DEBUG("dbwrap_change_int32_atomic_action_fn() "
+ "failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dbwrap_change_int32_atomic(struct db_context *db,
+ TDB_DATA key,
+ int32_t *oldval,
+ int32_t change_val)
+{
+ NTSTATUS ret;
+ struct dbwrap_change_int32_atomic_context state;
+
+ state.key = key;
+ state.oldval = oldval;
+ state.change_val = change_val;
+
+ ret = dbwrap_change_int32_atomic_action(db, &state);
+
+ return ret;
+}
+
+NTSTATUS dbwrap_change_int32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ int32_t *oldval,
+ int32_t change_val)
+{
+ return dbwrap_change_int32_atomic(db, string_term_tdb_data(keystr),
+ oldval, change_val);
+}
+
+NTSTATUS dbwrap_trans_change_int32_atomic_bystring(struct db_context *db,
+ const char *keystr,
+ int32_t *oldval,
+ int32_t change_val)
+{
+ NTSTATUS ret;
+ struct dbwrap_change_int32_atomic_context state;
+
+ state.key = string_term_tdb_data(keystr);
+ state.oldval = oldval;
+ state.change_val = change_val;
+
+ ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
+
+ return ret;
+}
+
+struct dbwrap_store_context {
+ TDB_DATA *key;
+ TDB_DATA *dbuf;
+ int flag;
+};
+
+static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
+{
+ NTSTATUS status;
+ struct dbwrap_store_context *store_ctx;
+
+ store_ctx = (struct dbwrap_store_context *)private_data;
+
+ status = dbwrap_store(db, *(store_ctx->key), *(store_ctx->dbuf),
+ store_ctx->flag);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("store returned %s\n", nt_errstr(status)));
+ }
+
+ return status;
+}
+
+NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
+ int flag)
+{
+ NTSTATUS status;
+ struct dbwrap_store_context store_ctx;
+
+ store_ctx.key = &key;
+ store_ctx.dbuf = &dbuf;
+ store_ctx.flag = flag;
+
+ status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
+
+ return status;
+}
+
+static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
+{
+ NTSTATUS status;
+ TDB_DATA *key = (TDB_DATA *)private_data;
+
+ status = dbwrap_delete(db, *key);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_INFO("dbwrap_record_delete returned %s\n",
+ nt_errstr(status));
+ }
+ return status;
+}
+
+NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
+{
+ NTSTATUS status;
+
+ status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
+
+ return status;
+}
+
+NTSTATUS dbwrap_trans_store_int32_bystring(struct db_context *db,
+ const char *keystr,
+ int32_t v)
+{
+ int32_t v_store;
+
+ SIVAL(&v_store, 0, v);
+
+ return dbwrap_trans_store(db, string_term_tdb_data(keystr),
+ make_tdb_data((const uint8_t *)&v_store,
+ sizeof(v_store)),
+ TDB_REPLACE);
+}
+
+NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
+ const char *keystr,
+ uint32_t v)
+{
+ uint32_t v_store;
+
+ SIVAL(&v_store, 0, v);
+
+ return dbwrap_trans_store(db, string_term_tdb_data(keystr),
+ make_tdb_data((const uint8_t *)&v_store,
+ sizeof(v_store)),
+ TDB_REPLACE);
+}
+
+NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags)
+{
+ return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
+}
+
+NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
+{
+ return dbwrap_trans_delete(db, string_term_tdb_data(key));
+}
+
+/**
+ * Wrap db action(s) into a transaction.
+ */
+NTSTATUS dbwrap_trans_do(struct db_context *db,
+ NTSTATUS (*action)(struct db_context *, void *),
+ void *private_data)
+{
+ int res;
+ NTSTATUS status;
+
+ res = dbwrap_transaction_start(db);
+ if (res != 0) {
+ DEBUG(5, ("transaction_start failed\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ status = action(db, private_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (dbwrap_transaction_cancel(db) != 0) {
+ smb_panic("Cancelling transaction failed");
+ }
+ return status;
+ }
+
+ res = dbwrap_transaction_commit(db);
+ if (res == 0) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(2, ("transaction_commit failed\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+}
+
+struct dbwrap_trans_traverse_action_ctx {
+ int (*f)(struct db_record* rec, void* private_data);
+ void* private_data;
+};
+
+
+static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
+{
+ struct dbwrap_trans_traverse_action_ctx* ctx =
+ (struct dbwrap_trans_traverse_action_ctx*)private_data;
+
+ NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
+
+ return status;
+}
+
+NTSTATUS dbwrap_trans_traverse(struct db_context *db,
+ int (*f)(struct db_record*, void*),
+ void *private_data)
+{
+ struct dbwrap_trans_traverse_action_ctx ctx = {
+ .f = f,
+ .private_data = private_data,
+ };
+ return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
+}
+
+NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key)
+{
+ NTSTATUS status;
+
+ status = dbwrap_delete(db, key);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ status = NT_STATUS_OK;
+ }
+
+ return status;
+}
+
+NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key)
+{
+ return dbwrap_purge(db, string_term_tdb_data(key));
+}
+
+NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
+{
+ return dbwrap_delete(db, string_term_tdb_data(key));
+}
+
+NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
+ TDB_DATA data, int flags)
+{
+ return dbwrap_store(db, string_term_tdb_data(key), data, flags);
+}
+
+NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
+ const char *key, TDB_DATA *value)
+{
+ return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
+}
+
+
+
+NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
+{
+ char *key_upper;
+ NTSTATUS status;
+
+ key_upper = talloc_strdup_upper(talloc_tos(), key);
+ if (key_upper == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dbwrap_delete_bystring(db, key_upper);
+
+ talloc_free(key_upper);
+ return status;
+}
+
+NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
+ TDB_DATA data, int flags)
+{
+ char *key_upper;
+ NTSTATUS status;
+
+ key_upper = talloc_strdup_upper(talloc_tos(), key);
+ if (key_upper == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dbwrap_store_bystring(db, key_upper, data, flags);
+
+ talloc_free(key_upper);
+ return status;
+}
+
+NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
+ const char *key, TDB_DATA *value)
+{
+ char *key_upper;
+ NTSTATUS status;
+
+ key_upper = talloc_strdup_upper(talloc_tos(), key);
+ if (key_upper == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dbwrap_fetch_bystring(db, mem_ctx, key_upper, value);
+
+ talloc_free(key_upper);
+ return status;
+}
+
+struct dbwrap_marshall_state {
+ uint8_t *buf;
+ size_t bufsize;
+ size_t dbsize;
+};
+
+static int dbwrap_marshall_fn(struct db_record *rec, void *private_data)
+{
+ struct dbwrap_marshall_state *state = private_data;
+ TDB_DATA key, value;
+ size_t new_dbsize;
+
+ key = dbwrap_record_get_key(rec);
+ value = dbwrap_record_get_value(rec);
+
+ new_dbsize = state->dbsize;
+ new_dbsize += 8 + key.dsize;
+ new_dbsize += 8 + value.dsize;
+
+ if (new_dbsize <= state->bufsize) {
+ uint8_t *p = state->buf + state->dbsize;
+
+ SBVAL(p, 0, key.dsize);
+ p += 8;
+ memcpy(p, key.dptr, key.dsize);
+ p += key.dsize;
+
+ SBVAL(p, 0, value.dsize);
+ p += 8;
+ memcpy(p, value.dptr, value.dsize);
+ }
+ state->dbsize = new_dbsize;
+ return 0;
+}
+
+size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize)
+{
+ struct dbwrap_marshall_state state;
+
+ state.bufsize = bufsize;
+ state.buf = buf;
+ state.dbsize = 0;
+
+ dbwrap_traverse_read(db, dbwrap_marshall_fn, &state, NULL);
+
+ return state.dbsize;
+}
+
+static ssize_t dbwrap_unmarshall_get_data(const uint8_t *buf, size_t buflen,
+ size_t ofs, TDB_DATA *pdata)
+{
+ uint64_t space, len;
+ const uint8_t *p;
+
+ if (ofs == buflen) {
+ return 0;
+ }
+ if (ofs > buflen) {
+ return -1;
+ }
+
+ space = buflen - ofs;
+ if (space < 8) {
+ return -1;
+ }
+
+ p = buf + ofs;
+ len = BVAL(p, 0);
+
+ p += 8;
+ space -= 8;
+
+ if (len > space) {
+ return -1;
+ }
+
+ *pdata = (TDB_DATA) { .dptr = discard_const_p(uint8_t, p),
+ .dsize = len };
+ return len + 8;
+}
+
+NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
+ bool (*fn)(TDB_DATA key, TDB_DATA value,
+ void *private_data),
+ void *private_data)
+{
+ size_t ofs = 0;
+
+ while (true) {
+ ssize_t len;
+ TDB_DATA key, value;
+ bool ok;
+
+ len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &key);
+ if (len == 0) {
+ break;
+ }
+ if (len == -1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ofs += len;
+
+ len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &value);
+ if (len == 0) {
+ break;
+ }
+ if (len == -1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ofs += len;
+
+ ok = fn(key, value, private_data);
+ if (!ok) {
+ break;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct dbwrap_unmarshall_state {
+ struct db_context *db;
+ NTSTATUS ret;
+};
+
+static bool dbwrap_unmarshall_fn(TDB_DATA key, TDB_DATA value,
+ void *private_data)
+{
+ struct dbwrap_unmarshall_state *state = private_data;
+ NTSTATUS status;
+
+ status = dbwrap_store(state->db, key, value, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("dbwrap_record_store failed: %s\n",
+ nt_errstr(status));
+ state->ret = status;
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
+ size_t buflen)
+{
+ struct dbwrap_unmarshall_state state = { .db = db };
+ NTSTATUS status;
+
+ status = dbwrap_parse_marshall_buf(buf, buflen,
+ dbwrap_unmarshall_fn, &state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return state.ret;
+}
diff --git a/lib/dbwrap/wscript_build b/lib/dbwrap/wscript_build
new file mode 100644
index 0000000..0e5f961
--- /dev/null
+++ b/lib/dbwrap/wscript_build
@@ -0,0 +1,8 @@
+SRC = '''dbwrap.c dbwrap_util.c dbwrap_rbt.c dbwrap_tdb.c
+ dbwrap_local_open.c'''
+DEPS= '''samba-util util_tdb samba-errors tdb tdb-wrap tevent tevent-util'''
+
+bld.SAMBA_LIBRARY('dbwrap',
+ source=SRC,
+ deps=DEPS,
+ private_library=True)
diff --git a/lib/fuzzing/README.md b/lib/fuzzing/README.md
new file mode 100644
index 0000000..d3e34bd
--- /dev/null
+++ b/lib/fuzzing/README.md
@@ -0,0 +1,87 @@
+# Fuzzing Samba
+
+See also https://wiki.samba.org/index.php/Fuzzing
+
+Fuzzing supplies valid, invalid, unexpected or random data as input to a piece
+of code. Instrumentation, usually compiler-implemented, is used to monitor for
+exceptions such as crashes, assertions or memory corruption.
+
+See [Wikipedia article on fuzzing](https://en.wikipedia.org/wiki/Fuzzing) for
+more information.
+
+# Honggfuzz
+
+## Configure with fuzzing
+
+Example command line to build binaries for use with
+[honggfuzz](https://github.com/google/honggfuzz/):
+
+```sh
+./configure -C --without-gettext --enable-debug --enable-developer \
+ --address-sanitizer --enable-libfuzzer --abi-check-disable \
+ CC=.../honggfuzz/hfuzz_cc/hfuzz-clang \
+ LINK_CC=.../honggfuzz/hfuzz_cc/hfuzz-clang
+```
+
+
+## Fuzzing tiniparser
+
+Example for fuzzing `tiniparser` using `honggfuzz` (see `--help` for more
+options):
+
+```sh
+make bin/fuzz_tiniparser && \
+.../honggfuzz/honggfuzz --sanitizers --timeout 3 --max_file_size 256 \
+ --rlimit_rss 100 -f .../tiniparser-corpus -- bin/fuzz_tiniparser
+```
+
+# AFL (american fuzzy lop)
+
+## Configure with fuzzing
+
+Example command line to build binaries for use with
+[afl](http://lcamtuf.coredump.cx/afl/)
+
+```sh
+./configure -C --without-gettext --enable-debug --enable-developer \
+ --enable-afl-fuzzer --abi-check-disable \
+ CC=afl-gcc
+```
+
+## Fuzzing tiniparser
+
+Example for fuzzing `tiniparser` using `afl-fuzz` (see `--help` for more
+options):
+
+```sh
+make bin/fuzz_tiniparser build && \
+afl-fuzz -m 200 -i inputdir -o outputdir -- bin/fuzz_tiniparser
+```
+
+# oss-fuzz
+
+Samba can be fuzzed by Google's oss-fuzz system. Assuming you have an
+oss-fuzz checkout from https://github.com/google/oss-fuzz with Samba's
+metadata in projects/samba, the following guides will help:
+
+## Testing locally
+
+https://google.github.io/oss-fuzz/getting-started/new-project-guide/#testing-locally
+
+## Debugging oss-fuzz
+
+See https://google.github.io/oss-fuzz/advanced-topics/debugging/
+
+## Samba-specific hints
+
+A typical debugging workflow is:
+
+oss-fuzz$ python infra/helper.py shell samba
+git fetch $REMOTE $BRANCH
+git checkout FETCH_HEAD
+lib/fuzzing/oss-fuzz/build_image.sh
+compile
+
+This will pull in any new Samba deps and build Samba's fuzzers.
+
+# vim: set sw=8 sts=8 ts=8 tw=79 :
diff --git a/lib/fuzzing/afl-fuzz-main.c b/lib/fuzzing/afl-fuzz-main.c
new file mode 100644
index 0000000..e0a1d26
--- /dev/null
+++ b/lib/fuzzing/afl-fuzz-main.c
@@ -0,0 +1,66 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Fuzz driver (AFL style)
+
+ Copyright (C) Andrew Bartlett 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/samba_util.h"
+#include "fuzzing.h"
+
+int main(int argc, char *argv[]) {
+ int ret;
+ size_t size = 0;
+ int i;
+
+ ret = LLVMFuzzerInitialize(&argc, &argv);
+ if (ret != 0) {
+ printf("LLVMFuzzerInitialize returned %d\n", ret);
+ return ret;
+ }
+
+
+#ifdef __AFL_LOOP
+ while (__AFL_LOOP(1000))
+#else
+ for (i = 1; i < argc; i++) {
+ uint8_t *buf = (uint8_t *)file_load(argv[i],
+ &size,
+ 0,
+ NULL);
+ ret = LLVMFuzzerTestOneInput(buf, size);
+ TALLOC_FREE(buf);
+ if (ret != 0) {
+ printf("LLVMFuzzerTestOneInput returned %d on argument %d\n",
+ ret, i);
+ return ret;
+ }
+ }
+ if (i == 1)
+#endif
+ {
+ uint8_t *buf = (uint8_t *)fd_load(0, &size, 0, NULL);
+ if (buf == NULL) {
+ exit(1);
+ }
+
+ ret = LLVMFuzzerTestOneInput(buf, size);
+ TALLOC_FREE(buf);
+ }
+ return ret;
+}
diff --git a/lib/fuzzing/decode_ndr_X_crash b/lib/fuzzing/decode_ndr_X_crash
new file mode 100755
index 0000000..63c3cd7
--- /dev/null
+++ b/lib/fuzzing/decode_ndr_X_crash
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+#
+# Interpret a file that crashes an fuzz_ndr_X binary.
+#
+# Copyright (C) Catalyst IT Ltd. 2019
+
+
+import sys
+import os
+from base64 import b64encode
+import struct
+import argparse
+import re
+
+TYPE_MASK = 3
+TYPES = ['struct', 'in', 'out']
+
+FLAGS = [
+ (4, 'ndr64', '--ndr64'),
+]
+
+
+def print_if_verbose(*args, **kwargs):
+ if verbose:
+ print(*args, **kwargs)
+
+
+def process_one_file(f):
+ print_if_verbose(f.name)
+ print_if_verbose('-' * len(f.name))
+
+ b = f.read()
+ flags, function = struct.unpack('<HH', b[:4])
+ if opnum is not None and opnum != function:
+ return
+
+ t = TYPES[flags & TYPE_MASK]
+ if ndr_type and ndr_type != t:
+ return
+
+ payload = b[4:]
+ data64 = b64encode(payload).decode('utf-8')
+
+ cmd = ['bin/ndrdump',
+ pipe,
+ str(function),
+ t,
+ '--base64-input',
+ '--input', data64,
+ ]
+
+ for flag, name, option in FLAGS:
+ if flags & flag:
+ print_if_verbose("flag: %s" % name)
+ cmd.append(option)
+
+ print_if_verbose("length: %d\n" % len(payload))
+ print(' '.join(cmd))
+ print_if_verbose()
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-p', '--pipe', default='$PIPE',
+ help='pipe name (for output command line)')
+ parser.add_argument('-t', '--type', default=None, choices=TYPES,
+ help='restrict to this type')
+ parser.add_argument('-o', '--opnum', default=None, type=int,
+ help='restrict to this function/struct number')
+ parser.add_argument('FILES', nargs='*', default=(),
+ help="read from these files")
+ parser.add_argument('-k', '--ignore-errors', action='store_true',
+ help='do not stop on errors')
+ parser.add_argument('-v', '--verbose', action='store_true',
+ help='say more')
+ parser.add_argument('-H', '--honggfuzz-file',
+ help="extract crashes from this honggfuzz report")
+ parser.add_argument('-f', '--crash-filter',
+ help="only print crashes matching this rexexp")
+
+ args = parser.parse_args()
+
+ global pipe, opnum, ndr_type, verbose
+ pipe = args.pipe
+ opnum = args.opnum
+ ndr_type = args.type
+ verbose = args.verbose
+
+ if not args.FILES and not args.honggfuzz_file:
+ parser.print_usage()
+ sys.exit(1)
+
+ for fn in args.FILES:
+ if args.crash_filter is not None:
+ if not re.search(args.crash_filter, fn):
+ print_if_verbose(f"skipping {fn}")
+ continue
+ try:
+ if fn == '-':
+ process_one_file(sys.stdin)
+ else:
+ with open(fn, 'rb') as f:
+ process_one_file(f)
+ except Exception:
+ print_if_verbose("Error processing %s\n" % fn)
+ if args.ignore_errors:
+ continue
+ raise
+
+ if args.honggfuzz_file:
+ print_if_verbose(f"looking at {args.honggfuzz_file}")
+ with open(args.honggfuzz_file) as f:
+ pipe = None
+ crash = None
+ for line in f:
+ m = re.match(r'^\s*fuzzTarget\s*:\s*bin/fuzz_ndr_(\w+)\s*$', line)
+ if m:
+ pipe = m.group(1).split('_TYPE_', 1)[0]
+ print_if_verbose(f"found pipe {pipe}")
+ m = re.match(r'^FUZZ_FNAME: (\S+)$', line)
+ if m:
+ crash = m.group(1)
+ if args.crash_filter is not None:
+ if not re.search(args.crash_filter, crash):
+ print_if_verbose(f"skipping {crash}")
+ pipe = None
+ crash = None
+ continue
+ print_if_verbose(f"found crash {crash}")
+ if pipe is not None and crash is not None:
+ with open(crash, 'rb') as f:
+ process_one_file(f)
+ pipe = None
+ crash = None
+
+
+main()
diff --git a/lib/fuzzing/fuzz_cli_credentials_parse_string.c b/lib/fuzzing/fuzz_cli_credentials_parse_string.c
new file mode 100644
index 0000000..0b0f97a
--- /dev/null
+++ b/lib/fuzzing/fuzz_cli_credentials_parse_string.c
@@ -0,0 +1,63 @@
+/*
+ Fuzz cli_credentials_parse_string
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "auth/credentials/credentials.h"
+#include "fuzzing/fuzzing.h"
+
+#define MAX_LENGTH (1024 * 10)
+char buf[MAX_LENGTH + 1];
+
+const enum credentials_obtained obtained = CRED_UNINITIALISED;
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_credentials *credentials = NULL;
+ bool anon;
+ const char *username;
+ const char *domain;
+
+ if (len > MAX_LENGTH) {
+ return 0;
+ }
+
+ memcpy(buf, input, len);
+ buf[len] = '\0';
+
+ mem_ctx = talloc_new(NULL);
+ credentials = cli_credentials_init(mem_ctx);
+
+ cli_credentials_parse_string(credentials, buf, obtained);
+
+ anon = cli_credentials_is_anonymous(credentials);
+
+ cli_credentials_get_ntlm_username_domain(credentials,
+ mem_ctx,
+ &username,
+ &domain);
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_conditional_ace_blob.c b/lib/fuzzing/fuzz_conditional_ace_blob.c
new file mode 100644
index 0000000..ebbd908
--- /dev/null
+++ b/lib/fuzzing/fuzz_conditional_ace_blob.c
@@ -0,0 +1,156 @@
+/*
+ Fuzz conditional ace decoding and encoding
+ Copyright (C) Catalyst IT 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "libcli/security/security.h"
+#include "lib/util/attr.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "fuzzing/fuzzing.h"
+
+
+#define MAX_LENGTH (1024 * 1024 - 1)
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ok;
+ struct ace_condition_script *s1 = NULL;
+ struct ace_condition_script *s2 = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ const char *sddl = NULL;
+ DATA_BLOB e1, e2;
+ size_t length;
+
+ if (len > MAX_LENGTH) {
+ return 0;
+ }
+
+ /*
+ * In this one we are treating the input data as an ACE blob,
+ * and decoding it into the structure and thence SDDL.
+ *
+ * This doesn't run the conditional ACE, for which we would
+ * need a security token.
+ */
+
+ e1.data = input;
+ e1.length = len;
+
+ mem_ctx = talloc_new(NULL);
+
+ s1 = parse_conditional_ace(mem_ctx, e1);
+ if (s1 == NULL) {
+ /* no worries, it was nonsense */
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ /* back to blob form */
+ ok = conditional_ace_encode_binary(mem_ctx, s1, &e2);
+ if (! ok) {
+ if (e1.length == CONDITIONAL_ACE_MAX_LENGTH) {
+ /*
+ * This is an edge case where the encoder and
+ * decoder treat the boundary slightly
+ * differently, and the encoder refuses to
+ * encode to the maximum length. This is not
+ * an issue in the real world.
+ */
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+ abort();
+ }
+
+ if (data_blob_cmp(&e1, &e2) != 0) {
+ abort();
+ }
+
+ sddl = sddl_from_conditional_ace(mem_ctx, s1);
+ if (sddl == NULL) {
+ /*
+ * we can't call this a failure, because the blob
+ * could easily have nonsensical programs that the
+ * SDDL decompiler is unwilling to countenance. For
+ * example, it could have an operator that requires
+ * arguments as the first token, when of course the
+ * arguments need to come first.
+ */
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ s2 = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl,
+ &message,
+ &message_offset,
+ &length);
+ if (s2 == NULL) {
+ /*
+ * We also don't complain when the SDDL decompiler
+ * produces an uncompilable program, because the
+ * decompiler is meant to be a display tool, not a
+ * verifier in itself.
+ */
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s2, &e2);
+ if (! ok) {
+ abort();
+ }
+
+ /*
+ * It would be nice here to go:
+ *
+ * if (data_blob_cmp(&e1, &e2) != 0) {
+ * abort();
+ * }
+ *
+ * but that isn't really fair. The decompilation into SDDL
+ * does not make thorough sanity checks because that is not
+ * its job -- it is just trying to depict what is there -- and
+ * there are many ambiguous decompilations.
+ *
+ * For example, a blob with a single literal integer token,
+ * say 42, can only really be shown in the SDDL syntax as
+ * "(42)", but when the compiler reads that it knows that a
+ * literal number is invalid except in a RHS argument, so it
+ * assumes "42" is a local attribute name.
+ *
+ * Even if the decompiler was a perfect verifier, a round trip
+ * through SDDL could not be guaranteed because, for example,
+ * an 8 bit integer can only be displayed in SDDL in the form
+ * that compiles to a 64 bit integer.
+ */
+
+ TALLOC_FREE(mem_ctx);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_dcerpc_parse_binding.c b/lib/fuzzing/fuzz_dcerpc_parse_binding.c
new file mode 100644
index 0000000..dcbf440
--- /dev/null
+++ b/lib/fuzzing/fuzz_dcerpc_parse_binding.c
@@ -0,0 +1,76 @@
+/*
+ Fuzz dcerpc_parse_binding
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#include "librpc/rpc/dcerpc.h"
+#include "fuzzing/fuzzing.h"
+
+#define MAX_LENGTH (1024 * 10)
+char buf[MAX_LENGTH + 1];
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct dcerpc_binding *binding = NULL;
+ struct dcerpc_binding *dup = NULL;
+ struct epm_tower tower;
+ NTSTATUS status;
+ struct GUID guid;
+
+ if (len > MAX_LENGTH) {
+ return 0;
+ }
+
+ memcpy(buf, input, len);
+ buf[len] = '\0';
+
+ mem_ctx = talloc_new(NULL);
+ status = dcerpc_parse_binding(mem_ctx, buf, &binding);
+
+ if (! NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ /* If the string parses, we try manipulating it a bit */
+
+ dcerpc_binding_string(mem_ctx, binding);
+ dcerpc_binding_get_abstract_syntax(binding);
+ dup = dcerpc_binding_dup(mem_ctx, binding);
+
+ status = dcerpc_binding_build_tower(mem_ctx,
+ binding,
+ &tower);
+ if (NT_STATUS_IS_OK(status)) {
+ status = dcerpc_binding_from_tower(mem_ctx,
+ &tower,
+ &dup);
+ }
+
+ guid = dcerpc_binding_get_object(binding);
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldap_decode.c b/lib/fuzzing/fuzz_ldap_decode.c
new file mode 100644
index 0000000..be286ea
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldap_decode.c
@@ -0,0 +1,66 @@
+/*
+ Fuzzing for ldap_decode.
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "lib/util/asn1.h"
+#include "libcli/ldap/ldap_message.h"
+#include "libcli/ldap/ldap_proto.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ struct ldap_request_limits limits = {
+ /*
+ * The default size is currently 256000 bytes
+ */
+ .max_search_size = 256000
+ };
+ NTSTATUS status;
+
+ /*
+ * Need to limit the max parse tree depth to 250 to prevent
+ * ASAN detecting stack overflows.
+ */
+ asn1 = asn1_init(mem_ctx, 250);
+ if (!asn1) {
+ goto out;
+ }
+
+ asn1_load_nocopy(asn1, buf, len);
+
+ ldap_msg = talloc(mem_ctx, struct ldap_message);
+ if (!ldap_msg) {
+ goto out;
+ }
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+
+out:
+ talloc_free(mem_ctx);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_comparison_fold.c b/lib/fuzzing/fuzz_ldb_comparison_fold.c
new file mode 100644
index 0000000..08b2f59
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_comparison_fold.c
@@ -0,0 +1,58 @@
+/*
+ Fuzzing ldb_comparison_fold()
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_handlers.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ struct ldb_val v1, v2;
+ struct ldb_context *ldb = NULL;
+
+ if (len < 2) {
+ return 0;
+ }
+
+ v1.length = PULL_LE_U16(input, 0);
+ if (v1.length > len - 2) {
+ /* the exact case of v2.length == 0 is still available */
+ return 0;
+ }
+ len -= 2;
+ input += 2;
+
+ ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ return 0;
+ }
+
+ v1.data = talloc_memdup(ldb, input, v1.length);
+ v2.length = len - v1.length;
+ v2.data = talloc_memdup(ldb, input + v1.length, v2.length);
+
+ ldb_comparison_fold(ldb, ldb, &v1, &v2);
+ talloc_free(ldb);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_dn_explode.c b/lib/fuzzing/fuzz_ldb_dn_explode.c
new file mode 100644
index 0000000..0e1560e
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_dn_explode.c
@@ -0,0 +1,53 @@
+/*
+ Fuzzing ldb_dn_explode
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "ldb.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ struct ldb_dn *dn = NULL;
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ return 0;
+ }
+ /*
+ * We copy the buffer in order to NUL-terminate, because running off
+ * the end of the string would be an uninteresting crash.
+ */
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+
+ dn = ldb_dn_new(ldb, ldb, buf);
+ ldb_dn_validate(dn);
+ TALLOC_FREE(ldb);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_ldif_read.c b/lib/fuzzing/fuzz_ldb_ldif_read.c
new file mode 100644
index 0000000..3c48b6a
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_ldif_read.c
@@ -0,0 +1,56 @@
+/*
+ Fuzzing ldb_ldif_read_string
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "ldb_private.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ struct ldb_ldif *ldif = NULL;
+ const char *s = NULL;
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ return 0;
+ }
+
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+ s = buf;
+
+ ldif = ldb_ldif_read_string(ldb, &s);
+
+ if(ldif != NULL) {
+ ldb_ldif_write_string(ldb, ldb, ldif);
+ ldb_ldif_write_redacted_trace_string(ldb, ldb, ldif);
+ }
+ TALLOC_FREE(ldb);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_parse_binary_decode.c b/lib/fuzzing/fuzz_ldb_parse_binary_decode.c
new file mode 100644
index 0000000..ac2e436
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_parse_binary_decode.c
@@ -0,0 +1,55 @@
+/*
+ Fuzzing ldb_binary_decode and ldb_binary_encode_string
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "ldb_private.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+static char * possibly_truncate(uint8_t *input, size_t len)
+{
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+ return buf;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
+ struct ldb_val val = {0};
+ const char *s = possibly_truncate(input, len);
+
+ /* we treat the same string to encoding and decoding, not
+ * round-tripping. */
+ val = ldb_binary_decode(mem_ctx, s);
+ ldb_binary_encode_string(mem_ctx, s);
+ TALLOC_FREE(mem_ctx);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_parse_control.c b/lib/fuzzing/fuzz_ldb_parse_control.c
new file mode 100644
index 0000000..722d9f9
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_parse_control.c
@@ -0,0 +1,55 @@
+/*
+ Fuzzing ldb_parse_control_from_string
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "ldb_private.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ struct ldb_control *control = NULL;
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ return 0;
+ }
+ /*
+ * We copy the buffer in order to NUL-terminate, because running off
+ * the end of the string would be an uninteresting crash.
+ */
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+
+ control = ldb_parse_control_from_string(ldb, ldb, buf);
+ if (control != NULL) {
+ ldb_control_to_string(ldb, control);
+ }
+ TALLOC_FREE(ldb);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_parse_tree.c b/lib/fuzzing/fuzz_ldb_parse_tree.c
new file mode 100644
index 0000000..1e64940
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_parse_tree.c
@@ -0,0 +1,53 @@
+/*
+ Fuzzing for ldb_parse_tree
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "ldb.h"
+#include "ldb_module.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
+ struct ldb_parse_tree *tree;
+ char *filter;
+
+ if (len < 1) {
+ goto out;
+ }
+
+ filter = talloc_strndup(mem_ctx, (const char*)buf, len);
+
+ if (filter == NULL) {
+ goto out;
+ }
+
+ tree = ldb_parse_tree(mem_ctx, filter);
+
+ (void)ldb_filter_from_tree(mem_ctx, tree);
+
+out:
+ talloc_free(mem_ctx);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress.c b/lib/fuzzing/fuzz_lzxpress.c
new file mode 100644
index 0000000..ddc7aa0
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress.c
@@ -0,0 +1,35 @@
+/*
+ Fuzzing for lzxpress_decompress
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "lzxpress.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ static uint8_t output[1024 * 1024] = {0};
+
+ lzxpress_decompress(buf, len, output, sizeof(output));
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress_compress.c b/lib/fuzzing/fuzz_lzxpress_compress.c
new file mode 100644
index 0000000..9e5c647
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress_compress.c
@@ -0,0 +1,35 @@
+/*
+ Fuzzing for lzxpress_decompress
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "lzxpress.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ static uint8_t output[1024 * 1024] = {0};
+
+ lzxpress_compress(buf, len, output, sizeof(output));
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress_huffman_compress.c b/lib/fuzzing/fuzz_lzxpress_huffman_compress.c
new file mode 100644
index 0000000..165244c
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress_huffman_compress.c
@@ -0,0 +1,58 @@
+/*
+ Fuzzing for lzxpress_huffman_compress_talloc
+ Copyright (C) Michael Hanselmann 2019
+ Copyright (C) Douglas Bagnall 2022 <dbagnall@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "compression/lzxpress_huffman.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+#define MAX_SIZE (1024 * 1024)
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ static uint8_t *output;
+ size_t output_len;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct lzxhuff_compressor_mem cmp_mem;
+
+ /*
+ * The round-trip fuzzer checks the compressor with an unconstrained
+ * output buffer; here we see what happens if the buffer is possibly too
+ * small.
+ */
+ if (len < 3) {
+ return 0;
+ }
+ output_len = MIN(MAX_SIZE, buf[0] | (buf[1] << 8) | (buf[2] << 16));
+ buf += 3;
+ len -= 3;
+ mem_ctx = talloc_new(NULL);
+
+ output = talloc_array(mem_ctx, uint8_t, output_len);
+
+ lzxpress_huffman_compress(&cmp_mem, buf, len, output, output_len);
+
+ talloc_free(mem_ctx);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress_huffman_decompress.c b/lib/fuzzing/fuzz_lzxpress_huffman_decompress.c
new file mode 100644
index 0000000..d475ff6
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress_huffman_decompress.c
@@ -0,0 +1,48 @@
+/*
+ Fuzzing for lzxpress_decompress
+ Copyright (C) Michael Hanselmann 2019
+ Copyright (C) Douglas Bagnall 2022 <dbagnall@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "compression/lzxpress_huffman.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+static uint8_t output[1024 * 1024] = {0};
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ size_t target_len;
+ if (len < 4) {
+ return 0;
+ }
+ /*
+ * An exact target length is required, which we store in the first 24
+ * bits.
+ */
+ target_len = MIN(sizeof(output), buf[0] | (buf[1] << 8) | (buf[2] << 16));
+ buf += 3;
+ len -= 3;
+
+ lzxpress_huffman_decompress(buf, len, output, target_len);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress_huffman_round_trip.c b/lib/fuzzing/fuzz_lzxpress_huffman_round_trip.c
new file mode 100644
index 0000000..adb8fbf
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress_huffman_round_trip.c
@@ -0,0 +1,68 @@
+/*
+ Fuzzing for lzxpress_huffman{_decompress,_compress} round trip
+ Copyright (C) Michael Hanselmann 2019
+ Copyright (C) Douglas Bagnall 2022 <dbagnall@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "compression/lzxpress_huffman.h"
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ /*
+ * we allow compressed to be 25% bigger than decompressed.
+ */
+ static uint8_t compressed[1024 * (1024 + 256)];
+ static uint8_t decompressed[1024 * 1024];
+ ssize_t compressed_size;
+ ssize_t decompressed_size;
+ struct lzxhuff_compressor_mem cmp;
+
+ if (len > sizeof(decompressed) || len == 0) {
+ return 0;
+ }
+
+ compressed_size = lzxpress_huffman_compress(&cmp,
+ buf,
+ len,
+ compressed,
+ sizeof(compressed));
+ if (compressed_size < 0) {
+ abort();
+ }
+
+ decompressed_size = lzxpress_huffman_decompress(compressed,
+ compressed_size,
+ decompressed,
+ len);
+
+ if (decompressed_size != len) {
+ abort();
+ }
+ if (memcmp(buf, decompressed, len) != 0) {
+ abort();
+ }
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress_round_trip.c b/lib/fuzzing/fuzz_lzxpress_round_trip.c
new file mode 100644
index 0000000..a4043c2
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress_round_trip.c
@@ -0,0 +1,56 @@
+/*
+ Fuzzing for lzxpress_decompress
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "lzxpress.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ static uint8_t compressed[1024 * 1280] = {0};
+ static uint8_t decompressed[1024 * 1024] = {0};
+ ssize_t compressed_size;
+ ssize_t decompressed_size;
+
+ if (len > sizeof(decompressed)) {
+ return 0;
+ }
+
+ compressed_size = lzxpress_compress(buf, len,
+ compressed, sizeof(compressed));
+ if (compressed_size < 0) {
+ abort();
+ }
+
+ decompressed_size = lzxpress_decompress(compressed, compressed_size,
+ decompressed, sizeof(decompressed));
+
+ if (decompressed_size != len) {
+ abort();
+ }
+ if (memcmp(buf, decompressed, len) != 0) {
+ abort();
+ }
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ndr_X.c b/lib/fuzzing/fuzz_ndr_X.c
new file mode 100644
index 0000000..16109cc
--- /dev/null
+++ b/lib/fuzzing/fuzz_ndr_X.c
@@ -0,0 +1,337 @@
+/*
+ Unix SMB/CIFS implementation.
+ Fuzzer for pidl-generated NDR pipes.
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2006
+ Copyright (C) Andrew Bartlett 2019
+ Copyright (C) Catalyst.NET Ltd 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "util/byteorder.h"
+#include "fuzzing/fuzzing.h"
+
+extern const struct ndr_interface_table FUZZ_PIPE_TABLE;
+
+#define FLAG_NDR64 4
+
+enum {
+ TYPE_STRUCT = 0,
+ TYPE_IN,
+ TYPE_OUT
+};
+
+/*
+ * header design (little endian):
+ *
+ * struct {
+ * uint16_t flags;
+ * uint16_t function_or_struct_no;
+ * };
+ */
+
+/*
+ * We want an even number here to ensure 4-byte alignment later
+ * not just for efficiency but because the fuzzers are known to guess
+ * that numbers will be 4-byte aligned
+ */
+#define HEADER_SIZE 4
+
+#define INVALID_FLAGS (~(FLAG_NDR64 | 3))
+
+static const struct ndr_interface_call *find_function(
+ const struct ndr_interface_table *p,
+ unsigned int function_no)
+{
+ if (function_no >= p->num_calls) {
+ return NULL;
+ }
+ return &p->calls[function_no];
+}
+
+/*
+ * Get a public structure by number and return it as if it were
+ * a function.
+ */
+static const struct ndr_interface_call *find_struct(
+ const struct ndr_interface_table *p,
+ unsigned int struct_no,
+ struct ndr_interface_call *out_buffer)
+{
+ const struct ndr_interface_public_struct *s = NULL;
+
+ if (struct_no >= p->num_public_structs) {
+ return NULL;
+ }
+
+ s = &p->public_structs[struct_no];
+
+ *out_buffer = (struct ndr_interface_call) {
+ .name = s->name,
+ .struct_size = s->struct_size,
+ .ndr_pull = s->ndr_pull,
+ .ndr_push = s->ndr_push,
+ .ndr_print = s->ndr_print
+ };
+ return out_buffer;
+}
+
+
+static NTSTATUS pull_chunks(struct ndr_pull *ndr_pull,
+ const struct ndr_interface_call_pipes *pipes)
+{
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+
+ for (i=0; i < pipes->num_pipes; i++) {
+ while (true) {
+ void *saved_mem_ctx;
+ uint32_t *count;
+ void *c;
+
+ c = talloc_zero_size(ndr_pull, pipes->pipes[i].chunk_struct_size);
+ if (c == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ /*
+ * Note: the first struct member is always
+ * 'uint32_t count;'
+ */
+ count = (uint32_t *)c;
+
+ saved_mem_ctx = ndr_pull->current_mem_ctx;
+ ndr_pull->current_mem_ctx = c;
+ ndr_err = pipes->pipes[i].ndr_pull(ndr_pull, NDR_SCALARS, c);
+ ndr_pull->current_mem_ctx = saved_mem_ctx;
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(c);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ if (*count == 0) {
+ talloc_free(c);
+ break;
+ }
+ talloc_free(c);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void ndr_print_nothing(struct ndr_print *ndr, const char *format, ...)
+{
+ /*
+ * This is here so that we walk the tree but don't output anything.
+ * This helps find buggy ndr_print routines
+ */
+
+ /*
+ * TODO: consider calling snprinf() to find strings without NULL
+ * terminators (for example)
+ */
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ uint8_t type;
+ ndr_flags_type pull_push_print_flags;
+ uint16_t fuzz_packet_flags, function;
+ TALLOC_CTX *mem_ctx = NULL;
+ libndr_flags ndr_flags = 0;
+ struct ndr_push *ndr_push;
+ enum ndr_err_code ndr_err;
+ struct ndr_interface_call f_buffer;
+ const struct ndr_interface_call *f = NULL;
+ NTSTATUS status;
+
+/*
+ * This allows us to build binaries to fuzz just one target function
+ *
+ * In this mode the input becomes the 'stub data', there is no prefix.
+ *
+ * There is no NDR64 support in this mode at this time.
+ */
+#if defined(FUZZ_TYPE) && defined(FUZZ_FUNCTION)
+#undef HEADER_SIZE
+#define HEADER_SIZE 0
+ fuzz_packet_flags = 0;
+ type = FUZZ_TYPE;
+ function = FUZZ_FUNCTION;
+#else
+ if (size < HEADER_SIZE) {
+ /*
+ * the first few bytes decide what is being fuzzed --
+ * if they aren't all there we do nothing.
+ */
+ return 0;
+ }
+
+ fuzz_packet_flags = SVAL(data, 0);
+ if (fuzz_packet_flags & INVALID_FLAGS) {
+ return 0;
+ }
+
+ function = SVAL(data, 2);
+
+ type = fuzz_packet_flags & 3;
+
+#ifdef FUZZ_TYPE
+ /*
+ * Fuzz targets should have as small an interface as possible.
+ * This allows us to create 3 binaries for most pipes,
+ * TYPE_IN, TYPE_OUT and TYPE_STRUCT
+ *
+ * We keep the header format, and just exit early if it does
+ * not match.
+ */
+ if (type != FUZZ_TYPE) {
+ return 0;
+ }
+#endif
+#endif
+
+ switch (type) {
+ case TYPE_STRUCT:
+ pull_push_print_flags = NDR_SCALARS|NDR_BUFFERS;
+ f = find_struct(&FUZZ_PIPE_TABLE, function, &f_buffer);
+ break;
+ case TYPE_IN:
+ pull_push_print_flags = NDR_IN;
+ f = find_function(&FUZZ_PIPE_TABLE, function);
+ break;
+ case TYPE_OUT:
+ pull_push_print_flags = NDR_OUT;
+ f = find_function(&FUZZ_PIPE_TABLE, function);
+ break;
+ default:
+ return 0;
+ }
+
+ if (f == NULL) {
+ return 0;
+ }
+ if (fuzz_packet_flags & FLAG_NDR64) {
+ ndr_flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ mem_ctx = talloc_init("ndrfuzz");
+
+ {
+ /*
+ * f->struct_size is well-controlled, it is essentially
+ * defined in the IDL
+ */
+ uint8_t st[f->struct_size];
+
+ DATA_BLOB blob = data_blob_const(data + HEADER_SIZE,
+ size - HEADER_SIZE);
+ struct ndr_pull *ndr_pull = ndr_pull_init_blob(&blob,
+ mem_ctx);
+
+ if (ndr_pull == NULL) {
+ perror("ndr_pull_init_blob");
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ /*
+ * We must initialise the buffer (even if we would
+ * prefer not to for the sake of eg valgrind) as
+ * otherwise the special handler for 'out pointer with
+ * [size_is()] refers to in value with [ref]' fails to
+ * trigger
+ */
+ memset(st, '\0', sizeof(st));
+
+ ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_pull->global_max_recursion = 128;
+
+ if (type == TYPE_OUT) {
+ status = pull_chunks(ndr_pull,
+ &f->out_pipes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+ }
+
+ ndr_err = f->ndr_pull(ndr_pull,
+ pull_push_print_flags,
+ st);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ if (type == TYPE_IN) {
+ status = pull_chunks(ndr_pull,
+ &f->in_pipes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+ }
+
+ ndr_push = ndr_push_init_ctx(mem_ctx);
+ if (ndr_push == NULL) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ ndr_push->flags |= ndr_flags;
+
+ /*
+ * Now push what was pulled, just in case we generated an
+ * invalid structure in memory, this should notice
+ */
+ ndr_err = f->ndr_push(ndr_push,
+ pull_push_print_flags,
+ st);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ {
+ struct ndr_print *ndr_print = talloc_zero(mem_ctx, struct ndr_print);
+ ndr_print->print = ndr_print_nothing;
+ ndr_print->depth = 1;
+
+ /*
+ * Finally print (to nowhere) the structure, this may also
+ * notice invalid memory
+ */
+ f->ndr_print(ndr_print,
+ f->name,
+ pull_push_print_flags,
+ st);
+ }
+ }
+ TALLOC_FREE(mem_ctx);
+
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_nmblib_parse_packet.c b/lib/fuzzing/fuzz_nmblib_parse_packet.c
new file mode 100644
index 0000000..c8a2d03
--- /dev/null
+++ b/lib/fuzzing/fuzz_nmblib_parse_packet.c
@@ -0,0 +1,62 @@
+/*
+ Fuzz NMB parse_packet
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../../source3/include/includes.h"
+#include "libsmb/libsmb.h"
+#include "libsmb/nmblib.h"
+#include "fuzzing/fuzzing.h"
+
+#define PORT 138
+#define MAX_LENGTH (1024 * 1024)
+char buf[MAX_LENGTH + 1];
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ struct packet_struct *p = NULL;
+ struct in_addr ip = {
+ 0x0100007f /* 127.0.0.1 */
+ };
+
+ p = parse_packet((char *)input,
+ len,
+ NMB_PACKET,
+ ip,
+ PORT);
+ /*
+ * We expect NULL (parse failure) most of the time.
+ *
+ * When it is not NULL we want to ensure the parsed packet is
+ * reasonably sound.
+ */
+
+ if (p != NULL) {
+ struct nmb_packet *nmb = &p->packet.nmb;
+ pull_ascii_nstring(buf, MAX_LENGTH,
+ nmb->question.question_name.name);
+ build_packet(buf, MAX_LENGTH, p);
+ free_packet(p);
+ }
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_oLschema2ldif.c b/lib/fuzzing/fuzz_oLschema2ldif.c
new file mode 100644
index 0000000..3bff8cf
--- /dev/null
+++ b/lib/fuzzing/fuzz_oLschema2ldif.c
@@ -0,0 +1,71 @@
+/*
+ Fuzzing for oLschema2ldif
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing.h"
+#include "utils/oLschema2ldif/lib.h"
+
+static FILE *devnull;
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ devnull = fopen("/dev/null", "w");
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ TALLOC_CTX *mem_ctx;
+ struct conv_options opt;
+
+ if (len == 0) {
+ /*
+ * Otherwise fmemopen() will return null and set errno
+ * to EINVAL
+ */
+ return 0;
+ }
+
+ mem_ctx = talloc_init(__FUNCTION__);
+ if (mem_ctx == NULL) {
+ return 0;
+ }
+
+ opt.in = fmemopen(buf, len, "r");
+ opt.out = devnull;
+ opt.ldb_ctx = ldb_init(mem_ctx, NULL);
+ if (opt.ldb_ctx == NULL || opt.in == NULL) {
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ opt.basedn = ldb_dn_new(mem_ctx, opt.ldb_ctx, "");
+ if (opt.basedn == NULL) {
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ process_file(mem_ctx, &opt);
+
+ fclose(opt.in);
+
+ talloc_free(mem_ctx);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_parse_lpq_entry.c b/lib/fuzzing/fuzz_parse_lpq_entry.c
new file mode 100644
index 0000000..3537ce5
--- /dev/null
+++ b/lib/fuzzing/fuzz_parse_lpq_entry.c
@@ -0,0 +1,65 @@
+/*
+ Fuzzing parse_lpq_entry
+ Copyright (C) Douglas Bagnall <dbagnall@samba.org> 2021
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "../../source3/include/includes.h"
+#include "printing.h"
+#include "fuzzing/fuzzing.h"
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+#define MAX_LENGTH (1024 * 1024)
+char line[MAX_LENGTH + 1];
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ enum printing_types printing_type;
+ print_queue_struct pq_buf = {0};
+ print_status_struct status = {0};
+ bool first;
+ unsigned x;
+ TALLOC_CTX *frame = NULL;
+
+ if (len < 1 || len > MAX_LENGTH) {
+ return 0;
+ }
+
+ x = input[0];
+ input++;
+ len--;
+
+ /* There are 14 types, default goes to bsd */
+ printing_type = x & 15;
+ first = (x & 16) ? true : false;
+
+ memcpy(line, input, len);
+ line[len] = '\0';
+
+ /* parse_lpq_bsd requires a stackframe */
+ frame = talloc_stackframe();
+
+ parse_lpq_entry(printing_type,
+ line,
+ &pq_buf, /* out */
+ &status, /* out */
+ first);
+ talloc_free(frame);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_reg_parse.c b/lib/fuzzing/fuzz_reg_parse.c
new file mode 100644
index 0000000..bbc62ea
--- /dev/null
+++ b/lib/fuzzing/fuzz_reg_parse.c
@@ -0,0 +1,46 @@
+/*
+ * Fuzzing for reg_parse
+ * Copyright (C) Michael Hanselmann 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "lib/util/fault.h"
+#include "registry.h"
+#include "registry/reg_parse.h"
+
+static FILE *fp;
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ fp = tmpfile();
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ const reg_parse_callback cb = {0};
+
+ rewind(fp);
+ (void)fwrite(buf, len, 1, fp);
+ (void)fflush(fp);
+ rewind(fp);
+
+ (void)reg_parse_fd(fileno(fp), &cb, "");
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_regfio.c b/lib/fuzzing/fuzz_regfio.c
new file mode 100644
index 0000000..588efb0
--- /dev/null
+++ b/lib/fuzzing/fuzz_regfio.c
@@ -0,0 +1,68 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Windows NT registry I/O library
+ * Copyright (C) Michael Hanselmann 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "system/filesys.h"
+#include "lib/util/fault.h"
+#include "registry/reg_objects.h"
+#include "registry/regfio.h"
+
+static FILE *fp;
+static char filename[128];
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ fp = tmpfile();
+
+ (void)snprintf(filename, sizeof(filename), "/proc/self/fd/%d", fileno(fp));
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ REGF_FILE* regfile;
+ REGF_NK_REC *nk, *subkey;
+
+ rewind(fp);
+ (void)fwrite(buf, len, 1, fp);
+ (void)fflush(fp);
+
+ regfile = regfio_open(filename, O_RDONLY, 0600);
+ if (!regfile) {
+ goto out;
+ }
+
+ regfile->ignore_checksums = true;
+
+ nk = regfio_rootkey(regfile);
+ if (nk != NULL) {
+ nk->subkey_index = 0;
+ while ((subkey = regfio_fetch_subkey(regfile, nk))) {
+ }
+ }
+
+out:
+ if (regfile != NULL) {
+ regfio_close(regfile);
+ }
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_sddl_access_check.c b/lib/fuzzing/fuzz_sddl_access_check.c
new file mode 100644
index 0000000..a7bf7b3
--- /dev/null
+++ b/lib/fuzzing/fuzz_sddl_access_check.c
@@ -0,0 +1,206 @@
+/*
+ Fuzz access check using SDDL strings and a known token
+ Copyright (C) Catalyst IT 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "lib/util/attr.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_conditional_ace.h"
+#include "lib/util/bytearray.h"
+#include "fuzzing/fuzzing.h"
+
+
+static struct security_token token = {0};
+
+static struct dom_sid dom_sid = {0};
+
+/*
+ * For this one we initialise a security token to have a few claims
+ * and SIDs. The fuzz strings contain SDDL that will be tested against
+ * this token in se_access_check() or sec_access_check_ds() --
+ * supposing they compile.
+ */
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct dom_sid *sid = NULL;
+
+ struct claim_def {
+ const char *type;
+ const char *name;
+ const char *claim_sddl;
+ } claims[] = {
+ {
+ "user",
+ "shoe size",
+ "44"
+ },
+ {
+ "user",
+ "©",
+ "{\"unknown\", \"\", \" ←ā\"}"
+ },
+ {
+ "device",
+ "©",
+ "{\"unknown\", \" \", \" ←ā\"}"
+ },
+ {
+ "device",
+ "least favourite groups",
+ "{SID(S-1-1-0),SID(S-1-5-3),SID(S-1-57777-333-33-33-2)}"
+ },
+ {
+ "local",
+ "birds",
+ "{\"tern\"}"
+ },
+ };
+
+ const char * device_sids[] = {
+ "S-1-1-0",
+ "S-1-333-66",
+ "S-1-2-3-4-5-6-7-8-9",
+ };
+ const char * user_sids[] = {
+ "S-1-333-66",
+ "S-1-16-8448",
+ "S-1-9-8-7",
+ };
+
+ for (i = 0; i < ARRAY_SIZE(user_sids); i++) {
+ sid = sddl_decode_sid(mem_ctx, &user_sids[i], NULL);
+ if (sid == NULL) {
+ abort();
+ }
+ add_sid_to_array(mem_ctx, sid,
+ &token.sids,
+ &token.num_sids);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(device_sids); i++) {
+ sid = sddl_decode_sid(mem_ctx, &device_sids[i], NULL);
+ if (sid == NULL) {
+ abort();
+ }
+ add_sid_to_array(mem_ctx, sid,
+ &token.device_sids,
+ &token.num_device_sids);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(claims); i++) {
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+ struct claim_def c = claims[i];
+
+ claim = parse_sddl_literal_as_claim(mem_ctx,
+ c.name,
+ c.claim_sddl);
+ if (claim == NULL) {
+ abort();
+ }
+ add_claim_to_token(mem_ctx, &token, claim, c.type);
+ }
+
+ /* we also need a global domain SID */
+ string_to_sid(&dom_sid, device_sids[2]);
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct security_descriptor *sd = NULL;
+ uint32_t access_desired;
+ uint32_t access_granted;
+ const char *sddl;
+ ssize_t i;
+ if (len < 5) {
+ return 0;
+ }
+ access_desired = PULL_LE_U32(input + len - 4, 0);
+
+ /*
+ * check there is a '\0'.
+ *
+ * Note this allows double-dealing for the last 4 bytes: they are used
+ * as the access_desired mask (see just above) but also *could* be
+ * part of the sddl string. But this doesn't matter, for three
+ * reasons:
+ *
+ * 1. the desired access mask doesn't usually matter much.
+ *
+ * 2. the final '\0' is rarely the operative one. Usually the
+ * effective string ends a long time before the end of the input, and
+ * the tail is just junk that comes along for the ride.
+ *
+ * 3. Even if there is a case where the end of the SDDL is part of the
+ * mask, the evolution strategy is very likely to try a different mask,
+ * because it likes to add junk on the end.
+ *
+ * But still, you ask, WHY? So that the seeds from here can be shared
+ * back and forth with the fuzz_sddl_parse seeds, which have the same
+ * form of a null-terminated-string-with-trailing-junk. If we started
+ * the loop at `len - 5` instead of `len - 1`, there might be
+ * interesting seeds that are valid there that would fail here. That's
+ * all.
+ */
+ for (i = len - 1; i >= 0; i--) {
+ if (input[i] == 0) {
+ break;
+ }
+ }
+ if (i < 0) {
+ return 0;
+ }
+
+ sddl = (const char *)input;
+ mem_ctx = talloc_new(NULL);
+
+ sd = sddl_decode(mem_ctx, sddl, &dom_sid);
+ if (sd == NULL) {
+ goto end;
+ }
+
+#ifdef FUZZ_SEC_ACCESS_CHECK_DS
+ /*
+ * The sec_access_check_ds() function has two arguments not found in
+ * se_access_check, and also not found in our fuzzing examples.
+ *
+ * One is a struct object_tree, which is used for object ACE types.
+ * The other is a SID, which is used as a default if an ACE lacks a
+ * SID.
+ */
+ sec_access_check_ds(sd,
+ &token,
+ access_desired,
+ &access_granted,
+ NULL,
+ NULL);
+#else
+ se_access_check(sd, &token, access_desired, &access_granted);
+#endif
+
+end:
+ talloc_free(mem_ctx);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_sddl_conditional_ace.c b/lib/fuzzing/fuzz_sddl_conditional_ace.c
new file mode 100644
index 0000000..636ebf1
--- /dev/null
+++ b/lib/fuzzing/fuzz_sddl_conditional_ace.c
@@ -0,0 +1,121 @@
+/*
+ Fuzz sddl conditional ace decoding and encoding
+ Copyright (C) Catalyst IT 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "libcli/security/security.h"
+#include "lib/util/attr.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "fuzzing/fuzzing.h"
+
+
+#define MAX_LENGTH (1024 * 1024 - 1)
+static char sddl_string[MAX_LENGTH + 1] = {0};
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ok;
+ struct ace_condition_script *s1 = NULL;
+ struct ace_condition_script *s2 = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ const char *resddl = NULL;
+ DATA_BLOB e1, e2, e3;
+ size_t length;
+
+ if (len > MAX_LENGTH) {
+ return 0;
+ }
+
+ memcpy(sddl_string, input, len);
+ sddl_string[len] = '\0';
+
+ mem_ctx = talloc_new(NULL);
+
+ s1 = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl_string,
+ &message,
+ &message_offset,
+ &length);
+ if (s1 == NULL) {
+ /* could assert message is non-empty */
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s1, &e1);
+ if (! ok) {
+ abort();
+ }
+
+ s2 = parse_conditional_ace(mem_ctx, e1);
+ if (s2 == NULL) {
+ abort();
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s2, &e2);
+ if (! ok) {
+ abort();
+ }
+ if (data_blob_cmp(&e1, &e2) != 0) {
+ abort();
+ }
+
+ /*
+ * We know now the SDDL representation compiles to a valid structure
+ * that survives a round trip through serialisation.
+ *
+ * A remaining question is whether it can be re-rendered as SDDL that
+ * compiles to the same blob.
+ */
+ resddl = sddl_from_conditional_ace(mem_ctx, s2);
+ if (resddl == NULL) {
+ abort();
+ }
+
+ s2 = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ resddl,
+ &message,
+ &message_offset,
+ &length);
+ if (s2 == NULL) {
+ abort();
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s2, &e3);
+ if (! ok) {
+ abort();
+ }
+ if (data_blob_cmp(&e1, &e3) != 0) {
+ abort();
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_sddl_parse.c b/lib/fuzzing/fuzz_sddl_parse.c
new file mode 100644
index 0000000..05900b0
--- /dev/null
+++ b/lib/fuzzing/fuzz_sddl_parse.c
@@ -0,0 +1,110 @@
+/*
+ Fuzz sddl decoding and encoding
+ Copyright (C) Catalyst IT 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "fuzzing/fuzzing.h"
+#include "util/charset/charset.h"
+
+#define MAX_LENGTH (100 * 1024 - 1)
+static char sddl_string[MAX_LENGTH + 1] = {0};
+static struct dom_sid dom_sid = {0};
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ string_to_sid(&dom_sid,
+ "S-1-5-21-2470180966-3899876309-2637894779");
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct security_descriptor *sd1 = NULL;
+ struct security_descriptor *sd2 = NULL;
+ char *result = NULL;
+ bool ok;
+
+ if (len > MAX_LENGTH) {
+ return 0;
+ }
+
+ memcpy(sddl_string, input, len);
+ sddl_string[len] = '\0';
+
+ mem_ctx = talloc_new(NULL);
+
+ sd1 = sddl_decode(mem_ctx, sddl_string, &dom_sid);
+ if (sd1 == NULL) {
+ goto end;
+ }
+ result = sddl_encode(mem_ctx, sd1, &dom_sid);
+ if (result == NULL) {
+ /*
+ * Because Samba currently doesn't enforce strict
+ * utf-8 parsing, illegal utf-8 sequences in
+ * sddl_string could have ferried bad characters
+ * through into the security descriptor conditions
+ * that we then find we can't encode.
+ *
+ * The proper solution is strict UTF-8 enforcement in
+ * sddl_decode, but for now we forgive unencodable
+ * security descriptors made from bad utf-8.
+ */
+ size_t byte_len, char_len, utf16_len;
+ ok = utf8_check(sddl_string, len,
+ &byte_len, &char_len, &utf16_len);
+ if (!ok) {
+ goto end;
+ }
+ /* utf-8 was fine, but we couldn't encode! */
+ abort();
+ }
+
+ sd2 = sddl_decode(mem_ctx, result, &dom_sid);
+ if (sd2 == NULL) {
+ if (strlen(result) > CONDITIONAL_ACE_MAX_LENGTH) {
+ /*
+ * This could fail if a unicode string or
+ * attribute name that contains escapable
+ * bytes (e.g '\x0b') in an unescaped form in
+ * the original string ends up with them in
+ * the escaped form ("%000b") in the result
+ * string, making the entire attribute name
+ * too long for the arbitrary limit we set for
+ * SDDL attribute names.
+ *
+ * We could increase that arbitrary limit (to,
+ * say, CONDITIONAL_ACE_MAX_LENGTH * 5), but
+ * that is getting very far from real world
+ * needs.
+ */
+ goto end;
+ }
+ abort();
+ }
+ ok = security_descriptor_equal(sd1, sd2);
+ if (!ok) {
+ abort();
+ }
+end:
+ talloc_free(mem_ctx);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_security_token_vs_descriptor.c b/lib/fuzzing/fuzz_security_token_vs_descriptor.c
new file mode 100644
index 0000000..f9b2552
--- /dev/null
+++ b/lib/fuzzing/fuzz_security_token_vs_descriptor.c
@@ -0,0 +1,78 @@
+/*
+ Fuzz a security token and descriptor through an access check
+ Copyright (C) Catalyst IT 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "fuzzing/fuzzing.h"
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct security_token_descriptor_fuzzing_pair p = {0};
+ enum ndr_err_code ndr_err;
+ uint32_t access_granted;
+
+ DATA_BLOB blob = {
+ .data = input,
+ .length = len
+ };
+
+ mem_ctx = talloc_new(NULL);
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, mem_ctx, &p,
+ (ndr_pull_flags_fn_t)ndr_pull_security_token_descriptor_fuzzing_pair);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto end;
+ }
+
+#ifdef FUZZ_SEC_ACCESS_CHECK_DS
+ /*
+ * The sec_access_check_ds() function has two arguments not found in
+ * se_access_check, and also not found in our fuzzing examples.
+ *
+ * One is a struct object_tree, which is used for object ACE types.
+ * The other is a SID, which is used as a default if an ACE lacks a
+ * SID.
+ */
+ sec_access_check_ds(&p.sd,
+ &p.token,
+ p.access_desired,
+ &access_granted,
+ NULL,
+ NULL);
+#else
+ se_access_check(&p.sd,
+ &p.token,
+ p.access_desired,
+ &access_granted);
+#endif
+
+end:
+ talloc_free(mem_ctx);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_sess_crypt_blob.c b/lib/fuzzing/fuzz_sess_crypt_blob.c
new file mode 100644
index 0000000..bed697e
--- /dev/null
+++ b/lib/fuzzing/fuzz_sess_crypt_blob.c
@@ -0,0 +1,55 @@
+/*
+ Fuzzing sess_*crypt_blob
+ Copyright (C) Catalyst IT 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "libcli/auth/libcli_auth.h"
+#include "session.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ DATA_BLOB blob, session_key, out;
+ size_t slen;
+ if (len < 1) {
+ return 0;
+ }
+
+ slen = input[0];
+ if (len < slen + 1) {
+ return 0;
+ }
+
+ session_key.data = input + 1;
+ session_key.length = slen;
+ blob.data = input + 1 + slen;
+ blob.length = len - slen - 1;
+
+ mem_ctx = talloc_new(NULL);
+
+ out = sess_encrypt_blob(mem_ctx, &blob, &session_key);
+ sess_decrypt_blob(mem_ctx, &blob, &session_key, &out);
+
+ TALLOC_FREE(mem_ctx);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_stable_sort.c b/lib/fuzzing/fuzz_stable_sort.c
new file mode 100644
index 0000000..e2195cb
--- /dev/null
+++ b/lib/fuzzing/fuzz_stable_sort.c
@@ -0,0 +1,88 @@
+/*
+ Fuzzing for stable_sort
+ Copyright © Catalyst IT
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "talloc.h"
+#include "util/stable_sort.h"
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+
+#define CMP_FN(type) static int cmp_ ## type (type *a, type *b) \
+{\
+ if (*a > *b) {\
+ return 1;\
+ }\
+ if (*a < *b) {\
+ return -1;\
+ }\
+ return 0;\
+}
+
+CMP_FN(uint8_t)
+CMP_FN(uint16_t)
+CMP_FN(uint32_t)
+CMP_FN(uint64_t)
+
+#define MAX_SIZE (1024 * 1024)
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ samba_compare_fn_t fn;
+ size_t s, i;
+ uint8_t buf2[MAX_SIZE];
+
+ if (len < 1 || len > MAX_SIZE) {
+ return 0;
+ }
+ s = 1 << (buf[0] & 3);
+ if (s == 1) {
+ fn = (samba_compare_fn_t)cmp_uint8_t;
+ } else if (s == 2) {
+ fn = (samba_compare_fn_t)cmp_uint16_t;
+ } else if (s == 4) {
+ fn = (samba_compare_fn_t)cmp_uint32_t;
+ } else {
+ fn = (samba_compare_fn_t)cmp_uint64_t;
+ }
+ buf++;
+ len--;
+ len -= len & (s - 1);
+
+ mem_ctx = talloc_new(NULL);
+ memcpy(buf2, buf, len);
+
+ stable_sort_talloc(mem_ctx, buf2, len / s, s, fn);
+
+ talloc_free(mem_ctx);
+
+ for (i = s; i < len; i += s) {
+ int c = fn(&buf2[i - s], &buf2[i]);
+ if (c > 0) {
+ abort();
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_stable_sort_r.c b/lib/fuzzing/fuzz_stable_sort_r.c
new file mode 100644
index 0000000..68be73b
--- /dev/null
+++ b/lib/fuzzing/fuzz_stable_sort_r.c
@@ -0,0 +1,69 @@
+/*
+ Fuzzing for stable_sort
+ Copyright © Catalyst IT
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "util/stable_sort.h"
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+/*
+ * For a "context" we use a byte that the values are XORed with before
+ * comparison, for a non-obvious but stable sort order.
+ */
+static int cmp_int8(int8_t *a, int8_t *b, int8_t *c)
+{
+ return (*a ^ *c) - (*b ^ *c);
+}
+
+
+#define MAX_SIZE (1024 * 1024)
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ size_t i;
+ int8_t buf2[MAX_SIZE];
+ int8_t aux[MAX_SIZE];
+ int8_t context;
+
+ if (len < 1 || len > MAX_SIZE) {
+ return 0;
+ }
+ context = (int8_t)buf[0];
+ buf++;
+ len--;
+
+ memcpy(buf2, buf, len);
+
+ stable_sort_r(buf2, aux, len, 1,
+ (samba_compare_with_context_fn_t)cmp_int8,
+ &context);
+
+ for (i = 1; i < len; i++) {
+ int c = cmp_int8(&buf2[i - 1], &buf2[i], &context);
+ if (c > 0) {
+ abort();
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_tiniparser.c b/lib/fuzzing/fuzz_tiniparser.c
new file mode 100644
index 0000000..a5c9310
--- /dev/null
+++ b/lib/fuzzing/fuzz_tiniparser.c
@@ -0,0 +1,51 @@
+/*
+ Fuzzing for trivial smb.conf parsing code.
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing.h"
+#include "lib/util/tiniparser.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
+{
+ FILE *fp = NULL;
+ struct tiniparser_dictionary *d = NULL;
+
+ if (len == 0) {
+ /*
+ * Otherwise fmemopen() will return null and set errno
+ * to EINVAL
+ */
+ return 0;
+ }
+
+ fp = fmemopen(buf, len, "r");
+
+ d = tiniparser_load_stream(fp);
+ if (d != NULL) {
+ tiniparser_freedict(d);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzzing.c b/lib/fuzzing/fuzzing.c
new file mode 100644
index 0000000..f0d7fb4
--- /dev/null
+++ b/lib/fuzzing/fuzzing.c
@@ -0,0 +1,21 @@
+/*
+ Unix SMB/CIFS implementation.
+ Fuzzing utility functions
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
diff --git a/lib/fuzzing/fuzzing.h b/lib/fuzzing/fuzzing.h
new file mode 100644
index 0000000..0d3cb70
--- /dev/null
+++ b/lib/fuzzing/fuzzing.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/CIFS implementation.
+ Fuzzing utility functions
+ Copyright (C) Michael Hanselmann 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_FUZZING_H
+#define _SAMBA_FUZZING_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* Prototypes for fuzzing interface */
+int LLVMFuzzerInitialize(int *argc, char ***argv);
+int LLVMFuzzerTestOneInput(const uint8_t * buf, size_t len);
+
+#endif /* _SAMBA_FUZZING_H */
diff --git a/lib/fuzzing/oss-fuzz/build_image.sh b/lib/fuzzing/oss-fuzz/build_image.sh
new file mode 100755
index 0000000..62a626b
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/build_image.sh
@@ -0,0 +1,7 @@
+#!/bin/sh -e
+
+DIST=ubuntu2004
+SCRIPT_DIR=$(dirname $0)
+
+$SCRIPT_DIR/../../../bootstrap/generated-dists/$DIST/bootstrap.sh
+$SCRIPT_DIR/../../../bootstrap/generated-dists/$DIST/locale.sh
diff --git a/lib/fuzzing/oss-fuzz/build_samba.sh b/lib/fuzzing/oss-fuzz/build_samba.sh
new file mode 100755
index 0000000..90c1733
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/build_samba.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# This is not a general-purpose build script, but instead one specific
+# to the Google oss-fuzz compile environment.
+#
+# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#Requirements
+#
+# https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/README.md#provided-environment-variables
+#
+# This file is run by
+# https://github.com/google/oss-fuzz/blob/master/projects/samba/build.sh
+# which does nothing else.
+#
+# Additional arguments are passed to configure, to allow this to be
+# tested in autobuild.py
+#
+
+# Ensure we give good trace info, fail right away and fail with unset
+# variables
+set -e
+set -x
+set -u
+
+"$(dirname "${0}")"/do_build.sh "$@"
+"$(dirname "${0}")"/check_build.sh "${OUT}" \ No newline at end of file
diff --git a/lib/fuzzing/oss-fuzz/check_build.sh b/lib/fuzzing/oss-fuzz/check_build.sh
new file mode 100755
index 0000000..487addf
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/check_build.sh
@@ -0,0 +1,48 @@
+#!/bin/sh -eux
+#
+# A very simple check script to confirm we still provide binaries
+# that look like the targets oss-fuzz wants.
+#
+# A much stronger check is available in oss-fuzz via
+# infra/helper.py check_build samba
+#
+
+# oss-fuzz provides an OUT variable, so for clarity this script
+# uses the same. See build_samba.sh
+OUT=$1
+
+# build_samba.sh will have put a non-zero number of fuzzers here. If
+# there are none, this will fail as it becomes literally fuzz_*
+
+seeds_found=no
+
+for bin in $OUT/fuzz_*; do
+ # we only want to look at the elf files, not the zips
+ if [ ${bin%_seed_corpus.zip} != $bin ]; then
+ continue
+ fi
+ # Confirm that the chrpath was reset to lib/ in the same directory
+ # as the binary. RPATH (not RUNPATH) is critical, otherwise
+ # libraries used by libraries won't be found on the oss-fuzz
+ # target host.
+ chrpath -l $bin | grep 'RPATH=$ORIGIN/lib'
+
+ # Confirm that we link to at least some libraries in this
+ # directory (shows that the libraries were found and copied).
+ ldd $bin | grep "$OUT/lib"
+ num_libs=$(ldd $bin | grep -v ld-linux | grep -v linux-vdso | grep -v "$OUT/lib" | wc -l)
+
+ if [ 0$num_libs -ne 0 ]; then
+ echo "some libraries not linked to $ORIGIN/lib, oss-fuzz will fail!"
+ exit 1
+ fi
+
+ if [ -f ${bin}_seed_corpus.zip ]; then
+ seeds_found=yes
+ fi
+done
+
+if [ $seeds_found = no ]; then
+ echo "no seed zip files were found!"
+ exit 1
+fi
diff --git a/lib/fuzzing/oss-fuzz/do_build.sh b/lib/fuzzing/oss-fuzz/do_build.sh
new file mode 100755
index 0000000..29a6ceb
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/do_build.sh
@@ -0,0 +1,294 @@
+#!/bin/sh
+#
+# This is not a general-purpose build script, but instead one specific
+# to the Google oss-fuzz compile environment.
+#
+# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#Requirements
+#
+# https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/README.md#provided-environment-variables
+#
+# This file is run by build_samba.sh, which is run by
+# https://github.com/google/oss-fuzz/blob/master/projects/samba/build.sh
+# which does nothing else.
+#
+# We have to push to oss-fuzz CFLAGS into the waf ADDITIONAL_CFLAGS
+# as otherwise waf's configure fails linking the first test binary
+#
+# CFLAGS are supplied by the caller, eg the oss-fuzz compile command
+#
+# Additional arguments are passed to configure, to allow this to be
+# tested in autobuild.py
+#
+
+# Ensure we give good trace info, fail right away and fail with unset
+# variables
+set -e
+set -x
+set -u
+
+# It is critical that this script, just as the rest of Samba's GitLab
+# CI docker has LANG set to en_US.utf8 (oss-fuzz fails to set this)
+if [ -f /etc/default/locale ]; then
+ . /etc/default/locale
+elif [ -f /etc/locale.conf ]; then
+ . /etc/locale.conf
+fi
+export LANG
+export LC_ALL
+
+ADDITIONAL_CFLAGS="$CFLAGS"
+export ADDITIONAL_CFLAGS
+CFLAGS=""
+export CFLAGS
+LD="$CXX"
+export LD
+
+# Use the system Python, not the OSS-Fuzz provided statically linked
+# and instrumented Python, because we can't statically link.
+
+PYTHON=/usr/bin/python3
+export PYTHON
+
+# $SANITIZER is provided by the oss-fuzz "compile" command
+#
+# We need to add the waf configure option as otherwise when we also
+# get (eg) -fsanitize=address via the CFLAGS we will fail to link
+# correctly
+
+case "$SANITIZER" in
+address)
+ SANITIZER_ARG='--address-sanitizer'
+ ;;
+undefined)
+ SANITIZER_ARG='--undefined-sanitizer'
+ ;;
+coverage)
+ # Thankfully clang operating as ld has no objection to the
+ # cc style options, so we can just set ADDITIONAL_LDFLAGS
+ # to ensure the coverage build is done, despite waf splitting
+ # the compile and link phases.
+ ADDITIONAL_LDFLAGS="${ADDITIONAL_LDFLAGS:-} $COVERAGE_FLAGS"
+ export ADDITIONAL_LDFLAGS
+
+ SANITIZER_ARG=''
+ ;;
+esac
+
+# $LIB_FUZZING_ENGINE is provided by the oss-fuzz "compile" command
+#
+
+# --disable-new-dtags linker flag creates fuzzer binaries with RPATH
+# header instead of RUNPATH header. Modern linkers use RUNPATH by
+# default.
+./configure -C --without-gettext --enable-debug --enable-developer \
+ --enable-libfuzzer \
+ $SANITIZER_ARG \
+ --disable-warnings-as-errors \
+ --abi-check-disable \
+ "--fuzz-target-ldflags=-Wl,--disable-new-dtags $LIB_FUZZING_ENGINE" \
+ --nonshared-binary=ALL \
+ "$@" \
+ LINK_CC="$CXX"
+
+make -j
+
+# Make a directory for the system shared libraries to be copied into
+mkdir -p $OUT/lib
+
+# oss-fuzz would prefer for all the binaries put into $OUT to be
+# statically linked.
+#
+# We can't static link to all the system libs with waf, so copy the
+# libraries we need to $OUT/lib and set the rpath to point there.
+# This is similar to how firefox handles this.
+#
+# NOTE on RPATH vs RUNPATH:
+#
+# RUNPATH appears to be the more modern version, and so modern ld.bfd
+# and ld.gold only set RUNPATH. RUNPATH makes sense on most systems,
+# but not for our hack.
+#
+# If we use RUNPATH, we can get an error like this:
+# Step #6: Error occurred while running fuzz_nmblib_parse_packet:
+# Step #6: /workspace/out/coverage/fuzz_nmblib_parse_packet: error while loading shared libraries: libavahi-common.so.3: cannot open shared object file: No such file or directory
+#
+# This is because the full contents of $OUT are copied to yet another
+# host, which otherwise does not have much of linux at all. oss-fuzz
+# prefers a static binary because that will 'just work', but we can't
+# do that, so we need to use linker tricks.
+#
+# If the linker used RUNPATH (eg ld.bfd on Ubuntu 18.04 and later, ld.gold):
+# * bin=fuzz_nmblib_parse_packet
+# * OUT=/tmp/3/b12207/prefix/samba-fuzz
+# * chrpath -r '$ORIGIN/lib' $OUT/$bin'
+# * ldd $OUT/$bin
+# linux-vdso.so.1 (0x00007ffd4b7a5000)
+# libasan.so.5 => /tmp/3/b12207/prefix/samba-fuzz/lib/libasan.so.5 (0x00007ff25bdd0000)
+# libldap_r-2.4.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libldap_r-2.4.so.2 (0x00007ff25bd7a000)
+# liblber-2.4.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/liblber-2.4.so.2 (0x00007ff25bd69000)
+# libunwind-x86_64.so.8 => /tmp/3/b12207/prefix/samba-fuzz/lib/libunwind-x86_64.so.8 (0x00007ff25bd47000)
+# libunwind.so.8 => /tmp/3/b12207/prefix/samba-fuzz/lib/libunwind.so.8 (0x00007ff25bd2a000)
+# libgnutls.so.30 => /tmp/3/b12207/prefix/samba-fuzz/lib/libgnutls.so.30 (0x00007ff25bb54000)
+# libdl.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libdl.so.2 (0x00007ff25bb4c000)
+# libz.so.1 => /tmp/3/b12207/prefix/samba-fuzz/lib/libz.so.1 (0x00007ff25bb30000)
+# libjansson.so.4 => /tmp/3/b12207/prefix/samba-fuzz/lib/libjansson.so.4 (0x00007ff25bb21000)
+# libresolv.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libresolv.so.2 (0x00007ff25bb05000)
+# libsystemd.so.0 => /tmp/3/b12207/prefix/samba-fuzz/lib/libsystemd.so.0 (0x00007ff25ba58000)
+# libpthread.so.0 => /tmp/3/b12207/prefix/samba-fuzz/lib/libpthread.so.0 (0x00007ff25ba35000)
+# libicuuc.so.66 => /tmp/3/b12207/prefix/samba-fuzz/lib/libicuuc.so.66 (0x00007ff25b84d000)
+# libicui18n.so.66 => /tmp/3/b12207/prefix/samba-fuzz/lib/libicui18n.so.66 (0x00007ff25b54e000)
+# libcap.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libcap.so.2 (0x00007ff25b545000)
+# libbsd.so.0 => /tmp/3/b12207/prefix/samba-fuzz/lib/libbsd.so.0 (0x00007ff25b52b000)
+# libnsl.so.1 => /tmp/3/b12207/prefix/samba-fuzz/lib/libnsl.so.1 (0x00007ff25b50e000)
+# libc.so.6 => /tmp/3/b12207/prefix/samba-fuzz/lib/libc.so.6 (0x00007ff25b31c000)
+# librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff25b2f2000)
+# libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff25b1a3000)
+# libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff25b188000)
+# libsasl2.so.2 => /usr/lib/x86_64-linux-gnu/libsasl2.so.2 (0x00007ff25b16b000)
+# libgssapi.so.3 => /usr/lib/x86_64-linux-gnu/libgssapi.so.3 (0x00007ff25b126000)
+# liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007ff25b0fd000)
+# /lib64/ld-linux-x86-64.so.2 (0x00007ff25ea0c000)
+# libp11-kit.so.0 => /usr/lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007ff25afc5000)
+# libidn2.so.0 => /usr/lib/x86_64-linux-gnu/libidn2.so.0 (0x00007ff25afa4000)
+# libunistring.so.2 => /usr/lib/x86_64-linux-gnu/libunistring.so.2 (0x00007ff25ae22000)
+# libtasn1.so.6 => /usr/lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007ff25ae0c000)
+# libnettle.so.7 => /usr/lib/x86_64-linux-gnu/libnettle.so.7 (0x00007ff25add2000)
+# libhogweed.so.5 => /usr/lib/x86_64-linux-gnu/libhogweed.so.5 (0x00007ff25ad9a000)
+# libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007ff25ad14000)
+# liblz4.so.1 => /usr/lib/x86_64-linux-gnu/liblz4.so.1 (0x00007ff25acf3000)
+# libgcrypt.so.20 => /usr/lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007ff25abd5000)
+# libicudata.so.66 => /usr/lib/x86_64-linux-gnu/libicudata.so.66 (0x00007ff259114000)
+# libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff258f33000)
+# libheimntlm.so.0 => /usr/lib/x86_64-linux-gnu/libheimntlm.so.0 (0x00007ff258f25000)
+# libkrb5.so.26 => /usr/lib/x86_64-linux-gnu/libkrb5.so.26 (0x00007ff258e92000)
+# libasn1.so.8 => /usr/lib/x86_64-linux-gnu/libasn1.so.8 (0x00007ff258deb000)
+# libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007ff258de4000)
+# libhcrypto.so.4 => /usr/lib/x86_64-linux-gnu/libhcrypto.so.4 (0x00007ff258dac000)
+# libroken.so.18 => /usr/lib/x86_64-linux-gnu/libroken.so.18 (0x00007ff258d93000)
+# libffi.so.7 => /usr/lib/x86_64-linux-gnu/libffi.so.7 (0x00007ff258d85000)
+# libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007ff258d62000)
+# libwind.so.0 => /usr/lib/x86_64-linux-gnu/libwind.so.0 (0x00007ff258d38000)
+# libheimbase.so.1 => /usr/lib/x86_64-linux-gnu/libheimbase.so.1 (0x00007ff258d26000)
+# libhx509.so.5 => /usr/lib/x86_64-linux-gnu/libhx509.so.5 (0x00007ff258cd8000)
+# libsqlite3.so.0 => /usr/lib/x86_64-linux-gnu/libsqlite3.so.0 (0x00007ff258bad000)
+# libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007ff258b72000)
+#
+# Note how all the dependencies of libc and gnutls are not forced to
+# $OUT/lib (via the magic $ORIGIN variable, meaning the directory of
+# the binary). These will not be found on the target system!
+#
+# If the linker used RPATH however
+# * bin=fuzz_nmblib_parse_packet
+# * OUT=/tmp/3/b22/prefix/samba-fuzz
+# * chrpath -r '$ORIGIN/lib' $OUT/$bin'
+# * ldd $OUT/$bin
+# linux-vdso.so.1 => (0x00007ffef85c7000)
+# libasan.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libasan.so.2 (0x00007f3668b4f000)
+# libldap_r-2.4.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libldap_r-2.4.so.2 (0x00007f36688fe000)
+# liblber-2.4.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/liblber-2.4.so.2 (0x00007f36686ef000)
+# libunwind-x86_64.so.8 => /tmp/3/b22/prefix/samba-fuzz/lib/libunwind-x86_64.so.8 (0x00007f36684d0000)
+# libunwind.so.8 => /tmp/3/b22/prefix/samba-fuzz/lib/libunwind.so.8 (0x00007f36682b5000)
+# libgnutls.so.30 => /tmp/3/b22/prefix/samba-fuzz/lib/libgnutls.so.30 (0x00007f3667f85000)
+# libdl.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libdl.so.2 (0x00007f3667d81000)
+# libz.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libz.so.1 (0x00007f3667b67000)
+# libjansson.so.4 => /tmp/3/b22/prefix/samba-fuzz/lib/libjansson.so.4 (0x00007f366795a000)
+# libresolv.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libresolv.so.2 (0x00007f366773f000)
+# libsystemd.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libsystemd.so.0 (0x00007f366be2f000)
+# libpthread.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libpthread.so.0 (0x00007f3667522000)
+# libicuuc.so.55 => /tmp/3/b22/prefix/samba-fuzz/lib/libicuuc.so.55 (0x00007f366718e000)
+# libicui18n.so.55 => /tmp/3/b22/prefix/samba-fuzz/lib/libicui18n.so.55 (0x00007f3666d2c000)
+# libcap.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libcap.so.2 (0x00007f3666b26000)
+# libbsd.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libbsd.so.0 (0x00007f3666911000)
+# libnsl.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libnsl.so.1 (0x00007f36666f8000)
+# libc.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libc.so.6 (0x00007f366632e000)
+# libm.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libm.so.6 (0x00007f3666025000)
+# libgcc_s.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libgcc_s.so.1 (0x00007f3665e0f000)
+# libsasl2.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libsasl2.so.2 (0x00007f3665bf4000)
+# libgssapi.so.3 => /tmp/3/b22/prefix/samba-fuzz/lib/libgssapi.so.3 (0x00007f36659b3000)
+# liblzma.so.5 => /tmp/3/b22/prefix/samba-fuzz/lib/liblzma.so.5 (0x00007f3665791000)
+# /lib64/ld-linux-x86-64.so.2 (0x00007f366bc93000)
+# libp11-kit.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libp11-kit.so.0 (0x00007f366552d000)
+# libidn.so.11 => /tmp/3/b22/prefix/samba-fuzz/lib/libidn.so.11 (0x00007f36652fa000)
+# libtasn1.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libtasn1.so.6 (0x00007f36650e7000)
+# libnettle.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libnettle.so.6 (0x00007f3664eb1000)
+# libhogweed.so.4 => /tmp/3/b22/prefix/samba-fuzz/lib/libhogweed.so.4 (0x00007f3664c7e000)
+# libgmp.so.10 => /tmp/3/b22/prefix/samba-fuzz/lib/libgmp.so.10 (0x00007f36649fe000)
+# libselinux.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libselinux.so.1 (0x00007f36647dc000)
+# librt.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/librt.so.1 (0x00007f36645d4000)
+# libgcrypt.so.20 => /tmp/3/b22/prefix/samba-fuzz/lib/libgcrypt.so.20 (0x00007f36642f3000)
+# libicudata.so.55 => /tmp/3/b22/prefix/samba-fuzz/lib/libicudata.so.55 (0x00007f366283c000)
+# libstdc++.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libstdc++.so.6 (0x00007f36624ba000)
+# libheimntlm.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libheimntlm.so.0 (0x00007f36622b1000)
+# libkrb5.so.26 => /tmp/3/b22/prefix/samba-fuzz/lib/libkrb5.so.26 (0x00007f3662027000)
+# libasn1.so.8 => /tmp/3/b22/prefix/samba-fuzz/lib/libasn1.so.8 (0x00007f3661d85000)
+# libcom_err.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libcom_err.so.2 (0x00007f3661b81000)
+# libhcrypto.so.4 => /tmp/3/b22/prefix/samba-fuzz/lib/libhcrypto.so.4 (0x00007f366194e000)
+# libroken.so.18 => /tmp/3/b22/prefix/samba-fuzz/lib/libroken.so.18 (0x00007f3661738000)
+# libffi.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libffi.so.6 (0x00007f3661530000)
+# libpcre.so.3 => /tmp/3/b22/prefix/samba-fuzz/lib/libpcre.so.3 (0x00007f36612c0000)
+# libgpg-error.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libgpg-error.so.0 (0x00007f36610ac000)
+# libwind.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libwind.so.0 (0x00007f3660e83000)
+# libheimbase.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libheimbase.so.1 (0x00007f3660c74000)
+# libhx509.so.5 => /tmp/3/b22/prefix/samba-fuzz/lib/libhx509.so.5 (0x00007f3660a29000)
+# libsqlite3.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libsqlite3.so.0 (0x00007f3660754000)
+# libcrypt.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libcrypt.so.1 (0x00007f366051c000)
+#
+# See how the runtime linker seems to honour the RPATH for
+# dependencies of dependencies in this case. This helps us us lot.
+
+for x in bin/fuzz_*; do
+ # Copy any system libraries needed by this fuzzer to $OUT/lib.
+
+ # We run ldd on $x, the fuzz_binary in bin/ which has not yet had
+ # the RPATH altered. This is clearer for debugging in local
+ # development builds as $OUT is not cleaned between runs.
+ #
+ # Otherwise trying to re-run this can see cp can fail with:
+ # cp: '/out/lib/libgcc_s.so.1' and '/out/lib/libgcc_s.so.1' are the same file
+ # which is really confusing!
+
+ # The cut for ( and ' ' removes the special case references to:
+ # linux-vdso.so.1 => (0x00007ffe8f2b2000)
+ # /lib64/ld-linux-x86-64.so.2 (0x00007fc63ea6f000)
+
+ ldd $x | cut -f 2 -d '>' | cut -f 1 -d \( | cut -f 2 -d ' ' | xargs -i cp \{\} $OUT/lib/
+
+ cp $x $OUT/
+ bin=$(basename $x)
+
+ # This means the copied libraries are found on the runner.
+ #
+ # The binaries should we built with RPATH, not RUNPATH, to allow
+ # libraries used by libraries to be found. This command retains the
+ # RPATH/RUNPATH header and only changes the path. We later verify this
+ # in the check_build.sh script.
+ chrpath -r '$ORIGIN/lib' $OUT/$bin
+
+ # Truncate the original binary to save space
+ echo -n >$x
+
+done
+
+# Strip RUNPATH: or RPATH: entries from shared libraries copied over to $OUT/lib.
+# When those libraries get loaded and have further dependencies, a RUNPATH: header
+# will cause the dynamic linker to search in the runpath, and not in $OUT/lib,
+# and there's no way it will be found in the fuzzing env.
+#
+# So how is the indirect dependency found in $OUT/lib? Well, suppose the fuzzer binary
+# links library A which links library B. During linking, both A and B as listed in the
+# executable file's runtime dependencies (This was pioneered in Fedora 13 in 2010, but
+# is common behavior now). So we have the fuzzer binary with RPATH set to $OUT/lib, and
+# a dependency on library B, and it will therefore find library B in $OUT/lib. On the
+# hand, if we keep the RUNPATH in library A, and load A first, it will try loading
+# library B as a dependency of A from the wrong place.
+chrpath -d $OUT/lib/*
+
+# Grab the seeds dictionary from github and put the seed zips in place
+# beside their executables.
+
+wget https://gitlab.com/samba-team/samba-fuzz-seeds/-/jobs/artifacts/master/download?job=zips \
+ -O seeds.zip
+
+# We might not have unzip, but we do have python
+$PYTHON -mzipfile -e seeds.zip $OUT
+rm -f seeds.zip
diff --git a/lib/fuzzing/patches/collect-access-check-seeds.txt b/lib/fuzzing/patches/collect-access-check-seeds.txt
new file mode 100644
index 0000000..db85f40
--- /dev/null
+++ b/lib/fuzzing/patches/collect-access-check-seeds.txt
@@ -0,0 +1,256 @@
+From b461fdf28c71b54ad5ebe663ea09212856e61973 Mon Sep 17 00:00:00 2001
+From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+Date: Mon, 17 Jul 2023 16:17:16 +1200
+Subject: [PATCH 1/2] libcli/security: save access check attempts for fuzz
+ examples
+
+If this patch is applied to a Samba tree, and the
+SAMBA_SAVE_ACCESS_CHECK_DIR environment variable points to a
+directory, the tokens and descriptors of all access checks will be
+stored in that directory in the form used by
+fuzz_security_token_vs_descriptor. This can be used to build up a
+corpus of seeds for the fuzzer.
+
+The steps to create the corpus go something like this:
+
+$ export SAMBA_SAVE_ACCESS_CHECK_DIR=/tmp/samba-seeds
+$ mkdir $SAMBA_SAVE_ACCESS_CHECK_DIR
+$ mkdir /tmp/final-seeds-go-here
+$ make test
+
+at this point you'd want to do something like this:
+
+$ for f in $SAMBA_SAVE_ACCESS_CHECK_DIR/*; do \
+ cp -n $f /tmp/final-seeds-go-here/$(md5sum $f | cut -d' ' -f 1) \
+ done
+
+but it takes way too long, so use the script in the second patch in
+this series, like so:
+
+$ script/find-unique-access-seeds \
+ $SAMBA_SAVE_ACCESS_CHECK_DIR \
+ /tmp/final-seeds-go-here/
+
+Think before applying this patch in production. It won't slow things
+down much, but it will capture your SIDs and ACLs.
+
+Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+---
+ libcli/security/access_check.c | 79 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 79 insertions(+)
+
+diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c
+index 1364a15f4dd..d79a247455a 100644
+--- a/libcli/security/access_check.c
++++ b/libcli/security/access_check.c
+@@ -26,6 +26,8 @@
+ #include "libcli/security/security.h"
+ #include "librpc/gen_ndr/conditional_ace.h"
+ #include "libcli/security/conditional_ace.h"
++#include "ndr/libndr.h"
++#include "gen_ndr/ndr_security.h"
+
+ /* Map generic access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+@@ -105,6 +107,77 @@ void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mappi
+ }
+ }
+
++
++static bool write_token_and_descriptor(const struct security_descriptor *sd,
++ const struct security_token *token,
++ uint32_t access_desired)
++{
++ /*
++ * You should not be seeing this function in master or a release
++ * branch! It should only be here if you have patched Samba to
++ * generate fuzz seeds for fuzz_security_token_vs_descriptor.
++ *
++ * It hooks into access_check functions, saving copies of each access
++ * request in a structure for use as a fuzz seed, into the directory
++ * specified by the SAMBA_SAVE_ACCESS_CHECK_DIR environment variable.
++ *
++ * If the environment variable is not set, nothing will happen.
++ *
++ * A full `make test` saves about four million files, but only about
++ * forty thousand of them are unique.
++ */
++ FILE *f = NULL;
++ char buf[200];
++ int len;
++ DATA_BLOB blob = {0};
++ uint pid;
++ struct security_token_descriptor_fuzzing_pair p = {
++ .token = *token,
++ .sd = *sd,
++ .access_desired = access_desired
++ };
++ static size_t n = 0;
++ enum ndr_err_code ndr_err;
++ static const char *dir = NULL;
++ TALLOC_CTX *tmp_ctx = NULL;
++
++ if (dir == NULL) {
++ if (n == SIZE_MAX) {
++ return true;
++ }
++ dir = getenv("SAMBA_SAVE_ACCESS_CHECK_DIR");
++ if (dir == NULL) {
++ n = SIZE_MAX;
++ return false;
++ }
++ }
++ tmp_ctx = talloc_new(NULL);
++ if (tmp_ctx == NULL) {
++ return false;
++ }
++
++ n++;
++ ndr_err = ndr_push_struct_blob(
++ &blob, tmp_ctx, &p,
++ (ndr_push_flags_fn_t)ndr_push_security_token_descriptor_fuzzing_pair);
++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
++ TALLOC_FREE(tmp_ctx);
++ return false;
++ }
++ pid = getpid();
++ len = snprintf(buf, sizeof(buf), "%s/%08u-%05zu.seed", dir, pid, n);
++ if (len >= sizeof(buf)) {
++ TALLOC_FREE(tmp_ctx);
++ return false;
++ }
++ f = fopen(buf, "w");
++ fwrite(blob.data, 1, blob.length, f);
++ fclose(f);
++ TALLOC_FREE(tmp_ctx);
++ return true;
++}
++
++
+ /*
+ perform a SEC_FLAG_MAXIMUM_ALLOWED access check
+ */
+@@ -117,6 +190,8 @@ static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
+ bool have_owner_rights_ace = false;
+ unsigned i;
+
++ write_token_and_descriptor(sd, token, SEC_FLAG_MAXIMUM_ALLOWED);
++
+ if (sd->dacl == NULL) {
+ if (security_token_has_sid(token, sd->owner_sid)) {
+ switch (implicit_owner_rights) {
+@@ -222,6 +297,8 @@ static NTSTATUS se_access_check_implicit_owner(const struct security_descriptor
+ bool am_owner = false;
+ bool have_owner_rights_ace = false;
+
++ write_token_and_descriptor(sd, token, access_desired);
++
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+
+@@ -613,6 +690,8 @@ NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd
+ uint32_t bits_remaining;
+ struct dom_sid self_sid;
+
++ write_token_and_descriptor(sd, token, access_desired);
++
+ dom_sid_parse(SID_NT_SELF, &self_sid);
+
+ *access_granted = access_desired;
+--
+2.34.1
+
+
+From 12bf242cece202658fe61f1c7408709d092632ea Mon Sep 17 00:00:00 2001
+From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+Date: Tue, 18 Jul 2023 16:07:11 +1200
+Subject: [PATCH 2/2] scripts: a script for deduplicating fuzz-seeds
+
+The previous patch adds a way to collect two million fuzz seeds, only
+a few thousand of which are unique. This script finds the unique ones.
+
+Some fuzzers like seeds to have names based on md5 hashes, so we do that.
+
+The naive technique takes ages.
+
+Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+---
+ script/find-unique-access-seeds | 66 +++++++++++++++++++++++++++++++++
+ 1 file changed, 66 insertions(+)
+ create mode 100755 script/find-unique-access-seeds
+
+diff --git a/script/find-unique-access-seeds b/script/find-unique-access-seeds
+new file mode 100755
+index 00000000000..174e811ecd0
+--- /dev/null
++++ b/script/find-unique-access-seeds
+@@ -0,0 +1,66 @@
++#!/usr/bin/env python3
++#
++# Copyright (C) Catalyst IT Ltd. 2023
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++"""USAGE: find-unique-access-seeds SRCDIR DESTDIR
++
++Copy the files in SRCDIR to DESTDIR with the name set to the
++md5sum of the contents. DESTDIR will thus have no duplicates.
++
++This is the same as going:
++
++ for f in $SRC/*; do
++ cp $f $DEST/$(md5sum $f | cut -d' ' -f 1)
++ done
++
++but much more efficient.
++"""
++
++
++import sys
++import os
++from pathlib import Path
++from hashlib import md5
++
++
++def usage(ret):
++ print(__doc__)
++ exit(ret)
++
++
++def main():
++ if {'-h', '--help'}.intersection(sys.argv):
++ usage(0)
++ if len(sys.argv) != 3:
++ usage(1)
++
++ src, dest = sys.argv[1:]
++ sp = Path(src)
++ dp = Path(dest)
++
++ strings = set()
++
++ for filename in sp.iterdir():
++ with open(filename, 'rb') as f:
++ strings.add(f.read())
++
++ for s in strings:
++ name = md5(s).hexdigest()
++ with open(dp / name, "wb") as f:
++ f.write(s)
++
++
++main()
+--
+2.34.1
+
diff --git a/lib/fuzzing/wscript_build b/lib/fuzzing/wscript_build
new file mode 100644
index 0000000..5a98013
--- /dev/null
+++ b/lib/fuzzing/wscript_build
@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+
+from waflib import Build
+
+bld.SAMBA_SUBSYSTEM('fuzzing',
+ source='fuzzing.c',
+ deps='talloc')
+
+bld.SAMBA_SUBSYSTEM('afl-fuzz-main',
+ source='afl-fuzz-main.c',
+ deps='samba-util',
+ enabled=bld.env.enable_afl_fuzzer
+ )
+
+bld.SAMBA_BINARY('fuzz_tiniparser',
+ source='fuzz_tiniparser.c',
+ deps='fuzzing tiniparser talloc afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_parse_lpq_entry',
+ source='fuzz_parse_lpq_entry.c',
+ deps='fuzzing afl-fuzz-main smbd_base PRINTING',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_oLschema2ldif',
+ source='fuzz_oLschema2ldif.c',
+ deps='fuzzing oLschema2ldif-lib afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_reg_parse',
+ source='fuzz_reg_parse.c',
+ deps='fuzzing samba3-util smbconf REGFIO afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_sddl_parse',
+ source='fuzz_sddl_parse.c',
+ deps='fuzzing samba-security afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_sess_crypt_blob',
+ source='fuzz_sess_crypt_blob.c',
+ deps='fuzzing samba-security LIBCLI_AUTH NDR_DSSETUP afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_conditional_ace_blob',
+ source='fuzz_conditional_ace_blob.c',
+ deps='fuzzing samba-security afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_nmblib_parse_packet',
+ source='fuzz_nmblib_parse_packet.c',
+ deps='fuzzing libsmb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_sddl_access_check',
+ source='fuzz_sddl_access_check.c',
+ deps='fuzzing samba-security afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_sddl_access_check_ds',
+ cflags='-DFUZZ_SEC_ACCESS_CHECK_DS=1',
+ source='fuzz_sddl_access_check.c',
+ deps='fuzzing samba-security afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_regfio',
+ source='fuzz_regfio.c',
+ deps='fuzzing samba3-util smbconf REGFIO afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress',
+ source='fuzz_lzxpress.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress_compress',
+ source='fuzz_lzxpress_compress.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress_round_trip',
+ source='fuzz_lzxpress_round_trip.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress_huffman_decompress',
+ source='fuzz_lzxpress_huffman_decompress.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress_huffman_compress',
+ source='fuzz_lzxpress_huffman_compress.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress_huffman_round_trip',
+ source='fuzz_lzxpress_huffman_round_trip.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldap_decode',
+ source='fuzz_ldap_decode.c',
+ deps='fuzzing cli-ldap afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_parse_control',
+ source='fuzz_ldb_parse_control.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_dn_explode',
+ source='fuzz_ldb_dn_explode.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_ldif_read',
+ source='fuzz_ldb_ldif_read.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_parse_binary_decode',
+ source='fuzz_ldb_parse_binary_decode.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_parse_tree',
+ source='fuzz_ldb_parse_tree.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_comparison_fold',
+ source='fuzz_ldb_comparison_fold.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_dcerpc_parse_binding',
+ source='fuzz_dcerpc_parse_binding.c',
+ deps='fuzzing dcerpc afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_cli_credentials_parse_string',
+ source='fuzz_cli_credentials_parse_string.c',
+ deps='fuzzing samba-credentials afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_stable_sort',
+ source='fuzz_stable_sort.c',
+ deps='fuzzing stable_sort afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_stable_sort_r',
+ source='fuzz_stable_sort_r.c',
+ deps='fuzzing stable_sort afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_security_token_vs_descriptor',
+ source='fuzz_security_token_vs_descriptor.c',
+ deps='fuzzing samba-security afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_security_token_vs_descriptor_ds',
+ cflags='-DFUZZ_SEC_ACCESS_CHECK_DS=1',
+ source='fuzz_security_token_vs_descriptor.c',
+ deps='fuzzing samba-security afl-fuzz-main',
+ fuzzer=True)
+
+
+# The fuzz_type and fuzz_function parameters make the built
+# fuzzer take the same input as ndrdump and so the same that
+# could be sent to the client or server as the stub data.
+
+def SAMBA_NDR_FUZZ(bld, interface, auto_deps=False,
+ fuzz_type=None, fuzz_function=None):
+ name = "fuzz_ndr_%s" % (interface.lower())
+ fuzz_dir = os.path.join(bld.env.srcdir, 'lib/fuzzing')
+ fuzz_reldir = os.path.relpath(fuzz_dir, bld.path.abspath())
+ fuzz_src = os.path.join(fuzz_reldir, 'fuzz_ndr_X.c')
+
+ cflags = "-D FUZZ_PIPE_TABLE=ndr_table_%s" % interface
+ if fuzz_type:
+ name += "_%s" % (fuzz_type)
+ cflags += " -D FUZZ_TYPE=%s " % (fuzz_type)
+ if fuzz_type and fuzz_function:
+ name += "_%d" % (fuzz_function)
+ cflags += " -D FUZZ_FUNCTION=%d" % (fuzz_function)
+
+ fuzz_named_src = os.path.join(fuzz_reldir,
+ '%s.c' % (name))
+ # Work around an issue that WAF is invoked from up to 3 different
+ # directories so doesn't create a unique name for the multiple .o
+ # files like it would if called from just one place.
+ bld.SAMBA_GENERATOR(fuzz_named_src,
+ source=fuzz_src,
+ target=fuzz_named_src,
+ rule='cp ${SRC} ${TGT}')
+
+ if auto_deps:
+ deps = "afl-fuzz-main talloc ndr NDR_%s" % interface.upper()
+ else:
+ deps = "afl-fuzz-main ndr-table NDR_DCERPC"
+
+ bld.SAMBA_BINARY(name, source=fuzz_named_src,
+ cflags = cflags,
+ deps = deps,
+ fuzzer=True)
+
+Build.BuildContext.SAMBA_NDR_FUZZ = SAMBA_NDR_FUZZ
+
+# fuzz_ndr_X is generated from the list of IDL fed to PIDL
+# however there are exceptions to the normal pattern
+bld.SAMBA_NDR_FUZZ('iremotewinspool') # winspool.idl
+bld.SAMBA_NDR_FUZZ('FileServerVssAgent') # fsvrp.idl
+bld.SAMBA_NDR_FUZZ('lsarpc') # lsa.idl
+bld.SAMBA_NDR_FUZZ('netdfs') # dfs.idl
+bld.SAMBA_NDR_FUZZ('nfs4acl_interface') # nfs4acl.idl
+bld.SAMBA_NDR_FUZZ('rpcecho') # echo.idl
+
+# quota.idl
+bld.SAMBA_NDR_FUZZ('file_quota')
+bld.SAMBA_NDR_FUZZ('smb2_query_quota')
+bld.SAMBA_NDR_FUZZ('smb1_nt_transact_query_quota')
+
+# ioctl.idl
+bld.SAMBA_NDR_FUZZ('copychunk')
+bld.SAMBA_NDR_FUZZ('compression')
+bld.SAMBA_NDR_FUZZ('netinterface')
+bld.SAMBA_NDR_FUZZ('sparse')
+bld.SAMBA_NDR_FUZZ('resiliency')
+bld.SAMBA_NDR_FUZZ('trim')
+
+# Specific struct or function on the interface
+
+bld.SAMBA_NDR_FUZZ('spoolss',
+ auto_deps=True,
+ fuzz_type="TYPE_IN",
+ fuzz_function=65)
diff --git a/lib/krb5_wrap/enctype_convert.c b/lib/krb5_wrap/enctype_convert.c
new file mode 100644
index 0000000..4a64435
--- /dev/null
+++ b/lib/krb5_wrap/enctype_convert.c
@@ -0,0 +1,108 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Kerberos utility functions
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "krb5_samba.h"
+#include "librpc/gen_ndr/netlogon.h"
+
+const krb5_enctype *samba_all_enctypes(void)
+{
+ /* TODO: Find a way not to have to use a fixed list */
+ static const krb5_enctype enctypes[] = {
+ ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ ENCTYPE_ARCFOUR_HMAC,
+ 0
+ };
+ return enctypes;
+};
+
+/* Translate between the IETF encryption type values and the Microsoft
+ * msDS-SupportedEncryptionTypes values */
+uint32_t kerberos_enctype_to_bitmap(krb5_enctype enc_type_enum)
+{
+ switch (enc_type_enum) {
+ case ENCTYPE_DES_CBC_CRC:
+ return ENC_CRC32;
+ case ENCTYPE_DES_CBC_MD5:
+ return ENC_RSA_MD5;
+ case ENCTYPE_ARCFOUR_HMAC:
+ return ENC_RC4_HMAC_MD5;
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ return ENC_HMAC_SHA1_96_AES128;
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return ENC_HMAC_SHA1_96_AES256;
+ default:
+ return 0;
+ }
+}
+
+/* Translate between the Microsoft msDS-SupportedEncryptionTypes values
+ * and the IETF encryption type values */
+krb5_enctype ms_suptype_to_ietf_enctype(uint32_t enctype_bitmap)
+{
+ switch (enctype_bitmap) {
+ case ENC_CRC32:
+ return ENCTYPE_DES_CBC_CRC;
+ case ENC_RSA_MD5:
+ return ENCTYPE_DES_CBC_MD5;
+ case ENC_RC4_HMAC_MD5:
+ return ENCTYPE_ARCFOUR_HMAC;
+ case ENC_HMAC_SHA1_96_AES128:
+ return ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ case ENC_HMAC_SHA1_96_AES256:
+ return ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ default:
+ return 0;
+ }
+}
+
+/* Return an array of krb5_enctype values */
+krb5_error_code ms_suptypes_to_ietf_enctypes(TALLOC_CTX *mem_ctx,
+ uint32_t enctype_bitmap,
+ krb5_enctype **enctypes)
+{
+ size_t max_bits = 8 * sizeof(enctype_bitmap);
+ size_t j = 0;
+ ssize_t i;
+
+ *enctypes = talloc_zero_array(mem_ctx, krb5_enctype,
+ max_bits + 1);
+ if (!*enctypes) {
+ return ENOMEM;
+ }
+
+ for (i = max_bits - 1; i >= 0; i--) {
+ uint32_t bit_value = (1U << i) & enctype_bitmap;
+ if (bit_value & enctype_bitmap) {
+ (*enctypes)[j] = ms_suptype_to_ietf_enctype(bit_value);
+ if (!(*enctypes)[j]) {
+ continue;
+ }
+ j++;
+ }
+ }
+ (*enctypes)[j] = 0;
+ return 0;
+}
diff --git a/lib/krb5_wrap/gss_samba.c b/lib/krb5_wrap/gss_samba.c
new file mode 100644
index 0000000..a594056
--- /dev/null
+++ b/lib/krb5_wrap/gss_samba.c
@@ -0,0 +1,222 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Simple GSSAPI wrappers
+ *
+ * Copyright (c) 2012 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "gss_samba.h"
+
+#ifdef HAVE_GSSAPI
+
+#if !defined(HAVE_GSS_OID_EQUAL)
+int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid)
+{
+ if (first_oid == GSS_C_NO_OID || second_oid == GSS_C_NO_OID) {
+ return 0;
+ }
+
+ if (first_oid == second_oid) {
+ return 1;
+ }
+
+ if ((first_oid)->length != (second_oid)->length) {
+ return 0;
+ }
+
+ if (memcmp((first_oid)->elements, (second_oid)->elements,
+ (first_oid)->length) == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* !HAVE_GSS_OID_EQUAL */
+
+
+/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
+ * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
+ * interposed by GSSPROXY while gss_krb5_import_cred() is not.
+ *
+ * This wrapper requires a proper krb5_context to resolve ccache name.
+ * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
+uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
+ krb5_ccache id, krb5_principal keytab_principal,
+ krb5_keytab keytab, gss_cred_id_t *cred)
+{
+ uint32_t major_status = 0;
+
+#ifdef HAVE_GSS_ACQUIRE_CRED_FROM
+ uint32_t minor = 0;
+ gss_key_value_element_desc ccache_element = {
+ .key = "ccache",
+ .value = NULL,
+ };
+
+ gss_key_value_element_desc keytab_element = {
+ .key = "keytab",
+ .value = NULL,
+ };
+
+ gss_key_value_element_desc elements[2];
+
+ gss_key_value_set_desc cred_store = {
+ .elements = &ccache_element,
+ .count = 1,
+ };
+
+ /* we are interested exclusively in krb5 credentials,
+ * indicate to GSSAPI that we are not interested in any other
+ * mechanism here */
+ gss_OID_set_desc mech_set = {
+ .count = 1,
+ .elements = discard_const_p(struct gss_OID_desc_struct,
+ gss_mech_krb5),
+ };
+
+ gss_cred_usage_t cred_usage = GSS_C_INITIATE;
+ gss_name_t name = NULL;
+ gss_buffer_desc pr_name = {
+ .value = NULL,
+ .length = 0,
+ };
+
+ if (id != NULL) {
+ major_status = krb5_cc_get_full_name(ctx,
+ id,
+ discard_const(&ccache_element.value));
+ if (major_status != 0) {
+ return major_status;
+ }
+ }
+
+ if (keytab != NULL) {
+ keytab_element.value = malloc(4096);
+ if (!keytab_element.value) {
+ return ENOMEM;
+ }
+ major_status = krb5_kt_get_name(ctx,
+ keytab,
+ discard_const(keytab_element.value), 4096);
+ if (major_status != 0) {
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ cred_usage = GSS_C_ACCEPT;
+ cred_store.elements = &keytab_element;
+
+ if (keytab_principal != NULL) {
+ major_status = krb5_unparse_name(ctx, keytab_principal, (char**)&pr_name.value);
+ if (major_status != 0) {
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ pr_name.length = strlen(pr_name.value);
+
+ major_status = gss_import_name(minor_status,
+ &pr_name,
+ discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
+ &name);
+ if (major_status != 0) {
+ krb5_free_unparsed_name(ctx, pr_name.value);
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ }
+ }
+
+ if (id != NULL && keytab != NULL) {
+ elements[0] = ccache_element;
+ elements[1] = keytab_element;
+
+ cred_store.elements = elements;
+ cred_store.count = 2;
+ cred_usage = GSS_C_BOTH;
+ }
+
+ major_status = gss_acquire_cred_from(minor_status,
+ name,
+ 0,
+ &mech_set,
+ cred_usage,
+ &cred_store,
+ cred,
+ NULL,
+ NULL);
+
+ if (pr_name.value != NULL) {
+ (void)gss_release_name(&minor, &name);
+ krb5_free_unparsed_name(ctx, pr_name.value);
+ }
+ if (keytab_element.value != NULL) {
+ free(discard_const(keytab_element.value));
+ }
+ krb5_free_string(ctx, discard_const(ccache_element.value));
+#else
+ major_status = gss_krb5_import_cred(minor_status,
+ id,
+ keytab_principal,
+ keytab, cred);
+
+ if (major_status == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
+ if ((keytab_principal == NULL) && (keytab != NULL)) {
+ /* No principal was specified and MIT krb5 1.9 version failed.
+ * We have to fall back to set global acceptor identity */
+ gss_OID_set_desc mech_set;
+ char *kt_name = NULL;
+
+ kt_name = malloc(4096);
+ if (!kt_name) {
+ return ENOMEM;
+ }
+
+ major_status = krb5_kt_get_name(ctx,
+ keytab,
+ kt_name, 4096);
+ if (major_status != 0) {
+ free(kt_name);
+ return major_status;
+ }
+
+ major_status = gsskrb5_register_acceptor_identity(kt_name);
+ if (major_status) {
+ free(kt_name);
+ return major_status;
+ }
+
+ /* We are dealing with krb5 GSSAPI mech in this fallback */
+ mech_set.count = 1;
+ mech_set.elements =
+ discard_const_p(struct gss_OID_desc_struct,
+ gss_mech_krb5);
+ major_status = gss_acquire_cred(minor_status,
+ GSS_C_NO_NAME,
+ GSS_C_INDEFINITE,
+ &mech_set,
+ GSS_C_ACCEPT,
+ cred,
+ NULL, NULL);
+ free(kt_name);
+ }
+ }
+#endif
+ return major_status;
+}
+
+
+#endif /* HAVE_GSSAPI */
diff --git a/lib/krb5_wrap/gss_samba.h b/lib/krb5_wrap/gss_samba.h
new file mode 100644
index 0000000..89aee34
--- /dev/null
+++ b/lib/krb5_wrap/gss_samba.h
@@ -0,0 +1,49 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Simple GSSAPI wrappers
+ *
+ * Copyright (c) 2012 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GSS_SAMBA_H
+#define _GSS_SAMBA_H
+
+#ifdef HAVE_GSSAPI
+
+#include "system/gssapi.h"
+#include "krb5_samba.h"
+
+#if defined(HAVE_GSS_OID_EQUAL)
+#define smb_gss_oid_equal gss_oid_equal
+#else
+int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid);
+#endif /* HAVE_GSS_OID_EQUAL */
+
+/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
+ * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
+ * interposed by GSS-proxy while gss_krb5_import_cred() is not.
+ *
+ * This wrapper requires a proper krb5_context to resolve the ccache name for
+ * gss_acquire_cred_from().
+ *
+ * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
+uint32_t smb_gss_krb5_import_cred(OM_uint32 *minor_status, krb5_context ctx,
+ krb5_ccache id, krb5_principal keytab_principal,
+ krb5_keytab keytab, gss_cred_id_t *cred);
+
+#endif /* HAVE_GSSAPI */
+#endif /* _GSS_SAMBA_H */
diff --git a/lib/krb5_wrap/keytab_util.c b/lib/krb5_wrap/keytab_util.c
new file mode 100644
index 0000000..ba8a79c
--- /dev/null
+++ b/lib/krb5_wrap/keytab_util.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2011 Andrew Bartlett
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 INSTITUTE OR CONTRIBUTORS 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.
+ */
+
+#include "includes.h"
+#include "krb5_samba.h"
+
+#if !defined(HAVE_KRB5_KT_COMPARE)
+krb5_boolean smb_krb5_kt_compare(krb5_context context,
+ krb5_keytab_entry *entry,
+ krb5_const_principal principal,
+ krb5_kvno kvno,
+ krb5_enctype enctype)
+{
+ if (principal) {
+ if (!krb5_principal_compare(context,
+ entry->principal, principal)) {
+ return false;
+ }
+ }
+ if (kvno) {
+ if (entry->vno != kvno) {
+ return false;
+ }
+ }
+ if (enctype) {
+ if (KRB5_KEY_TYPE(KRB5_KT_KEY(entry)) != enctype) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif
diff --git a/lib/krb5_wrap/krb5_errs.c b/lib/krb5_wrap/krb5_errs.c
new file mode 100644
index 0000000..d602b61
--- /dev/null
+++ b/lib/krb5_wrap/krb5_errs.c
@@ -0,0 +1,115 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Kerberos error mapping functions
+ * Copyright (C) Guenther Deschner 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "krb5_samba.h"
+
+#ifdef HAVE_KRB5
+
+static const struct {
+ krb5_error_code krb5_code;
+ NTSTATUS ntstatus;
+} krb5_to_nt_status_map[] = {
+ {KRB5_CC_IO, NT_STATUS_UNEXPECTED_IO_ERROR},
+ {KRB5KDC_ERR_BADOPTION, NT_STATUS_INVALID_PARAMETER},
+ {KRB5KDC_ERR_CLIENT_REVOKED, NT_STATUS_ACCOUNT_LOCKED_OUT},
+ {KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, NT_STATUS_INVALID_ACCOUNT_NAME},
+ {KRB5KDC_ERR_ETYPE_NOSUPP, NT_STATUS_LOGON_FAILURE},
+#if defined(KRB5KDC_ERR_KEY_EXP) /* MIT */
+ {KRB5KDC_ERR_KEY_EXP, NT_STATUS_PASSWORD_EXPIRED},
+#else /* old Heimdal releases have it with different name only in an enum: */
+ {KRB5KDC_ERR_KEY_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+#endif
+ {25, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: bug in heimdal 0.7 krb5_get_init_creds_password (Inappropriate ioctl for device (25)) */
+ {KRB5KDC_ERR_NULL_KEY, NT_STATUS_LOGON_FAILURE},
+ {KRB5KDC_ERR_POLICY, NT_STATUS_INVALID_WORKSTATION},
+ {KRB5KDC_ERR_PREAUTH_FAILED, NT_STATUS_LOGON_FAILURE},
+ {KRB5KDC_ERR_SERVICE_REVOKED, NT_STATUS_ACCESS_DENIED},
+ {KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, NT_STATUS_INVALID_COMPUTER_NAME},
+ {KRB5KDC_ERR_SUMTYPE_NOSUPP, NT_STATUS_LOGON_FAILURE},
+ {KRB5KDC_ERR_TGT_REVOKED, NT_STATUS_ACCESS_DENIED},
+ {KRB5_KDC_UNREACH, NT_STATUS_NO_LOGON_SERVERS},
+ {KRB5KRB_AP_ERR_BAD_INTEGRITY, NT_STATUS_LOGON_FAILURE},
+ {KRB5KRB_AP_ERR_MODIFIED, NT_STATUS_LOGON_FAILURE},
+ {KRB5KRB_AP_ERR_SKEW, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {KRB5_KDCREP_SKEW, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {KRB5KRB_AP_ERR_TKT_EXPIRED, NT_STATUS_LOGON_FAILURE},
+ {KRB5KRB_ERR_GENERIC, NT_STATUS_UNSUCCESSFUL},
+#if defined(KRB5KRB_ERR_RESPONSE_TOO_BIG)
+ {KRB5KRB_ERR_RESPONSE_TOO_BIG, NT_STATUS_PROTOCOL_UNREACHABLE},
+#endif
+ {KRB5_CC_NOTFOUND, NT_STATUS_NO_SUCH_FILE},
+ {KRB5_FCC_NOFILE, NT_STATUS_NO_SUCH_FILE},
+ {KRB5_RC_MALLOC, NT_STATUS_NO_MEMORY},
+ {ENOMEM, NT_STATUS_NO_MEMORY},
+ {KRB5_REALM_CANT_RESOLVE, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+ {KRB5_REALM_UNKNOWN, NT_STATUS_NO_SUCH_DOMAIN},
+
+ /* Must be last entry */
+ {KRB5KDC_ERR_NONE, NT_STATUS_OK}
+};
+
+static const struct {
+ NTSTATUS ntstatus;
+ krb5_error_code krb5_code;
+} nt_status_to_krb5_map[] = {
+ {NT_STATUS_LOGON_FAILURE, KRB5KDC_ERR_PREAUTH_FAILED},
+ {NT_STATUS_NO_LOGON_SERVERS, KRB5_KDC_UNREACH},
+ {NT_STATUS_OK, 0}
+};
+
+/*****************************************************************************
+convert a KRB5 error to a NT status32 code
+ *****************************************************************************/
+ NTSTATUS krb5_to_nt_status(krb5_error_code kerberos_error)
+{
+ int i;
+
+ if (kerberos_error == 0) {
+ return NT_STATUS_OK;
+ }
+
+ for (i=0; NT_STATUS_V(krb5_to_nt_status_map[i].ntstatus); i++) {
+ if (kerberos_error == krb5_to_nt_status_map[i].krb5_code)
+ return krb5_to_nt_status_map[i].ntstatus;
+ }
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a KRB5 error
+ *****************************************************************************/
+ krb5_error_code nt_status_to_krb5(NTSTATUS nt_status)
+{
+ int i;
+
+ if NT_STATUS_IS_OK(nt_status) {
+ return 0;
+ }
+
+ for (i=0; NT_STATUS_V(nt_status_to_krb5_map[i].ntstatus); i++) {
+ if (NT_STATUS_EQUAL(nt_status,nt_status_to_krb5_map[i].ntstatus))
+ return nt_status_to_krb5_map[i].krb5_code;
+ }
+
+ return KRB5KRB_ERR_GENERIC;
+}
+
+#endif
diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
new file mode 100644
index 0000000..116f916
--- /dev/null
+++ b/lib/krb5_wrap/krb5_samba.c
@@ -0,0 +1,4043 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5 routines for active directory
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Luke Howard 2002-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Guenther Deschner 2005-2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "krb5_samba.h"
+#include "lib/crypto/md4.h"
+#include "../libds/common/flags.h"
+
+#ifdef HAVE_COM_ERR_H
+#include <com_err.h>
+#endif /* HAVE_COM_ERR_H */
+
+#ifndef KRB5_AUTHDATA_WIN2K_PAC
+#define KRB5_AUTHDATA_WIN2K_PAC 128
+#endif
+
+#ifndef KRB5_AUTHDATA_IF_RELEVANT
+#define KRB5_AUTHDATA_IF_RELEVANT 1
+#endif
+
+#ifdef HAVE_KRB5
+
+#define GSSAPI_CHECKSUM 0x8003 /* Checksum type value for Kerberos */
+#define GSSAPI_BNDLENGTH 16 /* Bind Length (rfc-1964 pg.3) */
+#define GSSAPI_CHECKSUM_SIZE (4+GSSAPI_BNDLENGTH+4) /* Length of bind length,
+ bind field, flags field. */
+#define GSS_C_DELEG_FLAG 1
+
+/* MIT krb5 1.7beta3 (in Ubuntu Karmic) is missing the prototype,
+ but still has the symbol */
+#if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE
+krb5_error_code krb5_auth_con_set_req_cksumtype(
+ krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_cksumtype cksumtype);
+#endif
+
+#if !defined(SMB_MALLOC)
+#undef malloc
+#define SMB_MALLOC(s) malloc((s))
+#endif
+
+#ifndef SMB_STRDUP
+#define SMB_STRDUP(s) strdup(s)
+#endif
+
+/**********************************************************
+ * MISSING FUNCTIONS
+ **********************************************************/
+
+#if !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
+
+#if defined(HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES)
+
+/* With MIT kerberos, we should use krb5_set_default_tgs_enctypes in preference
+ * to krb5_set_default_tgs_ktypes. See
+ * http://lists.samba.org/archive/samba-technical/2006-July/048271.html
+ *
+ * If the MIT libraries are not exporting internal symbols, we will end up in
+ * this branch, which is correct. Otherwise we will continue to use the
+ * internal symbol
+ */
+ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
+{
+ return krb5_set_default_tgs_enctypes(ctx, enc);
+}
+
+#elif defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES)
+
+/* Heimdal */
+ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
+{
+ return krb5_set_default_in_tkt_etypes(ctx, enc);
+}
+
+#endif /* HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES */
+
+#endif /* HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
+
+
+#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
+krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *keyblock)
+{
+ return krb5_auth_con_setkey(context, auth_context, keyblock);
+}
+#endif
+
+#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
+void krb5_free_unparsed_name(krb5_context context, char *val)
+{
+ SAFE_FREE(val);
+}
+#endif
+
+#if !defined(HAVE_KRB5_FREE_ENCTYPES)
+void krb5_free_enctypes(krb5_context context, krb5_enctype *val) {
+ krb5_xfree(val);
+}
+#endif
+
+#if !defined(HAVE_KRB5_FREE_STRING)
+void krb5_free_string(krb5_context context, char *val) {
+ SAFE_FREE(val);
+}
+#endif
+
+krb5_error_code smb_krb5_princ_component(krb5_context context,
+ krb5_const_principal principal,
+ int i,
+ krb5_data *data);
+krb5_error_code smb_krb5_princ_component(krb5_context context,
+ krb5_const_principal principal,
+ int i,
+ krb5_data *data)
+{
+#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT)
+ const char *component = NULL;
+
+ if (i < 0) {
+ return EINVAL;
+ }
+
+ component = krb5_principal_get_comp_string(context, principal, i);
+ if (component == NULL) {
+ return ENOENT;
+ }
+
+ *data = smb_krb5_make_data(discard_const_p(char, component), strlen(component));
+
+ return 0;
+#else
+ const krb5_data *kdata = NULL;
+
+ if (i < 0) {
+ return EINVAL;
+ }
+
+ kdata = krb5_princ_component(context, principal, i);
+ if (kdata == NULL) {
+ return ENOENT;
+ }
+
+ *data = *kdata;
+
+ return 0;
+#endif
+}
+
+/**********************************************************
+ * WRAPPING FUNCTIONS
+ **********************************************************/
+
+/**
+ * @brief Stores the address of a 'struct sockaddr_storage' into a krb5_address
+ *
+ * @param[in] paddr A pointer to a 'struct sockaddr_storage to extract the
+ * address from.
+ *
+ * @param[out] pkaddr A Kerberos address to store the address in.
+ *
+ * @return True on success, false if an error occurred.
+ */
+bool smb_krb5_sockaddr_to_kaddr(struct sockaddr_storage *paddr,
+ krb5_address *pkaddr)
+{
+ memset(pkaddr, '\0', sizeof(krb5_address));
+#if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
+/* HEIMDAL */
+#ifdef HAVE_IPV6
+ if (paddr->ss_family == AF_INET6) {
+ pkaddr->addr_type = KRB5_ADDRESS_INET6;
+ pkaddr->address.length = sizeof(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ pkaddr->address.data = (char *)&(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ return true;
+ }
+#endif
+ if (paddr->ss_family == AF_INET) {
+ pkaddr->addr_type = KRB5_ADDRESS_INET;
+ pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
+ pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
+ return true;
+ }
+#elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
+/* MIT */
+#ifdef HAVE_IPV6
+ if (paddr->ss_family == AF_INET6) {
+ pkaddr->addrtype = ADDRTYPE_INET6;
+ pkaddr->length = sizeof(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in6 *)paddr)->sin6_addr);
+ return true;
+ }
+#endif
+ if (paddr->ss_family == AF_INET) {
+ pkaddr->addrtype = ADDRTYPE_INET;
+ pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
+ pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr);
+ return true;
+ }
+#else
+#error UNKNOWN_ADDRTYPE
+#endif
+ return false;
+}
+
+krb5_error_code smb_krb5_mk_error(krb5_context context,
+ krb5_error_code error_code,
+ const char *e_text,
+ krb5_data *e_data,
+ const krb5_principal client,
+ const krb5_principal server,
+ krb5_data *enc_err)
+{
+ krb5_error_code code = EINVAL;
+#ifdef SAMBA4_USES_HEIMDAL
+ code = krb5_mk_error(context,
+ error_code,
+ e_text,
+ e_data,
+ client,
+ server,
+ NULL, /* client_time */
+ NULL, /* client_usec */
+ enc_err);
+#else
+ krb5_principal unspec_server = NULL;
+ krb5_error errpkt;
+
+ errpkt.ctime = 0;
+ errpkt.cusec = 0;
+
+ code = krb5_us_timeofday(context,
+ &errpkt.stime,
+ &errpkt.susec);
+ if (code != 0) {
+ return code;
+ }
+
+ errpkt.error = error_code - ERROR_TABLE_BASE_krb5;
+
+ errpkt.text.length = 0;
+ if (e_text != NULL) {
+ errpkt.text = smb_krb5_make_data(discard_const_p(char, e_text), strlen(e_text));
+ }
+
+ errpkt.e_data = smb_krb5_make_data(NULL, 0);
+ if (e_data != NULL) {
+ errpkt.e_data = *e_data;
+ }
+
+ errpkt.client = client;
+
+ if (server != NULL) {
+ errpkt.server = server;
+ } else {
+ code = smb_krb5_make_principal(context,
+ &unspec_server,
+ "<unspecified realm>",
+ NULL);
+ if (code != 0) {
+ return code;
+ }
+ errpkt.server = unspec_server;
+ }
+
+ code = krb5_mk_error(context,
+ &errpkt,
+ enc_err);
+ krb5_free_principal(context, unspec_server);
+#endif
+ return code;
+}
+
+/**
+* @brief Create a keyblock based on input parameters
+*
+* @param context The krb5_context
+* @param host_princ The krb5_principal to use
+* @param salt The optional salt, if omitted, salt is calculated with
+* the provided principal.
+* @param password The krb5_data containing the password
+* @param enctype The krb5_enctype to use for the keyblock generation
+* @param key The returned krb5_keyblock, caller needs to free with
+* krb5_free_keyblock().
+*
+* @return krb5_error_code
+*/
+int smb_krb5_create_key_from_string(krb5_context context,
+ krb5_const_principal host_princ,
+ const krb5_data *salt,
+ const krb5_data *password,
+ krb5_enctype enctype,
+ krb5_keyblock *key)
+{
+ int ret = 0;
+
+ if (host_princ == NULL && salt == NULL) {
+ return -1;
+ }
+
+ if ((int)enctype == (int)ENCTYPE_ARCFOUR_HMAC) {
+ TALLOC_CTX *frame = talloc_stackframe();
+ uint8_t *utf16 = NULL;
+ size_t utf16_size = 0;
+ uint8_t nt_hash[16];
+ bool ok;
+
+ ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16LE,
+ password->data, password->length,
+ &utf16, &utf16_size);
+ if (!ok) {
+ if (errno == 0) {
+ errno = EINVAL;
+ }
+ ret = errno;
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ mdfour(nt_hash, utf16, utf16_size);
+ BURN_PTR_SIZE(utf16, utf16_size);
+ ret = smb_krb5_keyblock_init_contents(context,
+ ENCTYPE_ARCFOUR_HMAC,
+ nt_hash,
+ sizeof(nt_hash),
+ key);
+ ZERO_STRUCT(nt_hash);
+ if (ret != 0) {
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+ }
+
+#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_C_STRING_TO_KEY)
+{/* MIT */
+ krb5_data _salt;
+
+ if (salt == NULL) {
+ ret = krb5_principal2salt(context, host_princ, &_salt);
+ if (ret) {
+ DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+ } else {
+ _salt = *salt;
+ }
+ ret = krb5_c_string_to_key(context, enctype, password, &_salt, key);
+ if (salt == NULL) {
+ SAFE_FREE(_salt.data);
+ }
+}
+#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
+{/* Heimdal */
+ krb5_salt _salt;
+
+ if (salt == NULL) {
+ ret = krb5_get_pw_salt(context, host_princ, &_salt);
+ if (ret) {
+ DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+ } else {
+ _salt.saltvalue = *salt;
+ _salt.salttype = KRB5_PW_SALT;
+ }
+
+ ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, _salt, key);
+ if (salt == NULL) {
+ krb5_free_salt(context, _salt);
+ }
+}
+#else
+#error UNKNOWN_CREATE_KEY_FUNCTIONS
+#endif
+ return ret;
+}
+
+/**
+* @brief Create a salt for a given principal
+*
+* @param context The initialized krb5_context
+* @param host_princ The krb5_principal to create the salt for
+* @param psalt A pointer to a krb5_data struct
+*
+* caller has to free the contents of psalt with smb_krb5_free_data_contents
+* when function has succeeded
+*
+* @return krb5_error_code, returns 0 on success, error code otherwise
+*/
+
+int smb_krb5_get_pw_salt(krb5_context context,
+ krb5_const_principal host_princ,
+ krb5_data *psalt)
+#if defined(HAVE_KRB5_GET_PW_SALT)
+/* Heimdal */
+{
+ int ret;
+ krb5_salt salt;
+
+ ret = krb5_get_pw_salt(context, host_princ, &salt);
+ if (ret) {
+ return ret;
+ }
+
+ *psalt = salt.saltvalue;
+
+ return ret;
+}
+#elif defined(HAVE_KRB5_PRINCIPAL2SALT)
+/* MIT */
+{
+ return krb5_principal2salt(context, host_princ, psalt);
+}
+#else
+#error UNKNOWN_SALT_FUNCTIONS
+#endif
+
+/**
+ * @brief This constructs the salt principal used by active directory
+ *
+ * Most Kerberos encryption types require a salt in order to
+ * calculate the long term private key for user/computer object
+ * based on a password.
+ *
+ * The returned _salt_principal is a string in forms like this:
+ * - host/somehost.example.com@EXAMPLE.COM
+ * - SomeAccount@EXAMPLE.COM
+ * - SomePrincipal@EXAMPLE.COM
+ *
+ * This is not the form that's used as salt, it's just
+ * the human readable form. It needs to be converted by
+ * smb_krb5_salt_principal2data().
+ *
+ * @param[in] realm The realm the user/computer is added too.
+ *
+ * @param[in] sAMAccountName The sAMAccountName attribute of the object.
+ *
+ * @param[in] userPrincipalName The userPrincipalName attribute of the object
+ * or NULL if not available.
+ *
+ * @param[in] uac_flags UF_ACCOUNT_TYPE_MASKed userAccountControl field
+ *
+ * @param[in] mem_ctx The TALLOC_CTX to allocate _salt_principal.
+ *
+ * @param[out] _salt_principal The resulting principal as string.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ *
+ * @see smb_krb5_salt_principal2data
+ */
+int smb_krb5_salt_principal(krb5_context krb5_ctx,
+ const char *realm,
+ const char *sAMAccountName,
+ const char *userPrincipalName,
+ uint32_t uac_flags,
+ krb5_principal *salt_princ)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *upper_realm = NULL;
+ const char *principal = NULL;
+ int principal_len = 0;
+ krb5_error_code krb5_ret;
+
+ *salt_princ = NULL;
+
+ if (sAMAccountName == NULL) {
+ TALLOC_FREE(frame);
+ return EINVAL;
+ }
+
+ if (realm == NULL) {
+ TALLOC_FREE(frame);
+ return EINVAL;
+ }
+
+ if (uac_flags & ~UF_ACCOUNT_TYPE_MASK) {
+ /*
+ * catch callers which still
+ * pass 'true'.
+ */
+ TALLOC_FREE(frame);
+ return EINVAL;
+ }
+ if (uac_flags == 0) {
+ /*
+ * catch callers which still
+ * pass 'false'.
+ */
+ TALLOC_FREE(frame);
+ return EINVAL;
+ }
+
+ upper_realm = strupper_talloc(frame, realm);
+ if (upper_realm == NULL) {
+ TALLOC_FREE(frame);
+ return ENOMEM;
+ }
+
+ /* Many, many thanks to lukeh@padl.com for this
+ * algorithm, described in his Nov 10 2004 mail to
+ * samba-technical@lists.samba.org */
+
+ /*
+ * Determine a salting principal
+ */
+ if (uac_flags & UF_TRUST_ACCOUNT_MASK) {
+ int computer_len = 0;
+
+ computer_len = strlen(sAMAccountName);
+ if (sAMAccountName[computer_len-1] == '$') {
+ computer_len -= 1;
+ }
+
+ if (uac_flags & UF_INTERDOMAIN_TRUST_ACCOUNT) {
+ const char *krbtgt = "krbtgt";
+ krb5_ret = krb5_build_principal_ext(krb5_ctx,
+ salt_princ,
+ strlen(upper_realm),
+ upper_realm,
+ strlen(krbtgt),
+ krbtgt,
+ computer_len,
+ sAMAccountName,
+ 0);
+ if (krb5_ret != 0) {
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
+ } else {
+ const char *host = "host";
+ char *tmp = NULL;
+ char *tmp_lower = NULL;
+
+ tmp = talloc_asprintf(frame, "%*.*s.%s",
+ computer_len,
+ computer_len,
+ sAMAccountName,
+ realm);
+ if (tmp == NULL) {
+ TALLOC_FREE(frame);
+ return ENOMEM;
+ }
+
+ tmp_lower = strlower_talloc(frame, tmp);
+ if (tmp_lower == NULL) {
+ TALLOC_FREE(frame);
+ return ENOMEM;
+ }
+
+ krb5_ret = krb5_build_principal_ext(krb5_ctx,
+ salt_princ,
+ strlen(upper_realm),
+ upper_realm,
+ strlen(host),
+ host,
+ strlen(tmp_lower),
+ tmp_lower,
+ 0);
+ if (krb5_ret != 0) {
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
+ }
+
+ } else if (userPrincipalName != NULL) {
+ /*
+ * We parse the name not only to allow an easy
+ * replacement of the realm (no matter the realm in
+ * the UPN, the salt comes from the upper-case real
+ * realm, but also to correctly provide a salt when
+ * the UPN is host/foo.bar
+ *
+ * This can fail for a UPN of the form foo@bar@REALM
+ * (which is accepted by windows) however.
+ */
+ krb5_ret = krb5_parse_name(krb5_ctx,
+ userPrincipalName,
+ salt_princ);
+
+ if (krb5_ret != 0) {
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
+
+ /*
+ * No matter what realm (including none) in the UPN,
+ * the realm is replaced with our upper-case realm
+ */
+ krb5_ret = smb_krb5_principal_set_realm(krb5_ctx,
+ *salt_princ,
+ upper_realm);
+ if (krb5_ret != 0) {
+ krb5_free_principal(krb5_ctx, *salt_princ);
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
+ } else {
+ principal = sAMAccountName;
+ principal_len = strlen(principal);
+
+ krb5_ret = krb5_build_principal_ext(krb5_ctx,
+ salt_princ,
+ strlen(upper_realm),
+ upper_realm,
+ principal_len,
+ principal,
+ 0);
+ if (krb5_ret != 0) {
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+/**
+ * @brief This constructs the salt principal used by active directory
+ *
+ * Most Kerberos encryption types require a salt in order to
+ * calculate the long term private key for user/computer object
+ * based on a password.
+ *
+ * The returned _salt_principal is a string in forms like this:
+ * - host/somehost.example.com@EXAMPLE.COM
+ * - SomeAccount@EXAMPLE.COM
+ * - SomePrincipal@EXAMPLE.COM
+ *
+ * This is not the form that's used as salt, it's just
+ * the human readable form. It needs to be converted by
+ * smb_krb5_salt_principal2data().
+ *
+ * @param[in] realm The realm the user/computer is added too.
+ *
+ * @param[in] sAMAccountName The sAMAccountName attribute of the object.
+ *
+ * @param[in] userPrincipalName The userPrincipalName attribute of the object
+ * or NULL if not available.
+ *
+ * @param[in] uac_flags UF_ACCOUNT_TYPE_MASKed userAccountControl field
+ *
+ * @param[in] mem_ctx The TALLOC_CTX to allocate _salt_principal.
+ *
+ * @param[out] _salt_principal The resulting principal as string.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ *
+ * @see smb_krb5_salt_principal2data
+ */
+int smb_krb5_salt_principal_str(const char *realm,
+ const char *sAMAccountName,
+ const char *userPrincipalName,
+ uint32_t uac_flags,
+ TALLOC_CTX *mem_ctx,
+ char **_salt_principal_str)
+{
+ krb5_principal salt_principal = NULL;
+ char *salt_principal_malloc;
+ krb5_context krb5_ctx;
+ krb5_error_code krb5_ret
+ = smb_krb5_init_context_common(&krb5_ctx);
+ if (krb5_ret != 0) {
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(krb5_ret));
+ return krb5_ret;
+ }
+
+ krb5_ret = smb_krb5_salt_principal(krb5_ctx,
+ realm,
+ sAMAccountName,
+ userPrincipalName,
+ uac_flags,
+ &salt_principal);
+ if (krb5_ret != 0) {
+ DBG_ERR("unable to create salt principal:%s\n",
+ error_message(krb5_ret));
+ return krb5_ret;
+ }
+
+ krb5_ret = krb5_unparse_name(krb5_ctx, salt_principal,
+ &salt_principal_malloc);
+ if (krb5_ret != 0) {
+ krb5_free_principal(krb5_ctx, salt_principal);
+ DBG_ERR("kerberos unparse of salt principal failed (%s)\n",
+ error_message(krb5_ret));
+ return krb5_ret;
+ }
+ krb5_free_principal(krb5_ctx, salt_principal);
+ *_salt_principal_str
+ = talloc_strdup(mem_ctx, salt_principal_malloc);
+ krb5_free_unparsed_name(krb5_ctx, salt_principal_malloc);
+
+ if (*_salt_principal_str == NULL) {
+ return ENOMEM;
+ }
+ return 0;
+}
+
+/**
+ * @brief Converts the salt principal string into the salt data blob
+ *
+ * This function takes a salt_principal as string in forms like this:
+ * - host/somehost.example.com@EXAMPLE.COM
+ * - SomeAccount@EXAMPLE.COM
+ * - SomePrincipal@EXAMPLE.COM
+ *
+ * It generates values like:
+ * - EXAMPLE.COMhost/somehost.example.com
+ * - EXAMPLE.COMSomeAccount
+ * - EXAMPLE.COMSomePrincipal
+ *
+ * @param[in] realm The realm the user/computer is added too.
+ *
+ * @param[in] sAMAccountName The sAMAccountName attribute of the object.
+ *
+ * @param[in] userPrincipalName The userPrincipalName attribute of the object
+ * or NULL if not available.
+ *
+ * @param[in] is_computer The indication of the object includes
+ * objectClass=computer.
+ *
+ * @param[in] mem_ctx The TALLOC_CTX to allocate _salt_principal.
+ *
+ * @param[out] _salt_principal The resulting principal as string.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ *
+ * @see smb_krb5_salt_principal
+ */
+int smb_krb5_salt_principal2data(krb5_context context,
+ const char *salt_principal,
+ TALLOC_CTX *mem_ctx,
+ char **_salt_data)
+{
+ krb5_error_code ret;
+ krb5_principal salt_princ = NULL;
+ krb5_data salt;
+
+ *_salt_data = NULL;
+
+ ret = krb5_parse_name(context, salt_principal, &salt_princ);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = smb_krb5_get_pw_salt(context, salt_princ, &salt);
+ krb5_free_principal(context, salt_princ);
+ if (ret != 0) {
+ return ret;
+ }
+
+ *_salt_data = talloc_strndup(mem_ctx,
+ (char *)salt.data,
+ salt.length);
+ smb_krb5_free_data_contents(context, &salt);
+ if (*_salt_data == NULL) {
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
+/**
+ * @brief Get a list of encryption types allowed for session keys
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] enctypes An allocated, zero-terminated list of encryption types
+ *
+ * This function returns an allocated list of encryption types allowed for
+ * session keys.
+ *
+ * Use krb5_free_enctypes() to free the enctypes when it is no longer needed.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ */
+krb5_error_code smb_krb5_get_allowed_etypes(krb5_context context,
+ krb5_enctype **enctypes)
+{
+ return krb5_get_permitted_enctypes(context, enctypes);
+}
+#elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
+krb5_error_code smb_krb5_get_allowed_etypes(krb5_context context,
+ krb5_enctype **enctypes)
+{
+#ifdef HAVE_KRB5_PDU_NONE_DECL
+ return krb5_get_default_in_tkt_etypes(context, KRB5_PDU_NONE, enctypes);
+#else
+ return krb5_get_default_in_tkt_etypes(context, enctypes);
+#endif
+}
+#else
+#error UNKNOWN_GET_ENCTYPES_FUNCTIONS
+#endif
+
+
+/**
+ * @brief Convert a string principal name to a Kerberos principal.
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] name The principal as a unix charset string.
+ *
+ * @param[out] principal The newly allocated principal.
+ *
+ * Use krb5_free_principal() to free a principal when it is no longer needed.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_parse_name(krb5_context context,
+ const char *name,
+ krb5_principal *principal)
+{
+ krb5_error_code ret;
+ char *utf8_name;
+ size_t converted_size;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (!push_utf8_talloc(frame, &utf8_name, name, &converted_size)) {
+ talloc_free(frame);
+ return ENOMEM;
+ }
+
+ ret = krb5_parse_name(context, utf8_name, principal);
+ if (ret == KRB5_PARSE_MALFORMED) {
+ ret = krb5_parse_name_flags(context, utf8_name,
+ KRB5_PRINCIPAL_PARSE_ENTERPRISE,
+ principal);
+ }
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+/**
+ * @brief Convert a Kerberos principal structure to a string representation.
+ *
+ * The resulting string representation will be a unix charset name and is
+ * talloc'ed.
+ *
+ * @param[in] mem_ctx The talloc context to allocate memory on.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] principal The principal.
+ *
+ * @param[out] unix_name A string representation of the principal name as with
+ * unix charset.
+ *
+ * Use talloc_free() to free the string representation if it is no longer
+ * needed.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_const_principal principal,
+ char **unix_name)
+{
+ krb5_error_code ret;
+ char *utf8_name;
+ size_t converted_size;
+
+ *unix_name = NULL;
+ ret = krb5_unparse_name(context, principal, &utf8_name);
+ if (ret) {
+ return ret;
+ }
+
+ if (!pull_utf8_talloc(mem_ctx, unix_name, utf8_name, &converted_size)) {
+ krb5_free_unparsed_name(context, utf8_name);
+ return ENOMEM;
+ }
+ krb5_free_unparsed_name(context, utf8_name);
+ return 0;
+}
+
+/**
+ * @brief Free the contents of a krb5_data structure and zero the data field.
+ *
+ * @param[in] context The krb5 context
+ *
+ * @param[in] pdata The data structure to free contents of
+ *
+ * This function frees the contents, not the structure itself.
+ */
+void smb_krb5_free_data_contents(krb5_context context, krb5_data *pdata)
+{
+#if defined(HAVE_KRB5_FREE_DATA_CONTENTS)
+ if (pdata->data) {
+ krb5_free_data_contents(context, pdata);
+ }
+#elif defined(HAVE_KRB5_DATA_FREE)
+ krb5_data_free(context, pdata);
+#else
+ SAFE_FREE(pdata->data);
+#endif
+}
+
+/*
+ * @brief copy a buffer into a krb5_data struct
+ *
+ * @param[in] p The krb5_data
+ * @param[in] data The data to copy
+ * @param[in] length The length of the data to copy
+ * @return krb5_error_code
+ *
+ * Caller has to free krb5_data with smb_krb5_free_data_contents().
+ */
+krb5_error_code smb_krb5_copy_data_contents(krb5_data *p,
+ const void *data,
+ size_t len)
+{
+#if defined(HAVE_KRB5_DATA_COPY)
+ return krb5_data_copy(p, data, len);
+#else
+ if (len) {
+ p->data = malloc(len);
+ if (p->data == NULL) {
+ return ENOMEM;
+ }
+ memmove(p->data, data, len);
+ } else {
+ p->data = NULL;
+ }
+ p->length = len;
+ p->magic = KV5M_DATA;
+ return 0;
+#endif
+}
+
+/*
+ * @brief put a buffer reference into a krb5_data struct
+ *
+ * @param[in] data The data to reference
+ * @param[in] length The length of the data to reference
+ * @return krb5_data
+ *
+ * Caller should not free krb5_data.
+ */
+krb5_data smb_krb5_make_data(void *data,
+ size_t len)
+{
+ krb5_data d;
+
+#ifdef SAMBA4_USES_HEIMDAL
+ d.data = (uint8_t *)data;
+ d.length = len;
+#else
+ d.magic = KV5M_DATA;
+ d.data = data;
+ d.length = len;
+#endif
+ return d;
+}
+
+krb5_data smb_krb5_data_from_blob(DATA_BLOB blob)
+{
+ return smb_krb5_make_data(blob.data, blob.length);
+}
+
+bool smb_krb5_get_smb_session_key(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_auth_context auth_context,
+ DATA_BLOB *session_key,
+ bool remote)
+{
+ krb5_keyblock *skey = NULL;
+ krb5_error_code err = 0;
+ bool ret = false;
+
+ if (remote) {
+#ifdef HAVE_KRB5_AUTH_CON_GETRECVSUBKEY
+ err = krb5_auth_con_getrecvsubkey(context,
+ auth_context,
+ &skey);
+#else /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
+ err = krb5_auth_con_getremotesubkey(context,
+ auth_context, &skey);
+#endif /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
+ } else {
+#ifdef HAVE_KRB5_AUTH_CON_GETSENDSUBKEY
+ err = krb5_auth_con_getsendsubkey(context,
+ auth_context,
+ &skey);
+#else /* HAVE_KRB5_AUTH_CON_GETSENDSUBKEY */
+ err = krb5_auth_con_getlocalsubkey(context,
+ auth_context, &skey);
+#endif /* HAVE_KRB5_AUTH_CON_GETSENDSUBKEY */
+ }
+
+ if (err || skey == NULL) {
+ DEBUG(10, ("KRB5 error getting session key %d\n", err));
+ goto done;
+ }
+
+ DEBUG(10, ("Got KRB5 session key of length %d\n",
+ (int)KRB5_KEY_LENGTH(skey)));
+
+ *session_key = data_blob_talloc(mem_ctx,
+ KRB5_KEY_DATA(skey),
+ KRB5_KEY_LENGTH(skey));
+ dump_data_pw("KRB5 Session Key:\n",
+ session_key->data,
+ session_key->length);
+
+ ret = true;
+
+done:
+ if (skey) {
+ krb5_free_keyblock(context, skey);
+ }
+
+ return ret;
+}
+
+
+/**
+ * @brief Get talloced string component of a principal
+ *
+ * @param[in] mem_ctx The TALLOC_CTX
+ * @param[in] context The krb5_context
+ * @param[in] principal The principal
+ * @param[in] component The component
+ * @param[out] out The output string
+ * @return krb5_error_code
+ *
+ * Caller must talloc_free if the return value is not NULL.
+ *
+ */
+krb5_error_code smb_krb5_principal_get_comp_string(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_const_principal principal,
+ unsigned int component,
+ char **out)
+{
+ char *out_str = NULL;
+#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
+ const char *str = NULL;
+
+ str = krb5_principal_get_comp_string(context, principal, component);
+ if (str == NULL) {
+ return ENOENT;
+ }
+
+ out_str = talloc_strdup(mem_ctx, str);
+ if (out_str == NULL) {
+ return ENOMEM;
+ }
+#else
+ krb5_data *data;
+
+ if (component >= krb5_princ_size(context, principal)) {
+ return ENOENT;
+ }
+
+ data = krb5_princ_component(context, principal, component);
+ if (data == NULL) {
+ return ENOENT;
+ }
+
+ out_str = talloc_strndup(mem_ctx, data->data, data->length);
+ if (out_str == NULL) {
+ return ENOMEM;
+ }
+#endif
+ *out = out_str;
+ return 0;
+}
+
+/**
+ * @brief
+ *
+ * @param[in] ccache_string A string pointing to the cache to renew the ticket
+ * (e.g. FILE:/tmp/krb5cc_0) or NULL. If the principal
+ * ccache has not been specified, the default ccache
+ * will be used.
+ *
+ * @param[in] client_string The client principal string (e.g. user@SAMBA.SITE)
+ * or NULL. If the principal string has not been
+ * specified, the principal from the ccache will be
+ * retrieved.
+ *
+ * @param[in] service_string The service ticket string
+ * (e.g. krbtgt/SAMBA.SITE@SAMBA.SITE) or NULL. If
+ * the service ticket is specified, it is parsed
+ * (with the realm part ignored) and used as the
+ * server principal of the credential. Otherwise
+ * the ticket-granting service is used.
+ *
+ * @param[in] expire_time A pointer to store the credentials end time or
+ * NULL.
+ *
+ * @return 0 on Success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_renew_ticket(const char *ccache_string,
+ const char *client_string,
+ const char *service_string,
+ time_t *expire_time)
+{
+ krb5_error_code ret;
+ krb5_context context = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_principal client = NULL;
+ krb5_creds creds, creds_in;
+
+ ZERO_STRUCT(creds);
+ ZERO_STRUCT(creds_in);
+
+ ret = smb_krb5_init_context_common(&context);
+ if (ret) {
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(ret));
+ goto done;
+ }
+
+ if (!ccache_string) {
+ ccache_string = krb5_cc_default_name(context);
+ }
+
+ if (!ccache_string) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ DBG_DEBUG("Using %s as ccache for client '%s' and service '%s'\n",
+ ccache_string, client_string, service_string);
+
+ /* FIXME: we should not fall back to defaults */
+ ret = krb5_cc_resolve(context, discard_const_p(char, ccache_string), &ccache);
+ if (ret) {
+ goto done;
+ }
+
+ if (client_string) {
+ ret = smb_krb5_parse_name(context, client_string, &client);
+ if (ret) {
+ goto done;
+ }
+ } else {
+ ret = krb5_cc_get_principal(context, ccache, &client);
+ if (ret) {
+ goto done;
+ }
+ }
+
+ ret = krb5_get_renewed_creds(context, &creds, client, ccache, discard_const_p(char, service_string));
+ if (ret) {
+ DBG_DEBUG("krb5_get_renewed_creds using ccache '%s' "
+ "for client '%s' and service '%s' failed: %s\n",
+ ccache_string, client_string, service_string,
+ error_message(ret));
+ goto done;
+ }
+
+ /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
+ ret = krb5_cc_initialize(context, ccache, client);
+ if (ret) {
+ goto done;
+ }
+
+ ret = krb5_cc_store_cred(context, ccache, &creds);
+
+ if (expire_time) {
+ *expire_time = (time_t) creds.times.endtime;
+ }
+
+done:
+ krb5_free_cred_contents(context, &creds_in);
+ krb5_free_cred_contents(context, &creds);
+
+ if (client) {
+ krb5_free_principal(context, client);
+ }
+ if (ccache) {
+ krb5_cc_close(context, ccache);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Free the data stored in an smb_krb5_addresses structure.
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] addr The address structure to free.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_free_addresses(krb5_context context,
+ smb_krb5_addresses *addr)
+{
+ krb5_error_code ret = 0;
+ if (addr == NULL) {
+ return ret;
+ }
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ krb5_free_addresses(context, addr->addrs);
+#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
+ ret = krb5_free_addresses(context, addr->addrs);
+ SAFE_FREE(addr->addrs);
+#endif
+ SAFE_FREE(addr);
+ addr = NULL;
+ return ret;
+}
+
+#define MAX_NETBIOSNAME_LEN 16
+
+/**
+ * @brief Add a netbios name to the array of addresses
+ *
+ * @param[in] kerb_addr A pointer to the smb_krb5_addresses to add the
+ * netbios name to.
+ *
+ * @param[in] netbios_name The netbios name to add.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_gen_netbios_krb5_address(smb_krb5_addresses **kerb_addr,
+ const char *netbios_name)
+{
+ krb5_error_code ret = 0;
+ char buf[MAX_NETBIOSNAME_LEN];
+ int len;
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ krb5_address **addrs = NULL;
+#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
+ krb5_addresses *addrs = NULL;
+#endif
+
+ *kerb_addr = (smb_krb5_addresses *)SMB_MALLOC(sizeof(smb_krb5_addresses));
+ if (*kerb_addr == NULL) {
+ return ENOMEM;
+ }
+
+ /* temporarily duplicate put_name() code here to avoid dependency
+ * issues for a 5 lines function */
+ len = strlen(netbios_name);
+ memcpy(buf, netbios_name,
+ (len < MAX_NETBIOSNAME_LEN) ? len : MAX_NETBIOSNAME_LEN - 1);
+ if (len < MAX_NETBIOSNAME_LEN - 1) {
+ memset(buf + len, ' ', MAX_NETBIOSNAME_LEN - 1 - len);
+ }
+ buf[MAX_NETBIOSNAME_LEN - 1] = 0x20;
+
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ {
+ int num_addr = 2;
+
+ addrs = (krb5_address **)SMB_MALLOC(sizeof(krb5_address *) * num_addr);
+ if (addrs == NULL) {
+ SAFE_FREE(*kerb_addr);
+ return ENOMEM;
+ }
+
+ memset(addrs, 0, sizeof(krb5_address *) * num_addr);
+
+ addrs[0] = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
+ if (addrs[0] == NULL) {
+ SAFE_FREE(addrs);
+ SAFE_FREE(*kerb_addr);
+ return ENOMEM;
+ }
+
+ addrs[0]->magic = KV5M_ADDRESS;
+ addrs[0]->addrtype = KRB5_ADDR_NETBIOS;
+ addrs[0]->length = MAX_NETBIOSNAME_LEN;
+ addrs[0]->contents = (unsigned char *)SMB_MALLOC(addrs[0]->length);
+ if (addrs[0]->contents == NULL) {
+ SAFE_FREE(addrs[0]);
+ SAFE_FREE(addrs);
+ SAFE_FREE(*kerb_addr);
+ return ENOMEM;
+ }
+
+ memcpy(addrs[0]->contents, buf, addrs[0]->length);
+
+ addrs[1] = NULL;
+ }
+#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
+ {
+ addrs = (krb5_addresses *)SMB_MALLOC(sizeof(krb5_addresses));
+ if (addrs == NULL) {
+ SAFE_FREE(*kerb_addr);
+ return ENOMEM;
+ }
+
+ memset(addrs, 0, sizeof(krb5_addresses));
+
+ addrs->len = 1;
+ addrs->val = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
+ if (addrs->val == NULL) {
+ SAFE_FREE(addrs);
+ SAFE_FREE(*kerb_addr);
+ return ENOMEM;
+ }
+
+ addrs->val[0].addr_type = KRB5_ADDR_NETBIOS;
+ addrs->val[0].address.length = MAX_NETBIOSNAME_LEN;
+ addrs->val[0].address.data = (unsigned char *)SMB_MALLOC(addrs->val[0].address.length);
+ if (addrs->val[0].address.data == NULL) {
+ SAFE_FREE(addrs->val);
+ SAFE_FREE(addrs);
+ SAFE_FREE(*kerb_addr);
+ return ENOMEM;
+ }
+
+ memcpy(addrs->val[0].address.data, buf, addrs->val[0].address.length);
+ }
+#else
+#error UNKNOWN_KRB5_ADDRESS_FORMAT
+#endif
+ (*kerb_addr)->addrs = addrs;
+
+ return ret;
+}
+
+/**
+ * @brief Get the enctype from a key table entry
+ *
+ * @param[in] kt_entry Key table entry to get the enctype from.
+ *
+ * @return The enctype from the entry.
+ */
+krb5_enctype smb_krb5_kt_get_enctype_from_entry(krb5_keytab_entry *kt_entry)
+{
+ return KRB5_KEY_TYPE(KRB5_KT_KEY(kt_entry));
+}
+
+/**
+ * @brief Free the contents of a key table entry.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] kt_entry The key table entry to free the contents of.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ *
+ * The pointer itself is not freed.
+ */
+krb5_error_code smb_krb5_kt_free_entry(krb5_context context,
+ krb5_keytab_entry *kt_entry)
+{
+/* Try krb5_free_keytab_entry_contents first, since
+ * MIT Kerberos >= 1.7 has both krb5_free_keytab_entry_contents and
+ * krb5_kt_free_entry but only has a prototype for the first, while the
+ * second is considered private.
+ */
+#if defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS)
+ return krb5_free_keytab_entry_contents(context, kt_entry);
+#elif defined(HAVE_KRB5_KT_FREE_ENTRY)
+ return krb5_kt_free_entry(context, kt_entry);
+#else
+#error UNKNOWN_KT_FREE_FUNCTION
+#endif
+}
+
+
+/**
+ * @brief Convert an encryption type to a string.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] enctype The encryption type.
+ *
+ * @param[in] etype_s A pointer to store the allocated encryption type as a
+ * string.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ *
+ * The caller needs to free the allocated string etype_s.
+ */
+krb5_error_code smb_krb5_enctype_to_string(krb5_context context,
+ krb5_enctype enctype,
+ char **etype_s)
+{
+#ifdef HAVE_KRB5_ENCTYPE_TO_STRING_WITH_KRB5_CONTEXT_ARG
+ return krb5_enctype_to_string(context, enctype, etype_s); /* Heimdal */
+#elif defined(HAVE_KRB5_ENCTYPE_TO_STRING_WITH_SIZE_T_ARG)
+ char buf[256];
+ krb5_error_code ret = krb5_enctype_to_string(enctype, buf, 256); /* MIT */
+ if (ret) {
+ return ret;
+ }
+ *etype_s = SMB_STRDUP(buf);
+ if (!*etype_s) {
+ return ENOMEM;
+ }
+ return ret;
+#else
+#error UNKNOWN_KRB5_ENCTYPE_TO_STRING_FUNCTION
+#endif
+}
+
+/* This MAX_NAME_LEN is a constant defined in krb5.h */
+#ifndef MAX_KEYTAB_NAME_LEN
+#define MAX_KEYTAB_NAME_LEN 1100
+#endif
+
+/**
+ * @brief Open a key table readonly or with readwrite access.
+ *
+ * Allows one to use a different keytab than the default one using a relative
+ * path to the keytab.
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] keytab_name_req The path to the key table.
+ *
+ * @param[in] write_access Open with readwrite access.
+ *
+ * @param[in] keytab A pointer to the opened key table.
+ *
+ * The keytab pointer should be freed using krb5_kt_close().
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_kt_open_relative(krb5_context context,
+ const char *keytab_name_req,
+ bool write_access,
+ krb5_keytab *keytab)
+{
+ krb5_error_code ret = 0;
+ TALLOC_CTX *mem_ctx;
+ char keytab_string[MAX_KEYTAB_NAME_LEN];
+ char *kt_str = NULL;
+ bool found_valid_name = false;
+ const char *pragma = "FILE";
+ const char *tmp = NULL;
+
+ if (!write_access && !keytab_name_req) {
+ /* caller just wants to read the default keytab readonly, so be it */
+ return krb5_kt_default(context, keytab);
+ }
+
+ mem_ctx = talloc_init("smb_krb5_kt_open_relative");
+ if (!mem_ctx) {
+ return ENOMEM;
+ }
+
+#ifdef HAVE_WRFILE_KEYTAB
+ if (write_access) {
+ pragma = "WRFILE";
+ }
+#endif
+
+ if (keytab_name_req) {
+
+ if (strlen(keytab_name_req) > MAX_KEYTAB_NAME_LEN) {
+ ret = KRB5_CONFIG_NOTENUFSPACE;
+ goto out;
+ }
+
+ if ((strncmp(keytab_name_req, "WRFILE:", 7) == 0) ||
+ (strncmp(keytab_name_req, "FILE:", 5) == 0)) {
+ tmp = keytab_name_req;
+ goto resolve;
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s:%s", pragma, keytab_name_req);
+ if (!tmp) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ goto resolve;
+ }
+
+ /* we need to handle more complex keytab_strings, like:
+ * "ANY:FILE:/etc/krb5.keytab,krb4:/etc/srvtab" */
+
+ ret = krb5_kt_default_name(context, &keytab_string[0], MAX_KEYTAB_NAME_LEN - 2);
+ if (ret) {
+ goto out;
+ }
+
+ DBG_DEBUG("krb5_kt_default_name returned %s\n", keytab_string);
+
+ tmp = talloc_strdup(mem_ctx, keytab_string);
+ if (!tmp) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ if (strncmp(tmp, "ANY:", 4) == 0) {
+ tmp += 4;
+ }
+
+ memset(&keytab_string, '\0', sizeof(keytab_string));
+
+ while (next_token_talloc(mem_ctx, &tmp, &kt_str, ",")) {
+ if (strncmp(kt_str, "WRFILE:", 7) == 0) {
+ found_valid_name = true;
+ tmp = kt_str;
+ tmp += 7;
+ }
+
+ if (strncmp(kt_str, "FILE:", 5) == 0) {
+ found_valid_name = true;
+ tmp = kt_str;
+ tmp += 5;
+ }
+
+ if (tmp[0] == '/') {
+ /* Treat as a FILE: keytab definition. */
+ found_valid_name = true;
+ }
+
+ if (found_valid_name) {
+ if (tmp[0] != '/') {
+ ret = KRB5_KT_BADNAME;
+ goto out;
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s:%s", pragma, tmp);
+ if (!tmp) {
+ ret = ENOMEM;
+ goto out;
+ }
+ break;
+ }
+ }
+
+ if (!found_valid_name) {
+ ret = KRB5_KT_UNKNOWN_TYPE;
+ goto out;
+ }
+
+resolve:
+ DBG_DEBUG("resolving: %s\n", tmp);
+ ret = krb5_kt_resolve(context, tmp, keytab);
+
+out:
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/**
+ * @brief Open a key table readonly or with readwrite access.
+ *
+ * Allows one to use a different keytab than the default one. The path needs to be
+ * an absolute path or an error will be returned.
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] keytab_name_req The path to the key table.
+ *
+ * @param[in] write_access Open with readwrite access.
+ *
+ * @param[in] keytab A pointer to the opened key table.
+ *
+ * The keytab pointer should be freed using krb5_kt_close().
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_kt_open(krb5_context context,
+ const char *keytab_name_req,
+ bool write_access,
+ krb5_keytab *keytab)
+{
+ int cmp;
+
+ if (keytab_name_req == NULL) {
+ return KRB5_KT_BADNAME;
+ }
+
+ if (keytab_name_req[0] == '/') {
+ goto open_keytab;
+ }
+
+ cmp = strncmp(keytab_name_req, "FILE:/", 6);
+ if (cmp == 0) {
+ goto open_keytab;
+ }
+
+ cmp = strncmp(keytab_name_req, "WRFILE:/", 8);
+ if (cmp == 0) {
+ goto open_keytab;
+ }
+
+ DBG_WARNING("ERROR: Invalid keytab name: %s\n", keytab_name_req);
+
+ return KRB5_KT_BADNAME;
+
+open_keytab:
+ return smb_krb5_kt_open_relative(context,
+ keytab_name_req,
+ write_access,
+ keytab);
+}
+
+/**
+ * @brief Get a key table name.
+ *
+ * @param[in] mem_ctx The talloc context to use for allocation.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] keytab The key table to get the name from.
+ *
+ * @param[in] keytab_name A talloc'ed string of the key table name.
+ *
+ * The talloc'ed name string needs to be freed with talloc_free().
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_kt_get_name(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_keytab keytab,
+ const char **keytab_name)
+{
+ char keytab_string[MAX_KEYTAB_NAME_LEN];
+ krb5_error_code ret = 0;
+
+ ret = krb5_kt_get_name(context, keytab,
+ keytab_string, MAX_KEYTAB_NAME_LEN - 2);
+ if (ret) {
+ return ret;
+ }
+
+ *keytab_name = talloc_strdup(mem_ctx, keytab_string);
+ if (!*keytab_name) {
+ return ENOMEM;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Seek and delete old entries in a keytab based on the passed
+ * principal.
+ *
+ * @param[in] context The KRB5 context to use.
+ *
+ * @param[in] keytab The keytab to operate on.
+ *
+ * @param[in] keep_old_kvno Keep the entries with the previous kvno.
+ *
+ * @param[in] kvno The kvno to use.
+ *
+ * @param[in] enctype_only Only evaluate the enctype argument if true
+ *
+ * @param[in] enctype Only search for entries with the specified enctype
+ *
+ * @param[in] princ_s The principal as a string to search for.
+ *
+ * @param[in] princ The principal as a krb5_principal to search for.
+ *
+ * @param[in] flush Whether to flush the complete keytab.
+ *
+ * @retval 0 on Success
+ *
+ * @return An appropriate KRB5 error code.
+ */
+krb5_error_code smb_krb5_kt_seek_and_delete_old_entries(krb5_context context,
+ krb5_keytab keytab,
+ bool keep_old_kvno,
+ krb5_kvno kvno,
+ bool enctype_only,
+ krb5_enctype enctype,
+ const char *princ_s,
+ krb5_principal princ,
+ bool flush)
+{
+ krb5_error_code ret;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry kt_entry;
+ char *ktprinc = NULL;
+ krb5_kvno old_kvno = kvno - 1;
+ TALLOC_CTX *tmp_ctx;
+
+ if (flush) {
+ SMB_ASSERT(!keep_old_kvno);
+ SMB_ASSERT(!enctype_only);
+ SMB_ASSERT(princ_s == NULL);
+ SMB_ASSERT(princ == NULL);
+ } else {
+ SMB_ASSERT(princ_s != NULL);
+ SMB_ASSERT(princ != NULL);
+ }
+
+ ZERO_STRUCT(cursor);
+ ZERO_STRUCT(kt_entry);
+
+ /*
+ * Start with talloc_new() and only then call krb5_kt_start_seq_get().
+ * If any of them fails, the cleanup code is simpler.
+ */
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret == KRB5_KT_END || ret == ENOENT ) {
+ /* no entries */
+ talloc_free(tmp_ctx);
+ return 0;
+ }
+
+ DEBUG(3, (__location__ ": Will try to delete old keytab entries\n"));
+ while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
+ bool name_ok = false;
+ krb5_enctype kt_entry_enctype =
+ smb_krb5_kt_get_enctype_from_entry(&kt_entry);
+
+ if (princ_s != NULL) {
+ ret = smb_krb5_unparse_name(tmp_ctx, context,
+ kt_entry.principal,
+ &ktprinc);
+ if (ret) {
+ DEBUG(1, (__location__
+ ": smb_krb5_unparse_name failed "
+ "(%s)\n", error_message(ret)));
+ goto out;
+ }
+
+#ifdef HAVE_KRB5_KT_COMPARE
+ name_ok = krb5_kt_compare(context, &kt_entry,
+ princ, 0, 0);
+#else
+ name_ok = (strcmp(ktprinc, princ_s) == 0);
+#endif
+
+ if (!name_ok) {
+ DEBUG(10, (__location__ ": ignoring keytab "
+ "entry principal %s, kvno = %d\n",
+ ktprinc, kt_entry.vno));
+
+ /* Not a match,
+ * just free this entry and continue. */
+ ret = smb_krb5_kt_free_entry(context,
+ &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__
+ ": smb_krb5_kt_free_entry "
+ "failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ TALLOC_FREE(ktprinc);
+ continue;
+ }
+
+ TALLOC_FREE(ktprinc);
+ }
+
+ /*------------------------------------------------------------
+ * Save the entries with kvno - 1. This is what microsoft does
+ * to allow people with existing sessions that have kvno - 1
+ * to still work. Otherwise, when the password for the machine
+ * changes, all kerberized sessions will 'break' until either
+ * the client reboots or the client's session key expires and
+ * they get a new session ticket with the new kvno.
+ * Some keytab files only store the kvno in 8bits, limit
+ * the compare accordingly.
+ */
+
+ if (keep_old_kvno && ((kt_entry.vno & 0xff) == (old_kvno & 0xff))) {
+ DEBUG(5, (__location__ ": Saving previous (kvno %d) "
+ "entry for principal: %s.\n",
+ old_kvno,
+ princ_s != NULL ? princ_s : "UNKNOWN"));
+ continue;
+ }
+
+ if (enctype_only &&
+ ((kt_entry.vno & 0xff) == (kvno & 0xff)) &&
+ (kt_entry_enctype != enctype))
+ {
+ DEBUG(5, (__location__ ": Saving entry with kvno [%d] "
+ "enctype [%d] for principal: %s.\n",
+ kvno, kt_entry_enctype,
+ princ_s != NULL ? princ_s : "UNKNOWN"));
+ continue;
+ }
+
+ DEBUG(5, (__location__ ": Found old entry for principal: %s "
+ "(kvno %d) - trying to remove it.\n",
+ princ_s != NULL ? princ_s : "UNKNOWN",
+ kt_entry.vno));
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_end_seq_get() "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+ DEBUG(5, (__location__ ": removed old entry for principal: "
+ "%s (kvno %d).\n",
+ princ_s != NULL ? princ_s : "UNKNOWN",
+ kt_entry.vno));
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_start_seq() failed "
+ "(%s)\n", error_message(ret)));
+ goto out;
+ }
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+ }
+
+out:
+ talloc_free(tmp_ctx);
+ if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
+ smb_krb5_kt_free_entry(context, &kt_entry);
+ }
+ if (!all_zero((uint8_t *)&cursor, sizeof(cursor))) {
+ krb5_kt_end_seq_get(context, keytab, &cursor);
+ }
+ return ret;
+}
+
+/**
+ * @brief Add a keytab entry for the given principal
+ *
+ * @param[in] context The krb5 context to use.
+ *
+ * @param[in] keytab The keytab to add the entry to.
+ *
+ * @param[in] kvno The kvno to use.
+ *
+ * @param[in] princ_s The principal as a string.
+ *
+ * @param[in] salt_principal The salt principal to salt the password with.
+ * Only needed for keys which support salting.
+ * If no salt is used set no_salt to false and
+ * pass NULL here.
+ *
+ * @param[in] enctype The encryption type of the keytab entry.
+ *
+ * @param[in] password The password of the keytab entry.
+ *
+ * @param[in] no_salt If the password should not be salted. Normally
+ * this is only set to false for encryption types
+ * which do not support salting like RC4.
+ *
+ * @retval 0 on Success
+ *
+ * @return A corresponding KRB5 error code.
+ *
+ * @see smb_krb5_kt_open()
+ */
+krb5_error_code smb_krb5_kt_add_entry(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ const char *princ_s,
+ const char *salt_principal,
+ krb5_enctype enctype,
+ krb5_data *password,
+ bool no_salt)
+{
+ krb5_error_code ret;
+ krb5_keytab_entry kt_entry;
+ krb5_principal princ = NULL;
+ krb5_keyblock *keyp;
+
+ ZERO_STRUCT(kt_entry);
+
+ ret = smb_krb5_parse_name(context, princ_s, &princ);
+ if (ret) {
+ DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
+ "failed (%s)\n", princ_s, error_message(ret)));
+ goto out;
+ }
+
+ /* Seek and delete old keytab entries */
+ ret = smb_krb5_kt_seek_and_delete_old_entries(context,
+ keytab,
+ true, /* keep_old_kvno */
+ kvno,
+ true, /* enctype_only */
+ enctype,
+ princ_s,
+ princ,
+ false); /* flush */
+ if (ret) {
+ goto out;
+ }
+
+ /* If we get here, we have deleted all the old entries with kvno's
+ * not equal to the current kvno-1. */
+
+ keyp = KRB5_KT_KEY(&kt_entry);
+
+ if (no_salt) {
+ KRB5_KEY_DATA(keyp) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
+ if (KRB5_KEY_DATA(keyp) == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ memcpy(KRB5_KEY_DATA(keyp), password->data, password->length);
+ KRB5_KEY_LENGTH(keyp) = password->length;
+ KRB5_KEY_TYPE(keyp) = enctype;
+ } else {
+ krb5_principal salt_princ = NULL;
+
+ /* Now add keytab entries for all encryption types */
+ ret = smb_krb5_parse_name(context, salt_principal, &salt_princ);
+ if (ret) {
+ DBG_WARNING("krb5_parse_name(%s) failed (%s)\n",
+ salt_principal, error_message(ret));
+ goto out;
+ }
+
+ ret = smb_krb5_create_key_from_string(context,
+ salt_princ,
+ NULL,
+ password,
+ enctype,
+ keyp);
+ krb5_free_principal(context, salt_princ);
+ if (ret != 0) {
+ goto out;
+ }
+ }
+
+ kt_entry.principal = princ;
+ kt_entry.vno = kvno;
+
+ DEBUG(3, (__location__ ": adding keytab entry for (%s) with "
+ "encryption type (%d) and version (%d)\n",
+ princ_s, enctype, kt_entry.vno));
+ ret = krb5_kt_add_entry(context, keytab, &kt_entry);
+ krb5_free_keyblock_contents(context, keyp);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1, (__location__ ": adding entry to keytab "
+ "failed (%s)\n", error_message(ret)));
+ goto out;
+ }
+
+out:
+ if (princ) {
+ krb5_free_principal(context, princ);
+ }
+
+ return ret;
+}
+
+#if defined(HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE) && \
+ defined(HAVE_KRB5_GET_CREDS_OPT_ALLOC) && \
+ defined(HAVE_KRB5_GET_CREDS)
+static krb5_error_code smb_krb5_get_credentials_for_user_opt(krb5_context context,
+ krb5_ccache ccache,
+ krb5_principal me,
+ krb5_principal server,
+ krb5_principal impersonate_princ,
+ krb5_creds **out_creds)
+{
+ krb5_error_code ret;
+ krb5_get_creds_opt opt;
+
+ ret = krb5_get_creds_opt_alloc(context, &opt);
+ if (ret) {
+ goto done;
+ }
+ krb5_get_creds_opt_add_options(context, opt, KRB5_GC_FORWARDABLE);
+
+ if (impersonate_princ) {
+ ret = krb5_get_creds_opt_set_impersonate(context, opt,
+ impersonate_princ);
+ if (ret) {
+ goto done;
+ }
+ }
+
+ ret = krb5_get_creds(context, opt, ccache, server, out_creds);
+ if (ret) {
+ goto done;
+ }
+
+ done:
+ if (opt) {
+ krb5_get_creds_opt_free(context, opt);
+ }
+ return ret;
+}
+#endif /* HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE */
+
+#ifdef HAVE_KRB5_GET_CREDENTIALS_FOR_USER
+
+#if !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
+ krb5_ccache ccache, krb5_creds *in_creds,
+ krb5_data *subject_cert,
+ krb5_creds **out_creds);
+#endif /* !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER */
+
+static krb5_error_code smb_krb5_get_credentials_for_user(krb5_context context,
+ krb5_ccache ccache,
+ krb5_principal me,
+ krb5_principal server,
+ krb5_principal impersonate_princ,
+ krb5_creds **out_creds)
+{
+ krb5_error_code ret;
+ krb5_creds in_creds;
+
+ ZERO_STRUCT(in_creds);
+
+ if (impersonate_princ) {
+
+ in_creds.server = me;
+ in_creds.client = impersonate_princ;
+
+ ret = krb5_get_credentials_for_user(context,
+ 0, /* krb5_flags options */
+ ccache,
+ &in_creds,
+ NULL, /* krb5_data *subject_cert */
+ out_creds);
+ } else {
+ in_creds.client = me;
+ in_creds.server = server;
+
+ ret = krb5_get_credentials(context, 0, ccache,
+ &in_creds, out_creds);
+ }
+
+ return ret;
+}
+#endif /* HAVE_KRB5_GET_CREDENTIALS_FOR_USER */
+
+/*
+ * smb_krb5_get_credentials
+ *
+ * @brief Get krb5 credentials for a server
+ *
+ * @param[in] context An initialized krb5_context
+ * @param[in] ccache An initialized krb5_ccache
+ * @param[in] me The krb5_principal of the caller
+ * @param[in] server The krb5_principal of the requested service
+ * @param[in] impersonate_princ The krb5_principal of a user to impersonate as (optional)
+ * @param[out] out_creds The returned krb5_creds structure
+ * @return krb5_error_code
+ *
+ */
+krb5_error_code smb_krb5_get_credentials(krb5_context context,
+ krb5_ccache ccache,
+ krb5_principal me,
+ krb5_principal server,
+ krb5_principal impersonate_princ,
+ krb5_creds **out_creds)
+{
+ krb5_error_code ret;
+ krb5_creds *creds = NULL;
+
+ if (out_creds != NULL) {
+ *out_creds = NULL;
+ }
+
+ if (impersonate_princ) {
+#ifdef HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE /* Heimdal */
+ ret = smb_krb5_get_credentials_for_user_opt(context, ccache, me, server, impersonate_princ, &creds);
+#elif defined(HAVE_KRB5_GET_CREDENTIALS_FOR_USER) /* MIT */
+ ret = smb_krb5_get_credentials_for_user(context, ccache, me, server, impersonate_princ, &creds);
+#else
+ ret = ENOTSUP;
+#endif
+ } else {
+ krb5_creds in_creds;
+
+ ZERO_STRUCT(in_creds);
+
+ in_creds.client = me;
+ in_creds.server = server;
+
+ ret = krb5_get_credentials(context, 0, ccache,
+ &in_creds, &creds);
+ }
+ if (ret) {
+ goto done;
+ }
+
+ if (out_creds) {
+ *out_creds = creds;
+ }
+
+ done:
+ if (creds && ret) {
+ krb5_free_creds(context, creds);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Initialize a krb5_keyblock with the given data.
+ *
+ * Initializes a new keyblock, allocates the contents for the key and
+ * copies the data into the keyblock.
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] enctype The encryption type.
+ *
+ * @param[in] data The date to initialize the keyblock with.
+ *
+ * @param[in] length The length of the keyblock.
+ *
+ * @param[in] key Newly allocated keyblock structure.
+ *
+ * The key date must be freed using krb5_free_keyblock_contents() when it is
+ * no longer needed.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_keyblock_init_contents(krb5_context context,
+ krb5_enctype enctype,
+ const void *data,
+ size_t length,
+ krb5_keyblock *key)
+{
+#if defined(HAVE_KRB5_KEYBLOCK_INIT)
+ return krb5_keyblock_init(context, enctype, data, length, key);
+#else
+ memset(key, 0, sizeof(krb5_keyblock));
+ KRB5_KEY_DATA(key) = SMB_MALLOC(length);
+ if (NULL == KRB5_KEY_DATA(key)) {
+ return ENOMEM;
+ }
+ memcpy(KRB5_KEY_DATA(key), data, length);
+ KRB5_KEY_LENGTH(key) = length;
+ KRB5_KEY_TYPE(key) = enctype;
+ return 0;
+#endif
+}
+
+/**
+ * @brief Simulate a kinit by putting the tgt in the given credential cache.
+ *
+ * This function uses a keyblock rather than needing the original password.
+ *
+ * @param[in] ctx The library context
+ *
+ * @param[in] cc The credential cache to put the tgt in.
+ *
+ * @param[in] principal The client princial
+ *
+ * @param[in] keyblock The keyblock to use.
+ *
+ * @param[in] target_service The service name of the initial credentials (or NULL).
+ *
+ * @param[in] krb_options Initial credential options.
+ *
+ * @param[in] expire_time A pointer to store the expiration time of the
+ * credentials (or NULL).
+ *
+ * @param[in] kdc_time A pointer to store the time when the ticket becomes
+ * valid (or NULL).
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_kinit_keyblock_ccache(krb5_context ctx,
+ krb5_ccache cc,
+ krb5_principal principal,
+ krb5_keyblock *keyblock,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time)
+{
+ krb5_error_code code = 0;
+ krb5_creds my_creds;
+
+#if defined(HAVE_KRB5_GET_INIT_CREDS_KEYBLOCK)
+ code = krb5_get_init_creds_keyblock(ctx, &my_creds, principal,
+ keyblock, 0, target_service,
+ krb_options);
+#elif defined(HAVE_KRB5_GET_INIT_CREDS_KEYTAB)
+{
+#define SMB_CREDS_KEYTAB "MEMORY:tmp_kinit_keyblock_ccache"
+ char tmp_name[64] = {0};
+ krb5_keytab_entry entry;
+ krb5_keytab keytab;
+ int rc;
+
+ memset(&entry, 0, sizeof(entry));
+ entry.principal = principal;
+ *(KRB5_KT_KEY(&entry)) = *keyblock;
+
+ rc = snprintf(tmp_name, sizeof(tmp_name),
+ "%s-%p",
+ SMB_CREDS_KEYTAB,
+ &my_creds);
+ if (rc < 0) {
+ return KRB5_KT_BADNAME;
+ }
+ code = krb5_kt_resolve(ctx, tmp_name, &keytab);
+ if (code) {
+ return code;
+ }
+
+ code = krb5_kt_add_entry(ctx, keytab, &entry);
+ if (code) {
+ (void)krb5_kt_close(ctx, keytab);
+ goto done;
+ }
+
+ code = krb5_get_init_creds_keytab(ctx, &my_creds, principal,
+ keytab, 0, target_service,
+ krb_options);
+ (void)krb5_kt_close(ctx, keytab);
+}
+#else
+#error krb5_get_init_creds_keyblock not available!
+#endif
+ if (code) {
+ return code;
+ }
+
+#ifndef SAMBA4_USES_HEIMDAL /* MIT */
+ /*
+ * We need to store the principal as returned from the KDC to the
+ * credentials cache. If we don't do that the KRB5 library is not
+ * able to find the tickets it is looking for
+ */
+ principal = my_creds.client;
+#endif
+ code = krb5_cc_initialize(ctx, cc, principal);
+ if (code) {
+ goto done;
+ }
+
+ code = krb5_cc_store_cred(ctx, cc, &my_creds);
+ if (code) {
+ goto done;
+ }
+
+ if (expire_time) {
+ *expire_time = (time_t) my_creds.times.endtime;
+ }
+
+ if (kdc_time) {
+ *kdc_time = (time_t) my_creds.times.starttime;
+ }
+
+ code = 0;
+done:
+ krb5_free_cred_contents(ctx, &my_creds);
+ return code;
+}
+
+/**
+ * @brief Simulate a kinit by putting the tgt in the given credential cache.
+ *
+ * @param[in] ctx The library context
+ *
+ * @param[in] cc The credential cache to put the tgt in.
+ *
+ * @param[in] principal The client princial
+ *
+ * @param[in] password The password (or NULL).
+ *
+ * @param[in] target_service The service name of the initial credentials (or NULL).
+ *
+ * @param[in] krb_options Initial credential options.
+ *
+ * @param[in] expire_time A pointer to store the expiration time of the
+ * credentials (or NULL).
+ *
+ * @param[in] kdc_time A pointer to store the time when the ticket becomes
+ * valid (or NULL).
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_kinit_password_ccache(krb5_context ctx,
+ krb5_ccache cc,
+ krb5_principal principal,
+ const char *password,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time)
+{
+ krb5_error_code code = 0;
+ krb5_creds my_creds;
+
+ code = krb5_get_init_creds_password(ctx, &my_creds, principal,
+ password, NULL, NULL, 0,
+ target_service, krb_options);
+ if (code) {
+ return code;
+ }
+
+ /*
+ * We need to store the principal as returned from the KDC to the
+ * credentials cache. If we don't do that the KRB5 library is not
+ * able to find the tickets it is looking for
+ */
+ principal = my_creds.client;
+ code = krb5_cc_initialize(ctx, cc, principal);
+ if (code) {
+ goto done;
+ }
+
+ code = krb5_cc_store_cred(ctx, cc, &my_creds);
+ if (code) {
+ goto done;
+ }
+
+ if (expire_time) {
+ *expire_time = (time_t) my_creds.times.endtime;
+ }
+
+ if (kdc_time) {
+ *kdc_time = (time_t) my_creds.times.starttime;
+ }
+
+ code = 0;
+done:
+ krb5_free_cred_contents(ctx, &my_creds);
+ return code;
+}
+
+#ifdef SAMBA4_USES_HEIMDAL
+/**
+ * @brief Simulate a kinit by putting the tgt in the given credential cache.
+ *
+ * @param[in] ctx The library context
+ *
+ * @param[in] cc The credential cache to store the tgt in.
+ *
+ * @param[in] principal The initial client princial.
+ *
+ * @param[in] password The password (or NULL).
+ *
+ * @param[in] impersonate_principal The impersonation principal (or NULL).
+ *
+ * @param[in] self_service The local service for S4U2Self if
+ * impersonate_principal is specified).
+ *
+ * @param[in] target_service The service name of the initial credentials
+ * (kpasswd/REALM or a remote service). It defaults
+ * to the krbtgt if NULL.
+ *
+ * @param[in] krb_options Initial credential options.
+ *
+ * @param[in] expire_time A pointer to store the expiration time of the
+ * credentials (or NULL).
+ *
+ * @param[in] kdc_time A pointer to store the time when the ticket becomes
+ * valid (or NULL).
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx,
+ krb5_ccache store_cc,
+ krb5_principal init_principal,
+ const char *init_password,
+ krb5_principal impersonate_principal,
+ const char *self_service,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time)
+{
+ krb5_error_code code = 0;
+ krb5_get_creds_opt options;
+ krb5_principal store_principal;
+ krb5_creds store_creds;
+ krb5_creds *s4u2self_creds;
+ Ticket s4u2self_ticket;
+ size_t s4u2self_ticketlen;
+ krb5_creds *s4u2proxy_creds;
+ krb5_principal self_princ;
+ bool s4u2proxy;
+ krb5_principal target_princ;
+ krb5_ccache tmp_cc;
+ const char *self_realm;
+ const char *client_realm = NULL;
+ krb5_principal blacklist_principal = NULL;
+ krb5_principal whitelist_principal = NULL;
+
+ code = krb5_get_init_creds_password(ctx, &store_creds,
+ init_principal,
+ init_password,
+ NULL, NULL,
+ 0,
+ NULL,
+ krb_options);
+ if (code != 0) {
+ return code;
+ }
+
+ store_principal = init_principal;
+
+ /*
+ * We are trying S4U2Self now:
+ *
+ * As we do not want to expose our TGT in the
+ * krb5_ccache, which is also holds the impersonated creds.
+ *
+ * Some low level krb5/gssapi function might use the TGT
+ * identity and let the client act as our machine account.
+ *
+ * We need to avoid that and use a temporary krb5_ccache
+ * in order to pass our TGT to the krb5_get_creds() function.
+ */
+ code = krb5_cc_new_unique(ctx, NULL, NULL, &tmp_cc);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ code = krb5_cc_initialize(ctx, tmp_cc, store_creds.client);
+ if (code != 0) {
+ krb5_cc_destroy(ctx, tmp_cc);
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ code = krb5_cc_store_cred(ctx, tmp_cc, &store_creds);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ /*
+ * we need to remember the client principal of our
+ * TGT and make sure the KDC does not return this
+ * in the impersonated tickets. This can happen
+ * if the KDC does not support S4U2Self and S4U2Proxy.
+ */
+ blacklist_principal = store_creds.client;
+ store_creds.client = NULL;
+ krb5_free_cred_contents(ctx, &store_creds);
+
+ /*
+ * Check if we also need S4U2Proxy or if S4U2Self is
+ * enough in order to get a ticket for the target.
+ */
+ if (target_service == NULL) {
+ s4u2proxy = false;
+ } else if (strcmp(target_service, self_service) == 0) {
+ s4u2proxy = false;
+ } else {
+ s4u2proxy = true;
+ }
+
+ /*
+ * For S4U2Self we need our own service principal,
+ * which belongs to our own realm (available on
+ * our client principal).
+ */
+ self_realm = krb5_principal_get_realm(ctx, init_principal);
+
+ code = krb5_parse_name(ctx, self_service, &self_princ);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_principal_set_realm(ctx, self_princ, self_realm);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_principal(ctx, self_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds_opt_alloc(ctx, &options);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_principal(ctx, self_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ if (s4u2proxy) {
+ /*
+ * If we want S4U2Proxy, we need the forwardable flag
+ * on the S4U2Self ticket.
+ */
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+ }
+
+ code = krb5_get_creds_opt_set_impersonate(ctx, options,
+ impersonate_principal);
+ if (code != 0) {
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_principal(ctx, self_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds(ctx, options, tmp_cc,
+ self_princ, &s4u2self_creds);
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, self_princ);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ if (!s4u2proxy) {
+ krb5_cc_destroy(ctx, tmp_cc);
+
+ /*
+ * Now make sure we store the impersonated principal
+ * and creds instead of the TGT related stuff
+ * in the krb5_ccache of the caller.
+ */
+ code = krb5_copy_creds_contents(ctx, s4u2self_creds,
+ &store_creds);
+ krb5_free_creds(ctx, s4u2self_creds);
+ if (code != 0) {
+ return code;
+ }
+
+ /*
+ * It's important to store the principal the KDC
+ * returned, as otherwise the caller would not find
+ * the S4U2Self ticket in the krb5_ccache lookup.
+ */
+ store_principal = store_creds.client;
+ goto store;
+ }
+
+ /*
+ * We are trying S4U2Proxy:
+ *
+ * We need the ticket from the S4U2Self step
+ * and our TGT in order to get the delegated ticket.
+ */
+ code = decode_Ticket((const uint8_t *)s4u2self_creds->ticket.data,
+ s4u2self_creds->ticket.length,
+ &s4u2self_ticket,
+ &s4u2self_ticketlen);
+ if (code != 0) {
+ krb5_free_creds(ctx, s4u2self_creds);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ /*
+ * we need to remember the client principal of the
+ * S4U2Self stage and as it needs to match the one we
+ * will get for the S4U2Proxy stage. We need this
+ * in order to detect KDCs which does not support S4U2Proxy.
+ */
+ whitelist_principal = s4u2self_creds->client;
+ s4u2self_creds->client = NULL;
+ krb5_free_creds(ctx, s4u2self_creds);
+
+ /*
+ * For S4U2Proxy we also got a target service principal,
+ * which also belongs to our own realm (available on
+ * our client principal).
+ */
+ code = krb5_parse_name(ctx, target_service, &target_princ);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_principal_set_realm(ctx, target_princ, self_realm);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds_opt_alloc(ctx, &options);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_CONSTRAINED_DELEGATION);
+
+ code = krb5_get_creds_opt_set_ticket(ctx, options, &s4u2self_ticket);
+ free_Ticket(&s4u2self_ticket);
+ if (code != 0) {
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds(ctx, options, tmp_cc,
+ target_princ, &s4u2proxy_creds);
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, target_princ);
+ krb5_cc_destroy(ctx, tmp_cc);
+ if (code != 0) {
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ return code;
+ }
+
+ /*
+ * Now make sure we store the impersonated principal
+ * and creds instead of the TGT related stuff
+ * in the krb5_ccache of the caller.
+ */
+ code = krb5_copy_creds_contents(ctx, s4u2proxy_creds,
+ &store_creds);
+ krb5_free_creds(ctx, s4u2proxy_creds);
+ if (code != 0) {
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ return code;
+ }
+
+ /*
+ * It's important to store the principal the KDC
+ * returned, as otherwise the caller would not find
+ * the S4U2Self ticket in the krb5_ccache lookup.
+ */
+ store_principal = store_creds.client;
+
+ store:
+ if (blacklist_principal &&
+ krb5_principal_compare(ctx, store_creds.client, blacklist_principal)) {
+ char *sp = NULL;
+ char *ip = NULL;
+
+ code = krb5_unparse_name(ctx, blacklist_principal, &sp);
+ if (code != 0) {
+ sp = NULL;
+ }
+ code = krb5_unparse_name(ctx, impersonate_principal, &ip);
+ if (code != 0) {
+ ip = NULL;
+ }
+ DBG_WARNING("KDC returned self principal[%s] while impersonating [%s]\n",
+ sp?sp:"<no memory>",
+ ip?ip:"<no memory>");
+
+ SAFE_FREE(sp);
+ SAFE_FREE(ip);
+
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_free_cred_contents(ctx, &store_creds);
+ return KRB5_FWD_BAD_PRINCIPAL;
+ }
+ if (blacklist_principal) {
+ krb5_free_principal(ctx, blacklist_principal);
+ }
+
+ if (whitelist_principal &&
+ !krb5_principal_compare(ctx, store_creds.client, whitelist_principal)) {
+ char *sp = NULL;
+ char *ep = NULL;
+
+ code = krb5_unparse_name(ctx, store_creds.client, &sp);
+ if (code != 0) {
+ sp = NULL;
+ }
+ code = krb5_unparse_name(ctx, whitelist_principal, &ep);
+ if (code != 0) {
+ ep = NULL;
+ }
+ DBG_WARNING("KDC returned wrong principal[%s] we expected [%s]\n",
+ sp?sp:"<no memory>",
+ ep?ep:"<no memory>");
+
+ SAFE_FREE(sp);
+ SAFE_FREE(ep);
+
+ krb5_free_principal(ctx, whitelist_principal);
+ krb5_free_cred_contents(ctx, &store_creds);
+ return KRB5_FWD_BAD_PRINCIPAL;
+ }
+ if (whitelist_principal) {
+ krb5_free_principal(ctx, whitelist_principal);
+ }
+
+ code = krb5_cc_initialize(ctx, store_cc, store_principal);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ code = krb5_cc_store_cred(ctx, store_cc, &store_creds);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ client_realm = krb5_principal_get_realm(ctx, store_creds.client);
+ if (client_realm != NULL) {
+ /*
+ * Because the CANON flag doesn't have any impact
+ * on the impersonate_principal => store_creds.client
+ * realm mapping. We need to store the credentials twice,
+ * once with the returned realm and once with the
+ * realm of impersonate_principal.
+ */
+ code = krb5_principal_set_realm(ctx, store_creds.server,
+ client_realm);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+
+ code = krb5_cc_store_cred(ctx, store_cc, &store_creds);
+ if (code != 0) {
+ krb5_free_cred_contents(ctx, &store_creds);
+ return code;
+ }
+ }
+
+ if (expire_time) {
+ *expire_time = (time_t) store_creds.times.endtime;
+ }
+
+ if (kdc_time) {
+ *kdc_time = (time_t) store_creds.times.starttime;
+ }
+
+ krb5_free_cred_contents(ctx, &store_creds);
+
+ return 0;
+}
+
+#else /* MIT */
+
+static bool princ_compare_no_dollar(krb5_context ctx,
+ krb5_principal a,
+ krb5_principal b)
+{
+ krb5_principal mod = NULL;
+ bool cmp;
+
+ if (a->length == 1 && b->length == 1 &&
+ a->data[0].length != 0 && b->data[0].length != 0 &&
+ a->data[0].data[a->data[0].length - 1] !=
+ b->data[0].data[b->data[0].length - 1]) {
+ if (a->data[0].data[a->data[0].length - 1] == '$') {
+ mod = a;
+ mod->data[0].length--;
+ } else if (b->data[0].data[b->data[0].length - 1] == '$') {
+ mod = b;
+ mod->data[0].length--;
+ }
+ }
+
+ cmp = krb5_principal_compare_flags(ctx,
+ a,
+ b,
+ KRB5_PRINCIPAL_COMPARE_CASEFOLD);
+ if (mod != NULL) {
+ mod->data[0].length++;
+ }
+
+ return cmp;
+}
+
+krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx,
+ krb5_ccache store_cc,
+ krb5_principal init_principal,
+ const char *init_password,
+ krb5_principal impersonate_principal,
+ const char *self_service,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time)
+{
+ krb5_error_code code;
+ krb5_principal self_princ = NULL;
+ krb5_principal target_princ = NULL;
+ krb5_creds *store_creds = NULL;
+ krb5_creds *s4u2self_creds = NULL;
+ krb5_creds *s4u2proxy_creds = NULL;
+ krb5_creds init_creds = {0};
+ krb5_creds mcreds = {0};
+ krb5_flags options = KRB5_GC_NO_STORE;
+ krb5_ccache tmp_cc;
+ bool s4u2proxy = false;
+ bool ok;
+
+ code = krb5_cc_new_unique(ctx, "MEMORY", NULL, &tmp_cc);
+ if (code != 0) {
+ return code;
+ }
+
+ code = krb5_get_init_creds_password(ctx,
+ &init_creds,
+ init_principal,
+ init_password,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ krb_options);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = krb5_cc_initialize(ctx, tmp_cc, init_creds.client);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = krb5_cc_store_cred(ctx, tmp_cc, &init_creds);
+ if (code != 0) {
+ goto done;
+ }
+
+ /*
+ * Check if we also need S4U2Proxy or if S4U2Self is
+ * enough in order to get a ticket for the target.
+ */
+ if (target_service == NULL) {
+ s4u2proxy = false;
+ } else if (strcmp(target_service, self_service) == 0) {
+ s4u2proxy = false;
+ } else {
+ s4u2proxy = true;
+ }
+
+ code = krb5_parse_name(ctx, self_service, &self_princ);
+ if (code != 0) {
+ goto done;
+ }
+
+ /*
+ * MIT lacks aliases support in S4U, for S4U2Self we require the tgt
+ * client and the request server to be the same principal name.
+ */
+ ok = princ_compare_no_dollar(ctx, init_creds.client, self_princ);
+ if (!ok) {
+ code = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+ goto done;
+ }
+
+ mcreds.client = impersonate_principal;
+ mcreds.server = init_creds.client;
+
+ code = krb5_get_credentials_for_user(ctx, options, tmp_cc, &mcreds,
+ NULL, &s4u2self_creds);
+ if (code != 0) {
+ goto done;
+ }
+
+ if (s4u2proxy) {
+ code = krb5_parse_name(ctx, target_service, &target_princ);
+ if (code != 0) {
+ goto done;
+ }
+
+ mcreds.client = init_creds.client;
+ mcreds.server = target_princ;
+ mcreds.second_ticket = s4u2self_creds->ticket;
+
+ code = krb5_get_credentials(ctx, options |
+ KRB5_GC_CONSTRAINED_DELEGATION,
+ tmp_cc, &mcreds, &s4u2proxy_creds);
+ if (code != 0) {
+ goto done;
+ }
+
+ /* Check KDC support of S4U2Proxy extension */
+ if (!krb5_principal_compare(ctx, s4u2self_creds->client,
+ s4u2proxy_creds->client)) {
+ code = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+ goto done;
+ }
+
+ store_creds = s4u2proxy_creds;
+ } else {
+ store_creds = s4u2self_creds;;
+
+ /* We need to save the ticket with the requested server name
+ * or the caller won't be able to find it in cache. */
+ if (!krb5_principal_compare(ctx, self_princ,
+ store_creds->server)) {
+ krb5_free_principal(ctx, store_creds->server);
+ store_creds->server = NULL;
+ code = krb5_copy_principal(ctx, self_princ,
+ &store_creds->server);
+ if (code != 0) {
+ goto done;
+ }
+ }
+ }
+
+ code = krb5_cc_initialize(ctx, store_cc, store_creds->client);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = krb5_cc_store_cred(ctx, store_cc, store_creds);
+ if (code != 0) {
+ goto done;
+ }
+
+ if (expire_time) {
+ *expire_time = (time_t) store_creds->times.endtime;
+ }
+
+ if (kdc_time) {
+ *kdc_time = (time_t) store_creds->times.starttime;
+ }
+
+done:
+ krb5_cc_destroy(ctx, tmp_cc);
+ krb5_free_cred_contents(ctx, &init_creds);
+ krb5_free_creds(ctx, s4u2self_creds);
+ krb5_free_creds(ctx, s4u2proxy_creds);
+ krb5_free_principal(ctx, self_princ);
+ krb5_free_principal(ctx, target_princ);
+
+ return code;
+}
+#endif
+
+#if !defined(HAVE_KRB5_MAKE_PRINCIPAL) && defined(HAVE_KRB5_BUILD_PRINCIPAL_ALLOC_VA)
+/**
+ * @brief Create a principal name using a variable argument list.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[inout] principal A pointer to the principal structure.
+ *
+ * @param[in] _realm The realm to use. If NULL then the function will
+ * get the default realm name.
+ *
+ * @param[in] ... A list of 'char *' components, ending with NULL.
+ *
+ * Use krb5_free_principal() to free the principal when it is no longer needed.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_make_principal(krb5_context context,
+ krb5_principal *principal,
+ const char *_realm, ...)
+{
+ krb5_error_code code;
+ bool free_realm;
+ char *realm;
+ va_list ap;
+
+ if (_realm) {
+ realm = discard_const_p(char, _realm);
+ free_realm = false;
+ } else {
+ code = krb5_get_default_realm(context, &realm);
+ if (code) {
+ return code;
+ }
+ free_realm = true;
+ }
+
+ va_start(ap, _realm);
+ code = krb5_build_principal_alloc_va(context, principal,
+ strlen(realm), realm,
+ ap);
+ va_end(ap);
+
+ if (free_realm) {
+ krb5_free_default_realm(context, realm);
+ }
+
+ return code;
+}
+#endif
+
+#if !defined(HAVE_KRB5_CC_GET_LIFETIME) && defined(HAVE_KRB5_CC_RETRIEVE_CRED)
+/**
+ * @brief Get the lifetime of the initial ticket in the cache.
+ *
+ * @param[in] context The kerberos context.
+ *
+ * @param[in] id The credential cache to get the ticket lifetime.
+ *
+ * @param[out] t A pointer to a time value to store the lifetime.
+ *
+ * @return 0 on success, a krb5_error_code on error.
+ */
+krb5_error_code smb_krb5_cc_get_lifetime(krb5_context context,
+ krb5_ccache id,
+ time_t *t)
+{
+ krb5_cc_cursor cursor;
+ krb5_error_code kerr;
+ krb5_creds cred;
+ krb5_timestamp now;
+
+ *t = 0;
+
+ kerr = krb5_timeofday(context, &now);
+ if (kerr) {
+ return kerr;
+ }
+
+ kerr = krb5_cc_start_seq_get(context, id, &cursor);
+ if (kerr) {
+ return kerr;
+ }
+
+ while ((kerr = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) {
+#ifndef HAVE_FLAGS_IN_KRB5_CREDS
+ if (cred.ticket_flags & TKT_FLG_INITIAL) {
+#else
+ if (cred.flags.b.initial) {
+#endif
+ if (now < cred.times.endtime) {
+ *t = (time_t) (cred.times.endtime - now);
+ }
+ krb5_free_cred_contents(context, &cred);
+ break;
+ }
+ krb5_free_cred_contents(context, &cred);
+ }
+
+ krb5_cc_end_seq_get(context, id, &cursor);
+
+ return kerr;
+}
+#endif /* HAVE_KRB5_CC_GET_LIFETIME */
+
+#if !defined(HAVE_KRB5_FREE_CHECKSUM_CONTENTS) && defined(HAVE_FREE_CHECKSUM)
+void smb_krb5_free_checksum_contents(krb5_context ctx, krb5_checksum *cksum)
+{
+ free_Checksum(cksum);
+}
+#endif
+
+/**
+ * @brief Compute a checksum operating on a keyblock.
+ *
+ * This function computes a checksum over a PAC using the keyblock for a keyed
+ * checksum.
+ *
+ * @param[in] mem_ctx A talloc context to allocate the signature on.
+ *
+ * @param[in] pac_data The PAC as input.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] keyblock Encryption key for a keyed checksum.
+ *
+ * @param[out] sig_type The checksum type
+ *
+ * @param[out] sig_blob The talloc'ed checksum
+ *
+ * The caller must free the sig_blob with talloc_free() when it is not needed
+ * anymore.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_make_pac_checksum(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pac_data,
+ krb5_context context,
+ const krb5_keyblock *keyblock,
+ uint32_t *sig_type,
+ DATA_BLOB *sig_blob)
+{
+ krb5_error_code ret;
+ krb5_checksum cksum;
+#if defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CREATE_CHECKSUM)
+ krb5_crypto crypto;
+
+
+ ret = krb5_crypto_init(context,
+ keyblock,
+ 0,
+ &crypto);
+ if (ret) {
+ DEBUG(0,("krb5_crypto_init() failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ return ret;
+ }
+ ret = krb5_create_checksum(context,
+ crypto,
+ KRB5_KU_OTHER_CKSUM,
+ 0,
+ pac_data->data,
+ pac_data->length,
+ &cksum);
+ if (ret) {
+ DEBUG(2, ("PAC Verification failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ }
+
+ krb5_crypto_destroy(context, crypto);
+
+ if (ret) {
+ return ret;
+ }
+
+ *sig_type = cksum.cksumtype;
+ *sig_blob = data_blob_talloc(mem_ctx,
+ cksum.checksum.data,
+ cksum.checksum.length);
+#elif defined(HAVE_KRB5_C_MAKE_CHECKSUM)
+ krb5_data input;
+
+ input.data = (char *)pac_data->data;
+ input.length = pac_data->length;
+
+ ret = krb5_c_make_checksum(context,
+ 0,
+ keyblock,
+ KRB5_KEYUSAGE_APP_DATA_CKSUM,
+ &input,
+ &cksum);
+ if (ret) {
+ DEBUG(2, ("PAC Verification failed: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ return ret;
+ }
+
+ *sig_type = cksum.checksum_type;
+ *sig_blob = data_blob_talloc(mem_ctx,
+ cksum.contents,
+ cksum.length);
+
+#else
+#error krb5_create_checksum or krb5_c_make_checksum not available
+#endif /* HAVE_KRB5_C_MAKE_CHECKSUM */
+ smb_krb5_free_checksum_contents(context, &cksum);
+
+ return 0;
+}
+
+
+/**
+ * @brief Get realm of a principal
+ *
+ * @param[in] mem_ctx The talloc ctx to put the result on
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] principal The principal to get the realm from.
+ *
+ * @return A talloced string with the realm or NULL if an error occurred.
+ */
+char *smb_krb5_principal_get_realm(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_const_principal principal)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_GET_REALM /* Heimdal */
+ const char *realm = NULL;
+
+ realm = krb5_principal_get_realm(context, principal);
+ if (realm == NULL) {
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, realm);
+#elif defined(krb5_princ_realm) /* MIT */
+ const krb5_data *realm = NULL;
+
+ realm = krb5_princ_realm(context, principal);
+ if (realm == NULL) {
+ return NULL;
+ }
+
+ return talloc_strndup(mem_ctx, realm->data, realm->length);
+#else
+#error UNKNOWN_GET_PRINC_REALM_FUNCTIONS
+#endif
+}
+
+/**
+ * @brief Get realm of a principal
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] principal The principal to set the realm
+ *
+ * @param[in] realm The realm as a string to set.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_principal_set_realm(krb5_context context,
+ krb5_principal principal,
+ const char *realm)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_SET_REALM /* Heimdal */
+ return krb5_principal_set_realm(context, principal, realm);
+#elif defined(krb5_princ_realm) && defined(krb5_princ_set_realm) /* MIT */
+ krb5_error_code ret;
+ krb5_data data;
+ krb5_data *old_data;
+
+ old_data = krb5_princ_realm(context, principal);
+
+ ret = smb_krb5_copy_data_contents(&data,
+ realm,
+ strlen(realm));
+ if (ret) {
+ return ret;
+ }
+
+ /* free realm before setting */
+ free(old_data->data);
+
+ krb5_princ_set_realm(context, principal, &data);
+
+ return ret;
+#else
+#error UNKNOWN_PRINC_SET_REALM_FUNCTION
+#endif
+}
+
+
+/**
+ * @brief Get the realm from the service hostname.
+ *
+ * This function will look for a domain realm mapping in the [domain_realm]
+ * section of the krb5.conf first and fallback to extract the realm from
+ * the provided service hostname. As a last resort it will return the
+ * provided client_realm.
+ *
+ * @param[in] mem_ctx The talloc context
+ *
+ * @param[in] hostname The service hostname
+ *
+ * @param[in] client_realm If we can not find a mapping, fall back to
+ * this realm.
+ *
+ * @return The realm to use for the service hostname, NULL if a fatal error
+ * occurred.
+ */
+char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
+ const char *hostname,
+ const char *client_realm)
+{
+#if defined(HAVE_KRB5_REALM_TYPE)
+ /* Heimdal. */
+ krb5_realm *realm_list = NULL;
+#else
+ /* MIT */
+ char **realm_list = NULL;
+#endif
+ char *realm = NULL;
+ krb5_error_code kerr;
+ krb5_context ctx = NULL;
+
+ kerr = smb_krb5_init_context_common(&ctx);
+ if (kerr) {
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(kerr));
+ return NULL;
+ }
+
+ kerr = krb5_get_host_realm(ctx, hostname, &realm_list);
+ if (kerr == KRB5_ERR_HOST_REALM_UNKNOWN) {
+ realm_list = NULL;
+ kerr = 0;
+ }
+ if (kerr != 0) {
+ DEBUG(3,("kerberos_get_realm_from_hostname %s: "
+ "failed %s\n",
+ hostname ? hostname : "(NULL)",
+ error_message(kerr) ));
+ goto out;
+ }
+
+ if (realm_list != NULL &&
+ realm_list[0] != NULL &&
+ realm_list[0][0] != '\0') {
+ realm = talloc_strdup(mem_ctx, realm_list[0]);
+ if (realm == NULL) {
+ goto out;
+ }
+ } else {
+ const char *p = NULL;
+
+ /*
+ * "dc6.samba2003.example.com"
+ * returns a realm of "SAMBA2003.EXAMPLE.COM"
+ *
+ * "dc6." returns realm as NULL
+ */
+ p = strchr_m(hostname, '.');
+ if (p != NULL && p[1] != '\0') {
+ realm = talloc_strdup_upper(mem_ctx, p + 1);
+ if (realm == NULL) {
+ goto out;
+ }
+ }
+ }
+
+ if (realm == NULL) {
+ realm = talloc_strdup(mem_ctx, client_realm);
+ }
+
+ out:
+
+ if (ctx) {
+ if (realm_list) {
+ krb5_free_host_realm(ctx, realm_list);
+ realm_list = NULL;
+ }
+ krb5_free_context(ctx);
+ ctx = NULL;
+ }
+ return realm;
+}
+
+/**
+ * @brief Get an error string from a Kerberos error code.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] code The Kerberos error code.
+ *
+ * @param[in] mem_ctx The talloc context to allocate the error string on.
+ *
+ * @return A talloc'ed error string or NULL if an error occurred.
+ *
+ * The caller must free the returned error string with talloc_free() if not
+ * needed anymore
+ */
+char *smb_get_krb5_error_message(krb5_context context,
+ krb5_error_code code,
+ TALLOC_CTX *mem_ctx)
+{
+ char *ret;
+
+#if defined(HAVE_KRB5_GET_ERROR_MESSAGE) && defined(HAVE_KRB5_FREE_ERROR_MESSAGE)
+ const char *context_error = krb5_get_error_message(context, code);
+ if (context_error) {
+ ret = talloc_asprintf(mem_ctx, "%s: %s",
+ error_message(code), context_error);
+ krb5_free_error_message(context, context_error);
+ return ret;
+ }
+#endif
+ ret = talloc_strdup(mem_ctx, error_message(code));
+ return ret;
+}
+
+/**
+ * @brief Return the type of a krb5_principal
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] principal The principal to get the type from.
+ *
+ * @return The integer type of the principal.
+ */
+int smb_krb5_principal_get_type(krb5_context context,
+ krb5_const_principal principal)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_GET_TYPE /* Heimdal */
+ return krb5_principal_get_type(context, principal);
+#elif defined(krb5_princ_type) /* MIT */
+ return krb5_princ_type(context, principal);
+#else
+#error UNKNOWN_PRINC_GET_TYPE_FUNCTION
+#endif
+}
+
+/**
+ * @brief Set the type of a principal
+ *
+ * @param[in] context The library context
+ *
+ * @param[inout] principal The principal to set the type for.
+ *
+ * @param[in] type The principal type to set.
+ */
+void smb_krb5_principal_set_type(krb5_context context,
+ krb5_principal principal,
+ int type)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_SET_TYPE /* Heimdal */
+ krb5_principal_set_type(context, principal, type);
+#elif defined(krb5_princ_type) /* MIT */
+ krb5_princ_type(context, principal) = type;
+#else
+#error UNKNOWN_PRINC_SET_TYPE_FUNCTION
+#endif
+}
+
+/**
+ * @brief Check if a principal is a TGS
+ *
+ * @param[in] context The library context
+ *
+ * @param[inout] principal The principal to check.
+ *
+ * @returns 1 if equal, 0 if not and -1 on error.
+ */
+int smb_krb5_principal_is_tgs(krb5_context context,
+ krb5_const_principal principal)
+{
+ char *p = NULL;
+ int eq = 1;
+ krb5_error_code ret = 0;
+
+ if (krb5_princ_size(context, principal) > 2) {
+ return 0;
+ }
+
+ ret = smb_krb5_principal_get_comp_string(NULL, context, principal, 0, &p);
+ if (ret == ENOENT) {
+ return 0;
+ } else if (ret) {
+ return -1;
+ }
+
+ eq = strcmp(p, KRB5_TGS_NAME) == 0;
+
+ talloc_free(p);
+
+ return eq;
+}
+
+#if !defined(HAVE_KRB5_WARNX)
+/**
+ * @brief Log a Kerberos message
+ *
+ * It sends the message to com_err.
+ *
+ * @param[in] context The library context
+ *
+ * @param[in] fmt The message format
+ *
+ * @param[in] ... The message arguments
+ *
+ * @return 0 on success.
+ */
+krb5_error_code krb5_warnx(krb5_context context, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ com_err_va("samba-kdc", errno, fmt, args);
+ va_end(args);
+
+ return 0;
+}
+#endif
+
+/**
+ * @brief Copy a credential cache.
+ *
+ * @param[in] context The library context.
+ *
+ * @param[in] incc Credential cache to be copied.
+ *
+ * @param[inout] outcc Copy of credential cache to be filled in.
+ *
+ * @return 0 on success, a Kerberos error code otherwise.
+ */
+krb5_error_code smb_krb5_cc_copy_creds(krb5_context context,
+ krb5_ccache incc, krb5_ccache outcc)
+{
+#ifdef HAVE_KRB5_CC_COPY_CACHE /* Heimdal */
+ return krb5_cc_copy_cache(context, incc, outcc);
+#elif defined(HAVE_KRB5_CC_COPY_CREDS)
+ krb5_error_code ret;
+ krb5_principal princ = NULL;
+
+ ret = krb5_cc_get_principal(context, incc, &princ);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = krb5_cc_initialize(context, outcc, princ);
+ krb5_free_principal(context, princ);
+ if (ret != 0) {
+ return ret;
+ }
+ return krb5_cc_copy_creds(context, incc, outcc);
+#else
+#error UNKNOWN_KRB5_CC_COPY_CACHE_OR_CREDS_FUNCTION
+#endif
+}
+
+/**********************************************************
+ * ADS KRB5 CALLS
+ **********************************************************/
+
+static bool ads_cleanup_expired_creds(krb5_context context,
+ krb5_ccache ccache,
+ krb5_creds *credsp)
+{
+ krb5_error_code retval;
+ const char *cc_type = krb5_cc_get_type(context, ccache);
+
+ DEBUG(3, ("ads_cleanup_expired_creds: Ticket in ccache[%s:%s] expiration %s\n",
+ cc_type, krb5_cc_get_name(context, ccache),
+ http_timestring(talloc_tos(), credsp->times.endtime)));
+
+ /* we will probably need new tickets if the current ones
+ will expire within 10 seconds.
+ */
+ if (credsp->times.endtime >= (time(NULL) + 10))
+ return false;
+
+ /* heimdal won't remove creds from a file ccache, and
+ perhaps we shouldn't anyway, since internally we
+ use memory ccaches, and a FILE one probably means that
+ we're using creds obtained outside of our executable
+ */
+ if (strequal(cc_type, "FILE")) {
+ DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a %s ccache\n", cc_type));
+ return false;
+ }
+
+ retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
+ if (retval) {
+ DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
+ error_message(retval)));
+ /* If we have an error in this, we want to display it,
+ but continue as though we deleted it */
+ }
+ return true;
+}
+
+/* Allocate and setup the auth context into the state we need. */
+
+static krb5_error_code ads_setup_auth_context(krb5_context context,
+ krb5_auth_context *auth_context)
+{
+ krb5_error_code retval;
+
+ retval = krb5_auth_con_init(context, auth_context );
+ if (retval) {
+ DEBUG(1,("krb5_auth_con_init failed (%s)\n",
+ error_message(retval)));
+ return retval;
+ }
+
+ /* Ensure this is an addressless ticket. */
+ retval = krb5_auth_con_setaddrs(context, *auth_context, NULL, NULL);
+ if (retval) {
+ DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n",
+ error_message(retval)));
+ }
+
+ return retval;
+}
+
+#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
+static krb5_error_code ads_create_gss_checksum(krb5_data *in_data, /* [inout] */
+ uint32_t gss_flags)
+{
+ unsigned int orig_length = in_data->length;
+ unsigned int base_cksum_size = GSSAPI_CHECKSUM_SIZE;
+ char *gss_cksum = NULL;
+
+ if (orig_length) {
+ /* Extra length field for delegated ticket. */
+ base_cksum_size += 4;
+ }
+
+ if ((unsigned int)base_cksum_size + orig_length <
+ (unsigned int)base_cksum_size) {
+ return EINVAL;
+ }
+
+ gss_cksum = (char *)SMB_MALLOC(base_cksum_size + orig_length);
+ if (gss_cksum == NULL) {
+ return ENOMEM;
+ }
+
+ memset(gss_cksum, '\0', base_cksum_size + orig_length);
+ SIVAL(gss_cksum, 0, GSSAPI_BNDLENGTH);
+
+ /*
+ * GSS_C_NO_CHANNEL_BINDINGS means 16 zero bytes.
+ * This matches the behavior of heimdal and mit.
+ *
+ * And it is needed to work against some closed source
+ * SMB servers.
+ *
+ * See bug #7883
+ */
+ memset(&gss_cksum[4], 0x00, GSSAPI_BNDLENGTH);
+
+ SIVAL(gss_cksum, 20, gss_flags);
+
+ if (orig_length && in_data->data != NULL) {
+ SSVAL(gss_cksum, 24, 1); /* The Delegation Option identifier */
+ SSVAL(gss_cksum, 26, orig_length);
+ /* Copy the kerberos KRB_CRED data */
+ memcpy(gss_cksum + 28, in_data->data, orig_length);
+ free(in_data->data);
+ in_data->data = NULL;
+ in_data->length = 0;
+ }
+ in_data->data = gss_cksum;
+ in_data->length = base_cksum_size + orig_length;
+ return 0;
+}
+#endif
+
+/*
+ * We can't use krb5_mk_req because w2k wants the service to be in a particular
+ * format.
+ */
+static krb5_error_code ads_krb5_mk_req(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const char *principal,
+ krb5_ccache ccache,
+ krb5_data *outbuf,
+ time_t *expire_time,
+ const char *impersonate_princ_s)
+{
+ krb5_error_code retval;
+ krb5_principal server;
+ krb5_principal impersonate_princ = NULL;
+ krb5_creds *credsp;
+ krb5_creds creds;
+ krb5_data in_data;
+ bool creds_ready = false;
+ int i = 0, maxtries = 3;
+ bool ok;
+
+ ZERO_STRUCT(in_data);
+
+ retval = smb_krb5_parse_name(context, principal, &server);
+ if (retval != 0) {
+ DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
+ return retval;
+ }
+
+ if (impersonate_princ_s) {
+ retval = smb_krb5_parse_name(context, impersonate_princ_s,
+ &impersonate_princ);
+ if (retval) {
+ DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", impersonate_princ_s));
+ goto cleanup_princ;
+ }
+ }
+
+ /* obtain ticket & session key */
+ ZERO_STRUCT(creds);
+ if ((retval = krb5_copy_principal(context, server, &creds.server))) {
+ DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_princ;
+ }
+
+ retval = krb5_cc_get_principal(context, ccache, &creds.client);
+ if (retval != 0) {
+ /* This can commonly fail on smbd startup with no ticket in the cache.
+ * Report at higher level than 1. */
+ DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ while (!creds_ready && (i < maxtries)) {
+
+ retval = smb_krb5_get_credentials(context,
+ ccache,
+ creds.client,
+ creds.server,
+ impersonate_princ,
+ &credsp);
+ if (retval != 0) {
+ DBG_WARNING("smb_krb5_get_credentials failed for %s "
+ "(%s)\n",
+ principal,
+ error_message(retval));
+ goto cleanup_creds;
+ }
+
+ /* cope with ticket being in the future due to clock skew */
+ if ((unsigned)credsp->times.starttime > time(NULL)) {
+ time_t t = time(NULL);
+ int time_offset =(int)((unsigned)credsp->times.starttime-t);
+ DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
+ krb5_set_real_time(context, t + time_offset + 1, 0);
+ }
+
+ ok = ads_cleanup_expired_creds(context, ccache, credsp);
+ if (!ok) {
+ creds_ready = true;
+ }
+
+ i++;
+ }
+
+ DBG_DEBUG("Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
+ principal,
+ krb5_cc_get_type(context, ccache),
+ krb5_cc_get_name(context, ccache),
+ http_timestring(talloc_tos(),
+ (unsigned)credsp->times.endtime),
+ (unsigned)credsp->times.endtime);
+
+ if (expire_time) {
+ *expire_time = (time_t)credsp->times.endtime;
+ }
+
+ /* Allocate the auth_context. */
+ retval = ads_setup_auth_context(context, auth_context);
+ if (retval != 0) {
+ DBG_WARNING("ads_setup_auth_context failed (%s)\n",
+ error_message(retval));
+ goto cleanup_creds;
+ }
+
+#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
+ {
+ uint32_t gss_flags = 0;
+
+ if (credsp->ticket_flags & TKT_FLG_OK_AS_DELEGATE) {
+ /*
+ * Fetch a forwarded TGT from the KDC so that we can
+ * hand off a 2nd ticket as part of the kerberos
+ * exchange.
+ */
+
+ DBG_INFO("Server marked as OK to delegate to, building "
+ "forwardable TGT\n");
+
+ retval = krb5_auth_con_setuseruserkey(context,
+ *auth_context,
+ &credsp->keyblock );
+ if (retval != 0) {
+ DBG_WARNING("krb5_auth_con_setuseruserkey "
+ "failed (%s)\n",
+ error_message(retval));
+ goto cleanup_creds;
+ }
+
+ /* Must use a subkey for forwarded tickets. */
+ retval = krb5_auth_con_setflags(context,
+ *auth_context,
+ KRB5_AUTH_CONTEXT_USE_SUBKEY);
+ if (retval != 0) {
+ DBG_WARNING("krb5_auth_con_setflags failed (%s)\n",
+ error_message(retval));
+ goto cleanup_creds;
+ }
+
+ retval = krb5_fwd_tgt_creds(context,/* Krb5 context [in] */
+ *auth_context, /* Authentication context [in] */
+ discard_const_p(char, KRB5_TGS_NAME), /* Ticket service name ("krbtgt") [in] */
+ credsp->client, /* Client principal for the tgt [in] */
+ credsp->server, /* Server principal for the tgt [in] */
+ ccache, /* Credential cache to use for storage [in] */
+ 1, /* Turn on for "Forwardable ticket" [in] */
+ &in_data ); /* Resulting response [out] */
+
+ if (retval) {
+ DBG_INFO("krb5_fwd_tgt_creds failed (%s)\n",
+ error_message(retval));
+
+ /*
+ * This is not fatal. Delete the *auth_context and continue
+ * with krb5_mk_req_extended to get a non-forwardable ticket.
+ */
+
+ if (in_data.data) {
+ free( in_data.data );
+ in_data.data = NULL;
+ in_data.length = 0;
+ }
+ krb5_auth_con_free(context, *auth_context);
+ *auth_context = NULL;
+ retval = ads_setup_auth_context(context, auth_context);
+ if (retval != 0) {
+ DBG_WARNING("ads_setup_auth_context failed (%s)\n",
+ error_message(retval));
+ goto cleanup_creds;
+ }
+ } else {
+ /* We got a delegated ticket. */
+ gss_flags |= GSS_C_DELEG_FLAG;
+ }
+ }
+
+ /* Frees and reallocates in_data into a GSS checksum blob. */
+ retval = ads_create_gss_checksum(&in_data, gss_flags);
+ if (retval != 0) {
+ goto cleanup_data;
+ }
+
+ /* We always want GSS-checksum types. */
+ retval = krb5_auth_con_set_req_cksumtype(context, *auth_context, GSSAPI_CHECKSUM );
+ if (retval != 0) {
+ DEBUG(1,("krb5_auth_con_set_req_cksumtype failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_data;
+ }
+ }
+#endif
+
+ retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
+ &in_data, credsp, outbuf);
+ if (retval != 0) {
+ DBG_WARNING("krb5_mk_req_extended failed (%s)\n",
+ error_message(retval));
+ }
+
+#if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
+cleanup_data:
+#endif
+
+ if (in_data.data) {
+ free( in_data.data );
+ in_data.length = 0;
+ }
+
+ krb5_free_creds(context, credsp);
+
+cleanup_creds:
+ krb5_free_cred_contents(context, &creds);
+
+cleanup_princ:
+ krb5_free_principal(context, server);
+ if (impersonate_princ) {
+ krb5_free_principal(context, impersonate_princ);
+ }
+
+ return retval;
+}
+
+/*
+ get a kerberos5 ticket for the given service
+*/
+int ads_krb5_cli_get_ticket(TALLOC_CTX *mem_ctx,
+ const char *principal,
+ time_t time_offset,
+ DATA_BLOB *ticket,
+ DATA_BLOB *session_key_krb5,
+ uint32_t extra_ap_opts, const char *ccname,
+ time_t *tgs_expire,
+ const char *impersonate_princ_s)
+{
+ krb5_error_code retval;
+ krb5_data packet;
+ krb5_context context = NULL;
+ krb5_ccache ccdef = NULL;
+ krb5_auth_context auth_context = NULL;
+ krb5_enctype enc_types[] = {
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ ENCTYPE_ARCFOUR_HMAC,
+ ENCTYPE_NULL};
+ bool ok;
+
+ DBG_DEBUG("Getting ticket for service [%s] using creds from [%s] "
+ "and impersonating [%s]\n",
+ principal, ccname, impersonate_princ_s);
+
+ retval = smb_krb5_init_context_common(&context);
+ if (retval != 0) {
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(retval));
+ goto failed;
+ }
+
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
+ retval = krb5_cc_resolve(context,
+ ccname ? ccname : krb5_cc_default_name(context),
+ &ccdef);
+ if (retval != 0) {
+ DBG_WARNING("krb5_cc_default failed (%s)\n",
+ error_message(retval));
+ goto failed;
+ }
+
+ retval = krb5_set_default_tgs_ktypes(context, enc_types);
+ if (retval != 0) {
+ DBG_WARNING("krb5_set_default_tgs_ktypes failed (%s)\n",
+ error_message(retval));
+ goto failed;
+ }
+
+ retval = ads_krb5_mk_req(context,
+ &auth_context,
+ AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
+ principal,
+ ccdef,
+ &packet,
+ tgs_expire,
+ impersonate_princ_s);
+ if (retval != 0) {
+ goto failed;
+ }
+
+ ok = smb_krb5_get_smb_session_key(mem_ctx,
+ context,
+ auth_context,
+ session_key_krb5,
+ false);
+ if (!ok) {
+ retval = ENOMEM;
+ goto failed;
+ }
+
+ *ticket = data_blob_talloc(mem_ctx, packet.data, packet.length);
+
+ smb_krb5_free_data_contents(context, &packet);
+
+failed:
+
+ if (context) {
+ if (ccdef) {
+ krb5_cc_close(context, ccdef);
+ }
+ if (auth_context) {
+ krb5_auth_con_free(context, auth_context);
+ }
+ krb5_free_context(context);
+ }
+
+ return retval;
+}
+
+#ifndef SAMBA4_USES_HEIMDAL /* MITKRB5 tracing callback */
+static void smb_krb5_trace_cb(krb5_context ctx,
+#ifdef HAVE_KRB5_TRACE_INFO
+ const krb5_trace_info *info,
+#elif defined(HAVE_KRB5_TRACE_INFO_STRUCT)
+ const struct krb5_trace_info *info,
+#else
+#error unknown krb5_trace_info
+#endif
+ void *data)
+{
+ if (info != NULL) {
+ DBGC_DEBUG(DBGC_KERBEROS, "%s", info->message);
+ }
+}
+#endif
+
+krb5_error_code smb_krb5_init_context_common(krb5_context *_krb5_context)
+{
+ krb5_error_code ret;
+ krb5_context krb5_ctx;
+
+ initialize_krb5_error_table();
+
+ ret = krb5_init_context(&krb5_ctx);
+ if (ret) {
+ DBG_ERR("Krb5 context initialization failed (%s)\n",
+ error_message(ret));
+ return ret;
+ }
+
+ /* The MIT Kerberos build relies on using the system krb5.conf file.
+ * If you really want to use another file please set KRB5_CONFIG
+ * accordingly. */
+#ifndef SAMBA4_USES_HEIMDAL
+ ret = krb5_set_trace_callback(krb5_ctx, smb_krb5_trace_cb, NULL);
+ if (ret) {
+ DBG_ERR("Failed to set MIT kerberos trace callback! (%s)\n",
+ error_message(ret));
+ }
+#endif
+
+#ifdef SAMBA4_USES_HEIMDAL
+ /* Set options in kerberos */
+ krb5_set_dns_canonicalize_hostname(krb5_ctx, false);
+#endif
+
+ *_krb5_context = krb5_ctx;
+ return 0;
+}
+
+#else /* HAVE_KRB5 */
+/* This saves a few linking headaches */
+int ads_krb5_cli_get_ticket(TALLOC_CTX *mem_ctx,
+ const char *principal,
+ time_t time_offset,
+ DATA_BLOB *ticket,
+ DATA_BLOB *session_key_krb5,
+ uint32_t extra_ap_opts, const char *ccname,
+ time_t *tgs_expire,
+ const char *impersonate_princ_s)
+{
+ DEBUG(0,("NO KERBEROS SUPPORT\n"));
+ return 1;
+}
+
+#endif /* HAVE_KRB5 */
diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h
new file mode 100644
index 0000000..e158a40
--- /dev/null
+++ b/lib/krb5_wrap/krb5_samba.h
@@ -0,0 +1,443 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5 routines for active directory
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Luke Howard 2002-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Guenther Deschner 2005-2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _KRB5_SAMBA_H
+#define _KRB5_SAMBA_H
+
+#include "lib/util/data_blob.h"
+#include "libcli/util/ntstatus.h"
+
+#ifdef HAVE_KRB5
+
+#define KRB5_PRIVATE 1 /* this file uses PRIVATE interfaces! */
+/* this file uses DEPRECATED interfaces! */
+
+#ifdef KRB5_DEPRECATED
+#undef KRB5_DEPRECATED
+#endif
+
+#if defined(HAVE_KRB5_DEPRECATED_WITH_IDENTIFIER)
+#define KRB5_DEPRECATED 1
+#else
+#define KRB5_DEPRECATED
+#endif
+
+#include "system/kerberos.h"
+#include "system/network.h"
+
+#ifndef KRB5_ADDR_NETBIOS
+#define KRB5_ADDR_NETBIOS 0x14
+#endif
+
+#ifndef KRB5KRB_ERR_RESPONSE_TOO_BIG
+#define KRB5KRB_ERR_RESPONSE_TOO_BIG (-1765328332L)
+#endif
+
+/* Heimdal uses a slightly different name */
+#if defined(HAVE_ENCTYPE_ARCFOUR_HMAC_MD5) && !defined(HAVE_ENCTYPE_ARCFOUR_HMAC)
+#define ENCTYPE_ARCFOUR_HMAC ENCTYPE_ARCFOUR_HMAC_MD5
+#endif
+#if defined(HAVE_ENCTYPE_ARCFOUR_HMAC_MD5_56) && !defined(HAVE_ENCTYPE_ARCFOUR_HMAC_EXP)
+#define ENCTYPE_ARCFOUR_HMAC_EXP ENCTYPE_ARCFOUR_HMAC_MD5_56
+#endif
+
+/* The older versions of heimdal that don't have this
+ define don't seem to use it anyway. I'm told they
+ always use a subkey */
+#ifndef HAVE_AP_OPTS_USE_SUBKEY
+#define AP_OPTS_USE_SUBKEY 0
+#endif
+
+#ifndef KRB5_PW_SALT
+#define KRB5_PW_SALT 3
+#endif
+
+/* CKSUMTYPE_HMAC_MD5 in Heimdal
+ CKSUMTYPE_HMAC_MD5_ARCFOUR in MIT */
+#if defined(CKSUMTYPE_HMAC_MD5_ARCFOUR) && !defined(CKSUMTYPE_HMAC_MD5)
+#define CKSUMTYPE_HMAC_MD5 CKSUMTYPE_HMAC_MD5_ARCFOUR
+#endif
+
+/*
+ * CKSUMTYPE_HMAC_SHA1_96_AES_* in Heimdal
+ * CKSUMTYPE_HMAC_SHA1_96_AES* in MIT
+ */
+#if defined(CKSUMTYPE_HMAC_SHA1_96_AES128) && !defined(CKSUMTYPE_HMAC_SHA1_96_AES_128)
+#define CKSUMTYPE_HMAC_SHA1_96_AES_128 CKSUMTYPE_HMAC_SHA1_96_AES128
+#endif
+#if defined(CKSUMTYPE_HMAC_SHA1_96_AES256) && !defined(CKSUMTYPE_HMAC_SHA1_96_AES_256)
+#define CKSUMTYPE_HMAC_SHA1_96_AES_256 CKSUMTYPE_HMAC_SHA1_96_AES256
+#endif
+
+/*
+ * KRB5_KU_OTHER_ENCRYPTED in Heimdal
+ * KRB5_KEYUSAGE_APP_DATA_ENCRYPT in MIT
+ */
+#if defined(KRB5_KEYUSAGE_APP_DATA_ENCRYPT) && !defined(KRB5_KU_OTHER_ENCRYPTED)
+#define KRB5_KU_OTHER_ENCRYPTED KRB5_KEYUSAGE_APP_DATA_ENCRYPT
+#endif
+
+typedef struct {
+#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
+ krb5_address **addrs;
+#elif defined(HAVE_KRB5_ADDRESSES) /* Heimdal */
+ krb5_addresses *addrs;
+#else
+#error UNKNOWN_KRB5_ADDRESS_TYPE
+#endif /* defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) */
+} smb_krb5_addresses;
+
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
+#define KRB5_KT_KEY(k) (&(k)->key)
+#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK) /* Heimdal */
+#define KRB5_KT_KEY(k) (&(k)->keyblock)
+#else
+#error krb5_keytab_entry has no key or keyblock member
+#endif /* HAVE_KRB5_KEYTAB_ENTRY_KEY */
+
+/* work around broken krb5.h on sles9 */
+#ifdef SIZEOF_LONG
+#undef SIZEOF_LONG
+#endif
+
+#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE /* Heimdal */
+#define KRB5_KEY_TYPE(k) ((k)->keytype)
+#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length)
+#define KRB5_KEY_DATA(k) ((k)->keyvalue.data)
+#define KRB5_KEY_DATA_CAST void
+#else /* MIT */
+#define KRB5_KEY_TYPE(k) ((k)->enctype)
+#define KRB5_KEY_LENGTH(k) ((k)->length)
+#define KRB5_KEY_DATA(k) ((k)->contents)
+#define KRB5_KEY_DATA_CAST krb5_octet
+#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
+
+#ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR /* Heimdal */
+#define KRB5_ERROR_CODE(k) ((k)->error_code)
+#else /* MIT */
+#define KRB5_ERROR_CODE(k) ((k)->error)
+#endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
+
+#ifndef HAVE_KRB5_CONST_PAC
+#ifdef KRB5_CONST_PAC_GET_BUFFER
+typedef const struct krb5_pac_data *krb5_const_pac;
+#else
+/*
+ * Certain Heimdal versions include a version of krb5_pac_get_buffer() that is
+ * unusable in certain cases, taking a krb5_pac when a krb5_const_pac may be all
+ * that we can supply. Furthermore, MIT Kerberos doesn't declare krb5_const_pac
+ * at all. In such cases, we must declare krb5_const_pac as a non-const typedef
+ * so that the build can succeed.
+ */
+typedef struct krb5_pac_data *krb5_const_pac;
+#endif
+#endif
+
+krb5_error_code smb_krb5_parse_name(krb5_context context,
+ const char *name, /* in unix charset */
+ krb5_principal *principal);
+
+krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_const_principal principal,
+ char **unix_name);
+
+krb5_error_code smb_krb5_init_context_common(krb5_context *_krb5_context);
+
+krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc);
+
+#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
+krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock);
+#endif
+
+#ifndef HAVE_KRB5_FREE_UNPARSED_NAME
+void krb5_free_unparsed_name(krb5_context ctx, char *val);
+#endif
+
+#if !defined(HAVE_KRB5_FREE_ENCTYPES)
+void krb5_free_enctypes(krb5_context context, krb5_enctype *val);
+#endif
+
+#if !defined(HAVE_KRB5_FREE_STRING)
+void krb5_free_string(krb5_context context, char *val);
+#endif
+
+/* Stub out initialize_krb5_error_table since it is not present in all
+ * Kerberos implementations. If it's not present, it's not necessary to
+ * call it.
+ */
+#ifndef HAVE_INITIALIZE_KRB5_ERROR_TABLE
+#define initialize_krb5_error_table()
+#endif
+
+/* Samba wrapper functions for krb5 functionality. */
+bool smb_krb5_sockaddr_to_kaddr(struct sockaddr_storage *paddr,
+ krb5_address *pkaddr);
+
+krb5_error_code smb_krb5_mk_error(krb5_context context,
+ krb5_error_code error_code,
+ const char *e_text,
+ krb5_data *e_data,
+ const krb5_principal client,
+ const krb5_principal server,
+ krb5_data *enc_err);
+
+krb5_error_code smb_krb5_get_allowed_etypes(krb5_context context,
+ krb5_enctype **enctypes);
+
+bool smb_krb5_get_smb_session_key(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_auth_context auth_context,
+ DATA_BLOB *session_key,
+ bool remote);
+
+krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry);
+void smb_krb5_free_data_contents(krb5_context context, krb5_data *pdata);
+krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, const char *client_string, const char *service_string, time_t *expire_time);
+krb5_error_code smb_krb5_gen_netbios_krb5_address(smb_krb5_addresses **kerb_addr,
+ const char *netbios_name);
+krb5_error_code smb_krb5_free_addresses(krb5_context context, smb_krb5_addresses *addr);
+krb5_enctype smb_krb5_kt_get_enctype_from_entry(krb5_keytab_entry *kt_entry);
+
+krb5_error_code smb_krb5_enctype_to_string(krb5_context context,
+ krb5_enctype enctype,
+ char **etype_s);
+krb5_error_code smb_krb5_kt_open_relative(krb5_context context,
+ const char *keytab_name_req,
+ bool write_access,
+ krb5_keytab *keytab);
+krb5_error_code smb_krb5_kt_open(krb5_context context,
+ const char *keytab_name,
+ bool write_access,
+ krb5_keytab *keytab);
+krb5_error_code smb_krb5_kt_get_name(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_keytab keytab,
+ const char **keytab_name);
+krb5_error_code smb_krb5_kt_seek_and_delete_old_entries(krb5_context context,
+ krb5_keytab keytab,
+ bool keep_old_kvno,
+ krb5_kvno kvno,
+ bool enctype_only,
+ krb5_enctype enctype,
+ const char *princ_s,
+ krb5_principal princ,
+ bool flush);
+krb5_error_code smb_krb5_kt_add_entry(krb5_context context,
+ krb5_keytab keytab,
+ krb5_kvno kvno,
+ const char *princ_s,
+ const char *salt_principal,
+ krb5_enctype enctype,
+ krb5_data *password,
+ bool no_salt);
+
+krb5_error_code smb_krb5_get_credentials(krb5_context context,
+ krb5_ccache ccache,
+ krb5_principal me,
+ krb5_principal server,
+ krb5_principal impersonate_princ,
+ krb5_creds **out_creds);
+krb5_error_code smb_krb5_keyblock_init_contents(krb5_context context,
+ krb5_enctype enctype,
+ const void *data,
+ size_t length,
+ krb5_keyblock *key);
+krb5_error_code smb_krb5_kinit_keyblock_ccache(krb5_context ctx,
+ krb5_ccache cc,
+ krb5_principal principal,
+ krb5_keyblock *keyblock,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time);
+krb5_error_code smb_krb5_kinit_password_ccache(krb5_context ctx,
+ krb5_ccache cc,
+ krb5_principal principal,
+ const char *password,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time);
+krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx,
+ krb5_ccache store_cc,
+ krb5_principal init_principal,
+ const char *init_password,
+ krb5_principal impersonate_principal,
+ const char *self_service,
+ const char *target_service,
+ krb5_get_init_creds_opt *krb_options,
+ time_t *expire_time,
+ time_t *kdc_time);
+
+#if defined(HAVE_KRB5_MAKE_PRINCIPAL)
+#define smb_krb5_make_principal krb5_make_principal
+#elif defined(HAVE_KRB5_BUILD_PRINCIPAL_ALLOC_VA)
+krb5_error_code smb_krb5_make_principal(krb5_context context,
+ krb5_principal *principal,
+ const char *realm, ...);
+#else
+#error krb5_make_principal not available
+#endif
+
+#if defined(HAVE_KRB5_CC_GET_LIFETIME)
+#define smb_krb5_cc_get_lifetime krb5_cc_get_lifetime
+#elif defined(HAVE_KRB5_CC_RETRIEVE_CRED)
+krb5_error_code smb_krb5_cc_get_lifetime(krb5_context context,
+ krb5_ccache id,
+ time_t *t);
+#else
+#error krb5_cc_get_lifetime not available
+#endif
+
+#if defined(HAVE_KRB5_FREE_CHECKSUM_CONTENTS)
+#define smb_krb5_free_checksum_contents krb5_free_checksum_contents
+#elif defined (HAVE_FREE_CHECKSUM)
+void smb_krb5_free_checksum_contents(krb5_context ctx, krb5_checksum *cksum);
+#else
+#error krb5_free_checksum_contents/free_Checksum is not available
+#endif
+
+krb5_error_code smb_krb5_make_pac_checksum(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pac_data,
+ krb5_context context,
+ const krb5_keyblock *keyblock,
+ uint32_t *sig_type,
+ DATA_BLOB *sig_blob);
+
+char *smb_krb5_principal_get_realm(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_const_principal principal);
+
+void smb_krb5_principal_set_type(krb5_context context,
+ krb5_principal principal,
+ int type);
+
+int smb_krb5_principal_is_tgs(krb5_context context,
+ krb5_const_principal principal);
+
+krb5_error_code smb_krb5_principal_set_realm(krb5_context context,
+ krb5_principal principal,
+ const char *realm);
+
+char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
+ const char *hostname,
+ const char *client_realm);
+
+char *smb_get_krb5_error_message(krb5_context context,
+ krb5_error_code code,
+ TALLOC_CTX *mem_ctx);
+
+#if defined(HAVE_KRB5_KT_COMPARE)
+#define smb_krb5_kt_compare krb5_kt_compare
+#else
+krb5_boolean smb_krb5_kt_compare(krb5_context context,
+ krb5_keytab_entry *entry,
+ krb5_const_principal principal,
+ krb5_kvno vno,
+ krb5_enctype enctype);
+#endif
+
+const krb5_enctype *samba_all_enctypes(void);
+
+uint32_t kerberos_enctype_to_bitmap(krb5_enctype enc_type_enum);
+krb5_enctype ms_suptype_to_ietf_enctype(uint32_t enctype_bitmap);
+krb5_error_code ms_suptypes_to_ietf_enctypes(TALLOC_CTX *mem_ctx,
+ uint32_t enctype_bitmap,
+ krb5_enctype **enctypes);
+int smb_krb5_get_pw_salt(krb5_context context,
+ krb5_const_principal host_princ,
+ krb5_data *psalt);
+int smb_krb5_salt_principal(krb5_context krb5_ctx,
+ const char *realm,
+ const char *sAMAccountName,
+ const char *userPrincipalName,
+ uint32_t uac_flags,
+ krb5_principal *salt_princ);
+
+int smb_krb5_salt_principal_str(const char *realm,
+ const char *sAMAccountName,
+ const char *userPrincipalName,
+ uint32_t uac_flags,
+ TALLOC_CTX *mem_ctx,
+ char **_salt_principal);
+int smb_krb5_salt_principal2data(krb5_context context,
+ const char *salt_principal,
+ TALLOC_CTX *mem_ctx,
+ char **_salt_data);
+
+int smb_krb5_create_key_from_string(krb5_context context,
+ krb5_const_principal host_princ,
+ const krb5_data *salt,
+ const krb5_data *password,
+ krb5_enctype enctype,
+ krb5_keyblock *key);
+
+#ifndef krb5_princ_size
+#if defined(HAVE_KRB5_PRINCIPAL_GET_NUM_COMP)
+#define krb5_princ_size krb5_principal_get_num_comp
+#else
+#error krb5_princ_size unavailable
+#endif
+#endif
+
+krb5_error_code smb_krb5_principal_get_comp_string(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ krb5_const_principal principal,
+ unsigned int component,
+ char **out);
+
+krb5_error_code smb_krb5_copy_data_contents(krb5_data *p,
+ const void *data,
+ size_t len);
+
+krb5_data smb_krb5_make_data(void *data,
+ size_t len);
+
+krb5_data smb_krb5_data_from_blob(DATA_BLOB blob);
+
+int smb_krb5_principal_get_type(krb5_context context,
+ krb5_const_principal principal);
+
+#if !defined(HAVE_KRB5_WARNX)
+krb5_error_code krb5_warnx(krb5_context context, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2, 0);
+#endif
+
+krb5_error_code smb_krb5_cc_copy_creds(krb5_context context,
+ krb5_ccache incc, krb5_ccache outcc);
+
+#endif /* HAVE_KRB5 */
+
+int ads_krb5_cli_get_ticket(TALLOC_CTX *mem_ctx,
+ const char *principal,
+ time_t time_offset,
+ DATA_BLOB *ticket,
+ DATA_BLOB *session_key_krb5,
+ uint32_t extra_ap_opts, const char *ccname,
+ time_t *tgs_expire,
+ const char *impersonate_princ_s);
+
+NTSTATUS krb5_to_nt_status(krb5_error_code kerberos_error);
+krb5_error_code nt_status_to_krb5(NTSTATUS nt_status);
+
+#endif /* _KRB5_SAMBA_H */
diff --git a/lib/krb5_wrap/wscript_build b/lib/krb5_wrap/wscript_build
new file mode 100644
index 0000000..dd9fc08
--- /dev/null
+++ b/lib/krb5_wrap/wscript_build
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+add_deps = ''
+if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'):
+ add_deps = ' asn1'
+
+bld.SAMBA_LIBRARY('krb5samba',
+ source='''
+ krb5_samba.c
+ gss_samba.c
+ keytab_util.c
+ enctype_convert.c
+ krb5_errs.c
+ ''',
+ deps='''
+ samba-util
+ talloc
+ krb5
+ com_err
+ gssapi
+ ''' + add_deps,
+ private_library=True
+ )
diff --git a/lib/krb5_wrap/wscript_configure b/lib/krb5_wrap/wscript_configure
new file mode 100644
index 0000000..b595eef
--- /dev/null
+++ b/lib/krb5_wrap/wscript_configure
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Check whether we have the krb5_const_pac type, if we aren't sure already.
+if conf.CONFIG_SET('HAVE_KRB5_CONST_PAC') or (
+ conf.CHECK_TYPE('krb5_const_pac',
+ headers='krb5.h',
+ lib='krb5')):
+ # If the type is available, check whether krb5_pac_get_buffer() accepts it
+ # as its second parameter, or whether it takes krb5_pac instead.
+ conf.CHECK_C_PROTOTYPE('krb5_pac_get_buffer',
+ 'krb5_error_code krb5_pac_get_buffer('
+ ' krb5_context context,'
+ ' krb5_const_pac p,'
+ ' uint32_t type,'
+ ' krb5_data *data)',
+ define='KRB5_CONST_PAC_GET_BUFFER',
+ headers='krb5.h',
+ lib='krb5')
diff --git a/lib/ldb-samba/README b/lib/ldb-samba/README
new file mode 100644
index 0000000..3fa4715
--- /dev/null
+++ b/lib/ldb-samba/README
@@ -0,0 +1,7 @@
+This directory contains Samba specific extensions to ldb. It also
+serves as example code on how to extend ldb for your own application.
+
+The main extension Samba uses is to provide ldif encode/decode
+routines for specific attributes, so users can get nice pretty
+printing of attributes in ldbedit, while the attributes are stored in
+the standard NDR format in the database.
diff --git a/lib/ldb-samba/ldb_ildap.c b/lib/ldb-samba/ldb_ildap.c
new file mode 100644
index 0000000..37ef185
--- /dev/null
+++ b/lib/ldb-samba/ldb_ildap.c
@@ -0,0 +1,1018 @@
+/*
+ ldb database library - ildap backend
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Simo Sorce 2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_ildap
+ *
+ * Component: ldb ildap backend
+ *
+ * Description: This is a ldb backend for the internal ldap
+ * client library in Samba4. By using this backend we are
+ * independent of a system ldap library
+ *
+ * Author: Andrew Tridgell
+ *
+ * Modifications:
+ *
+ * - description: make the module use asynchronous calls
+ * date: Feb 2006
+ * author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb_module.h"
+#include "util/dlinklist.h"
+
+#include "libcli/ldap/libcli_ldap.h"
+#include "libcli/ldap/ldap_client.h"
+#include "auth/auth.h"
+#include "auth/credentials/credentials.h"
+#include "dsdb/common/util.h"
+
+struct ildb_private {
+ struct ldap_connection *ldap;
+ struct tevent_context *event_ctx;
+};
+
+struct ildb_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ struct ildb_private *ildb;
+ struct ldap_request *ireq;
+
+ /* indicate we are already processing
+ * the ldap_request in ildb_callback() */
+ bool in_ildb_callback;
+
+ bool done;
+
+ struct ildb_destructor_ctx *dc;
+};
+
+static void ildb_request_done(struct ildb_context *ctx,
+ struct ldb_control **ctrls, int error)
+{
+ struct ldb_context *ldb;
+ struct ldb_reply *ares;
+
+ ldb = ldb_module_get_ctx(ctx->module);
+
+ ctx->done = true;
+
+ if (ctx->req == NULL) {
+ /* if the req has been freed already just return */
+ return;
+ }
+
+ ares = talloc_zero(ctx->req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(ldb);
+ ctx->req->callback(ctx->req, NULL);
+ return;
+ }
+ ares->type = LDB_REPLY_DONE;
+ ares->controls = talloc_steal(ares, ctrls);
+ ares->error = error;
+
+ ctx->req->callback(ctx->req, ares);
+}
+
+static void ildb_auto_done_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *private_data)
+{
+ struct ildb_context *ac;
+
+ ac = talloc_get_type(private_data, struct ildb_context);
+ ildb_request_done(ac, NULL, LDB_SUCCESS);
+}
+
+/*
+ convert a ldb_message structure to a list of ldap_mod structures
+ ready for ildap_add() or ildap_modify()
+*/
+static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, unsigned int *num_mods,
+ const struct ldb_message *msg,
+ int use_flags)
+{
+ struct ldap_mod **mods;
+ unsigned int i;
+ unsigned int n = 0;
+
+ /* allocate maximum number of elements needed */
+ mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1);
+ if (!mods) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mods[0] = NULL;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+
+ mods[n] = talloc(mods, struct ldap_mod);
+ if (!mods[n]) {
+ goto failed;
+ }
+ mods[n + 1] = NULL;
+ mods[n]->type = 0;
+ mods[n]->attrib = *el;
+ if (use_flags) {
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ mods[n]->type = LDAP_MODIFY_ADD;
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ mods[n]->type = LDAP_MODIFY_DELETE;
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ mods[n]->type = LDAP_MODIFY_REPLACE;
+ break;
+ }
+ }
+ n++;
+ }
+
+ *num_mods = n;
+ return mods;
+
+failed:
+ talloc_free(mods);
+ return NULL;
+}
+
+
+/*
+ map an ildap NTSTATUS to a ldb error code
+*/
+static int ildb_map_error(struct ldb_module *module, NTSTATUS status)
+{
+ struct ildb_private *ildb;
+ struct ldb_context *ldb;
+ TALLOC_CTX *mem_ctx;
+
+ ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private);
+ ldb = ldb_module_get_ctx(module);
+
+ if (NT_STATUS_IS_OK(status)) {
+ return LDB_SUCCESS;
+ }
+
+ mem_ctx = talloc_new(ildb);
+ if (!mem_ctx) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ldb_set_errstring(ldb,
+ ldap_errstr(ildb->ldap, mem_ctx, status));
+ talloc_free(mem_ctx);
+ if (NT_STATUS_IS_LDAP(status)) {
+ return NT_STATUS_LDAP_CODE(status);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static void ildb_request_timeout(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct ildb_context *ac = talloc_get_type(private_data, struct ildb_context);
+
+ if (ac->ireq->state == LDAP_REQUEST_PENDING) {
+ DLIST_REMOVE(ac->ireq->conn->pending, ac->ireq);
+ }
+
+ ildb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED);
+}
+
+static void ildb_callback(struct ldap_request *req)
+{
+ struct ldb_context *ldb;
+ struct ildb_context *ac;
+ NTSTATUS status;
+ struct ldap_SearchResEntry *search;
+ struct ldap_message *msg;
+ struct ldb_control **controls;
+ struct ldb_message *ldbmsg;
+ char *referral;
+ bool callback_failed;
+ bool request_done;
+ int ret;
+ int i;
+
+ ac = talloc_get_type(req->async.private_data, struct ildb_context);
+ ldb = ldb_module_get_ctx(ac->module);
+ callback_failed = false;
+ request_done = false;
+ controls = NULL;
+
+ /* check if we are already processing this request */
+ if (ac->in_ildb_callback) {
+ return;
+ }
+ /* mark the request as being in process */
+ ac->in_ildb_callback = true;
+
+ if (!NT_STATUS_IS_OK(req->status)) {
+ ret = ildb_map_error(ac->module, req->status);
+ ildb_request_done(ac, NULL, ret);
+ return;
+ }
+
+ if (req->num_replies < 1) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ ildb_request_done(ac, NULL, ret);
+ return;
+ }
+
+ switch (req->type) {
+
+ case LDAP_TAG_ModifyRequest:
+ if (req->replies[0]->type != LDAP_TAG_ModifyResponse) {
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+ status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
+ ret = ildb_map_error(ac->module, status);
+ request_done = true;
+ break;
+
+ case LDAP_TAG_AddRequest:
+ if (req->replies[0]->type != LDAP_TAG_AddResponse) {
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
+ ret = ildb_map_error(ac->module, status);
+ request_done = true;
+ break;
+
+ case LDAP_TAG_DelRequest:
+ if (req->replies[0]->type != LDAP_TAG_DelResponse) {
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
+ ret = ildb_map_error(ac->module, status);
+ request_done = true;
+ break;
+
+ case LDAP_TAG_ModifyDNRequest:
+ if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) {
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
+ ret = ildb_map_error(ac->module, status);
+ request_done = true;
+ break;
+
+ case LDAP_TAG_SearchRequest:
+ /* loop over all messages */
+ ret = LDB_SUCCESS;
+ for (i = 0; i < req->num_replies; i++) {
+
+ msg = req->replies[i];
+ switch (msg->type) {
+
+ case LDAP_TAG_SearchResultDone:
+
+ status = ldap_check_response(ac->ireq->conn, &msg->r.GeneralResult);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = ildb_map_error(ac->module, status);
+ break;
+ }
+
+ controls = talloc_steal(ac, msg->controls);
+ if (msg->r.SearchResultDone.resultcode) {
+ if (msg->r.SearchResultDone.errormessage) {
+ ldb_set_errstring(ldb, msg->r.SearchResultDone.errormessage);
+ }
+ }
+
+ ret = msg->r.SearchResultDone.resultcode;
+ request_done = true;
+ break;
+
+ case LDAP_TAG_SearchResultEntry:
+
+ ldbmsg = ldb_msg_new(ac);
+ if (!ldbmsg) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+
+ search = &(msg->r.SearchResultEntry);
+
+ ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, search->dn);
+ if ( ! ldb_dn_validate(ldbmsg->dn)) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+ ldbmsg->num_elements = search->num_attributes;
+ ldbmsg->elements = talloc_move(ldbmsg, &search->attributes);
+
+ controls = talloc_steal(ac, msg->controls);
+
+ ret = ldb_module_send_entry(ac->req, ldbmsg, controls);
+ if (ret != LDB_SUCCESS) {
+ callback_failed = true;
+ }
+
+ break;
+
+ case LDAP_TAG_SearchResultReference:
+
+ referral = talloc_strdup(ac, msg->r.SearchResultReference.referral);
+
+ ret = ldb_module_send_referral(ac->req, referral);
+ if (ret != LDB_SUCCESS) {
+ callback_failed = true;
+ }
+
+ break;
+
+ default:
+ /* TAG not handled, fail ! */
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ break;
+ }
+ }
+
+ talloc_free(req->replies);
+ req->replies = NULL;
+ req->num_replies = 0;
+
+ break;
+
+ case LDAP_TAG_ExtendedRequest: {
+
+ struct ldap_ExtendedResponse *ext_response = NULL;
+ struct ldb_reply *ares = NULL;
+
+ if (req->replies[0]->type != LDAP_TAG_ExtendedResponse) {
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ ext_response = &req->replies[0]->r.ExtendedResponse;
+
+ status = ldap_check_response(ac->ireq->conn,
+ &req->replies[0]->r.GeneralResult);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = ildb_map_error(ac->module, status);
+ request_done = true;
+ break;
+ }
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (ares == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ request_done = true;
+ break;
+ }
+
+ ares->type = LDB_REPLY_DONE;
+
+ ares->response = talloc_zero(ares, struct ldb_extended);
+ if (ares->response == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ request_done = true;
+ break;
+ }
+
+ ares->response->oid =
+ talloc_strdup(ares->response, ext_response->oid);
+ if (ares->response->oid == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ request_done = true;
+ break;
+ }
+
+ if (ext_response->value != NULL) {
+ ares->response->data =
+ talloc_memdup(ares->response,
+ ext_response->value->data,
+ ext_response->value->length);
+ if (ares->response->data == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ request_done = true;
+ break;
+ }
+ }
+
+ ares->controls = talloc_move(ares, &req->replies[0]->controls);
+
+ ac->req->callback(ac->req, ares);
+ return;
+ }
+
+ default:
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+
+ if (ret != LDB_SUCCESS) {
+
+ /* if the callback failed the caller will have freed the
+ * request. Just return and don't try to use it */
+ if ( ! callback_failed) {
+ request_done = true;
+ }
+ }
+
+ /* mark the request as not being in progress */
+ ac->in_ildb_callback = false;
+
+ if (request_done) {
+ ildb_request_done(ac, controls, ret);
+ }
+
+ return;
+}
+
+static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg)
+{
+ struct ldb_context *ldb;
+ struct ldap_request *req;
+
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ ldb_request_set_state(ac->req, LDB_ASYNC_PENDING);
+
+ req = ldap_request_send(ac->ildb->ldap, msg);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "async send request failed");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->ireq = talloc_reparent(ac->ildb->ldap, ac, req);
+
+ if (!ac->ireq->conn) {
+ ldb_set_errstring(ldb, "connection to remote LDAP server dropped?");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ TALLOC_FREE(req->time_event);
+ if (ac->req->timeout > 0) {
+ struct timeval tv = {
+ .tv_sec = ac->req->starttime + ac->req->timeout,
+ };
+
+ req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac, tv,
+ ildb_request_timeout, ac);
+ }
+
+ req->async.fn = ildb_callback;
+ req->async.private_data = ac;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ search for matching records using an asynchronous function
+ */
+static int ildb_search(struct ildb_context *ac)
+{
+ struct ldb_context *ldb;
+ struct ldb_request *req = ac->req;
+ struct ldap_message *msg;
+ int n;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(ldb, "Invalid expression parse tree");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg = new_ldap_message(req);
+ if (msg == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_SearchRequest;
+
+ if (req->op.search.base == NULL) {
+ msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
+ } else {
+ msg->r.SearchRequest.basedn = ldb_dn_get_extended_linearized(msg, req->op.search.base, 0);
+ }
+ if (msg->r.SearchRequest.basedn == NULL) {
+ ldb_set_errstring(ldb, "Unable to determine baseDN");
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ switch (req->op.search.scope) {
+ case LDB_SCOPE_DEFAULT:
+ case LDB_SCOPE_SUBTREE:
+ msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_SUB;
+ break;
+ case LDB_SCOPE_BASE:
+ msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
+ break;
+ case LDB_SCOPE_ONELEVEL:
+ msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_SINGLE;
+ break;
+ }
+
+ msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ msg->r.SearchRequest.timelimit = 0;
+ msg->r.SearchRequest.sizelimit = 0;
+ msg->r.SearchRequest.attributesonly = 0;
+ msg->r.SearchRequest.tree = discard_const(req->op.search.tree);
+
+ for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ;
+ msg->r.SearchRequest.num_attributes = n;
+ msg->r.SearchRequest.attributes = req->op.search.attrs;
+ msg->controls = req->controls;
+
+ return ildb_request_send(ac, msg);
+}
+
+/*
+ add a record
+*/
+static int ildb_add(struct ildb_context *ac)
+{
+ struct ldb_request *req = ac->req;
+ struct ldap_message *msg;
+ struct ldap_mod **mods;
+ unsigned int i,n;
+
+ msg = new_ldap_message(req);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_AddRequest;
+
+ msg->r.AddRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.add.message->dn, 0);
+ if (msg->r.AddRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0);
+ if (mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->r.AddRequest.num_attributes = n;
+ msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
+ if (msg->r.AddRequest.attributes == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < n; i++) {
+ msg->r.AddRequest.attributes[i] = mods[i]->attrib;
+ }
+ msg->controls = req->controls;
+
+ return ildb_request_send(ac, msg);
+}
+
+/*
+ modify a record
+*/
+static int ildb_modify(struct ildb_context *ac)
+{
+ struct ldb_request *req = ac->req;
+ struct ldap_message *msg;
+ struct ldap_mod **mods;
+ unsigned int i,n;
+
+ msg = new_ldap_message(req);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_ModifyRequest;
+
+ msg->r.ModifyRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.mod.message->dn, 0);
+ if (msg->r.ModifyRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
+ if (mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->r.ModifyRequest.num_mods = n;
+ msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
+ if (msg->r.ModifyRequest.mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < n; i++) {
+ msg->r.ModifyRequest.mods[i] = *mods[i];
+ }
+ msg->controls = req->controls;
+ return ildb_request_send(ac, msg);
+}
+
+/*
+ delete a record
+*/
+static int ildb_delete(struct ildb_context *ac)
+{
+ struct ldb_request *req = ac->req;
+ struct ldap_message *msg;
+
+ msg = new_ldap_message(req);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_DelRequest;
+
+ msg->r.DelRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.del.dn, 0);
+ if (msg->r.DelRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ msg->controls = req->controls;
+
+ return ildb_request_send(ac, msg);
+}
+
+/*
+ rename a record
+*/
+static int ildb_rename(struct ildb_context *ac)
+{
+ struct ldb_request *req = ac->req;
+ struct ldap_message *msg;
+ const char *rdn_name;
+ const struct ldb_val *rdn_val;
+
+ msg = new_ldap_message(req);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ msg->r.ModifyDNRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.rename.olddn, 0);
+ if (msg->r.ModifyDNRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
+ rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);
+
+ if ((rdn_name != NULL) && (rdn_val != NULL)) {
+ msg->r.ModifyDNRequest.newrdn =
+ talloc_asprintf(msg, "%s=%s", rdn_name,
+ rdn_val->length > 0 ? ldb_dn_escape_value(msg, *rdn_val) : "");
+ } else {
+ msg->r.ModifyDNRequest.newrdn = talloc_strdup(msg, "");
+ }
+ if (msg->r.ModifyDNRequest.newrdn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->r.ModifyDNRequest.newsuperior =
+ ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn));
+ if (msg->r.ModifyDNRequest.newsuperior == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ msg->r.ModifyDNRequest.deleteolddn = true;
+ msg->controls = req->controls;
+
+ return ildb_request_send(ac, msg);
+}
+
+/*
+ * Issue an extended operation
+ */
+static int ildb_extended(struct ildb_context *ac)
+{
+ struct ldb_request *req = ac->req;
+ struct ldb_extended *extended_req = NULL;
+ struct ldap_message *msg = NULL;
+ DATA_BLOB *value = NULL;
+
+ if (req->operation != LDB_EXTENDED) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ extended_req = &req->op.extended;
+
+ msg = new_ldap_message(req);
+ if (msg == NULL) {
+ goto nomem;
+ }
+
+ if (extended_req->data != NULL) {
+ value = talloc(req, DATA_BLOB);
+ if (value == NULL) {
+ goto nomem;
+ }
+ *value = data_blob_talloc(value,
+ extended_req->data,
+ talloc_get_size(extended_req->data));
+ if (value->data == NULL) {
+ goto nomem;
+ }
+ }
+
+ *msg = (struct ldap_message){
+ .type = LDAP_TAG_ExtendedRequest,
+ .r.ExtendedRequest.oid = extended_req->oid,
+ .r.ExtendedRequest.value = value,
+ .controls = req->controls,
+ };
+
+ return ildb_request_send(ac, msg);
+nomem:
+ TALLOC_FREE(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int ildb_start_trans(struct ldb_module *module)
+{
+ /* TODO implement a local locking mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int ildb_end_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int ildb_del_trans(struct ldb_module *module)
+{
+ /* TODO implement a local locking mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static bool ildb_dn_is_special(struct ldb_request *req)
+{
+ struct ldb_dn *dn = NULL;
+
+ switch (req->operation) {
+ case LDB_SEARCH:
+ dn = req->op.search.base;
+ break;
+ case LDB_ADD:
+ dn = req->op.add.message->dn;
+ break;
+ case LDB_MODIFY:
+ dn = req->op.mod.message->dn;
+ break;
+ case LDB_DELETE:
+ dn = req->op.del.dn;
+ break;
+ case LDB_RENAME:
+ dn = req->op.rename.olddn;
+ break;
+ default:
+ break;
+ }
+
+ if (dn && ldb_dn_is_special(dn)) {
+ return true;
+ }
+ return false;
+}
+
+static int ildb_handle_request(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct ildb_private *ildb;
+ struct ildb_context *ac;
+ struct tevent_timer *te;
+ int ret;
+
+ ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private);
+ ldb = ldb_module_get_ctx(module);
+
+ if (req->starttime == 0 || req->timeout == 0) {
+ ldb_set_errstring(ldb, "Invalid timeout settings");
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+
+ ac = talloc_zero(req, struct ildb_context);
+ if (ac == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+ ac->ildb = ildb;
+
+ if (ildb_dn_is_special(req)) {
+
+ te = tevent_add_timer(ac->ildb->event_ctx,
+ ac, timeval_zero(),
+ ildb_auto_done_callback, ac);
+ if (NULL == te) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+ }
+
+ switch (ac->req->operation) {
+ case LDB_SEARCH:
+ ret = ildb_search(ac);
+ break;
+ case LDB_ADD:
+ ret = ildb_add(ac);
+ break;
+ case LDB_MODIFY:
+ ret = ildb_modify(ac);
+ break;
+ case LDB_DELETE:
+ ret = ildb_delete(ac);
+ break;
+ case LDB_RENAME:
+ ret = ildb_rename(ac);
+ break;
+ case LDB_EXTENDED:
+ ret = ildb_extended(ac);
+ break;
+ default:
+ /* no other op supported */
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct ldb_module_ops ildb_ops = {
+ .name = "ldap",
+ .search = ildb_handle_request,
+ .add = ildb_handle_request,
+ .modify = ildb_handle_request,
+ .del = ildb_handle_request,
+ .rename = ildb_handle_request,
+ .extended = ildb_handle_request,
+/* .request = ildb_handle_request, */
+ .start_transaction = ildb_start_trans,
+ .end_transaction = ildb_end_trans,
+ .del_transaction = ildb_del_trans,
+};
+
+/*
+ connect to the database
+*/
+static int ildb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[],
+ struct ldb_module **_module)
+{
+ struct ldb_module *module;
+ struct ildb_private *ildb;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ struct cli_credentials *creds;
+ struct loadparm_context *lp_ctx;
+
+ module = ldb_module_new(ldb, ldb, "ldb_ildap backend", &ildb_ops);
+ if (!module) return LDB_ERR_OPERATIONS_ERROR;
+
+ ildb = talloc(module, struct ildb_private);
+ if (!ildb) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+ ldb_module_set_private(module, ildb);
+
+ ildb->event_ctx = ldb_get_event_context(ldb);
+
+ lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
+ struct loadparm_context);
+
+ ildb->ldap = ldap4_new_connection(ildb, lp_ctx,
+ ildb->event_ctx);
+ if (!ildb->ldap) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+
+ if (flags & LDB_FLG_RECONNECT) {
+ ldap_set_reconn_params(ildb->ldap, 10);
+ }
+
+ status = ldap_connect(ildb->ldap, url);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s",
+ url, ldap_errstr(ildb->ldap, module, status));
+ goto failed;
+ }
+
+ /* caller can optionally setup credentials using the opaque token 'credentials' */
+ creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
+ if (creds == NULL) {
+ struct auth_session_info *session_info = talloc_get_type(
+ ldb_get_opaque(ldb, DSDB_SESSION_INFO),
+ struct auth_session_info);
+ if (session_info) {
+ creds = session_info->credentials;
+ }
+ }
+
+ if (creds != NULL && cli_credentials_authentication_requested(creds)) {
+ const char *bind_dn = cli_credentials_get_bind_dn(creds);
+ if (bind_dn) {
+ const char *password = cli_credentials_get_password(creds);
+ status = ldap_bind_simple(ildb->ldap, bind_dn, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
+ ldap_errstr(ildb->ldap, module, status));
+ goto failed;
+ }
+ } else {
+ status = ldap_bind_sasl(ildb->ldap, creds, lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
+ ldap_errstr(ildb->ldap, module, status));
+ goto failed;
+ }
+ }
+ }
+
+ *_module = module;
+ return LDB_SUCCESS;
+
+failed:
+ if (ildb != NULL && ildb->ldap != NULL) {
+ ldb_set_errstring(ldb, ldap_errstr(ildb->ldap, module, status));
+ }
+ talloc_free(module);
+ if (NT_STATUS_IS_LDAP(status)) {
+ return NT_STATUS_LDAP_CODE(status);
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)
+ || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
+ || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
+ || NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
+ return LDB_ERR_INVALID_CREDENTIALS;
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+ initialise the module
+ */
+_PUBLIC_ int ldb_ildap_init(const char *ldb_version)
+{
+ int ret, i;
+ const char *names[] = { "ldap", "ldaps", "ldapi", NULL };
+ for (i=0; names[i]; i++) {
+ ret = ldb_register_backend(names[i], ildb_connect, true);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb-samba/ldb_matching_rules.c b/lib/ldb-samba/ldb_matching_rules.c
new file mode 100644
index 0000000..59d1385
--- /dev/null
+++ b/lib/ldb-samba/ldb_matching_rules.c
@@ -0,0 +1,636 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ ldb database library - Extended match rules
+
+ Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
+ Copyright (C) Andrew Bartlett <abartlet@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <ldb_module.h>
+#include "dsdb/samdb/samdb.h"
+#include "ldb_matching_rules.h"
+#include "libcli/security/security.h"
+#include "dsdb/common/util.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "lib/util/smb_strtox.h"
+
+#undef strcasecmp
+
+static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ const char *attr,
+ const struct dsdb_dn *dn_to_match,
+ const char *dn_oid,
+ struct dsdb_dn *to_visit,
+ struct dsdb_dn ***visited,
+ unsigned int *visited_count,
+ bool *matched)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret, i, j;
+ struct ldb_result *res;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ const char *attrs[] = { attr, NULL };
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Fetch the entry to_visit
+ *
+ * NOTE: This is a new LDB search from the TOP of the module
+ * stack. This means that this search runs the whole stack
+ * from top to bottom.
+ *
+ * This may seem to be in-efficient, but it is also the only
+ * way to ensure that the ACLs for this search are applied
+ * correctly.
+ *
+ * Note also that we don't have the original request
+ * here, so we can not apply controls or timeouts here.
+ */
+ ret = dsdb_search_dn(ldb,
+ tmp_ctx,
+ &res,
+ to_visit->dn,
+ attrs,
+ DSDB_MARK_REQ_UNTRUSTED);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ if (res->count != 1) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg = res->msgs[0];
+
+ /* Fetch the attribute to match from the entry being visited */
+ el = ldb_msg_find_element(msg, attr);
+ if (el == NULL) {
+ /* This entry does not have the attribute to match */
+ talloc_free(tmp_ctx);
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * If the value to match is present in the attribute values of the
+ * current entry being visited, set matched to true and return OK
+ */
+ for (i=0; i<el->num_values; i++) {
+ struct dsdb_dn *dn;
+ dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
+ if (dn == NULL) {
+ talloc_free(tmp_ctx);
+ *matched = false;
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ if (ldb_dn_compare(dn_to_match->dn, dn->dn) == 0) {
+ talloc_free(tmp_ctx);
+ *matched = true;
+ return LDB_SUCCESS;
+ }
+ }
+
+ /*
+ * If arrived here, the value to match is not in the values of the
+ * entry being visited. Add the entry being visited (to_visit)
+ * to the visited array. The array is (re)allocated in the parent
+ * memory context.
+ */
+ if (visited == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ } else if (*visited == NULL) {
+ *visited = talloc_array(mem_ctx, struct dsdb_dn *, 1);
+ if (*visited == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ (*visited)[0] = to_visit;
+ (*visited_count) = 1;
+ } else {
+ *visited = talloc_realloc(mem_ctx, *visited, struct dsdb_dn *,
+ (*visited_count) + 1);
+ if (*visited == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ (*visited)[(*visited_count)] = to_visit;
+ (*visited_count)++;
+ }
+
+ /*
+ * steal to_visit into visited array context, as it has to live until
+ * the array is freed.
+ */
+ talloc_steal(*visited, to_visit);
+
+ /*
+ * Iterate over the values of the attribute of the entry being
+ * visited (to_visit) and follow them, calling this function
+ * recursively.
+ * If the value is in the visited array, skip it.
+ * Otherwise, follow the link and visit it.
+ */
+ for (i=0; i<el->num_values; i++) {
+ struct dsdb_dn *next_to_visit;
+ bool skip = false;
+
+ next_to_visit = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], dn_oid);
+ if (next_to_visit == NULL) {
+ talloc_free(tmp_ctx);
+ *matched = false;
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ /*
+ * If the value is already in the visited array, skip it.
+ * Note the last element of the array is ignored because it is
+ * the current entry DN.
+ */
+ for (j=0; j < (*visited_count) - 1; j++) {
+ struct dsdb_dn *visited_dn = (*visited)[j];
+ if (ldb_dn_compare(visited_dn->dn,
+ next_to_visit->dn) == 0) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip) {
+ talloc_free(next_to_visit);
+ continue;
+ }
+
+ /* If the value is not in the visited array, evaluate it */
+ ret = ldb_eval_transitive_filter_helper(tmp_ctx, ldb, attr,
+ dn_to_match, dn_oid,
+ next_to_visit,
+ visited, visited_count,
+ matched);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ if (*matched) {
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ *matched = false;
+ return LDB_SUCCESS;
+}
+
+/*
+ * This function parses the linked attribute value to match, whose syntax
+ * will be one of the different DN syntaxes, into a ldb_dn struct.
+ */
+static int ldb_eval_transitive_filter(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ const char *attr,
+ const struct ldb_val *value_to_match,
+ struct dsdb_dn *current_object_dn,
+ bool *matched)
+{
+ const struct dsdb_schema *schema;
+ const struct dsdb_attribute *schema_attr;
+ struct dsdb_dn *dn_to_match;
+ const char *dn_oid;
+ unsigned int count;
+ struct dsdb_dn **visited = NULL;
+
+ schema = dsdb_get_schema(ldb, mem_ctx);
+ if (schema == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attr);
+ if (schema_attr == NULL) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ /* This is the DN syntax of the attribute being matched */
+ dn_oid = schema_attr->syntax->ldap_oid;
+
+ /*
+ * Build a ldb_dn struct holding the value to match, which is the
+ * value entered in the search filter
+ */
+ dn_to_match = dsdb_dn_parse(mem_ctx, ldb, value_to_match, dn_oid);
+ if (dn_to_match == NULL) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ return ldb_eval_transitive_filter_helper(mem_ctx, ldb, attr,
+ dn_to_match, dn_oid,
+ current_object_dn,
+ &visited, &count, matched);
+}
+
+/*
+ * This rule provides recursive search of a link attribute
+ *
+ * Documented in [MS-ADTS] section 3.1.1.3.4.4.3 LDAP_MATCHING_RULE_TRANSITIVE_EVAL
+ * This allows a search filter such as:
+ *
+ * member:1.2.840.113556.1.4.1941:=cn=user,cn=users,dc=samba,dc=example,dc=com
+ *
+ * This searches not only the member attribute, but also any member
+ * attributes that point at an object with this member in them. All the
+ * various DN syntax types are supported, not just plain DNs.
+ *
+ */
+static int ldb_comparator_trans(struct ldb_context *ldb,
+ const char *oid,
+ const struct ldb_message *msg,
+ const char *attribute_to_match,
+ const struct ldb_val *value_to_match,
+ bool *matched)
+{
+ const struct dsdb_schema *schema;
+ const struct dsdb_attribute *schema_attr;
+ struct ldb_dn *msg_dn;
+ struct dsdb_dn *dsdb_msg_dn;
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * If the target attribute to match is not a linked attribute, then
+ * the filter evaluates to undefined
+ */
+ schema = dsdb_get_schema(ldb, tmp_ctx);
+ if (schema == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attribute_to_match);
+ if (schema_attr == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ /*
+ * This extended match filter is only valid for linked attributes,
+ * following the MS definition (the schema attribute has a linkID
+ * defined). See dochelp request 114111212024789 on cifs-protocols
+ * mailing list.
+ */
+ if (schema_attr->linkID == 0) {
+ *matched = false;
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+
+ /* Duplicate original msg dn as the msg must not be modified */
+ msg_dn = ldb_dn_copy(tmp_ctx, msg->dn);
+ if (msg_dn == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Build a dsdb dn from the message copied DN, which should be a plain
+ * DN syntax.
+ */
+ dsdb_msg_dn = dsdb_dn_construct(tmp_ctx, msg_dn, data_blob_null,
+ LDB_SYNTAX_DN);
+ if (dsdb_msg_dn == NULL) {
+ *matched = false;
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ ret = ldb_eval_transitive_filter(tmp_ctx, ldb,
+ attribute_to_match,
+ value_to_match,
+ dsdb_msg_dn, matched);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+/*
+ * This rule provides match of a dns object with expired records.
+ *
+ * This allows a search filter such as:
+ *
+ * dnsRecord:1.3.6.1.4.1.7165.4.5.3:=3694869
+ *
+ * where the value is a number of hours since the start of 1601.
+ *
+ * This allows the caller to find records that should become a DNS
+ * tomestone, despite that information being deep within an NDR packed
+ * object
+ */
+static int dsdb_match_for_dns_to_tombstone_time(struct ldb_context *ldb,
+ const char *oid,
+ const struct ldb_message *msg,
+ const char *attribute_to_match,
+ const struct ldb_val *value_to_match,
+ bool *matched)
+{
+ TALLOC_CTX *tmp_ctx;
+ unsigned int i;
+ struct ldb_message_element *el = NULL;
+ struct auth_session_info *session_info = NULL;
+ uint64_t tombstone_time;
+ struct dnsp_DnssrvRpcRecord *rec = NULL;
+ enum ndr_err_code err;
+ *matched = false;
+
+ /* Needs to be dnsRecord, no match otherwise */
+ if (ldb_attr_cmp(attribute_to_match, "dnsRecord") != 0) {
+ return LDB_SUCCESS;
+ }
+
+ el = ldb_msg_find_element(msg, attribute_to_match);
+ if (el == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ if (ldb_msg_element_is_inaccessible(el)) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"),
+ struct auth_session_info);
+ if (session_info == NULL) {
+ return ldb_oom(ldb);
+ }
+ if (security_session_user_level(session_info, NULL)
+ != SECURITY_SYSTEM) {
+
+ DBG_ERR("unauthorised access\n");
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ /* We only expect uint32_t <= 10 digits */
+ if (value_to_match->length >= 12) {
+ DBG_ERR("Invalid timestamp passed\n");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ } else {
+ int error = 0;
+ char s[12];
+
+ memcpy(s, value_to_match->data, value_to_match->length);
+ s[value_to_match->length] = 0;
+ if (s[0] == '\0') {
+ DBG_ERR("Empty timestamp passed\n");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ tombstone_time = smb_strtoull(s,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_FULL_STR_CONV);
+ if (error != 0) {
+ DBG_ERR("Invalid timestamp string passed\n");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ rec = talloc_zero(tmp_ctx, struct dnsp_DnssrvRpcRecord);
+ if (rec == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+ err = ndr_pull_struct_blob(
+ &(el->values[i]),
+ tmp_ctx,
+ rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)){
+ DBG_ERR("Failed to pull dns rec blob.\n");
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (rec->wType == DNS_TYPE_SOA || rec->wType == DNS_TYPE_NS) {
+ TALLOC_FREE(rec);
+ continue;
+ }
+
+ if (rec->wType == DNS_TYPE_TOMBSTONE) {
+ TALLOC_FREE(rec);
+ continue;
+ }
+ if (rec->dwTimeStamp == 0) {
+ TALLOC_FREE(rec);
+ continue;
+ }
+ if (rec->dwTimeStamp > tombstone_time) {
+ TALLOC_FREE(rec);
+ continue;
+ }
+
+ *matched = true;
+ break;
+ }
+
+ TALLOC_FREE(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+
+/*
+ * This rule provides match of a link attribute against a 'should be expunged' criteria
+ *
+ * This allows a search filter such as:
+ *
+ * member:1.3.6.1.4.1.7165.4.5.2:=131139216000000000
+ *
+ * This searches the member attribute, but also any member attributes
+ * that are deleted and should be expunged after the specified NTTIME
+ * time.
+ *
+ */
+static int dsdb_match_for_expunge(struct ldb_context *ldb,
+ const char *oid,
+ const struct ldb_message *msg,
+ const char *attribute_to_match,
+ const struct ldb_val *value_to_match,
+ bool *matched)
+{
+ const struct dsdb_schema *schema;
+ const struct dsdb_attribute *schema_attr;
+ TALLOC_CTX *tmp_ctx;
+ unsigned int i;
+ struct ldb_message_element *el;
+ struct auth_session_info *session_info;
+ uint64_t tombstone_time;
+ *matched = false;
+
+ el = ldb_msg_find_element(msg, attribute_to_match);
+ if (el == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ if (ldb_msg_element_is_inaccessible(el)) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ session_info
+ = talloc_get_type(ldb_get_opaque(ldb, DSDB_SESSION_INFO),
+ struct auth_session_info);
+ if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ /*
+ * If the target attribute to match is not a linked attribute, then
+ * the filter evaluates to undefined
+ */
+ schema = dsdb_get_schema(ldb, NULL);
+ if (schema == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* TODO this is O(log n) per attribute */
+ schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, attribute_to_match);
+ if (schema_attr == NULL) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ /*
+ * This extended match filter is only valid for forward linked attributes.
+ */
+ if (schema_attr->linkID == 0 || (schema_attr->linkID & 1) == 1) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ /* Just check we don't allow the caller to fill our stack */
+ if (value_to_match->length >=64) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ } else {
+ int error = 0;
+ char s[value_to_match->length+1];
+
+ memcpy(s, value_to_match->data, value_to_match->length);
+ s[value_to_match->length] = 0;
+ if (s[0] == '\0' || s[0] == '-') {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ tombstone_time = smb_strtoull(s,
+ NULL,
+ 10,
+ &error,
+ SMB_STR_FULL_STR_CONV);
+ if (error != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ NTSTATUS status;
+ struct dsdb_dn *dn;
+ uint64_t rmd_changetime;
+ if (dsdb_dn_is_deleted_val(&el->values[i]) == false) {
+ continue;
+ }
+
+ dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i],
+ schema_attr->syntax->ldap_oid);
+ if (dn == NULL) {
+ DEBUG(1, ("Error: Failed to parse linked attribute blob of %s.\n", el->name));
+ continue;
+ }
+
+ status = dsdb_get_extended_dn_uint64(dn->dn, &rmd_changetime,
+ "RMD_CHANGETIME");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Error: RMD_CHANGETIME is missing on a forward link.\n"));
+ continue;
+ }
+
+ if (rmd_changetime > tombstone_time) {
+ continue;
+ }
+
+ *matched = true;
+ break;
+ }
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+
+int ldb_register_samba_matching_rules(struct ldb_context *ldb)
+{
+ struct ldb_extended_match_rule *transitive_eval = NULL,
+ *match_for_expunge = NULL,
+ *match_for_dns_to_tombstone_time = NULL;
+ int ret;
+
+ transitive_eval = talloc_zero(ldb, struct ldb_extended_match_rule);
+ transitive_eval->oid = SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL;
+ transitive_eval->callback = ldb_comparator_trans;
+ ret = ldb_register_extended_match_rule(ldb, transitive_eval);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(transitive_eval);
+ return ret;
+ }
+
+ match_for_expunge = talloc_zero(ldb, struct ldb_extended_match_rule);
+ match_for_expunge->oid = DSDB_MATCH_FOR_EXPUNGE;
+ match_for_expunge->callback = dsdb_match_for_expunge;
+ ret = ldb_register_extended_match_rule(ldb, match_for_expunge);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(match_for_expunge);
+ return ret;
+ }
+
+ match_for_dns_to_tombstone_time = talloc_zero(
+ ldb,
+ struct ldb_extended_match_rule);
+ match_for_dns_to_tombstone_time->oid = DSDB_MATCH_FOR_DNS_TO_TOMBSTONE_TIME;
+ match_for_dns_to_tombstone_time->callback
+ = dsdb_match_for_dns_to_tombstone_time;
+ ret = ldb_register_extended_match_rule(ldb,
+ match_for_dns_to_tombstone_time);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(match_for_dns_to_tombstone_time);
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb-samba/ldb_matching_rules.h b/lib/ldb-samba/ldb_matching_rules.h
new file mode 100644
index 0000000..28c4e3d
--- /dev/null
+++ b/lib/ldb-samba/ldb_matching_rules.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ ldb database library - Extended match rules
+
+ Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LDB_MATCHING_RULES_H_
+#define _LDB_MATCHING_RULES_H_
+
+/* This rule provides recursive search of a link attribute */
+#define SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL "1.2.840.113556.1.4.1941"
+#define DSDB_MATCH_FOR_EXPUNGE "1.3.6.1.4.1.7165.4.5.2"
+#define DSDB_MATCH_FOR_DNS_TO_TOMBSTONE_TIME "1.3.6.1.4.1.7165.4.5.3"
+
+#endif /* _LDB_MATCHING_RULES_H_ */
diff --git a/lib/ldb-samba/ldb_wrap.c b/lib/ldb-samba/ldb_wrap.c
new file mode 100644
index 0000000..cfc8732
--- /dev/null
+++ b/lib/ldb-samba/ldb_wrap.c
@@ -0,0 +1,377 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ LDB wrap functions
+
+ Copyright (C) Andrew Tridgell 2004-2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ the stupidity of the unix fcntl locking design forces us to never
+ allow a database file to be opened twice in the same process. These
+ wrappers provide convenient access to a tdb or ldb, taking advantage
+ of talloc destructors to ensure that only a single open is done
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include <ldb.h>
+#include <ldb_errors.h>
+#include "lib/ldb-samba/ldif_handlers.h"
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
+#include "param/param.h"
+#include "../lib/util/dlinklist.h"
+#include "lib/util/util_paths.h"
+#include <tdb.h>
+#include <unistd.h>
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LDB
+
+/*
+ this is used to catch debug messages from ldb
+*/
+static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+
+static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap)
+{
+ int samba_level = -1;
+ switch (level) {
+ case LDB_DEBUG_FATAL:
+ samba_level = DBGLVL_ERR;
+ break;
+ case LDB_DEBUG_ERROR:
+ samba_level = DBGLVL_WARNING;
+ break;
+ case LDB_DEBUG_WARNING:
+ samba_level = DBGLVL_NOTICE;
+ break;
+ case LDB_DEBUG_TRACE:
+ samba_level = DBGLVL_DEBUG + 1;
+ break;
+
+ };
+ if (CHECK_DEBUGLVL(samba_level)) {
+ char *s = NULL;
+ int ret;
+
+ ret = vasprintf(&s, fmt, ap);
+ if (ret == -1) {
+ return;
+ }
+ DEBUG(samba_level, ("ldb: %s\n", s));
+ free(s);
+ }
+}
+
+
+/*
+ connecting to a ldb can be a relatively expensive operation because
+ of the schema and partition loads. We keep a list of open ldb
+ contexts here, and try to re-use when possible.
+
+ This means callers of ldb_wrap_connect() must use talloc_unlink() or
+ the free of a parent to destroy the context
+ */
+static struct ldb_wrap {
+ struct ldb_wrap *next, *prev;
+ struct ldb_wrap_context {
+ /* the context is what we use to tell if two ldb
+ * connections are exactly equivalent
+ */
+ pid_t pid; /* We want to re-open in a new PID due to
+ * the LMDB backend */
+ const char *url;
+ struct tevent_context *ev;
+ struct loadparm_context *lp_ctx;
+ struct auth_session_info *session_info;
+ struct cli_credentials *credentials;
+ unsigned int flags;
+ } context;
+ struct ldb_context *ldb;
+} *ldb_wrap_list;
+
+/*
+ free a ldb_wrap structure
+ */
+static int ldb_wrap_destructor(struct ldb_wrap *w)
+{
+ DLIST_REMOVE(ldb_wrap_list, w);
+ return 0;
+}
+
+/*
+ * The casefolder for s4's LDB databases - Unicode-safe
+ */
+char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n)
+{
+ return strupper_talloc_n(mem_ctx, s, n);
+}
+
+
+ struct ldb_context *samba_ldb_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials)
+{
+ struct ldb_context *ldb;
+ int ret;
+
+ ldb = ldb_init(mem_ctx, ev);
+ if (ldb == NULL) {
+ return NULL;
+ }
+
+ ldb_set_modules_dir(ldb, modules_path(ldb, "ldb"));
+
+ ldb_set_debug(ldb, ldb_wrap_debug, NULL);
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ if (session_info) {
+ if (ldb_set_opaque(ldb, DSDB_SESSION_INFO, session_info)) {
+ talloc_free(ldb);
+ return NULL;
+ }
+ }
+
+ if (credentials) {
+ if (ldb_set_opaque(ldb, "credentials", credentials)) {
+ talloc_free(ldb);
+ return NULL;
+ }
+ }
+
+ if (ldb_set_opaque(ldb, "loadparm", lp_ctx)) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ /* This must be done before we load the schema, as these
+ * handlers for objectSid and objectGUID etc must take
+ * precedence over the 'binary attribute' declaration in the
+ * schema */
+ ret = ldb_register_samba_handlers(ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ /* we usually want Samba databases to be private. If we later
+ find we need one public, we will need to add a parameter to
+ ldb_wrap_connect() */
+ ldb_set_create_perms(ldb, 0600);
+
+ return ldb;
+}
+
+ struct ldb_context *ldb_wrap_find(const char *url,
+ struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ unsigned int flags)
+{
+ pid_t pid = getpid();
+ struct ldb_wrap *w;
+ /* see if we can re-use an existing ldb */
+ for (w=ldb_wrap_list; w; w=w->next) {
+ if (w->context.pid == pid &&
+ w->context.ev == ev &&
+ w->context.lp_ctx == lp_ctx &&
+ w->context.session_info == session_info &&
+ w->context.credentials == credentials &&
+ w->context.flags == flags &&
+ (w->context.url == url || strcmp(w->context.url, url) == 0))
+ return w->ldb;
+ }
+
+ return NULL;
+}
+
+int samba_ldb_connect(struct ldb_context *ldb, struct loadparm_context *lp_ctx,
+ const char *url, unsigned int flags)
+{
+ int ret;
+ char *real_url = NULL;
+
+ /* allow admins to force non-sync ldb for all databases */
+ if (lpcfg_parm_bool(lp_ctx, NULL, "ldb", "nosync", false)) {
+ flags |= LDB_FLG_NOSYNC;
+ }
+
+ if (DEBUGLVL(10)) {
+ flags |= LDB_FLG_ENABLE_TRACING;
+ }
+
+ real_url = lpcfg_private_path(ldb, lp_ctx, url);
+ if (real_url == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_connect(ldb, real_url, flags, NULL);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* setup for leak detection */
+ ldb_set_opaque(ldb, "wrap_url", real_url);
+
+ return LDB_SUCCESS;
+}
+
+ bool ldb_wrap_add(const char *url, struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ unsigned int flags,
+ struct ldb_context *ldb)
+{
+ struct ldb_wrap *w;
+ struct ldb_wrap_context c;
+
+ /* add to the list of open ldb contexts */
+ w = talloc(ldb, struct ldb_wrap);
+ if (w == NULL) {
+ return false;
+ }
+
+ c.pid = getpid();
+ c.url = url;
+ c.ev = ev;
+ c.lp_ctx = lp_ctx;
+ c.session_info = session_info;
+ c.credentials = credentials;
+ c.flags = flags;
+
+ w->context = c;
+ w->context.url = talloc_strdup(w, url);
+ if (w->context.url == NULL) {
+ return false;
+ }
+
+ if (session_info) {
+ /* take a reference to the session_info, as it is
+ * possible for the ldb to live longer than the
+ * session_info. This happens when a DRS DsBind call
+ * reuses a handle, but the original connection is
+ * shutdown. The token for the new connection is still
+ * valid, so we need the session_info to remain valid for
+ * ldb modules to use
+ */
+ if (talloc_reference(w, session_info) == NULL) {
+ return false;
+ }
+ }
+
+ w->ldb = ldb;
+
+ DLIST_ADD(ldb_wrap_list, w);
+
+ talloc_set_destructor(w, ldb_wrap_destructor);
+
+ return true;
+}
+
+
+/*
+ wrapped connection to a ldb database
+ to close just talloc_free() the returned ldb_context
+
+ TODO: We need an error_string parameter
+ */
+ struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *url,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ unsigned int flags)
+{
+ struct ldb_context *ldb;
+ int ret;
+
+ /*
+ * Unlike samdb_connect_url() do not try and cache the LDB
+ * handle, get a new one each time. Only sam.ldb is
+ * punitively expensive to open and helpful caches like this
+ * cause challenges (such as if the value for 'private dir'
+ * changes).
+ */
+
+ ldb = samba_ldb_init(mem_ctx, ev, lp_ctx, session_info, credentials);
+
+ if (ldb == NULL)
+ return NULL;
+
+ ret = samba_ldb_connect(ldb, lp_ctx, url, flags);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ DEBUG(3,("ldb_wrap open of %s\n", url));
+
+ return ldb;
+}
+
+/*
+ call tdb_reopen_all() in case there is a TDB open so we are
+ not blocked from re-opening it inside ldb_tdb.
+*/
+ void ldb_wrap_fork_hook(void)
+{
+ if (tdb_reopen_all(1) != 0) {
+ smb_panic("tdb_reopen_all failed\n");
+ }
+}
+
+ char *ldb_relative_path(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *name)
+{
+ const char *base_url =
+ (const char *)ldb_get_opaque(ldb, "ldb_url");
+ char *path, *p, *full_name;
+ if (name == NULL) {
+ return NULL;
+ }
+ if (strncmp("tdb://", base_url, 6) == 0) {
+ base_url = base_url+6;
+ } else if (strncmp("mdb://", base_url, 6) == 0) {
+ base_url = base_url+6;
+ } else if (strncmp("ldb://", base_url, 6) == 0) {
+ base_url = base_url+6;
+ }
+ path = talloc_strdup(mem_ctx, base_url);
+ if (path == NULL) {
+ return NULL;
+ }
+ if ( (p = strrchr(path, '/')) != NULL) {
+ p[0] = '\0';
+ full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name);
+ } else {
+ full_name = talloc_asprintf(mem_ctx, "./%s", name);
+ }
+ talloc_free(path);
+ return full_name;
+}
diff --git a/lib/ldb-samba/ldb_wrap.h b/lib/ldb-samba/ldb_wrap.h
new file mode 100644
index 0000000..aa7ccb3
--- /dev/null
+++ b/lib/ldb-samba/ldb_wrap.h
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ database wrap headers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LDB_WRAP_H_
+#define _LDB_WRAP_H_
+
+#include <talloc.h>
+
+struct auth_session_info;
+struct ldb_message;
+struct ldb_dn;
+struct cli_credentials;
+struct loadparm_context;
+struct tevent_context;
+
+char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n);
+
+struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ const char *url,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ unsigned int flags);
+
+void ldb_wrap_fork_hook(void);
+
+struct ldb_context *samba_ldb_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials);
+struct ldb_context *ldb_wrap_find(const char *url,
+ struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ unsigned int flags);
+bool ldb_wrap_add(const char *url, struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ unsigned int flags,
+ struct ldb_context *ldb);
+char *ldb_relative_path(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *name);
+
+int samba_ldb_connect(struct ldb_context *ldb, struct loadparm_context *lp_ctx,
+ const char *url, unsigned int flags);
+
+#endif /* _LDB_WRAP_H_ */
diff --git a/lib/ldb-samba/ldif_handlers.c b/lib/ldb-samba/ldif_handlers.c
new file mode 100644
index 0000000..c30fd63
--- /dev/null
+++ b/lib/ldb-samba/ldif_handlers.c
@@ -0,0 +1,1843 @@
+/*
+ ldb database library - ldif handlers for Samba
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Andrew Bartlett 2006-2009
+ Copyright (C) Matthias Dieter Wallnöfer 2009
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <ldb.h>
+#include <ldb_module.h>
+#include "ldb_handlers.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/security/security.h"
+#include "param/param.h"
+#include "../lib/util/asn1.h"
+#include "lib/util/smb_strtox.h"
+
+/*
+ use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
+
+ If mask_errors is true, then function succeeds but out data
+ is set to "<Unable to decode binary data>" message
+
+ \return 0 on success; -1 on error
+*/
+static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out,
+ size_t struct_size,
+ ndr_pull_flags_fn_t pull_fn,
+ ndr_print_fn_t print_fn,
+ bool mask_errors)
+{
+ uint8_t *p;
+ enum ndr_err_code err;
+ if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+ p = talloc_size(mem_ctx, struct_size);
+ err = ndr_pull_struct_blob(in, mem_ctx,
+ p, pull_fn);
+ if (err != NDR_ERR_SUCCESS) {
+ /* fail in not in mask_error mode */
+ if (!mask_errors) {
+ return -1;
+ }
+ talloc_free(p);
+ out->data = (uint8_t *)talloc_strdup(mem_ctx, "<Unable to decode binary data>");
+ out->length = strlen((const char *)out->data);
+ return 0;
+ }
+ out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
+ talloc_free(p);
+ if (out->data == NULL) {
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/*
+ convert a ldif formatted objectSid to a NDR formatted blob
+*/
+static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ bool ret;
+ enum ndr_err_code ndr_err;
+ struct dom_sid sid;
+ if (in->length > DOM_SID_STR_BUFLEN) {
+ return -1;
+ } else {
+ char p[in->length+1];
+ memcpy(p, in->data, in->length);
+ p[in->length] = '\0';
+
+ ret = dom_sid_parse(p, &sid);
+ if (ret == false) {
+ return -1;
+ }
+
+ *out = data_blob_talloc(mem_ctx, NULL,
+ ndr_size_dom_sid(&sid, 0));
+ if (out->data == NULL) {
+ return -1;
+ }
+
+ ndr_err = ndr_push_struct_into_fixed_blob(out, &sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted objectSid
+*/
+int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct dom_sid sid;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob_all_noalloc(in, &sid,
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ *out = data_blob_string_const(dom_sid_string(mem_ctx, &sid));
+ if (out->data == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
+{
+ if (v->length < 3) {
+ return false;
+ }
+
+ if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
+
+ return true;
+}
+
+/*
+ compare two objectSids
+*/
+static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) {
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ } else if (ldif_comparision_objectSid_isString(v1)
+ && !ldif_comparision_objectSid_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
+ /* Perhaps not a string after all */
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
+ talloc_free(v.data);
+ return ret;
+ } else if (!ldif_comparision_objectSid_isString(v1)
+ && ldif_comparision_objectSid_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
+ /* Perhaps not a string after all */
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
+ talloc_free(v.data);
+ return ret;
+ }
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+}
+
+/*
+ canonicalise a objectSid
+*/
+static int ldif_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (ldif_comparision_objectSid_isString(in)) {
+ if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) {
+ /* Perhaps not a string after all */
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+ return 0;
+ }
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+}
+
+static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct dom_sid sid;
+ enum ndr_err_code ndr_err;
+ if (ldif_comparision_objectSid_isString(in)) {
+ if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
+ return 0;
+ }
+ }
+
+ /* Perhaps not a string after all */
+ *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
+
+ if (!out->data) {
+ return -1;
+ }
+
+ (*out).length = strhex_to_str((char *)out->data, out->length,
+ (const char *)in->data, in->length);
+
+ /* Check it looks like a SID */
+ ndr_err = ndr_pull_struct_blob_all_noalloc(out, &sid,
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ convert a ldif formatted objectGUID to a NDR formatted blob
+*/
+static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct GUID guid;
+ NTSTATUS status;
+
+ status = GUID_from_data_blob(in, &guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ status = GUID_to_ndr_blob(&guid, mem_ctx, out);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted objectGUID
+*/
+static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct GUID guid;
+ NTSTATUS status;
+
+ status = GUID_from_ndr_blob(in, &guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+ out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen((const char *)out->data);
+ return 0;
+}
+
+static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v)
+{
+ if (v->length != 36 && v->length != 38) return false;
+
+ /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
+ return true;
+}
+
+static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+
+ if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
+ return 0;
+ }
+
+ /* Try as 'hex' form */
+ if (in->length != 32) {
+ return -1;
+ }
+
+ *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
+
+ if (!out->data) {
+ return -1;
+ }
+
+ (*out).length = strhex_to_str((char *)out->data, out->length,
+ (const char *)in->data, in->length);
+
+ /* Check it looks like a GUID */
+ if ((*out).length != 16) {
+ data_blob_free(out);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ compare two objectGUIDs
+*/
+static int ldif_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (ldif_comparision_objectGUID_isString(v1) && ldif_comparision_objectGUID_isString(v2)) {
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ } else if (ldif_comparision_objectGUID_isString(v1)
+ && !ldif_comparision_objectGUID_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
+ /* Perhaps it wasn't a valid string after all */
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
+ talloc_free(v.data);
+ return ret;
+ } else if (!ldif_comparision_objectGUID_isString(v1)
+ && ldif_comparision_objectGUID_isString(v2)) {
+ struct ldb_val v;
+ int ret;
+ if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
+ /* Perhaps it wasn't a valid string after all */
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ }
+ ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
+ talloc_free(v.data);
+ return ret;
+ }
+ return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+}
+
+/*
+ canonicalise a objectGUID
+*/
+static int ldif_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (ldif_comparision_objectGUID_isString(in)) {
+ if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
+ /* Perhaps it wasn't a valid string after all */
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+ return 0;
+ }
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+}
+
+
+/*
+ convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
+*/
+static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct security_descriptor *sd;
+ enum ndr_err_code ndr_err;
+
+ if (in->length >= 2 && isupper(in->data[0]) && in->data[1] == ':') {
+ /*
+ * If it starts with an upper case character followed by ':',
+ * we know it's not NDR, but most likely SDDL...
+ */
+ const struct dom_sid *sid = samdb_domain_sid(ldb);
+
+ sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
+ if (sd == NULL) {
+ return -1;
+ }
+
+ goto decoded;
+ }
+
+ sd = talloc(mem_ctx, struct security_descriptor);
+ if (sd == NULL) {
+ return -1;
+ }
+
+ ndr_err = ndr_pull_struct_blob(in, sd, sd,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(sd);
+ return -1;
+ }
+
+decoded:
+ ndr_err = ndr_push_struct_blob(out, mem_ctx, sd,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+ talloc_free(sd);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
+*/
+static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct security_descriptor *sd;
+ enum ndr_err_code ndr_err;
+
+ if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct security_descriptor),
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor,
+ (ndr_print_fn_t)ndr_print_security_descriptor,
+ true);
+
+ }
+
+ sd = talloc(mem_ctx, struct security_descriptor);
+ if (sd == NULL) {
+ return -1;
+ }
+ /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
+ ndr_err = ndr_pull_struct_blob(in, sd, sd,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(sd);
+ return -1;
+ }
+ out->data = (uint8_t *)sddl_encode(mem_ctx, sd, samdb_domain_sid_cache_only(ldb));
+ talloc_free(sd);
+ if (out->data == NULL) {
+ return -1;
+ }
+ out->length = strlen((const char *)out->data);
+ return 0;
+}
+
+/*
+ convert a string formatted SDDL to a ldif formatted ntSecurityDescriptor (SDDL format)
+*/
+static int ldif_write_sddlSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
+ struct security_descriptor *sd;
+ const struct dom_sid *sid = samdb_domain_sid(ldb);
+
+ sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
+ out->data = (uint8_t *)ndr_print_struct_string(mem_ctx,
+ (ndr_print_fn_t)ndr_print_security_descriptor,
+ "SDDL", sd);
+ out->length = strlen((const char *)out->data);
+ talloc_free(sd);
+ return 0;
+ }
+
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+}
+
+/*
+ canonicalise an objectCategory. We use the long form as the canonical form:
+ 'person' becomes cn=Person,cn=Schema,cn=Configuration,<basedn>
+
+ Also any short name of an objectClass that points to a different
+ class (such as user) has the canonical form of the class it's
+ defaultObjectCategory points to (eg
+ cn=Person,cn=Schema,cn=Configuration,<basedn>)
+*/
+
+static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct ldb_dn *dn1 = NULL;
+ const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
+ const struct dsdb_class *sclass;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (!schema) {
+ talloc_free(tmp_ctx);
+ *out = data_blob_talloc(mem_ctx, in->data, in->length);
+ if (in->data && !out->data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+ }
+ dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
+ if ( ! ldb_dn_validate(dn1)) {
+ const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
+ sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
+ if (sclass) {
+ struct ldb_dn *dn = ldb_dn_new(tmp_ctx, ldb,
+ sclass->defaultObjectCategory);
+ if (dn == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
+ talloc_free(tmp_ctx);
+
+ if (!out->data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+ } else {
+ *out = data_blob_talloc(mem_ctx, in->data, in->length);
+ talloc_free(tmp_ctx);
+
+ if (in->data && !out->data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+ }
+ }
+ *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
+ talloc_free(tmp_ctx);
+
+ if (!out->data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+}
+
+static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_objectCategory,
+ v1, v2);
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted schemaInfo
+*/
+static int ldif_write_schemaInfo(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct repsFromToBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob,
+ (ndr_print_fn_t)ndr_print_schemaInfoBlob,
+ true);
+}
+
+/*
+ convert a ldif formatted prefixMap to a NDR formatted blob
+*/
+static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct prefixMapBlob *blob;
+ enum ndr_err_code ndr_err;
+ char *string, *line, *p, *oid;
+ DATA_BLOB oid_blob;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
+ if (blob == NULL) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ /* use the switch value to detect if this is in the binary
+ * format
+ */
+ if (in->length >= 4 && IVAL(in->data, 0) == PREFIX_MAP_VERSION_DSDB) {
+ ndr_err = ndr_pull_struct_blob(in, tmp_ctx, blob,
+ (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ ndr_err = ndr_push_struct_blob(out, mem_ctx,
+ blob,
+ (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+ talloc_free(tmp_ctx);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ /* If this does not parse, then it is probably the text version, and we should try it that way */
+ blob->version = PREFIX_MAP_VERSION_DSDB;
+
+ string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
+ if (string == NULL) {
+ talloc_free(blob);
+ return -1;
+ }
+
+ line = string;
+ while (line && line[0]) {
+ int error = 0;
+
+ p=strchr(line, ';');
+ if (p) {
+ p[0] = '\0';
+ } else {
+ p=strchr(line, '\n');
+ if (p) {
+ p[0] = '\0';
+ }
+ }
+ /* allow a trailing separator */
+ if (line == p) {
+ break;
+ }
+
+ blob->ctr.dsdb.mappings = talloc_realloc(blob,
+ blob->ctr.dsdb.mappings,
+ struct drsuapi_DsReplicaOIDMapping,
+ blob->ctr.dsdb.num_mappings+1);
+ if (!blob->ctr.dsdb.mappings) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix =
+ smb_strtoul(line, &oid, 10, &error, SMB_STR_STANDARD);
+
+ if (oid[0] != ':' || error != 0) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ /* we know there must be at least ":" */
+ oid++;
+
+ if (!ber_write_partial_OID_String(blob->ctr.dsdb.mappings, &oid_blob, oid)) {
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.length = oid_blob.length;
+ blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.binary_oid = oid_blob.data;
+
+ blob->ctr.dsdb.num_mappings++;
+
+ /* Now look past the terminator we added above */
+ if (p) {
+ line = p + 1;
+ } else {
+ line = NULL;
+ }
+ }
+
+ ndr_err = ndr_push_struct_blob(out, mem_ctx,
+ blob,
+ (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+ talloc_free(tmp_ctx);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted prefixMap
+*/
+static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct prefixMapBlob *blob;
+ enum ndr_err_code ndr_err;
+ char *string;
+ uint32_t i;
+
+ if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
+ int err;
+ /* try to decode the blob as S4 prefixMap */
+ err = ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct prefixMapBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
+ (ndr_print_fn_t)ndr_print_prefixMapBlob,
+ false);
+ if (0 == err) {
+ return err;
+ }
+ /* try parsing it as Windows PrefixMap value */
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct drsuapi_MSPrefixMap_Ctr),
+ (ndr_pull_flags_fn_t)ndr_pull_drsuapi_MSPrefixMap_Ctr,
+ (ndr_print_fn_t)ndr_print_drsuapi_MSPrefixMap_Ctr,
+ true);
+ }
+
+ blob = talloc(mem_ctx, struct prefixMapBlob);
+ if (blob == NULL) {
+ return -1;
+ }
+ ndr_err = ndr_pull_struct_blob_all(in, blob,
+ blob,
+ (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto failed;
+ }
+ if (blob->version != PREFIX_MAP_VERSION_DSDB) {
+ goto failed;
+ }
+ string = talloc_strdup(mem_ctx, "");
+ if (string == NULL) {
+ goto failed;
+ }
+
+ for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
+ DATA_BLOB oid_blob;
+ char *partial_oid = NULL;
+
+ if (i > 0) {
+ talloc_asprintf_addbuf(&string, ";");
+ }
+
+ oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
+ blob->ctr.dsdb.mappings[i].oid.length);
+ if (!ber_read_partial_OID_String(blob, oid_blob, &partial_oid)) {
+ DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X\n",
+ blob->ctr.dsdb.mappings[i].id_prefix));
+ goto failed;
+ }
+ talloc_asprintf_addbuf(&string, "%u:%s",
+ blob->ctr.dsdb.mappings[i].id_prefix,
+ partial_oid);
+ talloc_free(discard_const(partial_oid));
+ }
+
+ talloc_free(blob);
+ *out = data_blob_string_const(string);
+ return 0;
+
+failed:
+ talloc_free(blob);
+ return -1;
+}
+
+static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
+{
+ if (v->length < 4) {
+ return true;
+ }
+
+ if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ canonicalise a prefixMap
+*/
+static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (ldif_comparision_prefixMap_isString(in)) {
+ return ldif_read_prefixMap(ldb, mem_ctx, in, out);
+ }
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+}
+
+static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_prefixMap,
+ v1, v2);
+}
+
+/* length limited conversion of a ldb_val to a int32_t */
+static int val_to_int32(const struct ldb_val *in, int32_t *v)
+{
+ char *end;
+ char buf[64];
+
+ /* make sure we don't read past the end of the data */
+ if (in->length > sizeof(buf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ strncpy(buf, (char *)in->data, in->length);
+ buf[in->length] = 0;
+
+ /* We've to use "strtoll" here to have the intended overflows.
+ * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
+ *v = (int32_t) strtoll(buf, &end, 0);
+ if (*end != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ return LDB_SUCCESS;
+}
+
+/* length limited conversion of a ldb_val to a int64_t */
+static int val_to_int64(const struct ldb_val *in, int64_t *v)
+{
+ char *end;
+ char buf[64];
+
+ /* make sure we don't read past the end of the data */
+ if (in->length > sizeof(buf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ strncpy(buf, (char *)in->data, in->length);
+ buf[in->length] = 0;
+
+ *v = (int64_t) strtoll(buf, &end, 0);
+ if (*end != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ return LDB_SUCCESS;
+}
+
+/* Canonicalisation of two 32-bit integers */
+static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ int32_t i;
+ int ret;
+
+ ret = val_to_int32(in, &i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/*
+ * Lexicographically sorted representation for a 32-bit integer
+ *
+ * [ INT32_MIN ... -3, -2, -1 | 0 | +1, +2, +3 ... INT32_MAX ]
+ * n o p
+ *
+ * Refer to the comment in lib/ldb/common/attrib_handlers.c for the
+ * corresponding documentation for 64-bit integers.
+ *
+ * The same rules apply but use INT32_MIN and INT32_MAX.
+ *
+ * String representation padding is done to 10 characters.
+ *
+ * INT32_MAX = 2^31 - 1 = 2147483647 (10 characters long)
+ *
+ */
+static int ldif_index_format_int32(struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_val *in,
+ struct ldb_val *out)
+{
+ int32_t i;
+ int ret;
+ char prefix;
+ size_t len;
+
+ ret = val_to_int32(in, &i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (i < 0) {
+ /*
+ * i is negative, so this is subtraction rather than
+ * wrap-around.
+ */
+ prefix = 'n';
+ i = INT32_MAX + i + 1;
+ } else if (i > 0) {
+ prefix = 'p';
+ } else {
+ prefix = 'o';
+ }
+
+ out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%c%010ld", prefix, (long)i);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ len = talloc_array_length(out->data) - 1;
+ if (len != 11) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ __location__ ": expected index format str %s to"
+ " have length 11 but got %zu",
+ (char*)out->data, len);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ out->length = 11;
+ return 0;
+}
+
+/* Comparison of two 32-bit integers */
+static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ int32_t i1=0, i2=0;
+ val_to_int32(v1, &i1);
+ val_to_int32(v2, &i2);
+ if (i1 == i2) return 0;
+ return i1 > i2? 1 : -1;
+}
+
+/* Canonicalisation of two 64-bit integers */
+static int ldif_canonicalise_int64(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ int64_t i;
+ int ret;
+
+ ret = val_to_int64(in, &i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/* Comparison of two 64-bit integers */
+static int ldif_comparison_int64(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ int64_t i1=0, i2=0;
+ val_to_int64(v1, &i1);
+ val_to_int64(v2, &i2);
+ if (i1 == i2) return 0;
+ return i1 > i2? 1 : -1;
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted repsFromTo
+*/
+static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct repsFromToBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
+ (ndr_print_fn_t)ndr_print_repsFromToBlob,
+ true);
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted replPropertyMetaData
+*/
+static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct replPropertyMetaDataBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
+ (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
+ true);
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted replUpToDateVector
+*/
+static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct replUpToDateVectorBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
+ (ndr_print_fn_t)ndr_print_replUpToDateVectorBlob,
+ true);
+}
+
+static int ldif_write_dn_binary_NDR(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out,
+ size_t struct_size,
+ ndr_pull_flags_fn_t pull_fn,
+ ndr_print_fn_t print_fn,
+ bool mask_errors)
+{
+ uint8_t *p = NULL;
+ enum ndr_err_code err;
+ struct dsdb_dn *dsdb_dn = NULL;
+ char *dn_str = NULL;
+ char *str = NULL;
+
+ if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+
+ dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_BINARY_DN);
+ if (dsdb_dn == NULL) {
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+
+ p = talloc_size(dsdb_dn, struct_size);
+ if (p == NULL) {
+ TALLOC_FREE(dsdb_dn);
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+
+ err = ndr_pull_struct_blob(&dsdb_dn->extra_part, p, p, pull_fn);
+ if (err != NDR_ERR_SUCCESS) {
+ /* fail in not in mask_error mode */
+ if (!mask_errors) {
+ return -1;
+ }
+ TALLOC_FREE(dsdb_dn);
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+
+ dn_str = ldb_dn_get_extended_linearized(dsdb_dn, dsdb_dn->dn, 1);
+ if (dn_str == NULL) {
+ TALLOC_FREE(dsdb_dn);
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+
+ str = ndr_print_struct_string(mem_ctx, print_fn, dn_str, p);
+ TALLOC_FREE(dsdb_dn);
+ if (str == NULL) {
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+
+ *out = data_blob_string_const(str);
+ return 0;
+}
+
+static int ldif_write_msDS_RevealedUsers(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_dn_binary_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct replPropertyMetaData1),
+ (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaData1,
+ (ndr_print_fn_t)ndr_print_replPropertyMetaData1,
+ true);
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted dnsRecord
+*/
+static int ldif_write_dnsRecord(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct dnsp_DnssrvRpcRecord),
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord,
+ (ndr_print_fn_t)ndr_print_dnsp_DnssrvRpcRecord,
+ true);
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted dnsProperty
+*/
+static int ldif_write_dnsProperty(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct dnsp_DnsProperty),
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty,
+ (ndr_print_fn_t)ndr_print_dnsp_DnsProperty,
+ true);
+}
+
+/*
+ convert a NDR formatted blob of a supplementalCredentials into text
+*/
+static int ldif_write_supplementalCredentialsBlob(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct supplementalCredentialsBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob,
+ (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob,
+ true);
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted trustAuthInOutBlob
+*/
+static int ldif_write_trustAuthInOutBlob(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct trustAuthInOutBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob,
+ (ndr_print_fn_t)ndr_print_trustAuthInOutBlob,
+ true);
+}
+
+/*
+ convert a NDR formatted blob to a ldif formatted msDS-TrustForestTrustInfo
+*/
+static int ldif_write_ForestTrustInfo(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct ForestTrustInfo),
+ (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo,
+ (ndr_print_fn_t)ndr_print_ForestTrustInfo,
+ true);
+}
+/*
+ convert a NDR formatted blob of a partialAttributeSet into text
+*/
+static int ldif_write_partialAttributeSet(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ return ldif_write_NDR(ldb, mem_ctx, in, out,
+ sizeof(struct partialAttributeSetBlob),
+ (ndr_pull_flags_fn_t)ndr_pull_partialAttributeSetBlob,
+ (ndr_print_fn_t)ndr_print_partialAttributeSetBlob,
+ true);
+}
+
+
+static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ *out = data_blob_string_const(data_blob_hex_string_lower(mem_ctx, in));
+ if (!out->data) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ compare two dns
+*/
+static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ struct ldb_dn *dn1 = NULL, *dn2 = NULL;
+ int ret;
+
+ if (dsdb_dn_is_deleted_val(v1)) {
+ /* If the DN is deleted, then we can't search for it */
+ return -1;
+ }
+
+ if (dsdb_dn_is_deleted_val(v2)) {
+ /* If the DN is deleted, then we can't search for it */
+ return -1;
+ }
+
+ dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
+ if ( ! ldb_dn_validate(dn1)) return -1;
+
+ dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
+ if ( ! ldb_dn_validate(dn2)) {
+ talloc_free(dn1);
+ return -1;
+ }
+
+ ret = ldb_dn_compare(dn1, dn2);
+
+ talloc_free(dn1);
+ talloc_free(dn2);
+ return ret;
+}
+
+static int samba_ldb_dn_link_canonicalise(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct ldb_dn *dn;
+ int ret = -1;
+
+ out->length = 0;
+ out->data = NULL;
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
+ if ( ! ldb_dn_validate(dn)) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ /* By including the RMD_FLAGS of a deleted DN, we ensure it
+ * does not casually match a not deleted DN */
+ if (dsdb_dn_is_deleted_val(in)) {
+ out->data = (uint8_t *)talloc_asprintf(mem_ctx,
+ "<RMD_FLAGS=%u>%s",
+ dsdb_dn_val_rmd_flags(in),
+ ldb_dn_get_casefold(dn));
+ } else {
+ out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
+ }
+
+ if (out->data == NULL) {
+ goto done;
+ }
+ out->length = strlen((char *)out->data);
+
+ ret = 0;
+
+done:
+ talloc_free(dn);
+
+ return ret;
+}
+
+
+/*
+ write a 64 bit 2-part range
+*/
+static int ldif_write_range64(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ int64_t v;
+ int ret;
+ ret = val_to_int64(in, &v);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lu-%lu",
+ (unsigned long)(v&0xFFFFFFFF),
+ (unsigned long)(v>>32));
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ out->length = strlen((char *)out->data);
+ return LDB_SUCCESS;
+}
+
+/*
+ read a 64 bit 2-part range
+*/
+static int ldif_read_range64(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ unsigned long high, low;
+ char buf[64];
+
+ if (memchr(in->data, '-', in->length) == NULL) {
+ return ldb_handler_copy(ldb, mem_ctx, in, out);
+ }
+
+ if (in->length > sizeof(buf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ strncpy(buf, (const char *)in->data, in->length);
+ buf[in->length] = 0;
+
+ if (sscanf(buf, "%lu-%lu", &low, &high) != 2) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%llu",
+ (unsigned long long)(((uint64_t)high)<<32) | (low));
+
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ out->length = strlen((char *)out->data);
+ return LDB_SUCCESS;
+}
+
+/*
+ when this operator_fn is set for a syntax, the backend calls is in
+ preference to the comparison function. We are told the exact
+ comparison operation that is needed, and we can return errors
+ */
+static int samba_syntax_operator_fn(struct ldb_context *ldb, enum ldb_parse_op operation,
+ const struct ldb_schema_attribute *a,
+ const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
+{
+ switch (operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ case LDB_OP_NOT:
+ case LDB_OP_SUBSTRING:
+ case LDB_OP_APPROX:
+ case LDB_OP_EXTENDED:
+ /* handled in the backends */
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_EQUALITY:
+ {
+ TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+ int ret;
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
+ }
+ ret = a->syntax->comparison_fn(ldb, tmp_ctx, v1, v2);
+ talloc_free(tmp_ctx);
+ if (operation == LDB_OP_GREATER) {
+ *matched = (ret >= 0);
+ } else if (operation == LDB_OP_LESS) {
+ *matched = (ret <= 0);
+ } else {
+ *matched = (ret == 0);
+ }
+ return LDB_SUCCESS;
+ }
+
+ case LDB_OP_PRESENT:
+ *matched = true;
+ return LDB_SUCCESS;
+ }
+
+ /* we shouldn't get here */
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+}
+
+/*
+ compare two binary objects. This is correct for sorting as the sort order is:
+
+ a
+ aa
+ b
+ bb
+
+ rather than ldb_comparison_binary() which is:
+
+ a
+ b
+ aa
+ bb
+
+*/
+static int samba_ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ return data_blob_cmp(v1, v2);
+}
+
+/*
+ when this operator_fn is set for a syntax, the backend calls is in
+ preference to the comparison function. We are told the exact
+ comparison operation that is needed, and we can return errors.
+
+ This mode optimises for ldb_comparison_binary() if we need equality,
+ as this should be faster as it can do a length-check first.
+ */
+static int samba_syntax_binary_operator_fn(struct ldb_context *ldb, enum ldb_parse_op operation,
+ const struct ldb_schema_attribute *a,
+ const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
+{
+ if (operation == LDB_OP_EQUALITY) {
+ *matched = (ldb_comparison_binary(ldb, NULL, v1, v2) == 0);
+ return LDB_SUCCESS;
+ }
+ return samba_syntax_operator_fn(ldb, operation, a, v1, v2, matched);
+}
+
+/*
+ see if two DNs match, comparing first by GUID, then by SID, and
+ finally by string components
+ */
+static int samba_dn_extended_match(struct ldb_context *ldb,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2,
+ bool *matched)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn1, *dn2;
+ const struct ldb_val *guid1, *guid2, *sid1, *sid2;
+ uint32_t rmd_flags1, rmd_flags2;
+
+ tmp_ctx = talloc_new(ldb);
+
+ dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v1);
+ dn2 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v2);
+ if (!dn1 || !dn2) {
+ /* couldn't parse as DN's */
+ talloc_free(tmp_ctx);
+ (*matched) = false;
+ return LDB_SUCCESS;
+ }
+
+ rmd_flags1 = dsdb_dn_rmd_flags(dn1);
+ rmd_flags2 = dsdb_dn_rmd_flags(dn2);
+
+ if ((rmd_flags1 & DSDB_RMD_FLAG_DELETED) !=
+ (rmd_flags2 & DSDB_RMD_FLAG_DELETED)) {
+ /* only match if they have the same deletion status */
+ talloc_free(tmp_ctx);
+ (*matched) = false;
+ return LDB_SUCCESS;
+ }
+
+
+ guid1 = ldb_dn_get_extended_component(dn1, "GUID");
+ guid2 = ldb_dn_get_extended_component(dn2, "GUID");
+ if (guid1 && guid2) {
+ (*matched) = (data_blob_cmp(guid1, guid2) == 0);
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+
+ sid1 = ldb_dn_get_extended_component(dn1, "SID");
+ sid2 = ldb_dn_get_extended_component(dn2, "SID");
+ if (sid1 && sid2) {
+ (*matched) = (data_blob_cmp(sid1, sid2) == 0);
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+
+ (*matched) = (ldb_dn_compare(dn1, dn2) == 0);
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+/*
+ special operation for DNs, to take account of the RMD_FLAGS deleted bit
+ */
+static int samba_syntax_operator_dn(struct ldb_context *ldb, enum ldb_parse_op operation,
+ const struct ldb_schema_attribute *a,
+ const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
+{
+ if (operation == LDB_OP_PRESENT && dsdb_dn_is_deleted_val(v1)) {
+ /* If the DN is deleted, then we can't search for it */
+
+ /* should this be for equality too? */
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ if (operation == LDB_OP_EQUALITY &&
+ samba_dn_extended_match(ldb, v1, v2, matched) == LDB_SUCCESS) {
+ return LDB_SUCCESS;
+ }
+
+ return samba_syntax_operator_fn(ldb, operation, a, v1, v2, matched);
+}
+
+
+static const struct ldb_schema_syntax samba_syntaxes[] = {
+ {
+ .name = LDB_SYNTAX_SAMBA_SID,
+ .ldif_read_fn = ldif_read_objectSid,
+ .ldif_write_fn = ldif_write_objectSid,
+ .canonicalise_fn = ldif_canonicalise_objectSid,
+ .comparison_fn = ldif_comparison_objectSid,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
+ .ldif_read_fn = ldif_read_ntSecurityDescriptor,
+ .ldif_write_fn = ldif_write_ntSecurityDescriptor,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_sddlSecurityDescriptor,
+ .canonicalise_fn = ldb_handler_fold,
+ .comparison_fn = ldb_comparison_fold,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_GUID,
+ .ldif_read_fn = ldif_read_objectGUID,
+ .ldif_write_fn = ldif_write_objectGUID,
+ .canonicalise_fn = ldif_canonicalise_objectGUID,
+ .comparison_fn = ldif_comparison_objectGUID,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldif_canonicalise_objectCategory,
+ .comparison_fn = ldif_comparison_objectCategory,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_SCHEMAINFO,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_schemaInfo,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_PREFIX_MAP,
+ .ldif_read_fn = ldif_read_prefixMap,
+ .ldif_write_fn = ldif_write_prefixMap,
+ .canonicalise_fn = ldif_canonicalise_prefixMap,
+ .comparison_fn = ldif_comparison_prefixMap,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_INT32,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldif_canonicalise_int32,
+ .index_format_fn = ldif_index_format_int32,
+ .comparison_fn = ldif_comparison_int32,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_REPSFROMTO,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_repsFromTo,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_replPropertyMetaData,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_replUpToDateVector,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_REVEALEDUSERS,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_msDS_RevealedUsers,
+ .canonicalise_fn = dsdb_dn_binary_canonicalise,
+ .comparison_fn = dsdb_dn_binary_comparison,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_trustAuthInOutBlob,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_FORESTTRUSTINFO,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_ForestTrustInfo,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = DSDB_SYNTAX_BINARY_DN,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = dsdb_dn_binary_canonicalise,
+ .comparison_fn = dsdb_dn_binary_comparison,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = DSDB_SYNTAX_STRING_DN,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = dsdb_dn_string_canonicalise,
+ .comparison_fn = dsdb_dn_string_comparison,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_DN,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = samba_ldb_dn_link_canonicalise,
+ .comparison_fn = samba_ldb_dn_link_comparison,
+ .operator_fn = samba_syntax_operator_dn
+ },{
+ .name = LDB_SYNTAX_SAMBA_RANGE64,
+ .ldif_read_fn = ldif_read_range64,
+ .ldif_write_fn = ldif_write_range64,
+ .canonicalise_fn = ldif_canonicalise_int64,
+ .comparison_fn = ldif_comparison_int64,
+ .operator_fn = samba_syntax_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_DNSRECORD,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_dnsRecord,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_DNSPROPERTY,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_dnsProperty,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_supplementalCredentialsBlob,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldif_write_partialAttributeSet,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ },{
+ .name = LDB_SYNTAX_SAMBA_OCTET_STRING,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = samba_ldb_comparison_binary,
+ .operator_fn = samba_syntax_binary_operator_fn
+ }
+};
+
+static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
+ {
+ .name = "SID",
+ .read_fn = extended_dn_read_SID,
+ .write_clear_fn = ldif_write_objectSid,
+ .write_hex_fn = extended_dn_write_hex
+ },{
+ .name = "GUID",
+ .read_fn = extended_dn_read_GUID,
+ .write_clear_fn = ldif_write_objectGUID,
+ .write_hex_fn = extended_dn_write_hex
+ },{
+ .name = "WKGUID",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ },{
+ .name = "RMD_INVOCID",
+ .read_fn = extended_dn_read_GUID,
+ .write_clear_fn = ldif_write_objectGUID,
+ .write_hex_fn = extended_dn_write_hex
+ },{
+ .name = "RMD_FLAGS",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ },{
+ .name = "RMD_ADDTIME",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ },{
+ .name = "RMD_CHANGETIME",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ },{
+ .name = "RMD_LOCAL_USN",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ },{
+ .name = "RMD_ORIGINATING_USN",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ },{
+ .name = "RMD_VERSION",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy
+ }
+};
+
+/* TODO: Should be dynamic at some point */
+static const struct {
+ const char *name;
+ const char *syntax;
+} samba_attributes[] = {
+ { "ntSecurityDescriptor", LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
+ { "oMSyntax", LDB_SYNTAX_SAMBA_INT32 },
+ { "objectCategory", LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
+ { "schemaInfo", LDB_SYNTAX_SAMBA_SCHEMAINFO },
+ { "prefixMap", LDB_SYNTAX_SAMBA_PREFIX_MAP },
+ { "repsFrom", LDB_SYNTAX_SAMBA_REPSFROMTO },
+ { "repsTo", LDB_SYNTAX_SAMBA_REPSFROMTO },
+ { "replPropertyMetaData", LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
+ { "replUpToDateVector", LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
+ { "msDS-RevealedUsers", LDB_SYNTAX_SAMBA_REVEALEDUSERS },
+ { "trustAuthIncoming", LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
+ { "trustAuthOutgoing", LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
+ { "msDS-TrustForestTrustInfo", LDB_SYNTAX_SAMBA_FORESTTRUSTINFO },
+ { "rIDAllocationPool", LDB_SYNTAX_SAMBA_RANGE64 },
+ { "rIDPreviousAllocationPool", LDB_SYNTAX_SAMBA_RANGE64 },
+ { "rIDAvailablePool", LDB_SYNTAX_SAMBA_RANGE64 },
+ { "defaultSecurityDescriptor", LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR },
+
+ /*
+ * these are extracted by searching
+ * (&(attributeSyntax=2.5.5.17)(omSyntax=4))
+ *
+ * Except: msAuthz-CentralAccessPolicyID as it might be a GUID see:
+ * adminDescription: For a Central Access Policy, this attribute defines a GUID t
+ * hat can be used to identify the set of policies when applied to a resource.
+ * Until we see a msAuthz-CentralAccessPolicyID value on a windows
+ * server, we ignore it here.
+ */
+ { "mS-DS-CreatorSID", LDB_SYNTAX_SAMBA_SID },
+ { "msDS-QuotaTrustee", LDB_SYNTAX_SAMBA_SID },
+ { "objectSid", LDB_SYNTAX_SAMBA_SID },
+ { "tokenGroups", LDB_SYNTAX_SAMBA_SID },
+ { "tokenGroupsGlobalAndUniversal", LDB_SYNTAX_SAMBA_SID },
+ { "tokenGroupsNoGCAcceptable", LDB_SYNTAX_SAMBA_SID },
+ { "securityIdentifier", LDB_SYNTAX_SAMBA_SID },
+ { "sIDHistory", LDB_SYNTAX_SAMBA_SID },
+ { "syncWithSID", LDB_SYNTAX_SAMBA_SID },
+
+ /*
+ * these are extracted by searching
+ * (&(attributeSyntax=2.5.5.10)(rangeLower=16)(rangeUpper=16)(omSyntax=4))
+ */
+ { "attributeSecurityGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "categoryId", LDB_SYNTAX_SAMBA_GUID },
+ { "controlAccessRights", LDB_SYNTAX_SAMBA_GUID },
+ { "currMachineId", LDB_SYNTAX_SAMBA_GUID },
+ { "fRSReplicaSetGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "fRSVersionGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "implementedCategories", LDB_SYNTAX_SAMBA_GUID },
+ { "msDS-AzObjectGuid", LDB_SYNTAX_SAMBA_GUID },
+ { "msDS-GenerationId", LDB_SYNTAX_SAMBA_GUID },
+ { "msDS-OptionalFeatureGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "msDFSR-ContentSetGuid", LDB_SYNTAX_SAMBA_GUID },
+ { "msDFSR-ReplicationGroupGuid", LDB_SYNTAX_SAMBA_GUID },
+ { "mSMQDigests", LDB_SYNTAX_SAMBA_GUID },
+ { "mSMQOwnerID", LDB_SYNTAX_SAMBA_GUID },
+ { "mSMQQMID", LDB_SYNTAX_SAMBA_GUID },
+ { "mSMQQueueType", LDB_SYNTAX_SAMBA_GUID },
+ { "mSMQSites", LDB_SYNTAX_SAMBA_GUID },
+ { "netbootGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "objectGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "pKTGuid", LDB_SYNTAX_SAMBA_GUID },
+ { "requiredCategories", LDB_SYNTAX_SAMBA_GUID },
+ { "schemaIDGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "siteGUID", LDB_SYNTAX_SAMBA_GUID },
+ { "msDFS-GenerationGUIDv2", LDB_SYNTAX_SAMBA_GUID },
+ { "msDFS-LinkIdentityGUIDv2", LDB_SYNTAX_SAMBA_GUID },
+ { "msDFS-NamespaceIdentityGUIDv2", LDB_SYNTAX_SAMBA_GUID },
+ { "msSPP-CSVLKSkuId", LDB_SYNTAX_SAMBA_GUID },
+ { "msSPP-KMSIds", LDB_SYNTAX_SAMBA_GUID },
+
+ /*
+ * these are known to be GUIDs
+ */
+ { "invocationId", LDB_SYNTAX_SAMBA_GUID },
+ { "parentGUID", LDB_SYNTAX_SAMBA_GUID },
+
+ /* These NDR encoded things we want to be able to read with --show-binary */
+ { "dnsRecord", LDB_SYNTAX_SAMBA_DNSRECORD },
+ { "dNSProperty", LDB_SYNTAX_SAMBA_DNSPROPERTY },
+ { "supplementalCredentials", LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS},
+ { "partialAttributeSet", LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET}
+};
+
+const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
+{
+ unsigned int j;
+ const struct ldb_schema_syntax *s = NULL;
+
+ for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
+ if (strcmp(name, samba_syntaxes[j].name) == 0) {
+ s = &samba_syntaxes[j];
+ break;
+ }
+ }
+ return s;
+}
+
+const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
+{
+ unsigned int j;
+ const struct ldb_schema_syntax *s = NULL;
+
+ for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
+ if (strcmp(samba_attributes[j].name, name) == 0) {
+ s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
+ break;
+ }
+ }
+
+ return s;
+}
+
+static const char *secret_attributes[] = {DSDB_SECRET_ATTRIBUTES, "secret",
+ "priorSecret", NULL};
+
+/*
+ register the samba ldif handlers
+*/
+int ldb_register_samba_handlers(struct ldb_context *ldb)
+{
+ unsigned int i;
+ int ret;
+
+ if (ldb_get_opaque(ldb, "SAMBA_HANDLERS_REGISTERED") != NULL) {
+ return LDB_SUCCESS;
+ }
+
+ ret = ldb_set_opaque(ldb, LDB_SECRET_ATTRIBUTE_LIST_OPAQUE, discard_const_p(char *, secret_attributes));
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
+ const struct ldb_schema_syntax *s = NULL;
+
+ s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
+
+ if (!s) {
+ s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
+ }
+
+ if (!s) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
+ ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ }
+
+ ret = ldb_register_samba_matching_rules(ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return LDB_SUCCESS;
+ }
+
+ ret = ldb_set_opaque(ldb, "SAMBA_HANDLERS_REGISTERED", (void*)1);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb-samba/ldif_handlers.h b/lib/ldb-samba/ldif_handlers.h
new file mode 100644
index 0000000..8b2ade6
--- /dev/null
+++ b/lib/ldb-samba/ldif_handlers.h
@@ -0,0 +1,30 @@
+#ifndef __LIB_LDB_SAMBA_LDIF_HANDLERS_H__
+#define __LIB_LDB_SAMBA_LDIF_HANDLERS_H__
+
+#define LDB_SYNTAX_SAMBA_SID "LDB_SYNTAX_SAMBA_SID"
+#define LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR "1.2.840.113556.1.4.907"
+#define LDB_SYNTAX_SAMBA_GUID "LDB_SYNTAX_SAMBA_GUID"
+#define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
+#define LDB_SYNTAX_SAMBA_SCHEMAINFO "LDB_SYNTAX_SAMBA_SCHEMAINFO"
+#define LDB_SYNTAX_SAMBA_PREFIX_MAP "LDB_SYNTAX_SAMBA_PREFIX_MAP"
+#define LDB_SYNTAX_SAMBA_INT32 "LDB_SYNTAX_SAMBA_INT32"
+#define LDB_SYNTAX_SAMBA_REPSFROMTO "LDB_SYNTAX_SAMBA_REPSFROMTO"
+#define LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA "LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA"
+#define LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR "LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR"
+#define LDB_SYNTAX_SAMBA_REVEALEDUSERS "LDB_SYNTAX_SAMBA_REVEALEDUSERS"
+#define LDB_SYNTAX_SAMBA_RANGE64 "LDB_SYNTAX_SAMBA_RANGE64"
+#define LDB_SYNTAX_SAMBA_DNSRECORD "LDB_SYNTAX_SAMBA_DNSRECORD"
+#define LDB_SYNTAX_SAMBA_DNSPROPERTY "LDB_SYNTAX_SAMBA_DNSPROPERTY"
+#define LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS "LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS"
+#define LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR "LDB_SYNTAX_SAMBA_SDDL"
+#define LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB "LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB"
+#define LDB_SYNTAX_SAMBA_FORESTTRUSTINFO "LDB_SYNTAX_SAMBA_FORESTTRUSTINFO"
+#define LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET "LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET"
+#define LDB_SYNTAX_SAMBA_OCTET_STRING "LDB_SYNTAX_SAMBA_OCTET_STRING"
+#include "lib/ldb-samba/ldif_handlers_proto.h"
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* __LIB_LDB_SAMBA_LDIF_HANDLERS_H__ */
+
diff --git a/lib/ldb-samba/pyldb.c b/lib/ldb-samba/pyldb.c
new file mode 100644
index 0000000..2241abc
--- /dev/null
+++ b/lib/ldb-samba/pyldb.c
@@ -0,0 +1,320 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python interface to ldb, Samba-specific functions
+
+ Copyright (C) 2007-2010 Jelmer Vernooij <jelmer@samba.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include "python/py3compat.h"
+#include "includes.h"
+#include <ldb.h>
+#include <pyldb.h>
+#include "param/pyparam.h"
+#include "auth/credentials/pycredentials.h"
+#include "ldb_wrap.h"
+#include "lib/ldb-samba/ldif_handlers.h"
+#include "auth/pyauth.h"
+#include "source4/dsdb/common/util.h"
+#include "lib/ldb/include/ldb_private.h"
+
+
+static PyObject *pyldb_module;
+static PyObject *py_ldb_error;
+static PyTypeObject PySambaLdb;
+
+static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_ctx)
+{
+ if (ret == LDB_ERR_PYTHON_EXCEPTION)
+ return; /* Python exception should already be set, just keep that */
+
+ PyErr_SetObject(error,
+ Py_BuildValue(discard_const_p(char, "(i,s)"), ret,
+ ldb_ctx == NULL?ldb_strerror(ret):ldb_errstring(ldb_ctx)));
+}
+
+static PyObject *py_ldb_set_loadparm(PyObject *self, PyObject *args)
+{
+ PyObject *py_lp_ctx;
+ struct loadparm_context *lp_ctx;
+ struct ldb_context *ldb;
+
+ if (!PyArg_ParseTuple(args, "O", &py_lp_ctx))
+ return NULL;
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ lp_ctx = lpcfg_from_py_object(ldb, py_lp_ctx);
+ if (lp_ctx == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected loadparm object");
+ return NULL;
+ }
+
+ ldb_set_opaque(ldb, "loadparm", lp_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_credentials(PyObject *self, PyObject *args)
+{
+ PyObject *py_creds;
+ struct cli_credentials *creds;
+ struct ldb_context *ldb;
+
+ if (!PyArg_ParseTuple(args, "O", &py_creds))
+ return NULL;
+
+ creds = cli_credentials_from_py_object(py_creds);
+ if (creds == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected credentials object");
+ return NULL;
+ }
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ ldb_set_opaque(ldb, "credentials", creds);
+
+ Py_RETURN_NONE;
+}
+
+/* XXX: This function really should be in libldb's pyldb.c */
+static PyObject *py_ldb_set_opaque_integer(PyObject *self, PyObject *args)
+{
+ int value;
+ int *old_val, *new_val;
+ char *py_opaque_name, *opaque_name_talloc;
+ struct ldb_context *ldb;
+ int ret;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!PyArg_ParseTuple(args, "si", &py_opaque_name, &value))
+ return NULL;
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ /* see if we have a cached copy */
+ old_val = (int *)ldb_get_opaque(ldb, py_opaque_name);
+ /* XXX: We shouldn't just blindly assume that the value that is
+ * already present has the size of an int and is not shared
+ * with other code that may rely on it not changing.
+ * JRV 20100403 */
+
+ if (old_val) {
+ *old_val = value;
+ Py_RETURN_NONE;
+ }
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ new_val = talloc(tmp_ctx, int);
+ if (new_val == NULL) {
+ talloc_free(tmp_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ opaque_name_talloc = talloc_strdup(tmp_ctx, py_opaque_name);
+ if (opaque_name_talloc == NULL) {
+ talloc_free(tmp_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ *new_val = value;
+
+ /* cache the domain_sid in the ldb */
+ ret = ldb_set_opaque(ldb, opaque_name_talloc, new_val);
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ PyErr_SetLdbError(py_ldb_error, ret, ldb);
+ return NULL;
+ }
+
+ talloc_steal(ldb, new_val);
+ talloc_steal(ldb, opaque_name_talloc);
+ talloc_free(tmp_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_utf8_casefold(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb;
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_session_info(PyObject *self, PyObject *args)
+{
+ PyObject *py_session_info;
+ struct auth_session_info *info;
+ struct ldb_context *ldb;
+ PyObject *mod_samba_auth;
+ PyObject *PyAuthSession_Type;
+ bool ret;
+
+ mod_samba_auth = PyImport_ImportModule("samba.dcerpc.auth");
+ if (mod_samba_auth == NULL)
+ return NULL;
+
+ PyAuthSession_Type = PyObject_GetAttrString(mod_samba_auth, "session_info");
+ if (PyAuthSession_Type == NULL) {
+ Py_CLEAR(mod_samba_auth);
+ return NULL;
+ }
+
+ ret = PyArg_ParseTuple(args, "O!", PyAuthSession_Type, &py_session_info);
+
+ Py_DECREF(PyAuthSession_Type);
+ Py_DECREF(mod_samba_auth);
+
+ if (!ret)
+ return NULL;
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ info = PyAuthSession_AsSession(py_session_info);
+
+ ldb_set_opaque(ldb, DSDB_SESSION_INFO, info);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_samba_schema_attribute_add(PyLdbObject *self,
+ PyObject *args)
+{
+ char *attribute, *syntax;
+ const struct ldb_schema_syntax *s;
+ unsigned int flags;
+ int ret;
+ struct ldb_context *ldb_ctx;
+
+ if (!PyArg_ParseTuple(args, "sIs", &attribute, &flags, &syntax))
+ return NULL;
+
+ ldb_ctx = pyldb_Ldb_AsLdbContext((PyObject *)self);
+
+ s = ldb_samba_syntax_by_name(ldb_ctx, syntax);
+ ret = ldb_schema_attribute_add_with_syntax(ldb_ctx, attribute,
+ flags, s);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_error, ret, ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_register_samba_handlers(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb;
+ int ret;
+
+ /* XXX: Perhaps call this from PySambaLdb's init function ? */
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+ ret = ldb_register_samba_handlers(ldb);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_error, ret, ldb);
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_samba_ldb_methods[] = {
+ { "set_loadparm", (PyCFunction)py_ldb_set_loadparm, METH_VARARGS,
+ "set_loadparm(session_info)\n"
+ "Set loadparm context to use when connecting." },
+ { "set_credentials", (PyCFunction)py_ldb_set_credentials, METH_VARARGS,
+ "set_credentials(credentials)\n"
+ "Set credentials to use when connecting." },
+ { "set_opaque_integer", (PyCFunction)py_ldb_set_opaque_integer,
+ METH_VARARGS, NULL },
+ { "set_utf8_casefold", (PyCFunction)py_ldb_set_utf8_casefold,
+ METH_NOARGS,
+ "set_utf8_casefold()\n"
+ "Set the right Samba casefolding function for UTF8 charset." },
+ { "register_samba_handlers", (PyCFunction)py_ldb_register_samba_handlers,
+ METH_NOARGS,
+ "register_samba_handlers()\n"
+ "Register Samba-specific LDB modules and schemas." },
+ { "set_session_info", (PyCFunction)py_ldb_set_session_info, METH_VARARGS,
+ "set_session_info(session_info)\n"
+ "Set session info to use when connecting." },
+ { "samba_schema_attribute_add",
+ (PyCFunction)py_ldb_samba_schema_attribute_add,
+ METH_VARARGS, NULL },
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "_ldb",
+ .m_doc = "Samba-specific LDB python bindings",
+ .m_size = -1,
+ .m_methods = py_samba_ldb_methods,
+};
+
+static PyTypeObject PySambaLdb = {
+ .tp_name = "samba._ldb.Ldb",
+ .tp_doc = "Connection to a LDB database.",
+ .tp_methods = py_samba_ldb_methods,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
+
+MODULE_INIT_FUNC(_ldb)
+{
+ PyObject *m;
+
+ pyldb_module = PyImport_ImportModule("ldb");
+ if (pyldb_module == NULL)
+ return NULL;
+
+ PySambaLdb.tp_base = (PyTypeObject *)PyObject_GetAttrString(pyldb_module, "Ldb");
+ if (PySambaLdb.tp_base == NULL) {
+ Py_CLEAR(pyldb_module);
+ return NULL;
+ }
+
+ py_ldb_error = PyObject_GetAttrString(pyldb_module, "LdbError");
+
+ Py_CLEAR(pyldb_module);
+
+ if (PyType_Ready(&PySambaLdb) < 0)
+ return NULL;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ Py_INCREF(&PySambaLdb);
+ PyModule_AddObject(m, "Ldb", (PyObject *)&PySambaLdb);
+
+#define ADD_LDB_STRING(val) PyModule_AddStringConstant(m, #val, LDB_## val)
+ ADD_LDB_STRING(SYNTAX_SAMBA_INT32);
+
+ return m;
+}
diff --git a/lib/ldb-samba/samba_extensions.c b/lib/ldb-samba/samba_extensions.c
new file mode 100644
index 0000000..be92d98
--- /dev/null
+++ b/lib/ldb-samba/samba_extensions.c
@@ -0,0 +1,169 @@
+/*
+ ldb database library - samba extensions
+
+ Copyright (C) Andrew Tridgell 2010
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "ldb_module.h"
+#include "lib/cmdline/cmdline.h"
+#include "auth/gensec/gensec.h"
+#include "auth/auth.h"
+#include "param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
+#include "ldb_wrap.h"
+#include "popt.h"
+
+
+static bool is_popt_table_end(const struct poptOption *o)
+{
+ if (o->longName == NULL &&
+ o->shortName =='\0' &&
+ o->arg == NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ work out the length of a popt array
+ */
+static size_t calculate_popt_array_length(struct poptOption *opts)
+{
+ size_t i = 0;
+
+ for (i = 0; i < UINT32_MAX; i++) {
+ struct poptOption *o = &(opts[i]);
+
+ if (is_popt_table_end(o)) {
+ break;
+ }
+ }
+
+ return i;
+}
+
+/*
+ called to register additional command line options
+ */
+static int extensions_hook(struct ldb_context *ldb, enum ldb_module_hook_type t)
+{
+ switch (t) {
+ case LDB_MODULE_HOOK_CMDLINE_OPTIONS: {
+ size_t len1, len2;
+ struct poptOption **popt_options = ldb_module_popt_options(ldb);
+ struct poptOption *new_array = NULL;
+ bool ok;
+
+ struct poptOption cmdline_extensions[] = {
+ POPT_COMMON_SAMBA_LDB
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_LEGACY_S4
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+
+ ok = samba_cmdline_init(ldb,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ return ldb_oom(ldb);
+ }
+
+ len1 = calculate_popt_array_length(*popt_options);
+ len2 = calculate_popt_array_length(cmdline_extensions);
+ new_array = talloc_array(ldb,
+ struct poptOption,
+ len1 + len2 + 1);
+ if (NULL == new_array) {
+ return ldb_oom(ldb);
+ }
+
+ memcpy(new_array, *popt_options, len1*sizeof(struct poptOption));
+ memcpy(new_array+len1, cmdline_extensions, (1+len2)*sizeof(struct poptOption));
+
+#ifdef DEVELOPER
+ ok = samba_cmdline_sanity_check(new_array);
+ if (!ok) {
+ talloc_free(new_array);
+ return ldb_error(ldb,
+ LDB_ERR_OPERATIONS_ERROR,
+ "Duplicate cmdline options detected!");
+ }
+#endif
+
+ (*popt_options) = new_array;
+ return LDB_SUCCESS;
+ }
+
+ case LDB_MODULE_HOOK_CMDLINE_PRECONNECT: {
+ struct loadparm_context *lp_ctx = NULL;
+ struct cli_credentials *creds = NULL;
+
+ int r = ldb_register_samba_handlers(ldb);
+ if (r != LDB_SUCCESS) {
+ return ldb_operr(ldb);
+ }
+ gensec_init();
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+ creds = samba_cmdline_get_creds();
+
+ if (ldb_set_opaque(
+ ldb,
+ DSDB_SESSION_INFO,
+ system_session(lp_ctx))) {
+
+ return ldb_operr(ldb);
+ }
+ if (ldb_set_opaque(ldb, "credentials", creds)) {
+ return ldb_operr(ldb);
+ }
+ if (ldb_set_opaque(ldb, "loadparm", lp_ctx)) {
+ return ldb_operr(ldb);
+ }
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+ break;
+ }
+
+ case LDB_MODULE_HOOK_CMDLINE_POSTCONNECT:
+ /* get the domain SID into the cache for SDDL processing */
+ samdb_domain_sid(ldb);
+ break;
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ initialise the module
+ */
+_PUBLIC_ int ldb_samba_extensions_init(const char *ldb_version)
+{
+ ldb_register_hook(extensions_hook);
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb-samba/tests/index.py b/lib/ldb-samba/tests/index.py
new file mode 100644
index 0000000..2256e3e
--- /dev/null
+++ b/lib/ldb-samba/tests/index.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python3
+#
+# Tests for comparison expressions on indexed keys
+#
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2019
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+"""Tests for expressions containing comparisons on indexed attributes.
+ Copied from ldb's index.py"""
+
+import os
+from unittest import TestCase
+import sys
+from samba import _ldb
+import shutil
+from ldb import SCOPE_SUBTREE
+from samba.tests.subunitrun import TestProgram
+
+PY3 = sys.version_info > (3, 0)
+
+TDB_PREFIX = "tdb://"
+MDB_PREFIX = "mdb://"
+
+def tempdir():
+ import tempfile
+ try:
+ dir_prefix = os.path.join(os.environ["SELFTEST_PREFIX"], "tmp")
+ except KeyError:
+ dir_prefix = None
+ return tempfile.mkdtemp(dir=dir_prefix)
+
+class LdbBaseTest(TestCase):
+ def setUp(self):
+ super(LdbBaseTest, self).setUp()
+ try:
+ if self.prefix is None:
+ self.prefix = TDB_PREFIX
+ except AttributeError:
+ self.prefix = TDB_PREFIX
+
+ def tearDown(self):
+ super(LdbBaseTest, self).tearDown()
+
+ def url(self):
+ return self.prefix + self.filename
+
+ def flags(self):
+ if self.prefix == MDB_PREFIX:
+ return ldb.FLG_NOSYNC
+ else:
+ return 0
+
+ def options(self):
+ if self.prefix == MDB_PREFIX:
+ return ['disable_full_db_scan_for_self_test:1']
+ else:
+ return None
+
+class LdbTDBIndexedComparisonExpressions(LdbBaseTest):
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(LdbTDBIndexedComparisonExpressions, self).tearDown()
+
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+ def setUp(self):
+ super(LdbTDBIndexedComparisonExpressions, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "indexedcomptest.ldb")
+ # Note that the maximum key length is set to 54
+ # This accounts for the 4 bytes added by the dn formatting
+ # a leading dn=, and a trailing zero terminator
+ #
+ self.l = _ldb.Ldb(self.url(), options=self.options())
+ self.l.add({"dn": "@ATTRIBUTES"})
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"int32attr"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+
+ def test_comparison_expression(self):
+ self.l.samba_schema_attribute_add("int32attr", 0,
+ _ldb.SYNTAX_SAMBA_INT32)
+
+ int32_max = 2**31-1
+ int32_min = -2**31
+ test_nums = list(range(-5, 5))
+ test_nums += list(range(int32_max-5, int32_max+1))
+ test_nums += list(range(int32_min, int32_min+5))
+ test_nums = sorted(test_nums)
+
+ for i in test_nums:
+ ouuid = 0x0123456789abcdef + i
+ ouuid_s = bytes(('0' + hex(ouuid)[2:]).encode())
+ self.l.add({"dn": "OU=COMPTESTOU{},DC=SAMBA,DC=ORG".format(i),
+ "objectUUID": ouuid_s,
+ "int32attr": str(i)})
+
+ def assert_int32_expr(expr, py_expr=None):
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=SCOPE_SUBTREE,
+ expression="(int32attr%s)" % (expr))
+
+ if not py_expr:
+ py_expr = expr
+ expect = [n for n in test_nums if eval(str(n) + py_expr)]
+ vals = sorted([int(r.get("int32attr")[0]) for r in res])
+ self.assertEqual(len(res), len(expect))
+ self.assertEqual(set(vals), set(expect))
+ self.assertEqual(expect, vals)
+
+ assert_int32_expr(">=-2")
+ assert_int32_expr("<=2")
+ assert_int32_expr(">=" + str(int32_min))
+ assert_int32_expr("<=" + str(int32_min))
+ assert_int32_expr("<=" + str(int32_min+1))
+ assert_int32_expr("<=" + str(int32_max))
+ assert_int32_expr(">=" + str(int32_max))
+ assert_int32_expr(">=" + str(int32_max-1))
+ assert_int32_expr("=10", "==10")
+
+ def test_comparison_expression_duplicates(self):
+ self.l.samba_schema_attribute_add("int32attr", 0,
+ _ldb.SYNTAX_SAMBA_INT32)
+
+ int32_max = 2**31-1
+ int32_min = -2**31
+
+ test_nums = list(range(-5, 5)) * 3
+ test_nums += list(range(-20, 20, 5)) * 2
+ test_nums += list(range(-50, 50, 15))
+ test_nums = sorted(test_nums)
+
+ for i, n in enumerate(test_nums):
+ ouuid = 0x0123456789abcdef + i
+ ouuid_s = bytes(('0' + hex(ouuid)[2:]).encode())
+ self.l.add({"dn": "OU=COMPTESTOU{},DC=SAMBA,DC=ORG".format(i),
+ "objectUUID": ouuid_s,
+ "int32attr": str(n)})
+
+ def assert_int32_expr(expr, py_expr=None):
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=SCOPE_SUBTREE,
+ expression="(int32attr%s)" % (expr))
+
+ if not py_expr:
+ py_expr = expr
+ expect = [n for n in test_nums if eval(str(n) + py_expr)]
+ vals = sorted([int(r.get("int32attr")[0]) for r in res])
+ self.assertEqual(len(res), len(expect))
+ self.assertEqual(set(vals), set(expect))
+ self.assertEqual(expect, vals)
+
+ assert_int32_expr(">=-2")
+ assert_int32_expr("<=2")
+ assert_int32_expr(">=" + str(int32_min))
+ assert_int32_expr("<=" + str(int32_min))
+ assert_int32_expr("<=" + str(int32_min+1))
+ assert_int32_expr("<=" + str(int32_max))
+ assert_int32_expr(">=" + str(int32_max))
+ assert_int32_expr(">=" + str(int32_max-1))
+ assert_int32_expr("=-5", "==-5")
+ assert_int32_expr("=5", "==5")
+
+# Run the same tests against an lmdb backend
+class LdbLMDBIndexedComparisonExpressions(LdbTDBIndexedComparisonExpressions):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(LdbLMDBIndexedComparisonExpressions, self).setUp()
+
+ def tearDown(self):
+ super(LdbLMDBIndexedComparisonExpressions, self).tearDown()
+
+
+TestProgram(module=__name__, opts=[])
diff --git a/lib/ldb-samba/tests/match_rules.py b/lib/ldb-samba/tests/match_rules.py
new file mode 100755
index 0000000..2fe6c3e
--- /dev/null
+++ b/lib/ldb-samba/tests/match_rules.py
@@ -0,0 +1,1797 @@
+#!/usr/bin/env python3
+
+import optparse
+import sys
+import os
+import samba
+import samba.getopt as options
+
+from samba.tests.subunitrun import SubunitOptions, TestProgram
+
+from samba.samdb import SamDB
+from samba.auth import system_session
+from ldb import Message, MessageElement, Dn, LdbError
+from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
+from ldb import SCOPE_BASE, SCOPE_SUBTREE, SCOPE_ONELEVEL
+
+# TODO I'm ignoring case in these tests for now.
+# This should be fixed to work inline with Windows.
+# The literal strings are in the case Windows uses.
+# Windows appear to preserve casing of the RDN and uppercase the other keys.
+
+
+class MatchRulesTestsBase(samba.tests.TestCase):
+ def setUp(self):
+ super().setUp()
+ self.lp = self.sambaopts.get_loadparm()
+ self.creds = self.credopts.get_credentials(self.lp)
+
+ self.ldb = SamDB(self.host, credentials=self.creds,
+ session_info=system_session(self.lp),
+ lp=self.lp)
+ self.base_dn = self.ldb.domain_dn()
+ self.ou_rdn = "OU=matchrulestest"
+ self.ou = self.ou_rdn + "," + self.base_dn
+ self.ou_users = "OU=users,%s" % self.ou
+ self.ou_groups = "OU=groups,%s" % self.ou
+ self.ou_computers = "OU=computers,%s" % self.ou
+
+ try:
+ self.ldb.delete(self.ou, ["tree_delete:1"])
+ except LdbError as e:
+ pass
+
+ # Add a organizational unit to create objects
+ self.ldb.add({
+ "dn": self.ou,
+ "objectclass": "organizationalUnit"})
+
+ self.addCleanup(self.ldb.delete, self.ou, controls=['tree_delete:0'])
+
+
+ # Add the following OU hierarchy and set otherWellKnownObjects,
+ # which has BinaryDN syntax:
+ #
+ # o1
+ # |--> o2
+ # | |--> o3
+ # | | |-->o4
+
+ self.ldb.add({
+ "dn": "OU=o1,%s" % self.ou,
+ "objectclass": "organizationalUnit"})
+ self.ldb.add({
+ "dn": "OU=o2,OU=o1,%s" % self.ou,
+ "objectclass": "organizationalUnit"})
+ self.ldb.add({
+ "dn": "OU=o3,OU=o2,OU=o1,%s" % self.ou,
+ "objectclass": "organizationalUnit"})
+ self.ldb.add({
+ "dn": "OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou,
+ "objectclass": "organizationalUnit"})
+
+ m = Message()
+ m.dn = Dn(self.ldb, self.ou)
+ m["otherWellKnownObjects"] = MessageElement("B:32:00000000000000000000000000000001:OU=o1,%s" % self.ou,
+ FLAG_MOD_ADD, "otherWellKnownObjects")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "OU=o1,%s" % self.ou)
+ m["otherWellKnownObjects"] = MessageElement("B:32:00000000000000000000000000000002:OU=o2,OU=o1,%s" % self.ou,
+ FLAG_MOD_ADD, "otherWellKnownObjects")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "OU=o2,OU=o1,%s" % self.ou)
+ m["otherWellKnownObjects"] = MessageElement("B:32:00000000000000000000000000000003:OU=o3,OU=o2,OU=o1,%s" % self.ou,
+ FLAG_MOD_ADD, "otherWellKnownObjects")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "OU=o3,OU=o2,OU=o1,%s" % self.ou)
+ m["otherWellKnownObjects"] = MessageElement("B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou,
+ FLAG_MOD_ADD, "otherWellKnownObjects")
+ self.ldb.modify(m)
+
+ # Create OU for users and groups
+ self.ldb.add({
+ "dn": self.ou_users,
+ "objectclass": "organizationalUnit"})
+ self.ldb.add({
+ "dn": self.ou_groups,
+ "objectclass": "organizationalUnit"})
+ self.ldb.add({
+ "dn": self.ou_computers,
+ "objectclass": "organizationalUnit"})
+
+ # Add four groups
+ self.ldb.add({
+ "dn": "cn=g1,%s" % self.ou_groups,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=g2,%s" % self.ou_groups,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=g4,%s" % self.ou_groups,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=g3,%s" % self.ou_groups,
+ "objectclass": "group"})
+
+ # Add four users
+ self.ldb.add({
+ "dn": "cn=u1,%s" % self.ou_users,
+ "objectclass": "user"})
+ self.ldb.add({
+ "dn": "cn=u2,%s" % self.ou_users,
+ "objectclass": "user"})
+ self.ldb.add({
+ "dn": "cn=u3,%s" % self.ou_users,
+ "objectclass": "user"})
+ self.ldb.add({
+ "dn": "cn=u4,%s" % self.ou_users,
+ "objectclass": "user"})
+
+ # Add computers to test Object(DN-Binary) syntax
+ self.ldb.add({
+ "dn": "cn=c1,%s" % self.ou_computers,
+ "objectclass": "computer",
+ "dNSHostName": "c1.%s" % self.lp.get("realm").lower(),
+ "servicePrincipalName": ["HOST/c1"],
+ "sAMAccountName": "c1$",
+ "userAccountControl": "83890178"})
+
+ self.ldb.add({
+ "dn": "cn=c2,%s" % self.ou_computers,
+ "objectclass": "computer",
+ "dNSHostName": "c2.%s" % self.lp.get("realm").lower(),
+ "servicePrincipalName": ["HOST/c2"],
+ "sAMAccountName": "c2$",
+ "userAccountControl": "83890178"})
+
+ self.ldb.add({
+ "dn": "cn=c3,%s" % self.ou_computers,
+ "objectclass": "computer",
+ "dNSHostName": "c3.%s" % self.lp.get("realm").lower(),
+ "servicePrincipalName": ["HOST/c3"],
+ "sAMAccountName": "c3$",
+ "userAccountControl": "83890178"})
+
+ # Create the following hierarchy:
+ # g4
+ # |--> u4
+ # |--> g3
+ # | |--> u3
+ # | |--> g2
+ # | | |--> u2
+ # | | |--> g1
+ # | | | |--> u1
+
+ # u1 member of g1
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g1,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=u1,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # u2 member of g2
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups)
+ m["member"] = MessageElement("cn=u2,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # u3 member of g3
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=g3,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=u3,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # u4 member of g4
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=g4,%s" % self.ou_groups)
+ m["member"] = MessageElement("cn=u4,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # g3 member of g4
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
+ m["member"] = MessageElement("cn=g3,%s" % self.ou_groups,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # g2 member of g3
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=g3,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=g2,%s" % self.ou_groups,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # g1 member of g2
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=g2,%s" % self.ou_groups)
+ m["member"] = MessageElement("cn=g1,%s" % self.ou_groups,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # Add a couple of ms-Exch-Configuration-Container to test forward-link
+ # attributes without backward link (addressBookRoots2)
+ # e1
+ # |--> e2
+ # | |--> c1
+ self.ldb.add({
+ "dn": "cn=e1,%s" % self.ou,
+ "objectclass": "msExchConfigurationContainer"})
+ self.ldb.add({
+ "dn": "cn=e2,%s" % self.ou,
+ "objectclass": "msExchConfigurationContainer"})
+
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=e2,%s" % self.ou)
+ m["e1"] = MessageElement("cn=c1,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "addressBookRoots2")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=e1,%s" % self.ou)
+ m["e1"] = MessageElement("cn=e2,%s" % self.ou,
+ FLAG_MOD_ADD, "addressBookRoots2")
+ self.ldb.modify(m)
+
+
+
+class MatchRulesTests(MatchRulesTestsBase):
+ def setUp(self):
+ self.sambaopts = sambaopts
+ self.credopts = credopts
+ self.host = host
+ super().setUp()
+
+ # The msDS-RevealedUsers is owned by system and cannot be modified
+ # directly. Set the schemaUpgradeInProgress flag as workaround
+ # and create this hierarchy:
+ # ou=computers
+ # |-> c1
+ # | |->c2
+ # | | |->u1
+
+ #
+ # While appropriate for this test, this is NOT a good practice
+ # in general. This is only done here because the alternative
+ # is to make a schema modification.
+ #
+ # IF/WHEN Samba protects this attribute better, this
+ # particular part of the test can be removed, as the same code
+ # is covered by the addressBookRoots2 case well enough.
+ #
+ m = Message()
+ m.dn = Dn(self.ldb, "")
+ m["e1"] = MessageElement("1", FLAG_MOD_REPLACE, "schemaUpgradeInProgress")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=c2,%s" % self.ou_computers)
+ m["e1"] = MessageElement("B:8:01010101:cn=c3,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "msDS-RevealedUsers")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "cn=c1,%s" % self.ou_computers)
+ m["e1"] = MessageElement("B:8:01010101:cn=c2,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "msDS-RevealedUsers")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "")
+ m["e1"] = MessageElement("0", FLAG_MOD_REPLACE, "schemaUpgradeInProgress")
+ self.ldb.modify(m)
+
+
+ def test_u1_member_of_g4(self):
+ # Search without transitive match must return 0 results
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=u1,%s" % self.ou_users,
+ scope=SCOPE_BASE,
+ expression="memberOf=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ # Search with transitive match must return 1 results
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search("cn=u1,%s" % self.ou_users,
+ scope=SCOPE_BASE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=u1,%s" % self.ou_users).lower())
+
+ def test_g1_member_of_g4(self):
+ # Search without transitive match must return 0 results
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="memberOf=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ # Search with transitive match must return 1 results
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
+
+ def test_u1_groups(self):
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ def test_u2_groups(self):
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g2,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ def test_u3_groups(self):
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g3,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ def test_u4_groups(self):
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_users,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ def test_extended_dn_u1(self):
+ res1 = self.ldb.search("cn=u1,%s" % self.ou_users,
+ scope=SCOPE_BASE,
+ expression="objectClass=*",
+ attrs=['objectSid', 'objectGUID'])
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("cn=u1,%s" % self.ou_users).lower())
+
+ sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0]).decode('utf8')
+ guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0]).decode('utf8')
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g1,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g1,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ def test_extended_dn_u2(self):
+ res1 = self.ldb.search("cn=u2,%s" % self.ou_users,
+ scope=SCOPE_BASE,
+ expression="objectClass=*",
+ attrs=['objectSid', 'objectGUID'])
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("cn=u2,%s" % self.ou_users).lower())
+
+ sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0]).decode('utf8')
+ guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0]).decode('utf8')
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g2,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g2,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g2,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ def test_extended_dn_u3(self):
+ res1 = self.ldb.search("cn=u3,%s" % self.ou_users,
+ scope=SCOPE_BASE,
+ expression="objectClass=*",
+ attrs=['objectSid', 'objectGUID'])
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("cn=u3,%s" % self.ou_users).lower())
+
+ sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0]).decode('utf8')
+ guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0]).decode('utf8')
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g3,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g3,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=g3,%s" % self.ou_groups).lower() in dn_list)
+ self.assertTrue(("CN=g4,%s" % self.ou_groups).lower() in dn_list)
+
+ def test_extended_dn_u4(self):
+ res1 = self.ldb.search("cn=u4,%s" % self.ou_users,
+ scope=SCOPE_BASE,
+ expression="objectClass=*",
+ attrs=['objectSid', 'objectGUID'])
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("cn=u4,%s" % self.ou_users).lower())
+
+ sid = self.ldb.schema_format_value("objectSid", res1[0]["objectSid"][0]).decode('utf8')
+ guid = self.ldb.schema_format_value("objectGUID", res1[0]['objectGUID'][0]).decode('utf8')
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<SID=%s>" % sid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=<GUID=%s>" % guid)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ def test_object_dn_binary(self):
+ res1 = self.ldb.search(self.ou_computers,
+ scope=SCOPE_SUBTREE,
+ expression="msDS-RevealedUsers=B:8:01010101:cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=c2,%s" % self.ou_computers).lower())
+
+ res1 = self.ldb.search(self.ou_computers,
+ scope=SCOPE_ONELEVEL,
+ expression="msDS-RevealedUsers=B:8:01010101:cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=c2,%s" % self.ou_computers).lower())
+
+ res1 = self.ldb.search(self.ou_computers,
+ scope=SCOPE_SUBTREE,
+ expression="msDS-RevealedUsers:1.2.840.113556.1.4.1941:=B:8:01010101:cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=c1,%s" % self.ou_computers).lower() in dn_list)
+ self.assertTrue(("CN=c2,%s" % self.ou_computers).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou_computers,
+ scope=SCOPE_ONELEVEL,
+ expression="msDS-RevealedUsers:1.2.840.113556.1.4.1941:=B:8:01010101:cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=c1,%s" % self.ou_computers).lower() in dn_list)
+ self.assertTrue(("CN=c2,%s" % self.ou_computers).lower() in dn_list)
+
+ def test_one_way_links(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="addressBookRoots2=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=e2,%s" % self.ou).lower())
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_ONELEVEL,
+ expression="addressBookRoots2=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=e2,%s" % self.ou).lower())
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="addressBookRoots2:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=e1,%s" % self.ou).lower() in dn_list)
+ self.assertTrue(("CN=e2,%s" % self.ou).lower() in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_ONELEVEL,
+ expression="addressBookRoots2:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn).lower() for res in res1]
+ self.assertTrue(("CN=e1,%s" % self.ou).lower() in dn_list)
+ self.assertTrue(("CN=e2,%s" % self.ou).lower() in dn_list)
+
+ def test_not_linked_attrs(self):
+ res1 = self.ldb.search(self.base_dn,
+ scope=SCOPE_BASE,
+ expression="wellKnownObjects=B:32:aa312825768811d1aded00c04fd8d5cd:CN=computers,%s" % self.base_dn)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), self.base_dn.lower())
+
+ def test_invalid_basedn(self):
+ res1 = self.ldb.search(self.base_dn,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=c1,ou=computers,ou=matchrulestest,%sXX" % self.base_dn)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.base_dn,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=XX,ou=computers,ou=matchrulestest,%s" % self.base_dn)
+ self.assertEqual(len(res1), 0)
+
+ def test_subtree(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="otherWellKnownObjects=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("OU=o3,OU=o2,OU=o1,%s" % self.ou).lower())
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_ONELEVEL,
+ expression="otherWellKnownObjects=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="otherWellKnownObjects:1.2.840.113556.1.4.1941:=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_ONELEVEL,
+ expression="otherWellKnownObjects:1.2.840.113556.1.4.1941:=B:32:00000000000000000000000000000004:OU=o4,OU=o3,OU=o2,OU=o1,%s" % self.ou)
+ self.assertEqual(len(res1), 0)
+
+ def test_unknown_oid(self):
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:2.4.681.226012.2.8.3882:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:8.16.8720.1008448.8.32.15528:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.3.4:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ def test_nul_text(self):
+ self.assertRaises((ValueError,TypeError),
+ lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="\00member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users))
+ self.assertRaises((ValueError,TypeError),
+ lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840\00.113556.1.4.1941:=cn=u1,%s" % self.ou_users))
+ self.assertRaises((ValueError,TypeError),
+ lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1\00,%s" % self.ou_users))
+ self.assertRaises(LdbError,
+ lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users))
+ self.assertRaises(LdbError,
+ lambda: self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:"))
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=")
+ self.assertEqual(len(res1), 0)
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member=")
+ self.assertEqual(len(res1), 0)
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=nonexistent")
+ self.assertEqual(len(res1), 0)
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member=nonexistent")
+ self.assertEqual(len(res1), 0)
+ self.assertRaises(LdbError,
+ lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:cn=u1,%s" % self.ou_users))
+ self.assertRaises(LdbError,
+ lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1"))
+ self.assertRaises(LdbError,
+ lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn="))
+ self.assertRaises(LdbError,
+ lambda: self.ldb.search("cn=\00g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member::=cn=u1,%s" % self.ou_users))
+
+ def test_misc_matches(self):
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=g2,%s" % self.ou_groups)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=g2,%s" % self.ou_groups)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=g1,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="memberOf=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="memberOf=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), ("CN=g3,%s" % self.ou_groups))
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="memberOf=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), ("CN=g3,%s" % self.ou_groups))
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_ONELEVEL,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou_groups,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+
+class MatchRuleConditionTests(samba.tests.TestCase):
+ def setUp(self):
+ super(MatchRuleConditionTests, self).setUp()
+ self.lp = sambaopts.get_loadparm()
+ self.creds = credopts.get_credentials(self.lp)
+
+ self.ldb = SamDB(host, credentials=self.creds,
+ session_info=system_session(self.lp),
+ lp=self.lp)
+ self.base_dn = self.ldb.domain_dn()
+ self.ou = "OU=matchruleconditiontests,%s" % self.base_dn
+ self.ou_users = "OU=users,%s" % self.ou
+ self.ou_groups = "OU=groups,%s" % self.ou
+ self.ou_computers = "OU=computers,%s" % self.ou
+
+ # Add a organizational unit to create objects
+ self.ldb.add({
+ "dn": self.ou,
+ "objectclass": "organizationalUnit"})
+
+ # Create users, groups, and computers
+ self.ldb.add({
+ "dn": self.ou_users,
+ "objectclass": "organizationalUnit"})
+ self.ldb.add({
+ "dn": self.ou_groups,
+ "objectclass": "organizationalUnit"})
+ self.ldb.add({
+ "dn": self.ou_computers,
+ "objectclass": "organizationalUnit"})
+
+ self.ldb.add({
+ "dn": "cn=g1,%s" % self.ou_groups,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=g2,%s" % self.ou_groups,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=g3,%s" % self.ou_groups,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=g4,%s" % self.ou_groups,
+ "objectclass": "group"})
+
+ self.ldb.add({
+ "dn": "cn=u1,%s" % self.ou_users,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=u2,%s" % self.ou_users,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=u3,%s" % self.ou_users,
+ "objectclass": "group"})
+ self.ldb.add({
+ "dn": "cn=u4,%s" % self.ou_users,
+ "objectclass": "group"})
+
+ self.ldb.add({
+ "dn": "cn=c1,%s" % self.ou_computers,
+ "objectclass": "user"})
+
+ self.ldb.add({
+ "dn": "cn=c2,%s" % self.ou_computers,
+ "objectclass": "user"})
+
+ self.ldb.add({
+ "dn": "cn=c3,%s" % self.ou_computers,
+ "objectclass": "user"})
+
+ self.ldb.add({
+ "dn": "cn=c4,%s" % self.ou_computers,
+ "objectclass": "user"})
+
+ # Assign groups according to the following structure:
+ # g1-->g2---->g3 --g4
+ # \ | / | / / |
+ # u1- >u2-- | u3<- | u4
+ # \ \ \ \ |
+ # c1* >c2 ->c3 c4
+ # *c1 is a member of u1, u2, u3, and u4
+
+ # u2 is a member of g1 and g2
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g1,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=u2,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=u2,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # g2 is a member of g1
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g1,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=g2,%s" % self.ou_groups,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # g3 is a member of g2
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=g3,%s" % self.ou_groups,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # u3 is a member of g3 and g4
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g3,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=u3,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=u3,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # u4 is a member of g4
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=u4,%s" % self.ou_users,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # c1 is a member of u1, u2, u3, and u4
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=u1,%s" % self.ou_users)
+ m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=u2,%s" % self.ou_users)
+ m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=u3,%s" % self.ou_users)
+ m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=u4,%s" % self.ou_users)
+ m["member"] = MessageElement("CN=c1,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # c2 is a member of u1
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=u1,%s" % self.ou_users)
+ m["member"] = MessageElement("CN=c2,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # c3 is a member of u2 and g3
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=u2,%s" % self.ou_users)
+ m["member"] = MessageElement("CN=c3,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g3,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=c3,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ # c4 is a member of u4 and g4
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=u4,%s" % self.ou_users)
+ m["member"] = MessageElement("CN=c4,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(self.ldb, "CN=g4,%s" % self.ou_groups)
+ m["member"] = MessageElement("CN=c4,%s" % self.ou_computers,
+ FLAG_MOD_ADD, "member")
+ self.ldb.modify(m)
+
+ def tearDown(self):
+ super(MatchRuleConditionTests, self).tearDown()
+ self.ldb.delete(self.ou, controls=['tree_delete:0'])
+
+ def test_g1_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 6)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g1,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ def test_g2_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=g2,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 5)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=g2,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=g1,%s" % self.ou_groups)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g2,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=g1,%s" % self.ou_groups)
+
+ def test_g3_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=g3,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=g3,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=g2,%s" % self.ou_groups)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g3,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+
+ def test_g4_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=g4,%s" % self.ou_groups)
+ self.assertEqual(len(res1), 0)
+
+ def test_u1_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c2,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c2,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ def test_u2_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u2,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+
+ def test_u3_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=c1,%s" % self.ou_computers)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=u3,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=c1,%s" % self.ou_computers)
+
+ def test_u4_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=g4,%s" % self.ou_groups)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=g4,%s" % self.ou_groups)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=u4,%s" % self.ou_users)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+ def test_c1_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 8)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=c1,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ def test_c2_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=c2,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=u1,%s" % self.ou_users)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=c2,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=u1,%s" % self.ou_users)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=c2,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=c2,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ def test_c3_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 4)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=c3,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ def test_c4_members(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member=cn=c4,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=c4,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf=cn=c4,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression="memberOf:1.2.840.113556.1.4.1941:=cn=c4,%s" % self.ou_computers)
+ self.assertEqual(len(res1), 0)
+
+ def test_or_member_queries(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c1,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=c2,%s))") % (
+ self.ou_computers, self.ou_computers))
+ self.assertEqual(len(res1), 8)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c2,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=c3,%s))") % (
+ self.ou_computers, self.ou_computers))
+ self.assertEqual(len(res1), 5)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c2,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=c4,%s))") % (
+ self.ou_computers, self.ou_computers))
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u1,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(member:1.2.840.113556.1.4.1941:=cn=c3,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=c4,%s))") % (
+ self.ou_computers, self.ou_computers))
+ self.assertEqual(len(res1), 6)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(member:1.2.840.113556.1.4.1941:=cn=u1,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=c4,%s))") % (
+ self.ou_users, self.ou_computers))
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g4,%s" % self.ou_groups in dn_list)
+
+ def test_and_member_queries(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c1,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=c2,%s))") % (
+ self.ou_computers, self.ou_computers))
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn), "CN=u1,%s" % self.ou_users)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c2,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=c3,%s))") % (
+ self.ou_computers, self.ou_computers))
+ self.assertEqual(len(res1), 0)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c3,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=u3,%s))") % (
+ self.ou_computers, self.ou_users))
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=g1,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(member:1.2.840.113556.1.4.1941:=cn=c1,%s)"
+ "(member:1.2.840.113556.1.4.1941:=cn=u4,%s))") % (
+ self.ou_computers, self.ou_computers))
+ self.assertEqual(len(res1), 0)
+
+ def test_or_memberOf_queries(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 6)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 6)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 8)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g2,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") %
+ (self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 5)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 7)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(|(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 5)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u4,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c4,%s" % self.ou_computers in dn_list)
+
+ def test_and_memberOf_queries(self):
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 5)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u2,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=g3,%s" % self.ou_groups in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 3)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+ self.assertTrue("CN=c3,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g2,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g3,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=g4,%s))") % (
+ self.ou_groups, self.ou_groups))
+ self.assertEqual(len(res1), 2)
+ dn_list = [str(res.dn) for res in res1]
+ self.assertTrue("CN=u3,%s" % self.ou_users in dn_list)
+ self.assertTrue("CN=c1,%s" % self.ou_computers in dn_list)
+
+ res1 = self.ldb.search(self.ou,
+ scope=SCOPE_SUBTREE,
+ expression=("(&(memberOf:1.2.840.113556.1.4.1941:=cn=g1,%s)"
+ "(memberOf:1.2.840.113556.1.4.1941:=cn=c1,%s))") % (
+ self.ou_groups, self.ou_computers))
+ self.assertEqual(len(res1), 0)
+
+if __name__ == "__main__":
+
+ parser = optparse.OptionParser("match_rules.py [options] <host>")
+ sambaopts = options.SambaOptions(parser)
+ parser.add_option_group(sambaopts)
+ parser.add_option_group(options.VersionOptions(parser))
+
+ # use command line creds if available
+ credopts = options.CredentialsOptions(parser)
+ parser.add_option_group(credopts)
+ opts, args = parser.parse_args()
+ subunitopts = SubunitOptions(parser)
+ parser.add_option_group(subunitopts)
+
+ if len(args) < 1:
+ parser.print_usage()
+ sys.exit(1)
+
+ host = args[0]
+
+ if "://" not in host:
+ if os.path.isfile(host):
+ host = "tdb://%s" % host
+ else:
+ host = "ldap://%s" % host
+
+ TestProgram(module=__name__, opts=subunitopts)
diff --git a/lib/ldb-samba/tests/match_rules_remote.py b/lib/ldb-samba/tests/match_rules_remote.py
new file mode 100755
index 0000000..122231f
--- /dev/null
+++ b/lib/ldb-samba/tests/match_rules_remote.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+
+import optparse
+import sys
+import os
+import samba
+import samba.getopt as options
+
+from samba.tests.subunitrun import SubunitOptions, TestProgram
+
+from samba.samdb import SamDB
+from samba.auth import system_session
+from samba import sd_utils
+from samba.ndr import ndr_unpack
+from ldb import Message, MessageElement, Dn, LdbError
+from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
+from ldb import SCOPE_BASE, SCOPE_SUBTREE, SCOPE_ONELEVEL
+
+from match_rules import MatchRulesTestsBase
+
+
+class MatchRulesTestsUser(MatchRulesTestsBase):
+ def setUp(self):
+ self.sambaopts = sambaopts
+ self.credopts = credopts
+ self.host = host
+ super().setUp()
+ self.sd_utils = sd_utils.SDUtils(self.ldb)
+
+ self.user_pass = "samba123@"
+ self.match_test_user = "matchtestuser"
+ self.ldb.newuser(self.match_test_user,
+ self.user_pass,
+ userou=self.ou_rdn)
+ user_creds = self.insta_creds(template=self.creds,
+ username=self.match_test_user,
+ userpass=self.user_pass)
+ self.user_ldb = SamDB(host, credentials=user_creds, lp=self.lp)
+ token_res = self.user_ldb.search(scope=SCOPE_BASE,
+ base="",
+ attrs=["tokenGroups"])
+ self.user_sid = ndr_unpack(samba.dcerpc.security.dom_sid,
+ token_res[0]["tokenGroups"][0])
+
+ self.member_attr_guid = "bf9679c0-0de6-11d0-a285-00aa003049e2"
+
+ def test_with_denied_link(self):
+
+ # add an ACE that denies the user Read Property (RP) access to
+ # the member attr (which is similar to making the attribute
+ # confidential)
+ ace = "(OD;;RP;{0};;{1})".format(self.member_attr_guid,
+ self.user_sid)
+ g2_dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups)
+
+ # add the ACE that denies access to the attr under test
+ self.sd_utils.dacl_add_ace(g2_dn, ace)
+
+ # Search without transitive match must return 0 results
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+ # Search with transitive match must return 1 results
+ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 1)
+ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower())
+
+ # Search as a user match must return 0 results as the intermediate link can't be seen
+ res1 = self.user_ldb.search("cn=g4,%s" % self.ou_groups,
+ scope=SCOPE_BASE,
+ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users)
+ self.assertEqual(len(res1), 0)
+
+
+
+parser = optparse.OptionParser("match_rules_remote.py [options] <host>")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+
+# use command line creds if available
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+opts, args = parser.parse_args()
+subunitopts = SubunitOptions(parser)
+parser.add_option_group(subunitopts)
+
+if len(args) < 1:
+ parser.print_usage()
+ sys.exit(1)
+
+host = args[0]
+
+if "://" not in host:
+ if os.path.isfile(host):
+ host = "tdb://%s" % host
+ else:
+ host = "ldap://%s" % host
+
+TestProgram(module=__name__, opts=subunitopts)
diff --git a/lib/ldb-samba/wscript_build b/lib/ldb-samba/wscript_build
new file mode 100644
index 0000000..d02bc95
--- /dev/null
+++ b/lib/ldb-samba/wscript_build
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# LDBSAMBA gets included in the ldb build when we are building ldb_ildap
+# as a built-in module and this delutes the symbols in the ldb library with
+# the symbols of all of ldb_ildap's dependencies.
+
+bld.SAMBA_LIBRARY('ldbsamba',
+ source='ldif_handlers.c ldb_matching_rules.c',
+ autoproto='ldif_handlers_proto.h',
+ public_deps='ldb',
+ deps='samba-security ndr NDR_DRSBLOBS NDR_DNSP ldbwrap samdb-common SAMDB_SCHEMA tdb samba-errors',
+ private_library=True
+ )
+
+bld.SAMBA_SUBSYSTEM('ldbwrap',
+ source='ldb_wrap.c',
+ public_headers='ldb_wrap.h',
+ deps='ldb samba-util ldbsamba samba-hostconfig'
+ )
+
+pyparam_util = bld.pyembed_libname('pyparam_util')
+pyldb_util = bld.pyembed_libname('pyldb-util')
+pyauth = 'pyauth'
+bld.SAMBA_PYTHON('python_samba__ldb', 'pyldb.c',
+ deps='ldbsamba %s ldbwrap %s %s' % (pyparam_util, pyldb_util, pyauth),
+ realname='samba/_ldb.so')
+
+bld.SAMBA_MODULE('ldbsamba_extensions',
+ source='samba_extensions.c',
+ init_function='ldb_samba_extensions_init',
+ module_init_name='ldb_init_module',
+ subsystem='ldb',
+ deps='ldb ldbsamba CMDLINE_S4 gensec',
+ internal_module=False)
+
+
+# the s4-internal ldap backend
+bld.SAMBA_MODULE('ldb_ildap',
+ source='ldb_ildap.c',
+ init_function='ldb_ildap_init',
+ module_init_name='ldb_init_module',
+ deps='talloc cli-ldap samba-credentials auth_system_session',
+ internal_module=False,
+ subsystem='ldb')
diff --git a/lib/ldb/ABI/ldb-0.9.10.sigs b/lib/ldb/ABI/ldb-0.9.10.sigs
new file mode 100644
index 0000000..012ac65
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.10.sigs
@@ -0,0 +1,218 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(void *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(void *, const char *, int)
+ldb_binary_decode: struct ldb_val (void *, const char *)
+ldb_binary_encode: char *(void *, struct ldb_val)
+ldb_binary_encode_string: char *(void *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, void *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, void *, const char *, size_t)
+ldb_casefold_default: char *(void *, void *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(void *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(void *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_escape_value: char *(void *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(void *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(void *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(void *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(void *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(void *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, void *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(void *)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, void *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(void *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (void *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.12.sigs b/lib/ldb/ABI/ldb-0.9.12.sigs
new file mode 100644
index 0000000..2206e79
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.12.sigs
@@ -0,0 +1,219 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(void *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(void *, const char *, int)
+ldb_binary_decode: struct ldb_val (void *, const char *)
+ldb_binary_encode: char *(void *, struct ldb_val)
+ldb_binary_encode_string: char *(void *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, void *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, void *, const char *, size_t)
+ldb_casefold_default: char *(void *, void *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(void *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(void *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_escape_value: char *(void *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(void *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(void *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(void *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(void *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(void *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, void *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(void *)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, void *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(void *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (void *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.15.sigs b/lib/ldb/ABI/ldb-0.9.15.sigs
new file mode 100644
index 0000000..39d2f3e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.15.sigs
@@ -0,0 +1,226 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.16.sigs b/lib/ldb/ABI/ldb-0.9.16.sigs
new file mode 100644
index 0000000..610a0a4
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.16.sigs
@@ -0,0 +1,228 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.17.sigs b/lib/ldb/ABI/ldb-0.9.17.sigs
new file mode 100644
index 0000000..d0f5699
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.17.sigs
@@ -0,0 +1,229 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.18.sigs b/lib/ldb/ABI/ldb-0.9.18.sigs
new file mode 100644
index 0000000..15913c9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.18.sigs
@@ -0,0 +1,240 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_asq_init: int (const char *)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_paged_results_init: int (const char *)
+ldb_paged_searches_init: int (const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_rdn_name_init: int (const char *)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_sample_init: int (const char *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_server_sort_init: int (const char *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_skel_init: int (const char *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_tdb_init: int (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.19.sigs b/lib/ldb/ABI/ldb-0.9.19.sigs
new file mode 100644
index 0000000..6273870
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.19.sigs
@@ -0,0 +1,245 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_asq_init: int (const char *)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_paged_results_init: int (const char *)
+ldb_paged_searches_init: int (const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_rdn_name_init: int (const char *)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_sample_init: int (const char *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_server_sort_init: int (const char *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_skel_init: int (const char *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_tdb_init: int (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.20.sigs b/lib/ldb/ABI/ldb-0.9.20.sigs
new file mode 100644
index 0000000..6273870
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.20.sigs
@@ -0,0 +1,245 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_asq_init: int (const char *)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_paged_results_init: int (const char *)
+ldb_paged_searches_init: int (const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_rdn_name_init: int (const char *)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_sample_init: int (const char *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_server_sort_init: int (const char *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_skel_init: int (const char *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_tdb_init: int (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.22.sigs b/lib/ldb/ABI/ldb-0.9.22.sigs
new file mode 100644
index 0000000..b5a69c1
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.22.sigs
@@ -0,0 +1,245 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.23.sigs b/lib/ldb/ABI/ldb-0.9.23.sigs
new file mode 100644
index 0000000..73e5caa
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.23.sigs
@@ -0,0 +1,247 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-0.9.24.sigs b/lib/ldb/ABI/ldb-0.9.24.sigs
new file mode 100644
index 0000000..5cb32f7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-0.9.24.sigs
@@ -0,0 +1,248 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.0.0.sigs b/lib/ldb/ABI/ldb-1.0.0.sigs
new file mode 100644
index 0000000..5cb32f7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.0.0.sigs
@@ -0,0 +1,248 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.0.1.sigs b/lib/ldb/ABI/ldb-1.0.1.sigs
new file mode 100644
index 0000000..5cb32f7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.0.1.sigs
@@ -0,0 +1,248 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.0.2.sigs b/lib/ldb/ABI/ldb-1.0.2.sigs
new file mode 100644
index 0000000..c13ac87
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.0.2.sigs
@@ -0,0 +1,250 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.0.sigs b/lib/ldb/ABI/ldb-1.1.0.sigs
new file mode 100644
index 0000000..149d4bc
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.0.sigs
@@ -0,0 +1,253 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.1.sigs b/lib/ldb/ABI/ldb-1.1.1.sigs
new file mode 100644
index 0000000..2fe215c
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.1.sigs
@@ -0,0 +1,254 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.10.sigs b/lib/ldb/ABI/ldb-1.1.10.sigs
new file mode 100644
index 0000000..de5026e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.10.sigs
@@ -0,0 +1,259 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.11.sigs b/lib/ldb/ABI/ldb-1.1.11.sigs
new file mode 100644
index 0000000..de5026e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.11.sigs
@@ -0,0 +1,259 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.12.sigs b/lib/ldb/ABI/ldb-1.1.12.sigs
new file mode 100644
index 0000000..c8ccd25
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.12.sigs
@@ -0,0 +1,260 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.13.sigs b/lib/ldb/ABI/ldb-1.1.13.sigs
new file mode 100644
index 0000000..c8ccd25
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.13.sigs
@@ -0,0 +1,260 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.14.sigs b/lib/ldb/ABI/ldb-1.1.14.sigs
new file mode 100644
index 0000000..eac5194
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.14.sigs
@@ -0,0 +1,262 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.15.sigs b/lib/ldb/ABI/ldb-1.1.15.sigs
new file mode 100644
index 0000000..eac5194
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.15.sigs
@@ -0,0 +1,262 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.16.sigs b/lib/ldb/ABI/ldb-1.1.16.sigs
new file mode 100644
index 0000000..eac5194
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.16.sigs
@@ -0,0 +1,262 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.17.sigs b/lib/ldb/ABI/ldb-1.1.17.sigs
new file mode 100644
index 0000000..eac5194
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.17.sigs
@@ -0,0 +1,262 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.18.sigs b/lib/ldb/ABI/ldb-1.1.18.sigs
new file mode 100644
index 0000000..eac5194
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.18.sigs
@@ -0,0 +1,262 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.19.sigs b/lib/ldb/ABI/ldb-1.1.19.sigs
new file mode 100644
index 0000000..b46c5c7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.19.sigs
@@ -0,0 +1,263 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.2.sigs b/lib/ldb/ABI/ldb-1.1.2.sigs
new file mode 100644
index 0000000..d0df756
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.2.sigs
@@ -0,0 +1,256 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.20.sigs b/lib/ldb/ABI/ldb-1.1.20.sigs
new file mode 100644
index 0000000..b46c5c7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.20.sigs
@@ -0,0 +1,263 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.21.sigs b/lib/ldb/ABI/ldb-1.1.21.sigs
new file mode 100644
index 0000000..b46c5c7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.21.sigs
@@ -0,0 +1,263 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.22.sigs b/lib/ldb/ABI/ldb-1.1.22.sigs
new file mode 100644
index 0000000..6d9767b
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.22.sigs
@@ -0,0 +1,264 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.23.sigs b/lib/ldb/ABI/ldb-1.1.23.sigs
new file mode 100644
index 0000000..6d9767b
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.23.sigs
@@ -0,0 +1,264 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.24.sigs b/lib/ldb/ABI/ldb-1.1.24.sigs
new file mode 100644
index 0000000..6d9767b
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.24.sigs
@@ -0,0 +1,264 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.25.sigs b/lib/ldb/ABI/ldb-1.1.25.sigs
new file mode 100644
index 0000000..3f33df9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.25.sigs
@@ -0,0 +1,265 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.26.sigs b/lib/ldb/ABI/ldb-1.1.26.sigs
new file mode 100644
index 0000000..3f33df9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.26.sigs
@@ -0,0 +1,265 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.27.sigs b/lib/ldb/ABI/ldb-1.1.27.sigs
new file mode 100644
index 0000000..4fa30d8
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.27.sigs
@@ -0,0 +1,266 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.28.sigs b/lib/ldb/ABI/ldb-1.1.28.sigs
new file mode 100644
index 0000000..4fa30d8
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.28.sigs
@@ -0,0 +1,266 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.29.sigs b/lib/ldb/ABI/ldb-1.1.29.sigs
new file mode 100644
index 0000000..0ea968d
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.29.sigs
@@ -0,0 +1,268 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.3.sigs b/lib/ldb/ABI/ldb-1.1.3.sigs
new file mode 100644
index 0000000..d0df756
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.3.sigs
@@ -0,0 +1,256 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.30.sigs b/lib/ldb/ABI/ldb-1.1.30.sigs
new file mode 100644
index 0000000..ef9c53e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.30.sigs
@@ -0,0 +1,272 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.31.sigs b/lib/ldb/ABI/ldb-1.1.31.sigs
new file mode 100644
index 0000000..d183708
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.31.sigs
@@ -0,0 +1,274 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.4.sigs b/lib/ldb/ABI/ldb-1.1.4.sigs
new file mode 100644
index 0000000..d0df756
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.4.sigs
@@ -0,0 +1,256 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.5.sigs b/lib/ldb/ABI/ldb-1.1.5.sigs
new file mode 100644
index 0000000..cc0f859
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.5.sigs
@@ -0,0 +1,257 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.6.sigs b/lib/ldb/ABI/ldb-1.1.6.sigs
new file mode 100644
index 0000000..f90fa13
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.6.sigs
@@ -0,0 +1,258 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.7.sigs b/lib/ldb/ABI/ldb-1.1.7.sigs
new file mode 100644
index 0000000..f90fa13
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.7.sigs
@@ -0,0 +1,258 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.8.sigs b/lib/ldb/ABI/ldb-1.1.8.sigs
new file mode 100644
index 0000000..f90fa13
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.8.sigs
@@ -0,0 +1,258 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.1.9.sigs b/lib/ldb/ABI/ldb-1.1.9.sigs
new file mode 100644
index 0000000..f90fa13
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.9.sigs
@@ -0,0 +1,258 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.2.0.sigs b/lib/ldb/ABI/ldb-1.2.0.sigs
new file mode 100644
index 0000000..1be2ae7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.2.0.sigs
@@ -0,0 +1,276 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.2.1.sigs b/lib/ldb/ABI/ldb-1.2.1.sigs
new file mode 100644
index 0000000..1be2ae7
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.2.1.sigs
@@ -0,0 +1,276 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.2.2.sigs b/lib/ldb/ABI/ldb-1.2.2.sigs
new file mode 100644
index 0000000..9dc61cd
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.2.2.sigs
@@ -0,0 +1,277 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.2.3.sigs b/lib/ldb/ABI/ldb-1.2.3.sigs
new file mode 100644
index 0000000..9dc61cd
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.2.3.sigs
@@ -0,0 +1,277 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.3.0.sigs b/lib/ldb/ABI/ldb-1.3.0.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.3.0.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.3.1.sigs b/lib/ldb/ABI/ldb-1.3.1.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.3.1.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.3.2.sigs b/lib/ldb/ABI/ldb-1.3.2.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.3.2.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.4.0.sigs b/lib/ldb/ABI/ldb-1.4.0.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.4.0.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.4.1.sigs b/lib/ldb/ABI/ldb-1.4.1.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.4.1.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.5.0.sigs b/lib/ldb/ABI/ldb-1.5.0.sigs
new file mode 100644
index 0000000..a31b84e
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.5.0.sigs
@@ -0,0 +1,279 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.5.1.sigs b/lib/ldb/ABI/ldb-1.5.1.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.5.1.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.5.2.sigs b/lib/ldb/ABI/ldb-1.5.2.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.5.2.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.5.3.sigs b/lib/ldb/ABI/ldb-1.5.3.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.5.3.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.6.0.sigs b/lib/ldb/ABI/ldb-1.6.0.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.6.0.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.6.1.sigs b/lib/ldb/ABI/ldb-1.6.1.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.6.1.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.6.2.sigs b/lib/ldb/ABI/ldb-1.6.2.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.6.2.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-1.6.3.sigs b/lib/ldb/ABI/ldb-1.6.3.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.6.3.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.0.0.sigs b/lib/ldb/ABI/ldb-2.0.0.sigs
new file mode 100644
index 0000000..0c1234f
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.0.0.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.0.1.sigs b/lib/ldb/ABI/ldb-2.0.1.sigs
new file mode 100644
index 0000000..f782d73
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.0.1.sigs
@@ -0,0 +1,280 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.0.2.sigs b/lib/ldb/ABI/ldb-2.0.2.sigs
new file mode 100644
index 0000000..5fc5560
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.0.2.sigs
@@ -0,0 +1,281 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.0.3.sigs b/lib/ldb/ABI/ldb-2.0.3.sigs
new file mode 100644
index 0000000..5fc5560
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.0.3.sigs
@@ -0,0 +1,281 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.0.4.sigs b/lib/ldb/ABI/ldb-2.0.4.sigs
new file mode 100644
index 0000000..446804b
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.0.4.sigs
@@ -0,0 +1,282 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.0.5.sigs b/lib/ldb/ABI/ldb-2.0.5.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.0.5.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.1.0.sigs b/lib/ldb/ABI/ldb-2.1.0.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.1.0.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.1.1.sigs b/lib/ldb/ABI/ldb-2.1.1.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.1.1.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.2.0.sigs b/lib/ldb/ABI/ldb-2.2.0.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.2.0.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.4.0.sigs b/lib/ldb/ABI/ldb-2.4.0.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.4.0.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.4.1.sigs b/lib/ldb/ABI/ldb-2.4.1.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.4.1.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.5.0.sigs b/lib/ldb/ABI/ldb-2.5.0.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.5.0.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.6.0.sigs b/lib/ldb/ABI/ldb-2.6.0.sigs
new file mode 100644
index 0000000..5049dc6
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.6.0.sigs
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.6.1.sigs b/lib/ldb/ABI/ldb-2.6.1.sigs
new file mode 100644
index 0000000..40388d9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.6.1.sigs
@@ -0,0 +1,291 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_string_flags: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...)
+ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int)
+ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int)
+ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int)
+ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.7.0.sigs b/lib/ldb/ABI/ldb-2.7.0.sigs
new file mode 100644
index 0000000..40388d9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.7.0.sigs
@@ -0,0 +1,291 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_string_flags: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...)
+ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int)
+ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int)
+ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int)
+ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.8.0.sigs b/lib/ldb/ABI/ldb-2.8.0.sigs
new file mode 100644
index 0000000..759659a
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.8.0.sigs
@@ -0,0 +1,305 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_attrs_in_place: int (struct ldb_message *, const char * const *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_match_scope: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *, enum ldb_scope)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_distinguished_name: int (struct ldb_message *)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_string_flags: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...)
+ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int)
+ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int)
+ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int)
+ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_element_is_inaccessible: bool (const struct ldb_message_element *)
+ldb_msg_element_mark_inaccessible: void (struct ldb_message_element *)
+ldb_msg_elements_take_ownership: int (struct ldb_message *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_remove_inaccessible: void (struct ldb_message *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_shrink_to_fit: void (struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_get_attr: const char *(const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_register_redact_callback: int (struct ldb_context *, ldb_redact_fn, struct ldb_module *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_as_bool: int (const struct ldb_val *, bool *)
+ldb_val_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_val *)
+ldb_val_as_int64: int (const struct ldb_val *, int64_t *)
+ldb_val_as_uint64: int (const struct ldb_val *, uint64_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-2.9.0.sigs b/lib/ldb/ABI/ldb-2.9.0.sigs
new file mode 100644
index 0000000..759659a
--- /dev/null
+++ b/lib/ldb/ABI/ldb-2.9.0.sigs
@@ -0,0 +1,305 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_attrs_in_place: int (struct ldb_message *, const char * const *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_match_scope: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *, enum ldb_scope)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_distinguished_name: int (struct ldb_message *)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_string_flags: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...)
+ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int)
+ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int)
+ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int)
+ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_element_is_inaccessible: bool (const struct ldb_message_element *)
+ldb_msg_element_mark_inaccessible: void (struct ldb_message_element *)
+ldb_msg_elements_take_ownership: int (struct ldb_message *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_remove_inaccessible: void (struct ldb_message *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_shrink_to_fit: void (struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_get_attr: const char *(const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_register_redact_callback: int (struct ldb_context *, ldb_redact_fn, struct ldb_module *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_as_bool: int (const struct ldb_val *, bool *)
+ldb_val_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_val *)
+ldb_val_as_int64: int (const struct ldb_val *, int64_t *)
+ldb_val_as_uint64: int (const struct ldb_val *, uint64_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/ldb-ildap-0.9.12.sigs b/lib/ldb/ABI/ldb-ildap-0.9.12.sigs
new file mode 100644
index 0000000..4639220
--- /dev/null
+++ b/lib/ldb/ABI/ldb-ildap-0.9.12.sigs
@@ -0,0 +1,224 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(void *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(void *, const char *, int)
+ldb_binary_decode: struct ldb_val (void *, const char *)
+ldb_binary_encode: char *(void *, struct ldb_val)
+ldb_binary_encode_string: char *(void *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, void *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, void *, const char *, size_t)
+ldb_casefold_default: char *(void *, void *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(void *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(void *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_escape_value: char *(void *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(void *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(void *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(void *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(void *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(void *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, void *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(void *)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, void *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(void *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_register_samba_handlers: int (struct ldb_context *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_samba_syntax_by_lDAPDisplayName: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_samba_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (void *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
+ldb_wrap_connect: struct ldb_context *(TALLOC_CTX *, struct tevent_context *, struct loadparm_context *, const char *, struct auth_session_info *, struct cli_credentials *, unsigned int)
+ldb_wrap_fork_hook: void (void)
diff --git a/lib/ldb/ABI/ldb-samba4-0.9.10.sigs b/lib/ldb/ABI/ldb-samba4-0.9.10.sigs
new file mode 100644
index 0000000..7f9dbb5
--- /dev/null
+++ b/lib/ldb/ABI/ldb-samba4-0.9.10.sigs
@@ -0,0 +1,223 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(void *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(void *, const char *, int)
+ldb_binary_decode: struct ldb_val (void *, const char *)
+ldb_binary_encode: char *(void *, struct ldb_val)
+ldb_binary_encode_string: char *(void *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, void *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, void *, const char *, size_t)
+ldb_casefold_default: char *(void *, void *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(void *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(void *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_escape_value: char *(void *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(void *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(void *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(void *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(void *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(void *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, void *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(void *)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, void *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(void *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_register_samba_handlers: int (struct ldb_context *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_samba_syntax_by_lDAPDisplayName: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_samba_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (void *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
+ldb_wrap_connect: struct ldb_context *(TALLOC_CTX *, struct tevent_context *, struct loadparm_context *, const char *, struct auth_session_info *, struct cli_credentials *, unsigned int)
+ldb_wrap_fork_hook: void (void)
diff --git a/lib/ldb/ABI/ldb-samba4-0.9.11.sigs b/lib/ldb/ABI/ldb-samba4-0.9.11.sigs
new file mode 100644
index 0000000..4639220
--- /dev/null
+++ b/lib/ldb/ABI/ldb-samba4-0.9.11.sigs
@@ -0,0 +1,224 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(void *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(void *, const char *, int)
+ldb_binary_decode: struct ldb_val (void *, const char *)
+ldb_binary_encode: char *(void *, struct ldb_val)
+ldb_binary_encode_string: char *(void *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, void *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, void *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, void *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, void *, const char *, size_t)
+ldb_casefold_default: char *(void *, void *, const char *, size_t)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(void *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(void *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(void *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_escape_value: char *(void *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(void *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(void *, struct ldb_dn *, int)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(void *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(void *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(void *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(void *, struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_init_module_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_load_modules_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, void *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(void *)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, void *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(void *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_register_samba_handlers: int (struct ldb_context *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_samba_syntax_by_lDAPDisplayName: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_samba_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_val_dup: struct ldb_val (void *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
+ldb_wrap_connect: struct ldb_context *(TALLOC_CTX *, struct tevent_context *, struct loadparm_context *, const char *, struct auth_session_info *, struct cli_credentials *, unsigned int)
+ldb_wrap_fork_hook: void (void)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.10.sigs b/lib/ldb/ABI/pyldb-util-1.1.10.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.10.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.11.sigs b/lib/ldb/ABI/pyldb-util-1.1.11.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.11.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.12.sigs b/lib/ldb/ABI/pyldb-util-1.1.12.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.12.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.13.sigs b/lib/ldb/ABI/pyldb-util-1.1.13.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.13.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.14.sigs b/lib/ldb/ABI/pyldb-util-1.1.14.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.14.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.15.sigs b/lib/ldb/ABI/pyldb-util-1.1.15.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.15.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.16.sigs b/lib/ldb/ABI/pyldb-util-1.1.16.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.16.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.17.sigs b/lib/ldb/ABI/pyldb-util-1.1.17.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.17.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.18.sigs b/lib/ldb/ABI/pyldb-util-1.1.18.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.18.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.19.sigs b/lib/ldb/ABI/pyldb-util-1.1.19.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.19.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.2.sigs b/lib/ldb/ABI/pyldb-util-1.1.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.20.sigs b/lib/ldb/ABI/pyldb-util-1.1.20.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.20.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.21.sigs b/lib/ldb/ABI/pyldb-util-1.1.21.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.21.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.22.sigs b/lib/ldb/ABI/pyldb-util-1.1.22.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.22.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.23.sigs b/lib/ldb/ABI/pyldb-util-1.1.23.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.23.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.24.sigs b/lib/ldb/ABI/pyldb-util-1.1.24.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.24.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.25.sigs b/lib/ldb/ABI/pyldb-util-1.1.25.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.25.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.26.sigs b/lib/ldb/ABI/pyldb-util-1.1.26.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.26.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.27.sigs b/lib/ldb/ABI/pyldb-util-1.1.27.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.27.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.28.sigs b/lib/ldb/ABI/pyldb-util-1.1.28.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.28.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.29.sigs b/lib/ldb/ABI/pyldb-util-1.1.29.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.29.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.3.sigs b/lib/ldb/ABI/pyldb-util-1.1.3.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.3.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.30.sigs b/lib/ldb/ABI/pyldb-util-1.1.30.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.30.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.31.sigs b/lib/ldb/ABI/pyldb-util-1.1.31.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.31.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.4.sigs b/lib/ldb/ABI/pyldb-util-1.1.4.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.4.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.5.sigs b/lib/ldb/ABI/pyldb-util-1.1.5.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.5.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.6.sigs b/lib/ldb/ABI/pyldb-util-1.1.6.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.6.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.7.sigs b/lib/ldb/ABI/pyldb-util-1.1.7.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.7.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.8.sigs b/lib/ldb/ABI/pyldb-util-1.1.8.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.8.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.9.sigs b/lib/ldb/ABI/pyldb-util-1.1.9.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.9.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.2.0.sigs b/lib/ldb/ABI/pyldb-util-1.2.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.2.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.2.1.sigs b/lib/ldb/ABI/pyldb-util-1.2.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.2.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.2.2.sigs b/lib/ldb/ABI/pyldb-util-1.2.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.2.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.2.3.sigs b/lib/ldb/ABI/pyldb-util-1.2.3.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.2.3.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.3.0.sigs b/lib/ldb/ABI/pyldb-util-1.3.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.3.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.3.1.sigs b/lib/ldb/ABI/pyldb-util-1.3.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.3.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.3.2.sigs b/lib/ldb/ABI/pyldb-util-1.3.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.3.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.4.0.sigs b/lib/ldb/ABI/pyldb-util-1.4.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.4.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.4.1.sigs b/lib/ldb/ABI/pyldb-util-1.4.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.4.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.5.0.sigs b/lib/ldb/ABI/pyldb-util-1.5.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.5.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.5.1.sigs b/lib/ldb/ABI/pyldb-util-1.5.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.5.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.5.2.sigs b/lib/ldb/ABI/pyldb-util-1.5.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.5.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.5.3.sigs b/lib/ldb/ABI/pyldb-util-1.5.3.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.5.3.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.6.0.sigs b/lib/ldb/ABI/pyldb-util-1.6.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.6.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.6.1.sigs b/lib/ldb/ABI/pyldb-util-1.6.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.6.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.6.2.sigs b/lib/ldb/ABI/pyldb-util-1.6.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.6.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-1.6.3.sigs b/lib/ldb/ABI/pyldb-util-1.6.3.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.6.3.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-2.0.0.sigs b/lib/ldb/ABI/pyldb-util-2.0.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.0.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-2.0.1.sigs b/lib/ldb/ABI/pyldb-util-2.0.1.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.0.1.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-2.0.2.sigs b/lib/ldb/ABI/pyldb-util-2.0.2.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.0.2.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-2.0.3.sigs b/lib/ldb/ABI/pyldb-util-2.0.3.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.0.3.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-2.0.4.sigs b/lib/ldb/ABI/pyldb-util-2.0.4.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.0.4.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-2.0.5.sigs b/lib/ldb/ABI/pyldb-util-2.0.5.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.0.5.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util-2.1.0.sigs b/lib/ldb/ABI/pyldb-util-2.1.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.1.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.1.1.sigs b/lib/ldb/ABI/pyldb-util-2.1.1.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.1.1.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.2.0.sigs b/lib/ldb/ABI/pyldb-util-2.2.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.2.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.4.0.sigs b/lib/ldb/ABI/pyldb-util-2.4.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.4.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.4.1.sigs b/lib/ldb/ABI/pyldb-util-2.4.1.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.4.1.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.5.0.sigs b/lib/ldb/ABI/pyldb-util-2.5.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.5.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.6.0.sigs b/lib/ldb/ABI/pyldb-util-2.6.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.6.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.6.1.sigs b/lib/ldb/ABI/pyldb-util-2.6.1.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.6.1.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.7.0.sigs b/lib/ldb/ABI/pyldb-util-2.7.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.7.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.8.0.sigs b/lib/ldb/ABI/pyldb-util-2.8.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.8.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util-2.9.0.sigs b/lib/ldb/ABI/pyldb-util-2.9.0.sigs
new file mode 100644
index 0000000..164a806
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-2.9.0.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util.py3-2.0.0.sigs b/lib/ldb/ABI/pyldb-util.py3-2.0.0.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-2.0.0.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/Doxyfile b/lib/ldb/Doxyfile
new file mode 100644
index 0000000..07b12b5
--- /dev/null
+++ b/lib/ldb/Doxyfile
@@ -0,0 +1,26 @@
+PROJECT_NAME = LDB
+OUTPUT_DIRECTORY = apidocs
+REPEAT_BRIEF = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+GENERATE_TODOLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+INPUT = include .
+FILE_PATTERNS = *.h *.dox
+EXCLUDE = include/config.h include/dlinklist.h \
+ include/includes.h
+EXAMPLE_PATH = examples
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+GENERATE_MAN = YES
+ALWAYS_DETAILED_SEC = YES
+JAVADOC_AUTOBRIEF = YES
diff --git a/lib/ldb/Makefile b/lib/ldb/Makefile
new file mode 100644
index 0000000..b82723f
--- /dev/null
+++ b/lib/ldb/Makefile
@@ -0,0 +1,53 @@
+# simple makefile wrapper to run waf
+
+WAF_BIN=`PATH=buildtools/bin:../../buildtools/bin:$$PATH which waf`
+WAF_BINARY=$(PYTHON) $(WAF_BIN)
+WAF=PYTHONHASHSEED=1 WAF_MAKE=1 $(WAF_BINARY)
+
+all:
+ $(WAF) build
+
+install:
+ $(WAF) install
+
+uninstall:
+ $(WAF) uninstall
+
+test:
+ $(WAF) test $(TEST_OPTIONS)
+
+dist:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) dist
+
+distcheck:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) distcheck
+
+clean:
+ $(WAF) clean
+
+distclean:
+ $(WAF) distclean
+
+reconfigure: configure
+ $(WAF) reconfigure
+
+show_waf_options:
+ $(WAF) --help
+
+# some compatibility make targets
+everything: all
+
+testsuite: all
+
+check: test
+
+# this should do an install as well, once install is finished
+installcheck: test
+
+etags:
+ $(WAF) etags
+
+ctags:
+ $(WAF) ctags
diff --git a/lib/ldb/README_gcov.txt b/lib/ldb/README_gcov.txt
new file mode 100644
index 0000000..2abd937
--- /dev/null
+++ b/lib/ldb/README_gcov.txt
@@ -0,0 +1,29 @@
+Here is how to use gcov to test code coverage in ldb.
+
+Step 1: build ldb with gcov enabled
+
+ make clean all WITH_GCOV=1
+
+Step 3: run the test suite
+ make test-tdb
+
+Step 4: produce the gcov report
+ make gcov
+
+Step 5: read the summary reports
+ less *.report.gcov
+
+Step 6: examine the per-file reports
+ less ldb_tdb\#ldb_tdb.c.gcov
+
+You can also combine steps 2 to 4 like this:
+
+ make clean all test-tdb gcov WITH_GCOV=1
+
+Note that you should not expect 100% coverage, as some error paths
+(such as memory allocation failures) are very hard to trigger. There
+are ways of working around this, but they are quite tricky (they
+involve allocation wrappers that "fork and fail on malloc").
+
+The lines to look for in the per-file reports are the ones starting
+with "#####". Those are lines that are never executed.
diff --git a/lib/ldb/_ldb_text.py b/lib/ldb/_ldb_text.py
new file mode 100644
index 0000000..e0505e1
--- /dev/null
+++ b/lib/ldb/_ldb_text.py
@@ -0,0 +1,146 @@
+# Text wrapper for ldb bindings
+#
+# Copyright (C) 2015 Petr Viktorin <pviktori@redhat.com>
+# Published under the GNU LGPLv3 or later
+
+import ldb
+
+
+def _recursive_encode(obj):
+ if isinstance(obj, bytes):
+ return obj
+ elif isinstance(obj, str):
+ return obj.encode('utf-8')
+ else:
+ return [_recursive_encode(o) for o in obj]
+
+
+class _WrapBase(object):
+
+ @classmethod
+ def _wrap(cls, wrapped):
+ self = cls.__new__(cls)
+ self._wrapped = wrapped
+ return self
+
+ def __len__(self):
+ return len(self._wrapped)
+
+ def __eq__(self, other):
+ if hasattr(other, '_wrapped'):
+ return self._wrapped == other._wrapped
+ else:
+ return self._wrapped == other
+
+ def __ne__(self, other):
+ if hasattr(other, '_wrapped'):
+ return self._wrapped != other._wrapped
+ else:
+ return self._wrapped != other
+
+ def __lt__(self, other):
+ if hasattr(other, '_wrapped'):
+ return self._wrapped < other._wrapped
+ else:
+ return self._wrapped < other
+
+ def __le__(self, other):
+ if hasattr(other, '_wrapped'):
+ return self._wrapped >= other._wrapped
+ else:
+ return self._wrapped >= other
+
+ def __gt__(self, other):
+ if hasattr(other, '_wrapped'):
+ return self._wrapped > other._wrapped
+ else:
+ return self._wrapped > other
+
+ def __ge__(self, other):
+ if hasattr(other, '_wrapped'):
+ return self._wrapped >= other._wrapped
+ else:
+ return self._wrapped >= other
+
+ def __repr__(self):
+ return '%s.text' % repr(self._wrapped)
+
+
+class MessageElementTextWrapper(_WrapBase):
+
+ """Text interface for a LDB message element"""
+
+ def __iter__(self):
+ for item in self._wrapped:
+ yield item.decode('utf-8')
+
+ def __getitem__(self, key):
+ result = self._wrapped[key]
+ if result is None:
+ return None
+ else:
+ return result.decode('utf-8')
+
+ @property
+ def flags(self):
+ return self._wrapped.flags
+
+ @property
+ def set_flags(self):
+ return self._wrapped.set_flags
+
+
+_wrap_element = MessageElementTextWrapper._wrap
+
+
+class MessageTextWrapper(_WrapBase):
+
+ """Text interface for a LDB message"""
+
+ def __getitem__(self, key):
+ result = self._wrapped[key]
+ if result is None:
+ return None
+ else:
+ return _wrap_element(result)
+
+ def get(self, *args, **kwargs):
+ result = self._wrapped.get(*args, **kwargs)
+ if isinstance(result, ldb.MessageElement):
+ return _wrap_element(result)
+ elif isinstance(result, bytes):
+ return result.decode('utf-8')
+ else:
+ return result
+
+ def __setitem__(self, key, item):
+ self._wrapped[key] = _recursive_encode(item)
+
+ def __delitem__(self, key):
+ del self._wrapped[key]
+
+ def elements(self):
+ return [_wrap_element(el) for el in self._wrapped.elements()]
+
+ def items(self):
+ return [(attr, _wrap_element(el)) for attr, el in self._wrapped.items()]
+
+ @property
+ def keys(self):
+ return self._wrapped.keys
+
+ @property
+ def remove(self):
+ return self._wrapped.remove
+
+ @property
+ def add(self):
+ return self._wrapped.add
+
+ @property
+ def dn(self):
+ return self._wrapped.dn
+
+ @dn.setter
+ def dn(self, new_value):
+ self._wrapped.dn = new_value
diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c
new file mode 100644
index 0000000..15470cf
--- /dev/null
+++ b/lib/ldb/common/attrib_handlers.c
@@ -0,0 +1,639 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ attribute handlers for well known attribute types, selected by syntax OID
+ see rfc2252
+*/
+
+#include "ldb_private.h"
+#include "system/locale.h"
+#include "ldb_handlers.h"
+
+/*
+ default handler that just copies a ldb_val.
+*/
+int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ *out = ldb_val_dup(mem_ctx, in);
+ if (in->length > 0 && out->data == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ a case folding copy handler, removing leading and trailing spaces and
+ multiple internal spaces
+
+ We exploit the fact that utf8 never uses the space octet except for
+ the space itself
+*/
+int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ char *s, *t, *start;
+ bool in_space;
+
+ if (!in || !out || !(in->data)) {
+ return -1;
+ }
+
+ out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length);
+ if (out->data == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%.*s]", (int)in->length, (const char *)in->data);
+ return -1;
+ }
+
+ start = (char *)(out->data);
+ in_space = true;
+ t = start;
+ for (s = start; *s != '\0'; s++) {
+ if (*s == ' ') {
+ if (in_space) {
+ /*
+ * We already have one (or this is the start)
+ * and we don't want to add more
+ */
+ continue;
+ }
+ in_space = true;
+ } else {
+ in_space = false;
+ }
+ *t = *s;
+ t++;
+ }
+
+ if (in_space && t != start) {
+ /* the loop will have left a single trailing space */
+ t--;
+ }
+ *t = '\0';
+
+ out->length = t - start;
+ return 0;
+}
+
+/* length limited conversion of a ldb_val to an int64_t */
+static int val_to_int64(const struct ldb_val *in, int64_t *v)
+{
+ char *end;
+ char buf[64];
+
+ /* make sure we don't read past the end of the data */
+ if (in->length > sizeof(buf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ strncpy(buf, (char *)in->data, in->length);
+ buf[in->length] = 0;
+
+ *v = (int64_t) strtoll(buf, &end, 0);
+ if (*end != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ return LDB_SUCCESS;
+}
+
+
+/*
+ canonicalise a ldap Integer
+ rfc2252 specifies it should be in decimal form
+*/
+static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ int64_t i;
+ int ret;
+
+ ret = val_to_int64(in, &i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/*
+ * Lexicographically ordered format for a ldap Integer
+ *
+ * [ INT64_MIN ... -3, -2, -1 | 0 | +1, +2, +3 ... INT64_MAX ]
+ * n o p
+ *
+ * For human readability sake, we continue to format the key as a string
+ * (like the canonicalize) rather than store as a fixed binary representation.
+ *
+ * In order to sort the integers in the correct string order, there are three
+ * techniques we use:
+ *
+ * 1. Zero padding
+ * 2. Negative integer inversion
+ * 3. 1-byte prefixes: 'n' < 'o' < 'p'
+ *
+ * 1. To have a fixed-width representation so that 10 sorts after 2 rather than
+ * after 1, we zero pad, like this 4-byte width example:
+ *
+ * 0001, 0002, 0010
+ *
+ * INT64_MAX = 2^63 - 1 = 9223372036854775807 (19 characters long)
+ *
+ * Meaning we need to pad to 19 characters.
+ *
+ * 2. This works for positive integers, but negative integers will still be
+ * sorted backwards, for example:
+ *
+ * -9223372036854775808 ..., -0000000000000000002, -0000000000000000001
+ * INT64_MIN -2 -1
+ *
+ * gets sorted based on string as:
+ *
+ * -0000000000000000001, -0000000000000000002, ... -9223372036854775808
+ *
+ * In order to fix this, we invert the negative integer range, so that they
+ * get sorted the same way as positive numbers. INT64_MIN becomes the lowest
+ * possible non-negative number (zero), and -1 becomes the highest (INT64_MAX).
+ *
+ * The actual conversion applied to negative number 'x' is:
+ * INT64_MAX - abs(x) + 1
+ * (The +1 is needed because abs(INT64_MIN) is one greater than INT64_MAX)
+ *
+ * 3. Finally, we now have two different numbers that map to the same key, e.g.
+ * INT64_MIN maps to -0000000000000000000 and zero maps to 0000000000000000000.
+ * In order to avoid confusion, we give every number a prefix representing its
+ * sign: 'n' for negative numbers, 'o' for zero, and 'p' for positive. (Note
+ * that '+' and '-' weren't used because they sort the wrong way).
+ *
+ * The result is a range of key values that look like this:
+ *
+ * n0000000000000000000, ... n9223372036854775807,
+ * INT64_MIN -1
+ *
+ * o0000000000000000000,
+ * ZERO
+ *
+ * p0000000000000000001, ... p9223372036854775807
+ * +1 INT64_MAX
+ */
+static int ldb_index_format_Integer(struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_val *in,
+ struct ldb_val *out)
+{
+ int64_t i;
+ int ret;
+ char prefix;
+ size_t len;
+
+ ret = val_to_int64(in, &i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (i < 0) {
+ /*
+ * i is negative, so this is subtraction rather than
+ * wrap-around.
+ */
+ prefix = 'n';
+ i = INT64_MAX + i + 1;
+ } else if (i > 0) {
+ prefix = 'p';
+ } else {
+ prefix = 'o';
+ }
+
+ out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%c%019lld", prefix, (long long)i);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ len = talloc_array_length(out->data) - 1;
+ if (len != 20) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ __location__ ": expected index format str %s to"
+ " have length 20 but got %zu",
+ (char*)out->data, len);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ out->length = 20;
+ return 0;
+}
+
+/*
+ compare two Integers
+*/
+static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ int64_t i1=0, i2=0;
+ val_to_int64(v1, &i1);
+ val_to_int64(v2, &i2);
+ if (i1 == i2) return 0;
+ return i1 > i2? 1 : -1;
+}
+
+/*
+ canonicalise a ldap Boolean
+ rfc2252 specifies it should be either "TRUE" or "FALSE"
+*/
+static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ if (in->length >= 4 && strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
+ out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
+ out->length = 4;
+ } else if (in->length >= 5 && strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
+ out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
+ out->length = 5;
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ compare two Booleans
+*/
+static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
+}
+
+
+/*
+ compare two binary blobs
+*/
+int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+/*
+ compare two case insensitive strings, ignoring multiple whitespaces
+ and leading and trailing whitespaces
+ see rfc2252 section 8.1
+
+ try to optimize for the ascii case,
+ but if we find out an utf8 codepoint revert to slower but correct function
+*/
+int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
+ size_t n1 = v1->length, n2 = v2->length;
+ char *b1, *b2;
+ const char *u1, *u2;
+ int ret;
+
+ while (n1 && *s1 == ' ') { s1++; n1--; };
+ while (n2 && *s2 == ' ') { s2++; n2--; };
+
+ while (n1 && n2 && *s1 && *s2) {
+ /* the first 127 (0x7F) chars are ascii and utf8 guarantees they
+ * never appear in multibyte sequences */
+ if (((unsigned char)s1[0]) & 0x80) goto utf8str;
+ if (((unsigned char)s2[0]) & 0x80) goto utf8str;
+ if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
+ break;
+ if (*s1 == ' ') {
+ while (n1 > 1 && s1[0] == s1[1]) { s1++; n1--; }
+ while (n2 > 1 && s2[0] == s2[1]) { s2++; n2--; }
+ }
+ s1++; s2++;
+ n1--; n2--;
+ }
+
+ /* check for trailing spaces only if the other pointers has
+ * reached the end of the strings otherwise we can
+ * mistakenly match. ex. "domain users" <->
+ * "domainUpdates"
+ */
+ if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
+ while (n1 && *s1 == ' ') { s1++; n1--; }
+ }
+ if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
+ while (n2 && *s2 == ' ') { s2++; n2--; }
+ }
+ if (n1 == 0 && n2 != 0) {
+ return -(int)ldb_ascii_toupper(*s2);
+ }
+ if (n2 == 0 && n1 != 0) {
+ return (int)ldb_ascii_toupper(*s1);
+ }
+ if (n1 == 0 && n2 == 0) {
+ return 0;
+ }
+ return (int)ldb_ascii_toupper(*s1) - (int)ldb_ascii_toupper(*s2);
+
+utf8str:
+ /*
+ * No need to recheck from the start, just from the first utf8 charu
+ * found. Note that the callback of ldb_casefold() needs to be ascii
+ * compatible.
+ */
+ b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
+ b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
+
+ if (!b1 || !b2) {
+ /* One of the strings was not UTF8, so we have no
+ * options but to do a binary compare */
+ talloc_free(b1);
+ talloc_free(b2);
+ ret = memcmp(s1, s2, MIN(n1, n2));
+ if (ret == 0) {
+ if (n1 == n2) return 0;
+ if (n1 > n2) {
+ return (int)ldb_ascii_toupper(s1[n2]);
+ } else {
+ return -(int)ldb_ascii_toupper(s2[n1]);
+ }
+ }
+ return ret;
+ }
+
+ u1 = b1;
+ u2 = b2;
+
+ while (*u1 & *u2) {
+ if (*u1 != *u2)
+ break;
+ if (*u1 == ' ') {
+ while (u1[0] == u1[1]) u1++;
+ while (u2[0] == u2[1]) u2++;
+ }
+ u1++; u2++;
+ }
+ if (! (*u1 && *u2)) {
+ while (*u1 == ' ') u1++;
+ while (*u2 == ' ') u2++;
+ }
+ ret = (int)(*u1 - *u2);
+
+ talloc_free(b1);
+ talloc_free(b2);
+
+ return ret;
+}
+
+
+/*
+ canonicalise a attribute in DN format
+*/
+static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct ldb_dn *dn;
+ int ret = -1;
+
+ out->length = 0;
+ out->data = NULL;
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
+ if ( ! ldb_dn_validate(dn)) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
+ if (out->data == NULL) {
+ goto done;
+ }
+ out->length = strlen((char *)out->data);
+
+ ret = 0;
+
+done:
+ talloc_free(dn);
+
+ return ret;
+}
+
+/*
+ compare two dns
+*/
+static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ struct ldb_dn *dn1 = NULL, *dn2 = NULL;
+ int ret;
+
+ dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
+ if ( ! ldb_dn_validate(dn1)) return -1;
+
+ dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
+ if ( ! ldb_dn_validate(dn2)) {
+ talloc_free(dn1);
+ return -1;
+ }
+
+ ret = ldb_dn_compare(dn1, dn2);
+
+ talloc_free(dn1);
+ talloc_free(dn2);
+ return ret;
+}
+
+/*
+ compare two utc time values. 1 second resolution
+*/
+static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ time_t t1=0, t2=0;
+ ldb_val_to_time(v1, &t1);
+ ldb_val_to_time(v2, &t2);
+ if (t1 == t2) return 0;
+ return t1 > t2? 1 : -1;
+}
+
+/*
+ canonicalise a utc time
+*/
+static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ time_t t;
+ int ret;
+ ret = ldb_val_to_time(in, &t);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ out->data = (uint8_t *)ldb_timestring_utc(mem_ctx, t);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/*
+ canonicalise a generalized time
+*/
+static int ldb_canonicalise_generalizedtime(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ time_t t;
+ int ret;
+ ret = ldb_val_to_time(in, &t);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
+ if (out->data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ out->length = strlen((char *)out->data);
+ return 0;
+}
+
+/*
+ table of standard attribute handlers
+*/
+static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
+ {
+ .name = LDB_SYNTAX_INTEGER,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_Integer,
+ .comparison_fn = ldb_comparison_Integer
+ },
+ {
+ .name = LDB_SYNTAX_ORDERED_INTEGER,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_Integer,
+ .index_format_fn = ldb_index_format_Integer,
+ .comparison_fn = ldb_comparison_Integer
+ },
+ {
+ .name = LDB_SYNTAX_OCTET_STRING,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = ldb_comparison_binary
+ },
+ {
+ .name = LDB_SYNTAX_DIRECTORY_STRING,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_fold,
+ .comparison_fn = ldb_comparison_fold
+ },
+ {
+ .name = LDB_SYNTAX_DN,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_dn,
+ .comparison_fn = ldb_comparison_dn
+ },
+ {
+ .name = LDB_SYNTAX_OBJECTCLASS,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_fold,
+ .comparison_fn = ldb_comparison_fold
+ },
+ {
+ .name = LDB_SYNTAX_UTC_TIME,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_utctime,
+ .comparison_fn = ldb_comparison_utctime
+ },
+ {
+ .name = LDB_SYNTAX_GENERALIZED_TIME,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_generalizedtime,
+ .comparison_fn = ldb_comparison_utctime
+ },
+ {
+ .name = LDB_SYNTAX_BOOLEAN,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_canonicalise_Boolean,
+ .comparison_fn = ldb_comparison_Boolean
+ },
+};
+
+
+/*
+ return the attribute handlers for a given syntax name
+*/
+const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
+ const char *syntax)
+{
+ unsigned int i;
+ unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
+ /* TODO: should be replaced with a binary search */
+ for (i=0;i<num_handlers;i++) {
+ if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
+ return &ldb_standard_syntaxes[i];
+ }
+ }
+ return NULL;
+}
+
+int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
+ ldb_attr_handler_t canonicalise_fn,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ int ret, ret1, ret2;
+ struct ldb_val v1_canon, v2_canon;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+ /* I could try and bail if tmp_ctx was NULL, but what return
+ * value would I use?
+ *
+ * It seems easier to continue on the NULL context
+ */
+ ret1 = canonicalise_fn(ldb, tmp_ctx, v1, &v1_canon);
+ ret2 = canonicalise_fn(ldb, tmp_ctx, v2, &v2_canon);
+
+ if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
+ ret = ldb_comparison_binary(ldb, mem_ctx, &v1_canon, &v2_canon);
+ } else {
+ ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/lib/ldb/common/ldb.c b/lib/ldb/common/ldb.c
new file mode 100644
index 0000000..c1c33d8
--- /dev/null
+++ b/lib/ldb/common/ldb.c
@@ -0,0 +1,2204 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Simo Sorce 2005-2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb core API
+ *
+ * Description: core API routines interfacing to ldb backends
+ *
+ * Author: Andrew Tridgell
+ */
+
+#define TEVENT_DEPRECATED 1
+#include "ldb_private.h"
+#include "ldb.h"
+
+static int ldb_context_destructor(void *ptr)
+{
+ struct ldb_context *ldb = talloc_get_type(ptr, struct ldb_context);
+
+ if (ldb->transaction_active) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "A transaction is still active in ldb context [%p] on %s",
+ ldb, (const char *)ldb_get_opaque(ldb, "ldb_url"));
+ }
+
+ return 0;
+}
+
+/*
+ this is used to catch debug messages from events
+*/
+static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+
+static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
+ const char *fmt, va_list ap)
+{
+ struct ldb_context *ldb = talloc_get_type(context, struct ldb_context);
+ enum ldb_debug_level ldb_level = LDB_DEBUG_FATAL;
+
+ switch (level) {
+ case TEVENT_DEBUG_FATAL:
+ ldb_level = LDB_DEBUG_FATAL;
+ break;
+ case TEVENT_DEBUG_ERROR:
+ ldb_level = LDB_DEBUG_ERROR;
+ break;
+ case TEVENT_DEBUG_WARNING:
+ ldb_level = LDB_DEBUG_WARNING;
+ break;
+ case TEVENT_DEBUG_TRACE:
+ ldb_level = LDB_DEBUG_TRACE;
+ break;
+ };
+
+ /* There isn't a tevent: prefix here because to add it means
+ * actually printing the string, and most of the time we don't
+ * want to show it */
+ ldb_vdebug(ldb, ldb_level, fmt, ap);
+}
+
+/*
+ initialise a ldb context
+ The mem_ctx is required
+ The event_ctx is required
+*/
+struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx)
+{
+ struct ldb_context *ldb;
+ int ret;
+ const char *modules_path = getenv("LDB_MODULES_PATH");
+
+ if (modules_path == NULL) {
+ modules_path = LDB_MODULESDIR;
+ }
+
+ ret = ldb_modules_load(modules_path, LDB_VERSION);
+ if (ret != LDB_SUCCESS) {
+ return NULL;
+ }
+
+ ldb = talloc_zero(mem_ctx, struct ldb_context);
+ if (ldb == NULL) {
+ return NULL;
+ }
+
+ /* A new event context so that callers who don't want ldb
+ * operating on their global event context can work without
+ * having to provide their own private one explicitly */
+ if (ev_ctx == NULL) {
+ ev_ctx = tevent_context_init(ldb);
+ if (ev_ctx == NULL) {
+ talloc_free(ldb);
+ return NULL;
+ }
+ tevent_set_debug(ev_ctx, ldb_tevent_debug, ldb);
+ tevent_set_max_debug_level(ev_ctx, TEVENT_DEBUG_TRACE);
+ tevent_loop_allow_nesting(ev_ctx);
+ }
+
+ ret = ldb_setup_wellknown_attributes(ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ ldb_set_utf8_default(ldb);
+ ldb_set_create_perms(ldb, 0666);
+ ldb_set_modules_dir(ldb, LDB_MODULESDIR);
+ ldb_set_event_context(ldb, ev_ctx);
+ ret = ldb_register_extended_match_rules(ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ /* TODO: get timeout from options if available there */
+ ldb->default_timeout = 300; /* set default to 5 minutes */
+
+ talloc_set_destructor((TALLOC_CTX *)ldb, ldb_context_destructor);
+
+ return ldb;
+}
+
+/*
+ try to autodetect a basedn if none specified. This fixes one of my
+ pet hates about ldapsearch, which is that you have to get a long,
+ complex basedn right to make any use of it.
+*/
+void ldb_set_default_dns(struct ldb_context *ldb)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_result *res;
+ struct ldb_dn *tmp_dn=NULL;
+ static const char *attrs[] = {
+ "rootDomainNamingContext",
+ "configurationNamingContext",
+ "schemaNamingContext",
+ "defaultNamingContext",
+ NULL
+ };
+
+ tmp_ctx = talloc_new(ldb);
+ ret = ldb_search(ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, ldb, NULL),
+ LDB_SCOPE_BASE, attrs, "(objectClass=*)");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ if (res->count != 1) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ if (!ldb_get_opaque(ldb, "rootDomainNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "rootDomainNamingContext");
+ ldb_set_opaque(ldb, "rootDomainNamingContext", tmp_dn);
+ }
+
+ if (!ldb_get_opaque(ldb, "configurationNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "configurationNamingContext");
+ ldb_set_opaque(ldb, "configurationNamingContext", tmp_dn);
+ }
+
+ if (!ldb_get_opaque(ldb, "schemaNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "schemaNamingContext");
+ ldb_set_opaque(ldb, "schemaNamingContext", tmp_dn);
+ }
+
+ if (!ldb_get_opaque(ldb, "defaultNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "defaultNamingContext");
+ ldb_set_opaque(ldb, "defaultNamingContext", tmp_dn);
+ }
+
+ talloc_free(tmp_ctx);
+}
+
+struct ldb_dn *ldb_get_root_basedn(struct ldb_context *ldb)
+{
+ void *opaque = ldb_get_opaque(ldb, "rootDomainNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
+}
+
+struct ldb_dn *ldb_get_config_basedn(struct ldb_context *ldb)
+{
+ void *opaque = ldb_get_opaque(ldb, "configurationNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
+}
+
+struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb)
+{
+ void *opaque = ldb_get_opaque(ldb, "schemaNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
+}
+
+struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb)
+{
+ void *opaque = ldb_get_opaque(ldb, "defaultNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
+}
+
+/*
+ connect to a database. The URL can either be one of the following forms
+ ldb://path
+ ldapi://path
+
+ flags is made up of LDB_FLG_*
+
+ the options are passed uninterpreted to the backend, and are
+ backend specific
+*/
+int ldb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[])
+{
+ int ret;
+ char *url2;
+ /* We seem to need to do this here, or else some utilities don't
+ * get ldb backends */
+
+ ldb->flags = flags;
+
+ url2 = talloc_strdup(ldb, url);
+ if (!url2) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_set_opaque(ldb, "ldb_url", url2);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /*
+ * Take a copy of the options.
+ */
+ ldb->options = ldb_options_copy(ldb, options);
+ if (ldb->options == NULL && options != NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_module_connect_backend(ldb, url, options, &ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_load_modules(ldb, options);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "Unable to load modules for %s: %s",
+ url, ldb_errstring(ldb));
+ return ret;
+ }
+
+ /* set the default base dn */
+ ldb_set_default_dns(ldb);
+
+ return LDB_SUCCESS;
+}
+
+void ldb_set_errstring(struct ldb_context *ldb, const char *err_string)
+{
+ ldb_asprintf_errstring(ldb, "%s", err_string);
+}
+
+void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...)
+{
+ va_list ap;
+ char *old_err_string = NULL;
+ if (ldb->err_string) {
+ old_err_string = ldb->err_string;
+ }
+
+ va_start(ap, format);
+ ldb->err_string = talloc_vasprintf(ldb, format, ap);
+ va_end(ap);
+
+ TALLOC_FREE(old_err_string);
+
+ if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_asprintf/set_errstring: %s",
+ ldb->err_string);
+ }
+}
+
+void ldb_reset_err_string(struct ldb_context *ldb)
+{
+ TALLOC_FREE(ldb->err_string);
+}
+
+
+
+/*
+ set an ldb error based on file:line
+*/
+int ldb_error_at(struct ldb_context *ldb, int ecode,
+ const char *reason, const char *file, int line)
+{
+ if (reason == NULL) {
+ reason = ldb_strerror(ecode);
+ }
+ ldb_asprintf_errstring(ldb, "%s at %s:%d", reason, file, line);
+ return ecode;
+}
+
+
+#define FIRST_OP_NOERR(ldb, op) do { \
+ next_module = ldb->modules; \
+ while (next_module && next_module->ops->op == NULL) { \
+ next_module = next_module->next; \
+ }; \
+ if ((ldb->flags & LDB_FLG_ENABLE_TRACING) && next_module) { \
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_trace_request: (%s)->" #op, \
+ next_module->ops->name); \
+ } \
+} while (0)
+
+#define FIRST_OP(ldb, op) do { \
+ FIRST_OP_NOERR(ldb, op); \
+ if (next_module == NULL) { \
+ ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \
+ return LDB_ERR_OPERATIONS_ERROR; \
+ } \
+} while (0)
+
+
+/*
+ start a transaction
+*/
+int ldb_transaction_start(struct ldb_context *ldb)
+{
+ struct ldb_module *next_module;
+ int status;
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "start ldb transaction (nesting: %d)",
+ ldb->transaction_active);
+
+ /* explicit transaction active, count nested requests */
+ if (ldb->transaction_active) {
+ ldb->transaction_active++;
+ return LDB_SUCCESS;
+ }
+
+ /* start a new transaction */
+ ldb->transaction_active++;
+ ldb->prepare_commit_done = false;
+
+ FIRST_OP(ldb, start_transaction);
+
+ ldb_reset_err_string(ldb);
+
+ status = next_module->ops->start_transaction(next_module);
+ if (status != LDB_SUCCESS) {
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction start: %s (%d)",
+ ldb_strerror(status),
+ status);
+ ldb->transaction_active--;
+ }
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "start ldb transaction error: %s",
+ ldb_errstring(next_module->ldb));
+ }
+ } else {
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "start ldb transaction success");
+ }
+ }
+ return status;
+}
+
+/*
+ prepare for transaction commit (first phase of two phase commit)
+*/
+int ldb_transaction_prepare_commit(struct ldb_context *ldb)
+{
+ struct ldb_module *next_module;
+ int status;
+
+ if (ldb->prepare_commit_done) {
+ return LDB_SUCCESS;
+ }
+
+ /* commit only when all nested transactions are complete */
+ if (ldb->transaction_active > 1) {
+ return LDB_SUCCESS;
+ }
+
+ ldb->prepare_commit_done = true;
+
+ if (ldb->transaction_active < 0) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "prepare commit called but no ldb transactions are active!");
+ ldb->transaction_active = 0;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* call prepare transaction if available */
+ FIRST_OP_NOERR(ldb, prepare_commit);
+ if (next_module == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ ldb_reset_err_string(ldb);
+
+ status = next_module->ops->prepare_commit(next_module);
+ if (status != LDB_SUCCESS) {
+ ldb->transaction_active--;
+ /* if a next_module fails the prepare then we need
+ to call the end transaction for everyone */
+ FIRST_OP(ldb, del_transaction);
+ next_module->ops->del_transaction(next_module);
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction prepare commit: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "prepare commit transaction error: %s",
+ ldb_errstring(next_module->ldb));
+ }
+ }
+
+ return status;
+}
+
+
+/*
+ commit a transaction
+*/
+int ldb_transaction_commit(struct ldb_context *ldb)
+{
+ struct ldb_module *next_module;
+ int status;
+
+ status = ldb_transaction_prepare_commit(ldb);
+ if (status != LDB_SUCCESS) {
+ return status;
+ }
+
+ ldb->transaction_active--;
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "commit ldb transaction (nesting: %d)",
+ ldb->transaction_active);
+
+ /* commit only when all nested transactions are complete */
+ if (ldb->transaction_active > 0) {
+ return LDB_SUCCESS;
+ }
+
+ if (ldb->transaction_active < 0) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "commit called but no ldb transactions are active!");
+ ldb->transaction_active = 0;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_reset_err_string(ldb);
+
+ FIRST_OP(ldb, end_transaction);
+ status = next_module->ops->end_transaction(next_module);
+ if (status != LDB_SUCCESS) {
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction commit: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "commit ldb transaction error: %s",
+ ldb_errstring(next_module->ldb));
+ }
+ }
+ return status;
+}
+
+
+/*
+ cancel a transaction
+*/
+int ldb_transaction_cancel(struct ldb_context *ldb)
+{
+ struct ldb_module *next_module;
+ int status;
+
+ ldb->transaction_active--;
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "cancel ldb transaction (nesting: %d)",
+ ldb->transaction_active);
+
+ /* really cancel only if all nested transactions are complete */
+ if (ldb->transaction_active > 0) {
+ return LDB_SUCCESS;
+ }
+
+ if (ldb->transaction_active < 0) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "cancel called but no ldb transactions are active!");
+ ldb->transaction_active = 0;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ FIRST_OP(ldb, del_transaction);
+
+ status = next_module->ops->del_transaction(next_module);
+ if (status != LDB_SUCCESS) {
+ if (ldb->err_string == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction cancel: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ if ((next_module && next_module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(next_module->ldb, LDB_DEBUG_TRACE, "cancel ldb transaction error: %s",
+ ldb_errstring(next_module->ldb));
+ }
+ }
+ return status;
+}
+
+/*
+ cancel a transaction with no error if no transaction is pending
+ used when we fork() to clear any parent transactions
+*/
+int ldb_transaction_cancel_noerr(struct ldb_context *ldb)
+{
+ if (ldb->transaction_active > 0) {
+ return ldb_transaction_cancel(ldb);
+ }
+ return LDB_SUCCESS;
+}
+
+
+/* autostarts a transaction if none active */
+static int ldb_autotransaction_request(struct ldb_context *ldb,
+ struct ldb_request *req)
+{
+ int ret;
+
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_request(ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ return ldb_transaction_commit(ldb);
+ }
+ ldb_transaction_cancel(ldb);
+
+ return ret;
+}
+
+int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ if (handle == NULL) {
+ return LDB_ERR_UNAVAILABLE;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ if ((handle->status != LDB_SUCCESS) &&
+ (handle->ldb->err_string == NULL)) {
+ /* if no error string was setup by the backend */
+ ldb_asprintf_errstring(handle->ldb,
+ "ldb_wait from %s with LDB_ASYNC_DONE: %s (%d)",
+ handle->location,
+ ldb_strerror(handle->status),
+ handle->status);
+ }
+ return handle->status;
+ }
+
+ ev = ldb_handle_get_event_context(handle);
+ if (NULL == ev) {
+ return ldb_oom(handle->ldb);
+ }
+
+ switch (type) {
+ case LDB_WAIT_NONE:
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ return ldb_operr(handle->ldb);
+ }
+ if (handle->status == LDB_SUCCESS) {
+ return LDB_SUCCESS;
+ }
+ if (handle->ldb->err_string != NULL) {
+ return handle->status;
+ }
+ /*
+ * if no error string was setup by the backend
+ */
+ ldb_asprintf_errstring(handle->ldb,
+ "ldb_wait from %s with LDB_WAIT_NONE: %s (%d)",
+ handle->location,
+ ldb_strerror(handle->status),
+ handle->status);
+ return handle->status;
+
+ case LDB_WAIT_ALL:
+ while (handle->state != LDB_ASYNC_DONE) {
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ return ldb_operr(handle->ldb);
+ }
+ if (handle->status != LDB_SUCCESS) {
+ if (handle->ldb->err_string != NULL) {
+ return handle->status;
+ }
+ /*
+ * if no error string was setup by the
+ * backend
+ */
+ ldb_asprintf_errstring(handle->ldb,
+ "ldb_wait from %s with "
+ "LDB_WAIT_ALL: %s (%d)",
+ handle->location,
+ ldb_strerror(handle->status),
+ handle->status);
+ return handle->status;
+ }
+ }
+ if (handle->status == LDB_SUCCESS) {
+ return LDB_SUCCESS;
+ }
+ if (handle->ldb->err_string != NULL) {
+ return handle->status;
+ }
+ /*
+ * if no error string was setup by the backend
+ */
+ ldb_asprintf_errstring(handle->ldb,
+ "ldb_wait from %s with LDB_WAIT_ALL,"
+ " LDB_ASYNC_DONE: %s (%d)",
+ handle->location,
+ ldb_strerror(handle->status),
+ handle->status);
+ return handle->status;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* set the specified timeout or, if timeout is 0 set the default timeout */
+int ldb_set_timeout(struct ldb_context *ldb,
+ struct ldb_request *req,
+ int timeout)
+{
+ if (req == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ if (timeout != 0) {
+ req->timeout = timeout;
+ } else {
+ req->timeout = ldb->default_timeout;
+ }
+ req->starttime = time(NULL);
+
+ return LDB_SUCCESS;
+}
+
+/* calculates the new timeout based on the previous starttime and timeout */
+int ldb_set_timeout_from_prev_req(struct ldb_context *ldb,
+ struct ldb_request *oldreq,
+ struct ldb_request *newreq)
+{
+ if (newreq == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ if (oldreq == NULL) {
+ return ldb_set_timeout(ldb, newreq, 0);
+ }
+
+ newreq->starttime = oldreq->starttime;
+ newreq->timeout = oldreq->timeout;
+
+ return LDB_SUCCESS;
+}
+
+
+struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb)
+{
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return NULL;
+ }
+
+ h->status = LDB_SUCCESS;
+ h->state = LDB_ASYNC_INIT;
+ h->ldb = ldb;
+ h->flags = 0;
+ h->location = NULL;
+ h->parent = NULL;
+
+ if (h->ldb->require_private_event_context == true) {
+ h->event_context = tevent_context_init(h);
+ if (h->event_context == NULL) {
+ ldb_set_errstring(ldb,
+ "Out of Memory allocating "
+ "event context for new handle");
+ return NULL;
+ }
+ tevent_set_debug(h->event_context, ldb_tevent_debug, ldb);
+ tevent_set_max_debug_level(h->event_context, TEVENT_DEBUG_TRACE);
+ tevent_loop_allow_nesting(h->event_context);
+ }
+
+ return h;
+}
+
+static struct ldb_handle *ldb_handle_new_child(TALLOC_CTX *mem_ctx,
+ struct ldb_request *parent_req)
+{
+ struct ldb_handle *h;
+
+ h = talloc_zero(mem_ctx, struct ldb_handle);
+ if (h == NULL) {
+ ldb_set_errstring(parent_req->handle->ldb,
+ "Out of Memory");
+ return NULL;
+ }
+
+ h->status = LDB_SUCCESS;
+ h->state = LDB_ASYNC_INIT;
+ h->ldb = parent_req->handle->ldb;
+ h->parent = parent_req;
+ h->nesting = parent_req->handle->nesting + 1;
+ h->flags = parent_req->handle->flags;
+ h->custom_flags = parent_req->handle->custom_flags;
+ h->event_context = parent_req->handle->event_context;
+
+ return h;
+}
+
+/*
+ set the permissions for new files to be passed to open() in
+ backends that use local files
+ */
+void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms)
+{
+ ldb->create_perms = perms;
+}
+
+unsigned int ldb_get_create_perms(struct ldb_context *ldb)
+{
+ return ldb->create_perms;
+}
+
+void ldb_set_event_context(struct ldb_context *ldb, struct tevent_context *ev)
+{
+ ldb->ev_ctx = ev;
+}
+
+struct tevent_context * ldb_get_event_context(struct ldb_context *ldb)
+{
+ return ldb->ev_ctx;
+}
+
+void ldb_request_set_state(struct ldb_request *req, int state)
+{
+ req->handle->state = state;
+}
+
+int ldb_request_get_status(struct ldb_request *req)
+{
+ return req->handle->status;
+}
+
+/*
+ * This function obtains the private event context for the handle,
+ * which may have been created to avoid nested event loops during
+ * ldb_tdb with the locks held
+ */
+struct tevent_context *ldb_handle_get_event_context(struct ldb_handle *handle)
+{
+ if (handle->event_context != NULL) {
+ return handle->event_context;
+ }
+ return ldb_get_event_context(handle->ldb);
+}
+
+/*
+ * This function forces a specific ldb handle to use the global event
+ * context. This allows a nested event loop to operate, so any open
+ * transaction also needs to be aborted.
+ *
+ * Any events on this event context will be lost
+ *
+ * This is used in Samba when sending an IRPC to another part of the
+ * same process instead of making a local DB modification.
+ */
+void ldb_handle_use_global_event_context(struct ldb_handle *handle)
+{
+ TALLOC_FREE(handle->event_context);
+}
+
+void ldb_set_require_private_event_context(struct ldb_context *ldb)
+{
+ ldb->require_private_event_context = true;
+}
+
+/*
+ trace a ldb request
+*/
+static void ldb_trace_request(struct ldb_context *ldb, struct ldb_request *req)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(req);
+ unsigned int i;
+ struct ldb_ldif ldif;
+
+ switch (req->operation) {
+ case LDB_SEARCH:
+ ldb_debug_add(ldb, "ldb_trace_request: SEARCH\n");
+ ldb_debug_add(ldb, " dn: %s\n",
+ ldb_dn_is_null(req->op.search.base)?"<rootDSE>":
+ ldb_dn_get_linearized(req->op.search.base));
+ ldb_debug_add(ldb, " scope: %s\n",
+ req->op.search.scope==LDB_SCOPE_BASE?"base":
+ req->op.search.scope==LDB_SCOPE_ONELEVEL?"one":
+ req->op.search.scope==LDB_SCOPE_SUBTREE?"sub":"UNKNOWN");
+ ldb_debug_add(ldb, " expr: %s\n",
+ ldb_filter_from_tree(tmp_ctx, req->op.search.tree));
+ if (req->op.search.attrs == NULL) {
+ ldb_debug_add(ldb, " attr: <ALL>\n");
+ } else {
+ for (i=0; req->op.search.attrs[i]; i++) {
+ ldb_debug_add(ldb, " attr: %s\n", req->op.search.attrs[i]);
+ }
+ }
+ break;
+ case LDB_DELETE:
+ ldb_debug_add(ldb, "ldb_trace_request: DELETE\n");
+ ldb_debug_add(ldb, " dn: %s\n",
+ ldb_dn_get_linearized(req->op.del.dn));
+ break;
+ case LDB_RENAME:
+ ldb_debug_add(ldb, "ldb_trace_request: RENAME\n");
+ ldb_debug_add(ldb, " olddn: %s\n",
+ ldb_dn_get_linearized(req->op.rename.olddn));
+ ldb_debug_add(ldb, " newdn: %s\n",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ break;
+ case LDB_EXTENDED:
+ ldb_debug_add(ldb, "ldb_trace_request: EXTENDED\n");
+ ldb_debug_add(ldb, " oid: %s\n", req->op.extended.oid);
+ ldb_debug_add(ldb, " data: %s\n", req->op.extended.data?"yes":"no");
+ break;
+ case LDB_ADD:
+ ldif.changetype = LDB_CHANGETYPE_ADD;
+ ldif.msg = discard_const_p(struct ldb_message, req->op.add.message);
+
+ ldb_debug_add(ldb, "ldb_trace_request: ADD\n");
+
+ /*
+ * The choice to call
+ * ldb_ldif_write_redacted_trace_string() is CRITICAL
+ * for security. It ensures that we do not output
+ * passwords into debug logs
+ */
+
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ ldb_ldif_write_redacted_trace_string(req->handle->ldb, tmp_ctx, &ldif));
+ break;
+ case LDB_MODIFY:
+ ldif.changetype = LDB_CHANGETYPE_MODIFY;
+ ldif.msg = discard_const_p(struct ldb_message, req->op.mod.message);
+
+ ldb_debug_add(ldb, "ldb_trace_request: MODIFY\n");
+
+ /*
+ * The choice to call
+ * ldb_ldif_write_redacted_trace_string() is CRITICAL
+ * for security. It ensures that we do not output
+ * passwords into debug logs
+ */
+
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ ldb_ldif_write_redacted_trace_string(req->handle->ldb, tmp_ctx, &ldif));
+ break;
+ case LDB_REQ_REGISTER_CONTROL:
+ ldb_debug_add(ldb, "ldb_trace_request: REGISTER_CONTROL\n");
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ req->op.reg_control.oid);
+ break;
+ case LDB_REQ_REGISTER_PARTITION:
+ ldb_debug_add(ldb, "ldb_trace_request: REGISTER_PARTITION\n");
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ ldb_dn_get_linearized(req->op.reg_partition.dn));
+ break;
+ default:
+ ldb_debug_add(ldb, "ldb_trace_request: UNKNOWN(%u)\n",
+ req->operation);
+ break;
+ }
+
+ if (req->controls == NULL) {
+ ldb_debug_add(ldb, " control: <NONE>\n");
+ } else {
+ for (i=0; req->controls && req->controls[i]; i++) {
+ if (req->controls[i]->oid) {
+ ldb_debug_add(ldb, " control: %s crit:%u data:%s\n",
+ req->controls[i]->oid,
+ req->controls[i]->critical,
+ req->controls[i]->data?"yes":"no");
+ }
+ }
+ }
+
+ ldb_debug_end(ldb, LDB_DEBUG_TRACE);
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ check that the element flags don't have any internal bits set
+ */
+static int ldb_msg_check_element_flags(struct ldb_context *ldb,
+ const struct ldb_message *message)
+{
+ unsigned i;
+ for (i=0; i<message->num_elements; i++) {
+ if (message->elements[i].flags & LDB_FLAG_INTERNAL_MASK) {
+ ldb_asprintf_errstring(ldb, "Invalid element flags 0x%08x on element %s in %s\n",
+ message->elements[i].flags, message->elements[i].name,
+ ldb_dn_get_linearized(message->dn));
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ * This context allows us to make the unlock be a talloc destructor
+ *
+ * This ensures that a request started, but not waited on, will still
+ * unlock.
+ */
+struct ldb_db_lock_context {
+ struct ldb_request *req;
+ struct ldb_context *ldb;
+};
+
+/*
+ * We have to have the unlock on a destructor so that we unlock the
+ * DB if a caller calls talloc_free(req). We trust that the ldb
+ * context has not already gone away.
+ */
+static int ldb_db_lock_destructor(struct ldb_db_lock_context *lock_context)
+{
+ int ret;
+ struct ldb_module *next_module;
+ FIRST_OP_NOERR(lock_context->ldb, read_unlock);
+ if (next_module != NULL) {
+ ret = next_module->ops->read_unlock(next_module);
+ } else {
+ ret = LDB_SUCCESS;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(lock_context->ldb,
+ LDB_DEBUG_FATAL,
+ "Failed to unlock db: %s / %s",
+ ldb_errstring(lock_context->ldb),
+ ldb_strerror(ret));
+ }
+ return 0;
+}
+
+static int ldb_lock_backend_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_db_lock_context *lock_context;
+ int ret;
+
+ if (req->context == NULL) {
+ /*
+ * The usual way to get here is to ignore the return codes
+ * and continuing processing after an error.
+ */
+ abort();
+ }
+ lock_context = talloc_get_type(req->context,
+ struct ldb_db_lock_context);
+
+ if (!ares) {
+ return ldb_module_done(lock_context->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS || ares->type == LDB_REPLY_DONE) {
+ ret = ldb_module_done(lock_context->req, ares->controls,
+ ares->response, ares->error);
+ /*
+ * If this is a LDB_REPLY_DONE or an error, unlock the
+ * DB by calling the destructor on this context
+ */
+ TALLOC_FREE(req->context);
+ return ret;
+ }
+
+ /* Otherwise pass on the callback */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ return ldb_module_send_entry(lock_context->req, ares->message,
+ ares->controls);
+
+ case LDB_REPLY_REFERRAL:
+ return ldb_module_send_referral(lock_context->req,
+ ares->referral);
+ default:
+ /* Can't happen */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+}
+
+/*
+ * Do an ldb_search() with a lock held, but release it if the request
+ * is freed with talloc_free()
+ */
+static int lock_search(struct ldb_module *lock_module, struct ldb_request *req)
+{
+ /* Used in FIRST_OP_NOERR to find where to send the lock request */
+ struct ldb_module *next_module = NULL;
+ struct ldb_request *down_req = NULL;
+ struct ldb_db_lock_context *lock_context;
+ struct ldb_context *ldb = ldb_module_get_ctx(lock_module);
+ int ret;
+
+ lock_context = talloc(req, struct ldb_db_lock_context);
+ if (lock_context == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ lock_context->ldb = ldb;
+ lock_context->req = req;
+
+ ret = ldb_build_search_req_ex(&down_req, ldb, req,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ req->op.search.attrs,
+ req->controls,
+ lock_context,
+ ldb_lock_backend_callback,
+ req);
+ LDB_REQ_SET_LOCATION(down_req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* call DB lock */
+ FIRST_OP_NOERR(ldb, read_lock);
+ if (next_module != NULL) {
+ ret = next_module->ops->read_lock(next_module);
+ } else {
+ ret = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
+ if (ret == LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION) {
+ /* We might be talking LDAP */
+ ldb_reset_err_string(ldb);
+ TALLOC_FREE(lock_context);
+
+ return ldb_next_request(lock_module, req);
+ } else if ((ret != LDB_SUCCESS) && (ldb->err_string == NULL)) {
+ /* if no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb, "Failed to get DB lock: %s (%d)",
+ ldb_strerror(ret), ret);
+ } else {
+ talloc_set_destructor(lock_context, ldb_db_lock_destructor);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return ldb_next_request(lock_module, down_req);
+}
+
+/*
+ start an ldb request
+ NOTE: the request must be a talloc context.
+ returns LDB_ERR_* on errors.
+*/
+int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
+{
+ struct ldb_module *next_module;
+ int ret;
+
+ if (req->callback == NULL) {
+ ldb_set_errstring(ldb, "Requests MUST define callbacks");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ ldb_reset_err_string(ldb);
+
+ if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
+ ldb_trace_request(ldb, req);
+ }
+
+ /* call the first module in the chain */
+ switch (req->operation) {
+ case LDB_SEARCH:
+ {
+ /*
+ * A fake module to allow ldb_next_request() to be
+ * re-used and to keep the locking out of this function.
+ */
+ static const struct ldb_module_ops lock_module_ops = {
+ .name = "lock_searches",
+ .search = lock_search
+ };
+ struct ldb_module lock_module = {
+ .ldb = ldb,
+ .next = ldb->modules,
+ .ops = &lock_module_ops
+ };
+ next_module = &lock_module;
+
+ /* due to "ldb_build_search_req" base DN always != NULL */
+ if (!ldb_dn_validate(req->op.search.base)) {
+ ldb_asprintf_errstring(ldb, "ldb_search: invalid basedn '%s'",
+ ldb_dn_get_linearized(req->op.search.base));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ ret = next_module->ops->search(next_module, req);
+ break;
+ }
+ case LDB_ADD:
+ if (!ldb_dn_validate(req->op.add.message->dn)) {
+ ldb_asprintf_errstring(ldb, "ldb_add: invalid dn '%s'",
+ ldb_dn_get_linearized(req->op.add.message->dn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ /*
+ * we have to normalize here, as so many places
+ * in modules and backends assume we don't have two
+ * elements with the same name
+ */
+ ret = ldb_msg_normalize(ldb, req, req->op.add.message,
+ discard_const(&req->op.add.message));
+ if (ret != LDB_SUCCESS) {
+ ldb_oom(ldb);
+ return ret;
+ }
+ FIRST_OP(ldb, add);
+ ret = ldb_msg_check_element_flags(ldb, req->op.add.message);
+ if (ret != LDB_SUCCESS) {
+ /*
+ * "ldb_msg_check_element_flags" generates an error
+ * string
+ */
+ return ret;
+ }
+ ret = next_module->ops->add(next_module, req);
+ break;
+ case LDB_MODIFY:
+ if (!ldb_dn_validate(req->op.mod.message->dn)) {
+ ldb_asprintf_errstring(ldb, "ldb_modify: invalid dn '%s'",
+ ldb_dn_get_linearized(req->op.mod.message->dn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ FIRST_OP(ldb, modify);
+ ret = ldb_msg_check_element_flags(ldb, req->op.mod.message);
+ if (ret != LDB_SUCCESS) {
+ /*
+ * "ldb_msg_check_element_flags" generates an error
+ * string
+ */
+ return ret;
+ }
+ ret = next_module->ops->modify(next_module, req);
+ break;
+ case LDB_DELETE:
+ if (!ldb_dn_validate(req->op.del.dn)) {
+ ldb_asprintf_errstring(ldb, "ldb_delete: invalid dn '%s'",
+ ldb_dn_get_linearized(req->op.del.dn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ FIRST_OP(ldb, del);
+ ret = next_module->ops->del(next_module, req);
+ break;
+ case LDB_RENAME:
+ if (!ldb_dn_validate(req->op.rename.olddn)) {
+ ldb_asprintf_errstring(ldb, "ldb_rename: invalid olddn '%s'",
+ ldb_dn_get_linearized(req->op.rename.olddn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ if (!ldb_dn_validate(req->op.rename.newdn)) {
+ ldb_asprintf_errstring(ldb, "ldb_rename: invalid newdn '%s'",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ FIRST_OP(ldb, rename);
+ ret = next_module->ops->rename(next_module, req);
+ break;
+ case LDB_EXTENDED:
+ FIRST_OP(ldb, extended);
+ ret = next_module->ops->extended(next_module, req);
+ break;
+ default:
+ FIRST_OP(ldb, request);
+ ret = next_module->ops->request(next_module, req);
+ break;
+ }
+
+ if ((ret != LDB_SUCCESS) && (ldb->err_string == NULL)) {
+ /* if no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb, "ldb_request: %s (%d)",
+ ldb_strerror(ret), ret);
+ }
+
+ return ret;
+}
+
+int ldb_request_done(struct ldb_request *req, int status)
+{
+ req->handle->state = LDB_ASYNC_DONE;
+ req->handle->status = status;
+ return status;
+}
+
+/*
+ search the database given a LDAP-like search expression
+
+ returns an LDB error code
+
+ Use talloc_free to free the ldb_message returned in 'res', if successful
+
+*/
+int ldb_search_default_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_result *res;
+ unsigned int n;
+
+ res = talloc_get_type(req->context, struct ldb_result);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ res->msgs = talloc_realloc(res, res->msgs,
+ struct ldb_message *, res->count + 2);
+ if (! res->msgs) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ res->msgs[res->count + 1] = NULL;
+
+ res->msgs[res->count] = talloc_move(res->msgs, &ares->message);
+ res->count++;
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ if (res->refs) {
+ for (n = 0; res->refs[n]; n++) /*noop*/ ;
+ } else {
+ n = 0;
+ }
+
+ res->refs = talloc_realloc(res, res->refs, char *, n + 2);
+ if (! res->refs) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ res->refs[n] = talloc_move(res->refs, &ares->referral);
+ res->refs[n + 1] = NULL;
+ break;
+
+ case LDB_REPLY_DONE:
+ /* TODO: we should really support controls on entries
+ * and referrals too! */
+ res->controls = talloc_move(res, &ares->controls);
+
+ /* this is the last message, and means the request is done */
+ /* we have to signal and eventual ldb_wait() waiting that the
+ * async request operation was completed */
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ talloc_free(ares);
+
+ return LDB_SUCCESS;
+}
+
+int ldb_modify_default_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_result *res;
+ unsigned int n;
+ int ret;
+
+ res = talloc_get_type(req->context, struct ldb_result);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ ret = ares->error;
+ talloc_free(ares);
+ return ldb_request_done(req, ret);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_REFERRAL:
+ if (res->refs) {
+ for (n = 0; res->refs[n]; n++) /*noop*/ ;
+ } else {
+ n = 0;
+ }
+
+ res->refs = talloc_realloc(res, res->refs, char *, n + 2);
+ if (! res->refs) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ res->refs[n] = talloc_move(res->refs, &ares->referral);
+ res->refs[n + 1] = NULL;
+ break;
+
+ case LDB_REPLY_DONE:
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+ default:
+ talloc_free(ares);
+ ldb_asprintf_errstring(req->handle->ldb, "Invalid LDB reply type %d", ares->type);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+}
+
+int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ int ret;
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ ret = ares->error;
+ talloc_free(ares);
+ return ldb_request_done(req, ret);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_asprintf_errstring(req->handle->ldb, "Invalid LDB reply type %d", ares->type);
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+}
+
+static struct ldb_request *ldb_build_req_common(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req = NULL;
+
+ req = talloc_zero(mem_ctx, struct ldb_request);
+ if (req == NULL) {
+ return NULL;
+ }
+ req->controls = controls;
+ req->context = context;
+ req->callback = callback;
+
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ if (parent != NULL) {
+ req->handle = ldb_handle_new_child(req, parent);
+ if (req->handle == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ } else {
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ }
+
+ return req;
+}
+
+int ldb_build_search_req_ex(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *base,
+ enum ldb_scope scope,
+ struct ldb_parse_tree *tree,
+ const char * const *attrs,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
+ if (req == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_SEARCH;
+ if (base == NULL) {
+ req->op.search.base = ldb_dn_new(req, ldb, NULL);
+ if (req->op.search.base == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else {
+ req->op.search.base = base;
+ }
+ req->op.search.scope = scope;
+
+ req->op.search.tree = tree;
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(ldb, "'tree' can't be NULL");
+ talloc_free(req);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->op.search.attrs = attrs;
+ *ret_req = req;
+ return LDB_SUCCESS;
+}
+
+int ldb_build_search_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char * const *attrs,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_parse_tree *tree;
+ int ret;
+
+ tree = ldb_parse_tree(mem_ctx, expression);
+ if (tree == NULL) {
+ ldb_set_errstring(ldb, "Unable to parse search expression");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req_ex(ret_req, ldb, mem_ctx, base,
+ scope, tree, attrs, controls,
+ context, callback, parent);
+ if (ret == LDB_SUCCESS) {
+ talloc_steal(*ret_req, tree);
+ }
+ return ret;
+}
+
+int ldb_build_add_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_ADD;
+ req->op.add.message = message;
+ *ret_req = req;
+ return LDB_SUCCESS;
+}
+
+int ldb_build_mod_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_MODIFY;
+ req->op.mod.message = message;
+
+ *ret_req = req;
+ return LDB_SUCCESS;
+}
+
+int ldb_build_del_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_DELETE;
+ req->op.del.dn = dn;
+ *ret_req = req;
+ return LDB_SUCCESS;
+}
+
+int ldb_build_rename_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *olddn,
+ struct ldb_dn *newdn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_RENAME;
+ req->op.rename.olddn = olddn;
+ req->op.rename.newdn = newdn;
+ *ret_req = req;
+ return LDB_SUCCESS;
+}
+
+int ldb_extended_default_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_result *res;
+
+ res = talloc_get_type(req->context, struct ldb_result);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, ares->error);
+ }
+
+ if (ares->type == LDB_REPLY_DONE) {
+
+ /* TODO: we should really support controls on entries and referrals too! */
+ res->extended = talloc_move(res, &ares->response);
+ res->controls = talloc_move(res, &ares->controls);
+
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ talloc_free(ares);
+ ldb_asprintf_errstring(req->handle->ldb, "Invalid LDB reply type %d", ares->type);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+}
+
+int ldb_build_extended_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *oid,
+ void *data,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_request *req;
+
+ *ret_req = NULL;
+
+ req = ldb_build_req_common(mem_ctx, ldb, controls,
+ context, callback, parent);
+ if (req == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_EXTENDED;
+ req->op.extended.oid = oid;
+ req->op.extended.data = data;
+ *ret_req = req;
+ return LDB_SUCCESS;
+}
+
+int ldb_extended(struct ldb_context *ldb,
+ const char *oid,
+ void *data,
+ struct ldb_result **_res)
+{
+ struct ldb_request *req;
+ int ret;
+ struct ldb_result *res;
+
+ *_res = NULL;
+ req = NULL;
+
+ res = talloc_zero(ldb, struct ldb_result);
+ if (!res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_extended_req(&req, ldb, ldb,
+ oid, data, NULL,
+ res, ldb_extended_default_callback,
+ NULL);
+ ldb_req_set_location(req, "ldb_extended");
+
+ if (ret != LDB_SUCCESS) goto done;
+
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
+
+ ret = ldb_request(ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ res = NULL;
+ }
+
+ talloc_free(req);
+
+ *_res = res;
+ return ret;
+}
+
+/*
+ note that ldb_search() will automatically replace a NULL 'base' value
+ with the defaultNamingContext from the rootDSE if available.
+*/
+int ldb_search(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_result **result, struct ldb_dn *base,
+ enum ldb_scope scope, const char * const *attrs,
+ const char *exp_fmt, ...)
+{
+ struct ldb_request *req;
+ struct ldb_result *res;
+ char *expression;
+ va_list ap;
+ int ret;
+
+ expression = NULL;
+ *result = NULL;
+ req = NULL;
+
+ res = talloc_zero(mem_ctx, struct ldb_result);
+ if (!res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (exp_fmt) {
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
+ va_end(ap);
+
+ if (!expression) {
+ talloc_free(res);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ ret = ldb_build_search_req(&req, ldb, mem_ctx,
+ base?base:ldb_get_default_basedn(ldb),
+ scope,
+ expression,
+ attrs,
+ NULL,
+ res,
+ ldb_search_default_callback,
+ NULL);
+ ldb_req_set_location(req, "ldb_search");
+
+ if (ret != LDB_SUCCESS) goto done;
+
+ ret = ldb_request(ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ res = NULL;
+ }
+
+ talloc_free(expression);
+ talloc_free(req);
+
+ *result = res;
+ return ret;
+}
+
+/*
+ add a record to the database. Will fail if a record with the given class
+ and key already exists
+*/
+int ldb_add(struct ldb_context *ldb,
+ const struct ldb_message *message)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_add_req(&req, ldb, ldb,
+ message,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+ ldb_req_set_location(req, "ldb_add");
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+/*
+ modify the specified attributes of a record
+*/
+int ldb_modify(struct ldb_context *ldb,
+ const struct ldb_message *message)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_mod_req(&req, ldb, ldb,
+ message,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+ ldb_req_set_location(req, "ldb_modify");
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+
+/*
+ delete a record from the database
+*/
+int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_del_req(&req, ldb, ldb,
+ dn,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+ ldb_req_set_location(req, "ldb_delete");
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+/*
+ rename a record in the database
+*/
+int ldb_rename(struct ldb_context *ldb,
+ struct ldb_dn *olddn, struct ldb_dn *newdn)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_rename_req(&req, ldb, ldb,
+ olddn,
+ newdn,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+ ldb_req_set_location(req, "ldb_rename");
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_autotransaction_request(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+
+/*
+ return the global sequence number
+*/
+int ldb_sequence_number(struct ldb_context *ldb,
+ enum ldb_sequence_type type, uint64_t *seq_num)
+{
+ struct ldb_seqnum_request *seq;
+ struct ldb_seqnum_result *seqr;
+ struct ldb_result *res;
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+
+ *seq_num = 0;
+
+ tmp_ctx = talloc_zero(ldb, struct ldb_request);
+ if (tmp_ctx == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ seq = talloc_zero(tmp_ctx, struct ldb_seqnum_request);
+ if (seq == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ seq->type = type;
+
+ ret = ldb_extended(ldb, LDB_EXTENDED_SEQUENCE_NUMBER, seq, &res);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ talloc_steal(tmp_ctx, res);
+
+ if (strcmp(LDB_EXTENDED_SEQUENCE_NUMBER, res->extended->oid) != 0) {
+ ldb_set_errstring(ldb, "Invalid OID in reply");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ seqr = talloc_get_type(res->extended->data,
+ struct ldb_seqnum_result);
+ *seq_num = seqr->seq_num;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ return extended error information
+*/
+const char *ldb_errstring(struct ldb_context *ldb)
+{
+ if (ldb->err_string) {
+ return ldb->err_string;
+ }
+
+ return NULL;
+}
+
+/*
+ return a string explaining what a ldb error constant meancs
+*/
+const char *ldb_strerror(int ldb_err)
+{
+ switch (ldb_err) {
+ case LDB_SUCCESS:
+ return "Success";
+ case LDB_ERR_OPERATIONS_ERROR:
+ return "Operations error";
+ case LDB_ERR_PROTOCOL_ERROR:
+ return "Protocol error";
+ case LDB_ERR_TIME_LIMIT_EXCEEDED:
+ return "Time limit exceeded";
+ case LDB_ERR_SIZE_LIMIT_EXCEEDED:
+ return "Size limit exceeded";
+ case LDB_ERR_COMPARE_FALSE:
+ return "Compare false";
+ case LDB_ERR_COMPARE_TRUE:
+ return "Compare true";
+ case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
+ return "Auth method not supported";
+ case LDB_ERR_STRONG_AUTH_REQUIRED:
+ return "Strong auth required";
+/* 9 RESERVED */
+ case LDB_ERR_REFERRAL:
+ return "Referral error";
+ case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
+ return "Admin limit exceeded";
+ case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
+ return "Unsupported critical extension";
+ case LDB_ERR_CONFIDENTIALITY_REQUIRED:
+ return "Confidentiality required";
+ case LDB_ERR_SASL_BIND_IN_PROGRESS:
+ return "SASL bind in progress";
+ case LDB_ERR_NO_SUCH_ATTRIBUTE:
+ return "No such attribute";
+ case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
+ return "Undefined attribute type";
+ case LDB_ERR_INAPPROPRIATE_MATCHING:
+ return "Inappropriate matching";
+ case LDB_ERR_CONSTRAINT_VIOLATION:
+ return "Constraint violation";
+ case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
+ return "Attribute or value exists";
+ case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
+ return "Invalid attribute syntax";
+/* 22-31 unused */
+ case LDB_ERR_NO_SUCH_OBJECT:
+ return "No such object";
+ case LDB_ERR_ALIAS_PROBLEM:
+ return "Alias problem";
+ case LDB_ERR_INVALID_DN_SYNTAX:
+ return "Invalid DN syntax";
+/* 35 RESERVED */
+ case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
+ return "Alias dereferencing problem";
+/* 37-47 unused */
+ case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
+ return "Inappropriate authentication";
+ case LDB_ERR_INVALID_CREDENTIALS:
+ return "Invalid credentials";
+ case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+ return "insufficient access rights";
+ case LDB_ERR_BUSY:
+ return "Busy";
+ case LDB_ERR_UNAVAILABLE:
+ return "Unavailable";
+ case LDB_ERR_UNWILLING_TO_PERFORM:
+ return "Unwilling to perform";
+ case LDB_ERR_LOOP_DETECT:
+ return "Loop detect";
+/* 55-63 unused */
+ case LDB_ERR_NAMING_VIOLATION:
+ return "Naming violation";
+ case LDB_ERR_OBJECT_CLASS_VIOLATION:
+ return "Object class violation";
+ case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
+ return "Not allowed on non-leaf";
+ case LDB_ERR_NOT_ALLOWED_ON_RDN:
+ return "Not allowed on RDN";
+ case LDB_ERR_ENTRY_ALREADY_EXISTS:
+ return "Entry already exists";
+ case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
+ return "Object class mods prohibited";
+/* 70 RESERVED FOR CLDAP */
+ case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
+ return "Affects multiple DSAs";
+/* 72-79 unused */
+ case LDB_ERR_OTHER:
+ return "Other";
+ }
+
+ return "Unknown error";
+}
+
+/*
+ set backend specific opaque parameters
+*/
+int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value)
+{
+ struct ldb_opaque *o;
+
+ /* allow updating an existing value */
+ for (o=ldb->opaque;o;o=o->next) {
+ if (strcmp(o->name, name) == 0) {
+ o->value = value;
+ return LDB_SUCCESS;
+ }
+ }
+
+ o = talloc(ldb, struct ldb_opaque);
+ if (o == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OTHER;
+ }
+ o->next = ldb->opaque;
+ o->name = name;
+ o->value = value;
+ ldb->opaque = o;
+ return LDB_SUCCESS;
+}
+
+/*
+ get a previously set opaque value
+*/
+void *ldb_get_opaque(struct ldb_context *ldb, const char *name)
+{
+ struct ldb_opaque *o;
+ for (o=ldb->opaque;o;o=o->next) {
+ if (strcmp(o->name, name) == 0) {
+ return o->value;
+ }
+ }
+ return NULL;
+}
+
+int ldb_global_init(void)
+{
+ /* Provided for compatibility with some older versions of ldb */
+ return 0;
+}
+
+/* return the ldb flags */
+unsigned int ldb_get_flags(struct ldb_context *ldb)
+{
+ return ldb->flags;
+}
+
+/* set the ldb flags */
+void ldb_set_flags(struct ldb_context *ldb, unsigned flags)
+{
+ ldb->flags = flags;
+}
+
+
+/*
+ set the location in a ldb request. Used for debugging
+ */
+void ldb_req_set_location(struct ldb_request *req, const char *location)
+{
+ if (req && req->handle) {
+ req->handle->location = location;
+ }
+}
+
+/*
+ return the location set with dsdb_req_set_location
+ */
+const char *ldb_req_location(struct ldb_request *req)
+{
+ return req->handle->location;
+}
+
+/**
+ mark a request as untrusted. This tells the rootdse module to remove
+ unregistered controls
+ */
+void ldb_req_mark_untrusted(struct ldb_request *req)
+{
+ req->handle->flags |= LDB_HANDLE_FLAG_UNTRUSTED;
+}
+
+/**
+ mark a request as trusted.
+ */
+void ldb_req_mark_trusted(struct ldb_request *req)
+{
+ req->handle->flags &= ~LDB_HANDLE_FLAG_UNTRUSTED;
+}
+
+/**
+ set custom flags. Those flags are set by applications using ldb,
+ they are application dependent and the same bit can have different
+ meaning in different application.
+ */
+void ldb_req_set_custom_flags(struct ldb_request *req, uint32_t flags)
+{
+ if (req != NULL && req->handle != NULL) {
+ req->handle->custom_flags = flags;
+ }
+}
+
+
+/**
+ get custom flags. Those flags are set by applications using ldb,
+ they are application dependent and the same bit can have different
+ meaning in different application.
+ */
+uint32_t ldb_req_get_custom_flags(struct ldb_request *req)
+{
+ if (req != NULL && req->handle != NULL) {
+ return req->handle->custom_flags;
+ }
+
+ /*
+ * 0 is not something any better or worse than
+ * anything else as req or the handle is NULL
+ */
+ return 0;
+}
+
+
+/**
+ * return true if a request is untrusted
+ */
+bool ldb_req_is_untrusted(struct ldb_request *req)
+{
+ return (req->handle->flags & LDB_HANDLE_FLAG_UNTRUSTED) != 0;
+}
diff --git a/lib/ldb/common/ldb_attributes.c b/lib/ldb/common/ldb_attributes.c
new file mode 100644
index 0000000..32f25fd
--- /dev/null
+++ b/lib/ldb/common/ldb_attributes.c
@@ -0,0 +1,411 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ register handlers for specific attributes and objectclass relationships
+
+ this allows a backend to store its schema information in any format
+ it likes (or to not have any schema information at all) while keeping the
+ message matching logic generic
+*/
+
+#include "ldb_private.h"
+#include "ldb_handlers.h"
+
+/*
+ fill in an attribute to the ldb_schema into the supplied buffer
+
+ if flags contains LDB_ATTR_FLAG_ALLOCATED
+ the attribute name string will be copied using
+ talloc_strdup(), otherwise it needs to be a static const
+ string at least with a lifetime longer than the ldb struct!
+
+ the ldb_schema_syntax structure should be a pointer
+ to a static const struct or at least it needs to be
+ a struct with a longer lifetime than the ldb context!
+
+*/
+int ldb_schema_attribute_fill_with_syntax(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *attribute,
+ unsigned flags,
+ const struct ldb_schema_syntax *syntax,
+ struct ldb_schema_attribute *a)
+{
+ a->name = attribute;
+ a->flags = flags;
+ a->syntax = syntax;
+
+ if (a->flags & LDB_ATTR_FLAG_ALLOCATED) {
+ a->name = talloc_strdup(mem_ctx, a->name);
+ if (a->name == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ add a attribute to the ldb_schema
+
+ if flags contains LDB_ATTR_FLAG_ALLOCATED
+ the attribute name string will be copied using
+ talloc_strdup(), otherwise it needs to be a static const
+ string at least with a lifetime longer than the ldb struct!
+
+ the ldb_schema_syntax structure should be a pointer
+ to a static const struct or at least it needs to be
+ a struct with a longer lifetime than the ldb context!
+
+*/
+int ldb_schema_attribute_add_with_syntax(struct ldb_context *ldb,
+ const char *attribute,
+ unsigned flags,
+ const struct ldb_schema_syntax *syntax)
+{
+ unsigned int i, n;
+ struct ldb_schema_attribute *a;
+
+ if (!syntax) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ n = ldb->schema.num_attributes + 1;
+
+ a = talloc_realloc(ldb, ldb->schema.attributes,
+ struct ldb_schema_attribute, n);
+ if (a == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ ldb->schema.attributes = a;
+
+ for (i = 0; i < ldb->schema.num_attributes; i++) {
+ int cmp = ldb_attr_cmp(attribute, a[i].name);
+ if (cmp == 0) {
+ /* silently ignore attempts to overwrite fixed attributes */
+ if (a[i].flags & LDB_ATTR_FLAG_FIXED) {
+ return 0;
+ }
+ if (a[i].flags & LDB_ATTR_FLAG_ALLOCATED) {
+ talloc_free(discard_const_p(char, a[i].name));
+ }
+ /* To cancel out increment below */
+ ldb->schema.num_attributes--;
+ break;
+ } else if (cmp < 0) {
+ memmove(a+i+1, a+i, sizeof(*a) * (ldb->schema.num_attributes-i));
+ break;
+ }
+ }
+ ldb->schema.num_attributes++;
+
+ a[i].name = attribute;
+ a[i].flags = flags;
+ a[i].syntax = syntax;
+
+ if (a[i].flags & LDB_ATTR_FLAG_ALLOCATED) {
+ a[i].name = talloc_strdup(a, a[i].name);
+ if (a[i].name == NULL) {
+ ldb_oom(ldb);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static const struct ldb_schema_syntax ldb_syntax_default = {
+ .name = LDB_SYNTAX_OCTET_STRING,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = ldb_handler_copy,
+ .comparison_fn = ldb_comparison_binary
+};
+
+static const struct ldb_schema_attribute ldb_attribute_default = {
+ .name = NULL,
+ .flags = 0,
+ .syntax = &ldb_syntax_default
+};
+
+/*
+ * Return the attribute handlers for a given attribute
+ *
+ * @param ldb ldb context
+ * @param name attribute name to search for
+ * @return Always return valid pointer to schema attribute.
+ * In case there is no attribute with name,
+ * ldb_attribute_default is returned
+ */
+static const struct ldb_schema_attribute *ldb_schema_attribute_by_name_internal(
+ struct ldb_context *ldb,
+ const char *name)
+{
+ /* for binary search we need signed variables */
+ unsigned int i, e, b = 0;
+ int r;
+ const struct ldb_schema_attribute *def = &ldb_attribute_default;
+
+ /* fallback to default attribute implementation */
+ if (name == NULL) {
+ return def;
+ }
+
+ /* as handlers are sorted, '*' must be the first if present */
+ if (strcmp(ldb->schema.attributes[0].name, "*") == 0) {
+ def = &ldb->schema.attributes[0];
+ b = 1;
+ }
+
+ /* do a binary search on the array */
+ e = ldb->schema.num_attributes - 1;
+
+ while ((b <= e) && (e != (unsigned int) -1)) {
+ i = (b + e) / 2;
+
+ r = ldb_attr_cmp(name, ldb->schema.attributes[i].name);
+ if (r == 0) {
+ return &ldb->schema.attributes[i];
+ }
+ if (r < 0) {
+ e = i - 1;
+ } else {
+ b = i + 1;
+ }
+ }
+
+ return def;
+}
+
+/*
+ return the attribute handlers for a given attribute
+*/
+const struct ldb_schema_attribute *ldb_schema_attribute_by_name(struct ldb_context *ldb,
+ const char *name)
+{
+ if (ldb->schema.attribute_handler_override) {
+ const struct ldb_schema_attribute *ret =
+ ldb->schema.attribute_handler_override(ldb,
+ ldb->schema.attribute_handler_override_private,
+ name);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return ldb_schema_attribute_by_name_internal(ldb, name);
+}
+
+
+/*
+ add to the list of ldif handlers for this ldb context
+*/
+void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name)
+{
+ const struct ldb_schema_attribute *a;
+ ptrdiff_t i;
+
+ a = ldb_schema_attribute_by_name_internal(ldb, name);
+ if (a == NULL || a->name == NULL) {
+ return;
+ }
+
+ /* FIXED attributes are never removed */
+ if (a->flags & LDB_ATTR_FLAG_FIXED) {
+ return;
+ }
+
+ if (a->flags & LDB_ATTR_FLAG_ALLOCATED) {
+ talloc_free(discard_const_p(char, a->name));
+ }
+
+ i = a - ldb->schema.attributes;
+ if (i < ldb->schema.num_attributes - 1) {
+ memmove(&ldb->schema.attributes[i],
+ a+1, sizeof(*a) * (ldb->schema.num_attributes-(i+1)));
+ }
+
+ ldb->schema.num_attributes--;
+}
+
+/*
+ remove attributes with a specified flag (eg LDB_ATTR_FLAG_FROM_DB) for this ldb context
+
+ This is to permit correct reloads
+*/
+void ldb_schema_attribute_remove_flagged(struct ldb_context *ldb, unsigned int flag)
+{
+ ptrdiff_t i;
+
+ for (i = 0; i < ldb->schema.num_attributes;) {
+ const struct ldb_schema_attribute *a
+ = &ldb->schema.attributes[i];
+ /* FIXED attributes are never removed */
+ if (a->flags & LDB_ATTR_FLAG_FIXED) {
+ i++;
+ continue;
+ }
+ if ((a->flags & flag) == 0) {
+ i++;
+ continue;
+ }
+ if (a->flags & LDB_ATTR_FLAG_ALLOCATED) {
+ talloc_free(discard_const_p(char, a->name));
+ }
+ if (i < ldb->schema.num_attributes - 1) {
+ memmove(&ldb->schema.attributes[i],
+ a+1, sizeof(*a) * (ldb->schema.num_attributes-(i+1)));
+ }
+
+ ldb->schema.num_attributes--;
+ }
+}
+
+/*
+ setup a attribute handler using a standard syntax
+*/
+int ldb_schema_attribute_add(struct ldb_context *ldb,
+ const char *attribute,
+ unsigned flags,
+ const char *syntax)
+{
+ const struct ldb_schema_syntax *s = ldb_standard_syntax_by_name(ldb, syntax);
+ return ldb_schema_attribute_add_with_syntax(ldb, attribute, flags, s);
+}
+
+/*
+ setup the attribute handles for well known attributes
+*/
+int ldb_setup_wellknown_attributes(struct ldb_context *ldb)
+{
+ const struct {
+ const char *attr;
+ const char *syntax;
+ } wellknown[] = {
+ { "dn", LDB_SYNTAX_DN },
+ { "distinguishedName", LDB_SYNTAX_DN },
+ { "cn", LDB_SYNTAX_DIRECTORY_STRING },
+ { "dc", LDB_SYNTAX_DIRECTORY_STRING },
+ { "ou", LDB_SYNTAX_DIRECTORY_STRING },
+ { "objectClass", LDB_SYNTAX_OBJECTCLASS }
+ };
+ unsigned int i;
+ int ret;
+
+ for (i=0;i<ARRAY_SIZE(wellknown);i++) {
+ ret = ldb_schema_attribute_add(ldb, wellknown[i].attr, 0,
+ wellknown[i].syntax);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ add a extended dn syntax to the ldb_schema
+*/
+int ldb_dn_extended_add_syntax(struct ldb_context *ldb,
+ unsigned flags,
+ const struct ldb_dn_extended_syntax *syntax)
+{
+ unsigned int n;
+ struct ldb_dn_extended_syntax *a;
+
+ if (!syntax) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ n = ldb->schema.num_dn_extended_syntax + 1;
+
+ a = talloc_realloc(ldb, ldb->schema.dn_extended_syntax,
+ struct ldb_dn_extended_syntax, n);
+
+ if (!a) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ a[ldb->schema.num_dn_extended_syntax] = *syntax;
+ ldb->schema.dn_extended_syntax = a;
+
+ ldb->schema.num_dn_extended_syntax = n;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ return the extended dn syntax for a given name
+*/
+const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_context *ldb,
+ const char *name)
+{
+ unsigned int i;
+ for (i=0; i < ldb->schema.num_dn_extended_syntax; i++) {
+ if (ldb_attr_cmp(ldb->schema.dn_extended_syntax[i].name, name) == 0) {
+ return &ldb->schema.dn_extended_syntax[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ set an attribute handler override function - used to delegate schema handling
+ to external code
+ */
+void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
+ ldb_attribute_handler_override_fn_t override,
+ void *private_data)
+{
+ ldb->schema.attribute_handler_override_private = private_data;
+ ldb->schema.attribute_handler_override = override;
+}
+
+/*
+ set that the attribute handler override function - used to delegate
+ schema handling to external code, is handling setting
+ LDB_ATTR_FLAG_INDEXED
+ */
+void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
+ bool one_level_indexes)
+{
+ ldb->schema.index_handler_override = true;
+ ldb->schema.one_level_indexes = one_level_indexes;
+}
+
+/*
+ * set that the GUID index mode is in operation
+ *
+ * The caller must ensure the supplied strings do not go out of
+ * scope (they are typically constant memory).
+ */
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+ const char *GUID_index_attribute,
+ const char *GUID_index_dn_component)
+{
+ ldb->schema.GUID_index_attribute = GUID_index_attribute;
+ ldb->schema.GUID_index_dn_component = GUID_index_dn_component;
+}
diff --git a/lib/ldb/common/ldb_controls.c b/lib/ldb/common/ldb_controls.c
new file mode 100644
index 0000000..47e113a
--- /dev/null
+++ b/lib/ldb/common/ldb_controls.c
@@ -0,0 +1,1342 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_controls.c
+ *
+ * Component: ldb controls utility functions
+ *
+ * Description: helper functions for control modules
+ *
+ * Author: Simo Sorce
+ */
+
+#include "ldb_private.h"
+
+/* check if a control with the specified "oid" exist and return it */
+/* returns NULL if not found */
+struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid)
+{
+ unsigned int i;
+
+ if (req->controls != NULL) {
+ for (i = 0; req->controls[i]; i++) {
+ if (req->controls[i]->oid && strcmp(oid, req->controls[i]->oid) == 0) {
+ break;
+ }
+ }
+
+ return req->controls[i];
+ }
+
+ return NULL;
+}
+
+/* check if a control with the specified "oid" exist and return it */
+/* returns NULL if not found */
+struct ldb_control *ldb_reply_get_control(struct ldb_reply *rep, const char *oid)
+{
+ unsigned int i;
+
+ if (rep->controls != NULL) {
+ for (i = 0; rep->controls[i]; i++) {
+ if (rep->controls[i]->oid && strcmp(oid, rep->controls[i]->oid) == 0) {
+ break;
+ }
+ }
+
+ return rep->controls[i];
+ }
+
+ return NULL;
+}
+
+/*
+ * Saves the current controls list into the "saver" (can also be NULL) and
+ * replace the one in "req" with a new one excluding the "exclude" control
+ * (if it is NULL then the list remains the same)
+ *
+ * Returns 0 on error.
+ */
+int ldb_save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver)
+{
+ struct ldb_control **lcs, **lcs_old;
+ unsigned int i, j;
+
+ lcs_old = req->controls;
+ if (saver != NULL) {
+ *saver = lcs_old;
+ }
+
+ for (i = 0; req->controls && req->controls[i]; i++);
+ if (i == 0) {
+ req->controls = NULL;
+ return 1;
+ }
+
+ lcs = talloc_array(req, struct ldb_control *, i + 1);
+ if (!lcs) {
+ return 0;
+ }
+
+ for (i = 0, j = 0; lcs_old[i]; i++) {
+ if (exclude == lcs_old[i]) continue;
+ lcs[j] = lcs_old[i];
+ j++;
+ }
+ lcs[j] = NULL;
+
+ req->controls = talloc_realloc(req, lcs, struct ldb_control *, j + 1);
+ if (req->controls == NULL) {
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Returns a list of controls, except the one specified with "exclude" (can
+ * also be NULL). Included controls become a child of returned list if they
+ * were children of "controls_in".
+ *
+ * Returns NULL on error (OOM) or an empty control list.
+ */
+struct ldb_control **ldb_controls_except_specified(struct ldb_control **controls_in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_control *exclude)
+{
+ struct ldb_control **lcs = NULL;
+ unsigned int i, j, n;
+
+ for (i = 0; controls_in && controls_in[i]; i++);
+ if (i == 0) {
+ return NULL;
+ }
+ n = i;
+
+ for (i = 0, j = 0; controls_in && controls_in[i]; i++) {
+ if (exclude == controls_in[i]) continue;
+
+ if (!lcs) {
+ /* Allocate here so if we remove the only
+ * control, or there were no controls, we
+ * don't allocate at all, and just return
+ * NULL */
+ lcs = talloc_array(mem_ctx, struct ldb_control *,
+ n + 1);
+ if (!lcs) {
+ return NULL;
+ }
+ }
+
+ lcs[j] = controls_in[i];
+ talloc_reparent(controls_in, lcs, lcs[j]);
+ j++;
+ }
+ if (lcs) {
+ lcs[j] = NULL;
+
+ lcs = talloc_realloc(mem_ctx, lcs, struct ldb_control *, j + 1);
+ }
+
+ return lcs;
+}
+
+/* check if there's any control marked as critical in the list */
+/* return True if any, False if none */
+int ldb_check_critical_controls(struct ldb_control **controls)
+{
+ unsigned int i;
+
+ if (controls == NULL) {
+ return 0;
+ }
+
+ for (i = 0; controls[i]; i++) {
+ if (controls[i]->critical) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int ldb_request_add_control(struct ldb_request *req, const char *oid, bool critical, void *data)
+{
+ unsigned int i, n;
+ struct ldb_control **ctrls;
+ struct ldb_control *ctrl;
+
+ for (n=0; req->controls && req->controls[n];n++) {
+ /* having two controls of the same OID makes no sense */
+ if (req->controls[n]->oid && strcmp(oid, req->controls[n]->oid) == 0) {
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ }
+
+ ctrls = talloc_array(req,
+ struct ldb_control *,
+ n + 2);
+ if (!ctrls) return LDB_ERR_OPERATIONS_ERROR;
+
+ for (i=0; i<n; i++) {
+ ctrls[i] = req->controls[i];
+ }
+
+ req->controls = ctrls;
+ ctrls[n] = NULL;
+ ctrls[n+1] = NULL;
+
+ ctrl = talloc(ctrls, struct ldb_control);
+ if (!ctrl) return LDB_ERR_OPERATIONS_ERROR;
+
+ ctrl->oid = talloc_strdup(ctrl, oid);
+ if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR;
+ ctrl->critical = critical;
+ ctrl->data = data;
+
+ ctrls[n] = ctrl;
+ return LDB_SUCCESS;
+}
+
+int ldb_reply_add_control(struct ldb_reply *ares, const char *oid, bool critical, void *data)
+{
+ unsigned n;
+ struct ldb_control **ctrls;
+ struct ldb_control *ctrl;
+
+ for (n=0; ares->controls && ares->controls[n];) {
+ /* having two controls of the same OID makes no sense */
+ if (ares->controls[n]->oid && strcmp(oid, ares->controls[n]->oid) == 0) {
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ n++;
+ }
+
+ ctrls = talloc_realloc(ares, ares->controls,
+ struct ldb_control *,
+ n + 2);
+ if (!ctrls) return LDB_ERR_OPERATIONS_ERROR;
+ ares->controls = ctrls;
+ ctrls[n] = NULL;
+ ctrls[n+1] = NULL;
+
+ ctrl = talloc(ctrls, struct ldb_control);
+ if (!ctrl) return LDB_ERR_OPERATIONS_ERROR;
+
+ ctrl->oid = talloc_strdup(ctrl, oid);
+ if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR;
+ ctrl->critical = critical;
+ ctrl->data = data;
+
+ ctrls[n] = ctrl;
+ return LDB_SUCCESS;
+}
+
+/* Add a control to the request, replacing the old one if it is already in the request */
+int ldb_request_replace_control(struct ldb_request *req, const char *oid, bool critical, void *data)
+{
+ unsigned int n;
+ int ret;
+
+ ret = ldb_request_add_control(req, oid, critical, data);
+ if (ret != LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+ return ret;
+ }
+
+ for (n=0; req->controls[n];n++) {
+ if (req->controls[n]->oid && strcmp(oid, req->controls[n]->oid) == 0) {
+ req->controls[n]->critical = critical;
+ req->controls[n]->data = data;
+ return LDB_SUCCESS;
+ }
+ }
+
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+ * Return a control as string
+ * the project (ie. name:value1:value2:...:valuen
+ * The string didn't include the criticity of the critical flag
+ */
+char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *control)
+{
+ char *res = NULL;
+
+ if (strcmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID) == 0) {
+ struct ldb_paged_control *rep_control = talloc_get_type(control->data, struct ldb_paged_control);
+ char *cookie;
+ if (rep_control == NULL) {
+ return NULL;
+ }
+
+ cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, rep_control->cookie_len);
+ if (cookie == NULL) {
+ return NULL;
+ }
+ if (cookie[0] != '\0') {
+ res = talloc_asprintf(mem_ctx, "%s:%d:%s",
+ LDB_CONTROL_PAGED_RESULTS_NAME,
+ control->critical,
+ cookie);
+
+ talloc_free(cookie);
+ } else {
+ res = talloc_asprintf(mem_ctx, "%s:%d",
+ LDB_CONTROL_PAGED_RESULTS_NAME,
+ control->critical);
+ }
+ return res;
+ }
+
+ if (strcmp(control->oid, LDB_CONTROL_VLV_RESP_OID) == 0) {
+ struct ldb_vlv_resp_control *rep_control = talloc_get_type(control->data,
+ struct ldb_vlv_resp_control);
+
+ char *cookie;
+
+ if (rep_control == NULL) {
+ return NULL;
+ }
+
+ cookie = ldb_base64_encode(mem_ctx,
+ (char *)rep_control->contextId,
+ rep_control->ctxid_len);
+ if (cookie == NULL) {
+ return NULL;
+ }
+
+ res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%d:%s",
+ LDB_CONTROL_VLV_RESP_NAME,
+ control->critical,
+ rep_control->targetPosition,
+ rep_control->contentCount,
+ rep_control->vlv_result,
+ cookie);
+
+ return res;
+ }
+
+ if (strcmp(control->oid, LDB_CONTROL_SORT_RESP_OID) == 0) {
+ struct ldb_sort_resp_control *rep_control = talloc_get_type(control->data,
+ struct ldb_sort_resp_control);
+
+ if (rep_control == NULL) {
+ return NULL;
+ }
+ res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s",
+ LDB_CONTROL_SORT_RESP_NAME,
+ control->critical,
+ rep_control->result,
+ rep_control->attr_desc);
+
+ return res;
+ }
+
+ if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
+ struct ldb_asq_control *rep_control = talloc_get_type(control->data,
+ struct ldb_asq_control);
+
+ if (rep_control == NULL) {
+ return NULL;
+ }
+ res = talloc_asprintf(mem_ctx, "%s:%d:%d",
+ LDB_CONTROL_ASQ_NAME,
+ control->critical,
+ rep_control->result);
+
+ return res;
+ }
+
+ if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_OID) == 0) {
+ char *cookie;
+ struct ldb_dirsync_control *rep_control = talloc_get_type(control->data,
+ struct ldb_dirsync_control);
+
+ if (rep_control == NULL) {
+ return NULL;
+ }
+ cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
+ rep_control->cookie_len);
+ if (cookie == NULL) {
+ return NULL;
+ }
+ res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s",
+ LDB_CONTROL_DIRSYNC_NAME,
+ control->critical,
+ rep_control->flags,
+ rep_control->max_attributes,
+ cookie);
+
+ talloc_free(cookie);
+ return res;
+ }
+ if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_EX_OID) == 0) {
+ char *cookie;
+ struct ldb_dirsync_control *rep_control = talloc_get_type(control->data,
+ struct ldb_dirsync_control);
+
+ if (rep_control == NULL) {
+ return NULL;
+ }
+ cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
+ rep_control->cookie_len);
+ if (cookie == NULL) {
+ return NULL;
+ }
+ res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s",
+ LDB_CONTROL_DIRSYNC_EX_NAME,
+ control->critical,
+ rep_control->flags,
+ rep_control->max_attributes,
+ cookie);
+
+ talloc_free(cookie);
+ return res;
+ }
+
+ if (strcmp(control->oid, LDB_CONTROL_VERIFY_NAME_OID) == 0) {
+ struct ldb_verify_name_control *rep_control = talloc_get_type(control->data, struct ldb_verify_name_control);
+
+ if (rep_control == NULL) {
+ return NULL;
+ }
+ if (rep_control->gc != NULL) {
+ res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s",
+ LDB_CONTROL_VERIFY_NAME_NAME,
+ control->critical,
+ rep_control->flags,
+ rep_control->gc);
+
+ } else {
+ res = talloc_asprintf(mem_ctx, "%s:%d:%d",
+ LDB_CONTROL_VERIFY_NAME_NAME,
+ control->critical,
+ rep_control->flags);
+ }
+ return res;
+ }
+
+ /*
+ * From here we don't know the control
+ */
+ if (control->data == NULL) {
+ /*
+ * We don't know the control but there is no real data attached
+ * to it so we can represent it with local_oid:oid:criticity.
+ */
+ res = talloc_asprintf(mem_ctx, "local_oid:%s:%d",
+ control->oid,
+ control->critical);
+ } else {
+ res = talloc_asprintf(mem_ctx, "unknown oid:%s",
+ control->oid);
+ }
+ return res;
+}
+
+
+/*
+ * A little trick to allow one to use constants defined in headers rather than
+ * hardwritten in the file.
+ * "sizeof" will return the \0 char as well so it will take the place of ":"
+ * in the length of the string.
+ */
+#define LDB_CONTROL_CMP(control, NAME) strncmp(control, NAME ":", sizeof(NAME))
+
+/* Parse one string and return associated control if parsing is successful*/
+struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *control_strings)
+{
+ struct ldb_control *ctrl;
+
+ if (!(ctrl = talloc(mem_ctx, struct ldb_control))) {
+ ldb_oom(ldb);
+ return NULL;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings,
+ LDB_CONTROL_VLV_REQ_NAME) == 0) {
+ struct ldb_vlv_req_control *control;
+ const char *p;
+ char attr[1024];
+ char ctxid[1024];
+ int crit, bc, ac, os, cc, ret;
+
+ attr[0] = '\0';
+ ctxid[0] = '\0';
+ p = &(control_strings[sizeof(LDB_CONTROL_VLV_REQ_NAME)]);
+ ret = sscanf(p, "%d:%d:%d:%d:%d:%1023[^$]", &crit, &bc, &ac, &os, &cc, ctxid);
+ /* We allow 2 ways to encode the GT_EQ case, because the
+ comparison string might contain null bytes or colons, which
+ would break sscanf (or indeed any parsing mechanism). */
+ if (ret == 3) {
+ ret = sscanf(p, "%d:%d:%d:>=%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid);
+ }
+ if (ret == 3) {
+ int len;
+ ret = sscanf(p, "%d:%d:%d:base64>=%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid);
+ len = ldb_base64_decode(attr);
+ if (len < 0) {
+ ret = -1;
+ }
+ }
+
+ if ((ret < 4) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid VLV control syntax\n"
+ " syntax: crit(b):bc(n):ac(n):"
+ "{os(n):cc(n)|>=val(s)|base64>=val(o)}[:ctxid(o)]\n"
+ " note: b = boolean, n = number, s = string, o = b64 binary blob");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ ctrl->oid = LDB_CONTROL_VLV_REQ_OID;
+ ctrl->critical = crit;
+ if (!(control = talloc(ctrl,
+ struct ldb_vlv_req_control))) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->beforeCount = bc;
+ control->afterCount = ac;
+ if (attr[0]) {
+ control->type = 1;
+ control->match.gtOrEq.value = talloc_strdup(control, attr);
+ control->match.gtOrEq.value_len = strlen(attr);
+ } else {
+ control->type = 0;
+ control->match.byOffset.offset = os;
+ control->match.byOffset.contentCount = cc;
+ }
+ if (ctxid[0]) {
+ int len = ldb_base64_decode(ctxid);
+ if (len < 0) {
+ ldb_set_errstring(ldb,
+ "invalid VLV context_id\n");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->ctxid_len = len;
+ control->contextId = talloc_memdup(control, ctxid,
+ control->ctxid_len);
+ if (control->contextId == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ } else {
+ control->ctxid_len = 0;
+ control->contextId = NULL;
+ }
+ ctrl->data = control;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_NAME) == 0) {
+ struct ldb_dirsync_control *control;
+ const char *p;
+ char *cookie = NULL;
+ int crit, max_attrs, ret;
+ uint32_t flags;
+
+ cookie = talloc_zero_array(ctrl, char,
+ strlen(control_strings) + 1);
+ if (cookie == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_NAME)]);
+ ret = sscanf(p, "%d:%u:%d:%[^$]", &crit, &flags, &max_attrs, cookie);
+
+ if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) {
+ ldb_set_errstring(ldb,
+ "invalid dirsync control syntax\n"
+ " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n"
+ " note: b = boolean, n = number, o = b64 binary blob");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ /* w2k3 seems to ignore the parameter,
+ * but w2k sends a wrong cookie when this value is to small
+ * this would cause looping forever, while getting
+ * the same data and same cookie forever
+ */
+ if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
+
+ ctrl->oid = LDB_CONTROL_DIRSYNC_OID;
+ ctrl->critical = crit;
+ control = talloc(ctrl, struct ldb_dirsync_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->flags = flags;
+ control->max_attributes = max_attrs;
+ if (*cookie) {
+ int len = ldb_base64_decode(cookie);
+ if (len < 0) {
+ ldb_set_errstring(ldb,
+ "invalid dirsync cookie\n");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->cookie_len = len;
+ control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len);
+ if (control->cookie == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ } else {
+ control->cookie = NULL;
+ control->cookie_len = 0;
+ }
+ ctrl->data = control;
+ TALLOC_FREE(cookie);
+
+ return ctrl;
+ }
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_EX_NAME) == 0) {
+ struct ldb_dirsync_control *control;
+ const char *p;
+ char *cookie = NULL;
+ int crit, max_attrs, ret;
+ uint32_t flags;
+
+ cookie = talloc_zero_array(ctrl, char,
+ strlen(control_strings) + 1);
+ if (cookie == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_EX_NAME)]);
+ ret = sscanf(p, "%d:%u:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie);
+
+ if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) {
+ ldb_set_errstring(ldb,
+ "invalid dirsync_ex control syntax\n"
+ " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n"
+ " note: b = boolean, n = number, o = b64 binary blob");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ /* w2k3 seems to ignore the parameter,
+ * but w2k sends a wrong cookie when this value is to small
+ * this would cause looping forever, while getting
+ * the same data and same cookie forever
+ */
+ if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
+
+ ctrl->oid = LDB_CONTROL_DIRSYNC_EX_OID;
+ ctrl->critical = crit;
+ control = talloc(ctrl, struct ldb_dirsync_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->flags = flags;
+ control->max_attributes = max_attrs;
+ if (*cookie) {
+ int len = ldb_base64_decode(cookie);
+ if (len < 0) {
+ ldb_set_errstring(ldb,
+ "invalid dirsync_ex cookie"
+ " (probably too long)\n");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->cookie_len = len;
+ control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len);
+ if (control->cookie == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ } else {
+ control->cookie = NULL;
+ control->cookie_len = 0;
+ }
+ ctrl->data = control;
+ TALLOC_FREE(cookie);
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_ASQ_NAME) == 0) {
+ struct ldb_asq_control *control;
+ const char *p;
+ char attr[256];
+ int crit, ret;
+
+ attr[0] = '\0';
+ p = &(control_strings[sizeof(LDB_CONTROL_ASQ_NAME)]);
+ ret = sscanf(p, "%d:%255[^$]", &crit, attr);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (attr[0] == '\0')) {
+ ldb_set_errstring(ldb,
+ "invalid asq control syntax\n"
+ " syntax: crit(b):attr(s)\n"
+ " note: b = boolean, s = string");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_ASQ_OID;
+ ctrl->critical = crit;
+ control = talloc(ctrl, struct ldb_asq_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->request = 1;
+ control->source_attribute = talloc_strdup(control, attr);
+ control->src_attr_len = strlen(attr);
+ ctrl->data = control;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_EXTENDED_DN_NAME) == 0) {
+ struct ldb_extended_dn_control *control;
+ const char *p;
+ int crit, type, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_EXTENDED_DN_NAME)]);
+ ret = sscanf(p, "%d:%d", &crit, &type);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) {
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid extended_dn control syntax\n"
+ " syntax: crit(b)[:type(i)]\n"
+ " note: b = boolean\n"
+ " i = integer\n"
+ " valid values are: 0 - hexadecimal representation\n"
+ " 1 - normal string representation");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control = NULL;
+ } else {
+ control = talloc(ctrl, struct ldb_extended_dn_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->type = type;
+ }
+
+ ctrl->oid = LDB_CONTROL_EXTENDED_DN_OID;
+ ctrl->critical = crit;
+ ctrl->data = control;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SD_FLAGS_NAME) == 0) {
+ struct ldb_sd_flags_control *control;
+ const char *p;
+ int crit, ret;
+ unsigned secinfo_flags;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_SD_FLAGS_NAME)]);
+ ret = sscanf(p, "%d:%u", &crit, &secinfo_flags);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags > 0xF)) {
+ ldb_set_errstring(ldb,
+ "invalid sd_flags control syntax\n"
+ " syntax: crit(b):secinfo_flags(n)\n"
+ " note: b = boolean, n = number");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_SD_FLAGS_OID;
+ ctrl->critical = crit;
+ control = talloc(ctrl, struct ldb_sd_flags_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ control->secinfo_flags = secinfo_flags;
+ ctrl->data = control;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SEARCH_OPTIONS_NAME) == 0) {
+ struct ldb_search_options_control *control;
+ const char *p;
+ int crit, ret;
+ unsigned search_options;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_SEARCH_OPTIONS_NAME)]);
+ ret = sscanf(p, "%d:%u", &crit, &search_options);
+ if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options > 0xF)) {
+ ldb_set_errstring(ldb,
+ "invalid search_options control syntax\n"
+ " syntax: crit(b):search_options(n)\n"
+ " note: b = boolean, n = number");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_SEARCH_OPTIONS_OID;
+ ctrl->critical = crit;
+ control = talloc(ctrl, struct ldb_search_options_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ control->search_options = search_options;
+ ctrl->data = control;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_BYPASS_OPERATIONAL_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_BYPASS_OPERATIONAL_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid bypassoperational control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_BYPASS_OPERATIONAL_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RELAX_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_RELAX_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid relax control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_RELAX_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RECALCULATE_SD_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_RECALCULATE_SD_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid recalculate_sd control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_RECALCULATE_SD_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DOMAIN_SCOPE_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_DOMAIN_SCOPE_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid domain_scope control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_DOMAIN_SCOPE_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PAGED_RESULTS_NAME) == 0) {
+ struct ldb_paged_control *control;
+ const char *p;
+ char cookie[1024];
+ int crit, size, ret;
+
+ cookie[0] = '\0';
+ p = &(control_strings[sizeof(LDB_CONTROL_PAGED_RESULTS_NAME)]);
+ ret = sscanf(p, "%d:%d:%1023[^$]", &crit, &size, cookie);
+ if ((ret < 2) || (ret > 3) || (crit < 0) || (crit > 1) ||
+ (size < 0)) {
+ ldb_set_errstring(ldb,
+ "invalid paged_results control syntax\n"
+ " syntax: crit(b):size(n)[:cookie(base64)]\n"
+ " note: b = boolean, n = number");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_PAGED_RESULTS_OID;
+ ctrl->critical = crit;
+ control = talloc(ctrl, struct ldb_paged_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ control->size = size;
+ if (cookie[0] != '\0') {
+ int len = ldb_base64_decode(cookie);
+ if (len < 0) {
+ ldb_set_errstring(ldb,
+ "invalid paged_results cookie"
+ " (probably too long)\n");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ control->cookie_len = len;
+ control->cookie = talloc_memdup(control, cookie, control->cookie_len);
+ if (control->cookie == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ } else {
+ control->cookie = NULL;
+ control->cookie_len = 0;
+ }
+ ctrl->data = control;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SERVER_SORT_NAME) == 0) {
+ struct ldb_server_sort_control **control;
+ const char *p;
+ char attr[256];
+ char rule[128];
+ int crit, rev, ret;
+
+ attr[0] = '\0';
+ rule[0] = '\0';
+ p = &(control_strings[sizeof(LDB_CONTROL_SERVER_SORT_NAME)]);
+ ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule);
+ if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') {
+ ldb_set_errstring(ldb,
+ "invalid server_sort control syntax\n"
+ " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n"
+ " note: b = boolean, s = string");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ ctrl->oid = LDB_CONTROL_SERVER_SORT_OID;
+ ctrl->critical = crit;
+ control = talloc_array(ctrl, struct ldb_server_sort_control *, 2);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ control[0] = talloc(control, struct ldb_server_sort_control);
+ if (control[0] == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ control[0]->attributeName = talloc_strdup(control, attr);
+ if (control[0]->attributeName == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ if (rule[0]) {
+ control[0]->orderingRule = talloc_strdup(control, rule);
+ if (control[0]->orderingRule == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ } else {
+ control[0]->orderingRule = NULL;
+ }
+ control[0]->reverse = rev;
+ control[1] = NULL;
+ ctrl->data = control;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_NOTIFICATION_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_NOTIFICATION_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid notification control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_NOTIFICATION_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_TREE_DELETE_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_TREE_DELETE_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid tree_delete control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_TREE_DELETE_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_DELETED_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_SHOW_DELETED_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid show_deleted control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_SHOW_DELETED_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_DEACTIVATED_LINK_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_SHOW_DEACTIVATED_LINK_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid show_deactivated_link control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_SHOW_DEACTIVATED_LINK_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_RECYCLED_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_SHOW_RECYCLED_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid show_recycled control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_SHOW_RECYCLED_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PERMISSIVE_MODIFY_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_PERMISSIVE_MODIFY_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid permissive_modify control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_REVEAL_INTERNALS_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_REVEAL_INTERNALS_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid reveal_internals control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_REVEAL_INTERNALS;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (strncmp(control_strings, "local_oid:", 10) == 0) {
+ const char *p;
+ int crit = 0, ret = 0;
+ char oid[256];
+
+ oid[0] = '\0';
+ p = &(control_strings[10]);
+ ret = sscanf(p, "%255[^:]:%d", oid, &crit);
+
+ if ((ret != 2) || strlen(oid) == 0 || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid local_oid control syntax\n"
+ " syntax: oid(s):crit(b)\n"
+ " note: b = boolean, s = string");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = talloc_strdup(ctrl, oid);
+ if (!ctrl->oid) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RODC_DCPROMO_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_RODC_DCPROMO_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid rodc_join control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_RODC_DCPROMO_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PROVISION_NAME) == 0) {
+ const char *p;
+ int crit, ret;
+
+ p = &(control_strings[sizeof(LDB_CONTROL_PROVISION_NAME)]);
+ ret = sscanf(p, "%d", &crit);
+ if ((ret != 1) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid provision control syntax\n"
+ " syntax: crit(b)\n"
+ " note: b = boolean");
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ ctrl->oid = LDB_CONTROL_PROVISION_OID;
+ ctrl->critical = crit;
+ ctrl->data = NULL;
+
+ return ctrl;
+ }
+ if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_VERIFY_NAME_NAME) == 0) {
+ const char *p;
+ char gc[1024];
+ int crit, flags, ret;
+ struct ldb_verify_name_control *control;
+
+ gc[0] = '\0';
+
+ p = &(control_strings[sizeof(LDB_CONTROL_VERIFY_NAME_NAME)]);
+ ret = sscanf(p, "%d:%d:%1023[^$]", &crit, &flags, gc);
+ if ((ret != 3) || (crit < 0) || (crit > 1)) {
+ ret = sscanf(p, "%d:%d", &crit, &flags);
+ if ((ret != 2) || (crit < 0) || (crit > 1)) {
+ ldb_set_errstring(ldb,
+ "invalid verify_name control syntax\n"
+ " syntax: crit(b):flags(i)[:gc(s)]\n"
+ " note: b = boolean"
+ " note: i = integer"
+ " note: s = string");
+ talloc_free(ctrl);
+ return NULL;
+ }
+ }
+
+ ctrl->oid = LDB_CONTROL_VERIFY_NAME_OID;
+ ctrl->critical = crit;
+ control = talloc(ctrl, struct ldb_verify_name_control);
+ if (control == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ control->gc = talloc_strdup(control, gc);
+ if (control->gc == NULL) {
+ ldb_oom(ldb);
+ talloc_free(ctrl);
+ return NULL;
+ }
+
+ control->gc_len = strlen(gc);
+ control->flags = flags;
+ ctrl->data = control;
+ return ctrl;
+ }
+ /*
+ * When no matching control has been found.
+ */
+ TALLOC_FREE(ctrl);
+ return NULL;
+}
+
+/* Parse controls from the format used on the command line and in ejs */
+struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char **control_strings)
+{
+ unsigned int i;
+ struct ldb_control **ctrl;
+
+ if (control_strings == NULL || control_strings[0] == NULL)
+ return NULL;
+
+ for (i = 0; control_strings[i]; i++);
+
+ ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1);
+
+ ldb_reset_err_string(ldb);
+ for (i = 0; control_strings[i]; i++) {
+ ctrl[i] = ldb_parse_control_from_string(ldb, ctrl, control_strings[i]);
+ if (ctrl[i] == NULL) {
+ if (ldb_errstring(ldb) == NULL) {
+ /* no controls matched, throw an error */
+ ldb_asprintf_errstring(ldb, "Invalid control name: '%s'", control_strings[i]);
+ }
+ talloc_free(ctrl);
+ return NULL;
+ }
+ }
+
+ ctrl[i] = NULL;
+
+ return ctrl;
+}
+
+
diff --git a/lib/ldb/common/ldb_debug.c b/lib/ldb/common/ldb_debug.c
new file mode 100644
index 0000000..d5e9e7a
--- /dev/null
+++ b/lib/ldb/common/ldb_debug.c
@@ -0,0 +1,150 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb debug
+ *
+ * Description: functions for printing debug messages
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_private.h"
+
+/*
+ this allows the user to choose their own debug function
+*/
+int ldb_set_debug(struct ldb_context *ldb,
+ void (*debug)(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap),
+ void *context)
+{
+ ldb->debug_ops.debug = debug;
+ ldb->debug_ops.context = context;
+ return 0;
+}
+
+/*
+ debug function for ldb_set_debug_stderr
+*/
+static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap)
+{
+ if (level <= LDB_DEBUG_WARNING) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ }
+}
+
+static void ldb_debug_stderr_all(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+static void ldb_debug_stderr_all(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap)
+{
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+}
+
+/*
+ convenience function to setup debug messages on stderr
+ messages of level LDB_DEBUG_WARNING and higher are printed
+*/
+int ldb_set_debug_stderr(struct ldb_context *ldb)
+{
+ return ldb_set_debug(ldb, ldb_debug_stderr, ldb);
+}
+
+/*
+ log a message (va_list helper for ldb_tevent_debug)
+*/
+void ldb_vdebug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, va_list ap)
+{
+ if (ldb->debug_ops.debug == NULL) {
+ if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
+ ldb_set_debug(ldb, ldb_debug_stderr_all, ldb);
+ } else {
+ ldb_set_debug_stderr(ldb);
+ }
+ }
+ ldb->debug_ops.debug(ldb->debug_ops.context, level, fmt, ap);
+}
+
+/*
+ log a message
+*/
+void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ ldb_vdebug(ldb, level, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ add to an accumulated log message
+ */
+void ldb_debug_add(struct ldb_context *ldb, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (ldb->partial_debug == NULL) {
+ ldb->partial_debug = talloc_vasprintf(ldb, fmt, ap);
+ } else {
+ ldb->partial_debug = talloc_vasprintf_append(ldb->partial_debug,
+ fmt, ap);
+ }
+ va_end(ap);
+}
+
+/*
+ send the accumulated log message, and free it
+ */
+void ldb_debug_end(struct ldb_context *ldb, enum ldb_debug_level level)
+{
+ ldb_debug(ldb, level, "%s", ldb->partial_debug);
+ talloc_free(ldb->partial_debug);
+ ldb->partial_debug = NULL;
+}
+
+/*
+ log a message, and set the ldb error string to the same message
+*/
+void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+ va_start(ap, fmt);
+ msg = talloc_vasprintf(ldb, fmt, ap);
+ va_end(ap);
+ if (msg != NULL) {
+ ldb_set_errstring(ldb, msg);
+ ldb_debug(ldb, level, "%s", msg);
+ }
+ talloc_free(msg);
+}
+
diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c
new file mode 100644
index 0000000..601da57
--- /dev/null
+++ b/lib/ldb/common/ldb_dn.c
@@ -0,0 +1,2234 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb dn creation and manipulation utility functions
+ *
+ * Description: - explode a dn into it's own basic elements
+ * and put them in a structure (only if necessary)
+ * - manipulate ldb_dn structures
+ *
+ * Author: Simo Sorce
+ */
+
+#include "ldb_private.h"
+#include <ctype.h>
+
+#define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
+
+#define LDB_FREE(x) do { talloc_free(x); x = NULL; } while(0)
+
+/**
+ internal ldb exploded dn structures
+*/
+struct ldb_dn_component {
+
+ char *name;
+ struct ldb_val value;
+
+ char *cf_name;
+ struct ldb_val cf_value;
+};
+
+struct ldb_dn_ext_component {
+
+ const char *name;
+ struct ldb_val value;
+};
+
+struct ldb_dn {
+
+ struct ldb_context *ldb;
+
+ /* Special DNs are always linearized */
+ bool special;
+ bool invalid;
+
+ bool valid_case;
+
+ char *linearized;
+ char *ext_linearized;
+ char *casefold;
+
+ unsigned int comp_num;
+ struct ldb_dn_component *components;
+
+ unsigned int ext_comp_num;
+ struct ldb_dn_ext_component *ext_components;
+};
+
+/* it is helpful to be able to break on this in gdb */
+static void ldb_dn_mark_invalid(struct ldb_dn *dn)
+{
+ dn->invalid = true;
+}
+
+/* strdn may be NULL */
+struct ldb_dn *ldb_dn_from_ldb_val(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ const struct ldb_val *strdn)
+{
+ struct ldb_dn *dn;
+
+ if (ldb == NULL || strdn == NULL) {
+ return NULL;
+ }
+ if (strdn->data
+ && (strnlen((const char*)strdn->data, strdn->length) != strdn->length)) {
+ /* The RDN must not contain a character with value 0x0 */
+ return NULL;
+ }
+
+ dn = talloc_zero(mem_ctx, struct ldb_dn);
+ LDB_DN_NULL_FAILED(dn);
+
+ dn->ldb = talloc_get_type(ldb, struct ldb_context);
+ if (dn->ldb == NULL) {
+ /* the caller probably got the arguments to
+ ldb_dn_new() mixed up */
+ talloc_free(dn);
+ return NULL;
+ }
+
+ if (strdn->data && strdn->length) {
+ const char *data = (const char *)strdn->data;
+ size_t length = strdn->length;
+
+ if (data[0] == '@') {
+ dn->special = true;
+ }
+ dn->ext_linearized = talloc_strndup(dn, data, length);
+ LDB_DN_NULL_FAILED(dn->ext_linearized);
+
+ if (data[0] == '<') {
+ const char *p_save, *p = dn->ext_linearized;
+ do {
+ p_save = p;
+ p = strstr(p, ">;");
+ if (p) {
+ p = p + 2;
+ }
+ } while (p);
+
+ if (p_save == dn->ext_linearized) {
+ dn->linearized = talloc_strdup(dn, "");
+ } else {
+ dn->linearized = talloc_strdup(dn, p_save);
+ }
+ LDB_DN_NULL_FAILED(dn->linearized);
+ } else {
+ dn->linearized = dn->ext_linearized;
+ dn->ext_linearized = NULL;
+ }
+ } else {
+ dn->linearized = talloc_strdup(dn, "");
+ LDB_DN_NULL_FAILED(dn->linearized);
+ }
+
+ return dn;
+
+failed:
+ talloc_free(dn);
+ return NULL;
+}
+
+/* strdn may be NULL */
+struct ldb_dn *ldb_dn_new(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ const char *strdn)
+{
+ struct ldb_val blob;
+ blob.data = discard_const_p(uint8_t, strdn);
+ blob.length = strdn ? strlen(strdn) : 0;
+ return ldb_dn_from_ldb_val(mem_ctx, ldb, &blob);
+}
+
+struct ldb_dn *ldb_dn_new_fmt(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ const char *new_fmt, ...)
+{
+ char *strdn;
+ va_list ap;
+
+ if (! ldb) return NULL;
+
+ va_start(ap, new_fmt);
+ strdn = talloc_vasprintf(mem_ctx, new_fmt, ap);
+ va_end(ap);
+
+ if (strdn) {
+ struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, strdn);
+ talloc_free(strdn);
+ return dn;
+ }
+
+ return NULL;
+}
+
+/* see RFC2253 section 2.4 */
+static int ldb_dn_escape_internal(char *dst, const char *src, int len)
+{
+ char c;
+ char *d;
+ int i;
+ d = dst;
+
+ for (i = 0; i < len; i++){
+ c = src[i];
+ switch (c) {
+ case ' ':
+ if (i == 0 || i == len - 1) {
+ /* if at the beginning or end
+ * of the string then escape */
+ *d++ = '\\';
+ *d++ = c;
+ } else {
+ /* otherwise don't escape */
+ *d++ = c;
+ }
+ break;
+
+ case '#':
+ /* despite the RFC, windows escapes a #
+ anywhere in the string */
+ case ',':
+ case '+':
+ case '"':
+ case '\\':
+ case '<':
+ case '>':
+ case '?':
+ /* these must be escaped using \c form */
+ *d++ = '\\';
+ *d++ = c;
+ break;
+
+ case ';':
+ case '\r':
+ case '\n':
+ case '=':
+ case '\0': {
+ /* any others get \XX form */
+ unsigned char v;
+ const char *hexbytes = "0123456789ABCDEF";
+ v = (const unsigned char)c;
+ *d++ = '\\';
+ *d++ = hexbytes[v>>4];
+ *d++ = hexbytes[v&0xF];
+ break;
+ }
+ default:
+ *d++ = c;
+ }
+ }
+
+ /* return the length of the resulting string */
+ return (d - dst);
+}
+
+char *ldb_dn_escape_value(TALLOC_CTX *mem_ctx, struct ldb_val value)
+{
+ char *dst;
+ size_t len;
+ if (!value.length)
+ return NULL;
+
+ /* allocate destination string, it will be at most 3 times the source */
+ dst = talloc_array(mem_ctx, char, value.length * 3 + 1);
+ if ( ! dst) {
+ talloc_free(dst);
+ return NULL;
+ }
+
+ len = ldb_dn_escape_internal(dst, (const char *)value.data, value.length);
+
+ dst = talloc_realloc(mem_ctx, dst, char, len + 1);
+ if ( ! dst) {
+ talloc_free(dst);
+ return NULL;
+ }
+ dst[len] = '\0';
+ return dst;
+}
+
+/*
+ explode a DN string into a ldb_dn structure
+ based on RFC4514 except that we don't support multiple valued RDNs
+
+ TODO: according to MS-ADTS:3.1.1.5.2 Naming Constraints
+ DN must be compliant with RFC2253
+*/
+static bool ldb_dn_explode(struct ldb_dn *dn)
+{
+ char *p, *ex_name = NULL, *ex_value = NULL, *data, *d, *dt, *t;
+ bool trim = true;
+ bool in_extended = true;
+ bool in_ex_name = false;
+ bool in_ex_value = false;
+ bool in_attr = false;
+ bool in_value = false;
+ bool in_quote = false;
+ bool is_oid = false;
+ bool escape = false;
+ unsigned int x;
+ size_t l = 0;
+ int ret;
+ char *parse_dn;
+ bool is_index;
+
+ if (dn == NULL || dn->invalid) {
+ return false;
+ }
+
+ if (dn->components != NULL) {
+ return true;
+ }
+
+ if (dn->ext_linearized != NULL) {
+ parse_dn = dn->ext_linearized;
+ } else {
+ parse_dn = dn->linearized;
+ }
+
+ if (parse_dn == NULL) {
+ return false;
+ }
+
+ is_index = (strncmp(parse_dn, "DN=@INDEX:", 10) == 0);
+
+ /* Empty DNs */
+ if (parse_dn[0] == '\0') {
+ return true;
+ }
+
+ /* Special DNs case */
+ if (dn->special) {
+ return true;
+ }
+
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+ dn->comp_num = 0;
+
+ /* in the common case we have 3 or more components */
+ /* make sure all components are zeroed, other functions depend on it */
+ dn->components = talloc_zero_array(dn, struct ldb_dn_component, 3);
+ if (dn->components == NULL) {
+ return false;
+ }
+
+ /* Components data space is allocated here once */
+ data = talloc_array(dn->components, char, strlen(parse_dn) + 1);
+ if (data == NULL) {
+ goto failed;
+ }
+
+ p = parse_dn;
+ t = NULL;
+ d = dt = data;
+
+ while (*p) {
+ if (in_extended) {
+
+ if (!in_ex_name && !in_ex_value) {
+
+ if (p[0] == '<') {
+ p++;
+ ex_name = d;
+ in_ex_name = true;
+ continue;
+ } else {
+ in_extended = false;
+ in_attr = true;
+ dt = d;
+
+ continue;
+ }
+ }
+
+ if (in_ex_name && *p == '=') {
+ *d++ = '\0';
+ p++;
+ ex_value = d;
+ in_ex_name = false;
+ in_ex_value = true;
+ continue;
+ }
+
+ if (in_ex_value && *p == '>') {
+ struct ldb_dn_ext_component *ext_comp = NULL;
+ const struct ldb_dn_extended_syntax *ext_syntax;
+ struct ldb_val ex_val = {
+ .data = (uint8_t *)ex_value,
+ .length = d - ex_value
+ };
+
+ *d++ = '\0';
+ p++;
+ in_ex_value = false;
+
+ /* Process name and ex_value */
+
+ ext_comp = talloc_realloc(
+ dn,
+ dn->ext_components,
+ struct ldb_dn_ext_component,
+ dn->ext_comp_num + 1);
+
+ if (ext_comp == NULL) {
+ /* ouch ! */
+ goto failed;
+ }
+
+ dn->ext_components = ext_comp;
+
+ ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, ex_name);
+ if (ext_syntax == NULL) {
+ /* We don't know about this type of extended DN */
+ goto failed;
+ }
+
+ dn->ext_components[dn->ext_comp_num].name = ext_syntax->name;
+ ret = ext_syntax->read_fn(dn->ldb, dn->ext_components,
+ &ex_val, &dn->ext_components[dn->ext_comp_num].value);
+ if (ret != LDB_SUCCESS) {
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+
+ dn->ext_comp_num++;
+
+ if (*p == '\0') {
+ /* We have reached the end (extended component only)! */
+ talloc_free(data);
+ return true;
+
+ } else if (*p == ';') {
+ p++;
+ continue;
+ } else {
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+ }
+
+ *d++ = *p++;
+ continue;
+ }
+ if (in_attr) {
+ if (trim) {
+ if (*p == ' ') {
+ p++;
+ continue;
+ }
+
+ /* first char */
+ trim = false;
+
+ if (!isascii(*p)) {
+ /* attr names must be ascii only */
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+
+ if (isdigit(*p)) {
+ is_oid = true;
+ } else
+ if ( ! isalpha(*p)) {
+ /* not a digit nor an alpha,
+ * invalid attribute name */
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+
+ /* Copy this character across from parse_dn,
+ * now we have trimmed out spaces */
+ *d++ = *p++;
+ continue;
+ }
+
+ if (*p == ' ') {
+ p++;
+ /* valid only if we are at the end */
+ trim = true;
+ continue;
+ }
+
+ if (*p == '=') {
+ /* attribute terminated */
+ in_attr = false;
+ in_value = true;
+ trim = true;
+ l = 0;
+
+ /* Terminate this string in d
+ * (which is a copy of parse_dn
+ * with spaces trimmed) */
+ *d++ = '\0';
+ dn->components[dn->comp_num].name = talloc_strdup(dn->components, dt);
+ if (dn->components[dn->comp_num].name == NULL) {
+ /* ouch */
+ goto failed;
+ }
+
+ dt = d;
+
+ p++;
+ continue;
+ }
+
+ if (!isascii(*p)) {
+ /* attr names must be ascii only */
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+
+ if (is_oid && ( ! (isdigit(*p) || (*p == '.')))) {
+ /* not a digit nor a dot,
+ * invalid attribute oid */
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ } else
+ if ( ! (isalpha(*p) || isdigit(*p) || (*p == '-'))) {
+ /* not ALPHA, DIGIT or HYPHEN */
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+
+ *d++ = *p++;
+ continue;
+ }
+
+ if (in_value) {
+ if (in_quote) {
+ if (*p == '\"') {
+ if (p[-1] != '\\') {
+ p++;
+ in_quote = false;
+ continue;
+ }
+ }
+ *d++ = *p++;
+ l++;
+ continue;
+ }
+
+ if (trim) {
+ if (*p == ' ') {
+ p++;
+ continue;
+ }
+
+ /* first char */
+ trim = false;
+
+ if (*p == '\"') {
+ in_quote = true;
+ p++;
+ continue;
+ }
+ }
+
+ switch (*p) {
+
+ /* TODO: support ber encoded values
+ case '#':
+ */
+
+ case ',':
+ if (escape) {
+ *d++ = *p++;
+ l++;
+ escape = false;
+ continue;
+ }
+ /* ok found value terminator */
+
+ if (t != NULL) {
+ /* trim back */
+ d -= (p - t);
+ l -= (p - t);
+ t = NULL;
+ }
+
+ in_attr = true;
+ in_value = false;
+ trim = true;
+
+ p++;
+ *d++ = '\0';
+
+ /*
+ * This talloc_memdup() is OK with the
+ * +1 because *d has been set to '\0'
+ * just above
+ */
+ dn->components[dn->comp_num].value.data = \
+ (uint8_t *)talloc_memdup(dn->components, dt, l + 1);
+ dn->components[dn->comp_num].value.length = l;
+ if (dn->components[dn->comp_num].value.data == NULL) {
+ /* ouch ! */
+ goto failed;
+ }
+ talloc_set_name_const(dn->components[dn->comp_num].value.data,
+ (const char *)dn->components[dn->comp_num].value.data);
+
+ dt = d;
+
+ dn->comp_num++;
+ if (dn->comp_num > 2) {
+ dn->components = talloc_realloc(dn,
+ dn->components,
+ struct ldb_dn_component,
+ dn->comp_num + 1);
+ if (dn->components == NULL) {
+ /* ouch ! */
+ goto failed;
+ }
+ /* make sure all components are zeroed, other functions depend on this */
+ memset(&dn->components[dn->comp_num], '\0', sizeof(struct ldb_dn_component));
+ }
+
+ continue;
+
+ case '+':
+ case '=':
+ /* to main compatibility with earlier
+ versions of ldb indexing, we have to
+ accept the base64 encoded binary index
+ values, which contain a '+' or '='
+ which should normally be escaped */
+ if (is_index) {
+ if (t != NULL) {
+ t = NULL;
+ }
+ *d++ = *p++;
+ l++;
+ break;
+ }
+
+ FALL_THROUGH;
+ case '\"':
+ case '<':
+ case '>':
+ case ';':
+ /* a string with not escaped specials is invalid (tested) */
+ if (!escape) {
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+ escape = false;
+
+ *d++ = *p++;
+ l++;
+
+ if (t != NULL) {
+ t = NULL;
+ }
+ break;
+
+ case '\\':
+ if (!escape) {
+ escape = true;
+ p++;
+ continue;
+ }
+ escape = false;
+
+ *d++ = *p++;
+ l++;
+
+ if (t != NULL) {
+ t = NULL;
+ }
+ break;
+
+ default:
+ if (escape) {
+ if (isxdigit(p[0]) && isxdigit(p[1])) {
+ if (sscanf(p, "%02x", &x) != 1) {
+ /* invalid escaping sequence */
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+ p += 2;
+ *d++ = (unsigned char)x;
+ } else {
+ *d++ = *p++;
+ }
+
+ escape = false;
+ l++;
+ if (t != NULL) {
+ t = NULL;
+ }
+ break;
+ }
+
+ if (*p == ' ') {
+ if (t == NULL) {
+ t = p;
+ }
+ } else {
+ if (t != NULL) {
+ t = NULL;
+ }
+ }
+
+ *d++ = *p++;
+ l++;
+
+ break;
+ }
+
+ }
+ }
+
+ if (in_attr || in_quote) {
+ /* invalid dn */
+ ldb_dn_mark_invalid(dn);
+ goto failed;
+ }
+
+ if (in_value) {
+ /* save last element */
+ if (t != NULL) {
+ /* trim back */
+ d -= (p - t);
+ l -= (p - t);
+ }
+
+ *d++ = '\0';
+ /*
+ * This talloc_memdup() is OK with the
+ * +1 because *d has been set to '\0'
+ * just above.
+ */
+ dn->components[dn->comp_num].value.length = l;
+ dn->components[dn->comp_num].value.data =
+ (uint8_t *)talloc_memdup(dn->components, dt, l + 1);
+ if (dn->components[dn->comp_num].value.data == NULL) {
+ /* ouch */
+ goto failed;
+ }
+ talloc_set_name_const(dn->components[dn->comp_num].value.data,
+ (const char *)dn->components[dn->comp_num].value.data);
+
+ dn->comp_num++;
+ }
+ talloc_free(data);
+ return true;
+
+failed:
+ LDB_FREE(dn->components); /* "data" is implicitly free'd */
+ dn->comp_num = 0;
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+
+ return false;
+}
+
+bool ldb_dn_validate(struct ldb_dn *dn)
+{
+ return ldb_dn_explode(dn);
+}
+
+const char *ldb_dn_get_linearized(struct ldb_dn *dn)
+{
+ unsigned int i;
+ size_t len;
+ char *d, *n;
+
+ if ( ! dn || ( dn->invalid)) return NULL;
+
+ if (dn->linearized) return dn->linearized;
+
+ if ( ! dn->components) {
+ ldb_dn_mark_invalid(dn);
+ return NULL;
+ }
+
+ if (dn->comp_num == 0) {
+ dn->linearized = talloc_strdup(dn, "");
+ if ( ! dn->linearized) return NULL;
+ return dn->linearized;
+ }
+
+ /* calculate maximum possible length of DN */
+ for (len = 0, i = 0; i < dn->comp_num; i++) {
+ /* name len */
+ len += strlen(dn->components[i].name);
+ /* max escaped data len */
+ len += (dn->components[i].value.length * 3);
+ len += 2; /* '=' and ',' */
+ }
+ dn->linearized = talloc_array(dn, char, len);
+ if ( ! dn->linearized) return NULL;
+
+ d = dn->linearized;
+
+ for (i = 0; i < dn->comp_num; i++) {
+
+ /* copy the name */
+ n = dn->components[i].name;
+ while (*n) *d++ = *n++;
+
+ *d++ = '=';
+
+ /* and the value */
+ d += ldb_dn_escape_internal( d,
+ (char *)dn->components[i].value.data,
+ dn->components[i].value.length);
+ *d++ = ',';
+ }
+
+ *(--d) = '\0';
+
+ /* don't waste more memory than necessary */
+ dn->linearized = talloc_realloc(dn, dn->linearized,
+ char, (d - dn->linearized + 1));
+
+ return dn->linearized;
+}
+
+static int ldb_dn_extended_component_compare(const void *p1, const void *p2)
+{
+ const struct ldb_dn_ext_component *ec1 = (const struct ldb_dn_ext_component *)p1;
+ const struct ldb_dn_ext_component *ec2 = (const struct ldb_dn_ext_component *)p2;
+ return strcmp(ec1->name, ec2->name);
+}
+
+char *ldb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, int mode)
+{
+ const char *linearized = ldb_dn_get_linearized(dn);
+ char *p = NULL;
+ unsigned int i;
+
+ if (!linearized) {
+ return NULL;
+ }
+
+ if (!ldb_dn_has_extended(dn)) {
+ return talloc_strdup(mem_ctx, linearized);
+ }
+
+ if (!ldb_dn_validate(dn)) {
+ return NULL;
+ }
+
+ /* sort the extended components by name. The idea is to make
+ * the resulting DNs consistent, plus to ensure that we put
+ * 'DELETED' first, so it can be very quickly recognised
+ */
+ TYPESAFE_QSORT(dn->ext_components, dn->ext_comp_num,
+ ldb_dn_extended_component_compare);
+
+ for (i = 0; i < dn->ext_comp_num; i++) {
+ const struct ldb_dn_extended_syntax *ext_syntax;
+ const char *name = dn->ext_components[i].name;
+ struct ldb_val ec_val = dn->ext_components[i].value;
+ struct ldb_val val;
+ int ret;
+
+ ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, name);
+ if (!ext_syntax) {
+ return NULL;
+ }
+
+ if (mode == 1) {
+ ret = ext_syntax->write_clear_fn(dn->ldb, mem_ctx,
+ &ec_val, &val);
+ } else if (mode == 0) {
+ ret = ext_syntax->write_hex_fn(dn->ldb, mem_ctx,
+ &ec_val, &val);
+ } else {
+ ret = -1;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ return NULL;
+ }
+
+ if (i == 0) {
+ p = talloc_asprintf(mem_ctx, "<%s=%.*s>",
+ name,
+ (int)val.length,
+ val.data);
+ } else {
+ talloc_asprintf_addbuf(&p, ";<%s=%.*s>",
+ name,
+ (int)val.length,
+ val.data);
+ }
+
+ talloc_free(val.data);
+ }
+
+ if (dn->ext_comp_num && *linearized) {
+ talloc_asprintf_addbuf(&p, ";%s", linearized);
+ }
+
+ if (!p) {
+ return NULL;
+ }
+
+ return p;
+}
+
+/*
+ filter out all but an acceptable list of extended DN components
+ */
+void ldb_dn_extended_filter(struct ldb_dn *dn, const char * const *accept_list)
+{
+ unsigned int i;
+ for (i=0; i<dn->ext_comp_num; i++) {
+ if (!ldb_attr_in_list(accept_list, dn->ext_components[i].name)) {
+ ARRAY_DEL_ELEMENT(
+ dn->ext_components, i, dn->ext_comp_num);
+ dn->ext_comp_num--;
+ i--;
+ }
+ }
+ LDB_FREE(dn->ext_linearized);
+}
+
+
+char *ldb_dn_alloc_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
+{
+ return talloc_strdup(mem_ctx, ldb_dn_get_linearized(dn));
+}
+
+/*
+ casefold a dn. We need to casefold the attribute names, and canonicalize
+ attribute values of case insensitive attributes.
+*/
+
+static bool ldb_dn_casefold_internal(struct ldb_dn *dn)
+{
+ unsigned int i;
+ int ret;
+
+ if ( ! dn || dn->invalid) return false;
+
+ if (dn->valid_case) return true;
+
+ if (( ! dn->components) && ( ! ldb_dn_explode(dn))) {
+ return false;
+ }
+
+ for (i = 0; i < dn->comp_num; i++) {
+ const struct ldb_schema_attribute *a;
+
+ dn->components[i].cf_name =
+ ldb_attr_casefold(dn->components,
+ dn->components[i].name);
+ if (!dn->components[i].cf_name) {
+ goto failed;
+ }
+
+ a = ldb_schema_attribute_by_name(dn->ldb,
+ dn->components[i].cf_name);
+
+ ret = a->syntax->canonicalise_fn(dn->ldb, dn->components,
+ &(dn->components[i].value),
+ &(dn->components[i].cf_value));
+ if (ret != 0) {
+ goto failed;
+ }
+ }
+
+ dn->valid_case = true;
+
+ return true;
+
+failed:
+ for (i = 0; i < dn->comp_num; i++) {
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+ return false;
+}
+
+const char *ldb_dn_get_casefold(struct ldb_dn *dn)
+{
+ unsigned int i;
+ size_t len;
+ char *d, *n;
+
+ if (dn->casefold) return dn->casefold;
+
+ if (dn->special) {
+ dn->casefold = talloc_strdup(dn, dn->linearized);
+ if (!dn->casefold) return NULL;
+ dn->valid_case = true;
+ return dn->casefold;
+ }
+
+ if ( ! ldb_dn_casefold_internal(dn)) {
+ return NULL;
+ }
+
+ if (dn->comp_num == 0) {
+ dn->casefold = talloc_strdup(dn, "");
+ return dn->casefold;
+ }
+
+ /* calculate maximum possible length of DN */
+ for (len = 0, i = 0; i < dn->comp_num; i++) {
+ /* name len */
+ len += strlen(dn->components[i].cf_name);
+ /* max escaped data len */
+ len += (dn->components[i].cf_value.length * 3);
+ len += 2; /* '=' and ',' */
+ }
+ dn->casefold = talloc_array(dn, char, len);
+ if ( ! dn->casefold) return NULL;
+
+ d = dn->casefold;
+
+ for (i = 0; i < dn->comp_num; i++) {
+
+ /* copy the name */
+ n = dn->components[i].cf_name;
+ while (*n) *d++ = *n++;
+
+ *d++ = '=';
+
+ /* and the value */
+ d += ldb_dn_escape_internal( d,
+ (char *)dn->components[i].cf_value.data,
+ dn->components[i].cf_value.length);
+ *d++ = ',';
+ }
+ *(--d) = '\0';
+
+ /* don't waste more memory than necessary */
+ dn->casefold = talloc_realloc(dn, dn->casefold,
+ char, strlen(dn->casefold) + 1);
+
+ return dn->casefold;
+}
+
+char *ldb_dn_alloc_casefold(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
+{
+ return talloc_strdup(mem_ctx, ldb_dn_get_casefold(dn));
+}
+
+/* Determine if dn is below base, in the ldap tree. Used for
+ * evaluating a subtree search.
+ * 0 if they match, otherwise non-zero
+ */
+
+int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn)
+{
+ int ret;
+ unsigned int n_base, n_dn;
+
+ if ( ! base || base->invalid) return 1;
+ if ( ! dn || dn->invalid) return -1;
+
+ if (( ! base->valid_case) || ( ! dn->valid_case)) {
+ if (base->linearized && dn->linearized && dn->special == base->special) {
+ /* try with a normal compare first, if we are lucky
+ * we will avoid exploding and casefolding */
+ int dif;
+ dif = strlen(dn->linearized) - strlen(base->linearized);
+ if (dif < 0) {
+ return dif;
+ }
+ if (strcmp(base->linearized,
+ &dn->linearized[dif]) == 0) {
+ return 0;
+ }
+ }
+
+ if ( ! ldb_dn_casefold_internal(base)) {
+ return 1;
+ }
+
+ if ( ! ldb_dn_casefold_internal(dn)) {
+ return -1;
+ }
+
+ }
+
+ /* if base has more components,
+ * they don't have the same base */
+ if (base->comp_num > dn->comp_num) {
+ return (dn->comp_num - base->comp_num);
+ }
+
+ if ((dn->comp_num == 0) || (base->comp_num == 0)) {
+ if (dn->special && base->special) {
+ return strcmp(base->linearized, dn->linearized);
+ } else if (dn->special) {
+ return -1;
+ } else if (base->special) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ n_base = base->comp_num - 1;
+ n_dn = dn->comp_num - 1;
+
+ while (n_base != (unsigned int) -1) {
+ char *b_name = base->components[n_base].cf_name;
+ char *dn_name = dn->components[n_dn].cf_name;
+
+ char *b_vdata = (char *)base->components[n_base].cf_value.data;
+ char *dn_vdata = (char *)dn->components[n_dn].cf_value.data;
+
+ size_t b_vlen = base->components[n_base].cf_value.length;
+ size_t dn_vlen = dn->components[n_dn].cf_value.length;
+
+ /* compare attr names */
+ ret = strcmp(b_name, dn_name);
+ if (ret != 0) return ret;
+
+ /* compare attr.cf_value. */
+ if (b_vlen != dn_vlen) {
+ return b_vlen - dn_vlen;
+ }
+ ret = strncmp(b_vdata, dn_vdata, b_vlen);
+ if (ret != 0) return ret;
+
+ n_base--;
+ n_dn--;
+ }
+
+ return 0;
+}
+
+/* compare DNs using casefolding compare functions.
+
+ If they match, then return 0
+ */
+
+int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
+{
+ unsigned int i;
+ int ret;
+
+ if (( ! dn0) || dn0->invalid || ! dn1 || dn1->invalid) {
+ return -1;
+ }
+
+ if (( ! dn0->valid_case) || ( ! dn1->valid_case)) {
+ if (dn0->linearized && dn1->linearized) {
+ /* try with a normal compare first, if we are lucky
+ * we will avoid exploding and casefolding */
+ if (strcmp(dn0->linearized, dn1->linearized) == 0) {
+ return 0;
+ }
+ }
+
+ if ( ! ldb_dn_casefold_internal(dn0)) {
+ return 1;
+ }
+
+ if ( ! ldb_dn_casefold_internal(dn1)) {
+ return -1;
+ }
+
+ }
+
+ if (dn0->comp_num != dn1->comp_num) {
+ return (dn1->comp_num - dn0->comp_num);
+ }
+
+ if (dn0->comp_num == 0) {
+ if (dn0->special && dn1->special) {
+ return strcmp(dn0->linearized, dn1->linearized);
+ } else if (dn0->special) {
+ return 1;
+ } else if (dn1->special) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ for (i = 0; i < dn0->comp_num; i++) {
+ char *dn0_name = dn0->components[i].cf_name;
+ char *dn1_name = dn1->components[i].cf_name;
+
+ char *dn0_vdata = (char *)dn0->components[i].cf_value.data;
+ char *dn1_vdata = (char *)dn1->components[i].cf_value.data;
+
+ size_t dn0_vlen = dn0->components[i].cf_value.length;
+ size_t dn1_vlen = dn1->components[i].cf_value.length;
+
+ /* compare attr names */
+ ret = strcmp(dn0_name, dn1_name);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* compare attr.cf_value. */
+ if (dn0_vlen != dn1_vlen) {
+ return dn0_vlen - dn1_vlen;
+ }
+ ret = strncmp(dn0_vdata, dn1_vdata, dn0_vlen);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct ldb_dn_component ldb_dn_copy_component(
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn_component *src)
+{
+ struct ldb_dn_component dst;
+
+ memset(&dst, 0, sizeof(dst));
+
+ if (src == NULL) {
+ return dst;
+ }
+
+ dst.value = ldb_val_dup(mem_ctx, &(src->value));
+ if (dst.value.data == NULL) {
+ return dst;
+ }
+
+ dst.name = talloc_strdup(mem_ctx, src->name);
+ if (dst.name == NULL) {
+ LDB_FREE(dst.value.data);
+ return dst;
+ }
+
+ if (src->cf_value.data) {
+ dst.cf_value = ldb_val_dup(mem_ctx, &(src->cf_value));
+ if (dst.cf_value.data == NULL) {
+ LDB_FREE(dst.value.data);
+ LDB_FREE(dst.name);
+ return dst;
+ }
+
+ dst.cf_name = talloc_strdup(mem_ctx, src->cf_name);
+ if (dst.cf_name == NULL) {
+ LDB_FREE(dst.cf_name);
+ LDB_FREE(dst.value.data);
+ LDB_FREE(dst.name);
+ return dst;
+ }
+ } else {
+ dst.cf_value.data = NULL;
+ dst.cf_name = NULL;
+ }
+
+ return dst;
+}
+
+static struct ldb_dn_ext_component ldb_dn_ext_copy_component(
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn_ext_component *src)
+{
+ struct ldb_dn_ext_component dst;
+
+ memset(&dst, 0, sizeof(dst));
+
+ if (src == NULL) {
+ return dst;
+ }
+
+ dst.value = ldb_val_dup(mem_ctx, &(src->value));
+ if (dst.value.data == NULL) {
+ return dst;
+ }
+
+ dst.name = talloc_strdup(mem_ctx, src->name);
+ if (dst.name == NULL) {
+ LDB_FREE(dst.value.data);
+ return dst;
+ }
+
+ return dst;
+}
+
+struct ldb_dn *ldb_dn_copy(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
+{
+ struct ldb_dn *new_dn;
+
+ if (!dn || dn->invalid) {
+ return NULL;
+ }
+
+ new_dn = talloc_zero(mem_ctx, struct ldb_dn);
+ if ( !new_dn) {
+ return NULL;
+ }
+
+ *new_dn = *dn;
+
+ if (dn->components) {
+ unsigned int i;
+
+ new_dn->components =
+ talloc_zero_array(new_dn,
+ struct ldb_dn_component,
+ dn->comp_num);
+ if ( ! new_dn->components) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ for (i = 0; i < dn->comp_num; i++) {
+ new_dn->components[i] =
+ ldb_dn_copy_component(new_dn->components,
+ &dn->components[i]);
+ if ( ! new_dn->components[i].value.data) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+ }
+ }
+
+ if (dn->ext_components) {
+ unsigned int i;
+
+ new_dn->ext_components =
+ talloc_zero_array(new_dn,
+ struct ldb_dn_ext_component,
+ dn->ext_comp_num);
+ if ( ! new_dn->ext_components) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ for (i = 0; i < dn->ext_comp_num; i++) {
+ new_dn->ext_components[i] =
+ ldb_dn_ext_copy_component(
+ new_dn->ext_components,
+ &dn->ext_components[i]);
+ if ( ! new_dn->ext_components[i].value.data) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+ }
+ }
+
+ if (dn->casefold) {
+ new_dn->casefold = talloc_strdup(new_dn, dn->casefold);
+ if ( ! new_dn->casefold) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+ }
+
+ if (dn->linearized) {
+ new_dn->linearized = talloc_strdup(new_dn, dn->linearized);
+ if ( ! new_dn->linearized) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+ }
+
+ if (dn->ext_linearized) {
+ new_dn->ext_linearized = talloc_strdup(new_dn,
+ dn->ext_linearized);
+ if ( ! new_dn->ext_linearized) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+ }
+
+ return new_dn;
+}
+
+/* modify the given dn by adding a base.
+ *
+ * return true if successful and false if not
+ * if false is returned the dn may be marked invalid
+ */
+bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base)
+{
+ const char *s;
+ char *t;
+
+ if ( !base || base->invalid || !dn || dn->invalid) {
+ return false;
+ }
+
+ if (dn == base) {
+ return false; /* or we will visit infinity */
+ }
+
+ if (dn->components) {
+ unsigned int i;
+
+ if ( ! ldb_dn_validate(base)) {
+ return false;
+ }
+
+ s = NULL;
+ if (dn->valid_case) {
+ if ( ! (s = ldb_dn_get_casefold(base))) {
+ return false;
+ }
+ }
+
+ dn->components = talloc_realloc(dn,
+ dn->components,
+ struct ldb_dn_component,
+ dn->comp_num + base->comp_num);
+ if ( ! dn->components) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+
+ for (i = 0; i < base->comp_num; dn->comp_num++, i++) {
+ dn->components[dn->comp_num] =
+ ldb_dn_copy_component(dn->components,
+ &base->components[i]);
+ if (dn->components[dn->comp_num].value.data == NULL) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+ }
+
+ if (dn->casefold && s) {
+ if (*dn->casefold) {
+ t = talloc_asprintf(dn, "%s,%s",
+ dn->casefold, s);
+ } else {
+ t = talloc_strdup(dn, s);
+ }
+ LDB_FREE(dn->casefold);
+ dn->casefold = t;
+ }
+ }
+
+ if (dn->linearized) {
+
+ s = ldb_dn_get_linearized(base);
+ if ( ! s) {
+ return false;
+ }
+
+ if (*dn->linearized) {
+ t = talloc_asprintf(dn, "%s,%s",
+ dn->linearized, s);
+ } else {
+ t = talloc_strdup(dn, s);
+ }
+ if ( ! t) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+ LDB_FREE(dn->linearized);
+ dn->linearized = t;
+ }
+
+ /* Wipe the ext_linearized DN,
+ * the GUID and SID are almost certainly no longer valid */
+ LDB_FREE(dn->ext_linearized);
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+
+ return true;
+}
+
+/* modify the given dn by adding a base.
+ *
+ * return true if successful and false if not
+ * if false is returned the dn may be marked invalid
+ */
+bool ldb_dn_add_base_fmt(struct ldb_dn *dn, const char *base_fmt, ...)
+{
+ struct ldb_dn *base;
+ char *base_str;
+ va_list ap;
+ bool ret;
+
+ if ( !dn || dn->invalid) {
+ return false;
+ }
+
+ va_start(ap, base_fmt);
+ base_str = talloc_vasprintf(dn, base_fmt, ap);
+ va_end(ap);
+
+ if (base_str == NULL) {
+ return false;
+ }
+
+ base = ldb_dn_new(base_str, dn->ldb, base_str);
+
+ ret = ldb_dn_add_base(dn, base);
+
+ talloc_free(base_str);
+
+ return ret;
+}
+
+/* modify the given dn by adding children elements.
+ *
+ * return true if successful and false if not
+ * if false is returned the dn may be marked invalid
+ */
+bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child)
+{
+ const char *s;
+ char *t;
+
+ if ( !child || child->invalid || !dn || dn->invalid) {
+ return false;
+ }
+
+ if (dn->components) {
+ unsigned int n;
+ unsigned int i, j;
+
+ if (dn->comp_num == 0) {
+ return false;
+ }
+
+ if ( ! ldb_dn_validate(child)) {
+ return false;
+ }
+
+ s = NULL;
+ if (dn->valid_case) {
+ if ( ! (s = ldb_dn_get_casefold(child))) {
+ return false;
+ }
+ }
+
+ n = dn->comp_num + child->comp_num;
+
+ dn->components = talloc_realloc(dn,
+ dn->components,
+ struct ldb_dn_component,
+ n);
+ if ( ! dn->components) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+
+ for (i = dn->comp_num - 1, j = n - 1; i != (unsigned int) -1;
+ i--, j--) {
+ dn->components[j] = dn->components[i];
+ }
+
+ for (i = 0; i < child->comp_num; i++) {
+ dn->components[i] =
+ ldb_dn_copy_component(dn->components,
+ &child->components[i]);
+ if (dn->components[i].value.data == NULL) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+ }
+
+ dn->comp_num = n;
+
+ if (dn->casefold && s) {
+ t = talloc_asprintf(dn, "%s,%s", s, dn->casefold);
+ LDB_FREE(dn->casefold);
+ dn->casefold = t;
+ }
+ }
+
+ if (dn->linearized) {
+ if (dn->linearized[0] == '\0') {
+ return false;
+ }
+
+ s = ldb_dn_get_linearized(child);
+ if ( ! s) {
+ return false;
+ }
+
+ t = talloc_asprintf(dn, "%s,%s", s, dn->linearized);
+ if ( ! t) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+ LDB_FREE(dn->linearized);
+ dn->linearized = t;
+ }
+
+ /* Wipe the ext_linearized DN,
+ * the GUID and SID are almost certainly no longer valid */
+ LDB_FREE(dn->ext_linearized);
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+
+ return true;
+}
+
+/* modify the given dn by adding children elements.
+ *
+ * return true if successful and false if not
+ * if false is returned the dn may be marked invalid
+ */
+bool ldb_dn_add_child_fmt(struct ldb_dn *dn, const char *child_fmt, ...)
+{
+ struct ldb_dn *child;
+ char *child_str;
+ va_list ap;
+ bool ret;
+
+ if ( !dn || dn->invalid) {
+ return false;
+ }
+
+ va_start(ap, child_fmt);
+ child_str = talloc_vasprintf(dn, child_fmt, ap);
+ va_end(ap);
+
+ if (child_str == NULL) {
+ return false;
+ }
+
+ child = ldb_dn_new(child_str, dn->ldb, child_str);
+
+ ret = ldb_dn_add_child(dn, child);
+
+ talloc_free(child_str);
+
+ return ret;
+}
+
+/* modify the given dn by adding a single child element.
+ *
+ * return true if successful and false if not
+ * if false is returned the dn may be marked invalid
+ */
+bool ldb_dn_add_child_val(struct ldb_dn *dn,
+ const char *rdn,
+ struct ldb_val value)
+{
+ bool ret;
+ int ldb_ret;
+ struct ldb_dn *child = NULL;
+
+ if ( !dn || dn->invalid) {
+ return false;
+ }
+
+ child = ldb_dn_new(dn, dn->ldb, "X=Y");
+ ret = ldb_dn_add_child(dn, child);
+
+ if (ret == false) {
+ return false;
+ }
+
+ ldb_ret = ldb_dn_set_component(dn,
+ 0,
+ rdn,
+ value);
+ if (ldb_ret != LDB_SUCCESS) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num)
+{
+ unsigned int i;
+
+ if ( ! ldb_dn_validate(dn)) {
+ return false;
+ }
+
+ if (dn->comp_num < num) {
+ return false;
+ }
+
+ /* free components */
+ for (i = dn->comp_num - num; i < dn->comp_num; i++) {
+ LDB_FREE(dn->components[i].name);
+ LDB_FREE(dn->components[i].value.data);
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+
+ dn->comp_num -= num;
+
+ if (dn->valid_case) {
+ for (i = 0; i < dn->comp_num; i++) {
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+ dn->valid_case = false;
+ }
+
+ LDB_FREE(dn->casefold);
+ LDB_FREE(dn->linearized);
+
+ /* Wipe the ext_linearized DN,
+ * the GUID and SID are almost certainly no longer valid */
+ LDB_FREE(dn->ext_linearized);
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+
+ return true;
+}
+
+bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num)
+{
+ unsigned int i, j;
+
+ if ( ! ldb_dn_validate(dn)) {
+ return false;
+ }
+
+ if (dn->comp_num < num) {
+ return false;
+ }
+
+ for (i = 0, j = num; j < dn->comp_num; i++, j++) {
+ if (i < num) {
+ LDB_FREE(dn->components[i].name);
+ LDB_FREE(dn->components[i].value.data);
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+ dn->components[i] = dn->components[j];
+ }
+
+ dn->comp_num -= num;
+
+ if (dn->valid_case) {
+ for (i = 0; i < dn->comp_num; i++) {
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+ dn->valid_case = false;
+ }
+
+ LDB_FREE(dn->casefold);
+ LDB_FREE(dn->linearized);
+
+ /* Wipe the ext_linearized DN,
+ * the GUID and SID are almost certainly no longer valid */
+ LDB_FREE(dn->ext_linearized);
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+
+ return true;
+}
+
+
+/* replace the components of a DN with those from another DN, without
+ * touching the extended components
+ *
+ * return true if successful and false if not
+ * if false is returned the dn may be marked invalid
+ */
+bool ldb_dn_replace_components(struct ldb_dn *dn, struct ldb_dn *new_dn)
+{
+ unsigned int i;
+
+ if ( ! ldb_dn_validate(dn) || ! ldb_dn_validate(new_dn)) {
+ return false;
+ }
+
+ /* free components */
+ for (i = 0; i < dn->comp_num; i++) {
+ LDB_FREE(dn->components[i].name);
+ LDB_FREE(dn->components[i].value.data);
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+
+ dn->components = talloc_realloc(dn,
+ dn->components,
+ struct ldb_dn_component,
+ new_dn->comp_num);
+ if (dn->components == NULL) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+
+ dn->comp_num = new_dn->comp_num;
+ dn->valid_case = new_dn->valid_case;
+
+ for (i = 0; i < dn->comp_num; i++) {
+ dn->components[i] = ldb_dn_copy_component(dn->components, &new_dn->components[i]);
+ if (dn->components[i].name == NULL) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+ }
+ if (new_dn->linearized == NULL) {
+ dn->linearized = NULL;
+ } else {
+ dn->linearized = talloc_strdup(dn, new_dn->linearized);
+ if (dn->linearized == NULL) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+struct ldb_dn *ldb_dn_get_parent(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
+{
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_copy(mem_ctx, dn);
+ if ( !new_dn ) {
+ return NULL;
+ }
+
+ if ( ! ldb_dn_remove_child_components(new_dn, 1)) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ return new_dn;
+}
+
+/* Create a 'canonical name' string from a DN:
+
+ ie dc=samba,dc=org -> samba.org/
+ uid=administrator,ou=users,dc=samba,dc=org = samba.org/users/administrator
+
+ There are two formats,
+ the EX format has the last '/' replaced with a newline (\n).
+
+*/
+static char *ldb_dn_canonical(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, int ex_format) {
+ unsigned int i;
+ TALLOC_CTX *tmpctx;
+ char *cracked = NULL;
+ const char *format = (ex_format ? "\n" : "/" );
+
+ if ( ! ldb_dn_validate(dn)) {
+ return NULL;
+ }
+
+ tmpctx = talloc_new(mem_ctx);
+
+ /* Walk backwards down the DN, grabbing 'dc' components at first */
+ for (i = dn->comp_num - 1; i != (unsigned int) -1; i--) {
+ if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) {
+ break;
+ }
+ if (cracked) {
+ cracked = talloc_asprintf(tmpctx, "%s.%s",
+ ldb_dn_escape_value(tmpctx,
+ dn->components[i].value),
+ cracked);
+ } else {
+ cracked = ldb_dn_escape_value(tmpctx,
+ dn->components[i].value);
+ }
+ if (!cracked) {
+ goto done;
+ }
+ }
+
+ /* Only domain components? Finish here */
+ if (i == (unsigned int) -1) {
+ cracked = talloc_strdup_append_buffer(cracked, format);
+ talloc_steal(mem_ctx, cracked);
+ goto done;
+ }
+
+ /* Now walk backwards appending remaining components */
+ for (; i > 0; i--) {
+ cracked = talloc_asprintf_append_buffer(cracked, "/%s",
+ ldb_dn_escape_value(tmpctx,
+ dn->components[i].value));
+ if (!cracked) {
+ goto done;
+ }
+ }
+
+ /* Last one, possibly a newline for the 'ex' format */
+ cracked = talloc_asprintf_append_buffer(cracked, "%s%s", format,
+ ldb_dn_escape_value(tmpctx,
+ dn->components[i].value));
+
+ talloc_steal(mem_ctx, cracked);
+done:
+ talloc_free(tmpctx);
+ return cracked;
+}
+
+/* Wrapper functions for the above, for the two different string formats */
+char *ldb_dn_canonical_string(TALLOC_CTX *mem_ctx, struct ldb_dn *dn) {
+ return ldb_dn_canonical(mem_ctx, dn, 0);
+
+}
+
+char *ldb_dn_canonical_ex_string(TALLOC_CTX *mem_ctx, struct ldb_dn *dn) {
+ return ldb_dn_canonical(mem_ctx, dn, 1);
+}
+
+int ldb_dn_get_comp_num(struct ldb_dn *dn)
+{
+ if ( ! ldb_dn_validate(dn)) {
+ return -1;
+ }
+ return dn->comp_num;
+}
+
+int ldb_dn_get_extended_comp_num(struct ldb_dn *dn)
+{
+ if ( ! ldb_dn_validate(dn)) {
+ return -1;
+ }
+ return dn->ext_comp_num;
+}
+
+const char *ldb_dn_get_component_name(struct ldb_dn *dn, unsigned int num)
+{
+ if ( ! ldb_dn_validate(dn)) {
+ return NULL;
+ }
+ if (num >= dn->comp_num) return NULL;
+ return dn->components[num].name;
+}
+
+const struct ldb_val *ldb_dn_get_component_val(struct ldb_dn *dn,
+ unsigned int num)
+{
+ if ( ! ldb_dn_validate(dn)) {
+ return NULL;
+ }
+ if (num >= dn->comp_num) return NULL;
+ return &dn->components[num].value;
+}
+
+const char *ldb_dn_get_rdn_name(struct ldb_dn *dn)
+{
+ if ( ! ldb_dn_validate(dn)) {
+ return NULL;
+ }
+ if (dn->comp_num == 0) return NULL;
+ return dn->components[0].name;
+}
+
+const struct ldb_val *ldb_dn_get_rdn_val(struct ldb_dn *dn)
+{
+ if ( ! ldb_dn_validate(dn)) {
+ return NULL;
+ }
+ if (dn->comp_num == 0) return NULL;
+ return &dn->components[0].value;
+}
+
+int ldb_dn_set_component(struct ldb_dn *dn, int num,
+ const char *name, const struct ldb_val val)
+{
+ char *n;
+ struct ldb_val v;
+
+ if ( ! ldb_dn_validate(dn)) {
+ return LDB_ERR_OTHER;
+ }
+
+ if (num < 0) {
+ return LDB_ERR_OTHER;
+ }
+
+ if ((unsigned)num >= dn->comp_num) {
+ return LDB_ERR_OTHER;
+ }
+
+ if (val.length > val.length + 1) {
+ return LDB_ERR_OTHER;
+ }
+
+ n = talloc_strdup(dn, name);
+ if ( ! n) {
+ return LDB_ERR_OTHER;
+ }
+
+ v.length = val.length;
+
+ /*
+ * This is like talloc_memdup(dn, v.data, v.length + 1), but
+ * avoids the over-read
+ */
+ v.data = (uint8_t *)talloc_size(dn, v.length+1);
+ if ( ! v.data) {
+ talloc_free(n);
+ return LDB_ERR_OTHER;
+ }
+ memcpy(v.data, val.data, val.length);
+
+ /*
+ * Enforce NUL termination outside the stated length, as is
+ * traditional in LDB
+ */
+ v.data[v.length] = '\0';
+
+ talloc_free(dn->components[num].name);
+ talloc_free(dn->components[num].value.data);
+ dn->components[num].name = n;
+ dn->components[num].value = v;
+
+ if (dn->valid_case) {
+ unsigned int i;
+ for (i = 0; i < dn->comp_num; i++) {
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+ dn->valid_case = false;
+ }
+ LDB_FREE(dn->casefold);
+ LDB_FREE(dn->linearized);
+
+ /* Wipe the ext_linearized DN,
+ * the GUID and SID are almost certainly no longer valid */
+ LDB_FREE(dn->ext_linearized);
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+
+ return LDB_SUCCESS;
+}
+
+const struct ldb_val *ldb_dn_get_extended_component(struct ldb_dn *dn,
+ const char *name)
+{
+ unsigned int i;
+ if ( ! ldb_dn_validate(dn)) {
+ return NULL;
+ }
+ for (i=0; i < dn->ext_comp_num; i++) {
+ if (ldb_attr_cmp(dn->ext_components[i].name, name) == 0) {
+ return &dn->ext_components[i].value;
+ }
+ }
+ return NULL;
+}
+
+int ldb_dn_set_extended_component(struct ldb_dn *dn,
+ const char *name, const struct ldb_val *val)
+{
+ struct ldb_dn_ext_component *p;
+ unsigned int i;
+ struct ldb_val v2;
+ const struct ldb_dn_extended_syntax *ext_syntax;
+
+ if ( ! ldb_dn_validate(dn)) {
+ return LDB_ERR_OTHER;
+ }
+
+ ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, name);
+ if (ext_syntax == NULL) {
+ /* We don't know how to handle this type of thing */
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ for (i=0; i < dn->ext_comp_num; i++) {
+ if (ldb_attr_cmp(dn->ext_components[i].name, name) == 0) {
+ if (val) {
+ dn->ext_components[i].value =
+ ldb_val_dup(dn->ext_components, val);
+
+ dn->ext_components[i].name = ext_syntax->name;
+ if (!dn->ext_components[i].value.data) {
+ ldb_dn_mark_invalid(dn);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else {
+ ARRAY_DEL_ELEMENT(
+ dn->ext_components,
+ i,
+ dn->ext_comp_num);
+ dn->ext_comp_num--;
+
+ dn->ext_components = talloc_realloc(dn,
+ dn->ext_components,
+ struct ldb_dn_ext_component,
+ dn->ext_comp_num);
+ if (!dn->ext_components) {
+ ldb_dn_mark_invalid(dn);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ LDB_FREE(dn->ext_linearized);
+
+ return LDB_SUCCESS;
+ }
+ }
+
+ if (val == NULL) {
+ /* removing a value that doesn't exist is not an error */
+ return LDB_SUCCESS;
+ }
+
+ v2 = *val;
+
+ p = dn->ext_components
+ = talloc_realloc(dn,
+ dn->ext_components,
+ struct ldb_dn_ext_component,
+ dn->ext_comp_num + 1);
+ if (!dn->ext_components) {
+ ldb_dn_mark_invalid(dn);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ p[dn->ext_comp_num].value = ldb_val_dup(dn->ext_components, &v2);
+ p[dn->ext_comp_num].name = talloc_strdup(p, name);
+
+ if (!dn->ext_components[i].name || !dn->ext_components[i].value.data) {
+ ldb_dn_mark_invalid(dn);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ dn->ext_components = p;
+ dn->ext_comp_num++;
+
+ LDB_FREE(dn->ext_linearized);
+
+ return LDB_SUCCESS;
+}
+
+void ldb_dn_remove_extended_components(struct ldb_dn *dn)
+{
+ LDB_FREE(dn->ext_linearized);
+ LDB_FREE(dn->ext_components);
+ dn->ext_comp_num = 0;
+}
+
+bool ldb_dn_is_valid(struct ldb_dn *dn)
+{
+ if ( ! dn) return false;
+ return ! dn->invalid;
+}
+
+bool ldb_dn_is_special(struct ldb_dn *dn)
+{
+ if ( ! dn || dn->invalid) return false;
+ return dn->special;
+}
+
+bool ldb_dn_has_extended(struct ldb_dn *dn)
+{
+ if ( ! dn || dn->invalid) return false;
+ if (dn->ext_linearized && (dn->ext_linearized[0] == '<')) return true;
+ return dn->ext_comp_num != 0;
+}
+
+bool ldb_dn_check_special(struct ldb_dn *dn, const char *check)
+{
+ if ( ! dn || dn->invalid) return false;
+ return ! strcmp(dn->linearized, check);
+}
+
+bool ldb_dn_is_null(struct ldb_dn *dn)
+{
+ if ( ! dn || dn->invalid) return false;
+ if (ldb_dn_has_extended(dn)) return false;
+ if (dn->linearized && (dn->linearized[0] == '\0')) return true;
+ return false;
+}
+
+/*
+ this updates dn->components, taking the components from ref_dn.
+ This is used by code that wants to update the DN path of a DN
+ while not impacting on the extended DN components
+ */
+int ldb_dn_update_components(struct ldb_dn *dn, const struct ldb_dn *ref_dn)
+{
+ dn->components = talloc_realloc(dn, dn->components,
+ struct ldb_dn_component, ref_dn->comp_num);
+ if (!dn->components) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ memcpy(dn->components, ref_dn->components,
+ sizeof(struct ldb_dn_component)*ref_dn->comp_num);
+ dn->comp_num = ref_dn->comp_num;
+
+ LDB_FREE(dn->casefold);
+ LDB_FREE(dn->linearized);
+ LDB_FREE(dn->ext_linearized);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ minimise a DN. The caller must pass in a validated DN.
+
+ If the DN has an extended component then only the first extended
+ component is kept, the DN string is stripped.
+
+ The existing dn is modified
+ */
+bool ldb_dn_minimise(struct ldb_dn *dn)
+{
+ unsigned int i;
+
+ if (!ldb_dn_validate(dn)) {
+ return false;
+ }
+ if (dn->ext_comp_num == 0) {
+ return true;
+ }
+
+ /* free components */
+ for (i = 0; i < dn->comp_num; i++) {
+ LDB_FREE(dn->components[i].name);
+ LDB_FREE(dn->components[i].value.data);
+ LDB_FREE(dn->components[i].cf_name);
+ LDB_FREE(dn->components[i].cf_value.data);
+ }
+ dn->comp_num = 0;
+ dn->valid_case = false;
+
+ LDB_FREE(dn->casefold);
+ LDB_FREE(dn->linearized);
+
+ /* note that we don't free dn->components as this there are
+ * several places in ldb_dn.c that rely on it being non-NULL
+ * for an exploded DN
+ */
+
+ for (i = 1; i < dn->ext_comp_num; i++) {
+ LDB_FREE(dn->ext_components[i].value.data);
+ }
+ dn->ext_comp_num = 1;
+
+ dn->ext_components = talloc_realloc(dn, dn->ext_components, struct ldb_dn_ext_component, 1);
+ if (dn->ext_components == NULL) {
+ ldb_dn_mark_invalid(dn);
+ return false;
+ }
+
+ LDB_FREE(dn->ext_linearized);
+
+ return true;
+}
+
+struct ldb_context *ldb_dn_get_ldb_context(struct ldb_dn *dn)
+{
+ return dn->ldb;
+}
diff --git a/lib/ldb/common/ldb_ldif.c b/lib/ldb/common/ldb_ldif.c
new file mode 100644
index 0000000..96237dd
--- /dev/null
+++ b/lib/ldb/common/ldb_ldif.c
@@ -0,0 +1,1128 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldif routines
+ *
+ * Description: ldif pack/unpack routines
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+ see RFC2849 for the LDIF format definition
+*/
+
+#include "ldb_private.h"
+#include "system/locale.h"
+
+/*
+
+*/
+static int ldb_read_data_file(TALLOC_CTX *mem_ctx, struct ldb_val *value)
+{
+ struct stat statbuf;
+ char *buf;
+ int count, size, bytes;
+ int ret;
+ int f;
+ const char *fname = (const char *)value->data;
+
+ if (strncmp(fname, "file://", 7) != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ fname += 7;
+
+ f = open(fname, O_RDONLY);
+ if (f == -1) {
+ return -1;
+ }
+
+ if (fstat(f, &statbuf) != 0) {
+ ret = -1;
+ goto done;
+ }
+
+ if (statbuf.st_size == 0) {
+ ret = -1;
+ goto done;
+ }
+
+ value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1);
+ if (value->data == NULL) {
+ ret = -1;
+ goto done;
+ }
+ value->data[statbuf.st_size] = 0;
+
+ count = 0;
+ size = statbuf.st_size;
+ buf = (char *)value->data;
+ while (count < statbuf.st_size) {
+ bytes = read(f, buf, size);
+ if (bytes == -1) {
+ talloc_free(value->data);
+ ret = -1;
+ goto done;
+ }
+ count += bytes;
+ buf += bytes;
+ size -= bytes;
+ }
+
+ value->length = statbuf.st_size;
+ ret = statbuf.st_size;
+
+done:
+ close(f);
+ return ret;
+}
+
+/*
+ this base64 decoder was taken from jitterbug (written by tridge).
+ we might need to replace it with a new version
+*/
+int ldb_base64_decode(char *s)
+{
+ const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset=0, byte_offset, idx, i, n;
+ uint8_t *d = (uint8_t *)s;
+ char *p=NULL;
+
+ n=i=0;
+
+ while (*s && (p=strchr(b64,*s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ d[byte_offset] &= ~((1<<(8-bit_offset))-1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (idx << (2-bit_offset));
+ n = byte_offset+1;
+ } else {
+ d[byte_offset] |= (idx >> (bit_offset-2));
+ d[byte_offset+1] = 0;
+ d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
+ n = byte_offset+2;
+ }
+ s++; i++;
+ }
+ if (bit_offset >= 3) {
+ n--;
+ }
+
+ if (*s && !p) {
+ /* the only termination allowed */
+ if (*s != '=') {
+ return -1;
+ }
+ }
+
+ /* null terminate */
+ d[n] = 0;
+ return n;
+}
+
+
+/*
+ encode as base64
+ caller frees
+*/
+char *ldb_base64_encode(TALLOC_CTX *mem_ctx, const char *buf, int len)
+{
+ const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i;
+ const uint8_t *d = (const uint8_t *)buf;
+ int bytes = (len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
+ char *out;
+
+ out = talloc_array(mem_ctx, char, bytes+pad_bytes+1);
+ if (!out) return NULL;
+
+ for (i=0;i<bytes;i++) {
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ if (bit_offset < 3) {
+ idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
+ } else {
+ idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
+ if (byte_offset+1 < len) {
+ idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
+ }
+ }
+ out[i] = b64[idx];
+ }
+
+ for (;i<bytes+pad_bytes;i++)
+ out[i] = '=';
+ out[i] = 0;
+
+ return out;
+}
+
+/*
+ see if a buffer should be base64 encoded
+*/
+int ldb_should_b64_encode(struct ldb_context *ldb, const struct ldb_val *val)
+{
+ unsigned int i;
+ uint8_t *p = val->data;
+
+ if (val->length == 0) {
+ return 0;
+ }
+
+ if (p[0] == ' ' || p[0] == ':') {
+ return 1;
+ }
+
+ for (i=0; i<val->length; i++) {
+ if (!isprint(p[i]) || p[i] == '\n') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* this macro is used to handle the return checking on fprintf_fn() */
+#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
+
+/*
+ write a line folded string onto a file
+*/
+static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data,
+ const char *buf, size_t length, int start_pos)
+{
+ size_t i;
+ size_t total = 0;
+ int ret;
+
+ for (i=0;i<length;i++) {
+ ret = fprintf_fn(private_data, "%c", buf[i]);
+ CHECK_RET;
+ if (i != (length-1) && (i + start_pos) % 77 == 0) {
+ ret = fprintf_fn(private_data, "\n ");
+ CHECK_RET;
+ }
+ }
+
+ return total;
+}
+
+#undef CHECK_RET
+
+/*
+ encode as base64 to a file
+*/
+static int base64_encode_f(struct ldb_context *ldb,
+ int (*fprintf_fn)(void *, const char *, ...),
+ void *private_data,
+ const char *buf, int len, int start_pos)
+{
+ char *b = ldb_base64_encode(ldb, buf, len);
+ int ret;
+
+ if (!b) {
+ return -1;
+ }
+
+ ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
+
+ talloc_free(b);
+ return ret;
+}
+
+
+static const struct {
+ const char *name;
+ enum ldb_changetype changetype;
+} ldb_changetypes[] = {
+ {"add", LDB_CHANGETYPE_ADD},
+ {"delete", LDB_CHANGETYPE_DELETE},
+ {"modify", LDB_CHANGETYPE_MODIFY},
+ {"modrdn", LDB_CHANGETYPE_MODRDN},
+ {"moddn", LDB_CHANGETYPE_MODRDN},
+ {NULL, 0}
+};
+
+/* this macro is used to handle the return checking on fprintf_fn() */
+#define CHECK_RET do { if (ret < 0) { talloc_free(mem_ctx); return ret; } total += ret; } while (0)
+
+/*
+ write to ldif, using a caller supplied write method, and only printing secrets if we are not in a trace
+*/
+static int ldb_ldif_write_trace(struct ldb_context *ldb,
+ int (*fprintf_fn)(void *, const char *, ...),
+ void *private_data,
+ const struct ldb_ldif *ldif,
+ bool in_trace)
+{
+ TALLOC_CTX *mem_ctx;
+ unsigned int i, j;
+ size_t total = 0;
+ int ret;
+ char *p;
+ const struct ldb_message *msg;
+ const char * const * secret_attributes = ldb_get_opaque(ldb, LDB_SECRET_ATTRIBUTE_LIST_OPAQUE);
+
+ mem_ctx = talloc_named_const(NULL, 0, "ldb_ldif_write");
+
+ msg = ldif->msg;
+ p = ldb_dn_get_extended_linearized(mem_ctx, msg->dn, 1);
+ ret = fprintf_fn(private_data, "dn: %s\n", p);
+ talloc_free(p);
+ CHECK_RET;
+
+ if (ldif->changetype != LDB_CHANGETYPE_NONE) {
+ for (i=0;ldb_changetypes[i].name;i++) {
+ if (ldb_changetypes[i].changetype == ldif->changetype) {
+ break;
+ }
+ }
+ if (!ldb_changetypes[i].name) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Invalid ldif changetype %d",
+ ldif->changetype);
+ talloc_free(mem_ctx);
+ return -1;
+ }
+ ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name);
+ CHECK_RET;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_schema_attribute *a;
+ size_t namelen;
+
+ if (msg->elements[i].name == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Invalid element name (NULL) at position %d", i);
+ talloc_free(mem_ctx);
+ return -1;
+ }
+
+ namelen = strlen(msg->elements[i].name);
+ a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
+
+ if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
+ switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ fprintf_fn(private_data, "add: %s\n",
+ msg->elements[i].name);
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ fprintf_fn(private_data, "delete: %s\n",
+ msg->elements[i].name);
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ fprintf_fn(private_data, "replace: %s\n",
+ msg->elements[i].name);
+ break;
+ }
+ }
+
+ if (in_trace && secret_attributes && ldb_attr_in_list(secret_attributes, msg->elements[i].name)) {
+ /* Deliberately skip printing this password */
+ ret = fprintf_fn(private_data, "# %s::: REDACTED SECRET ATTRIBUTE\n",
+ msg->elements[i].name);
+ CHECK_RET;
+ continue;
+ }
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ struct ldb_val v;
+ bool use_b64_encode = false;
+ bool copy_raw_bytes = false;
+
+ ret = a->syntax->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v);
+ if (ret != LDB_SUCCESS) {
+ v = msg->elements[i].values[j];
+ }
+
+ if (ldb->flags & LDB_FLG_SHOW_BINARY) {
+ use_b64_encode = false;
+ copy_raw_bytes = true;
+ } else if (a->flags & LDB_ATTR_FLAG_FORCE_BASE64_LDIF) {
+ use_b64_encode = true;
+ } else if (msg->elements[i].flags &
+ LDB_FLAG_FORCE_NO_BASE64_LDIF) {
+ use_b64_encode = false;
+ copy_raw_bytes = true;
+ } else {
+ use_b64_encode = ldb_should_b64_encode(ldb, &v);
+ }
+
+ if (ret != LDB_SUCCESS || use_b64_encode) {
+ ret = fprintf_fn(private_data, "%s:: ",
+ msg->elements[i].name);
+ CHECK_RET;
+ ret = base64_encode_f(ldb, fprintf_fn, private_data,
+ (char *)v.data, v.length,
+ namelen + 3);
+ CHECK_RET;
+ ret = fprintf_fn(private_data, "\n");
+ CHECK_RET;
+ } else {
+ ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
+ CHECK_RET;
+ if (copy_raw_bytes) {
+ ret = fprintf_fn(private_data, "%*.*s",
+ v.length, v.length, (char *)v.data);
+ } else {
+ ret = fold_string(fprintf_fn, private_data,
+ (char *)v.data, v.length,
+ namelen + 2);
+ }
+ CHECK_RET;
+ ret = fprintf_fn(private_data, "\n");
+ CHECK_RET;
+ }
+ if (v.data != msg->elements[i].values[j].data) {
+ talloc_free(v.data);
+ }
+ }
+ if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
+ fprintf_fn(private_data, "-\n");
+ }
+ }
+ ret = fprintf_fn(private_data,"\n");
+ CHECK_RET;
+
+ talloc_free(mem_ctx);
+
+ return total;
+}
+
+#undef CHECK_RET
+
+
+/*
+ write to ldif, using a caller supplied write method
+*/
+int ldb_ldif_write(struct ldb_context *ldb,
+ int (*fprintf_fn)(void *, const char *, ...),
+ void *private_data,
+ const struct ldb_ldif *ldif)
+{
+ return ldb_ldif_write_trace(ldb, fprintf_fn, private_data, ldif, false);
+}
+
+
+/*
+ pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
+ this routine removes any RFC2849 continuations and comments
+
+ caller frees
+*/
+static char *next_chunk(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ int (*fgetc_fn)(void *), void *private_data)
+{
+ size_t alloc_size=0, chunk_size = 0;
+ char *chunk = NULL;
+ int c;
+ int in_comment = 0;
+
+ while ((c = fgetc_fn(private_data)) != EOF) {
+ if (chunk_size+1 >= alloc_size) {
+ char *c2;
+ alloc_size += 1024;
+ c2 = talloc_realloc(mem_ctx, chunk, char, alloc_size);
+ if (!c2) {
+ talloc_free(chunk);
+ errno = ENOMEM;
+ return NULL;
+ }
+ chunk = c2;
+ }
+
+ if (in_comment) {
+ if (c == '\n') {
+ in_comment = 0;
+ }
+ continue;
+ }
+
+ /* handle continuation lines - see RFC2849 */
+ if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
+ chunk_size--;
+ continue;
+ }
+
+ /* chunks are terminated by a double line-feed */
+ if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
+ chunk[chunk_size-1] = 0;
+ return chunk;
+ }
+
+ if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
+ in_comment = 1;
+ continue;
+ }
+
+ /* ignore leading blank lines */
+ if (chunk_size == 0 && c == '\n') {
+ continue;
+ }
+
+ chunk[chunk_size++] = c;
+ }
+
+ if (chunk) {
+ chunk[chunk_size] = 0;
+ }
+
+ return chunk;
+}
+
+
+/* simple ldif attribute parser */
+static int next_attr(TALLOC_CTX *mem_ctx, char **s, const char **attr, struct ldb_val *value)
+{
+ char *p;
+ int base64_encoded = 0;
+ int binary_file = 0;
+
+ if (strncmp(*s, "-\n", 2) == 0) {
+ value->length = 0;
+ *attr = "-";
+ *s += 2;
+ return 0;
+ }
+
+ p = strchr(*s, ':');
+ if (!p) {
+ return -1;
+ }
+
+ *p++ = 0;
+
+ if (*p == ':') {
+ base64_encoded = 1;
+ p++;
+ }
+
+ if (*p == '<') {
+ binary_file = 1;
+ p++;
+ }
+
+ *attr = *s;
+
+ while (*p == ' ' || *p == '\t') {
+ p++;
+ }
+
+ value->data = (uint8_t *)p;
+
+ p = strchr(p, '\n');
+
+ if (!p) {
+ value->length = strlen((char *)value->data);
+ *s = ((char *)value->data) + value->length;
+ } else {
+ value->length = p - (char *)value->data;
+ *s = p+1;
+ *p = 0;
+ }
+
+ if (base64_encoded) {
+ int len = ldb_base64_decode((char *)value->data);
+ if (len == -1) {
+ /* it wasn't valid base64 data */
+ return -1;
+ }
+ value->length = len;
+ }
+
+ if (binary_file) {
+ int len = ldb_read_data_file(mem_ctx, value);
+ if (len == -1) {
+ /* an error occurred while trying to retrieve the file */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ free a message from a ldif_read
+*/
+void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
+{
+ talloc_free(ldif);
+}
+
+int ldb_ldif_parse_modrdn(struct ldb_context *ldb,
+ const struct ldb_ldif *ldif,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn **_olddn,
+ struct ldb_dn **_newrdn,
+ bool *_deleteoldrdn,
+ struct ldb_dn **_newsuperior,
+ struct ldb_dn **_newdn)
+{
+ struct ldb_message *msg = ldif->msg;
+ struct ldb_val _newrdn_val = {};
+ struct ldb_val *newrdn_val = NULL;
+ struct ldb_val *deleteoldrdn_val = NULL;
+ struct ldb_val *newsuperior_val = NULL;
+ struct ldb_dn *olddn = NULL;
+ struct ldb_dn *newrdn = NULL;
+ bool deleteoldrdn = true;
+ struct ldb_dn *newsuperior = NULL;
+ struct ldb_dn *newdn = NULL;
+ struct ldb_val tmp_false;
+ struct ldb_val tmp_true;
+ bool ok;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+ if (tmp_ctx == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "Error: talloc_new() failed");
+ goto err_op;
+ }
+
+ if (ldif->changetype != LDB_CHANGETYPE_MODRDN) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: invalid changetype '%d'",
+ ldif->changetype);
+ goto err_other;
+ }
+
+ if (msg->num_elements < 2) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: num_elements[%u] < 2",
+ msg->num_elements);
+ goto err_other;
+ }
+
+ if (msg->num_elements > 3) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: num_elements[%u] > 3",
+ msg->num_elements);
+ goto err_other;
+ }
+
+#define CHECK_ELEMENT(i, _name, v, needed) do { \
+ v = NULL; \
+ if (msg->num_elements < (i + 1)) { \
+ if (needed) { \
+ ldb_debug(ldb, LDB_DEBUG_ERROR, \
+ "Error: num_elements[%u] < (%u + 1)", \
+ msg->num_elements, i); \
+ goto err_other; \
+ } \
+ } else if (ldb_attr_cmp(msg->elements[i].name, _name) != 0) { \
+ ldb_debug(ldb, LDB_DEBUG_ERROR, \
+ "Error: elements[%u].name[%s] != [%s]", \
+ i, msg->elements[i].name, _name); \
+ goto err_other; \
+ } else if (msg->elements[i].flags != 0) { \
+ ldb_debug(ldb, LDB_DEBUG_ERROR, \
+ "Error: elements[%u].flags[0x%X} != [0x0]", \
+ i, msg->elements[i].flags); \
+ goto err_other; \
+ } else if (msg->elements[i].num_values != 1) { \
+ ldb_debug(ldb, LDB_DEBUG_ERROR, \
+ "Error: elements[%u].num_values[%u] != 1", \
+ i, msg->elements[i].num_values); \
+ goto err_other; \
+ } else { \
+ v = &msg->elements[i].values[0]; \
+ } \
+} while (0)
+
+ CHECK_ELEMENT(0, "newrdn", newrdn_val, true);
+ CHECK_ELEMENT(1, "deleteoldrdn", deleteoldrdn_val, true);
+ CHECK_ELEMENT(2, "newsuperior", newsuperior_val, false);
+
+#undef CHECK_ELEMENT
+
+ olddn = ldb_dn_copy(tmp_ctx, msg->dn);
+ if (olddn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: failed to copy olddn '%s'",
+ ldb_dn_get_linearized(msg->dn));
+ goto err_op;
+ }
+
+ if (newrdn_val->length != 0 && strchr((const char *)newrdn_val->data, '=') == NULL) {
+ const char *rdn_name = ldb_dn_get_rdn_name(olddn);
+ char *new_rdn = NULL;
+
+ new_rdn = talloc_asprintf(tmp_ctx,
+ "%s=%s",
+ rdn_name,
+ (const char *)newrdn_val->data);
+ if (new_rdn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: failed to allocate '%s=%s'",
+ rdn_name, (char *)newrdn_val->data);
+ goto err_op;
+ }
+ _newrdn_val.data = (uint8_t *)new_rdn;
+ _newrdn_val.length = strlen(new_rdn);
+ newrdn_val = &_newrdn_val;
+ }
+
+ newrdn = ldb_dn_from_ldb_val(tmp_ctx, ldb, newrdn_val);
+ if (!ldb_dn_validate(newrdn)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Unable to parse dn '%s'",
+ (char *)newrdn_val->data);
+ goto err_dn;
+ }
+
+ tmp_false.length = 1;
+ tmp_false.data = discard_const_p(uint8_t, "0");
+ tmp_true.length = 1;
+ tmp_true.data = discard_const_p(uint8_t, "1");
+ if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_false) == 1) {
+ deleteoldrdn = false;
+ } else if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_true) == 1) {
+ deleteoldrdn = true;
+ } else {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: deleteoldrdn value invalid '%s' not '0'/'1'",
+ (char *)deleteoldrdn_val->data);
+ goto err_attr;
+ }
+
+ if (newsuperior_val) {
+ newsuperior = ldb_dn_from_ldb_val(tmp_ctx, ldb, newsuperior_val);
+ if (!ldb_dn_validate(newsuperior)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Unable to parse dn '%s'",
+ (char *)newsuperior_val->data);
+ goto err_dn;
+ }
+ } else {
+ newsuperior = ldb_dn_get_parent(tmp_ctx, msg->dn);
+ if (newsuperior == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Unable to get parent dn '%s'",
+ ldb_dn_get_linearized(msg->dn));
+ goto err_dn;
+ }
+ }
+
+ newdn = ldb_dn_copy(tmp_ctx, newrdn);
+ if (newdn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: failed to copy newrdn '%s'",
+ ldb_dn_get_linearized(newrdn));
+ goto err_op;
+ }
+
+ ok = ldb_dn_add_base(newdn, newsuperior);
+ if (!ok) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: failed to base '%s' to newdn '%s'",
+ ldb_dn_get_linearized(newsuperior),
+ ldb_dn_get_linearized(newdn));
+ goto err_op;
+ }
+
+ if (_olddn) {
+ *_olddn = talloc_move(mem_ctx, &olddn);
+ }
+ if (_newrdn) {
+ *_newrdn = talloc_move(mem_ctx, &newrdn);
+ }
+ if (_deleteoldrdn) {
+ *_deleteoldrdn = deleteoldrdn;
+ }
+ if (_newsuperior != NULL && _newrdn != NULL) {
+ if (newsuperior_val) {
+ *_newrdn = talloc_move(mem_ctx, &newrdn);
+ } else {
+ *_newrdn = NULL;
+ }
+ }
+ if (_newdn) {
+ *_newdn = talloc_move(mem_ctx, &newdn);
+ }
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+err_other:
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OTHER;
+err_op:
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+err_attr:
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+err_dn:
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+}
+
+/*
+ read from a LDIF source, creating a ldb_message
+*/
+struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
+ int (*fgetc_fn)(void *), void *private_data)
+{
+ struct ldb_ldif *ldif;
+ struct ldb_message *msg;
+ const char *attr=NULL;
+ char *chunk=NULL, *s;
+ struct ldb_val value;
+ unsigned flags = 0;
+ value.data = NULL;
+
+ ldif = talloc(ldb, struct ldb_ldif);
+ if (!ldif) return NULL;
+
+ ldif->msg = ldb_msg_new(ldif);
+ if (ldif->msg == NULL) {
+ talloc_free(ldif);
+ return NULL;
+ }
+
+ ldif->changetype = LDB_CHANGETYPE_NONE;
+ msg = ldif->msg;
+
+ chunk = next_chunk(ldb, ldif, fgetc_fn, private_data);
+ if (!chunk) {
+ goto failed;
+ }
+
+ s = chunk;
+
+ if (next_attr(ldif, &s, &attr, &value) != 0) {
+ goto failed;
+ }
+
+ /* first line must be a dn */
+ if (ldb_attr_cmp(attr, "dn") != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'",
+ attr);
+ goto failed;
+ }
+
+ msg->dn = ldb_dn_from_ldb_val(msg, ldb, &value);
+
+ if ( ! ldb_dn_validate(msg->dn)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Unable to parse dn '%s'",
+ (char *)value.data);
+ goto failed;
+ }
+
+ while (next_attr(ldif, &s, &attr, &value) == 0) {
+ const struct ldb_schema_attribute *a;
+ struct ldb_message_element *el;
+ int ret, empty = 0;
+
+ if (ldb_attr_cmp(attr, "changetype") == 0) {
+ int i;
+ for (i=0;ldb_changetypes[i].name;i++) {
+ if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) {
+ ldif->changetype = ldb_changetypes[i].changetype;
+ break;
+ }
+ }
+ if (!ldb_changetypes[i].name) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Bad ldif changetype '%s'",(char *)value.data);
+ }
+ flags = 0;
+ continue;
+ }
+
+ if (ldb_attr_cmp(attr, "add") == 0) {
+ flags = LDB_FLAG_MOD_ADD;
+ empty = 1;
+ }
+ if (ldb_attr_cmp(attr, "delete") == 0) {
+ flags = LDB_FLAG_MOD_DELETE;
+ empty = 1;
+ }
+ if (ldb_attr_cmp(attr, "replace") == 0) {
+ flags = LDB_FLAG_MOD_REPLACE;
+ empty = 1;
+ }
+ if (ldb_attr_cmp(attr, "-") == 0) {
+ flags = 0;
+ continue;
+ }
+
+ if (empty) {
+ if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) {
+ goto failed;
+ }
+ continue;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, attr);
+ el = (msg->num_elements > 0
+ ? &msg->elements[msg->num_elements - 1]
+ : NULL);
+
+ if (el && ldb_attr_cmp(attr, el->name) == 0 && flags == el->flags) {
+ /* its a continuation */
+ el->values =
+ talloc_realloc(msg->elements, el->values,
+ struct ldb_val, el->num_values+1);
+ if (!el->values) {
+ goto failed;
+ }
+ ret = a->syntax->ldif_read_fn(ldb, el->values, &value, &el->values[el->num_values]);
+ if (ret != 0) {
+ goto failed;
+ }
+ if (value.length == 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Attribute value cannot be empty for attribute '%s'", el->name);
+ goto failed;
+ }
+ if (value.data != el->values[el->num_values].data) {
+ talloc_steal(el->values, el->values[el->num_values].data);
+ }
+ el->num_values++;
+ } else {
+ /* its a new attribute */
+ msg->elements = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element,
+ msg->num_elements+1);
+ if (!msg->elements) {
+ goto failed;
+ }
+ el = &msg->elements[msg->num_elements];
+ el->flags = flags;
+ el->name = talloc_strdup(msg->elements, attr);
+ el->values = talloc(msg->elements, struct ldb_val);
+ if (!el->values || !el->name) {
+ goto failed;
+ }
+ el->num_values = 1;
+ ret = a->syntax->ldif_read_fn(ldb, el->values, &value, &el->values[0]);
+ if (ret != 0) {
+ goto failed;
+ }
+ if (value.data != el->values[0].data) {
+ talloc_steal(el->values, el->values[0].data);
+ }
+ msg->num_elements++;
+ }
+ }
+
+ if (ldif->changetype == LDB_CHANGETYPE_MODRDN) {
+ int ret;
+
+ ret = ldb_ldif_parse_modrdn(ldb, ldif, ldif,
+ NULL, NULL, NULL, NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+ }
+
+ return ldif;
+
+failed:
+ talloc_free(ldif);
+ return NULL;
+}
+
+
+
+/*
+ a wrapper around ldif_read() for reading from FILE*
+*/
+
+static int fgetc_file(void *private_data)
+{
+ int c;
+ struct ldif_read_file_state *state =
+ (struct ldif_read_file_state *)private_data;
+ c = fgetc(state->f);
+ if (c == '\n') {
+ state->line_no++;
+ }
+ return c;
+}
+
+struct ldb_ldif *ldb_ldif_read_file_state(struct ldb_context *ldb,
+ struct ldif_read_file_state *state)
+{
+ return ldb_ldif_read(ldb, fgetc_file, state);
+}
+
+struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f)
+{
+ struct ldif_read_file_state state;
+ state.f = f;
+ return ldb_ldif_read_file_state(ldb, &state);
+}
+
+/*
+ a wrapper around ldif_read() for reading from const char*
+*/
+struct ldif_read_string_state {
+ const char *s;
+};
+
+static int fgetc_string(void *private_data)
+{
+ struct ldif_read_string_state *state =
+ (struct ldif_read_string_state *)private_data;
+ if (state->s[0] != 0) {
+ return *state->s++;
+ }
+ return EOF;
+}
+
+struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s)
+{
+ struct ldif_read_string_state state;
+ struct ldb_ldif *ldif;
+ state.s = *s;
+ ldif = ldb_ldif_read(ldb, fgetc_string, &state);
+ *s = state.s;
+ return ldif;
+}
+
+
+/*
+ wrapper around ldif_write() for a file
+*/
+struct ldif_write_file_state {
+ FILE *f;
+};
+
+static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+
+static int fprintf_file(void *private_data, const char *fmt, ...)
+{
+ struct ldif_write_file_state *state =
+ (struct ldif_write_file_state *)private_data;
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(state->f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif)
+{
+ struct ldif_write_file_state state;
+ state.f = f;
+ return ldb_ldif_write(ldb, fprintf_file, &state, ldif);
+}
+
+/*
+ wrapper around ldif_write() for a string
+*/
+struct ldif_write_string_state {
+ char *string;
+};
+
+static int ldif_printf_string(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+
+static int ldif_printf_string(void *private_data, const char *fmt, ...)
+{
+ struct ldif_write_string_state *state =
+ (struct ldif_write_string_state *)private_data;
+ va_list ap;
+ size_t oldlen = talloc_get_size(state->string);
+ va_start(ap, fmt);
+
+ state->string = talloc_vasprintf_append(state->string, fmt, ap);
+ va_end(ap);
+ if (!state->string) {
+ return -1;
+ }
+
+ return talloc_get_size(state->string) - oldlen;
+}
+
+char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ const struct ldb_ldif *ldif)
+{
+ struct ldif_write_string_state state;
+ state.string = talloc_strdup(mem_ctx, "");
+ if (!state.string) {
+ return NULL;
+ }
+ if (ldb_ldif_write_trace(ldb, ldif_printf_string, &state, ldif, true) == -1) {
+ return NULL;
+ }
+ return state.string;
+}
+
+char *ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ const struct ldb_ldif *ldif)
+{
+ struct ldif_write_string_state state;
+ state.string = talloc_strdup(mem_ctx, "");
+ if (!state.string) {
+ return NULL;
+ }
+ if (ldb_ldif_write(ldb, ldif_printf_string, &state, ldif) == -1) {
+ return NULL;
+ }
+ return state.string;
+}
+
+/*
+ convenient function to turn a ldb_message into a string. Useful for
+ debugging
+ */
+char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ enum ldb_changetype changetype,
+ const struct ldb_message *msg)
+{
+ struct ldb_ldif ldif;
+
+ ldif.changetype = changetype;
+ ldif.msg = discard_const_p(struct ldb_message, msg);
+
+ return ldb_ldif_write_string(ldb, mem_ctx, &ldif);
+}
+
+/*
+ * convenient function to turn a ldb_message into a string. Useful for
+ * debugging but also safer if some of the LDIF could be sensitive.
+ *
+ * The secret attributes are specified in a 'const char * const *' within
+ * the LDB_SECRET_ATTRIBUTE_LIST opaque set on the ldb
+ *
+ */
+char *ldb_ldif_message_redacted_string(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ enum ldb_changetype changetype,
+ const struct ldb_message *msg)
+{
+ struct ldb_ldif ldif;
+
+ ldif.changetype = changetype;
+ ldif.msg = discard_const_p(struct ldb_message, msg);
+
+ return ldb_ldif_write_redacted_trace_string(ldb, mem_ctx, &ldif);
+}
diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c
new file mode 100644
index 0000000..1f74ebb
--- /dev/null
+++ b/lib/ldb/common/ldb_match.c
@@ -0,0 +1,826 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004-2005
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb expression matching
+ *
+ * Description: ldb expression matching
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_private.h"
+#include "dlinklist.h"
+#include "ldb_handlers.h"
+
+/*
+ check if the scope matches in a search result
+*/
+int ldb_match_scope(struct ldb_context *ldb,
+ struct ldb_dn *base,
+ struct ldb_dn *dn,
+ enum ldb_scope scope)
+{
+ int ret = 0;
+
+ if (base == NULL || dn == NULL) {
+ return 1;
+ }
+
+ switch (scope) {
+ case LDB_SCOPE_BASE:
+ if (ldb_dn_compare(base, dn) == 0) {
+ ret = 1;
+ }
+ break;
+
+ case LDB_SCOPE_ONELEVEL:
+ if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) {
+ if (ldb_dn_compare_base(base, dn) == 0) {
+ ret = 1;
+ }
+ }
+ break;
+
+ case LDB_SCOPE_SUBTREE:
+ default:
+ if (ldb_dn_compare_base(base, dn) == 0) {
+ ret = 1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ match if node is present
+*/
+static int ldb_match_present(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope, bool *matched)
+{
+ const struct ldb_schema_attribute *a;
+ struct ldb_message_element *el;
+
+ if (ldb_attr_dn(tree->u.present.attr) == 0) {
+ *matched = true;
+ return LDB_SUCCESS;
+ }
+
+ el = ldb_msg_find_element(msg, tree->u.present.attr);
+ if (el == NULL) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, el->name);
+ if (!a) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ if (a->syntax->operator_fn) {
+ unsigned int i;
+ for (i = 0; i < el->num_values; i++) {
+ int ret = a->syntax->operator_fn(ldb, LDB_OP_PRESENT, a, &el->values[i], NULL, matched);
+ if (ret != LDB_SUCCESS) return ret;
+ if (*matched) return LDB_SUCCESS;
+ }
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ *matched = true;
+ return LDB_SUCCESS;
+}
+
+static int ldb_match_comparison(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope,
+ enum ldb_parse_op comp_op, bool *matched)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+ const struct ldb_schema_attribute *a;
+
+ /* FIXME: APPROX comparison not handled yet */
+ if (comp_op == LDB_OP_APPROX) {
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+
+ el = ldb_msg_find_element(msg, tree->u.comparison.attr);
+ if (el == NULL) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, el->name);
+ if (!a) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ if (a->syntax->operator_fn) {
+ int ret;
+ ret = a->syntax->operator_fn(ldb, comp_op, a, &el->values[i], &tree->u.comparison.value, matched);
+ if (ret != LDB_SUCCESS) return ret;
+ if (*matched) return LDB_SUCCESS;
+ } else {
+ int ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
+
+ if (ret == 0) {
+ *matched = true;
+ return LDB_SUCCESS;
+ }
+ if (ret > 0 && comp_op == LDB_OP_GREATER) {
+ *matched = true;
+ return LDB_SUCCESS;
+ }
+ if (ret < 0 && comp_op == LDB_OP_LESS) {
+ *matched = true;
+ return LDB_SUCCESS;
+ }
+ }
+ }
+
+ *matched = false;
+ return LDB_SUCCESS;
+}
+
+/*
+ match a simple leaf node
+*/
+static int ldb_match_equality(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope,
+ bool *matched)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+ const struct ldb_schema_attribute *a;
+ struct ldb_dn *valuedn;
+ int ret;
+
+ if (ldb_attr_dn(tree->u.equality.attr) == 0) {
+ valuedn = ldb_dn_from_ldb_val(ldb, ldb, &tree->u.equality.value);
+ if (valuedn == NULL) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ ret = ldb_dn_compare(msg->dn, valuedn);
+
+ talloc_free(valuedn);
+
+ *matched = (ret == 0);
+ return LDB_SUCCESS;
+ }
+
+ /* TODO: handle the "*" case derived from an extended search
+ operation without the attribute type defined */
+ el = ldb_msg_find_element(msg, tree->u.equality.attr);
+ if (el == NULL) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, el->name);
+ if (a == NULL) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ if (a->syntax->operator_fn) {
+ ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
+ &tree->u.equality.value, &el->values[i], matched);
+ if (ret != LDB_SUCCESS) return ret;
+ if (*matched) return LDB_SUCCESS;
+ } else {
+ if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value,
+ &el->values[i]) == 0) {
+ *matched = true;
+ return LDB_SUCCESS;
+ }
+ }
+ }
+
+ *matched = false;
+ return LDB_SUCCESS;
+}
+
+static int ldb_wildcard_compare(struct ldb_context *ldb,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_val value, bool *matched)
+{
+ const struct ldb_schema_attribute *a;
+ struct ldb_val val;
+ struct ldb_val cnk;
+ struct ldb_val *chunk;
+ uint8_t *save_p = NULL;
+ unsigned int c = 0;
+
+ if (tree->operation != LDB_OP_SUBSTRING) {
+ *matched = false;
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr);
+ if (!a) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ if (tree->u.substring.chunks == NULL) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ /* No need to just copy this value for a binary match */
+ if (a->syntax->canonicalise_fn != ldb_handler_copy) {
+ if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ /*
+ * Only set save_p if we allocate (call
+ * a->syntax->canonicalise_fn()), as we
+ * talloc_free(save_p) below to clean up
+ */
+ save_p = val.data;
+ } else {
+ val = value;
+ }
+
+ cnk.data = NULL;
+
+ if ( ! tree->u.substring.start_with_wildcard ) {
+ uint8_t *cnk_to_free = NULL;
+
+ chunk = tree->u.substring.chunks[c];
+ /* No need to just copy this value for a binary match */
+ if (a->syntax->canonicalise_fn != ldb_handler_copy) {
+ if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) {
+ goto mismatch;
+ }
+
+ cnk_to_free = cnk.data;
+ } else {
+ cnk = *chunk;
+ }
+
+ /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
+ if (cnk.length > val.length) {
+ TALLOC_FREE(cnk_to_free);
+ goto mismatch;
+ }
+ /*
+ * Empty strings are returned as length 0. Ensure
+ * we can cope with this.
+ */
+ if (cnk.length == 0) {
+ TALLOC_FREE(cnk_to_free);
+ goto mismatch;
+ }
+
+ if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) {
+ TALLOC_FREE(cnk_to_free);
+ goto mismatch;
+ }
+
+ val.length -= cnk.length;
+ val.data += cnk.length;
+ c++;
+ TALLOC_FREE(cnk_to_free);
+ cnk.data = NULL;
+ }
+
+ while (tree->u.substring.chunks[c]) {
+ uint8_t *p;
+ uint8_t *cnk_to_free = NULL;
+
+ chunk = tree->u.substring.chunks[c];
+ /* No need to just copy this value for a binary match */
+ if (a->syntax->canonicalise_fn != ldb_handler_copy) {
+ if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) {
+ goto mismatch;
+ }
+
+ cnk_to_free = cnk.data;
+ } else {
+ cnk = *chunk;
+ }
+ /*
+ * Empty strings are returned as length 0. Ensure
+ * we can cope with this.
+ */
+ if (cnk.length == 0) {
+ TALLOC_FREE(cnk_to_free);
+ goto mismatch;
+ }
+ if (cnk.length > val.length) {
+ TALLOC_FREE(cnk_to_free);
+ goto mismatch;
+ }
+
+ if ( (tree->u.substring.chunks[c + 1]) == NULL &&
+ (! tree->u.substring.end_with_wildcard) ) {
+ /*
+ * The last bit, after all the asterisks, must match
+ * exactly the last bit of the string.
+ */
+ int cmp;
+ p = val.data + val.length - cnk.length;
+ cmp = memcmp(p,
+ cnk.data,
+ cnk.length);
+ TALLOC_FREE(cnk_to_free);
+
+ if (cmp != 0) {
+ goto mismatch;
+ }
+ } else {
+ /*
+ * Values might be binary blobs. Don't use string
+ * search, but memory search instead.
+ */
+ p = memmem((const void *)val.data, val.length,
+ (const void *)cnk.data, cnk.length);
+ if (p == NULL) {
+ TALLOC_FREE(cnk_to_free);
+ goto mismatch;
+ }
+ /* move val to the end of the match */
+ p += cnk.length;
+ val.length -= (p - val.data);
+ val.data = p;
+ TALLOC_FREE(cnk_to_free);
+ }
+ c++;
+ }
+
+ talloc_free(save_p);
+ *matched = true;
+ return LDB_SUCCESS;
+
+mismatch:
+ *matched = false;
+ talloc_free(save_p);
+ return LDB_SUCCESS;
+}
+
+/*
+ match a simple leaf node
+*/
+static int ldb_match_substring(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope, bool *matched)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+
+ el = ldb_msg_find_element(msg, tree->u.substring.attr);
+ if (el == NULL) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ int ret;
+ ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched);
+ if (ret != LDB_SUCCESS) return ret;
+ if (*matched) return LDB_SUCCESS;
+ }
+
+ *matched = false;
+ return LDB_SUCCESS;
+}
+
+
+/*
+ bitwise and/or comparator depending on oid
+*/
+static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2,
+ bool *matched)
+{
+ uint64_t i1, i2;
+ char ibuf[100];
+ char *endptr = NULL;
+
+ if (v1->length >= sizeof(ibuf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ memcpy(ibuf, (char *)v1->data, v1->length);
+ ibuf[v1->length] = 0;
+ i1 = strtoull(ibuf, &endptr, 0);
+ if (endptr != NULL) {
+ if (endptr == ibuf || *endptr != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+
+ if (v2->length >= sizeof(ibuf)-1) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ endptr = NULL;
+ memcpy(ibuf, (char *)v2->data, v2->length);
+ ibuf[v2->length] = 0;
+ i2 = strtoull(ibuf, &endptr, 0);
+ if (endptr != NULL) {
+ if (endptr == ibuf || *endptr != 0) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+ if (strcmp(LDB_OID_COMPARATOR_AND, oid) == 0) {
+ *matched = ((i1 & i2) == i2);
+ } else if (strcmp(LDB_OID_COMPARATOR_OR, oid) == 0) {
+ *matched = ((i1 & i2) != 0);
+ } else {
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+ return LDB_SUCCESS;
+}
+
+static int ldb_match_bitmask(struct ldb_context *ldb,
+ const char *oid,
+ const struct ldb_message *msg,
+ const char *attribute_to_match,
+ const struct ldb_val *value_to_match,
+ bool *matched)
+{
+ unsigned int i;
+ struct ldb_message_element *el;
+
+ /* find the message element */
+ el = ldb_msg_find_element(msg, attribute_to_match);
+ if (el == NULL) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ for (i=0;i<el->num_values;i++) {
+ int ret;
+ struct ldb_val *v = &el->values[i];
+
+ ret = ldb_comparator_bitmask(oid, v, value_to_match, matched);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (*matched) {
+ return LDB_SUCCESS;
+ }
+ }
+
+ *matched = false;
+ return LDB_SUCCESS;
+}
+
+/*
+ always return false
+*/
+static int ldb_comparator_false(struct ldb_context *ldb,
+ const char *oid,
+ const struct ldb_message *msg,
+ const char *attribute_to_match,
+ const struct ldb_val *value_to_match,
+ bool *matched)
+{
+ *matched = false;
+ return LDB_SUCCESS;
+}
+
+
+static const struct ldb_extended_match_rule *ldb_find_extended_match_rule(struct ldb_context *ldb,
+ const char *oid)
+{
+ struct ldb_extended_match_entry *extended_match_rule;
+
+ for (extended_match_rule = ldb->extended_match_rules;
+ extended_match_rule;
+ extended_match_rule = extended_match_rule->next) {
+ if (strcmp(extended_match_rule->rule->oid, oid) == 0) {
+ return extended_match_rule->rule;
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+ extended match, handles things like bitops
+*/
+static int ldb_match_extended(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope, bool *matched)
+{
+ const struct ldb_extended_match_rule *rule;
+
+ if (tree->u.extended.dnAttributes) {
+ /* FIXME: We really need to find out what this ":dn" part in
+ * an extended match means and how to handle it. For now print
+ * only a warning to have s3 winbind and other tools working
+ * against us. - Matthias */
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb: dnAttributes extended match not supported yet");
+ }
+ if (tree->u.extended.rule_id == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+ if (tree->u.extended.attr == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+
+ rule = ldb_find_extended_match_rule(ldb, tree->u.extended.rule_id);
+ if (rule == NULL) {
+ *matched = false;
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s",
+ tree->u.extended.rule_id);
+ return LDB_SUCCESS;
+ }
+
+ return rule->callback(ldb, rule->oid, msg,
+ tree->u.extended.attr,
+ &tree->u.extended.value, matched);
+}
+
+static bool ldb_must_suppress_match(const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree)
+{
+ const char *attr = NULL;
+ struct ldb_message_element *el = NULL;
+
+ attr = ldb_parse_tree_get_attr(tree);
+ if (attr == NULL) {
+ return false;
+ }
+
+ /* find the message element */
+ el = ldb_msg_find_element(msg, attr);
+ if (el == NULL) {
+ return false;
+ }
+
+ return ldb_msg_element_is_inaccessible(el);
+}
+
+/*
+ Check if a particular message will match the given filter
+
+ set *matched to true if it matches, false otherwise
+
+ returns LDB_SUCCESS or an error
+
+ this is a recursive function, and does short-circuit evaluation
+ */
+int ldb_match_message(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope, bool *matched)
+{
+ unsigned int i;
+ int ret;
+
+ *matched = false;
+
+ if (scope != LDB_SCOPE_BASE && ldb_dn_is_special(msg->dn)) {
+ /* don't match special records except on base searches */
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * Suppress matches on confidential attributes (handled
+ * manually in extended matches as these can do custom things
+ * like read other parts of the DB or other attributes).
+ */
+ if (tree->operation != LDB_OP_EXTENDED) {
+ if (ldb_must_suppress_match(msg, tree)) {
+ return LDB_SUCCESS;
+ }
+ }
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
+ if (ret != LDB_SUCCESS) return ret;
+ if (!*matched) return LDB_SUCCESS;
+ }
+ *matched = true;
+ return LDB_SUCCESS;
+
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
+ if (ret != LDB_SUCCESS) return ret;
+ if (*matched) return LDB_SUCCESS;
+ }
+ *matched = false;
+ return LDB_SUCCESS;
+
+ case LDB_OP_NOT:
+ ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched);
+ if (ret != LDB_SUCCESS) return ret;
+ *matched = ! *matched;
+ return LDB_SUCCESS;
+
+ case LDB_OP_EQUALITY:
+ return ldb_match_equality(ldb, msg, tree, scope, matched);
+
+ case LDB_OP_SUBSTRING:
+ return ldb_match_substring(ldb, msg, tree, scope, matched);
+
+ case LDB_OP_GREATER:
+ return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched);
+
+ case LDB_OP_LESS:
+ return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched);
+
+ case LDB_OP_PRESENT:
+ return ldb_match_present(ldb, msg, tree, scope, matched);
+
+ case LDB_OP_APPROX:
+ return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched);
+
+ case LDB_OP_EXTENDED:
+ return ldb_match_extended(ldb, msg, tree, scope, matched);
+ }
+
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+}
+
+/*
+ return 0 if the given parse tree matches the given message. Assumes
+ the message is in sorted order
+
+ return 1 if it matches, and 0 if it doesn't match
+*/
+
+int ldb_match_msg(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ struct ldb_dn *base,
+ enum ldb_scope scope)
+{
+ bool matched;
+ int ret;
+
+ if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
+ return 0;
+ }
+
+ ret = ldb_match_message(ldb, msg, tree, scope, &matched);
+ if (ret != LDB_SUCCESS) {
+ /* to match the old API, we need to consider this a
+ failure to match */
+ return 0;
+ }
+ return matched?1:0;
+}
+
+int ldb_match_msg_error(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ struct ldb_dn *base,
+ enum ldb_scope scope,
+ bool *matched)
+{
+ if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
+ *matched = false;
+ return LDB_SUCCESS;
+ }
+
+ return ldb_match_message(ldb, msg, tree, scope, matched);
+}
+
+int ldb_match_msg_objectclass(const struct ldb_message *msg,
+ const char *objectclass)
+{
+ unsigned int i;
+ struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
+ if (!el) {
+ return 0;
+ }
+ for (i=0; i < el->num_values; i++) {
+ if (ldb_attr_cmp((const char *)el->values[i].data, objectclass) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+_PRIVATE_ int ldb_register_extended_match_rules(struct ldb_context *ldb)
+{
+ struct ldb_extended_match_rule *bitmask_and;
+ struct ldb_extended_match_rule *bitmask_or;
+ struct ldb_extended_match_rule *always_false;
+ int ret;
+
+ /* Register bitmask-and match */
+ bitmask_and = talloc_zero(ldb, struct ldb_extended_match_rule);
+ if (bitmask_and == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ bitmask_and->oid = LDB_OID_COMPARATOR_AND;
+ bitmask_and->callback = ldb_match_bitmask;
+
+ ret = ldb_register_extended_match_rule(ldb, bitmask_and);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* Register bitmask-or match */
+ bitmask_or = talloc_zero(ldb, struct ldb_extended_match_rule);
+ if (bitmask_or == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ bitmask_or->oid = LDB_OID_COMPARATOR_OR;
+ bitmask_or->callback = ldb_match_bitmask;
+
+ ret = ldb_register_extended_match_rule(ldb, bitmask_or);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* Register always-false match */
+ always_false = talloc_zero(ldb, struct ldb_extended_match_rule);
+ if (always_false == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ always_false->oid = SAMBA_LDAP_MATCH_ALWAYS_FALSE;
+ always_false->callback = ldb_comparator_false;
+
+ ret = ldb_register_extended_match_rule(ldb, always_false);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ register a new ldb extended matching rule
+*/
+int ldb_register_extended_match_rule(struct ldb_context *ldb,
+ const struct ldb_extended_match_rule *rule)
+{
+ const struct ldb_extended_match_rule *lookup_rule;
+ struct ldb_extended_match_entry *entry;
+
+ lookup_rule = ldb_find_extended_match_rule(ldb, rule->oid);
+ if (lookup_rule) {
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
+
+ entry = talloc_zero(ldb, struct ldb_extended_match_entry);
+ if (!entry) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ entry->rule = rule;
+ DLIST_ADD_END(ldb->extended_match_rules, entry);
+
+ return LDB_SUCCESS;
+}
+
+int ldb_register_redact_callback(struct ldb_context *ldb,
+ ldb_redact_fn redact_fn,
+ struct ldb_module *module)
+{
+ if (ldb->redact.callback != NULL) {
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
+
+ ldb->redact.callback = redact_fn;
+ ldb->redact.module = module;
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb/common/ldb_modules.c b/lib/ldb/common/ldb_modules.c
new file mode 100644
index 0000000..b5627b0
--- /dev/null
+++ b/lib/ldb/common/ldb_modules.c
@@ -0,0 +1,1237 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2004-2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb modules core
+ *
+ * Description: core modules routines
+ *
+ * Author: Simo Sorce
+ */
+
+#include "ldb_private.h"
+#include "dlinklist.h"
+#include "system/dir.h"
+
+static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string)
+{
+ size_t i, len;
+ char *trimmed;
+
+ trimmed = talloc_strdup(mem_ctx, string);
+ if (!trimmed) {
+ return NULL;
+ }
+
+ len = strlen(trimmed);
+ for (i = 0; trimmed[i] != '\0'; i++) {
+ switch (trimmed[i]) {
+ case ' ':
+ case '\t':
+ case '\n':
+ memmove(&trimmed[i], &trimmed[i + 1], len -i -1);
+ break;
+ }
+ }
+
+ return trimmed;
+}
+
+
+/* modules are called in inverse order on the stack.
+ Lets place them as an admin would think the right order is.
+ Modules order is important */
+const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string)
+{
+ char **modules = NULL;
+ const char **m;
+ char *modstr, *p;
+ unsigned int i;
+
+ /* spaces not admitted */
+ modstr = ldb_modules_strdup_no_spaces(mem_ctx, string);
+ if ( ! modstr) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_strdup_no_spaces()");
+ return NULL;
+ }
+
+ modules = talloc_realloc(mem_ctx, modules, char *, 2);
+ if ( ! modules ) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()");
+ talloc_free(modstr);
+ return NULL;
+ }
+ talloc_steal(modules, modstr);
+
+ if (modstr[0] == '\0') {
+ modules[0] = NULL;
+ m = discard_const_p(const char *, modules);
+ return m;
+ }
+
+ i = 0;
+ /* The str*r*chr walks backwards: This is how we get the inverse order mentioned above */
+ while ((p = strrchr(modstr, ',')) != NULL) {
+ *p = '\0';
+ p++;
+ modules[i] = p;
+
+ i++;
+ modules = talloc_realloc(mem_ctx, modules, char *, i + 2);
+ if ( ! modules ) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()");
+ return NULL;
+ }
+
+ }
+ modules[i] = modstr;
+
+ modules[i + 1] = NULL;
+
+ m = discard_const_p(const char *, modules);
+
+ return m;
+}
+
+static struct backends_list_entry {
+ struct ldb_backend_ops *ops;
+ struct backends_list_entry *prev, *next;
+} *ldb_backends = NULL;
+
+static struct ops_list_entry {
+ const struct ldb_module_ops *ops;
+ struct ops_list_entry *next;
+} *registered_modules = NULL;
+
+static struct backends_list_entry *ldb_find_backend(const char *url_prefix)
+{
+ struct backends_list_entry *backend;
+
+ for (backend = ldb_backends; backend; backend = backend->next) {
+ if (strcmp(backend->ops->name, url_prefix) == 0) {
+ return backend;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ register a new ldb backend
+
+ if override is true, then override any existing backend for this prefix
+*/
+int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn, bool override)
+{
+ struct backends_list_entry *be;
+
+ be = ldb_find_backend(url_prefix);
+ if (be) {
+ if (!override) {
+ return LDB_SUCCESS;
+ }
+ } else {
+ be = talloc_zero(ldb_backends, struct backends_list_entry);
+ if (!be) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ be->ops = talloc_zero(be, struct ldb_backend_ops);
+ if (!be->ops) {
+ talloc_free(be);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ DLIST_ADD_END(ldb_backends, be);
+ }
+
+ be->ops->name = url_prefix;
+ be->ops->connect_fn = connectfn;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ Return the ldb module form of a database.
+ The URL looks something like this:
+ tdb://PATH
+ ldb://PATH
+ mdb://PATH
+ ldapi://PATH
+ PATH (unadorned PATH defaults to tdb://)
+
+ for a complete list of backends (including possibly unmaintained ones) grep
+ for calls to ldb_register_backend().
+
+ the options are passed uninterpreted to the backend, and are
+ backend specific.
+
+ This allows modules to get at only the backend module, for example where a
+ module may wish to direct certain requests at a particular backend.
+*/
+int ldb_module_connect_backend(struct ldb_context *ldb,
+ const char *url,
+ const char *options[],
+ struct ldb_module **backend_module)
+{
+ int ret;
+ char *backend;
+ struct backends_list_entry *be;
+ char *colon = NULL;
+
+ colon = strchr(url, ':');
+ if (colon != NULL) {
+ backend = talloc_strndup(ldb, url, colon-url);
+ } else {
+ /* Default to tdb */
+ backend = talloc_strdup(ldb, "tdb");
+ }
+ if (backend == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ be = ldb_find_backend(backend);
+
+ talloc_free(backend);
+
+ if (be == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "Unable to find backend for '%s' - do you need to set LDB_MODULES_PATH?", url);
+ return LDB_ERR_OTHER;
+ }
+
+ ret = be->ops->connect_fn(ldb, url, ldb->flags, options, backend_module);
+
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Failed to connect to '%s' with backend '%s': %s", url, be->ops->name, ldb_errstring(ldb));
+ return ret;
+ }
+ return ret;
+}
+
+static struct ldb_hooks {
+ struct ldb_hooks *next, *prev;
+ ldb_hook_fn hook_fn;
+} *ldb_hooks;
+
+/*
+ register a ldb hook function
+ */
+int ldb_register_hook(ldb_hook_fn hook_fn)
+{
+ struct ldb_hooks *lc;
+ lc = talloc_zero(ldb_hooks, struct ldb_hooks);
+ if (lc == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ lc->hook_fn = hook_fn;
+ DLIST_ADD_END(ldb_hooks, lc);
+ return LDB_SUCCESS;
+}
+
+/*
+ call ldb hooks of a given type
+ */
+int ldb_modules_hook(struct ldb_context *ldb, enum ldb_module_hook_type t)
+{
+ struct ldb_hooks *lc;
+ for (lc = ldb_hooks; lc; lc=lc->next) {
+ int ret = lc->hook_fn(ldb, t);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return LDB_SUCCESS;
+}
+
+
+static const struct ldb_module_ops *ldb_find_module_ops(const char *name)
+{
+ struct ops_list_entry *e;
+
+ for (e = registered_modules; e; e = e->next) {
+ if (strcmp(e->ops->name, name) == 0)
+ return e->ops;
+ }
+
+ return NULL;
+}
+
+
+int ldb_register_module(const struct ldb_module_ops *ops)
+{
+ struct ops_list_entry *entry;
+
+ if (ldb_find_module_ops(ops->name) != NULL)
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+
+ /*
+ * ldb modules are not (yet) unloaded and
+ * are only loaded once (the above check
+ * makes sure of this). Allocate off the NULL
+ * context. We never want this to be freed
+ * until process shutdown. If eventually we
+ * want to unload ldb modules we can add a
+ * deregister function that walks and
+ * frees the list.
+ */
+ entry = talloc(NULL, struct ops_list_entry);
+ if (entry == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ entry->ops = ops;
+ entry->next = registered_modules;
+ registered_modules = entry;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ load a list of modules
+ */
+int ldb_module_load_list(struct ldb_context *ldb, const char **module_list,
+ struct ldb_module *backend, struct ldb_module **out)
+{
+ struct ldb_module *module;
+ unsigned int i;
+
+ module = backend;
+
+ for (i = 0; module_list && module_list[i] != NULL; i++) {
+ struct ldb_module *current;
+ const struct ldb_module_ops *ops;
+
+ if (strcmp(module_list[i], "") == 0) {
+ continue;
+ }
+
+ ops = ldb_find_module_ops(module_list[i]);
+
+ if (ops == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "WARNING: Module [%s] not found - do you need to set LDB_MODULES_PATH?",
+ module_list[i]);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ current = talloc_zero(ldb, struct ldb_module);
+ if (current == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ talloc_set_name(current, "ldb_module: %s", module_list[i]);
+
+ current->ldb = ldb;
+ current->ops = ops;
+
+ DLIST_ADD(module, current);
+ }
+ *out = module;
+ return LDB_SUCCESS;
+}
+
+/*
+ initialise a chain of modules
+ */
+int ldb_module_init_chain(struct ldb_context *ldb, struct ldb_module *module)
+{
+ while (module && module->ops->init_context == NULL)
+ module = module->next;
+
+ /* init is different in that it is not an error if modules
+ * do not require initialization */
+
+ if (module) {
+ int ret = module->ops->init_context(module);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "module %s initialization failed : %s",
+ module->ops->name, ldb_strerror(ret));
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+int ldb_load_modules(struct ldb_context *ldb, const char *options[])
+{
+ const char *modules_string;
+ const char **modules = NULL;
+ int ret;
+ TALLOC_CTX *mem_ctx = talloc_new(ldb);
+ if (!mem_ctx) {
+ return ldb_oom(ldb);
+ }
+
+ /* find out which modules we are requested to activate */
+
+ /* check if we have a custom module list passd as ldb option */
+ if (options) {
+ modules_string = ldb_options_find(ldb, options, "modules");
+ if (modules_string) {
+ modules = ldb_modules_list_from_string(ldb, mem_ctx, modules_string);
+ }
+ }
+
+ /* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */
+ if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) {
+ const char * const attrs[] = { "@LIST" , NULL};
+ struct ldb_result *res = NULL;
+ struct ldb_dn *mods_dn;
+
+ mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES");
+ if (mods_dn == NULL) {
+ talloc_free(mem_ctx);
+ return ldb_oom(ldb);
+ }
+
+ ret = ldb_search(ldb, mods_dn, &res, mods_dn, LDB_SCOPE_BASE, attrs, "@LIST=*");
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db");
+ } else if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out", ldb_errstring(ldb));
+ talloc_free(mem_ctx);
+ return ret;
+ } else {
+ const char *module_list;
+ if (res->count == 0) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db");
+ } else if (res->count > 1) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%u), bailing out", res->count);
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ } else {
+ module_list = ldb_msg_find_attr_as_string(res->msgs[0], "@LIST", NULL);
+ if (!module_list) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db");
+ }
+ modules = ldb_modules_list_from_string(ldb, mem_ctx,
+ module_list);
+ }
+ }
+
+ talloc_free(mods_dn);
+ }
+
+ if (modules != NULL) {
+ ret = ldb_module_load_list(ldb, modules, ldb->modules, &ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+ } else {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database");
+ }
+
+ ret = ldb_module_init_chain(ldb, ldb->modules);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ by using this we allow ldb modules to only implement the functions they care about,
+ which makes writing a module simpler, and makes it more likely to keep working
+ when ldb is extended
+*/
+#define FIND_OP_NOERR(module, op) do { \
+ module = module->next; \
+ while (module && module->ops->op == NULL) module = module->next; \
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { \
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_trace_next_request: (%s)->" #op, \
+ module->ops->name); \
+ } \
+} while (0)
+
+#define FIND_OP(module, op) do { \
+ struct ldb_context *ldb = module->ldb; \
+ FIND_OP_NOERR(module, op); \
+ if (module == NULL) { \
+ ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \
+ return LDB_ERR_OPERATIONS_ERROR; \
+ } \
+} while (0)
+
+
+struct ldb_module *ldb_module_new(TALLOC_CTX *memctx,
+ struct ldb_context *ldb,
+ const char *module_name,
+ const struct ldb_module_ops *ops)
+{
+ struct ldb_module *module;
+
+ module = talloc(memctx, struct ldb_module);
+ if (!module) {
+ ldb_oom(ldb);
+ return NULL;
+ }
+ talloc_set_name_const(module, module_name);
+ module->ldb = ldb;
+ module->prev = module->next = NULL;
+ module->ops = ops;
+
+ return module;
+}
+
+const char * ldb_module_get_name(struct ldb_module *module)
+{
+ return module->ops->name;
+}
+
+struct ldb_context *ldb_module_get_ctx(struct ldb_module *module)
+{
+ return module->ldb;
+}
+
+const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module)
+{
+ return module->ops;
+}
+
+void *ldb_module_get_private(struct ldb_module *module)
+{
+ return module->private_data;
+}
+
+void ldb_module_set_private(struct ldb_module *module, void *private_data)
+{
+ module->private_data = private_data;
+}
+
+/*
+ helper functions to call the next module in chain
+*/
+
+int ldb_next_request(struct ldb_module *module, struct ldb_request *request)
+{
+ int ret;
+
+ if (request->callback == NULL) {
+ ldb_set_errstring(module->ldb, "Requests MUST define callbacks");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ request->handle->nesting++;
+
+ switch (request->operation) {
+ case LDB_SEARCH:
+ FIND_OP(module, search);
+ ret = module->ops->search(module, request);
+ break;
+ case LDB_ADD:
+ FIND_OP(module, add);
+ ret = module->ops->add(module, request);
+ break;
+ case LDB_MODIFY:
+ FIND_OP(module, modify);
+ ret = module->ops->modify(module, request);
+ break;
+ case LDB_DELETE:
+ FIND_OP(module, del);
+ ret = module->ops->del(module, request);
+ break;
+ case LDB_RENAME:
+ FIND_OP(module, rename);
+ ret = module->ops->rename(module, request);
+ break;
+ case LDB_EXTENDED:
+ FIND_OP(module, extended);
+ ret = module->ops->extended(module, request);
+ break;
+ default:
+ FIND_OP(module, request);
+ ret = module->ops->request(module, request);
+ break;
+ }
+
+ request->handle->nesting--;
+
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ const char *op;
+ switch (request->operation) {
+ case LDB_SEARCH:
+ op = "LDB_SEARCH";
+ break;
+ case LDB_ADD:
+ op = "LDB_ADD";
+ break;
+ case LDB_MODIFY:
+ op = "LDB_MODIFY";
+ break;
+ case LDB_DELETE:
+ op = "LDB_DELETE";
+ break;
+ case LDB_RENAME:
+ op = "LDB_RENAME";
+ break;
+ case LDB_EXTENDED:
+ op = "LDB_EXTENDED";
+ break;
+ default:
+ op = "request";
+ break;
+ }
+
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb, "error in module %s: %s during %s (%d)", module->ops->name, ldb_strerror(ret), op, ret);
+ }
+
+ if (!(request->handle->flags & LDB_HANDLE_FLAG_DONE_CALLED)) {
+ /* It is _extremely_ common that a module returns a
+ * failure without calling ldb_module_done(), but that
+ * guarantees we will end up hanging in
+ * ldb_wait(). This fixes it without having to rewrite
+ * all our modules, and leaves us one less sharp
+ * corner for module developers to cut themselves on
+ */
+ ret = ldb_module_done(request, NULL, NULL, ret);
+ }
+ return ret;
+}
+
+int ldb_next_init(struct ldb_module *module)
+{
+ module = module->next;
+
+ return ldb_module_init_chain(module->ldb, module);
+}
+
+int ldb_next_start_trans(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP(module, start_transaction);
+ ret = module->ops->start_transaction(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb, "start_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_start_trans error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
+int ldb_next_end_trans(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP(module, end_transaction);
+ ret = module->ops->end_transaction(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb, "end_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_end_trans error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
+int ldb_next_read_lock(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP(module, read_lock);
+ ret = module->ops->read_lock(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb,
+ "read_lock error in module %s: %s (%d)",
+ module->ops->name, ldb_strerror(ret),
+ ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE,
+ "ldb_next_read_lock error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
+int ldb_next_read_unlock(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP(module, read_unlock);
+ ret = module->ops->read_unlock(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb,
+ "read_unlock error in module %s: %s (%d)",
+ module->ops->name, ldb_strerror(ret),
+ ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE,
+ "ldb_next_read_unlock error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
+int ldb_next_prepare_commit(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP_NOERR(module, prepare_commit);
+ if (module == NULL) {
+ /* we are allowed to have no prepare commit in
+ backends */
+ return LDB_SUCCESS;
+ }
+ ret = module->ops->prepare_commit(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb, "prepare_commit error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_prepare_commit error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
+int ldb_next_del_trans(struct ldb_module *module)
+{
+ int ret;
+ FIND_OP(module, del_transaction);
+ ret = module->ops->del_transaction(module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb, "del_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_del_trans error: %s",
+ ldb_errstring(module->ldb));
+ }
+ return ret;
+}
+
+/* calls the request callback to send an entry
+ *
+ * params:
+ * req: the original request passed to your module
+ * msg: reply message (must be a talloc pointer, and it will be stolen
+ * on the ldb_reply that is sent to the callback)
+ * ctrls: controls to send in the reply (must be a talloc pointer, and it will be stolen
+ * on the ldb_reply that is sent to the callback)
+ */
+
+int ldb_module_send_entry(struct ldb_request *req,
+ struct ldb_message *msg,
+ struct ldb_control **ctrls)
+{
+ struct ldb_reply *ares;
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(req->handle->ldb);
+ req->callback(req, NULL);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ares->type = LDB_REPLY_ENTRY;
+ ares->message = talloc_steal(ares, msg);
+ ares->controls = talloc_steal(ares, ctrls);
+ ares->error = LDB_SUCCESS;
+
+ if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) &&
+ req->handle->nesting == 0) {
+ char *s;
+ struct ldb_ldif ldif;
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = discard_const_p(struct ldb_message, msg);
+
+ ldb_debug_add(req->handle->ldb, "ldb_trace_response: ENTRY\n");
+
+ /*
+ * The choice to call
+ * ldb_ldif_write_redacted_trace_string() is CRITICAL
+ * for security. It ensures that we do not output
+ * passwords into debug logs
+ */
+
+ s = ldb_ldif_write_redacted_trace_string(req->handle->ldb, msg, &ldif);
+ ldb_debug_add(req->handle->ldb, "%s\n", s);
+ talloc_free(s);
+ ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE);
+ }
+
+ return req->callback(req, ares);
+}
+
+/* calls the request callback to send a referral
+ *
+ * params:
+ * req: the original request passed to your module
+ * ref: referral string (must be a talloc pointer, steal)
+ */
+
+int ldb_module_send_referral(struct ldb_request *req,
+ char *ref)
+{
+ struct ldb_reply *ares;
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(req->handle->ldb);
+ req->callback(req, NULL);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ares->type = LDB_REPLY_REFERRAL;
+ ares->referral = talloc_steal(ares, ref);
+ ares->error = LDB_SUCCESS;
+
+ if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) &&
+ req->handle->nesting == 0) {
+ ldb_debug_add(req->handle->ldb, "ldb_trace_response: REFERRAL\n");
+ ldb_debug_add(req->handle->ldb, "ref: %s\n", ref);
+ ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE);
+ }
+
+ return req->callback(req, ares);
+}
+
+/* calls the original request callback
+ *
+ * params:
+ * req: the original request passed to your module
+ * ctrls: controls to send in the reply (must be a talloc pointer, steal)
+ * response: results for extended request (steal)
+ * error: LDB_SUCCESS for a successful return
+ * any other ldb error otherwise
+ */
+int ldb_module_done(struct ldb_request *req,
+ struct ldb_control **ctrls,
+ struct ldb_extended *response,
+ int error)
+{
+ struct ldb_reply *ares;
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(req->handle->ldb);
+ req->callback(req, NULL);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ares->type = LDB_REPLY_DONE;
+ ares->controls = talloc_steal(ares, ctrls);
+ ares->response = talloc_steal(ares, response);
+ ares->error = error;
+
+ req->handle->flags |= LDB_HANDLE_FLAG_DONE_CALLED;
+
+ if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) &&
+ req->handle->nesting == 0) {
+ ldb_debug_add(req->handle->ldb, "ldb_trace_response: DONE\n");
+ ldb_debug_add(req->handle->ldb, "error: %d\n", error);
+ if (ldb_errstring(req->handle->ldb)) {
+ ldb_debug_add(req->handle->ldb, "msg: %s\n",
+ ldb_errstring(req->handle->ldb));
+ }
+ ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE);
+ }
+
+ return req->callback(req, ares);
+}
+
+/* to be used *only* in modules init functions.
+ * this function is synchronous and will register
+ * the requested OID in the rootdse module if present
+ * otherwise it will return an error */
+int ldb_mod_register_control(struct ldb_module *module, const char *oid)
+{
+ struct ldb_request *req;
+ int ret;
+
+ req = talloc_zero(module, struct ldb_request);
+ if (req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_REQ_REGISTER_CONTROL;
+ req->op.reg_control.oid = oid;
+ req->callback = ldb_op_default_callback;
+
+ ldb_set_timeout(module->ldb, req, 0);
+
+ req->handle = ldb_handle_new(req, module->ldb);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_request(module->ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ talloc_free(req);
+
+ return ret;
+}
+
+static int ldb_modules_load_dir(const char *modules_dir, const char *version);
+
+
+/*
+ load one module. A static list of loaded module inode numbers is
+ used to prevent a module being loaded twice
+
+ dlopen() is used on the module, and dlsym() is then used to look for
+ a ldb_init_module() function. If present, that function is called
+ with the ldb version number as an argument.
+
+ The ldb_init_module() function will typically call
+ ldb_register_module() and ldb_register_backend() to register a
+ module or backend, but it may also be used to register command line
+ handling functions, ldif handlers or any other local
+ modifications.
+
+ The ldb_init_module() function does not get a ldb_context passed in,
+ as modules will be used for multiple ldb context handles. The call
+ from the first ldb_init() is just a convenient way to ensure it is
+ called early enough.
+ */
+static int ldb_modules_load_path(const char *path, const char *version)
+{
+ void *handle;
+ int (*init_fn)(const char *);
+ int ret;
+ struct stat st;
+ static struct loaded {
+ struct loaded *next, *prev;
+ ino_t st_ino;
+ dev_t st_dev;
+ } *loaded;
+ struct loaded *le;
+ int dlopen_flags;
+
+#ifdef RTLD_DEEPBIND
+ bool deepbind_enabled = (getenv("LDB_MODULES_DISABLE_DEEPBIND") == NULL);
+#endif
+
+ ret = stat(path, &st);
+ if (ret != 0) {
+ fprintf(stderr, "ldb: unable to stat module %s : %s\n", path, strerror(errno));
+ return LDB_ERR_UNAVAILABLE;
+ }
+
+ for (le=loaded; le; le=le->next) {
+ if (le->st_ino == st.st_ino &&
+ le->st_dev == st.st_dev) {
+ /* its already loaded */
+ return LDB_SUCCESS;
+ }
+ }
+
+ le = talloc(loaded, struct loaded);
+ if (le == NULL) {
+ fprintf(stderr, "ldb: unable to allocated loaded entry\n");
+ return LDB_ERR_UNAVAILABLE;
+ }
+
+ le->st_ino = st.st_ino;
+ le->st_dev = st.st_dev;
+
+ DLIST_ADD_END(loaded, le);
+
+ /* if it is a directory, recurse */
+ if (S_ISDIR(st.st_mode)) {
+ return ldb_modules_load_dir(path, version);
+ }
+
+ dlopen_flags = RTLD_NOW;
+#ifdef RTLD_DEEPBIND
+ /*
+ * use deepbind if possible, to avoid issues with different
+ * system library variants, for example ldb modules may be linked
+ * against Heimdal while the application may use MIT kerberos.
+ *
+ * See the dlopen manpage for details.
+ *
+ * One typical user is the bind_dlz module of Samba,
+ * but symbol versioning might be enough...
+ *
+ * We need a way to disable this in order to allow the
+ * ldb_*ldap modules to work with a preloaded socket wrapper.
+ *
+ * So in future we may remove this completely
+ * or at least invert the default behavior.
+ */
+ if (deepbind_enabled) {
+ dlopen_flags |= RTLD_DEEPBIND;
+ }
+#endif
+
+ handle = dlopen(path, dlopen_flags);
+ if (handle == NULL) {
+ fprintf(stderr, "ldb: unable to dlopen %s : %s\n", path, dlerror());
+ return LDB_SUCCESS;
+ }
+
+ init_fn = dlsym(handle, "ldb_init_module");
+ if (init_fn == NULL) {
+ /* ignore it, it could be an old-style
+ * module. Once we've converted all modules we
+ * could consider this an error */
+ dlclose(handle);
+ return LDB_SUCCESS;
+ }
+
+ ret = init_fn(version);
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ /* the module is already registered - ignore this, as
+ * it can happen if LDB_MODULES_PATH points at both
+ * the build and install directory
+ */
+ ret = LDB_SUCCESS;
+ }
+ return ret;
+}
+
+static int qsort_string(const char **s1, const char **s2)
+{
+ return strcmp(*s1, *s2);
+}
+
+
+/*
+ load all modules from the given ldb modules directory. This is run once
+ during the first ldb_init() call.
+
+ Modules are loaded in alphabetical order to ensure that any module
+ load ordering dependencies are reproducible. Modules should avoid
+ relying on load order
+ */
+static int ldb_modules_load_dir(const char *modules_dir, const char *version)
+{
+ DIR *dir;
+ struct dirent *de;
+ const char **modlist = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ unsigned i, num_modules = 0;
+
+ dir = opendir(modules_dir);
+ if (dir == NULL) {
+ if (errno == ENOENT) {
+ talloc_free(tmp_ctx);
+ /* we don't have any modules */
+ return LDB_SUCCESS;
+ }
+ talloc_free(tmp_ctx);
+ fprintf(stderr, "ldb: unable to open modules directory '%s' - %s\n",
+ modules_dir, strerror(errno));
+ return LDB_ERR_UNAVAILABLE;
+ }
+
+
+ while ((de = readdir(dir))) {
+ if (ISDOT(de->d_name) || ISDOTDOT(de->d_name))
+ continue;
+
+ modlist = talloc_realloc(tmp_ctx, modlist, const char *, num_modules+1);
+ if (modlist == NULL) {
+ talloc_free(tmp_ctx);
+ closedir(dir);
+ fprintf(stderr, "ldb: unable to allocate modules list\n");
+ return LDB_ERR_UNAVAILABLE;
+ }
+ modlist[num_modules] = talloc_asprintf(modlist, "%s/%s", modules_dir, de->d_name);
+ if (modlist[num_modules] == NULL) {
+ talloc_free(tmp_ctx);
+ closedir(dir);
+ fprintf(stderr, "ldb: unable to allocate module list entry\n");
+ return LDB_ERR_UNAVAILABLE;
+ }
+ num_modules++;
+ }
+
+ closedir(dir);
+
+ /* sort the directory, so we get consistent load ordering */
+ TYPESAFE_QSORT(modlist, num_modules, qsort_string);
+
+ for (i=0; i<num_modules; i++) {
+ int ret = ldb_modules_load_path(modlist[i], version);
+ if (ret != LDB_SUCCESS) {
+ fprintf(stderr, "ldb: failed to initialise module %s : %s\n",
+ modlist[i], ldb_strerror(ret));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ talloc_free(tmp_ctx);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ load any additional modules from the given directory
+*/
+void ldb_set_modules_dir(struct ldb_context *ldb, const char *path)
+{
+ int ret = ldb_modules_load_dir(path, LDB_VERSION);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Failed to load modules from: %s\n", path);
+ }
+}
+
+
+/*
+ load all modules static (builtin) modules
+ */
+static int ldb_modules_load_static(const char *version)
+{
+ static bool initialised;
+#define _MODULE_PROTO(init) extern int init(const char *);
+ STATIC_ldb_MODULES_PROTO;
+ const ldb_module_init_fn static_init_functions[] = { STATIC_ldb_MODULES };
+ unsigned i;
+
+ if (initialised) {
+ return LDB_SUCCESS;
+ }
+ initialised = true;
+
+ for (i=0; static_init_functions[i]; i++) {
+ int ret = static_init_functions[i](version);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ load all modules from the given ldb modules path, colon
+ separated.
+
+ modules are loaded recursively for all subdirectories in the paths
+ */
+int ldb_modules_load(const char *modules_path, const char *version)
+{
+ char *tok, *path, *tok_ptr=NULL;
+ int ret;
+
+ ret = ldb_modules_load_static(version);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ path = talloc_strdup(NULL, modules_path);
+ if (path == NULL) {
+ fprintf(stderr, "ldb: failed to allocate modules_path\n");
+ return LDB_ERR_UNAVAILABLE;
+ }
+
+ for (tok=strtok_r(path, ":", &tok_ptr);
+ tok;
+ tok=strtok_r(NULL, ":", &tok_ptr)) {
+ ret = ldb_modules_load_path(tok, version);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(path);
+ return ret;
+ }
+ }
+ talloc_free(path);
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ return a string representation of the calling chain for the given
+ ldb request
+ */
+char *ldb_module_call_chain(struct ldb_request *req, TALLOC_CTX *mem_ctx)
+{
+ char *ret;
+ unsigned int i = 0;
+
+ ret = talloc_strdup(mem_ctx, "");
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ while (req && req->handle) {
+ talloc_asprintf_addbuf(&ret, "req[%u] %p : %s\n",
+ i++, req, ldb_req_location(req));
+ req = req->handle->parent;
+ }
+ return ret;
+}
+
+
+/*
+ return the next module in the chain
+ */
+struct ldb_module *ldb_module_next(struct ldb_module *module)
+{
+ return module->next;
+}
+
+/*
+ set the next module in the module chain
+ */
+void ldb_module_set_next(struct ldb_module *module, struct ldb_module *next)
+{
+ module->next = next;
+}
+
+
+/*
+ get the popt_options pointer in the ldb structure. This allows a ldb
+ module to change the command line parsing
+ */
+struct poptOption **ldb_module_popt_options(struct ldb_context *ldb)
+{
+ return &ldb->popt_options;
+}
+
+
+/*
+ return the current ldb flags LDB_FLG_*
+ */
+uint32_t ldb_module_flags(struct ldb_context *ldb)
+{
+ return ldb->flags;
+}
diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c
new file mode 100644
index 0000000..afddbe4
--- /dev/null
+++ b/lib/ldb/common/ldb_msg.c
@@ -0,0 +1,1784 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb message component utility functions
+ *
+ * Description: functions for manipulating ldb_message structures
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_private.h"
+
+/*
+ create a new ldb_message in a given memory context (NULL for top level)
+*/
+struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, struct ldb_message);
+}
+
+/*
+ find an element in a message by attribute name
+*/
+struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
+ const char *attr_name)
+{
+ unsigned int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
+ return &msg->elements[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ see if two ldb_val structures contain exactly the same data
+ return 1 for a match, 0 for a mismatch
+*/
+int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) return 0;
+ if (v1->data == v2->data) return 1;
+ if (v1->length == 0) return 1;
+
+ if (memcmp(v1->data, v2->data, v1->length) == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ find a value in an element
+ assumes case sensitive comparison
+*/
+struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
+ struct ldb_val *val)
+{
+ unsigned int i;
+ for (i=0;i<el->num_values;i++) {
+ if (ldb_val_equal_exact(val, &el->values[i])) {
+ return &el->values[i];
+ }
+ }
+ return NULL;
+}
+
+
+static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ if (v1->length != v2->length) {
+ return v1->length - v2->length;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+
+/*
+ ldb_msg_find_duplicate_val() will set the **duplicate pointer to the first
+ duplicate value it finds. It does a case sensitive comparison (memcmp).
+
+ LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown
+ options flag, otherwise LDB_SUCCESS.
+*/
+#define LDB_DUP_QUADRATIC_THRESHOLD 10
+
+int ldb_msg_find_duplicate_val(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message_element *el,
+ struct ldb_val **duplicate,
+ uint32_t options)
+{
+ unsigned int i, j;
+ struct ldb_val *val;
+
+ if (options != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *duplicate = NULL;
+
+ /*
+ If there are not many values, it is best to avoid the talloc
+ overhead and just do a brute force search.
+ */
+ if (el->num_values < LDB_DUP_QUADRATIC_THRESHOLD) {
+ for (j = 0; j < el->num_values; j++) {
+ val = &el->values[j];
+ for ( i = j + 1; i < el->num_values; i++) {
+ if (ldb_val_equal_exact(val, &el->values[i])) {
+ *duplicate = val;
+ return LDB_SUCCESS;
+ }
+ }
+ }
+ } else {
+ struct ldb_val *values;
+ values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
+ if (values == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(values, el->values,
+ el->num_values * sizeof(struct ldb_val));
+ TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
+ for (i = 1; i < el->num_values; i++) {
+ if (ldb_val_equal_exact(&values[i],
+ &values[i - 1])) {
+ /* find the original location */
+ for (j = 0; j < el->num_values; j++) {
+ if (ldb_val_equal_exact(&values[i],
+ &el->values[j])
+ ) {
+ *duplicate = &el->values[j];
+ break;
+ }
+ }
+ talloc_free(values);
+ if (*duplicate == NULL) {
+ /* how we got here, I don't know */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+ }
+ }
+ talloc_free(values);
+ }
+ return LDB_SUCCESS;
+}
+
+
+/*
+ Determine whether the values in an element are also in another element.
+
+ Without any flags, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS if the elements
+ share values, or LDB_SUCCESS if they don't. In this case, the function
+ simply determines the set intersection and it doesn't matter in which order
+ the elements are provided.
+
+ With the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, any values in common are
+ removed from the first element and LDB_SUCCESS is returned.
+
+ LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown option.
+ LDB_ERR_INAPPROPRIATE_MATCHING is returned if the elements differ in name.
+*/
+
+int ldb_msg_find_common_values(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *el,
+ struct ldb_message_element *el2,
+ uint32_t options)
+{
+ struct ldb_val *values;
+ struct ldb_val *values2;
+ unsigned int i, j, k, n_values;
+
+ bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
+
+ if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (strcmp(el->name, el2->name) != 0) {
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+ if (el->num_values == 0 || el2->num_values == 0) {
+ return LDB_SUCCESS;
+ }
+ /*
+ With few values, it is better to do the brute-force search than the
+ clever search involving tallocs, memcpys, sorts, etc.
+ */
+ if (MIN(el->num_values, el2->num_values) == 1 ||
+ MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
+ for (i = 0; i < el2->num_values; i++) {
+ for (j = 0; j < el->num_values; j++) {
+ if (ldb_val_equal_exact(&el->values[j],
+ &el2->values[i])) {
+ if (! remove_duplicates) {
+ return \
+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ /*
+ With the remove_duplicates flag, we
+ resolve the intersection by removing
+ the offending one from el.
+ */
+ el->num_values--;
+ for (k = j; k < el->num_values; k++) {
+ el->values[k] = \
+ el->values[k + 1];
+ }
+ j--; /* rewind */
+ }
+ }
+ }
+ return LDB_SUCCESS;
+ }
+
+ values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
+ if (values == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ values2 = talloc_array(mem_ctx, struct ldb_val,
+ el2->num_values);
+ if (values2 == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(values, el->values,
+ el->num_values * sizeof(struct ldb_val));
+ memcpy(values2, el2->values,
+ el2->num_values * sizeof(struct ldb_val));
+ TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
+ TYPESAFE_QSORT(values2, el2->num_values, ldb_val_cmp);
+
+ /*
+ el->n_values may diverge from the number of values in the sorted
+ list when the remove_duplicates flag is used.
+ */
+ n_values = el->num_values;
+ i = 0;
+ j = 0;
+ while (i != n_values && j < el2->num_values) {
+ int ret = ldb_val_cmp(&values[i], &values2[j]);
+ if (ret < 0) {
+ i++;
+ } else if (ret > 0) {
+ j++;
+ } else {
+ /* we have a collision */
+ if (! remove_duplicates) {
+ TALLOC_FREE(values);
+ TALLOC_FREE(values2);
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ /*
+ With the remove_duplicates flag we need to find
+ this in the original list and remove it, which is
+ inefficient but hopefully rare.
+ */
+ for (k = 0; k < el->num_values; k++) {
+ if (ldb_val_equal_exact(&el->values[k],
+ &values[i])) {
+ break;
+ }
+ }
+ el->num_values--;
+ for (; k < el->num_values; k++) {
+ el->values[k] = el->values[k + 1];
+ }
+ i++;
+ }
+ }
+ TALLOC_FREE(values);
+ TALLOC_FREE(values2);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ duplicate a ldb_val structure
+*/
+struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
+{
+ struct ldb_val v2;
+ v2.length = v->length;
+ if (v->data == NULL) {
+ v2.data = NULL;
+ return v2;
+ }
+
+ /* the +1 is to cope with buggy C library routines like strndup
+ that look one byte beyond */
+ v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
+ if (!v2.data) {
+ v2.length = 0;
+ return v2;
+ }
+
+ memcpy(v2.data, v->data, v->length);
+ ((char *)v2.data)[v->length] = 0;
+ return v2;
+}
+
+/**
+ * Adds new empty element to msg->elements
+ */
+static int _ldb_msg_add_el(struct ldb_message *msg,
+ struct ldb_message_element **return_el)
+{
+ struct ldb_message_element *els;
+
+ /*
+ * TODO: Find out a way to assert on input parameters.
+ * msg and return_el must be valid
+ */
+
+ els = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element, msg->num_elements + 1);
+ if (!els) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ els[msg->num_elements] = (struct ldb_message_element) {};
+
+ msg->elements = els;
+ msg->num_elements++;
+
+ *return_el = &els[msg->num_elements-1];
+
+ return LDB_SUCCESS;
+}
+
+/**
+ * Add an empty element with a given name to a message
+ */
+int ldb_msg_add_empty(struct ldb_message *msg,
+ const char *attr_name,
+ int flags,
+ struct ldb_message_element **return_el)
+{
+ int ret;
+ struct ldb_message_element *el;
+
+ ret = _ldb_msg_add_el(msg, &el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* initialize newly added element */
+ el->flags = flags;
+ el->name = talloc_strdup(msg->elements, attr_name);
+ if (!el->name) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (return_el) {
+ *return_el = el;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/**
+ * Adds an element to a message.
+ *
+ * NOTE: Ownership of ldb_message_element fields
+ * is NOT transferred. Thus, if *el pointer
+ * is invalidated for some reason, this will
+ * corrupt *msg contents also
+ */
+int ldb_msg_add(struct ldb_message *msg,
+ const struct ldb_message_element *el,
+ int flags)
+{
+ int ret;
+ struct ldb_message_element *el_new;
+ /* We have to copy this, just in case *el is a pointer into
+ * what ldb_msg_add_empty() is about to realloc() */
+ struct ldb_message_element el_copy = *el;
+
+ ret = _ldb_msg_add_el(msg, &el_new);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ el_new->flags = flags;
+ el_new->name = el_copy.name;
+ el_new->num_values = el_copy.num_values;
+ el_new->values = el_copy.values;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ * add a value to a message element
+ */
+int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *el,
+ const struct ldb_val *val)
+{
+ struct ldb_val *vals;
+
+ if (el->flags & LDB_FLAG_INTERNAL_SHARED_VALUES) {
+ /*
+ * Another message is using this message element's values array,
+ * so we don't want to make any modifications to the original
+ * message, or potentially invalidate its own values by calling
+ * talloc_realloc(). Make a copy instead.
+ */
+ el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
+
+ vals = talloc_array(mem_ctx, struct ldb_val,
+ el->num_values + 1);
+ if (vals == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (el->values != NULL) {
+ memcpy(vals, el->values, el->num_values * sizeof(struct ldb_val));
+ }
+ } else {
+ vals = talloc_realloc(mem_ctx, el->values, struct ldb_val,
+ el->num_values + 1);
+ if (vals == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ el->values = vals;
+ el->values[el->num_values] = *val;
+ el->num_values++;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ add a value to a message
+*/
+int ldb_msg_add_value(struct ldb_message *msg,
+ const char *attr_name,
+ const struct ldb_val *val,
+ struct ldb_message_element **return_el)
+{
+ struct ldb_message_element *el;
+ int ret;
+
+ el = ldb_msg_find_element(msg, attr_name);
+ if (!el) {
+ ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ ret = ldb_msg_element_add_value(msg->elements, el, val);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (return_el) {
+ *return_el = el;
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ add a value to a message, stealing it into the 'right' place
+*/
+int ldb_msg_add_steal_value(struct ldb_message *msg,
+ const char *attr_name,
+ struct ldb_val *val)
+{
+ int ret;
+ struct ldb_message_element *el;
+
+ ret = ldb_msg_add_value(msg, attr_name, val, &el);
+ if (ret == LDB_SUCCESS) {
+ talloc_steal(el->values, val->data);
+ }
+ return ret;
+}
+
+
+/*
+ add a string element to a message, specifying flags
+*/
+int ldb_msg_add_string_flags(struct ldb_message *msg,
+ const char *attr_name, const char *str,
+ int flags)
+{
+ struct ldb_val val;
+ int ret;
+ struct ldb_message_element *el = NULL;
+
+ val.data = discard_const_p(uint8_t, str);
+ val.length = strlen(str);
+
+ if (val.length == 0) {
+ /* allow empty strings as non-existent attributes */
+ return LDB_SUCCESS;
+ }
+
+ ret = ldb_msg_add_value(msg, attr_name, &val, &el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (flags != 0) {
+ el->flags = flags;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ add a string element to a message
+*/
+int ldb_msg_add_string(struct ldb_message *msg,
+ const char *attr_name, const char *str)
+{
+ return ldb_msg_add_string_flags(msg, attr_name, str, 0);
+}
+
+/*
+ add a string element to a message, stealing it into the 'right' place
+*/
+int ldb_msg_add_steal_string(struct ldb_message *msg,
+ const char *attr_name, char *str)
+{
+ struct ldb_val val;
+
+ val.data = (uint8_t *)str;
+ val.length = strlen(str);
+
+ if (val.length == 0) {
+ /* allow empty strings as non-existent attributes */
+ return LDB_SUCCESS;
+ }
+
+ return ldb_msg_add_steal_value(msg, attr_name, &val);
+}
+
+/*
+ add a DN element to a message
+*/
+int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
+ struct ldb_dn *dn)
+{
+ char *str = ldb_dn_alloc_linearized(msg, dn);
+
+ if (str == NULL) {
+ /* we don't want to have unknown DNs added */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_msg_add_steal_string(msg, attr_name, str);
+}
+
+/*
+ add a printf formatted element to a message
+*/
+int ldb_msg_add_fmt(struct ldb_message *msg,
+ const char *attr_name, const char *fmt, ...)
+{
+ struct ldb_val val;
+ va_list ap;
+ char *str;
+
+ va_start(ap, fmt);
+ str = talloc_vasprintf(msg, fmt, ap);
+ va_end(ap);
+
+ if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ val.data = (uint8_t *)str;
+ val.length = strlen(str);
+
+ return ldb_msg_add_steal_value(msg, attr_name, &val);
+}
+
+static int ldb_msg_append_value_impl(struct ldb_message *msg,
+ const char *attr_name,
+ const struct ldb_val *val,
+ int flags,
+ struct ldb_message_element **return_el)
+{
+ struct ldb_message_element *el = NULL;
+ int ret;
+
+ ret = ldb_msg_add_empty(msg, attr_name, flags, &el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_msg_element_add_value(msg->elements, el, val);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (return_el != NULL) {
+ *return_el = el;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ append a value to a message
+*/
+int ldb_msg_append_value(struct ldb_message *msg,
+ const char *attr_name,
+ const struct ldb_val *val,
+ int flags)
+{
+ return ldb_msg_append_value_impl(msg, attr_name, val, flags, NULL);
+}
+
+/*
+ append a value to a message, stealing it into the 'right' place
+*/
+int ldb_msg_append_steal_value(struct ldb_message *msg,
+ const char *attr_name,
+ struct ldb_val *val,
+ int flags)
+{
+ int ret;
+ struct ldb_message_element *el = NULL;
+
+ ret = ldb_msg_append_value_impl(msg, attr_name, val, flags, &el);
+ if (ret == LDB_SUCCESS) {
+ talloc_steal(el->values, val->data);
+ }
+ return ret;
+}
+
+/*
+ append a string element to a message, stealing it into the 'right' place
+*/
+int ldb_msg_append_steal_string(struct ldb_message *msg,
+ const char *attr_name, char *str,
+ int flags)
+{
+ struct ldb_val val;
+
+ val.data = (uint8_t *)str;
+ val.length = strlen(str);
+
+ if (val.length == 0) {
+ /* allow empty strings as non-existent attributes */
+ return LDB_SUCCESS;
+ }
+
+ return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
+}
+
+/*
+ append a string element to a message
+*/
+int ldb_msg_append_string(struct ldb_message *msg,
+ const char *attr_name, const char *str, int flags)
+{
+ struct ldb_val val;
+
+ val.data = discard_const_p(uint8_t, str);
+ val.length = strlen(str);
+
+ if (val.length == 0) {
+ /* allow empty strings as non-existent attributes */
+ return LDB_SUCCESS;
+ }
+
+ return ldb_msg_append_value(msg, attr_name, &val, flags);
+}
+
+/*
+ append a DN element to a message
+*/
+int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
+ struct ldb_dn *dn, int flags)
+{
+ char *str = ldb_dn_alloc_linearized(msg, dn);
+
+ if (str == NULL) {
+ /* we don't want to have unknown DNs added */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_msg_append_steal_string(msg, attr_name, str, flags);
+}
+
+/*
+ append a printf formatted element to a message
+*/
+int ldb_msg_append_fmt(struct ldb_message *msg, int flags,
+ const char *attr_name, const char *fmt, ...)
+{
+ struct ldb_val val;
+ va_list ap;
+ char *str = NULL;
+
+ va_start(ap, fmt);
+ str = talloc_vasprintf(msg, fmt, ap);
+ va_end(ap);
+
+ if (str == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ val.data = (uint8_t *)str;
+ val.length = strlen(str);
+
+ return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
+}
+
+/*
+ compare two ldb_message_element structures
+ assumes case sensitive comparison
+*/
+int ldb_msg_element_compare(struct ldb_message_element *el1,
+ struct ldb_message_element *el2)
+{
+ unsigned int i;
+
+ if (el1->num_values != el2->num_values) {
+ return el1->num_values - el2->num_values;
+ }
+
+ for (i=0;i<el1->num_values;i++) {
+ if (!ldb_msg_find_val(el2, &el1->values[i])) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ compare two ldb_message_element structures.
+ Different ordering is considered a mismatch
+*/
+bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
+ const struct ldb_message_element *el2)
+{
+ unsigned i;
+ if (el1->num_values != el2->num_values) {
+ return false;
+ }
+ for (i=0;i<el1->num_values;i++) {
+ if (ldb_val_equal_exact(&el1->values[i],
+ &el2->values[i]) != 1) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ compare two ldb_message_element structures
+ comparing by element name
+*/
+int ldb_msg_element_compare_name(struct ldb_message_element *el1,
+ struct ldb_message_element *el2)
+{
+ if (el1->name == el2->name) {
+ return 0;
+ }
+
+ if (el1->name == NULL) {
+ return -1;
+ }
+
+ if (el2->name == NULL) {
+ return 1;
+ }
+
+ return ldb_attr_cmp(el1->name, el2->name);
+}
+
+void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el)
+{
+ el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
+}
+
+bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el)
+{
+ return (el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE) != 0;
+}
+
+void ldb_msg_remove_inaccessible(struct ldb_message *msg)
+{
+ unsigned i;
+ unsigned num_del = 0;
+
+ for (i = 0; i < msg->num_elements; ++i) {
+ if (ldb_msg_element_is_inaccessible(&msg->elements[i])) {
+ ++num_del;
+ } else if (num_del) {
+ msg->elements[i - num_del] = msg->elements[i];
+ }
+ }
+
+ msg->num_elements -= num_del;
+}
+
+/*
+ convenience functions to return common types from a message
+ these return the first value if the attribute is multi-valued
+*/
+const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
+ const char *attr_name)
+{
+ struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
+ if (!el || el->num_values == 0) {
+ return NULL;
+ }
+ return &el->values[0];
+}
+
+int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ char buf[sizeof("-2147483648")] = {};
+ char *end = NULL;
+ int ret;
+
+ if (!v || !v->data) {
+ return default_value;
+ }
+
+ if (v->length >= sizeof(buf)) {
+ return default_value;
+ }
+
+ memcpy(buf, v->data, v->length);
+ errno = 0;
+ ret = (int) strtoll(buf, &end, 10);
+ if (errno != 0) {
+ return default_value;
+ }
+ if (end && end[0] != '\0') {
+ return default_value;
+ }
+ return ret;
+}
+
+unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
+ const char *attr_name,
+ unsigned int default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ char buf[sizeof("-2147483648")] = {};
+ char *end = NULL;
+ unsigned int ret;
+
+ if (!v || !v->data) {
+ return default_value;
+ }
+
+ if (v->length >= sizeof(buf)) {
+ return default_value;
+ }
+
+ memcpy(buf, v->data, v->length);
+ errno = 0;
+ ret = (unsigned int) strtoll(buf, &end, 10);
+ if (errno != 0) {
+ errno = 0;
+ ret = (unsigned int) strtoull(buf, &end, 10);
+ if (errno != 0) {
+ return default_value;
+ }
+ }
+ if (end && end[0] != '\0') {
+ return default_value;
+ }
+ return ret;
+}
+
+int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
+ const char *attr_name,
+ int64_t default_value)
+{
+ int64_t val = 0;
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ int ret = ldb_val_as_int64(v, &val);
+ return ret ? default_value : val;
+}
+
+int ldb_val_as_int64(const struct ldb_val *v, int64_t *val)
+{
+ char buf[sizeof("-9223372036854775808")] = {};
+ char *end = NULL;
+ int64_t result;
+
+ if (!v || !v->data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (v->length >= sizeof(buf)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(buf, v->data, v->length);
+ errno = 0;
+ result = (int64_t) strtoll(buf, &end, 10);
+ if (errno != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (end && end[0] != '\0') {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *val = result;
+ return LDB_SUCCESS;
+}
+
+uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
+ const char *attr_name,
+ uint64_t default_value)
+{
+ uint64_t val = 0;
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ int ret = ldb_val_as_uint64(v, &val);
+ return ret ? default_value : val;
+}
+
+int ldb_val_as_uint64(const struct ldb_val *v, uint64_t *val)
+{
+ char buf[sizeof("-9223372036854775808")] = {};
+ char *end = NULL;
+ uint64_t result;
+
+ if (!v || !v->data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (v->length >= sizeof(buf)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(buf, v->data, v->length);
+ errno = 0;
+ result = (uint64_t) strtoll(buf, &end, 10);
+ if (errno != 0) {
+ errno = 0;
+ result = (uint64_t) strtoull(buf, &end, 10);
+ if (errno != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ if (end && end[0] != '\0') {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *val = result;
+ return LDB_SUCCESS;
+}
+
+double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
+ const char *attr_name,
+ double default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ char *buf;
+ char *end = NULL;
+ double ret;
+
+ if (!v || !v->data) {
+ return default_value;
+ }
+ buf = talloc_strndup(msg, (const char *)v->data, v->length);
+ if (buf == NULL) {
+ return default_value;
+ }
+
+ errno = 0;
+ ret = strtod(buf, &end);
+ talloc_free(buf);
+ if (errno != 0) {
+ return default_value;
+ }
+ if (end && end[0] != '\0') {
+ return default_value;
+ }
+ return ret;
+}
+
+int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value)
+{
+ bool val = false;
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ int ret = ldb_val_as_bool(v, &val);
+ return ret ? default_value : val;
+}
+
+int ldb_val_as_bool(const struct ldb_val *v, bool *val)
+{
+ if (!v || !v->data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
+ *val = false;
+ return LDB_SUCCESS;
+ }
+ if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
+ *val = true;
+ return LDB_SUCCESS;
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
+ const char *attr_name,
+ const char *default_value)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ if (!v || !v->data) {
+ return default_value;
+ }
+ if (v->data[v->length] != '\0') {
+ return default_value;
+ }
+ return (const char *)v->data;
+}
+
+struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg,
+ const char *attr_name)
+{
+ const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+ return ldb_val_as_dn(ldb, mem_ctx, v);
+}
+
+struct ldb_dn *ldb_val_as_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_val *v)
+{
+ struct ldb_dn *res_dn;
+
+ if (!v || !v->data) {
+ return NULL;
+ }
+ res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
+ if ( ! ldb_dn_validate(res_dn)) {
+ talloc_free(res_dn);
+ return NULL;
+ }
+ return res_dn;
+}
+
+/*
+ sort the elements of a message by name
+*/
+void ldb_msg_sort_elements(struct ldb_message *msg)
+{
+ TYPESAFE_QSORT(msg->elements, msg->num_elements,
+ ldb_msg_element_compare_name);
+}
+
+static struct ldb_message *ldb_msg_copy_shallow_impl(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg)
+{
+ struct ldb_message *msg2;
+ unsigned int i;
+
+ msg2 = talloc(mem_ctx, struct ldb_message);
+ if (msg2 == NULL) return NULL;
+
+ *msg2 = *msg;
+
+ msg2->elements = talloc_array(msg2, struct ldb_message_element,
+ msg2->num_elements);
+ if (msg2->elements == NULL) goto failed;
+
+ for (i=0;i<msg2->num_elements;i++) {
+ msg2->elements[i] = msg->elements[i];
+ }
+
+ return msg2;
+
+failed:
+ talloc_free(msg2);
+ return NULL;
+}
+
+/*
+ shallow copy a message - copying only the elements array so that the caller
+ can safely add new elements without changing the message
+*/
+struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg)
+{
+ struct ldb_message *msg2;
+ unsigned int i;
+
+ msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
+ if (msg2 == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < msg2->num_elements; ++i) {
+ /*
+ * Mark this message's elements as sharing their values with the
+ * original message, so that we don't inadvertently modify or
+ * free them. We don't mark the original message element as
+ * shared, so the original message element should not be
+ * modified or freed while the shallow copy lives.
+ */
+ struct ldb_message_element *el = &msg2->elements[i];
+ el->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
+ }
+
+ return msg2;
+}
+
+/*
+ copy a message, allocating new memory for all parts
+*/
+struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg)
+{
+ struct ldb_message *msg2;
+ unsigned int i, j;
+
+ msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
+ if (msg2 == NULL) return NULL;
+
+ if (msg2->dn != NULL) {
+ msg2->dn = ldb_dn_copy(msg2, msg2->dn);
+ if (msg2->dn == NULL) goto failed;
+ }
+
+ for (i=0;i<msg2->num_elements;i++) {
+ struct ldb_message_element *el = &msg2->elements[i];
+ struct ldb_val *values = el->values;
+ if (el->name != NULL) {
+ el->name = talloc_strdup(msg2->elements, el->name);
+ if (el->name == NULL) goto failed;
+ }
+ el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
+ if (el->values == NULL) goto failed;
+ for (j=0;j<el->num_values;j++) {
+ el->values[j] = ldb_val_dup(el->values, &values[j]);
+ if (el->values[j].data == NULL && values[j].length != 0) {
+ goto failed;
+ }
+ }
+
+ /*
+ * Since we copied this element's values, we can mark them as
+ * not shared.
+ */
+ el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
+ }
+
+ return msg2;
+
+failed:
+ talloc_free(msg2);
+ return NULL;
+}
+
+
+/**
+ * Canonicalize a message, merging elements of the same name
+ */
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+ const struct ldb_message *msg)
+{
+ int ret;
+ struct ldb_message *msg2;
+
+ /*
+ * Preserve previous behavior and allocate
+ * *msg2 into *ldb context
+ */
+ ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
+ if (ret != LDB_SUCCESS) {
+ return NULL;
+ }
+
+ return msg2;
+}
+
+/**
+ * Canonicalize a message, merging elements of the same name
+ */
+int ldb_msg_normalize(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg,
+ struct ldb_message **_msg_out)
+{
+ unsigned int i;
+ struct ldb_message *msg2;
+
+ msg2 = ldb_msg_copy(mem_ctx, msg);
+ if (msg2 == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_msg_sort_elements(msg2);
+
+ for (i=1; i < msg2->num_elements; i++) {
+ struct ldb_message_element *el1 = &msg2->elements[i-1];
+ struct ldb_message_element *el2 = &msg2->elements[i];
+
+ if (ldb_msg_element_compare_name(el1, el2) == 0) {
+ el1->values = talloc_realloc(msg2->elements,
+ el1->values, struct ldb_val,
+ el1->num_values + el2->num_values);
+ if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
+ talloc_free(msg2);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ memcpy(el1->values + el1->num_values,
+ el2->values,
+ sizeof(struct ldb_val) * el2->num_values);
+ el1->num_values += el2->num_values;
+ talloc_free(discard_const_p(char, el2->name));
+ if ((i+1) < msg2->num_elements) {
+ memmove(el2, el2+1, sizeof(struct ldb_message_element) *
+ (msg2->num_elements - (i+1)));
+ }
+ msg2->num_elements--;
+ i--;
+ }
+ }
+
+ *_msg_out = msg2;
+ return LDB_SUCCESS;
+}
+
+
+/**
+ * return a ldb_message representing the differences between msg1 and msg2.
+ * If you then use this in a ldb_modify() call,
+ * it can be used to save edits to a message
+ */
+struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2)
+{
+ int ldb_ret;
+ struct ldb_message *mod;
+
+ ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
+ if (ldb_ret != LDB_SUCCESS) {
+ return NULL;
+ }
+
+ return mod;
+}
+
+/**
+ * return a ldb_message representing the differences between msg1 and msg2.
+ * If you then use this in a ldb_modify() call it can be used to save edits to a message
+ *
+ * Result message is constructed as follows:
+ * - LDB_FLAG_MOD_ADD - elements found only in msg2
+ * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
+ * Value for msg2 element is used
+ * - LDB_FLAG_MOD_DELETE - elements found only in msg2
+ *
+ * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
+ */
+int ldb_msg_difference(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2,
+ struct ldb_message **_msg_out)
+{
+ int ldb_res;
+ unsigned int i;
+ struct ldb_message *mod;
+ struct ldb_message_element *el;
+ TALLOC_CTX *temp_ctx;
+
+ temp_ctx = talloc_new(mem_ctx);
+ if (!temp_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ mod = ldb_msg_new(temp_ctx);
+ if (mod == NULL) {
+ goto failed;
+ }
+
+ mod->dn = msg1->dn;
+ mod->num_elements = 0;
+ mod->elements = NULL;
+
+ /*
+ * Canonicalize *msg2 so we have no repeated elements
+ * Resulting message is allocated in *mod's mem context,
+ * as we are going to move some elements from *msg2 to
+ * *mod object later
+ */
+ ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
+ if (ldb_res != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ /* look in msg2 to find elements that need to be added or modified */
+ for (i=0;i<msg2->num_elements;i++) {
+ el = ldb_msg_find_element(msg1, msg2->elements[i].name);
+
+ if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
+ continue;
+ }
+
+ ldb_res = ldb_msg_add(mod,
+ &msg2->elements[i],
+ el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
+ if (ldb_res != LDB_SUCCESS) {
+ goto failed;
+ }
+ }
+
+ /* look in msg1 to find elements that need to be deleted */
+ for (i=0;i<msg1->num_elements;i++) {
+ el = ldb_msg_find_element(msg2, msg1->elements[i].name);
+ if (el == NULL) {
+ ldb_res = ldb_msg_add_empty(mod,
+ msg1->elements[i].name,
+ LDB_FLAG_MOD_DELETE, NULL);
+ if (ldb_res != LDB_SUCCESS) {
+ goto failed;
+ }
+ }
+ }
+
+ /* steal resulting message into supplied context */
+ talloc_steal(mem_ctx, mod);
+ *_msg_out = mod;
+
+ talloc_free(temp_ctx);
+ return LDB_SUCCESS;
+
+failed:
+ talloc_free(temp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+
+int ldb_msg_sanity_check(struct ldb_context *ldb,
+ const struct ldb_message *msg)
+{
+ unsigned int i, j;
+
+ /* basic check on DN */
+ if (msg->dn == NULL) {
+ ldb_set_errstring(ldb, "ldb message lacks a DN!");
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ /* basic syntax checks */
+ for (i = 0; i < msg->num_elements; i++) {
+ for (j = 0; j < msg->elements[i].num_values; j++) {
+ if (msg->elements[i].values[j].length == 0) {
+ /* an attribute cannot be empty */
+ ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
+ msg->elements[i].name,
+ ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+
+
+/*
+ copy an attribute list. This only copies the array, not the elements
+ (ie. the elements are left as the same pointers)
+*/
+const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
+{
+ const char **ret;
+ unsigned int i;
+
+ for (i=0;attrs && attrs[i];i++) /* noop */ ;
+ ret = talloc_array(mem_ctx, const char *, i+1);
+ if (ret == NULL) {
+ return NULL;
+ }
+ for (i=0;attrs && attrs[i];i++) {
+ ret[i] = attrs[i];
+ }
+ ret[i] = attrs[i];
+ return ret;
+}
+
+
+/*
+ copy an attribute list. This only copies the array, not the elements
+ (ie. the elements are left as the same pointers). The new attribute is added to the list.
+*/
+const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
+{
+ const char **ret;
+ unsigned int i;
+ bool found = false;
+
+ for (i=0;attrs && attrs[i];i++) {
+ if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
+ found = true;
+ }
+ }
+ if (found) {
+ return ldb_attr_list_copy(mem_ctx, attrs);
+ }
+ ret = talloc_array(mem_ctx, const char *, i+2);
+ if (ret == NULL) {
+ return NULL;
+ }
+ for (i=0;attrs && attrs[i];i++) {
+ ret[i] = attrs[i];
+ }
+ ret[i] = new_attr;
+ ret[i+1] = NULL;
+ return ret;
+}
+
+
+/*
+ return 1 if an attribute is in a list of attributes, or 0 otherwise
+*/
+int ldb_attr_in_list(const char * const *attrs, const char *attr)
+{
+ unsigned int i;
+ for (i=0;attrs && attrs[i];i++) {
+ if (ldb_attr_cmp(attrs[i], attr) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ rename the specified attribute in a search result
+*/
+int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
+{
+ struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
+ if (el == NULL) {
+ return LDB_SUCCESS;
+ }
+ el->name = talloc_strdup(msg->elements, replace);
+ if (el->name == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+}
+
+
+/*
+ copy the specified attribute in a search result to a new attribute
+*/
+int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
+{
+ struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
+ int ret;
+
+ if (el == NULL) {
+ return LDB_SUCCESS;
+ }
+ ret = ldb_msg_add(msg, el, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ return ldb_msg_rename_attr(msg, attr, replace);
+}
+
+/*
+ remove the specified element in a search result
+*/
+void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
+{
+ ptrdiff_t n = (el - msg->elements);
+ if (n >= msg->num_elements || n < 0) {
+ /* the element is not in the list. the caller is crazy. */
+ return;
+ }
+ msg->num_elements--;
+ if (n != msg->num_elements) {
+ memmove(el, el+1, (msg->num_elements - n)*sizeof(*el));
+ }
+}
+
+
+/*
+ remove the specified attribute in a search result
+*/
+void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
+{
+ unsigned int i;
+ unsigned int num_del = 0;
+
+ for (i = 0; i < msg->num_elements; ++i) {
+ if (ldb_attr_cmp(msg->elements[i].name, attr) == 0) {
+ ++num_del;
+ } else if (num_del) {
+ msg->elements[i - num_del] = msg->elements[i];
+ }
+ }
+
+ msg->num_elements -= num_del;
+}
+
+/* Reallocate elements to drop any excess capacity. */
+void ldb_msg_shrink_to_fit(struct ldb_message *msg)
+{
+ if (msg->num_elements > 0) {
+ struct ldb_message_element *elements = talloc_realloc(msg,
+ msg->elements,
+ struct ldb_message_element,
+ msg->num_elements);
+ if (elements != NULL) {
+ msg->elements = elements;
+ }
+ } else {
+ TALLOC_FREE(msg->elements);
+ }
+}
+
+/*
+ return a LDAP formatted GeneralizedTime string
+*/
+char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ char *ts;
+ int r;
+
+ if (!tm) {
+ return NULL;
+ }
+
+ /* we know exactly how long this string will be */
+ ts = talloc_array(mem_ctx, char, 18);
+
+ /* formatted like: 20040408072012.0Z */
+ r = snprintf(ts, 18,
+ "%04u%02u%02u%02u%02u%02u.0Z",
+ tm->tm_year+1900, tm->tm_mon+1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+
+ if (r != 17) {
+ talloc_free(ts);
+ errno = EOVERFLOW;
+ return NULL;
+ }
+
+ return ts;
+}
+
+/*
+ convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
+*/
+time_t ldb_string_to_time(const char *s)
+{
+ struct tm tm;
+
+ if (s == NULL) return 0;
+
+ memset(&tm, 0, sizeof(tm));
+ if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
+/*
+ convert a LDAP GeneralizedTime string in ldb_val format to a
+ time_t.
+*/
+int ldb_val_to_time(const struct ldb_val *v, time_t *t)
+{
+ char val[15] = {0};
+ struct tm tm = {
+ .tm_year = 0,
+ };
+
+ if (v == NULL) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ if (v->data == NULL) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ if (v->length < 16 && v->length != 13) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ if (v->data[v->length - 1] != 'Z') {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ if (v->length == 13) {
+ memcpy(val, v->data, 12);
+
+ if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ if (tm.tm_year < 50) {
+ tm.tm_year += 100;
+ }
+ } else {
+
+ /*
+ * anything between '.' and 'Z' is silently ignored.
+ */
+ if (v->data[14] != '.') {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+
+ memcpy(val, v->data, 14);
+
+ if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ tm.tm_year -= 1900;
+ }
+ tm.tm_mon -= 1;
+
+ *t = timegm(&tm);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ return a LDAP formatted UTCTime string
+*/
+char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ char *ts;
+ int r;
+
+ if (!tm) {
+ return NULL;
+ }
+
+ /* we know exactly how long this string will be */
+ ts = talloc_array(mem_ctx, char, 14);
+
+ /* formatted like: 20040408072012.0Z => 040408072012Z */
+ r = snprintf(ts, 14,
+ "%02u%02u%02u%02u%02u%02uZ",
+ (tm->tm_year+1900)%100, tm->tm_mon+1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+
+ if (r != 13) {
+ talloc_free(ts);
+ return NULL;
+ }
+
+ return ts;
+}
+
+/*
+ convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
+*/
+time_t ldb_string_utc_to_time(const char *s)
+{
+ struct tm tm;
+
+ if (s == NULL) return 0;
+
+ memset(&tm, 0, sizeof(tm));
+ if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ if (tm.tm_year < 50) {
+ tm.tm_year += 100;
+ }
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
+
+/*
+ dump a set of results to a file. Useful from within gdb
+*/
+void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
+{
+ unsigned int i;
+
+ for (i = 0; i < result->count; i++) {
+ struct ldb_ldif ldif;
+ fprintf(f, "# record %d\n", i+1);
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = result->msgs[i];
+ ldb_ldif_write_file(ldb, f, &ldif);
+ }
+}
+
+/*
+ checks for a string attribute. Returns "1" on match and otherwise "0".
+*/
+int ldb_msg_check_string_attribute(const struct ldb_message *msg,
+ const char *name, const char *value)
+{
+ struct ldb_message_element *el;
+ struct ldb_val val;
+
+ el = ldb_msg_find_element(msg, name);
+ if (el == NULL) {
+ return 0;
+ }
+
+ val.data = discard_const_p(uint8_t, value);
+ val.length = strlen(value);
+
+ if (ldb_msg_find_val(el, &val)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*
+ compare a ldb_val to a string
+*/
+int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
+{
+ size_t len = strlen(str);
+ if (len != v->length) {
+ return len - v->length;
+ }
+ return strncmp((const char *)v->data, str, len);
+}
diff --git a/lib/ldb/common/ldb_options.c b/lib/ldb/common/ldb_options.c
new file mode 100644
index 0000000..ee8c728
--- /dev/null
+++ b/lib/ldb/common/ldb_options.c
@@ -0,0 +1,107 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2010
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb options[] handling
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_private.h"
+
+/*
+ find an option within an options array
+
+ accepts the following forms:
+
+ NAME
+ NAME:value
+ NAME=value
+
+ returns a pointer into an element of the options[] array, or NULL is
+ not found.
+
+ For the NAME form, returns a pointer to an empty string (thus
+ allowing for boolean options).
+ */
+const char *ldb_options_find(struct ldb_context *ldb, const char *options[],
+ const char *option_name)
+{
+ size_t len = strlen(option_name);
+ int i;
+
+ if (options == NULL) {
+ return NULL;
+ }
+
+ for (i=0; options[i]; i++) {
+ if (strncmp(option_name, options[i], len) != 0) {
+ continue;
+ }
+ if (options[i][len] == ':' || options[i][len] == '=') {
+ return &options[i][len+1];
+ }
+ if (options[i][len] == 0) {
+ return &options[i][len];
+ }
+ }
+
+ return NULL;
+}
+
+const char **ldb_options_copy(TALLOC_CTX *ctx, const char *options[])
+{
+
+ size_t num_options = 0;
+ const char **copy = NULL;
+ size_t i = 0;
+
+ if (options == NULL) {
+ return copy;
+ }
+
+ for (i=0; options[i]; i++) {
+ num_options++;
+ }
+
+ copy = talloc_zero_array(ctx, const char *, num_options + 1);
+ if (copy == NULL) {
+ return copy;
+ }
+
+ for (i=0; options[i]; i++) {
+ copy[i] = talloc_strdup(copy, options[i]);
+ if (copy[i] == NULL) {
+ TALLOC_FREE(copy);
+ return copy;
+ }
+ }
+ return copy;
+}
+
+const char **ldb_options_get(struct ldb_context *ldb)
+{
+ return ldb->options;
+}
diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c
new file mode 100644
index 0000000..b06a6e2
--- /dev/null
+++ b/lib/ldb/common/ldb_pack.c
@@ -0,0 +1,1362 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb pack/unpack
+ *
+ * Description: pack/unpack routines for ldb messages as key/value blobs
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_private.h"
+
+/*
+ * These macros are from byte_array.h via libssh
+ * TODO: This will be replaced with use of the byte_array.h header when it
+ * becomes available.
+ *
+ * Macros for handling integer types in byte arrays
+ *
+ * This file is originally from the libssh.org project
+ *
+ * Copyright (c) 2018 Andreas Schneider <asn@cryptomilk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define _DATA_BYTE_CONST(data, pos) \
+ ((uint8_t)(((const uint8_t *)(data))[(pos)]))
+#define PULL_LE_U8(data, pos) \
+ (_DATA_BYTE_CONST(data, pos))
+#define PULL_LE_U16(data, pos) \
+ ((uint16_t)PULL_LE_U8(data, pos) |\
+ ((uint16_t)(PULL_LE_U8(data, (pos) + 1))) << 8)
+#define PULL_LE_U32(data, pos) \
+ ((uint32_t)(PULL_LE_U16(data, pos) |\
+ ((uint32_t)PULL_LE_U16(data, (pos) + 2)) << 16))
+
+#define _DATA_BYTE(data, pos) \
+ (((uint8_t *)(data))[(pos)])
+#define PUSH_LE_U8(data, pos, val) \
+ (_DATA_BYTE(data, pos) = ((uint8_t)(val)))
+#define PUSH_LE_U16(data, pos, val) \
+ (PUSH_LE_U8((data), (pos), (uint8_t)((uint16_t)(val) & 0xff)),\
+ PUSH_LE_U8((data), (pos) + 1,\
+ (uint8_t)((uint16_t)(val) >> 8)))
+#define PUSH_LE_U32(data, pos, val) \
+ (PUSH_LE_U16((data), (pos), (uint16_t)((uint32_t)(val) & 0xffff)),\
+ PUSH_LE_U16((data), (pos) + 2, (uint16_t)((uint32_t)(val) >> 16)))
+
+#define U32_LEN 4
+#define U16_LEN 2
+#define U8_LEN 1
+#define NULL_PAD_BYTE_LEN 1
+
+static int attribute_storable_values(const struct ldb_message_element *el)
+{
+ if (el->num_values == 0) return 0;
+
+ if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
+
+ return el->num_values;
+}
+
+static int ldb_pack_data_v1(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_val *data)
+{
+ unsigned int i, j, real_elements=0;
+ size_t size, dn_len, attr_len, value_len;
+ const char *dn;
+ uint8_t *p;
+ size_t len;
+
+ dn = ldb_dn_get_linearized(message->dn);
+ if (dn == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* work out how big it needs to be */
+ size = U32_LEN * 2 + NULL_PAD_BYTE_LEN;
+
+ dn_len = strlen(dn);
+ if (size + dn_len < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += dn_len;
+
+ /*
+ * First calculate the buffer size we need, and check for
+ * overflows
+ */
+ for (i=0;i<message->num_elements;i++) {
+ if (attribute_storable_values(&message->elements[i]) == 0) {
+ continue;
+ }
+
+ real_elements++;
+
+ if (size + U32_LEN + NULL_PAD_BYTE_LEN < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += U32_LEN + NULL_PAD_BYTE_LEN;
+
+ attr_len = strlen(message->elements[i].name);
+ if (size + attr_len < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += attr_len;
+
+ for (j=0;j<message->elements[i].num_values;j++) {
+ if (size + U32_LEN + NULL_PAD_BYTE_LEN < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += U32_LEN + NULL_PAD_BYTE_LEN;
+
+ value_len = message->elements[i].values[j].length;
+ if (size + value_len < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += value_len;
+ }
+ }
+
+ /* allocate it */
+ data->data = talloc_array(ldb, uint8_t, size);
+ if (!data->data) {
+ errno = ENOMEM;
+ return -1;
+ }
+ data->length = size;
+
+ p = data->data;
+ PUSH_LE_U32(p, 0, LDB_PACKING_FORMAT);
+ p += U32_LEN;
+ PUSH_LE_U32(p, 0, real_elements);
+ p += U32_LEN;
+
+ /* the dn needs to be packed so we can be case preserving
+ while hashing on a case folded dn */
+ len = dn_len;
+ memcpy(p, dn, len+NULL_PAD_BYTE_LEN);
+ p += len + NULL_PAD_BYTE_LEN;
+
+ for (i=0;i<message->num_elements;i++) {
+ if (attribute_storable_values(&message->elements[i]) == 0) {
+ continue;
+ }
+ len = strlen(message->elements[i].name);
+ memcpy(p, message->elements[i].name, len+NULL_PAD_BYTE_LEN);
+ p += len + NULL_PAD_BYTE_LEN;
+ PUSH_LE_U32(p, 0, message->elements[i].num_values);
+ p += U32_LEN;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ PUSH_LE_U32(p, 0,
+ message->elements[i].values[j].length);
+ p += U32_LEN;
+ memcpy(p, message->elements[i].values[j].data,
+ message->elements[i].values[j].length);
+ p[message->elements[i].values[j].length] = 0;
+ p += message->elements[i].values[j].length +
+ NULL_PAD_BYTE_LEN;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * New pack version designed based on performance profiling of version 1.
+ * The approach is to separate value data from the rest of the record's data.
+ * This improves performance because value data is not needed during unpacking
+ * or filtering of the message's attribute list. During filtering we only copy
+ * attributes which are present in the attribute list, however at the parse
+ * stage we need to point to all attributes as they may be referenced in the
+ * search expression.
+ * With this new format, we don't lose time loading data (eg via
+ * talloc_memdup()) that is never needed (for the vast majority of attributes
+ * are are never found in either the search expression or attribute list).
+ * Additional changes include adding a canonicalized DN (for later
+ * optimizations) and variable width length fields for faster unpacking.
+ * The pack and unpack performance improvement is tested in the torture
+ * test torture_ldb_pack_format_perf.
+ *
+ * Layout:
+ *
+ * Version (4 bytes)
+ * Number of Elements (4 bytes)
+ * DN length (4 bytes)
+ * DN with null terminator (DN length + 1 bytes)
+ * Canonicalized DN length (4 bytes)
+ * Canonicalized DN with null terminator (Canonicalized DN length + 1 bytes)
+ * Number of bytes from here to value data section (4 bytes)
+ * # For each element:
+ * Element name length (4 bytes)
+ * Element name with null terminator (Element name length + 1 bytes)
+ * Number of values (4 bytes)
+ * Width of value lengths
+ * # For each value:
+ * Value data length (#bytes given by width field above)
+ * # For each element:
+ * # For each value:
+ * Value data (#bytes given by corresponding length above)
+ */
+static int ldb_pack_data_v2(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_val *data)
+{
+ unsigned int i, j, real_elements=0;
+ size_t size, dn_len, dn_canon_len, attr_len, value_len;
+ const char *dn, *dn_canon;
+ uint8_t *p, *q;
+ size_t len;
+ size_t max_val_len;
+ uint8_t val_len_width;
+
+ /*
+ * First half of this function will calculate required size for
+ * packed data. Initial size is 20 = 5 * 4. 5 fixed fields are:
+ * version, num elements, dn len, canon dn len, attr section len
+ */
+ size = U32_LEN * 5;
+
+ /*
+ * Get linearized and canonicalized form of the DN and add the lengths
+ * of each to size, plus 1 for null terminator.
+ */
+ dn = ldb_dn_get_linearized(message->dn);
+ if (dn == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ dn_len = strlen(dn) + NULL_PAD_BYTE_LEN;
+ if (size + dn_len < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += dn_len;
+
+ if (ldb_dn_is_special(message->dn)) {
+ dn_canon_len = NULL_PAD_BYTE_LEN;
+ dn_canon = discard_const_p(char, "\0");
+ } else {
+ dn_canon = ldb_dn_canonical_string(message->dn, message->dn);
+ if (dn_canon == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ dn_canon_len = strlen(dn_canon) + NULL_PAD_BYTE_LEN;
+ if (size + dn_canon_len < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ size += dn_canon_len;
+
+ /* Add the size required by each element */
+ for (i=0;i<message->num_elements;i++) {
+ if (attribute_storable_values(&message->elements[i]) == 0) {
+ continue;
+ }
+
+ real_elements++;
+
+ /*
+ * Add length of element name + 9 for:
+ * 1 for null terminator
+ * 4 for element name length field
+ * 4 for number of values field
+ */
+ attr_len = strlen(message->elements[i].name);
+ if (size + attr_len + U32_LEN * 2 + NULL_PAD_BYTE_LEN < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += attr_len + U32_LEN * 2 + NULL_PAD_BYTE_LEN;
+
+ /*
+ * Find the max value length, so we can calculate the width
+ * required for the value length fields.
+ */
+ max_val_len = 0;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ value_len = message->elements[i].values[j].length;
+ if (value_len > max_val_len) {
+ max_val_len = value_len;
+ }
+
+ if (size + value_len + NULL_PAD_BYTE_LEN < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += value_len + NULL_PAD_BYTE_LEN;
+ }
+
+ if (max_val_len <= UCHAR_MAX) {
+ val_len_width = U8_LEN;
+ } else if (max_val_len <= USHRT_MAX) {
+ val_len_width = U16_LEN;
+ } else if (max_val_len <= UINT_MAX) {
+ val_len_width = U32_LEN;
+ } else {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ /* Total size required for val lengths (re-using variable) */
+ max_val_len = (val_len_width*message->elements[i].num_values);
+
+ /* Add one for storing the width */
+ max_val_len += U8_LEN;
+ if (size + max_val_len < size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ size += max_val_len;
+ }
+
+ /* Allocate */
+ data->data = talloc_array(ldb, uint8_t, size);
+ if (!data->data) {
+ errno = ENOMEM;
+ return -1;
+ }
+ data->length = size;
+
+ /* Packing format version and number of element */
+ p = data->data;
+ PUSH_LE_U32(p, 0, LDB_PACKING_FORMAT_V2);
+ p += U32_LEN;
+ PUSH_LE_U32(p, 0, real_elements);
+ p += U32_LEN;
+
+ /* Pack DN and Canonicalized DN */
+ PUSH_LE_U32(p, 0, dn_len-NULL_PAD_BYTE_LEN);
+ p += U32_LEN;
+ memcpy(p, dn, dn_len);
+ p += dn_len;
+
+ PUSH_LE_U32(p, 0, dn_canon_len-NULL_PAD_BYTE_LEN);
+ p += U32_LEN;
+ memcpy(p, dn_canon, dn_canon_len);
+ p += dn_canon_len;
+
+ /*
+ * Save pointer at this point and leave a U32_LEN gap for
+ * storing the size of the attribute names and value lengths
+ * section
+ */
+ q = p;
+ p += U32_LEN;
+
+ for (i=0;i<message->num_elements;i++) {
+ if (attribute_storable_values(&message->elements[i]) == 0) {
+ continue;
+ }
+
+ /* Length of el name */
+ len = strlen(message->elements[i].name);
+ PUSH_LE_U32(p, 0, len);
+ p += U32_LEN;
+
+ /*
+ * Even though we have the element name's length, put a null
+ * terminator at the end so if any code uses the name
+ * directly, it'll be safe to do things requiring null
+ * termination like strlen
+ */
+ memcpy(p, message->elements[i].name, len+NULL_PAD_BYTE_LEN);
+ p += len + NULL_PAD_BYTE_LEN;
+ /* Num values */
+ PUSH_LE_U32(p, 0, message->elements[i].num_values);
+ p += U32_LEN;
+
+ /*
+ * Calculate value length width again. It's faster to
+ * calculate it again than do the array management to
+ * store the result during size calculation.
+ */
+ max_val_len = 0;
+ for (j=0;j<message->elements[i].num_values;j++) {
+ value_len = message->elements[i].values[j].length;
+ if (value_len > max_val_len) {
+ max_val_len = value_len;
+ }
+ }
+
+ if (max_val_len <= UCHAR_MAX) {
+ val_len_width = U8_LEN;
+ } else if (max_val_len <= USHRT_MAX) {
+ val_len_width = U16_LEN;
+ } else if (max_val_len <= UINT_MAX) {
+ val_len_width = U32_LEN;
+ } else {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ /* Pack the width */
+ *p = val_len_width & 0xFF;
+ p += U8_LEN;
+
+ /*
+ * Pack each value's length using the minimum number of bytes
+ * required, which we just calculated. We repeat the loop
+ * for each case here so the compiler can inline code.
+ */
+ if (val_len_width == U8_LEN) {
+ for (j=0;j<message->elements[i].num_values;j++) {
+ PUSH_LE_U8(p, 0,
+ message->elements[i].values[j].length);
+ p += U8_LEN;
+ }
+ } else if (val_len_width == U16_LEN) {
+ for (j=0;j<message->elements[i].num_values;j++) {
+ PUSH_LE_U16(p, 0,
+ message->elements[i].values[j].length);
+ p += U16_LEN;
+ }
+ } else if (val_len_width == U32_LEN) {
+ for (j=0;j<message->elements[i].num_values;j++) {
+ PUSH_LE_U32(p, 0,
+ message->elements[i].values[j].length);
+ p += U32_LEN;
+ }
+ }
+ }
+
+ /*
+ * We've finished packing the attr names and value lengths
+ * section, so store the size in the U32_LEN gap we left
+ * earlier
+ */
+ PUSH_LE_U32(q, 0, p-q);
+
+ /* Now pack the values */
+ for (i=0;i<message->num_elements;i++) {
+ if (attribute_storable_values(&message->elements[i]) == 0) {
+ continue;
+ }
+ for (j=0;j<message->elements[i].num_values;j++) {
+ memcpy(p, message->elements[i].values[j].data,
+ message->elements[i].values[j].length);
+
+ /*
+ * Even though we have the data length, put a null
+ * terminator at the end of each value's data so if
+ * any code uses the data directly, it'll be safe to
+ * do things requiring null termination like strlen.
+ */
+ p[message->elements[i].values[j].length] = 0;
+ p += message->elements[i].values[j].length +
+ NULL_PAD_BYTE_LEN;
+ }
+ }
+
+ /*
+ * If we didn't end up at the end of the data here, something has
+ * gone very wrong.
+ */
+ if (p != data->data + size) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ pack a ldb message into a linear buffer in a ldb_val
+
+ note that this routine avoids saving elements with zero values,
+ as these are equivalent to having no element
+
+ caller frees the data buffer after use
+*/
+int ldb_pack_data(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_val *data,
+ uint32_t pack_format_version) {
+
+ if (pack_format_version == LDB_PACKING_FORMAT) {
+ return ldb_pack_data_v1(ldb, message, data);
+ } else if (pack_format_version == LDB_PACKING_FORMAT_V2) {
+ return ldb_pack_data_v2(ldb, message, data);
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+ * Unpack a ldb message from a linear buffer in ldb_val
+ */
+static int ldb_unpack_data_flags_v1(struct ldb_context *ldb,
+ const struct ldb_val *data,
+ struct ldb_message *message,
+ unsigned int flags,
+ unsigned format)
+{
+ uint8_t *p;
+ size_t remaining;
+ size_t dn_len;
+ unsigned int i, j;
+ unsigned int nelem = 0;
+ size_t len;
+ struct ldb_val *ldb_val_single_array = NULL;
+
+ message->elements = NULL;
+
+ p = data->data;
+
+ /* Format (U32, already read) + U32 for num_elements */
+ if (data->length < U32_LEN * 2) {
+ errno = EIO;
+ goto failed;
+ }
+
+ /* Skip first 4 bytes, format already read */
+ p += U32_LEN;
+ message->num_elements = PULL_LE_U32(p, 0);
+ p += U32_LEN;
+
+ remaining = data->length - U32_LEN * 2;
+
+ switch (format) {
+ case LDB_PACKING_FORMAT_NODN:
+ message->dn = NULL;
+ break;
+
+ case LDB_PACKING_FORMAT:
+ /*
+ * With this check, we know that the DN at p is \0
+ * terminated.
+ */
+ dn_len = strnlen((char *)p, remaining);
+ if (dn_len == remaining) {
+ errno = EIO;
+ goto failed;
+ }
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_DN) {
+ message->dn = NULL;
+ } else {
+ struct ldb_val blob;
+ blob.data = discard_const_p(uint8_t, p);
+ blob.length = dn_len;
+ message->dn = ldb_dn_from_ldb_val(message, ldb, &blob);
+ if (message->dn == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+ /*
+ * Redundant: by definition, remaining must be more
+ * than one less than dn_len, as otherwise it would be
+ * == dn_len
+ */
+ if (remaining < dn_len + NULL_PAD_BYTE_LEN) {
+ errno = EIO;
+ goto failed;
+ }
+ remaining -= dn_len + NULL_PAD_BYTE_LEN;
+ p += dn_len + NULL_PAD_BYTE_LEN;
+ break;
+
+ default:
+ errno = EIO;
+ goto failed;
+ }
+
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_ATTRS) {
+ message->num_elements = 0;
+ return 0;
+ }
+
+ if (message->num_elements == 0) {
+ return 0;
+ }
+
+ if (message->num_elements > remaining / 6) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->elements = talloc_zero_array(message, struct ldb_message_element,
+ message->num_elements);
+ if (!message->elements) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ /*
+ * In typical use, most values are single-valued. This makes
+ * it quite expensive to allocate an array of ldb_val for each
+ * of these, just to then hold the pointer to the data buffer
+ * So with LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC we allocate this
+ * ahead of time and use it for the single values where possible.
+ * (This is used the the normal search case, but not in the
+ * index case because of caller requirements).
+ */
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) {
+ ldb_val_single_array = talloc_array(message->elements, struct ldb_val,
+ message->num_elements);
+ if (ldb_val_single_array == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+
+ for (i=0;i<message->num_elements;i++) {
+ const char *attr = NULL;
+ size_t attr_len;
+ struct ldb_message_element *element = NULL;
+
+ /*
+ * Sanity check: Element must be at least the size of empty
+ * attr name and value and NULL terms for each.
+ */
+ if (remaining < U32_LEN * 2 + NULL_PAD_BYTE_LEN * 2) {
+ errno = EIO;
+ goto failed;
+ }
+
+ /*
+ * With this check, we know that the attribute name at
+ * p is \0 terminated.
+ */
+ attr_len = strnlen((char *)p, remaining-6);
+ if (attr_len == remaining-6) {
+ errno = EIO;
+ goto failed;
+ }
+ if (attr_len == 0) {
+ errno = EIO;
+ goto failed;
+ }
+ attr = (char *)p;
+
+ element = &message->elements[nelem];
+ element->name = attr;
+ element->flags = 0;
+
+ if (remaining < (attr_len + NULL_PAD_BYTE_LEN)) {
+ errno = EIO;
+ goto failed;
+ }
+ remaining -= attr_len + NULL_PAD_BYTE_LEN;
+ p += attr_len + NULL_PAD_BYTE_LEN;
+ element->num_values = PULL_LE_U32(p, 0);
+ element->values = NULL;
+ if ((flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) && element->num_values == 1) {
+ element->values = &ldb_val_single_array[nelem];
+ element->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
+ } else if (element->num_values != 0) {
+ element->values = talloc_array(message->elements,
+ struct ldb_val,
+ element->num_values);
+ if (!element->values) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+ p += U32_LEN;
+ if (remaining < U32_LEN) {
+ errno = EIO;
+ goto failed;
+ }
+ remaining -= U32_LEN;
+ for (j = 0; j < element->num_values; j++) {
+ /*
+ * Sanity check: Value must be at least the size of
+ * empty val and NULL terminator.
+ */
+ if (remaining < U32_LEN + NULL_PAD_BYTE_LEN) {
+ errno = EIO;
+ goto failed;
+ }
+ remaining -= U32_LEN + NULL_PAD_BYTE_LEN;
+
+ len = PULL_LE_U32(p, 0);
+ if (remaining < len) {
+ errno = EIO;
+ goto failed;
+ }
+ if (len + NULL_PAD_BYTE_LEN < len) {
+ errno = EIO;
+ goto failed;
+ }
+
+ element->values[j].length = len;
+ element->values[j].data = p + U32_LEN;
+ remaining -= len;
+ p += len + U32_LEN + NULL_PAD_BYTE_LEN;
+ }
+ nelem++;
+ }
+ /*
+ * Adapt the number of elements to the real number of unpacked elements,
+ * it means that we overallocated elements array.
+ */
+ message->num_elements = nelem;
+
+ /*
+ * Shrink the allocated size. On current talloc behaviour
+ * this will help if we skipped 32 or more attributes.
+ */
+ message->elements = talloc_realloc(message, message->elements,
+ struct ldb_message_element,
+ message->num_elements);
+
+ if (remaining != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: %zu bytes unread in ldb_unpack_data_flags",
+ remaining);
+ }
+
+ return 0;
+
+failed:
+ talloc_free(message->elements);
+ return -1;
+}
+
+/*
+ * Unpack a ldb message from a linear buffer in ldb_val
+ */
+static int ldb_unpack_data_flags_v2(struct ldb_context *ldb,
+ const struct ldb_val *data,
+ struct ldb_message *message,
+ unsigned int flags)
+{
+ uint8_t *p, *q, *end_p, *value_section_p;
+ unsigned int i, j;
+ unsigned int nelem = 0;
+ size_t len;
+ struct ldb_val *ldb_val_single_array = NULL;
+ uint8_t val_len_width;
+
+ message->elements = NULL;
+
+ p = data->data;
+ end_p = p + data->length;
+
+ /* Skip first 4 bytes, format already read */
+ p += U32_LEN;
+
+ /* First fields are fixed: num_elements, DN length */
+ if (U32_LEN * 2 > end_p - p) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->num_elements = PULL_LE_U32(p, 0);
+ p += U32_LEN;
+
+ len = PULL_LE_U32(p, 0);
+ p += U32_LEN;
+
+ if (len + NULL_PAD_BYTE_LEN > end_p - p) {
+ errno = EIO;
+ goto failed;
+ }
+
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_DN) {
+ message->dn = NULL;
+ } else {
+ struct ldb_val blob;
+ blob.data = discard_const_p(uint8_t, p);
+ blob.length = len;
+ message->dn = ldb_dn_from_ldb_val(message, ldb, &blob);
+ if (message->dn == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+
+ p += len + NULL_PAD_BYTE_LEN;
+
+ if (*(p-NULL_PAD_BYTE_LEN) != '\0') {
+ errno = EINVAL;
+ goto failed;
+ }
+
+ /* Now skip the canonicalized DN and its length */
+ len = PULL_LE_U32(p, 0) + NULL_PAD_BYTE_LEN;
+ p += U32_LEN;
+
+ if (len > end_p - p) {
+ errno = EIO;
+ goto failed;
+ }
+
+ p += len;
+
+ if (*(p-NULL_PAD_BYTE_LEN) != '\0') {
+ errno = EINVAL;
+ goto failed;
+ }
+
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_ATTRS) {
+ message->num_elements = 0;
+ return 0;
+ }
+
+ if (message->num_elements == 0) {
+ return 0;
+ }
+
+ /*
+ * Sanity check (17 bytes is the minimum element size)
+ */
+ if (message->num_elements > (end_p - p) / 17) {
+ errno = EIO;
+ goto failed;
+ }
+
+ message->elements = talloc_zero_array(message,
+ struct ldb_message_element,
+ message->num_elements);
+ if (!message->elements) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ /*
+ * In typical use, most values are single-valued. This makes
+ * it quite expensive to allocate an array of ldb_val for each
+ * of these, just to then hold the pointer to the data buffer.
+ * So with LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC we allocate this
+ * ahead of time and use it for the single values where possible.
+ * (This is used the the normal search case, but not in the
+ * index case because of caller requirements).
+ */
+ if (flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) {
+ ldb_val_single_array = talloc_array(message->elements,
+ struct ldb_val,
+ message->num_elements);
+ if (ldb_val_single_array == NULL) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+
+ q = p + PULL_LE_U32(p, 0);
+ value_section_p = q;
+ p += U32_LEN;
+
+ for (i=0;i<message->num_elements;i++) {
+ const char *attr = NULL;
+ size_t attr_len;
+ struct ldb_message_element *element = NULL;
+
+ /* Sanity check: minimum element size */
+ if ((U32_LEN * 2) + /* attr name len, num values */
+ (U8_LEN * 2) + /* value length width, one val length */
+ (NULL_PAD_BYTE_LEN * 2) /* null for attr name + val */
+ > value_section_p - p) {
+ errno = EIO;
+ goto failed;
+ }
+
+ attr_len = PULL_LE_U32(p, 0);
+ p += U32_LEN;
+
+ if (attr_len == 0) {
+ errno = EIO;
+ goto failed;
+ }
+ attr = (char *)p;
+
+ p += attr_len + NULL_PAD_BYTE_LEN;
+ /*
+ * num_values, val_len_width
+ *
+ * val_len_width is the width specifier
+ * for the variable length encoding
+ */
+ if (U32_LEN + U8_LEN > value_section_p - p) {
+ errno = EIO;
+ goto failed;
+ }
+
+ if (*(p-NULL_PAD_BYTE_LEN) != '\0') {
+ errno = EINVAL;
+ goto failed;
+ }
+
+ element = &message->elements[nelem];
+ element->name = attr;
+ element->flags = 0;
+
+ element->num_values = PULL_LE_U32(p, 0);
+ element->values = NULL;
+ if ((flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) &&
+ element->num_values == 1) {
+ element->values = &ldb_val_single_array[nelem];
+ element->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
+ } else if (element->num_values != 0) {
+ element->values = talloc_array(message->elements,
+ struct ldb_val,
+ element->num_values);
+ if (!element->values) {
+ errno = ENOMEM;
+ goto failed;
+ }
+ }
+
+ p += U32_LEN;
+
+ /*
+ * Here we read how wide the remaining lengths are
+ * which avoids storing and parsing a lot of leading
+ * 0s
+ */
+ val_len_width = *p;
+ p += U8_LEN;
+
+ if (val_len_width * element->num_values >
+ value_section_p - p) {
+ errno = EIO;
+ goto failed;
+ }
+
+ /*
+ * This is structured weird for compiler optimization
+ * purposes, but we need to pull the array of widths
+ * with different macros depending on how wide the
+ * biggest one is (specified by val_len_width)
+ */
+ if (val_len_width == U8_LEN) {
+ for (j = 0; j < element->num_values; j++) {
+ element->values[j].length = PULL_LE_U8(p, 0);
+ p += U8_LEN;
+ }
+ } else if (val_len_width == U16_LEN) {
+ for (j = 0; j < element->num_values; j++) {
+ element->values[j].length = PULL_LE_U16(p, 0);
+ p += U16_LEN;
+ }
+ } else if (val_len_width == U32_LEN) {
+ for (j = 0; j < element->num_values; j++) {
+ element->values[j].length = PULL_LE_U32(p, 0);
+ p += U32_LEN;
+ }
+ } else {
+ errno = ERANGE;
+ goto failed;
+ }
+
+ for (j = 0; j < element->num_values; j++) {
+ len = element->values[j].length;
+ if (len + NULL_PAD_BYTE_LEN < len) {
+ errno = EIO;
+ goto failed;
+ }
+ if (len + NULL_PAD_BYTE_LEN > end_p - q) {
+ errno = EIO;
+ goto failed;
+ }
+
+ element->values[j].data = q;
+ q += len + NULL_PAD_BYTE_LEN;
+ }
+ nelem++;
+ }
+
+ /*
+ * If p isn't now pointing at the beginning of the value section,
+ * something went very wrong.
+ */
+ if (p != value_section_p) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: Data corruption in ldb_unpack_data_flags");
+ errno = EIO;
+ goto failed;
+ }
+
+ /*
+ * Adapt the number of elements to the real number of unpacked
+ * elements it means that we overallocated elements array.
+ */
+ message->num_elements = nelem;
+
+ /*
+ * Shrink the allocated size. On current talloc behaviour
+ * this will help if we skipped 32 or more attributes.
+ */
+ message->elements = talloc_realloc(message, message->elements,
+ struct ldb_message_element,
+ message->num_elements);
+
+ if (q != end_p) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Error: %zu bytes unread in ldb_unpack_data_flags",
+ end_p - q);
+ errno = EIO;
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ talloc_free(message->elements);
+ return -1;
+}
+
+int ldb_unpack_get_format(const struct ldb_val *data,
+ uint32_t *pack_format_version)
+{
+ if (data->length < U32_LEN) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ *pack_format_version = PULL_LE_U32(data->data, 0);
+ return LDB_SUCCESS;
+}
+
+/*
+ * Unpack a ldb message from a linear buffer in ldb_val
+ */
+int ldb_unpack_data_flags(struct ldb_context *ldb,
+ const struct ldb_val *data,
+ struct ldb_message *message,
+ unsigned int flags)
+{
+ unsigned format;
+
+ if (data->length < U32_LEN) {
+ errno = EIO;
+ return -1;
+ }
+
+ format = PULL_LE_U32(data->data, 0);
+ if (format == LDB_PACKING_FORMAT_V2) {
+ return ldb_unpack_data_flags_v2(ldb, data, message, flags);
+ }
+
+ /*
+ * The v1 function we're about to call takes either LDB_PACKING_FORMAT
+ * or LDB_PACKING_FORMAT_NODN packing format versions, and will error
+ * if given some other version, so we don't need to do any further
+ * checks on 'format'.
+ */
+ return ldb_unpack_data_flags_v1(ldb, data, message, flags, format);
+}
+
+
+/*
+ * Unpack a ldb message from a linear buffer in ldb_val
+ *
+ * Free with ldb_unpack_data_free()
+ */
+int ldb_unpack_data(struct ldb_context *ldb,
+ const struct ldb_val *data,
+ struct ldb_message *message)
+{
+ return ldb_unpack_data_flags(ldb, data, message, 0);
+}
+
+/*
+ add the special distinguishedName element
+*/
+int ldb_msg_add_distinguished_name(struct ldb_message *msg)
+{
+ const char *dn_attr = "distinguishedName";
+ char *dn = NULL;
+
+ if (ldb_msg_find_element(msg, dn_attr)) {
+ /*
+ * This should not happen, but this is
+ * existing behaviour...
+ */
+ return LDB_SUCCESS;
+ }
+
+ dn = ldb_dn_alloc_linearized(msg, msg->dn);
+ if (dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_msg_add_steal_string(msg, dn_attr, dn);
+}
+
+/*
+ * filter the specified list of attributes from msg,
+ * adding requested attributes, and perhaps all for *,
+ * but not the DN to filtered_msg.
+ */
+int ldb_filter_attrs(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const char *const *attrs,
+ struct ldb_message *filtered_msg)
+{
+ unsigned int i;
+ bool keep_all = false;
+ bool add_dn = false;
+ uint32_t num_elements;
+ uint32_t elements_size;
+
+ if (attrs) {
+ /* check for special attrs */
+ for (i = 0; attrs[i]; i++) {
+ int cmp = strcmp(attrs[i], "*");
+ if (cmp == 0) {
+ keep_all = true;
+ break;
+ }
+ cmp = ldb_attr_cmp(attrs[i], "distinguishedName");
+ if (cmp == 0) {
+ add_dn = true;
+ }
+ }
+ } else {
+ keep_all = true;
+ }
+
+ if (keep_all) {
+ add_dn = true;
+ elements_size = msg->num_elements + 1;
+
+ /* Shortcuts for the simple cases */
+ } else if (add_dn && i == 1) {
+ if (ldb_msg_add_distinguished_name(filtered_msg) != 0) {
+ goto failed;
+ }
+ return 0;
+ } else if (i == 0) {
+ return 0;
+
+ /*
+ * Otherwise we are copying at most as many elements as we
+ * have attributes
+ */
+ } else {
+ elements_size = i;
+ }
+
+ filtered_msg->elements = talloc_array(filtered_msg,
+ struct ldb_message_element,
+ elements_size);
+ if (filtered_msg->elements == NULL) goto failed;
+
+ num_elements = 0;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+
+ /*
+ * el2 is assigned after the Pigeonhole principle
+ * check below for clarity
+ */
+ struct ldb_message_element *el2 = NULL;
+ unsigned int j;
+
+ if (keep_all == false) {
+ bool found = false;
+ for (j = 0; attrs[j]; j++) {
+ int cmp = ldb_attr_cmp(el->name, attrs[j]);
+ if (cmp == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (found == false) {
+ continue;
+ }
+ }
+
+ /*
+ * Pigeonhole principle: we can't have more elements
+ * than the number of attributes if they are unique in
+ * the DB.
+ */
+ if (num_elements >= elements_size) {
+ goto failed;
+ }
+
+ el2 = &filtered_msg->elements[num_elements];
+
+ *el2 = *el;
+ el2->name = talloc_strdup(filtered_msg->elements,
+ el->name);
+ if (el2->name == NULL) {
+ goto failed;
+ }
+ el2->values = talloc_array(filtered_msg->elements,
+ struct ldb_val, el->num_values);
+ if (el2->values == NULL) {
+ goto failed;
+ }
+ for (j=0;j<el->num_values;j++) {
+ el2->values[j] = ldb_val_dup(el2->values, &el->values[j]);
+ if (el2->values[j].data == NULL && el->values[j].length != 0) {
+ goto failed;
+ }
+ }
+ num_elements++;
+ }
+
+ filtered_msg->num_elements = num_elements;
+
+ if (add_dn) {
+ if (ldb_msg_add_distinguished_name(filtered_msg) != 0) {
+ goto failed;
+ }
+ }
+
+ if (filtered_msg->num_elements > 0) {
+ filtered_msg->elements
+ = talloc_realloc(filtered_msg,
+ filtered_msg->elements,
+ struct ldb_message_element,
+ filtered_msg->num_elements);
+ if (filtered_msg->elements == NULL) {
+ goto failed;
+ }
+ } else {
+ TALLOC_FREE(filtered_msg->elements);
+ }
+
+ return 0;
+failed:
+ TALLOC_FREE(filtered_msg->elements);
+ return -1;
+}
+
+/*
+ * filter the specified list of attributes from msg,
+ * adding requested attributes, and perhaps all for *.
+ * Unlike ldb_filter_attrs(), the DN will not be added
+ * if it is missing.
+ */
+int ldb_filter_attrs_in_place(struct ldb_message *msg,
+ const char *const *attrs)
+{
+ unsigned int i = 0;
+ bool keep_all = false;
+ unsigned int num_del = 0;
+
+ if (attrs) {
+ /* check for special attrs */
+ for (i = 0; attrs[i]; i++) {
+ int cmp = strcmp(attrs[i], "*");
+ if (cmp == 0) {
+ keep_all = true;
+ break;
+ }
+ }
+ if (!keep_all && i == 0) {
+ msg->num_elements = 0;
+ return LDB_SUCCESS;
+ }
+ } else {
+ keep_all = true;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ bool found = false;
+ unsigned int j;
+
+ if (keep_all) {
+ found = true;
+ } else {
+ for (j = 0; attrs[j]; j++) {
+ int cmp = ldb_attr_cmp(msg->elements[i].name, attrs[j]);
+ if (cmp == 0) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ ++num_del;
+ } else if (num_del != 0) {
+ msg->elements[i - num_del] = msg->elements[i];
+ }
+ }
+
+ msg->num_elements -= num_del;
+
+ return LDB_SUCCESS;
+}
+
+/* Have an unpacked ldb message take talloc ownership of its elements. */
+int ldb_msg_elements_take_ownership(struct ldb_message *msg)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ const char *name;
+ unsigned int j;
+
+ name = talloc_strdup(msg->elements,
+ el->name);
+ if (name == NULL) {
+ return -1;
+ }
+ el->name = name;
+
+ if (el->flags & LDB_FLAG_INTERNAL_SHARED_VALUES) {
+ struct ldb_val *values = talloc_memdup(msg->elements, el->values,
+ sizeof(struct ldb_val) * el->num_values);
+ if (values == NULL) {
+ return -1;
+ }
+ el->values = values;
+ el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
+ }
+
+ for (j = 0; j < el->num_values; j++) {
+ struct ldb_val val = ldb_val_dup(el->values, &el->values[j]);
+ if (val.data == NULL && el->values[j].length != 0) {
+ return -1;
+ }
+ el->values[j] = val;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb/common/ldb_parse.c b/lib/ldb/common/ldb_parse.c
new file mode 100644
index 0000000..f1d224a
--- /dev/null
+++ b/lib/ldb/common/ldb_parse.c
@@ -0,0 +1,1028 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb expression parsing
+ *
+ * Description: parse LDAP-like search expressions
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+ TODO:
+ - add RFC2254 binary string handling
+ - possibly add ~=, <= and >= handling
+ - expand the test suite
+ - add better parse error handling
+
+*/
+
+#include "ldb_private.h"
+#include "system/locale.h"
+
+/*
+ * Maximum depth of the filter parse tree, the value chosen is small enough to
+ * avoid triggering ASAN stack overflow checks. But large enough to be useful.
+ *
+ * On Windows clients the maximum number of levels of recursion allowed is 100.
+ * In the LDAP server, Windows restricts clients to 512 nested
+ * (eg) OR statements.
+ */
+#define LDB_MAX_PARSE_TREE_DEPTH 128
+
+/*
+a filter is defined by:
+ <filter> ::= '(' <filtercomp> ')'
+ <filtercomp> ::= <and> | <or> | <not> | <simple>
+ <and> ::= '&' <filterlist>
+ <or> ::= '|' <filterlist>
+ <not> ::= '!' <filter>
+ <filterlist> ::= <filter> | <filter> <filterlist>
+ <simple> ::= <attributetype> <filtertype> <attributevalue>
+ <filtertype> ::= '=' | '~=' | '<=' | '>='
+*/
+
+/*
+ decode a RFC2254 binary string representation of a buffer.
+ Used in LDAP filters.
+*/
+struct ldb_val ldb_binary_decode(TALLOC_CTX *mem_ctx, const char *str)
+{
+ size_t i, j;
+ struct ldb_val ret;
+ size_t slen = str?strlen(str):0;
+
+ ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1);
+ ret.length = 0;
+ if (ret.data == NULL) return ret;
+
+ for (i=j=0;i<slen;i++) {
+ if (str[i] == '\\') {
+ uint8_t c;
+ bool ok;
+
+ ok = hex_byte(&str[i+1], &c);
+ if (!ok) {
+ talloc_free(ret.data);
+ memset(&ret, 0, sizeof(ret));
+ return ret;
+ }
+ ((uint8_t *)ret.data)[j++] = c;
+ i += 2;
+ } else {
+ ((uint8_t *)ret.data)[j++] = str[i];
+ }
+ }
+ ret.length = j;
+ ((uint8_t *)ret.data)[j] = 0;
+
+ return ret;
+}
+
+static bool need_encode(unsigned char cval)
+{
+ if (cval < 0x20 || cval > 0x7E || strchr(" *()\\&|!\"", cval)) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ encode a blob as a RFC2254 binary string, escaping any
+ non-printable or '\' characters
+*/
+char *ldb_binary_encode(TALLOC_CTX *mem_ctx, struct ldb_val val)
+{
+ size_t i;
+ char *ret;
+ size_t len = val.length;
+ unsigned char *buf = val.data;
+
+ for (i=0;i<val.length;i++) {
+ if (need_encode(buf[i])) {
+ len += 2;
+ }
+ }
+ ret = talloc_array(mem_ctx, char, len+1);
+ if (ret == NULL) return NULL;
+
+ len = 0;
+ for (i=0;i<val.length;i++) {
+ if (need_encode(buf[i])) {
+ snprintf(ret+len, 4, "\\%02X", buf[i]);
+ len += 3;
+ } else {
+ ret[len++] = buf[i];
+ }
+ }
+
+ ret[len] = 0;
+
+ return ret;
+}
+
+/*
+ encode a string as a RFC2254 binary string, escaping any
+ non-printable or '\' characters. This routine is suitable for use
+ in escaping user data in ldap filters.
+*/
+char *ldb_binary_encode_string(TALLOC_CTX *mem_ctx, const char *string)
+{
+ struct ldb_val val;
+ if (string == NULL) {
+ return NULL;
+ }
+ val.data = discard_const_p(uint8_t, string);
+ val.length = strlen(string);
+ return ldb_binary_encode(mem_ctx, val);
+}
+
+/* find the first matching wildcard */
+static char *ldb_parse_find_wildcard(char *value)
+{
+ while (*value) {
+ value = strpbrk(value, "\\*");
+ if (value == NULL) return NULL;
+
+ if (value[0] == '\\') {
+ if (value[1] == '\0') return NULL;
+ value += 2;
+ continue;
+ }
+
+ if (value[0] == '*') return value;
+ }
+
+ return NULL;
+}
+
+/* return a NULL terminated list of binary strings representing the value
+ chunks separated by wildcards that makes the value portion of the filter
+*/
+static struct ldb_val **ldb_wildcard_decode(TALLOC_CTX *mem_ctx, const char *string)
+{
+ struct ldb_val **ret = NULL;
+ unsigned int val = 0;
+ char *wc, *str;
+
+ wc = talloc_strdup(mem_ctx, string);
+ if (wc == NULL) return NULL;
+
+ while (wc && *wc) {
+ str = wc;
+ wc = ldb_parse_find_wildcard(str);
+ if (wc && *wc) {
+ if (wc == str) {
+ wc++;
+ continue;
+ }
+ *wc = 0;
+ wc++;
+ }
+
+ ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
+ if (ret == NULL) return NULL;
+
+ ret[val] = talloc(mem_ctx, struct ldb_val);
+ if (ret[val] == NULL) return NULL;
+
+ *(ret[val]) = ldb_binary_decode(mem_ctx, str);
+ if ((ret[val])->data == NULL) return NULL;
+
+ val++;
+ }
+
+ if (ret != NULL) {
+ ret[val] = NULL;
+ }
+
+ return ret;
+}
+
+static struct ldb_parse_tree *ldb_parse_filter(
+ TALLOC_CTX *mem_ctx,
+ const char **s,
+ unsigned depth,
+ unsigned max_depth);
+
+
+/*
+ parse an extended match
+
+ possible forms:
+ (attr:oid:=value)
+ (attr:dn:oid:=value)
+ (attr:dn:=value)
+ (:dn:oid:=value)
+
+ the ':dn' part sets the dnAttributes boolean if present
+ the oid sets the rule_id string
+
+*/
+static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret,
+ char *attr, char *value)
+{
+ char *p1, *p2;
+
+ ret->operation = LDB_OP_EXTENDED;
+ ret->u.extended.value = ldb_binary_decode(ret, value);
+ if (ret->u.extended.value.data == NULL) goto failed;
+
+ p1 = strchr(attr, ':');
+ if (p1 == NULL) goto failed;
+ p2 = strchr(p1+1, ':');
+
+ *p1 = 0;
+ if (p2) *p2 = 0;
+
+ ret->u.extended.attr = attr;
+ if (strcmp(p1+1, "dn") == 0) {
+ ret->u.extended.dnAttributes = 1;
+ if (p2) {
+ ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
+ if (ret->u.extended.rule_id == NULL) goto failed;
+ } else {
+ ret->u.extended.rule_id = NULL;
+ }
+ } else {
+ ret->u.extended.dnAttributes = 0;
+ ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
+ if (ret->u.extended.rule_id == NULL) goto failed;
+ }
+
+ return ret;
+
+failed:
+ talloc_free(ret);
+ return NULL;
+}
+
+static enum ldb_parse_op ldb_parse_filtertype(TALLOC_CTX *mem_ctx, char **type, char **value, const char **s)
+{
+ enum ldb_parse_op filter = 0;
+ char *name, *val, *k;
+ const char *p = *s;
+ const char *t, *t1;
+
+ /* retrieve attributetype name */
+ t = p;
+
+ if (*p == '@') { /* for internal attributes the first char can be @ */
+ p++;
+ }
+
+ while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-') || (*p == '.')) {
+ /* attribute names can only be alphanums */
+ p++;
+ }
+
+ if (*p == ':') { /* but extended searches have : and . chars too */
+ p = strstr(p, ":=");
+ if (p == NULL) { /* malformed attribute name */
+ return 0;
+ }
+ }
+
+ t1 = p;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ if (!strchr("=<>~:", *p)) {
+ return 0;
+ }
+
+ /* save name */
+ name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1);
+ if (name == NULL) return 0;
+ name[t1 - t] = '\0';
+
+ /* retrieve filtertype */
+
+ if (*p == '=') {
+ filter = LDB_OP_EQUALITY;
+ } else if (*p != '\0' && *(p + 1) == '=') {
+ switch (*p) {
+ case '<':
+ filter = LDB_OP_LESS;
+ p++;
+ break;
+ case '>':
+ filter = LDB_OP_GREATER;
+ p++;
+ break;
+ case '~':
+ filter = LDB_OP_APPROX;
+ p++;
+ break;
+ case ':':
+ filter = LDB_OP_EXTENDED;
+ p++;
+ break;
+ }
+ }
+ if (!filter) {
+ talloc_free(name);
+ return 0;
+ }
+ p++;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ /* retrieve value */
+ t = p;
+
+ while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++;
+
+ val = (char *)talloc_memdup(mem_ctx, t, p - t + 1);
+ if (val == NULL) {
+ talloc_free(name);
+ return 0;
+ }
+ val[p - t] = '\0';
+
+ k = &(val[p - t]);
+
+ /* remove trailing spaces from value */
+ while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--;
+ *k = '\0';
+
+ *type = name;
+ *value = val;
+ *s = p;
+ return filter;
+}
+
+/*
+ <simple> ::= <attributetype> <filtertype> <attributevalue>
+*/
+static struct ldb_parse_tree *ldb_parse_simple(TALLOC_CTX *mem_ctx, const char **s)
+{
+ char *attr, *value;
+ struct ldb_parse_tree *ret;
+ enum ldb_parse_op filtertype;
+
+ ret = talloc_zero(mem_ctx, struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ filtertype = ldb_parse_filtertype(ret, &attr, &value, s);
+ if (!filtertype) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ switch (filtertype) {
+
+ case LDB_OP_PRESENT:
+ ret->operation = LDB_OP_PRESENT;
+ ret->u.present.attr = attr;
+ break;
+
+ case LDB_OP_EQUALITY:
+
+ if (strcmp(value, "*") == 0) {
+ ret->operation = LDB_OP_PRESENT;
+ ret->u.present.attr = attr;
+ break;
+ }
+
+ if (ldb_parse_find_wildcard(value) != NULL) {
+ ret->operation = LDB_OP_SUBSTRING;
+ ret->u.substring.attr = attr;
+ ret->u.substring.start_with_wildcard = 0;
+ ret->u.substring.end_with_wildcard = 0;
+ ret->u.substring.chunks = ldb_wildcard_decode(ret, value);
+ if (ret->u.substring.chunks == NULL){
+ talloc_free(ret);
+ return NULL;
+ }
+ if (value[0] == '*')
+ ret->u.substring.start_with_wildcard = 1;
+ if (value[strlen(value) - 1] == '*')
+ ret->u.substring.end_with_wildcard = 1;
+ talloc_free(value);
+
+ break;
+ }
+
+ ret->operation = LDB_OP_EQUALITY;
+ ret->u.equality.attr = attr;
+ ret->u.equality.value = ldb_binary_decode(ret, value);
+ if (ret->u.equality.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_GREATER:
+ ret->operation = LDB_OP_GREATER;
+ ret->u.comparison.attr = attr;
+ ret->u.comparison.value = ldb_binary_decode(ret, value);
+ if (ret->u.comparison.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_LESS:
+ ret->operation = LDB_OP_LESS;
+ ret->u.comparison.attr = attr;
+ ret->u.comparison.value = ldb_binary_decode(ret, value);
+ if (ret->u.comparison.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_APPROX:
+ ret->operation = LDB_OP_APPROX;
+ ret->u.comparison.attr = attr;
+ ret->u.comparison.value = ldb_binary_decode(ret, value);
+ if (ret->u.comparison.value.data == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ talloc_free(value);
+ break;
+
+ case LDB_OP_EXTENDED:
+
+ ret = ldb_parse_extended(ret, attr, value);
+ break;
+
+ default:
+ talloc_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+/*
+ parse a filterlist
+ <and> ::= '&' <filterlist>
+ <or> ::= '|' <filterlist>
+ <filterlist> ::= <filter> | <filter> <filterlist>
+*/
+static struct ldb_parse_tree *ldb_parse_filterlist(
+ TALLOC_CTX *mem_ctx,
+ const char **s,
+ unsigned depth,
+ unsigned max_depth)
+{
+ struct ldb_parse_tree *ret, *next;
+ enum ldb_parse_op op;
+ const char *p = *s;
+
+ switch (*p) {
+ case '&':
+ op = LDB_OP_AND;
+ break;
+ case '|':
+ op = LDB_OP_OR;
+ break;
+ default:
+ return NULL;
+ }
+ p++;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ ret = talloc(mem_ctx, struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret->operation = op;
+ ret->u.list.num_elements = 1;
+ ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
+ if (!ret->u.list.elements) {
+ errno = ENOMEM;
+ talloc_free(ret);
+ return NULL;
+ }
+
+ ret->u.list.elements[0] =
+ ldb_parse_filter(ret->u.list.elements, &p, depth, max_depth);
+ if (!ret->u.list.elements[0]) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ while (isspace((unsigned char)*p)) p++;
+
+ while (*p) {
+ struct ldb_parse_tree **e;
+ if (*p == ')') {
+ break;
+ }
+
+ next = ldb_parse_filter(
+ ret->u.list.elements, &p, depth, max_depth);
+ if (next == NULL) {
+ /* an invalid filter element */
+ talloc_free(ret);
+ return NULL;
+ }
+ e = talloc_realloc(ret, ret->u.list.elements,
+ struct ldb_parse_tree *,
+ ret->u.list.num_elements + 1);
+ if (!e) {
+ errno = ENOMEM;
+ talloc_free(ret);
+ return NULL;
+ }
+ ret->u.list.elements = e;
+ ret->u.list.elements[ret->u.list.num_elements] = next;
+ ret->u.list.num_elements++;
+ while (isspace((unsigned char)*p)) p++;
+ }
+
+ *s = p;
+
+ return ret;
+}
+
+
+/*
+ <not> ::= '!' <filter>
+*/
+static struct ldb_parse_tree *ldb_parse_not(
+ TALLOC_CTX *mem_ctx,
+ const char **s,
+ unsigned depth,
+ unsigned max_depth)
+{
+ struct ldb_parse_tree *ret;
+ const char *p = *s;
+
+ if (*p != '!') {
+ return NULL;
+ }
+ p++;
+
+ ret = talloc(mem_ctx, struct ldb_parse_tree);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret->operation = LDB_OP_NOT;
+ ret->u.isnot.child = ldb_parse_filter(ret, &p, depth, max_depth);
+ if (!ret->u.isnot.child) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ *s = p;
+
+ return ret;
+}
+
+/*
+ parse a filtercomp
+ <filtercomp> ::= <and> | <or> | <not> | <simple>
+*/
+static struct ldb_parse_tree *ldb_parse_filtercomp(
+ TALLOC_CTX *mem_ctx,
+ const char **s,
+ unsigned depth,
+ unsigned max_depth)
+{
+ struct ldb_parse_tree *ret;
+ const char *p = *s;
+
+ while (isspace((unsigned char)*p)) p++;
+
+ switch (*p) {
+ case '&':
+ ret = ldb_parse_filterlist(mem_ctx, &p, depth, max_depth);
+ break;
+
+ case '|':
+ ret = ldb_parse_filterlist(mem_ctx, &p, depth, max_depth);
+ break;
+
+ case '!':
+ ret = ldb_parse_not(mem_ctx, &p, depth, max_depth);
+ break;
+
+ case '(':
+ case ')':
+ return NULL;
+
+ default:
+ ret = ldb_parse_simple(mem_ctx, &p);
+
+ }
+
+ *s = p;
+ return ret;
+}
+
+/*
+ <filter> ::= '(' <filtercomp> ')'
+*/
+static struct ldb_parse_tree *ldb_parse_filter(
+ TALLOC_CTX *mem_ctx,
+ const char **s,
+ unsigned depth,
+ unsigned max_depth)
+{
+ struct ldb_parse_tree *ret;
+ const char *p = *s;
+
+ /*
+ * Check the depth of the parse tree, and reject the input if
+ * max_depth exceeded. This avoids stack overflow
+ * issues.
+ */
+ if (depth > max_depth) {
+ return NULL;
+ }
+ depth++;
+
+ if (*p != '(') {
+ return NULL;
+ }
+ p++;
+
+ ret = ldb_parse_filtercomp(mem_ctx, &p, depth, max_depth);
+
+ if (*p != ')') {
+ return NULL;
+ }
+ p++;
+
+ while (isspace((unsigned char)*p)) {
+ p++;
+ }
+
+ *s = p;
+
+ return ret;
+}
+
+
+/*
+ main parser entry point. Takes a search string and returns a parse tree
+
+ expression ::= <simple> | <filter>
+*/
+struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
+{
+ unsigned depth = 0;
+
+ while (s && isspace((unsigned char)*s)) s++;
+
+ if (s == NULL || *s == 0) {
+ s = "(|(objectClass=*)(distinguishedName=*))";
+ }
+
+ if (*s == '(') {
+ return ldb_parse_filter(
+ mem_ctx, &s, depth, LDB_MAX_PARSE_TREE_DEPTH);
+ }
+
+ return ldb_parse_simple(mem_ctx, &s);
+}
+
+
+/*
+ construct a ldap parse filter given a parse tree
+*/
+char *ldb_filter_from_tree(TALLOC_CTX *mem_ctx, const struct ldb_parse_tree *tree)
+{
+ char *s, *s2, *ret;
+ unsigned int i;
+
+ if (tree == NULL) {
+ return NULL;
+ }
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|');
+ if (ret == NULL) return NULL;
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ s2 = talloc_asprintf_append(ret, "%s", s);
+ talloc_free(s);
+ if (s2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = s2;
+ }
+ s = talloc_asprintf_append(ret, ")");
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ return s;
+ case LDB_OP_NOT:
+ s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child);
+ if (s == NULL) return NULL;
+
+ ret = talloc_asprintf(mem_ctx, "(!%s)", s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_EQUALITY:
+ s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s=%s)",
+ tree->u.equality.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_SUBSTRING:
+ ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr,
+ tree->u.substring.start_with_wildcard?"*":"");
+ if (ret == NULL) return NULL;
+ for (i = 0; tree->u.substring.chunks && tree->u.substring.chunks[i]; i++) {
+ s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
+ if (s2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ if (tree->u.substring.chunks[i+1] ||
+ tree->u.substring.end_with_wildcard) {
+ s = talloc_asprintf_append(ret, "%s*", s2);
+ } else {
+ s = talloc_asprintf_append(ret, "%s", s2);
+ }
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = s;
+ }
+ s = talloc_asprintf_append(ret, ")");
+ if (s == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = s;
+ return ret;
+ case LDB_OP_GREATER:
+ s = ldb_binary_encode(mem_ctx, tree->u.comparison.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s>=%s)",
+ tree->u.comparison.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_LESS:
+ s = ldb_binary_encode(mem_ctx, tree->u.comparison.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s<=%s)",
+ tree->u.comparison.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_PRESENT:
+ ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr);
+ return ret;
+ case LDB_OP_APPROX:
+ s = ldb_binary_encode(mem_ctx, tree->u.comparison.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s~=%s)",
+ tree->u.comparison.attr, s);
+ talloc_free(s);
+ return ret;
+ case LDB_OP_EXTENDED:
+ s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
+ if (s == NULL) return NULL;
+ ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)",
+ tree->u.extended.attr?tree->u.extended.attr:"",
+ tree->u.extended.dnAttributes?":dn":"",
+ tree->u.extended.rule_id?":":"",
+ tree->u.extended.rule_id?tree->u.extended.rule_id:"",
+ s);
+ talloc_free(s);
+ return ret;
+ }
+
+ return NULL;
+}
+
+
+/*
+ walk a parse tree, calling the provided callback on each node
+*/
+int ldb_parse_tree_walk(struct ldb_parse_tree *tree,
+ int (*callback)(struct ldb_parse_tree *tree, void *),
+ void *private_context)
+{
+ unsigned int i;
+ int ret;
+
+ ret = callback(tree, private_context);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ ret = ldb_parse_tree_walk(tree->u.list.elements[i], callback, private_context);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ break;
+ case LDB_OP_NOT:
+ ret = ldb_parse_tree_walk(tree->u.isnot.child, callback, private_context);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ break;
+ case LDB_OP_EQUALITY:
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_APPROX:
+ case LDB_OP_SUBSTRING:
+ case LDB_OP_PRESENT:
+ case LDB_OP_EXTENDED:
+ break;
+ }
+ return LDB_SUCCESS;
+}
+
+struct parse_tree_attr_replace_ctx {
+ const char *attr;
+ const char *replace;
+};
+
+/*
+ callback for ldb_parse_tree_attr_replace()
+ */
+static int parse_tree_attr_replace(struct ldb_parse_tree *tree, void *private_context)
+{
+ struct parse_tree_attr_replace_ctx *ctx = private_context;
+ switch (tree->operation) {
+ case LDB_OP_EQUALITY:
+ if (ldb_attr_cmp(tree->u.equality.attr, ctx->attr) == 0) {
+ tree->u.equality.attr = ctx->replace;
+ }
+ break;
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_APPROX:
+ if (ldb_attr_cmp(tree->u.comparison.attr, ctx->attr) == 0) {
+ tree->u.comparison.attr = ctx->replace;
+ }
+ break;
+ case LDB_OP_SUBSTRING:
+ if (ldb_attr_cmp(tree->u.substring.attr, ctx->attr) == 0) {
+ tree->u.substring.attr = ctx->replace;
+ }
+ break;
+ case LDB_OP_PRESENT:
+ if (ldb_attr_cmp(tree->u.present.attr, ctx->attr) == 0) {
+ tree->u.present.attr = ctx->replace;
+ }
+ break;
+ case LDB_OP_EXTENDED:
+ if (tree->u.extended.attr &&
+ ldb_attr_cmp(tree->u.extended.attr, ctx->attr) == 0) {
+ tree->u.extended.attr = ctx->replace;
+ }
+ break;
+ default:
+ break;
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ replace any occurrences of an attribute name in the parse tree with a
+ new name
+*/
+void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
+ const char *attr,
+ const char *replace)
+{
+ struct parse_tree_attr_replace_ctx ctx;
+
+ ctx.attr = attr;
+ ctx.replace = replace;
+
+ ldb_parse_tree_walk(tree, parse_tree_attr_replace, &ctx);
+}
+
+/*
+ shallow copy a tree - copying only the elements array so that the caller
+ can safely add new elements without changing the message
+*/
+struct ldb_parse_tree *ldb_parse_tree_copy_shallow(TALLOC_CTX *mem_ctx,
+ const struct ldb_parse_tree *ot)
+{
+ unsigned int i;
+ struct ldb_parse_tree *nt;
+
+ nt = talloc(mem_ctx, struct ldb_parse_tree);
+ if (!nt) {
+ return NULL;
+ }
+
+ *nt = *ot;
+
+ switch (ot->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ nt->u.list.elements = talloc_array(nt, struct ldb_parse_tree *,
+ ot->u.list.num_elements);
+ if (!nt->u.list.elements) {
+ talloc_free(nt);
+ return NULL;
+ }
+
+ for (i=0;i<ot->u.list.num_elements;i++) {
+ nt->u.list.elements[i] =
+ ldb_parse_tree_copy_shallow(nt->u.list.elements,
+ ot->u.list.elements[i]);
+ if (!nt->u.list.elements[i]) {
+ talloc_free(nt);
+ return NULL;
+ }
+ }
+ break;
+ case LDB_OP_NOT:
+ nt->u.isnot.child = ldb_parse_tree_copy_shallow(nt,
+ ot->u.isnot.child);
+ if (!nt->u.isnot.child) {
+ talloc_free(nt);
+ return NULL;
+ }
+ break;
+ case LDB_OP_EQUALITY:
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_APPROX:
+ case LDB_OP_SUBSTRING:
+ case LDB_OP_PRESENT:
+ case LDB_OP_EXTENDED:
+ break;
+ }
+
+ return nt;
+}
+
+/* Get the attribute (if any) associated with the top node of a parse tree. */
+const char *ldb_parse_tree_get_attr(const struct ldb_parse_tree *tree)
+{
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ case LDB_OP_NOT:
+ return NULL;
+ case LDB_OP_EQUALITY:
+ return tree->u.equality.attr;
+ case LDB_OP_SUBSTRING:
+ return tree->u.substring.attr;
+ case LDB_OP_GREATER:
+ case LDB_OP_LESS:
+ case LDB_OP_APPROX:
+ return tree->u.comparison.attr;
+ case LDB_OP_PRESENT:
+ return tree->u.present.attr;
+ case LDB_OP_EXTENDED:
+ return tree->u.extended.attr;
+ }
+
+ return NULL;
+}
diff --git a/lib/ldb/common/ldb_utf8.c b/lib/ldb/common/ldb_utf8.c
new file mode 100644
index 0000000..f45b72d
--- /dev/null
+++ b/lib/ldb/common/ldb_utf8.c
@@ -0,0 +1,140 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb utf8 handling
+ *
+ * Description: case folding and case comparison for UTF8 strings
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_private.h"
+#include "system/locale.h"
+
+
+/*
+ this allow the user to pass in a caseless comparison
+ function to handle utf8 caseless comparisons
+ */
+void ldb_set_utf8_fns(struct ldb_context *ldb,
+ void *context,
+ char *(*casefold)(void *, void *, const char *, size_t))
+{
+ if (context)
+ ldb->utf8_fns.context = context;
+ if (casefold)
+ ldb->utf8_fns.casefold = casefold;
+}
+
+/*
+ a simple case folding function
+ NOTE: does not handle UTF8
+*/
+char *ldb_casefold_default(void *context, TALLOC_CTX *mem_ctx, const char *s, size_t n)
+{
+ size_t i;
+ char *ret = talloc_strndup(mem_ctx, s, n);
+ if (!s) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ for (i=0;ret[i];i++) {
+ ret[i] = ldb_ascii_toupper((unsigned char)ret[i]);
+ }
+ return ret;
+}
+
+void ldb_set_utf8_default(struct ldb_context *ldb)
+{
+ ldb_set_utf8_fns(ldb, NULL, ldb_casefold_default);
+}
+
+char *ldb_casefold(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *s, size_t n)
+{
+ return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s, n);
+}
+
+/*
+ check the attribute name is valid according to rfc2251
+ returns 1 if the name is ok
+ */
+
+int ldb_valid_attr_name(const char *s)
+{
+ size_t i;
+
+ if (!s || !s[0])
+ return 0;
+
+ /* handle special ldb_tdb wildcard */
+ if (strcmp(s, "*") == 0) return 1;
+
+ for (i = 0; s[i]; i++) {
+ if (! isascii(s[i])) {
+ return 0;
+ }
+ if (i == 0) { /* first char must be an alpha (or our special '@' identifier) */
+ if (! (isalpha(s[i]) || (s[i] == '@'))) {
+ return 0;
+ }
+ } else {
+ if (! (isalnum(s[i]) || (s[i] == '-'))) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+char *ldb_attr_casefold(TALLOC_CTX *mem_ctx, const char *s)
+{
+ size_t i;
+ char *ret = talloc_strdup(mem_ctx, s);
+ if (!ret) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ for (i = 0; ret[i]; i++) {
+ ret[i] = ldb_ascii_toupper((unsigned char)ret[i]);
+ }
+ return ret;
+}
+
+/*
+ we accept either 'dn' or 'distinguishedName' for a distinguishedName
+*/
+int ldb_attr_dn(const char *attr)
+{
+ if (ldb_attr_cmp(attr, "dn") == 0 ||
+ ldb_attr_cmp(attr, "distinguishedName") == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+_PRIVATE_ char ldb_ascii_toupper(char c) {
+ return ('a' <= c && c <= 'z') ? c ^ 0x20 : toupper(c);
+}
diff --git a/lib/ldb/common/qsort.c b/lib/ldb/common/qsort.c
new file mode 100644
index 0000000..012aaf3
--- /dev/null
+++ b/lib/ldb/common/qsort.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */
+
+/* If you consider tuning this algorithm, you should consult first:
+ Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
+ Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
+
+/* Modified to be used in samba4 by
+ * Simo Sorce <idra@samba.org> 2005
+ */
+
+#include "ldb_private.h"
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(a, b, size) \
+ do \
+ { \
+ register size_t __size = (size); \
+ register char *__a = (a), *__b = (b); \
+ do \
+ { \
+ char __tmp = *__a; \
+ *__a++ = *__b; \
+ *__b++ = __tmp; \
+ } while (--__size > 0); \
+ } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 4
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+ {
+ char *lo;
+ char *hi;
+ } stack_node;
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+/* The stack needs log (total_elements) entries (we could even subtract
+ log(MAX_THRESH)). Since total_elements has type size_t, we get as
+ upper bound for log (total_elements):
+ bits per byte (CHAR_BIT) * sizeof(size_t). */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
+#define PUSH(low, high) ((void) ((stack[i].lo = (low)), (stack[i].hi = (high)), i++))
+#define POP(low, high) ((void) (i--, (low = stack[i].lo), (high = stack[i].hi)))
+
+
+/* Order size using quicksort. This implementation incorporates
+ four optimizations discussed in Sedgewick:
+
+ 1. Non-recursive, using an explicit stack of pointer that store the
+ next array partition to sort. To save time, this maximum amount
+ of space required to store an array of SIZE_MAX is allocated on the
+ stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
+ only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
+ Pretty cheap, actually.
+
+ 2. Chose the pivot element using a median-of-three decision tree.
+ This reduces the probability of selecting a bad pivot value and
+ eliminates certain extraneous comparisons.
+
+ 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+ insertion sort to order the MAX_THRESH items within each partition.
+ This is a big win, since insertion sort is faster for small, mostly
+ sorted array segments.
+
+ 4. The larger of the two sub-partitions is always pushed onto the
+ stack first, with the algorithm then concentrating on the
+ smaller partition. This *guarantees* no more than log (total_elems)
+ stack size is needed (actually O(1) in this case)! */
+
+void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
+ void *opaque, ldb_qsort_cmp_fn_t cmp)
+{
+ register char *base_ptr = (char *) pbase;
+
+ const size_t max_thresh = MAX_THRESH * size;
+
+ if (total_elems == 0)
+ /* Avoid lossage with unsigned arithmetic below. */
+ return;
+
+ if (total_elems > MAX_THRESH)
+ {
+ char *lo = base_ptr;
+ char *hi = &lo[size * (total_elems - 1)];
+ stack_node stack[STACK_SIZE];
+ size_t i = 0;
+
+ PUSH (NULL, NULL);
+
+ do
+ {
+ char *left_ptr;
+ char *right_ptr;
+
+ /* Select median value from among LO, MID, and HI. Rearrange
+ LO and HI so the three values are sorted. This lowers the
+ probability of picking a pathological pivot value and
+ skips a comparison for both the LEFT_PTR and RIGHT_PTR in
+ the while loops. */
+
+ char *mid = lo + size * ((hi - lo) / size >> 1);
+
+ if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
+ SWAP (mid, lo, size);
+ if ((*cmp) ((void *) hi, (void *) mid, opaque) < 0)
+ SWAP (mid, hi, size);
+ else
+ goto jump_over;
+ if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
+ SWAP (mid, lo, size);
+ jump_over:;
+
+ left_ptr = lo + size;
+ right_ptr = hi - size;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do
+ {
+ while ((*cmp) ((void *) left_ptr, (void *) mid, opaque) < 0)
+ left_ptr += size;
+
+ while ((*cmp) ((void *) mid, (void *) right_ptr, opaque) < 0)
+ right_ptr -= size;
+
+ if (left_ptr < right_ptr)
+ {
+ SWAP (left_ptr, right_ptr, size);
+ if (mid == left_ptr)
+ mid = right_ptr;
+ else if (mid == right_ptr)
+ mid = left_ptr;
+ left_ptr += size;
+ right_ptr -= size;
+ }
+ else if (left_ptr == right_ptr)
+ {
+ left_ptr += size;
+ right_ptr -= size;
+ break;
+ }
+ }
+ while (left_ptr <= right_ptr);
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((size_t) (right_ptr - lo) <= max_thresh)
+ {
+ if ((size_t) (hi - left_ptr) <= max_thresh)
+ /* Ignore both small partitions. */
+ POP (lo, hi);
+ else
+ /* Ignore small left partition. */
+ lo = left_ptr;
+ }
+ else if ((size_t) (hi - left_ptr) <= max_thresh)
+ /* Ignore small right partition. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr))
+ {
+ /* Push larger left partition indices. */
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else
+ {
+ /* Push larger right partition indices. */
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ while (i > 0 && i < STACK_SIZE);
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
+ {
+ char *const end_ptr = &base_ptr[size * (total_elems - 1)];
+ char *tmp_ptr = base_ptr;
+ char *thresh = min(end_ptr, base_ptr + max_thresh);
+ register char *run_ptr;
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+ if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != base_ptr)
+ SWAP (tmp_ptr, base_ptr, size);
+
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
+
+ run_ptr = base_ptr + size;
+ while ((run_ptr += size) <= end_ptr)
+ {
+ tmp_ptr = run_ptr - size;
+ while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+ tmp_ptr -= size;
+
+ tmp_ptr += size;
+ if (tmp_ptr != run_ptr)
+ {
+ char *trav;
+
+ trav = run_ptr + size;
+ while (--trav >= run_ptr)
+ {
+ char c = *trav;
+ char *hi, *lo;
+
+ for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+ *hi = *lo;
+ *hi = c;
+ }
+ }
+ }
+ }
+}
diff --git a/lib/ldb/configure b/lib/ldb/configure
new file mode 100755
index 0000000..2ed3240
--- /dev/null
+++ b/lib/ldb/configure
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PREVPATH=$(dirname $0)
+
+if [ -f $PREVPATH/../../buildtools/bin/waf ]; then
+ WAF=../../buildtools/bin/waf
+elif [ -f $PREVPATH/buildtools/bin/waf ]; then
+ WAF=./buildtools/bin/waf
+else
+ echo "ldb: Unable to find waf"
+ exit 1
+fi
+
+# using JOBS=1 gives maximum compatibility with
+# systems like AIX which have broken threading in python
+JOBS=1
+export JOBS
+
+# Make sure we don't have any library preloaded.
+unset LD_PRELOAD
+
+# Make sure we get stable hashes
+PYTHONHASHSEED=1
+export PYTHONHASHSEED
+
+cd . || exit 1
+$PYTHON $WAF configure "$@" || exit 1
+cd $PREVPATH
diff --git a/lib/ldb/docs/builddocs.sh b/lib/ldb/docs/builddocs.sh
new file mode 100755
index 0000000..b7e11d3
--- /dev/null
+++ b/lib/ldb/docs/builddocs.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# build ldb docs
+# tridge@samba.org August 2006
+
+XSLTPROC="$1"
+SRCDIR="$2"
+
+if [ -z "$XSLTPROC" ] || [ ! -x "$XSLTPROC" ]; then
+ echo "xsltproc not installed"
+ exit 0
+fi
+
+MANXSL="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"
+HTMLXSL="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"
+
+mkdir -p man
+
+for f in $SRCDIR/man/*.xml; do
+ base=$(basename $f .xml)
+ out=man/"$(basename $base)"
+ if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then
+ echo Processing manpage $f
+ $XSLTPROC --nonet -o "$out" "$MANXSL" $f
+ ret=$?
+ if [ "$ret" = "4" ]; then
+ echo "ignoring stylesheet error 4 for $MANXSL"
+ exit 0
+ fi
+ if [ "$ret" != "0" ]; then
+ echo "xsltproc failed with error $ret"
+ exit $ret
+ fi
+ fi
+done
+
+for f in $SRCDIR/man/*.xml; do
+ base=$(basename $f .xml)
+ out=man/"$(basename $base)".html
+ if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then
+ echo Processing html $f
+ $XSLTPROC --nonet -o "$out" "$HTMLXSL" $f
+ ret=$?
+ if [ "$ret" = "4" ]; then
+ echo "ignoring stylesheet error 4 for $HTMLXSL"
+ exit 0
+ fi
+ if [ "$ret" != "0" ]; then
+ echo "xsltproc failed with error $ret"
+ exit $ret
+ fi
+ fi
+done
diff --git a/lib/ldb/docs/design.txt b/lib/ldb/docs/design.txt
new file mode 100644
index 0000000..0bb278b
--- /dev/null
+++ b/lib/ldb/docs/design.txt
@@ -0,0 +1,41 @@
+The list of indexed fields
+--------------------------
+
+dn=@INDEXLIST
+ list of field names that are indexed
+
+ contains fields of type @IDXATTR which contain attriute names
+ of indexed fields
+
+
+Data records
+------------
+
+for each user record in the db there is:
+ main record
+ key: DN=dn
+ data: packed attribute/value list
+
+ a index record for each indexed field in the record
+
+
+Index Records
+-------------
+
+The index records contain the list of dn's that contain records
+matching the index key
+
+All index records are of the form:
+ dn=@INDEX:field:value
+
+and contain fields of type @IDX which are the dns of the records
+that have that value for some attribute
+
+
+Search Expressions
+------------------
+
+Very similar to LDAP search expressions, but does not allow ~=, <= or >=
+
+ attrib0 := (field=value)
+ attrib := attrib0 | (attrib&&attrib) | (attrib||attrib) | !attrib
diff --git a/lib/ldb/docs/installdocs.sh b/lib/ldb/docs/installdocs.sh
new file mode 100755
index 0000000..90daf6f
--- /dev/null
+++ b/lib/ldb/docs/installdocs.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# install ldb docs
+# tridge@samba.org August 2006
+
+MANDIR="$1"
+
+MAN1="$(/bin/ls man/*.1)"
+MAN3="$(/bin/ls man/*.3)"
+
+if [ -z "$MAN1" ] && [ -z "$MAN3" ]; then
+ echo "No manpages have been built"
+ exit 0
+fi
+
+mkdir -p "$MANDIR/man1" "$MANDIR/man3"
+cp $MAN1 "$MANDIR/man1/" || exit 1
+cp $MAN3 "$MANDIR/man3/" || exit 1
diff --git a/lib/ldb/examples.dox b/lib/ldb/examples.dox
new file mode 100644
index 0000000..ef4b4f0
--- /dev/null
+++ b/lib/ldb/examples.dox
@@ -0,0 +1,16 @@
+/** \example ldbreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the records in a LDB database to standard output.
+
+*/
+
+
+/** \example ldifreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the entries in an LDIF file to standard output.
+
+*/
diff --git a/lib/ldb/examples/ldbreader.c b/lib/ldb/examples/ldbreader.c
new file mode 100644
index 0000000..3496baf
--- /dev/null
+++ b/lib/ldb/examples/ldbreader.c
@@ -0,0 +1,122 @@
+/*
+ example code for the ldb database library
+
+ Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/** \example ldbreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the records in a LDB database to standard output.
+
+*/
+
+#include "ldb.h"
+
+/*
+ ldb_ldif_write takes a function pointer to a custom output
+ function. This version is about as simple as the output function can
+ be. In a more complex example, you'd likely be doing something with
+ the private data function (e.g. holding a file handle).
+*/
+static int vprintf_fn(void *private_data, const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* We just write to standard output */
+ retval = vprintf(fmt, ap);
+ va_end(ap);
+ /* Note that the function should return the number of
+ bytes written, or a negative error code */
+ return retval;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ const char *expression = "(dn=*)";
+ struct ldb_result *resultMsg;
+ int i;
+
+ /*
+ This is the always the first thing you want to do in an LDB
+ application - initialise up the context structure.
+
+ Note that you can use the context structure as a parent
+ for talloc allocations as well
+ */
+ ldb = ldb_init(NULL, NULL);
+
+ /*
+ We now open the database. In this example we just hard code the connection path.
+
+ Also note that the database is being opened read-only. This means that the
+ call will fail unless the database already exists.
+ */
+ if (LDB_SUCCESS != ldb_connect(ldb, "tdb://tdbtest.ldb", LDB_FLG_RDONLY, NULL) ){
+ printf("Problem on connection\n");
+ exit(-1);
+ }
+
+ /*
+ At this stage we have an open database, and can start using it. It is opened
+ read-only, so a query is possible.
+
+ We construct a search that just returns all the (sensible) contents. You can do
+ quite fine grained results with the LDAP search syntax, however it is a bit
+ confusing to start with. See RFC2254.
+ */
+ if (LDB_SUCCESS != ldb_search(ldb, ldb, &resultMsg,
+ NULL, LDB_SCOPE_DEFAULT, NULL,
+ "%s", expression)) {
+ printf("Problem in search\n");
+ exit(-1);
+ }
+
+ printf("%i records returned\n", resultMsg->count);
+
+ /*
+ We can now iterate through the results, writing them out
+ (to standard output) with our custom output routine as defined
+ at the top of this file
+ */
+ for (i = 0; i < resultMsg->count; ++i) {
+ struct ldb_ldif ldifMsg;
+
+ printf("Message: %i\n", i+1);
+
+ ldifMsg.changetype = LDB_CHANGETYPE_NONE;
+ ldifMsg.msg = resultMsg->msgs[i];
+ ldb_ldif_write(ldb, vprintf_fn, NULL, &ldifMsg);
+ }
+
+ /*
+ There are two objects to clean up - the result from the
+ ldb_search() query, and the original ldb context.
+ */
+ talloc_free(resultMsg);
+
+ talloc_free(ldb);
+
+ return 0;
+}
diff --git a/lib/ldb/examples/ldifreader.c b/lib/ldb/examples/ldifreader.c
new file mode 100644
index 0000000..dcd9daf
--- /dev/null
+++ b/lib/ldb/examples/ldifreader.c
@@ -0,0 +1,125 @@
+/*
+ example code for the ldb database library
+
+ Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/** \example ldifreader.c
+
+The code below shows a simple LDB application.
+
+It lists / dumps the entries in an LDIF file to standard output.
+
+*/
+
+#include "ldb.h"
+
+/*
+ ldb_ldif_write takes a function pointer to a custom output
+ function. This version is about as simple as the output function can
+ be. In a more complex example, you'd likely be doing something with
+ the private data function (e.g. holding a file handle).
+*/
+static int vprintf_fn(void *private_data, const char *fmt, ...)
+{
+ int retval;
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* We just write to standard output */
+ retval = vprintf(fmt, ap);
+ va_end(ap);
+ /* Note that the function should return the number of
+ bytes written, or a negative error code */
+ return retval;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ FILE *fileStream;
+ struct ldb_ldif *ldifMsg;
+
+ if (argc != 2) {
+ printf("Usage %s filename.ldif\n", argv[0]);
+ exit(1);
+ }
+
+ /*
+ This is the always the first thing you want to do in an LDB
+ application - initialise up the context structure.
+
+ Note that you can use the context structure as a parent
+ for talloc allocations as well
+ */
+ ldb = ldb_init(NULL, NULL);
+
+ fileStream = fopen(argv[1], "r");
+ if (0 == fileStream) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ /*
+ We now work through the filestream to get each entry.
+ */
+ while ( (ldifMsg = ldb_ldif_read_file(ldb, fileStream)) ) {
+ /*
+ Each message has a particular change type. For Add,
+ Modify and Delete, this will also appear in the
+ output listing (as changetype: add, changetype:
+ modify or changetype:delete, respectively).
+ */
+ switch (ldifMsg->changetype) {
+ case LDB_CHANGETYPE_NONE:
+ printf("ChangeType: None\n");
+ break;
+ case LDB_CHANGETYPE_ADD:
+ printf("ChangeType: Add\n");
+ break;
+ case LDB_CHANGETYPE_MODIFY:
+ printf("ChangeType: Modify\n");
+ break;
+ case LDB_CHANGETYPE_DELETE:
+ printf("ChangeType: Delete\n");
+ break;
+ default:
+ printf("ChangeType: Unknown\n");
+ }
+
+ /*
+ We can now write out the results, using our custom
+ output routine as defined at the top of this file.
+ */
+ ldb_ldif_write(ldb, vprintf_fn, NULL, ldifMsg);
+
+ /*
+ Clean up the message
+ */
+ ldb_ldif_read_free(ldb, ldifMsg);
+ }
+
+ /*
+ Clean up the context
+ */
+ talloc_free(ldb);
+
+ return 0;
+}
diff --git a/lib/ldb/include/dlinklist.h b/lib/ldb/include/dlinklist.h
new file mode 100644
index 0000000..49a135a
--- /dev/null
+++ b/lib/ldb/include/dlinklist.h
@@ -0,0 +1,198 @@
+/*
+ Unix SMB/CIFS implementation.
+ some simple double linked list macros
+
+ Copyright (C) Andrew Tridgell 1998-2010
+
+ ** NOTE! The following LGPL license applies to this file (*dlinklist.h).
+ ** This does NOT imply that all of Samba is released under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* To use these macros you must have a structure containing a next and
+ prev pointer */
+
+#ifndef _DLINKLIST_H
+#define _DLINKLIST_H
+
+/*
+ February 2010 - changed list format to have a prev pointer from the
+ list head. This makes DLIST_ADD_END() O(1) even though we only have
+ one list pointer.
+
+ The scheme is as follows:
+
+ 1) with no entries in the list:
+ list_head == NULL
+
+ 2) with 1 entry in the list:
+ list_head->next == NULL
+ list_head->prev == list_head
+
+ 3) with 2 entries in the list:
+ list_head->next == element2
+ list_head->prev == element2
+ element2->prev == list_head
+ element2->next == NULL
+
+ 4) with N entries in the list:
+ list_head->next == element2
+ list_head->prev == elementN
+ elementN->prev == element{N-1}
+ elementN->next == NULL
+
+ This allows us to find the tail of the list by using
+ list_head->prev, which means we can add to the end of the list in
+ O(1) time
+ */
+
+
+/*
+ add an element at the front of a list
+*/
+#define DLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (p)->prev = (list) = (p); \
+ (p)->next = NULL; \
+ } else { \
+ (p)->prev = (list)->prev; \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (list) = (p); \
+ } \
+} while (0)
+
+/*
+ remove an element from a list
+ Note that the element doesn't have to be in the list. If it
+ isn't then this is a no-op
+*/
+#define DLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ (list) = (p)->next; \
+ } else if ((p)->prev && (list) && (p) == (list)->prev) { \
+ (p)->prev->next = NULL; \
+ (list)->prev = (p)->prev; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) != (list)) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+/*
+ find the head of the list given any element in it.
+ Note that this costs O(N), so you should avoid this macro
+ if at all possible!
+*/
+#define DLIST_HEAD(p, result_head) \
+do { \
+ (result_head) = (p); \
+ while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
+} while(0)
+
+/* return the last element in the list */
+#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
+
+/* return the previous element in the list. */
+#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+ this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+ if (!(list) || !(el)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ (p)->prev = (el); \
+ (p)->next = (el)->next; \
+ (el)->next = (p); \
+ if ((p)->next) (p)->next->prev = (p); \
+ if ((list)->prev == (el)) (list)->prev = (p); \
+ }\
+} while (0)
+
+
+/*
+ add to the end of a list.
+*/
+#define DLIST_ADD_END(list, p) \
+do { \
+ if (!(list)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ DLIST_ADD_AFTER(list, p, (list)->prev); \
+ } \
+} while (0)
+
+/* promote an element to the front of a list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD(list, p); \
+} while (0)
+
+/*
+ demote an element to the end of a list.
+*/
+#define DLIST_DEMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD_END(list, p); \
+} while (0)
+
+/*
+ * like DLIST_DEMOTE(), but optimized
+ * for short lists with 0, 1 or 2 elements
+ */
+#define DLIST_DEMOTE_SHORT(list, p) \
+do { \
+ if ((list) == NULL) { \
+ /* no reason to demote, just add */ \
+ DLIST_ADD(list, p); \
+ } else if ((list)->prev == (p)) { \
+ /* optimize if p is last */ \
+ } else if ((list) == (p)) { \
+ /* optimize if p is first */ \
+ (list)->prev->next = (p); \
+ (list) = (p)->next; \
+ (p)->next = NULL; \
+ } else { \
+ DLIST_DEMOTE(list, p); \
+ } \
+} while (0)
+
+/*
+ concatenate two lists - putting all elements of the 2nd list at the
+ end of the first list.
+*/
+#define DLIST_CONCATENATE(list1, list2) \
+do { \
+ if (!(list1)) { \
+ (list1) = (list2); \
+ } else { \
+ (list1)->prev->next = (list2); \
+ if (list2) { \
+ void *_tmplist = (void *)(list1)->prev; \
+ (list1)->prev = (list2)->prev; \
+ (list2)->prev = _tmplist; \
+ } \
+ } \
+} while (0)
+
+#endif /* _DLINKLIST_H */
diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
new file mode 100644
index 0000000..5d83a27
--- /dev/null
+++ b/lib/ldb/include/ldb.h
@@ -0,0 +1,2399 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2005-2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb header
+ *
+ * Description: defines for base ldb API
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ */
+
+/**
+ \file ldb.h Samba's ldb database
+
+ This header file provides the main API for ldb.
+*/
+
+#ifndef _LDB_H_
+
+/*! \cond DOXYGEN_IGNORE */
+#define _LDB_H_ 1
+/*! \endcond */
+
+#include <stdbool.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb_version.h>
+#include <ldb_errors.h>
+
+/*
+ major restrictions as compared to normal LDAP:
+
+ - each record must have a unique key field
+ - the key must be representable as a NULL terminated C string and may not
+ contain a comma or braces
+
+ major restrictions as compared to tdb:
+
+ - no explicit locking calls, but we have transactions when using ldb_tdb
+
+*/
+
+#ifndef ldb_val
+/**
+ Result value
+
+ An individual lump of data in a result comes in this format. The
+ pointer will usually be to a UTF-8 string if the application is
+ sensible, but it can be to anything you like, including binary data
+ blobs of arbitrary size.
+
+ \note the data is null (0x00) terminated, but the length does not
+ include the terminator.
+*/
+struct ldb_val {
+ uint8_t *data; /*!< result data */
+ size_t length; /*!< length of data */
+};
+#endif
+
+/*! \cond DOXYGEN_IGNORE */
+#ifndef PRINTF_ATTRIBUTE
+#define PRINTF_ATTRIBUTE(a,b)
+#endif
+
+#ifndef _DEPRECATED_
+#if __has_attribute(deprecated) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+/*! \endcond */
+
+/* opaque ldb_dn structures, see ldb_dn.c for internals */
+struct ldb_dn_component;
+struct ldb_dn;
+
+/**
+ There are a number of flags that are used with ldap_modify() in
+ ldb_message_element.flags fields. The LDB_FLAG_MOD_ADD,
+ LDB_FLAG_MOD_DELETE and LDB_FLAG_MOD_REPLACE are better thought of as
+ an enumeration, not flags, and are used in ldap_modify() calls to
+ specify whether attributes are being added, deleted or modified
+ respectively.
+*/
+#define LDB_FLAG_MOD_MASK 0x3
+
+/**
+ use this to extract the mod type (enum) from the operation
+ */
+#define LDB_FLAG_MOD_TYPE(flags) ((flags) & LDB_FLAG_MOD_MASK)
+
+/**
+ Value used in ldap_modify() to indicate that attributes are
+ being added.
+
+ \sa LDB_FLAG_MOD_MASK
+*/
+#define LDB_FLAG_MOD_ADD 1
+
+/**
+ Value used in ldap_modify() to indicate that attributes are
+ being replaced.
+
+ \sa LDB_FLAG_MOD_MASK
+*/
+#define LDB_FLAG_MOD_REPLACE 2
+
+/**
+ Value used in ldap_modify() to indicate that attributes are
+ being deleted.
+
+ \sa LDB_FLAG_MOD_MASK
+*/
+#define LDB_FLAG_MOD_DELETE 3
+
+/**
+ Flag value used in ldb_ldif_write_trace() to enforce binary encoded
+ attribute values per attribute.
+
+ This is a genuine flag, being outside LDB_FLAG_MOD_MASK and also
+ outside LDB_FLAG_INTERNAL_MASK
+*/
+#define LDB_FLAG_FORCE_NO_BASE64_LDIF 4
+
+/**
+ flag bits on an element usable only by the internal implementation
+*/
+#define LDB_FLAG_INTERNAL_MASK 0xFFFFFFF0
+
+/**
+ OID for logic AND comparison.
+
+ This is the well known object ID for a logical AND comparator.
+*/
+#define LDB_OID_COMPARATOR_AND "1.2.840.113556.1.4.803"
+
+/**
+ OID for logic OR comparison.
+
+ This is the well known object ID for a logical OR comparator.
+*/
+#define LDB_OID_COMPARATOR_OR "1.2.840.113556.1.4.804"
+
+/**
+ results are given back as arrays of ldb_message_element
+*/
+struct ldb_message_element {
+ unsigned int flags;
+ const char *name;
+ unsigned int num_values;
+ struct ldb_val *values;
+};
+
+
+/**
+ a ldb_message represents all or part of a record. It can contain an arbitrary
+ number of elements.
+*/
+struct ldb_message {
+ struct ldb_dn *dn;
+ unsigned int num_elements;
+ struct ldb_message_element *elements;
+};
+
+enum ldb_changetype {
+ LDB_CHANGETYPE_NONE=0,
+ LDB_CHANGETYPE_ADD,
+ LDB_CHANGETYPE_DELETE,
+ LDB_CHANGETYPE_MODIFY,
+ LDB_CHANGETYPE_MODRDN
+};
+
+/**
+ LDIF record
+
+ This structure contains a LDIF record, as returned from ldif_read()
+ and equivalent functions.
+*/
+struct ldb_ldif {
+ enum ldb_changetype changetype; /*!< The type of change */
+ struct ldb_message *msg; /*!< The changes */
+};
+
+enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
+ LDB_SCOPE_BASE=0,
+ LDB_SCOPE_ONELEVEL=1,
+ LDB_SCOPE_SUBTREE=2};
+
+struct ldb_context;
+struct tevent_context;
+
+/* debugging uses one of the following levels */
+enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR,
+ LDB_DEBUG_WARNING, LDB_DEBUG_TRACE};
+
+/* alias for something that's not a fatal error but we really want to log */
+#define LDB_DEBUG_ALWAYS_LOG LDB_DEBUG_FATAL
+
+/**
+ the user can optionally supply a debug function. The function
+ is based on the vfprintf() style of interface, but with the addition
+ of a severity level
+*/
+struct ldb_debug_ops {
+ void (*debug)(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+ void *context;
+};
+
+/**
+ The user can optionally supply a custom utf8 functions,
+ to handle comparisons and casefolding.
+*/
+struct ldb_utf8_fns {
+ void *context;
+ char *(*casefold)(void *context, TALLOC_CTX *mem_ctx, const char *s, size_t n);
+};
+
+/**
+ Flag value for database connection mode.
+
+ If LDB_FLG_RDONLY is used in ldb_connect, then the database will be
+ opened read-only, if possible.
+*/
+#define LDB_FLG_RDONLY 1
+
+/**
+ Flag value for database connection mode.
+
+ If LDB_FLG_NOSYNC is used in ldb_connect, then the database will be
+ opened without synchronous operations, if possible.
+*/
+#define LDB_FLG_NOSYNC 2
+
+/**
+ Flag value to specify autoreconnect mode.
+
+ If LDB_FLG_RECONNECT is used in ldb_connect, then the backend will
+ be opened in a way that makes it try to auto reconnect if the
+ connection is dropped (actually make sense only with ldap).
+*/
+#define LDB_FLG_RECONNECT 4
+
+/**
+ Flag to tell backends not to use mmap
+*/
+#define LDB_FLG_NOMMAP 8
+
+/**
+ Flag to tell ldif handlers not to force encoding of binary
+ structures in base64
+*/
+#define LDB_FLG_SHOW_BINARY 16
+
+/**
+ Flags to enable ldb tracing
+*/
+#define LDB_FLG_ENABLE_TRACING 32
+
+/**
+ Flags to tell LDB not to create a new database file:
+
+ Without this flag ldb_tdb (for example) will create a blank file
+ during an invocation of ldb_connect(), even when the caller only
+ wanted read operations, for example in ldbsearch.
+*/
+#define LDB_FLG_DONT_CREATE_DB 64
+
+/*
+ structures for ldb_parse_tree handling code
+*/
+enum ldb_parse_op { LDB_OP_AND=1, LDB_OP_OR=2, LDB_OP_NOT=3,
+ LDB_OP_EQUALITY=4, LDB_OP_SUBSTRING=5,
+ LDB_OP_GREATER=6, LDB_OP_LESS=7, LDB_OP_PRESENT=8,
+ LDB_OP_APPROX=9, LDB_OP_EXTENDED=10 };
+
+struct ldb_parse_tree {
+ enum ldb_parse_op operation;
+ union {
+ struct {
+ struct ldb_parse_tree *child;
+ } isnot;
+ struct {
+ const char *attr;
+ struct ldb_val value;
+ } equality;
+ struct {
+ const char *attr;
+ int start_with_wildcard;
+ int end_with_wildcard;
+ struct ldb_val **chunks;
+ } substring;
+ struct {
+ const char *attr;
+ } present;
+ struct {
+ const char *attr;
+ struct ldb_val value;
+ } comparison;
+ struct {
+ const char *attr;
+ int dnAttributes;
+ const char *rule_id;
+ struct ldb_val value;
+ } extended;
+ struct {
+ unsigned int num_elements;
+ struct ldb_parse_tree **elements;
+ } list;
+ } u;
+};
+
+struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s);
+char *ldb_filter_from_tree(TALLOC_CTX *mem_ctx, const struct ldb_parse_tree *tree);
+
+/**
+ Encode a binary blob
+
+ This function encodes a binary blob using the encoding rules in RFC
+ 2254 (Section 4). This function also escapes any non-printable
+ characters.
+
+ \param mem_ctx the memory context to allocate the return string in.
+ \param val the (potentially) binary data to be encoded
+
+ \return the encoded data as a null terminated string
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>.
+*/
+char *ldb_binary_encode(TALLOC_CTX *mem_ctx, struct ldb_val val);
+
+/**
+ Encode a string
+
+ This function encodes a string using the encoding rules in RFC 2254
+ (Section 4). This function also escapes any non-printable
+ characters.
+
+ \param mem_ctx the memory context to allocate the return string in.
+ \param string the string to be encoded
+
+ \return the encoded data as a null terminated string
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>.
+*/
+char *ldb_binary_encode_string(TALLOC_CTX *mem_ctx, const char *string);
+
+/*
+ functions for controlling attribute handling
+*/
+typedef int (*ldb_attr_handler_t)(struct ldb_context *, TALLOC_CTX *mem_ctx, const struct ldb_val *, struct ldb_val *);
+typedef int (*ldb_attr_comparison_t)(struct ldb_context *, TALLOC_CTX *mem_ctx, const struct ldb_val *, const struct ldb_val *);
+struct ldb_schema_attribute;
+typedef int (*ldb_attr_operator_t)(struct ldb_context *, enum ldb_parse_op operation,
+ const struct ldb_schema_attribute *a,
+ const struct ldb_val *, const struct ldb_val *, bool *matched);
+
+/*
+ attribute handler structure
+
+ attr -> The attribute name
+ ldif_read_fn -> convert from ldif to binary format
+ ldif_write_fn -> convert from binary to ldif format
+ canonicalise_fn -> canonicalise a value, for use by indexing and dn construction
+ index_form_fn -> get lexicographically sorted format for index
+ comparison_fn -> compare two values
+ operator_fn -> override function for optimizing out unnecessary
+ calls to canonicalise_fn and comparison_fn
+*/
+
+struct ldb_schema_syntax {
+ const char *name;
+ ldb_attr_handler_t ldif_read_fn;
+ ldb_attr_handler_t ldif_write_fn;
+ ldb_attr_handler_t canonicalise_fn;
+ ldb_attr_handler_t index_format_fn;
+ ldb_attr_comparison_t comparison_fn;
+ ldb_attr_operator_t operator_fn;
+};
+
+struct ldb_schema_attribute {
+ const char *name;
+ unsigned flags;
+ const struct ldb_schema_syntax *syntax;
+};
+
+const struct ldb_schema_attribute *ldb_schema_attribute_by_name(struct ldb_context *ldb,
+ const char *name);
+
+struct ldb_dn_extended_syntax {
+ const char *name;
+ ldb_attr_handler_t read_fn;
+ ldb_attr_handler_t write_clear_fn;
+ ldb_attr_handler_t write_hex_fn;
+};
+
+const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_context *ldb,
+ const char *name);
+
+/**
+ The attribute is not returned by default
+*/
+#define LDB_ATTR_FLAG_HIDDEN (1<<0)
+
+/* the attribute handler name should be freed when released */
+#define LDB_ATTR_FLAG_ALLOCATED (1<<1)
+
+/**
+ The attribute is supplied by the application and should not be removed
+*/
+#define LDB_ATTR_FLAG_FIXED (1<<2)
+
+/*
+ when this is set, attempts to create two records which have the same
+ value for this attribute will return LDB_ERR_ENTRY_ALREADY_EXISTS
+ */
+#define LDB_ATTR_FLAG_UNIQUE_INDEX (1<<3)
+
+/*
+ when this is set, attempts to create two attribute values for this attribute on a single DN will return LDB_ERR_CONSTRAINT_VIOLATION
+ */
+#define LDB_ATTR_FLAG_SINGLE_VALUE (1<<4)
+
+/*
+ * The values should always be base64 encoded
+ */
+#define LDB_ATTR_FLAG_FORCE_BASE64_LDIF (1<<5)
+
+/*
+ * The attribute was loaded from a DB, rather than via the C API
+ */
+#define LDB_ATTR_FLAG_FROM_DB (1<<6)
+
+/*
+ * The attribute is indexed
+ */
+#define LDB_ATTR_FLAG_INDEXED (1<<7)
+
+/**
+ LDAP attribute syntax for a DN
+
+ This is the well-known LDAP attribute syntax for a DN.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_DN "1.3.6.1.4.1.1466.115.121.1.12"
+
+/**
+ LDAP attribute syntax for a Directory String
+
+ This is the well-known LDAP attribute syntax for a Directory String.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_DIRECTORY_STRING "1.3.6.1.4.1.1466.115.121.1.15"
+
+/**
+ LDAP attribute syntax for an integer
+
+ This is the well-known LDAP attribute syntax for an integer.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_INTEGER "1.3.6.1.4.1.1466.115.121.1.27"
+
+/**
+ Custom attribute syntax for an integer whose index is lexicographically
+ ordered by attribute value in the database.
+*/
+#define LDB_SYNTAX_ORDERED_INTEGER "LDB_SYNTAX_ORDERED_INTEGER"
+
+/**
+ LDAP attribute syntax for a boolean
+
+ This is the well-known LDAP attribute syntax for a boolean.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_BOOLEAN "1.3.6.1.4.1.1466.115.121.1.7"
+
+/**
+ LDAP attribute syntax for an octet string
+
+ This is the well-known LDAP attribute syntax for an octet string.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_OCTET_STRING "1.3.6.1.4.1.1466.115.121.1.40"
+
+/**
+ LDAP attribute syntax for UTC time.
+
+ This is the well-known LDAP attribute syntax for a UTC time.
+
+ See <a href="http://www.ietf.org/rfc/rfc2252.txt">RFC 2252</a>, Section 4.3.2
+*/
+#define LDB_SYNTAX_UTC_TIME "1.3.6.1.4.1.1466.115.121.1.53"
+#define LDB_SYNTAX_GENERALIZED_TIME "1.3.6.1.4.1.1466.115.121.1.24"
+
+#define LDB_SYNTAX_OBJECTCLASS "LDB_SYNTAX_OBJECTCLASS"
+
+/* sorting helpers */
+typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
+
+/* Individual controls */
+
+/**
+ OID for getting and manipulating attributes from the ldb
+ without interception in the operational module.
+ It can be used to access attribute that used to be stored in the sam
+ and that are now calculated.
+*/
+#define LDB_CONTROL_BYPASS_OPERATIONAL_OID "1.3.6.1.4.1.7165.4.3.13"
+#define LDB_CONTROL_BYPASS_OPERATIONAL_NAME "bypassoperational"
+
+/**
+ OID for recalculate RDN (rdn attribute and 'name') control. This control forces
+ the rdn_name module to the recalculate the rdn and name attributes as if the
+ object was just created.
+*/
+#define LDB_CONTROL_RECALCULATE_RDN_OID "1.3.6.1.4.1.7165.4.3.30"
+
+/**
+ OID for recalculate SD control. This control force the
+ dsdb code to recalculate the SD of the object as if the
+ object was just created.
+
+*/
+#define LDB_CONTROL_RECALCULATE_SD_OID "1.3.6.1.4.1.7165.4.3.5"
+#define LDB_CONTROL_RECALCULATE_SD_NAME "recalculate_sd"
+
+/**
+ REVEAL_INTERNALS is used to reveal internal attributes and DN
+ components which are not normally shown to the user
+*/
+#define LDB_CONTROL_REVEAL_INTERNALS "1.3.6.1.4.1.7165.4.3.6"
+#define LDB_CONTROL_REVEAL_INTERNALS_NAME "reveal_internals"
+
+/**
+ LDB_CONTROL_AS_SYSTEM is used to skip access checks on operations
+ that are performed by the system, but with a user's credentials, e.g.
+ updating prefix map
+*/
+#define LDB_CONTROL_AS_SYSTEM_OID "1.3.6.1.4.1.7165.4.3.7"
+
+/**
+ LDB_CONTROL_PROVISION_OID is used to skip some constraint checks. It's is
+ mainly thought to be used for the provisioning.
+*/
+#define LDB_CONTROL_PROVISION_OID "1.3.6.1.4.1.7165.4.3.16"
+#define LDB_CONTROL_PROVISION_NAME "provision"
+
+/* AD controls */
+
+/**
+ OID for the paged results control. This control is included in the
+ searchRequest and searchResultDone messages as part of the controls
+ field of the LDAPMessage, as defined in Section 4.1.12 of
+ LDAP v3.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>.
+*/
+#define LDB_CONTROL_PAGED_RESULTS_OID "1.2.840.113556.1.4.319"
+#define LDB_CONTROL_PAGED_RESULTS_NAME "paged_results"
+
+/**
+ OID for specifying the returned elements of the ntSecurityDescriptor
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_sd_flags_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SD_FLAGS_OID "1.2.840.113556.1.4.801"
+#define LDB_CONTROL_SD_FLAGS_NAME "sd_flags"
+
+/**
+ OID for specifying an advanced scope for the search (one partition)
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_domain_scope_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_DOMAIN_SCOPE_OID "1.2.840.113556.1.4.1339"
+#define LDB_CONTROL_DOMAIN_SCOPE_NAME "domain_scope"
+
+/**
+ OID for specifying an advanced scope for a search
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_search_options_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SEARCH_OPTIONS_OID "1.2.840.113556.1.4.1340"
+#define LDB_CONTROL_SEARCH_OPTIONS_NAME "search_options"
+
+/**
+ OID for notification
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_notification_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_NOTIFICATION_OID "1.2.840.113556.1.4.528"
+#define LDB_CONTROL_NOTIFICATION_NAME "notification"
+
+/**
+ OID for performing subtree deletes
+
+ \sa <a href="http://msdn.microsoft.com/en-us/library/aa366991(v=VS.85).aspx">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_TREE_DELETE_OID "1.2.840.113556.1.4.805"
+#define LDB_CONTROL_TREE_DELETE_NAME "tree_delete"
+
+/**
+ OID for getting deleted objects
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_show_deleted_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SHOW_DELETED_OID "1.2.840.113556.1.4.417"
+#define LDB_CONTROL_SHOW_DELETED_NAME "show_deleted"
+
+/**
+ OID for getting recycled objects
+
+ \sa <a href="http://msdn.microsoft.com/en-us/library/dd304621(PROT.13).aspx">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SHOW_RECYCLED_OID "1.2.840.113556.1.4.2064"
+#define LDB_CONTROL_SHOW_RECYCLED_NAME "show_recycled"
+
+/**
+ OID for getting deactivated linked attributes
+
+ \sa <a href="http://msdn.microsoft.com/en-us/library/dd302781(PROT.13).aspx">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SHOW_DEACTIVATED_LINK_OID "1.2.840.113556.1.4.2065"
+#define LDB_CONTROL_SHOW_DEACTIVATED_LINK_NAME "show_deactivated_link"
+
+/**
+ OID for extended DN
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_extended_dn_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_EXTENDED_DN_OID "1.2.840.113556.1.4.529"
+#define LDB_CONTROL_EXTENDED_DN_NAME "extended_dn"
+
+/**
+ OID for LDAP server sort result extension.
+
+ This control is included in the searchRequest message as part of
+ the controls field of the LDAPMessage, as defined in Section 4.1.12
+ of LDAP v3. The controlType is set to
+ "1.2.840.113556.1.4.473". The criticality MAY be either TRUE or
+ FALSE (where absent is also equivalent to FALSE) at the client's
+ option.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
+*/
+#define LDB_CONTROL_SERVER_SORT_OID "1.2.840.113556.1.4.473"
+#define LDB_CONTROL_SERVER_SORT_NAME "server_sort"
+
+/**
+ OID for LDAP server sort result response extension.
+
+ This control is included in the searchResultDone message as part of
+ the controls field of the LDAPMessage, as defined in Section 4.1.12 of
+ LDAP v3.
+
+ \sa <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
+*/
+#define LDB_CONTROL_SORT_RESP_OID "1.2.840.113556.1.4.474"
+#define LDB_CONTROL_SORT_RESP_NAME "server_sort_resp"
+
+/**
+ OID for LDAP Attribute Scoped Query extension.
+
+ This control is included in SearchRequest or SearchResponse
+ messages as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_ASQ_OID "1.2.840.113556.1.4.1504"
+#define LDB_CONTROL_ASQ_NAME "asq"
+
+/**
+ OID for LDAP Directory Sync extension.
+
+ This control is included in SearchRequest or SearchResponse
+ messages as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_DIRSYNC_OID "1.2.840.113556.1.4.841"
+#define LDB_CONTROL_DIRSYNC_NAME "dirsync"
+#define LDB_CONTROL_DIRSYNC_EX_OID "1.2.840.113556.1.4.2090"
+#define LDB_CONTROL_DIRSYNC_EX_NAME "dirsync_ex"
+
+
+/**
+ OID for LDAP Virtual List View Request extension.
+
+ This control is included in SearchRequest messages
+ as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_VLV_REQ_OID "2.16.840.1.113730.3.4.9"
+#define LDB_CONTROL_VLV_REQ_NAME "vlv"
+
+/**
+ OID for LDAP Virtual List View Response extension.
+
+ This control is included in SearchResponse messages
+ as part of the controls field of the LDAPMessage.
+*/
+#define LDB_CONTROL_VLV_RESP_OID "2.16.840.1.113730.3.4.10"
+#define LDB_CONTROL_VLV_RESP_NAME "vlv_resp"
+
+/**
+ OID to let modifies don't give an error when adding an existing
+ attribute with the same value or deleting an nonexisting one attribute
+
+ \sa <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_permissive_modify_oid.asp">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_PERMISSIVE_MODIFY_OID "1.2.840.113556.1.4.1413"
+#define LDB_CONTROL_PERMISSIVE_MODIFY_NAME "permissive_modify"
+
+/**
+ OID to allow the server to be more 'fast and loose' with the data being added.
+
+ \sa <a href="http://msdn.microsoft.com/en-us/library/aa366982(v=VS.85).aspx">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_SERVER_LAZY_COMMIT "1.2.840.113556.1.4.619"
+
+/**
+ Control for RODC join -see [MS-ADTS] section 3.1.1.3.4.1.23
+
+ \sa <a href="">Microsoft documentation of this OID</a>
+*/
+#define LDB_CONTROL_RODC_DCPROMO_OID "1.2.840.113556.1.4.1341"
+#define LDB_CONTROL_RODC_DCPROMO_NAME "rodc_join"
+
+/* Other standardised controls */
+
+/**
+ OID for the allowing client to request temporary relaxed
+ enforcement of constraints of the x.500 model.
+
+ Mainly used for the OpenLDAP backend.
+
+ \sa <a href="http://opends.dev.java.net/public/standards/draft-zeilenga-ldap-managedit.txt">draft managedit</a>.
+*/
+#define LDB_CONTROL_RELAX_OID "1.3.6.1.4.1.4203.666.5.12"
+#define LDB_CONTROL_RELAX_NAME "relax"
+
+/**
+ OID for the allowing some kind of relax check for attributes with DNs
+
+
+ \sa 3.1.1.3.4.1.16 in [MS-ADTS].pdf
+*/
+#define LDB_CONTROL_VERIFY_NAME_OID "1.2.840.113556.1.4.1338"
+#define LDB_CONTROL_VERIFY_NAME_NAME "verify_name"
+
+/* Extended operations */
+
+/**
+ OID for LDAP Extended Operation SEQUENCE_NUMBER
+
+ This extended operation is used to retrieve the extended sequence number.
+*/
+#define LDB_EXTENDED_SEQUENCE_NUMBER "1.3.6.1.4.1.7165.4.4.3"
+
+/**
+ OID for LDAP Extended Operation PASSWORD_CHANGE.
+
+ This Extended operation is used to allow user password changes by the user
+ itself.
+*/
+#define LDB_EXTENDED_PASSWORD_CHANGE_OID "1.3.6.1.4.1.4203.1.11.1"
+
+
+/**
+ OID for LDAP Extended Operation FAST_BIND
+
+ This Extended operations is used to perform a fast bind.
+*/
+#define LDB_EXTENDED_FAST_BIND_OID "1.2.840.113556.1.4.1781"
+
+/**
+ OID for LDAP Extended Operation START_TLS.
+
+ This Extended operation is used to start a new TLS channel on top of a clear
+ text channel.
+*/
+#define LDB_EXTENDED_START_TLS_OID "1.3.6.1.4.1.1466.20037"
+
+/**
+ OID for LDAP Extended Operation DYNAMIC_REFRESH.
+
+ This Extended operation is used to create and maintain objects which exist
+ only a specific time, e.g. when a certain client or a certain person is
+ logged in. Data refreshes have to be periodically sent in a specific
+ interval. Otherwise the entry is going to be removed.
+*/
+#define LDB_EXTENDED_DYNAMIC_OID "1.3.6.1.4.1.1466.101.119.1"
+
+/**
+ OID for RFC4532 "Who Am I" extended operation
+*/
+#define LDB_EXTENDED_WHOAMI_OID "1.3.6.1.4.1.4203.1.11.3"
+
+struct ldb_sd_flags_control {
+ /*
+ * request the owner 0x00000001
+ * request the group 0x00000002
+ * request the DACL 0x00000004
+ * request the SACL 0x00000008
+ */
+ unsigned secinfo_flags;
+};
+
+/*
+ * DOMAIN_SCOPE 0x00000001
+ * this limits the search to one partition,
+ * and no referrals will be returned.
+ * (Note this doesn't limit the entries by there
+ * objectSid belonging to a domain! Builtin and Foreign Sids
+ * are still returned)
+ *
+ * PHANTOM_ROOT 0x00000002
+ * this search on the whole tree on a domain controller
+ * over multiple partitions without referrals.
+ * (This is the default behavior on the Global Catalog Port)
+ */
+
+#define LDB_SEARCH_OPTION_DOMAIN_SCOPE 0x00000001
+#define LDB_SEARCH_OPTION_PHANTOM_ROOT 0x00000002
+
+struct ldb_search_options_control {
+ unsigned search_options;
+};
+
+struct ldb_paged_control {
+ int size;
+ int cookie_len;
+ char *cookie;
+};
+
+struct ldb_extended_dn_control {
+ int type;
+};
+
+struct ldb_server_sort_control {
+ const char *attributeName;
+ const char *orderingRule;
+ int reverse;
+};
+
+struct ldb_sort_resp_control {
+ int result;
+ char *attr_desc;
+};
+
+struct ldb_asq_control {
+ int request;
+ char *source_attribute;
+ int src_attr_len;
+ int result;
+};
+
+struct ldb_dirsync_control {
+ int flags;
+ int max_attributes;
+ int cookie_len;
+ char *cookie;
+};
+
+struct ldb_vlv_req_control {
+ int beforeCount;
+ int afterCount;
+ int type;
+ union {
+ struct {
+ int offset;
+ int contentCount;
+ } byOffset;
+ struct {
+ int value_len;
+ char *value;
+ } gtOrEq;
+ } match;
+ int ctxid_len;
+ uint8_t *contextId;
+};
+
+struct ldb_vlv_resp_control {
+ int targetPosition;
+ int contentCount;
+ int vlv_result;
+ int ctxid_len;
+ uint8_t *contextId;
+};
+
+struct ldb_verify_name_control {
+ int flags;
+ size_t gc_len;
+ char *gc;
+};
+
+struct ldb_control {
+ const char *oid;
+ int critical;
+ void *data;
+};
+
+enum ldb_request_type {
+ LDB_SEARCH,
+ LDB_ADD,
+ LDB_MODIFY,
+ LDB_DELETE,
+ LDB_RENAME,
+ LDB_EXTENDED,
+ LDB_REQ_REGISTER_CONTROL,
+ LDB_REQ_REGISTER_PARTITION
+};
+
+enum ldb_reply_type {
+ LDB_REPLY_ENTRY,
+ LDB_REPLY_REFERRAL,
+ LDB_REPLY_DONE
+};
+
+enum ldb_wait_type {
+ LDB_WAIT_ALL,
+ LDB_WAIT_NONE
+};
+
+enum ldb_state {
+ LDB_ASYNC_INIT,
+ LDB_ASYNC_PENDING,
+ LDB_ASYNC_DONE
+};
+
+struct ldb_extended {
+ const char *oid;
+ void *data; /* NULL or a valid talloc pointer! talloc_get_type() will be used on it */
+};
+
+enum ldb_sequence_type {
+ LDB_SEQ_HIGHEST_SEQ,
+ LDB_SEQ_HIGHEST_TIMESTAMP,
+ LDB_SEQ_NEXT
+};
+
+#define LDB_SEQ_GLOBAL_SEQUENCE 0x01
+#define LDB_SEQ_TIMESTAMP_SEQUENCE 0x02
+
+struct ldb_seqnum_request {
+ enum ldb_sequence_type type;
+};
+
+struct ldb_seqnum_result {
+ uint64_t seq_num;
+ uint32_t flags;
+};
+
+struct ldb_result {
+ unsigned int count;
+ struct ldb_message **msgs;
+ struct ldb_extended *extended;
+ struct ldb_control **controls;
+ char **refs;
+};
+
+struct ldb_reply {
+ int error;
+ enum ldb_reply_type type;
+ struct ldb_message *message;
+ struct ldb_extended *response;
+ struct ldb_control **controls;
+ char *referral;
+};
+
+struct ldb_request;
+struct ldb_handle;
+
+struct ldb_search {
+ struct ldb_dn *base;
+ enum ldb_scope scope;
+ struct ldb_parse_tree *tree;
+ const char * const *attrs;
+ struct ldb_result *res;
+};
+
+struct ldb_add {
+ const struct ldb_message *message;
+};
+
+struct ldb_modify {
+ const struct ldb_message *message;
+};
+
+struct ldb_delete {
+ struct ldb_dn *dn;
+};
+
+struct ldb_rename {
+ struct ldb_dn *olddn;
+ struct ldb_dn *newdn;
+};
+
+struct ldb_register_control {
+ const char *oid;
+};
+
+struct ldb_register_partition {
+ struct ldb_dn *dn;
+};
+
+typedef int (*ldb_request_callback_t)(struct ldb_request *, struct ldb_reply *);
+
+struct ldb_request {
+
+ enum ldb_request_type operation;
+
+ union {
+ struct ldb_search search;
+ struct ldb_add add;
+ struct ldb_modify mod;
+ struct ldb_delete del;
+ struct ldb_rename rename;
+ struct ldb_extended extended;
+ struct ldb_register_control reg_control;
+ struct ldb_register_partition reg_partition;
+ } op;
+
+ struct ldb_control **controls;
+
+ void *context;
+ ldb_request_callback_t callback;
+
+ int timeout;
+ time_t starttime;
+ struct ldb_handle *handle;
+};
+
+int ldb_request(struct ldb_context *ldb, struct ldb_request *request);
+int ldb_request_done(struct ldb_request *req, int status);
+bool ldb_request_is_done(struct ldb_request *req);
+
+int ldb_modules_wait(struct ldb_handle *handle);
+int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type);
+
+int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout);
+int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq);
+void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms);
+void ldb_set_modules_dir(struct ldb_context *ldb, const char *path);
+struct tevent_context;
+void ldb_set_event_context(struct ldb_context *ldb, struct tevent_context *ev);
+struct tevent_context * ldb_get_event_context(struct ldb_context *ldb);
+
+/**
+ Initialise ldbs' global information
+
+ This is required before any other LDB call
+
+ \return 0 if initialisation succeeded, -1 otherwise
+*/
+int ldb_global_init(void);
+
+/**
+ Initialise an ldb context
+
+ This is required before any other LDB call.
+
+ \param mem_ctx pointer to a talloc memory context. Pass NULL if there is
+ no suitable context available.
+
+ \note The LDB modules will be loaded from directory specified by the environment
+ variable LDB_MODULES_PATH. If the variable is not specified, the compiled-in default
+ is used.
+
+ \return pointer to ldb_context that should be free'd (using talloc_free())
+ at the end of the program.
+*/
+struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx);
+
+/**
+ Connect to a database.
+
+ This is typically called soon after ldb_init(), and is required prior to
+ any search or database modification operations.
+
+ The URL can be one of the following forms:
+ - tdb://path
+ - ldapi://path
+ - ldap://host
+ - sqlite://path
+
+ \param ldb the context associated with the database (from ldb_init())
+ \param url the URL of the database to connect to, as noted above
+ \param flags a combination of LDB_FLG_* to modify the connection behaviour
+ \param options backend specific options - passed uninterpreted to the backend
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+
+ \note It is an error to connect to a database that does not exist in readonly mode
+ (that is, with LDB_FLG_RDONLY). However in read-write mode, the database will be
+ created if it does not exist.
+*/
+int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]);
+
+/*
+ return an automatic basedn from the rootDomainNamingContext of the rootDSE
+ This value have been set in an opaque pointer at connection time
+*/
+struct ldb_dn *ldb_get_root_basedn(struct ldb_context *ldb);
+
+/*
+ return an automatic basedn from the configurationNamingContext of the rootDSE
+ This value have been set in an opaque pointer at connection time
+*/
+struct ldb_dn *ldb_get_config_basedn(struct ldb_context *ldb);
+
+/*
+ return an automatic basedn from the schemaNamingContext of the rootDSE
+ This value have been set in an opaque pointer at connection time
+*/
+struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb);
+
+/*
+ return an automatic baseDN from the defaultNamingContext of the rootDSE
+ This value have been set in an opaque pointer at connection time
+*/
+struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb);
+
+/**
+ The default async search callback function
+
+ \param req the request we are callback of
+ \param ares a single reply from the async core
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+
+ \note this function expects req->context to always be an struct ldb_result pointer
+ AND a talloc context, this function will steal on the context each message
+ from the ares reply passed on by the async core so that in the end all the
+ messages will be in the context (ldb_result) memory tree.
+ Freeing the passed context (ldb_result tree) will free all the resources
+ (the request need to be freed separately and the result doe not depend on the
+ request that can be freed as sson as the search request is finished)
+*/
+
+int ldb_search_default_callback(struct ldb_request *req, struct ldb_reply *ares);
+
+/**
+ The default async extended operation callback function
+
+ \param req the request we are callback of
+ \param ares a single reply from the async core
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares);
+
+int ldb_modify_default_callback(struct ldb_request *req, struct ldb_reply *ares);
+
+/**
+ Helper function to build a search request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc memory context (used as parent of ret_req)
+ \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one)
+ \param scope the search scope for the query
+ \param expression the search expression to use for this query
+ \param attrs the search attributes for the query (pass NULL if none required)
+ \param controls an array of controls
+ \param context the callback function context
+ \param callback the callback function to handle the async replies
+ \param parent the parent request if any
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_search_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char * const *attrs,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent);
+
+int ldb_build_search_req_ex(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *base,
+ enum ldb_scope scope,
+ struct ldb_parse_tree *tree,
+ const char * const *attrs,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent);
+
+/**
+ Helper function to build an add request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc memory context (used as parent of ret_req)
+ \param message contains the entry to be added
+ \param controls an array of controls
+ \param context the callback function context
+ \param callback the callback function to handle the async replies
+ \param parent the parent request if any
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_add_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent);
+
+/**
+ Helper function to build a modify request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc memory context (used as parent of ret_req)
+ \param message contains the entry to be modified
+ \param controls an array of controls
+ \param context the callback function context
+ \param callback the callback function to handle the async replies
+ \param parent the parent request if any
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_mod_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *message,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent);
+
+/**
+ Helper function to build a delete request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc memory context (used as parent of ret_req)
+ \param dn the DN to be deleted
+ \param controls an array of controls
+ \param context the callback function context
+ \param callback the callback function to handle the async replies
+ \param parent the parent request if any
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_del_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent);
+
+/**
+ Helper function to build a rename request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc memory context (used as parent of ret_req)
+ \param olddn the old DN
+ \param newdn the new DN
+ \param controls an array of controls
+ \param context the callback function context
+ \param callback the callback function to handle the async replies
+ \param parent the parent request if any
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+
+int ldb_build_rename_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *olddn,
+ struct ldb_dn *newdn,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent);
+
+/**
+ Add a ldb_control to a ldb_request
+
+ \param req the request struct where to add the control
+ \param oid the object identifier of the control as string
+ \param critical whether the control should be critical or not
+ \param data a talloc pointer to the control specific data
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+int ldb_request_add_control(struct ldb_request *req, const char *oid, bool critical, void *data);
+
+/**
+ replace a ldb_control in a ldb_request
+
+ \param req the request struct where to add the control
+ \param oid the object identifier of the control as string
+ \param critical whether the control should be critical or not
+ \param data a talloc pointer to the control specific data
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+int ldb_request_replace_control(struct ldb_request *req, const char *oid, bool critical, void *data);
+
+/**
+ check if a control with the specified "oid" exist and return it
+ \param req the request struct where to add the control
+ \param oid the object identifier of the control as string
+
+ \return the control, NULL if not found
+*/
+struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid);
+
+/**
+ check if a control with the specified "oid" exist and return it
+ \param rep the reply struct where to add the control
+ \param oid the object identifier of the control as string
+
+ \return the control, NULL if not found
+*/
+struct ldb_control *ldb_reply_get_control(struct ldb_reply *rep, const char *oid);
+
+/**
+ Search the database
+
+ This function searches the database, and returns
+ records that match an LDAP-like search expression
+
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx the memory context to use for the request and the results
+ \param result the return result
+ \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one)
+ \param scope the search scope for the query
+ \param attrs the search attributes for the query (pass NULL if none required)
+ \param exp_fmt the search expression to use for this query (printf like)
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+
+ \note use talloc_free() to free the ldb_result returned
+*/
+int ldb_search(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_result **result, struct ldb_dn *base,
+ enum ldb_scope scope, const char * const *attrs,
+ const char *exp_fmt, ...) PRINTF_ATTRIBUTE(7,8);
+
+/**
+ Add a record to the database.
+
+ This function adds a record to the database. This function will fail
+ if a record with the specified class and key already exists in the
+ database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param message the message containing the record to add.
+
+ \return result code (LDB_SUCCESS if the record was added, otherwise
+ a failure code)
+*/
+int ldb_add(struct ldb_context *ldb,
+ const struct ldb_message *message);
+
+/**
+ Modify the specified attributes of a record
+
+ This function modifies a record that is in the database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param message the message containing the changes required.
+
+ \return result code (LDB_SUCCESS if the record was modified as
+ requested, otherwise a failure code)
+*/
+int ldb_modify(struct ldb_context *ldb,
+ const struct ldb_message *message);
+
+/**
+ Rename a record in the database
+
+ This function renames a record in the database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param olddn the DN for the record to be renamed.
+ \param newdn the new DN
+
+ \return result code (LDB_SUCCESS if the record was renamed as
+ requested, otherwise a failure code)
+*/
+int ldb_rename(struct ldb_context *ldb, struct ldb_dn *olddn, struct ldb_dn *newdn);
+
+/**
+ Delete a record from the database
+
+ This function deletes a record from the database.
+
+ \param ldb the context associated with the database (from
+ ldb_init())
+ \param dn the DN for the record to be deleted.
+
+ \return result code (LDB_SUCCESS if the record was deleted,
+ otherwise a failure code)
+*/
+int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn);
+
+/**
+ The default async extended operation callback function
+
+ \param req the request we are callback of
+ \param ares a single reply from the async core
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+
+ \note this function expects req->context to always be an struct ldb_result pointer
+ AND a talloc context, this function will steal on the context each message
+ from the ares reply passed on by the async core so that in the end all the
+ messages will be in the context (ldb_result) memory tree.
+ Freeing the passed context (ldb_result tree) will free all the resources
+ (the request need to be freed separately and the result doe not depend on the
+ request that can be freed as sson as the search request is finished)
+*/
+
+int ldb_extended_default_callback(struct ldb_request *req, struct ldb_reply *ares);
+
+
+/**
+ Helper function to build a extended request
+
+ \param ret_req the request structure is returned here (talloced on mem_ctx)
+ \param ldb the context associated with the database (from ldb_init())
+ \param mem_ctx a talloc memory context (used as parent of ret_req)
+ \param oid the OID of the extended operation.
+ \param data a void pointer to the extended operation specific parameters,
+ it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it
+ \param controls an array of controls
+ \param context the callback function context
+ \param callback the callback function to handle the async replies
+ \param parent the parent request if any
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+int ldb_build_extended_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *oid,
+ void *data,/* NULL or a valid talloc pointer! talloc_get_type() will be used on it */
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent);
+
+/**
+ call an extended operation
+
+ \param ldb the context associated with the database (from ldb_init())
+ \param oid the OID of the extended operation.
+ \param data a void pointer to the extended operation specific parameters,
+ it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it
+ \param res the result of the extended operation
+
+ \return result code (LDB_SUCCESS if the extended operation returned fine,
+ otherwise a failure code)
+*/
+int ldb_extended(struct ldb_context *ldb,
+ const char *oid,
+ void *data,/* NULL or a valid talloc pointer! talloc_get_type() will be used on it */
+ struct ldb_result **res);
+
+/**
+ Obtain current/next database sequence number
+*/
+int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num);
+
+/**
+ start a transaction
+*/
+int ldb_transaction_start(struct ldb_context *ldb);
+
+/**
+ first phase of two phase commit
+ */
+int ldb_transaction_prepare_commit(struct ldb_context *ldb);
+
+/**
+ commit a transaction
+*/
+int ldb_transaction_commit(struct ldb_context *ldb);
+
+/**
+ cancel a transaction
+*/
+int ldb_transaction_cancel(struct ldb_context *ldb);
+
+/*
+ cancel a transaction with no error if no transaction is pending
+ used when we fork() to clear any parent transactions
+*/
+int ldb_transaction_cancel_noerr(struct ldb_context *ldb);
+
+
+/**
+ return extended error information from the last call
+*/
+const char *ldb_errstring(struct ldb_context *ldb);
+
+/**
+ return a string explaining what a ldb error constant means
+*/
+const char *ldb_strerror(int ldb_err);
+
+/**
+ setup the default utf8 functions
+ FIXME: these functions do not yet handle utf8
+*/
+void ldb_set_utf8_default(struct ldb_context *ldb);
+
+/**
+ \brief Casefold a string
+
+ Note that the callback needs to be ASCII compatible. So first ASCII needs
+ to be handle before any UTF-8. This is needed to avoid issues with dotted
+ languages.
+
+ \param ldb the ldb context
+ \param mem_ctx the memory context to allocate the result string
+ memory from.
+ \param s the string that is to be folded
+ \return a copy of the string, converted to upper case
+
+ \note The default function is not yet UTF8 aware. Provide your own
+ set of functions through ldb_set_utf8_fns()
+*/
+char *ldb_casefold(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *s, size_t n);
+
+/**
+ Check the attribute name is valid according to rfc2251
+ \param s the string to check
+
+ \return 1 if the name is ok
+*/
+int ldb_valid_attr_name(const char *s);
+
+/*
+ ldif manipulation functions
+*/
+
+/**
+ Write an LDIF message
+
+ This function writes an LDIF message using a caller supplied write
+ function.
+
+ \param ldb the ldb context (from ldb_init())
+ \param fprintf_fn a function pointer for the write function. This must take
+ a private data pointer, followed by a format string, and then a variable argument
+ list.
+ \param private_data pointer that will be provided back to the write
+ function. This is useful for maintaining state or context.
+ \param ldif the message to write out
+
+ \return the total number of bytes written, or an error code as returned
+ from the write function.
+
+ \sa ldb_ldif_write_file for a more convenient way to write to a
+ file stream.
+
+ \sa ldb_ldif_read for the reader equivalent to this function.
+*/
+int ldb_ldif_write(struct ldb_context *ldb,
+ int (*fprintf_fn)(void *, const char *, ...) PRINTF_ATTRIBUTE(2,3),
+ void *private_data,
+ const struct ldb_ldif *ldif);
+
+/**
+ Clean up an LDIF message
+
+ This function cleans up a LDIF message read using ldb_ldif_read()
+ or related functions (such as ldb_ldif_read_string() and
+ ldb_ldif_read_file().
+
+ \param ldb the ldb context (from ldb_init())
+ \param msg the message to clean up and free
+
+*/
+void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *msg);
+
+/**
+ Read an LDIF message
+
+ This function creates an LDIF message using a caller supplied read
+ function.
+
+ \param ldb the ldb context (from ldb_init())
+ \param fgetc_fn a function pointer for the read function. This must
+ take a private data pointer, and must return a pointer to an
+ integer corresponding to the next byte read (or EOF if there is no
+ more data to be read).
+ \param private_data pointer that will be provided back to the read
+ function. This is udeful for maintaining state or context.
+
+ \return the LDIF message that has been read in
+
+ \note You must free the LDIF message when no longer required, using
+ ldb_ldif_read_free().
+
+ \sa ldb_ldif_read_file for a more convenient way to read from a
+ file stream.
+
+ \sa ldb_ldif_read_string for a more convenient way to read from a
+ string (char array).
+
+ \sa ldb_ldif_write for the writer equivalent to this function.
+*/
+struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
+ int (*fgetc_fn)(void *), void *private_data);
+
+/**
+ Read an LDIF message from a file
+
+ This function reads the next LDIF message from the contents of a
+ file stream. If you want to get all of the LDIF messages, you will
+ need to repeatedly call this function, until it returns NULL.
+
+ \param ldb the ldb context (from ldb_init())
+ \param f the file stream to read from (typically from fdopen())
+
+ \sa ldb_ldif_read_string for an equivalent function that will read
+ from a string (char array).
+
+ \sa ldb_ldif_write_file for the writer equivalent to this function.
+
+*/
+struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f);
+
+/**
+ Read an LDIF message from a string
+
+ This function reads the next LDIF message from the contents of a char
+ array. If you want to get all of the LDIF messages, you will need
+ to repeatedly call this function, until it returns NULL.
+
+ \param ldb the ldb context (from ldb_init())
+ \param s pointer to the char array to read from
+
+ \sa ldb_ldif_read_file for an equivalent function that will read
+ from a file stream.
+
+ \sa ldb_ldif_write for a more general (arbitrary read function)
+ version of this function.
+*/
+struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s);
+
+/**
+ Parse a modrdn LDIF message from a struct ldb_message
+
+ \param ldb the ldb context (from ldb_init())
+ \param ldif the preparsed LDIF chunk (from ldb_ldif_read())
+
+ \param mem_ctx the memory context that's used for return values
+
+ \param olddn the old dn as struct ldb_dn, if not needed pass NULL
+ \param newrdn the new rdn as struct ldb_dn, if not needed pass NULL
+ \param deleteoldrdn the deleteoldrdn value as bool, if not needed pass NULL
+ \param newsuperior the newsuperior dn as struct ldb_dn, if not needed pass NULL
+ *newsuperior can be NULL as it is optional in the LDIF
+ \param newdn the full constructed new dn as struct ldb_dn, if not needed pass NULL
+
+*/
+int ldb_ldif_parse_modrdn(struct ldb_context *ldb,
+ const struct ldb_ldif *ldif,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn **olddn,
+ struct ldb_dn **newrdn,
+ bool *deleteoldrdn,
+ struct ldb_dn **newsuperior,
+ struct ldb_dn **newdn);
+
+/**
+ Write an LDIF message to a file
+
+ \param ldb the ldb context (from ldb_init())
+ \param f the file stream to write to (typically from fdopen())
+ \param msg the message to write out
+
+ \return the total number of bytes written, or a negative error code
+
+ \sa ldb_ldif_read_file for the reader equivalent to this function.
+*/
+int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *msg);
+
+/**
+ Write an LDIF message to a string
+
+ \param ldb the ldb context (from ldb_init())
+ \param mem_ctx the talloc context on which to attach the string)
+ \param msg the message to write out
+
+ \return the string containing the LDIF, or NULL on error
+
+ \sa ldb_ldif_read_string for the reader equivalent to this function.
+*/
+char * ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ const struct ldb_ldif *msg);
+
+
+/**
+ Write an LDB message to a string
+
+ \param ldb the ldb context (from ldb_init())
+ \param mem_ctx the talloc context on which to attach the string)
+ \param changetype LDB_CHANGETYPE_ADD or LDB_CHANGETYPE_MODIFY
+ \param msg the message to write out
+
+ \return the string containing the LDIF, or NULL on error
+
+ \sa ldb_ldif_message_redacted_string for a safer version of this
+ function
+*/
+char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ enum ldb_changetype changetype,
+ const struct ldb_message *msg);
+
+/**
+ Write an LDB message to a string
+
+ \param ldb the ldb context (from ldb_init())
+ \param mem_ctx the talloc context on which to attach the string)
+ \param changetype LDB_CHANGETYPE_ADD or LDB_CHANGETYPE_MODIFY
+ \param msg the message to write out
+
+ \return the string containing the LDIF, or NULL on error, but
+ with secret attributes redacted
+
+ \note The secret attributes are specified in a
+ 'const char * const *' within the LDB_SECRET_ATTRIBUTE_LIST
+ opaque set on the ldb
+
+ \sa ldb_ldif_message_string for an exact representation of the
+ message as LDIF
+*/
+char *ldb_ldif_message_redacted_string(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ enum ldb_changetype changetype,
+ const struct ldb_message *msg);
+
+
+/**
+ Base64 encode a buffer
+
+ \param mem_ctx the memory context that the result is allocated
+ from.
+ \param buf pointer to the array that is to be encoded
+ \param len the number of elements in the array to be encoded
+
+ \return pointer to an array containing the encoded data
+
+ \note The caller is responsible for freeing the result
+*/
+char *ldb_base64_encode(TALLOC_CTX *mem_ctx, const char *buf, int len);
+
+/**
+ Base64 decode a buffer
+
+ This function decodes a base64 encoded string in place.
+
+ \param s the string to decode.
+
+ \return the length of the returned (decoded) string.
+
+ \note the string is null terminated, but the null terminator is not
+ included in the length.
+*/
+int ldb_base64_decode(char *s);
+
+/* The following definitions come from lib/ldb/common/ldb_dn.c */
+
+/**
+ Get the linear form of a DN (without any extended components)
+
+ \param dn The DN to linearize
+*/
+
+const char *ldb_dn_get_linearized(struct ldb_dn *dn);
+
+/**
+ Allocate a copy of the linear form of a DN (without any extended components) onto the supplied memory context
+
+ \param dn The DN to linearize
+ \param mem_ctx TALLOC context to return result on
+*/
+
+char *ldb_dn_alloc_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn);
+
+/**
+ Get the linear form of a DN (with any extended components)
+
+ \param mem_ctx TALLOC context to return result on
+ \param dn The DN to linearize
+ \param mode Style of extended DN to return (0 is HEX representation of binary form, 1 is a string form)
+*/
+char *ldb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, int mode);
+const struct ldb_val *ldb_dn_get_extended_component(struct ldb_dn *dn, const char *name);
+int ldb_dn_set_extended_component(struct ldb_dn *dn, const char *name, const struct ldb_val *val);
+void ldb_dn_extended_filter(struct ldb_dn *dn, const char * const *accept_list);
+void ldb_dn_remove_extended_components(struct ldb_dn *dn);
+bool ldb_dn_has_extended(struct ldb_dn *dn);
+
+int ldb_dn_extended_add_syntax(struct ldb_context *ldb,
+ unsigned flags,
+ const struct ldb_dn_extended_syntax *syntax);
+
+/**
+ Allocate a new DN from a string
+
+ \param mem_ctx TALLOC context to return resulting ldb_dn structure on
+ \param dn The new DN
+
+ \note The DN will not be parsed at this time. Use ldb_dn_validate to tell if the DN is syntactically correct
+*/
+
+struct ldb_dn *ldb_dn_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *dn);
+/**
+ Allocate a new DN from a printf style format string and arguments
+
+ \param mem_ctx TALLOC context to return resulting ldb_dn structure on
+ \param new_fmt The new DN as a format string (plus arguments)
+
+ \note The DN will not be parsed at this time. Use ldb_dn_validate to tell if the DN is syntactically correct
+*/
+
+struct ldb_dn *ldb_dn_new_fmt(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...) PRINTF_ATTRIBUTE(3,4);
+/**
+ Allocate a new DN from a struct ldb_val (useful to avoid buffer overrun)
+
+ \param mem_ctx TALLOC context to return resulting ldb_dn structure on
+ \param dn The new DN
+
+ \note The DN will not be parsed at this time. Use ldb_dn_validate to tell if the DN is syntactically correct
+*/
+
+struct ldb_dn *ldb_dn_from_ldb_val(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const struct ldb_val *strdn);
+
+/**
+ Determine if this DN is syntactically valid
+
+ \param dn The DN to validate
+*/
+
+bool ldb_dn_validate(struct ldb_dn *dn);
+
+char *ldb_dn_escape_value(TALLOC_CTX *mem_ctx, struct ldb_val value);
+const char *ldb_dn_get_casefold(struct ldb_dn *dn);
+char *ldb_dn_alloc_casefold(TALLOC_CTX *mem_ctx, struct ldb_dn *dn);
+
+int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn);
+int ldb_dn_compare(struct ldb_dn *edn0, struct ldb_dn *edn1);
+
+bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base);
+bool ldb_dn_add_base_fmt(struct ldb_dn *dn, const char *base_fmt, ...) PRINTF_ATTRIBUTE(2,3);
+bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child);
+bool ldb_dn_add_child_fmt(struct ldb_dn *dn, const char *child_fmt, ...) PRINTF_ATTRIBUTE(2,3);
+bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num);
+bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num);
+bool ldb_dn_add_child_val(struct ldb_dn *dn,
+ const char *rdn,
+ struct ldb_val value);
+
+struct ldb_dn *ldb_dn_copy(TALLOC_CTX *mem_ctx, struct ldb_dn *dn);
+struct ldb_dn *ldb_dn_get_parent(TALLOC_CTX *mem_ctx, struct ldb_dn *dn);
+char *ldb_dn_canonical_string(TALLOC_CTX *mem_ctx, struct ldb_dn *dn);
+char *ldb_dn_canonical_ex_string(TALLOC_CTX *mem_ctx, struct ldb_dn *dn);
+int ldb_dn_get_comp_num(struct ldb_dn *dn);
+int ldb_dn_get_extended_comp_num(struct ldb_dn *dn);
+const char *ldb_dn_get_component_name(struct ldb_dn *dn, unsigned int num);
+const struct ldb_val *ldb_dn_get_component_val(struct ldb_dn *dn, unsigned int num);
+const char *ldb_dn_get_rdn_name(struct ldb_dn *dn);
+const struct ldb_val *ldb_dn_get_rdn_val(struct ldb_dn *dn);
+int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val);
+
+bool ldb_dn_is_valid(struct ldb_dn *dn);
+bool ldb_dn_is_special(struct ldb_dn *dn);
+bool ldb_dn_check_special(struct ldb_dn *dn, const char *check);
+bool ldb_dn_is_null(struct ldb_dn *dn);
+int ldb_dn_update_components(struct ldb_dn *dn, const struct ldb_dn *ref_dn);
+
+
+/**
+ Compare two attributes
+
+ This function compares to attribute names. Note that this is a
+ case-insensitive comparison.
+
+ \param a the first attribute name to compare
+ \param b the second attribute name to compare
+
+ \return 0 if the attribute names are the same, or only differ in
+ case; non-zero if there are any differences
+
+ attribute names are restricted by rfc2251 so using
+ strcasecmp and toupper here is ok.
+ return 0 for match
+*/
+#undef strcasecmp
+#define ldb_attr_cmp(a, b) strcasecmp(a, b)
+char *ldb_attr_casefold(TALLOC_CTX *mem_ctx, const char *s);
+int ldb_attr_dn(const char *attr);
+
+/**
+ Create an empty message
+
+ \param mem_ctx the memory context to create in. You can pass NULL
+ to get the top level context, however the ldb context (from
+ ldb_init()) may be a better choice
+*/
+struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx);
+
+/**
+ Find an element within an message
+*/
+struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
+ const char *attr_name);
+
+/**
+ Compare two ldb_val values
+
+ \param v1 first ldb_val structure to be tested
+ \param v2 second ldb_val structure to be tested
+
+ \return 1 for a match, 0 if there is any difference
+*/
+int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2);
+
+/**
+ find a value within an ldb_message_element
+
+ \param el the element to search
+ \param val the value to search for
+
+ \note This search is case sensitive
+*/
+struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
+ struct ldb_val *val);
+
+/**
+ add a new empty element to a ldb_message
+*/
+int ldb_msg_add_empty(struct ldb_message *msg,
+ const char *attr_name,
+ int flags,
+ struct ldb_message_element **return_el);
+
+/**
+ add a value to a message element
+*/
+int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *el,
+ const struct ldb_val *val);
+/**
+ add a element to a ldb_message
+*/
+int ldb_msg_add(struct ldb_message *msg,
+ const struct ldb_message_element *el,
+ int flags);
+int ldb_msg_add_value(struct ldb_message *msg,
+ const char *attr_name,
+ const struct ldb_val *val,
+ struct ldb_message_element **return_el);
+int ldb_msg_add_steal_value(struct ldb_message *msg,
+ const char *attr_name,
+ struct ldb_val *val);
+int ldb_msg_add_steal_string(struct ldb_message *msg,
+ const char *attr_name, char *str);
+int ldb_msg_add_string_flags(struct ldb_message *msg,
+ const char *attr_name, const char *str,
+ int flags);
+int ldb_msg_add_string(struct ldb_message *msg,
+ const char *attr_name, const char *str);
+int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
+ struct ldb_dn *dn);
+int ldb_msg_add_fmt(struct ldb_message *msg,
+ const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+/**
+ append a element to a ldb_message
+*/
+int ldb_msg_append_value(struct ldb_message *msg,
+ const char *attr_name,
+ const struct ldb_val *val,
+ int flags);
+int ldb_msg_append_steal_value(struct ldb_message *msg,
+ const char *attr_name,
+ struct ldb_val *val,
+ int flags);
+int ldb_msg_append_steal_string(struct ldb_message *msg,
+ const char *attr_name, char *str,
+ int flags);
+int ldb_msg_append_string(struct ldb_message *msg,
+ const char *attr_name, const char *str,
+ int flags);
+int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
+ struct ldb_dn *dn, int flags);
+int ldb_msg_append_fmt(struct ldb_message *msg, int flags,
+ const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(4,5);
+
+/**
+ compare two message elements - return 0 on match
+*/
+int ldb_msg_element_compare(struct ldb_message_element *el1,
+ struct ldb_message_element *el2);
+int ldb_msg_element_compare_name(struct ldb_message_element *el1,
+ struct ldb_message_element *el2);
+
+/**
+ Find elements in a message.
+
+ This function finds elements and converts to a specific type, with
+ a given default value if not found. Assumes that elements are
+ single valued.
+*/
+const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name);
+int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value);
+unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
+ const char *attr_name,
+ unsigned int default_value);
+int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
+ const char *attr_name,
+ int64_t default_value);
+uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
+ const char *attr_name,
+ uint64_t default_value);
+double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
+ const char *attr_name,
+ double default_value);
+int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
+ const char *attr_name,
+ int default_value);
+const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
+ const char *attr_name,
+ const char *default_value);
+
+struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg,
+ const char *attr_name);
+
+void ldb_msg_sort_elements(struct ldb_message *msg);
+
+struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg);
+struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg);
+
+/*
+ * ldb_msg_canonicalize() is now deprecated
+ * Please use ldb_msg_normalize() instead
+ *
+ * NOTE: Returned ldb_message object is allocated
+ * into *ldb's context. Callers are recommended
+ * to steal the returned object into a TALLOC_CTX
+ * with short lifetime.
+ */
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
+ const struct ldb_message *msg) _DEPRECATED_;
+
+int ldb_msg_normalize(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg,
+ struct ldb_message **_msg_out);
+
+
+/*
+ * ldb_msg_diff() is now deprecated
+ * Please use ldb_msg_difference() instead
+ *
+ * NOTE: Returned ldb_message object is allocated
+ * into *ldb's context. Callers are recommended
+ * to steal the returned object into a TALLOC_CTX
+ * with short lifetime.
+ */
+struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2) _DEPRECATED_;
+
+/**
+ * return a ldb_message representing the differences between msg1 and msg2.
+ * If you then use this in a ldb_modify() call,
+ * it can be used to save edits to a message
+ *
+ * Result message is constructed as follows:
+ * - LDB_FLAG_MOD_ADD - elements found only in msg2
+ * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have
+ * different value in msg1
+ * Value for msg2 element is used
+ * - LDB_FLAG_MOD_DELETE - elements found only in msg2
+ *
+ * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
+ */
+int ldb_msg_difference(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2,
+ struct ldb_message **_msg_out);
+
+/**
+ Tries to find a certain string attribute in a message
+
+ \param msg the message to check
+ \param name attribute name
+ \param value attribute value
+
+ \return 1 on match and 0 otherwise.
+*/
+int ldb_msg_check_string_attribute(const struct ldb_message *msg,
+ const char *name,
+ const char *value);
+
+/**
+ Integrity check an ldb_message
+
+ This function performs basic sanity / integrity checks on an
+ ldb_message.
+
+ \param ldb context in which to perform the checks
+ \param msg the message to check
+
+ \return LDB_SUCCESS if the message is OK, or a non-zero error code
+ (one of LDB_ERR_INVALID_DN_SYNTAX, LDB_ERR_ENTRY_ALREADY_EXISTS or
+ LDB_ERR_INVALID_ATTRIBUTE_SYNTAX) if there is a problem with a
+ message.
+*/
+int ldb_msg_sanity_check(struct ldb_context *ldb,
+ const struct ldb_message *msg);
+
+/**
+ Duplicate an ldb_val structure
+
+ This function copies an ldb value structure.
+
+ \param mem_ctx the memory context that the duplicated value will be
+ allocated from
+ \param v the ldb_val to be duplicated.
+
+ \return the duplicated ldb_val structure.
+*/
+struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v);
+
+/**
+ this allows the user to set a debug function for error reporting
+*/
+int ldb_set_debug(struct ldb_context *ldb,
+ void (*debug)(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0),
+ void *context);
+
+/**
+ this allows the user to set custom utf8 function for error reporting. make
+ sure it is able to handle ASCII first, so it prevents issues with dotted
+ languages.
+*/
+void ldb_set_utf8_fns(struct ldb_context *ldb,
+ void *context,
+ char *(*casefold)(void *, void *, const char *, size_t n));
+
+/**
+ this sets up debug to print messages on stderr
+*/
+int ldb_set_debug_stderr(struct ldb_context *ldb);
+
+/* control backend specific opaque values */
+int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value);
+void *ldb_get_opaque(struct ldb_context *ldb, const char *name);
+
+const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs);
+const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr);
+int ldb_attr_in_list(const char * const *attrs, const char *attr);
+
+int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace);
+int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace);
+void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr);
+void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el);
+
+
+void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
+ const char *attr,
+ const char *replace);
+
+/*
+ shallow copy a tree - copying only the elements array so that the caller
+ can safely add new elements without changing the message
+*/
+struct ldb_parse_tree *ldb_parse_tree_copy_shallow(TALLOC_CTX *mem_ctx,
+ const struct ldb_parse_tree *ot);
+
+/**
+ Convert a time structure to a string
+
+ This function converts a time_t structure to an LDAP formatted
+ GeneralizedTime string.
+
+ \param mem_ctx the memory context to allocate the return string in
+ \param t the time structure to convert
+
+ \return the formatted string, or NULL if the time structure could
+ not be converted
+*/
+char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t);
+
+/**
+ Convert a string to a time structure
+
+ This function converts an LDAP formatted GeneralizedTime string
+ to a time_t structure.
+
+ \param s the string to convert
+
+ \return the time structure, or 0 if the string cannot be converted
+*/
+time_t ldb_string_to_time(const char *s);
+
+/**
+ convert a LDAP GeneralizedTime string in ldb_val format to a
+ time_t.
+*/
+int ldb_val_to_time(const struct ldb_val *v, time_t *t);
+
+/**
+ Convert a time structure to a string
+
+ This function converts a time_t structure to an LDAP formatted
+ UTCTime string.
+
+ \param mem_ctx the memory context to allocate the return string in
+ \param t the time structure to convert
+
+ \return the formatted string, or NULL if the time structure could
+ not be converted
+*/
+char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t);
+
+/**
+ Convert a string to a time structure
+
+ This function converts an LDAP formatted UTCTime string
+ to a time_t structure.
+
+ \param s the string to convert
+
+ \return the time structure, or 0 if the string cannot be converted
+*/
+time_t ldb_string_utc_to_time(const char *s);
+
+
+void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque, ldb_qsort_cmp_fn_t cmp);
+
+#ifndef discard_const
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+#endif
+
+/*
+ a wrapper around ldb_qsort() that ensures the comparison function is
+ type safe. This will produce a compilation warning if the types
+ don't match
+ */
+#define LDB_TYPESAFE_QSORT(base, numel, opaque, comparison) \
+do { \
+ if (numel > 1) { \
+ ldb_qsort(base, numel, sizeof((base)[0]), discard_const(opaque), (ldb_qsort_cmp_fn_t)comparison); \
+ if (0) { \
+ comparison(&((base)[0]), &((base)[1]), opaque); \
+ } \
+ } \
+} while (0)
+
+/* allow ldb to also call TYPESAFE_QSORT() */
+#ifndef TYPESAFE_QSORT
+#define TYPESAFE_QSORT(base, numel, comparison) \
+do { \
+ if (numel > 1) { \
+ qsort(base, numel, sizeof((base)[0]), (int (*)(const void *, const void *))comparison); \
+ if (0) { \
+ comparison(&((base)[0]), &((base)[1])); \
+ } \
+ } \
+} while (0)
+#endif
+
+
+
+/**
+ Convert a control into its string representation.
+
+ \param mem_ctx TALLOC context to return result on, and to allocate error_string on
+ \param control A struct ldb_control to convert
+
+ \return string representation of the control
+*/
+char* ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *control);
+/**
+ Convert a string representing a control into a ldb_control structure
+
+ \param ldb LDB context
+ \param mem_ctx TALLOC context to return result on, and to allocate error_string on
+ \param control_strings A string-formatted control
+
+ \return a ldb_control element
+*/
+struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *control_strings);
+/**
+ Convert an array of string representation of a control into an array of ldb_control structures
+
+ \param ldb LDB context
+ \param mem_ctx TALLOC context to return result on, and to allocate error_string on
+ \param control_strings Array of string-formatted controls
+
+ \return array of ldb_control elements
+*/
+struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char **control_strings);
+
+/**
+ return the ldb flags
+*/
+unsigned int ldb_get_flags(struct ldb_context *ldb);
+
+/* set the ldb flags */
+void ldb_set_flags(struct ldb_context *ldb, unsigned flags);
+
+
+struct ldb_dn *ldb_dn_binary_from_ldb_val(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ const struct ldb_val *strdn);
+
+int ldb_dn_get_binary(struct ldb_dn *dn, struct ldb_val *val);
+int ldb_dn_set_binary(struct ldb_dn *dn, struct ldb_val *val);
+
+/* debugging functions for ldb requests */
+void ldb_req_set_location(struct ldb_request *req, const char *location);
+const char *ldb_req_location(struct ldb_request *req);
+
+/* set the location marker on a request handle - used for debugging */
+#define LDB_REQ_SET_LOCATION(req) ldb_req_set_location(req, __location__)
+
+/*
+ minimise a DN. The caller must pass in a validated DN.
+
+ If the DN has an extended component then only the first extended
+ component is kept, the DN string is stripped.
+
+ The existing dn is modified
+ */
+bool ldb_dn_minimise(struct ldb_dn *dn);
+
+/*
+ compare a ldb_val to a string
+*/
+int ldb_val_string_cmp(const struct ldb_val *v, const char *str);
+
+#endif
diff --git a/lib/ldb/include/ldb_errors.h b/lib/ldb/include/ldb_errors.h
new file mode 100644
index 0000000..b247fbe
--- /dev/null
+++ b/lib/ldb/include/ldb_errors.h
@@ -0,0 +1,312 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb header
+ *
+ * Description: defines error codes following RFC 2251 ldap error codes
+ *
+ * Author: Simo Sorce
+ */
+
+#ifndef _LDB_ERRORS_H_
+
+/*! \cond DOXYGEN_IGNORE */
+#define _LDB_ERRORS_H_ 1
+/*! \endcond */
+
+/**
+ \file ldb_errors.h
+
+ This header provides a set of result codes for LDB function calls.
+
+ Many LDB function calls return an integer value (int). As shown in
+ the function documentation, those return values may indicate
+ whether the function call worked correctly (in which case it
+ returns LDB_SUCCESS) or some problem occurred (in which case some
+ other value will be returned). As a special case,
+ LDB_ERR_COMPARE_FALSE or LDB_ERR_COMPARE_TRUE may be returned,
+ which does not indicate an error.
+
+ \note Not all error codes make sense for LDB, however they are
+ based on the LDAP error codes, and are kept for reference and to
+ avoid overlap.
+
+ \note Some of this documentation is based on information in
+ the OpenLDAP documentation, as developed and maintained by the
+ <a href="http://www.openldap.org/">The OpenLDAP Project</a>.
+ */
+
+/**
+ The function call succeeded.
+
+ If a function returns LDB_SUCCESS, then that function, and the
+ underlying transactions that may have been required, completed
+ successfully.
+*/
+#define LDB_SUCCESS 0
+
+/**
+ The function call failed for some non-specific reason.
+*/
+#define LDB_ERR_OPERATIONS_ERROR 1
+
+/**
+ The function call failed because of a protocol violation.
+*/
+#define LDB_ERR_PROTOCOL_ERROR 2
+
+/**
+ The function call failed because a time limit was exceeded.
+*/
+#define LDB_ERR_TIME_LIMIT_EXCEEDED 3
+
+/**
+ The function call failed because a size limit was exceeded.
+*/
+#define LDB_ERR_SIZE_LIMIT_EXCEEDED 4
+
+/**
+ The function was for value comparison, and the comparison operation
+ returned false.
+
+ \note This is a status value, and doesn't normally indicate an
+ error.
+*/
+#define LDB_ERR_COMPARE_FALSE 5
+
+/**
+ The function was for value comparison, and the comparison operation
+ returned true.
+
+ \note This is a status value, and doesn't normally indicate an
+ error.
+*/
+#define LDB_ERR_COMPARE_TRUE 6
+
+/**
+ The function used an authentication method that is not supported by
+ the database.
+*/
+#define LDB_ERR_AUTH_METHOD_NOT_SUPPORTED 7
+
+/**
+ The function call required a underlying operation that required
+ strong authentication.
+
+ This will normally only occur if you are using LDB with a LDAP
+ backend.
+*/
+#define LDB_ERR_STRONG_AUTH_REQUIRED 8
+
+/* 9 RESERVED */
+
+/**
+ The function resulted in a referral to another server.
+*/
+#define LDB_ERR_REFERRAL 10
+
+/**
+ The function failed because an administrative / policy limit was
+ exceeded.
+*/
+#define LDB_ERR_ADMIN_LIMIT_EXCEEDED 11
+
+/**
+ The function required an extension or capability that the
+ database cannot provide.
+*/
+#define LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION 12
+
+/**
+ The function involved a transaction or database operation that
+ could not be performed without a secure link.
+*/
+#define LDB_ERR_CONFIDENTIALITY_REQUIRED 13
+
+/**
+ This is an intermediate result code for SASL bind operations that
+ have more than one step.
+
+ \note This is a result code that does not normally indicate an
+ error has occurred.
+*/
+#define LDB_ERR_SASL_BIND_IN_PROGRESS 14
+
+/**
+ The function referred to an attribute type that is not present in
+ the entry.
+*/
+#define LDB_ERR_NO_SUCH_ATTRIBUTE 16
+
+/**
+ The function referred to an attribute type that is invalid
+*/
+#define LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE 17
+
+/**
+ The function required a filter type that is not available for the
+ specified attribute.
+*/
+#define LDB_ERR_INAPPROPRIATE_MATCHING 18
+
+/**
+ The function would have violated an attribute constraint.
+*/
+#define LDB_ERR_CONSTRAINT_VIOLATION 19
+
+/**
+ The function involved an attribute type or attribute value that
+ already exists in the entry.
+*/
+#define LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS 20
+
+/**
+ The function used an invalid (incorrect syntax) attribute value.
+*/
+#define LDB_ERR_INVALID_ATTRIBUTE_SYNTAX 21
+
+/* 22-31 unused */
+
+/**
+ The function referred to an object that does not exist in the
+ database.
+*/
+#define LDB_ERR_NO_SUCH_OBJECT 32
+
+/**
+ The function referred to an alias which points to a non-existent
+ object in the database.
+*/
+#define LDB_ERR_ALIAS_PROBLEM 33
+
+/**
+ The function used a DN which was invalid (incorrect syntax).
+*/
+#define LDB_ERR_INVALID_DN_SYNTAX 34
+
+/* 35 RESERVED */
+
+/**
+ The function required dereferencing of an alias, and something went
+ wrong during the dereferencing process.
+*/
+#define LDB_ERR_ALIAS_DEREFERENCING_PROBLEM 36
+
+/* 37-47 unused */
+
+/**
+ The function passed in the wrong authentication method.
+*/
+#define LDB_ERR_INAPPROPRIATE_AUTHENTICATION 48
+
+/**
+ The function passed in or referenced incorrect credentials during
+ authentication.
+*/
+#define LDB_ERR_INVALID_CREDENTIALS 49
+
+/**
+ The function required access permissions that the user does not
+ possess.
+*/
+#define LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS 50
+
+/**
+ The function required a transaction or call that the database could
+ not perform because it is busy.
+*/
+#define LDB_ERR_BUSY 51
+
+/**
+ The function required a transaction or call to a database that is
+ not available.
+*/
+#define LDB_ERR_UNAVAILABLE 52
+
+/**
+ The function required a transaction or call to a database that the
+ database declined to perform.
+*/
+#define LDB_ERR_UNWILLING_TO_PERFORM 53
+
+/**
+ The function failed because it resulted in a loop being detected.
+*/
+#define LDB_ERR_LOOP_DETECT 54
+
+/* 55-63 unused */
+
+/**
+ The function failed because it would have violated a naming rule.
+*/
+#define LDB_ERR_NAMING_VIOLATION 64
+
+/**
+ The function failed because it would have violated the schema.
+*/
+#define LDB_ERR_OBJECT_CLASS_VIOLATION 65
+
+/**
+ The function required an operation that is only allowed on leaf
+ objects, but the object is not a leaf.
+*/
+#define LDB_ERR_NOT_ALLOWED_ON_NON_LEAF 66
+
+/**
+ The function required an operation that cannot be performed on a
+ Relative DN, but the object is a Relative DN.
+*/
+#define LDB_ERR_NOT_ALLOWED_ON_RDN 67
+
+/**
+ The function failed because the entry already exists.
+*/
+#define LDB_ERR_ENTRY_ALREADY_EXISTS 68
+
+/**
+ The function failed because modifications to an object class are
+ not allowable.
+*/
+#define LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED 69
+
+/* 70 RESERVED FOR CLDAP */
+
+/**
+ The function failed because it needed to be applied to multiple
+ databases.
+*/
+#define LDB_ERR_AFFECTS_MULTIPLE_DSAS 71
+
+/* 72-79 unused */
+
+/**
+ The function failed for unknown reasons.
+*/
+#define LDB_ERR_OTHER 80
+
+/* 81-90 RESERVED for APIs */
+
+#endif /* _LDB_ERRORS_H_ */
diff --git a/lib/ldb/include/ldb_handlers.h b/lib/ldb/include/ldb_handlers.h
new file mode 100644
index 0000000..79d8bb6
--- /dev/null
+++ b/lib/ldb/include/ldb_handlers.h
@@ -0,0 +1,45 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb header
+ *
+ * Description: defines attribute handlers
+ *
+ * Author: Simo Sorce
+ */
+#ifndef __LDB_HANDLERS_H__
+#define __LDB_HANDLERS_H__
+
+int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out);
+int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out);
+int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2);
+int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2);
+
+#endif /* __LDB_HANDLERS_H__ */
diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h
new file mode 100644
index 0000000..e3f3d99
--- /dev/null
+++ b/lib/ldb/include/ldb_module.h
@@ -0,0 +1,640 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb module header
+ *
+ * Description: defines ldb modules structures and helpers
+ *
+ */
+
+#ifndef _LDB_MODULE_H_
+#define _LDB_MODULE_H_
+
+#include <ldb.h>
+
+#if defined(_SAMBA_BUILD_) && defined(USING_SYSTEM_LDB)
+
+/*
+ * Versions before 1.2.0 doesn't define these values
+ * so we assume 1.1.29 (which was used in Samba 4.6)
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=12859
+ */
+#ifndef EXPECTED_SYSTEM_LDB_VERSION_MAJOR
+#define EXPECTED_SYSTEM_LDB_VERSION_MAJOR 1
+#endif
+#ifndef EXPECTED_SYSTEM_LDB_VERSION_MINOR
+#define EXPECTED_SYSTEM_LDB_VERSION_MINOR 1
+#endif
+#ifndef EXPECTED_SYSTEM_LDB_VERSION_MINOR
+#define EXPECTED_SYSTEM_LDB_VERSION_MINOR 29
+#endif
+
+/*
+ * Only Samba versions which expect ldb >= 1.4.0
+ * reopen the ldb after each fork().
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=13519
+ */
+#if EXPECTED_SYSTEM_LDB_VERSION_MAJOR > 1
+#define __LDB_FORK_COMPATIBLE__ 1
+#elif EXPECTED_SYSTEM_LDB_VERSION_MINOR > 3
+#define __LDB_FORK_COMPATIBLE__ 1
+#endif
+#ifndef __LDB_FORK_COMPATIBLE__
+#error "Samba < 4.9 is not compatible with this version of ldb due to assumptions around fork() behaviour"
+#endif
+
+#endif /* defined(_SAMBA_BUILD_) && defined(USING_SYSTEM_LDB) */
+
+struct ldb_context;
+struct ldb_module;
+
+/**
+ internal flag bits on message elements. Must be within LDB_FLAG_INTERNAL_MASK
+ */
+#define LDB_FLAG_INTERNAL_DISABLE_VALIDATION 0x10
+
+/* disable any single value checking on this attribute */
+#define LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK 0x20
+
+/* attribute has failed access check and must not be exposed */
+#define LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE 0x40
+
+/* force single value checking on this attribute */
+#define LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK 0x80
+
+/*
+ * ensure that this value is unique on an index
+ * (despite the index not otherwise being configured as UNIQUE).
+ * For example, all words starting with 'a' must be unique, but duplicates of
+ * words starting with b are allowed. This is specifically for Samba's
+ * objectSid index which is unique in the primary domain only.
+ */
+#define LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX 0x100
+
+/*
+ * indicates that this element's values are shared with another element (for
+ * example, in a shallow copy of an ldb_message) and should not be freed
+ */
+#define LDB_FLAG_INTERNAL_SHARED_VALUES 0x200
+
+/*
+ * this attribute has been access checked. Used internally in Samba aclread
+ * module.
+ */
+#define LDB_FLAG_INTERNAL_ACCESS_CHECKED 0x400
+
+/* an extended match rule that always fails to match */
+#define SAMBA_LDAP_MATCH_ALWAYS_FALSE "1.3.6.1.4.1.7165.4.5.1"
+
+/* The const char * const * pointer to a list of secret (password)
+ * attributes, not to be printed in trace messages */
+#define LDB_SECRET_ATTRIBUTE_LIST_OPAQUE "LDB_SECRET_ATTRIBUTE_LIST"
+
+/*
+ * The scheme to be used for referral entries, i.e. ldap or ldaps
+ */
+#define LDAP_REFERRAL_SCHEME_OPAQUE "LDAP_REFERRAL_SCHEME"
+
+/*
+ these function pointers define the operations that a ldb module can intercept
+*/
+struct ldb_module_ops {
+ const char *name;
+ int (*init_context) (struct ldb_module *);
+ int (*search)(struct ldb_module *, struct ldb_request *); /* search */
+ int (*add)(struct ldb_module *, struct ldb_request *); /* add */
+ int (*modify)(struct ldb_module *, struct ldb_request *); /* modify */
+ int (*del)(struct ldb_module *, struct ldb_request *); /* delete */
+ int (*rename)(struct ldb_module *, struct ldb_request *); /* rename */
+ int (*request)(struct ldb_module *, struct ldb_request *); /* match any other operation */
+ int (*extended)(struct ldb_module *, struct ldb_request *); /* extended operations */
+ int (*start_transaction)(struct ldb_module *);
+ int (*prepare_commit)(struct ldb_module *);
+ int (*end_transaction)(struct ldb_module *);
+ int (*del_transaction)(struct ldb_module *);
+ int (*sequence_number)(struct ldb_module *, struct ldb_request *);
+ int (*read_lock)(struct ldb_module *);
+ int (*read_unlock)(struct ldb_module *);
+ void *private_data;
+};
+
+
+/* The following definitions come from lib/ldb/common/ldb_debug.c */
+void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+void ldb_debug_add(struct ldb_context *ldb, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+void ldb_debug_end(struct ldb_context *ldb, enum ldb_debug_level level);
+void ldb_vdebug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3, 0);
+
+#define ldb_error(ldb, ecode, reason) ldb_error_at(ldb, ecode, reason, __FILE__, __LINE__)
+#define ldb_module_error(module, ecode, reason) ldb_error_at(ldb_module_get_ctx(module), ecode, reason, __FILE__, __LINE__)
+
+#define ldb_oom(ldb) ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "ldb out of memory")
+#define ldb_module_oom(module) ldb_oom(ldb_module_get_ctx(module))
+#define ldb_operr(ldb) ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "operations error")
+#define ldb_module_operr(module) ldb_error(ldb_module_get_ctx(module), LDB_ERR_OPERATIONS_ERROR, "operations error")
+
+/* The following definitions come from lib/ldb/common/ldb.c */
+
+void ldb_request_set_state(struct ldb_request *req, int state);
+int ldb_request_get_status(struct ldb_request *req);
+
+unsigned int ldb_get_create_perms(struct ldb_context *ldb);
+
+const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
+ const char *syntax);
+
+/* The following definitions come from lib/ldb/common/ldb_attributes.c */
+
+int ldb_schema_attribute_add_with_syntax(struct ldb_context *ldb,
+ const char *name,
+ unsigned flags,
+ const struct ldb_schema_syntax *syntax);
+int ldb_schema_attribute_add(struct ldb_context *ldb,
+ const char *name,
+ unsigned flags,
+ const char *syntax);
+void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name);
+
+/* we allow external code to override the name -> schema_attribute function */
+typedef const struct ldb_schema_attribute *(*ldb_attribute_handler_override_fn_t)(struct ldb_context *, void *, const char *);
+
+/**
+ Allow the caller to define a callback for the attribute handler
+
+ \param ldb The ldb context
+ \param override The callback to be used for attribute lookups
+ \param private_data Private data for the callback
+
+*/
+void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
+ ldb_attribute_handler_override_fn_t override,
+ void *private_data);
+
+/**
+ Allow the caller to define that the callback for the attribute handler
+ also overrides the index list
+
+ \param ldb The ldb context
+ \param one_level_indexes Indicates that the index for SCOPE_ONELEVEL
+ should also be maintained
+
+*/
+void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
+ bool one_level_indexes);
+
+/**
+
+ \param ldb The ldb context
+ \param GUID_index_attribute The globally attribute (eg objectGUID)
+ on each entry
+ \param GUID_index_attribute The DN component matching the
+ globally attribute on each entry (eg GUID)
+
+ The caller must ensure the supplied strings do not go out of
+ scope (they are typically constant memory).
+
+*/
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+ const char *GUID_index_attribute,
+ const char *GUID_index_dn_component);
+
+/* A useful function to build comparison functions with */
+int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
+ ldb_attr_handler_t canonicalise_fn,
+ const struct ldb_val *v1,
+ const struct ldb_val *v2);
+
+/* The following definitions come from lib/ldb/common/ldb_controls.c */
+int ldb_save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver);
+/* Returns a list of controls, except the one specified. Included
+ * controls become a child of returned list if they were children of
+ * controls_in */
+struct ldb_control **ldb_controls_except_specified(struct ldb_control **controls_in,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_control *exclude);
+int ldb_check_critical_controls(struct ldb_control **controls);
+
+/* The following definitions come from lib/ldb/common/ldb_ldif.c */
+int ldb_should_b64_encode(struct ldb_context *ldb, const struct ldb_val *val);
+
+/* The following definitions come from lib/ldb/common/ldb_match.c */
+int ldb_match_msg(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ struct ldb_dn *base,
+ enum ldb_scope scope);
+
+int ldb_match_msg_error(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ struct ldb_dn *base,
+ enum ldb_scope scope,
+ bool *matched);
+
+int ldb_match_msg_objectclass(const struct ldb_message *msg,
+ const char *objectclass);
+
+int ldb_register_extended_match_rules(struct ldb_context *ldb);
+
+/* The following definitions come from lib/ldb/common/ldb_modules.c */
+
+struct ldb_module *ldb_module_new(TALLOC_CTX *memctx,
+ struct ldb_context *ldb,
+ const char *module_name,
+ const struct ldb_module_ops *ops);
+
+const char * ldb_module_get_name(struct ldb_module *module);
+struct ldb_context *ldb_module_get_ctx(struct ldb_module *module);
+void *ldb_module_get_private(struct ldb_module *module);
+void ldb_module_set_private(struct ldb_module *module, void *private_data);
+const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module);
+
+int ldb_next_request(struct ldb_module *module, struct ldb_request *request);
+int ldb_next_start_trans(struct ldb_module *module);
+int ldb_next_end_trans(struct ldb_module *module);
+int ldb_next_del_trans(struct ldb_module *module);
+int ldb_next_prepare_commit(struct ldb_module *module);
+int ldb_next_init(struct ldb_module *module);
+int ldb_next_read_lock(struct ldb_module *module);
+int ldb_next_read_unlock(struct ldb_module *module);
+
+void ldb_set_errstring(struct ldb_context *ldb, const char *err_string);
+void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+void ldb_reset_err_string(struct ldb_context *ldb);
+int ldb_error_at(struct ldb_context *ldb, int ecode, const char *reason, const char *file, int line);
+
+const char *ldb_default_modules_dir(void);
+
+int ldb_register_module(const struct ldb_module_ops *);
+
+typedef int (*ldb_connect_fn)(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[],
+ struct ldb_module **module);
+
+/**
+ Require that LDB use a private event context for each request
+
+ A private event context may need to be created to avoid nested event
+ loops during ldb_tdb with the locks held. This indicates that a
+ backend is in use that requires this to hold locks safely.
+
+ \param handle The ldb handle to set the flag on
+ */
+void ldb_set_require_private_event_context(struct ldb_context *ldb);
+
+struct ldb_backend_ops {
+ const char *name;
+ ldb_connect_fn connect_fn;
+};
+
+const char *ldb_default_modules_dir(void);
+
+int ldb_register_backend(const char *url_prefix, ldb_connect_fn, bool);
+
+struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb);
+
+/**
+ Obtains the private event context for the handle,
+
+ A private event context may have been created to avoid nested event
+ loops during ldb_tdb with the locks held. Otherwise return the
+ global one.
+
+ \param handle The ldb handle to obtain the event context for
+ \return the tevent event context for this handle (private or global)
+ */
+struct tevent_context *ldb_handle_get_event_context(struct ldb_handle *handle);
+
+int ldb_module_send_entry(struct ldb_request *req,
+ struct ldb_message *msg,
+ struct ldb_control **ctrls);
+
+int ldb_module_send_referral(struct ldb_request *req,
+ char *ref);
+
+int ldb_module_done(struct ldb_request *req,
+ struct ldb_control **ctrls,
+ struct ldb_extended *response,
+ int error);
+
+int ldb_mod_register_control(struct ldb_module *module, const char *oid);
+
+void ldb_set_default_dns(struct ldb_context *ldb);
+/**
+ Add a ldb_control to a ldb_reply
+
+ \param ares the reply struct where to add the control
+ \param oid the object identifier of the control as string
+ \param critical whether the control should be critical or not
+ \param data a talloc pointer to the control specific data
+
+ \return result code (LDB_SUCCESS on success, or a failure code)
+*/
+int ldb_reply_add_control(struct ldb_reply *ares, const char *oid, bool critical, void *data);
+
+/**
+ mark a request as untrusted.
+
+ This tells the rootdse module to remove unregistered controls
+
+ \param req the request to mark as untrusted
+*/
+void ldb_req_mark_untrusted(struct ldb_request *req);
+
+/**
+ mark a request as trusted.
+
+ This tells the rootdse module to allow unregistered controls
+
+ \param req the request to mark as trusted
+*/
+void ldb_req_mark_trusted(struct ldb_request *req);
+
+/**
+ return true is a request is untrusted
+
+ This indicates the request came across a trust boundary
+ for example over LDAP
+
+ \param req the request check
+ \return is req trusted
+*/
+bool ldb_req_is_untrusted(struct ldb_request *req);
+
+/**
+ set custom flags. Those flags are set by applications using ldb,
+ they are application dependent and the same bit can have different
+ meaning in different application.
+ */
+void ldb_req_set_custom_flags(struct ldb_request *req, uint32_t flags);
+
+/**
+ get custom flags. Those flags are set by applications using ldb,
+ they are application dependent and the same bit can have different
+ meaning in different application.
+ */
+uint32_t ldb_req_get_custom_flags(struct ldb_request *req);
+
+/* load all modules from the given directory */
+int ldb_modules_load(const char *modules_path, const char *version);
+
+/* init functions prototype */
+typedef int (*ldb_module_init_fn)(const char *);
+
+/*
+ general ldb hook function
+ */
+enum ldb_module_hook_type { LDB_MODULE_HOOK_CMDLINE_OPTIONS = 1,
+ LDB_MODULE_HOOK_CMDLINE_PRECONNECT = 2,
+ LDB_MODULE_HOOK_CMDLINE_POSTCONNECT = 3 };
+
+typedef int (*ldb_hook_fn)(struct ldb_context *, enum ldb_module_hook_type );
+
+/*
+ register a ldb hook function
+ */
+int ldb_register_hook(ldb_hook_fn hook_fn);
+
+/*
+ call ldb hooks of a given type
+ */
+int ldb_modules_hook(struct ldb_context *ldb, enum ldb_module_hook_type t);
+
+#define LDB_MODULE_CHECK_VERSION(version) do { \
+ if (strcmp(version, LDB_VERSION) != 0) { \
+ fprintf(stderr, "ldb: module version mismatch in %s : ldb_version=%s module_version=%s\n", \
+ __FILE__, version, LDB_VERSION); \
+ return LDB_ERR_UNAVAILABLE; \
+ }} while (0)
+
+
+/*
+ return a string representation of the calling chain for the given
+ ldb request
+ */
+char *ldb_module_call_chain(struct ldb_request *req, TALLOC_CTX *mem_ctx);
+
+/*
+ return the next module in the chain
+ */
+struct ldb_module *ldb_module_next(struct ldb_module *module);
+
+/*
+ set the next module in the module chain
+ */
+void ldb_module_set_next(struct ldb_module *module, struct ldb_module *next);
+
+/*
+ load a list of modules
+ */
+int ldb_module_load_list(struct ldb_context *ldb, const char **module_list,
+ struct ldb_module *backend, struct ldb_module **out);
+
+/*
+ get the popt_options pointer in the ldb structure. This allows a ldb
+ module to change the command line parsing
+ */
+struct poptOption **ldb_module_popt_options(struct ldb_context *ldb);
+
+/* modules are called in inverse order on the stack.
+ Lets place them as an admin would think the right order is.
+ Modules order is important */
+const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string);
+
+/*
+ return the current ldb flags LDB_FLG_*
+ */
+uint32_t ldb_module_flags(struct ldb_context *ldb);
+
+int ldb_module_connect_backend(struct ldb_context *ldb,
+ const char *url,
+ const char *options[],
+ struct ldb_module **backend_module);
+
+/*
+ initialise a chain of modules
+ */
+int ldb_module_init_chain(struct ldb_context *ldb, struct ldb_module *module);
+
+/*
+ * prototype for the init function defined by dynamically loaded modules
+ */
+int ldb_init_module(const char *version);
+
+/* replace the components of a DN with those from another DN, without
+ * touching the extended components
+ *
+ * return true if successful and false if not
+ * if false is returned the dn may be marked invalid
+ */
+bool ldb_dn_replace_components(struct ldb_dn *dn, struct ldb_dn *new_dn);
+
+/* Get the attribute (if any) associated with the top node of a parse tree. */
+const char *ldb_parse_tree_get_attr(const struct ldb_parse_tree *tree);
+
+/*
+ walk a parse tree, calling the provided callback on each node
+*/
+int ldb_parse_tree_walk(struct ldb_parse_tree *tree,
+ int (*callback)(struct ldb_parse_tree *tree, void *),
+ void *private_context);
+
+/* compare two message elements with ordering - used by modify */
+bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
+ const struct ldb_message_element *el2);
+
+
+struct ldb_extended_match_rule
+{
+ const char *oid;
+ int (*callback)(struct ldb_context *, const char *oid,
+ const struct ldb_message *, const char *,
+ const struct ldb_val *, bool *);
+};
+
+int ldb_register_extended_match_rule(struct ldb_context *ldb,
+ const struct ldb_extended_match_rule *rule);
+
+void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el);
+bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el);
+void ldb_msg_remove_inaccessible(struct ldb_message *msg);
+
+typedef int (*ldb_redact_fn)(struct ldb_module *, struct ldb_request *, struct ldb_message *);
+int ldb_register_redact_callback(struct ldb_context *ldb,
+ ldb_redact_fn redact_fn,
+ struct ldb_module *module);
+
+/*
+ * these pack/unpack functions are exposed in the library for use by
+ * ldb tools like ldbdump and for use in tests,
+ * but are not part of the public API
+ */
+int ldb_pack_data(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_val *data,
+ uint32_t pack_format_version);
+/*
+ * Unpack a ldb message from a linear buffer in ldb_val
+ */
+int ldb_unpack_data(struct ldb_context *ldb,
+ const struct ldb_val *data,
+ struct ldb_message *message);
+
+/*
+ * filter the specified list of attributes from msg,
+ * adding requested attributes, and perhaps all for *,
+ * but not the DN to filtered_msg.
+ */
+int ldb_filter_attrs(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const char *const *attrs,
+ struct ldb_message *filtered_msg);
+
+/*
+ * filter the specified list of attributes from msg,
+ * adding requested attributes, and perhaps all for *.
+ * Unlike ldb_filter_attrs(), the DN will not be added
+ * if it is missing.
+ */
+int ldb_filter_attrs_in_place(struct ldb_message *msg,
+ const char *const *attrs);
+
+/* Have an unpacked ldb message take talloc ownership of its elements. */
+int ldb_msg_elements_take_ownership(struct ldb_message *msg);
+
+/*
+ * Unpack a ldb message from a linear buffer in ldb_val
+ *
+ * If LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC is specified, then values
+ * array are not allocated individually (for single-valued
+ * attributes), instead they point into a single buffer per message.
+ *
+ * Likewise if LDB_UNPACK_DATA_FLAG_NO_DN is specified, the DN is omitted.
+ *
+ * If LDB_UNPACK_DATA_FLAG_NO_ATTRS is specified, then no attributes
+ * are unpacked or returned.
+ *
+ */
+int ldb_unpack_data_flags(struct ldb_context *ldb,
+ const struct ldb_val *data,
+ struct ldb_message *message,
+ unsigned int flags);
+
+int ldb_unpack_get_format(const struct ldb_val *data,
+ uint32_t *pack_format_version);
+
+/* currently unused (was NO_DATA_ALLOC) 0x0001 */
+#define LDB_UNPACK_DATA_FLAG_NO_DN 0x0002
+#define LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC 0x0004
+#define LDB_UNPACK_DATA_FLAG_NO_ATTRS 0x0008
+#define LDB_UNPACK_DATA_FLAG_READ_LOCKED 0x0010
+
+enum ldb_pack_format {
+
+ /* Old packing format (based on a somewhat arbitrary date) */
+ LDB_PACKING_FORMAT_NODN = 0x26011966,
+
+ /* In-use packing formats */
+ LDB_PACKING_FORMAT,
+ LDB_PACKING_FORMAT_V2
+};
+
+/**
+ Forces a specific ldb handle to use the global event context.
+
+ This allows a nested event loop to operate, so any open
+ transaction also needs to be aborted.
+
+ Any events on this event context will be lost.
+
+ This is used in Samba when sending an IRPC to another part of the
+ same process instead of making a local DB modification.
+
+ \param handle The ldb handle to force to use the global context
+
+ */
+void ldb_handle_use_global_event_context(struct ldb_handle *handle);
+
+/**
+ * Get the options passed to ldb_connect.
+ *
+ * This allows the options to be inspected by elements in the module stack
+ *
+ */
+const char **ldb_options_get(struct ldb_context *ldb);
+
+struct ldb_dn *ldb_val_as_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_val *v);
+int ldb_val_as_int64(const struct ldb_val *v, int64_t *val);
+int ldb_val_as_uint64(const struct ldb_val *v, uint64_t *val);
+int ldb_val_as_bool(const struct ldb_val *v, bool *val);
+
+#endif
diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h
new file mode 100644
index 0000000..a7064f4
--- /dev/null
+++ b/lib/ldb/include/ldb_private.h
@@ -0,0 +1,354 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2004-2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb private header
+ *
+ * Description: defines internal ldb structures used by the subsystem and modules
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ */
+
+#ifndef _LDB_PRIVATE_H_
+#define _LDB_PRIVATE_H_ 1
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb.h"
+#include "ldb_module.h"
+
+struct ldb_context;
+
+struct ldb_module_ops;
+
+struct ldb_backend_ops;
+
+#define LDB_HANDLE_FLAG_DONE_CALLED 1
+/* call is from an untrusted source - eg. over ldap:// */
+#define LDB_HANDLE_FLAG_UNTRUSTED 2
+
+struct ldb_handle {
+ int status;
+ enum ldb_state state;
+ struct ldb_context *ldb;
+ unsigned flags;
+ /* flags dedicated to be set by application using ldb */
+ uint32_t custom_flags;
+ unsigned nesting;
+
+ /* Private event context (if not NULL) */
+ struct tevent_context *event_context;
+
+ /* used for debugging */
+ struct ldb_request *parent;
+ const char *location;
+};
+
+/* basic module structure */
+struct ldb_module {
+ struct ldb_module *prev, *next;
+ struct ldb_context *ldb;
+ void *private_data;
+ const struct ldb_module_ops *ops;
+};
+
+/*
+ schema related information needed for matching rules
+*/
+struct ldb_schema {
+ void *attribute_handler_override_private;
+ ldb_attribute_handler_override_fn_t attribute_handler_override;
+
+ /* attribute handling table */
+ unsigned num_attributes;
+ struct ldb_schema_attribute *attributes;
+
+ unsigned num_dn_extended_syntax;
+ struct ldb_dn_extended_syntax *dn_extended_syntax;
+
+ /*
+ * If set, the attribute_handler_override has the details of
+ * what attributes have an index
+ */
+ bool index_handler_override;
+ bool one_level_indexes;
+
+ const char *GUID_index_attribute;
+ const char *GUID_index_dn_component;
+};
+
+/*
+ every ldb connection is started by establishing a ldb_context
+*/
+struct ldb_context {
+ /* the operations provided by the backend */
+ struct ldb_module *modules;
+
+ /* debugging operations */
+ struct ldb_debug_ops debug_ops;
+
+ /* extended matching rules */
+ struct ldb_extended_match_entry {
+ const struct ldb_extended_match_rule *rule;
+ struct ldb_extended_match_entry *prev, *next;
+ } *extended_match_rules;
+
+ struct {
+ struct ldb_module *module;
+ ldb_redact_fn callback;
+ } redact;
+
+ /* custom utf8 functions */
+ struct ldb_utf8_fns utf8_fns;
+
+ /* backend specific opaque parameters */
+ struct ldb_opaque {
+ struct ldb_opaque *next;
+ const char *name;
+ void *value;
+ } *opaque;
+
+ struct ldb_schema schema;
+
+ char *err_string;
+
+ int transaction_active;
+
+ int default_timeout;
+
+ unsigned int flags;
+
+ unsigned int create_perms;
+
+ struct tevent_context *ev_ctx;
+
+ /*
+ * If the backend holds locks, we must not use a global event
+ * context, so this flag will be set and ldb_handle_new() will
+ * build a new event context
+ */
+ bool require_private_event_context;
+
+ bool prepare_commit_done;
+
+ char *partial_debug;
+
+ struct poptOption *popt_options;
+
+ /*
+ * The ldb options passed to ldb_connect
+ * A NULL terminated array of zero terminated strings
+ */
+ const char **options;
+};
+
+/* The following definitions come from lib/ldb/common/ldb.c */
+
+extern const struct ldb_module_ops ldb_objectclass_module_ops;
+extern const struct ldb_module_ops ldb_paged_results_module_ops;
+extern const struct ldb_module_ops ldb_rdn_name_module_ops;
+extern const struct ldb_module_ops ldb_schema_module_ops;
+extern const struct ldb_module_ops ldb_asq_module_ops;
+extern const struct ldb_module_ops ldb_server_sort_module_ops;
+extern const struct ldb_module_ops ldb_ldap_module_ops;
+extern const struct ldb_module_ops ldb_ildap_module_ops;
+extern const struct ldb_module_ops ldb_paged_searches_module_ops;
+extern const struct ldb_module_ops ldb_tdb_module_ops;
+extern const struct ldb_module_ops ldb_skel_module_ops;
+extern const struct ldb_module_ops ldb_subtree_rename_module_ops;
+extern const struct ldb_module_ops ldb_subtree_delete_module_ops;
+extern const struct ldb_module_ops ldb_sqlite3_module_ops;
+extern const struct ldb_module_ops ldb_wins_ldb_module_ops;
+extern const struct ldb_module_ops ldb_ranged_results_module_ops;
+
+extern const struct ldb_backend_ops ldb_tdb_backend_ops;
+extern const struct ldb_backend_ops ldb_sqlite3_backend_ops;
+extern const struct ldb_backend_ops ldb_ldap_backend_ops;
+extern const struct ldb_backend_ops ldb_ldapi_backend_ops;
+extern const struct ldb_backend_ops ldb_ldaps_backend_ops;
+
+int ldb_setup_wellknown_attributes(struct ldb_context *ldb);
+/*
+ remove attributes with a specified flag (eg LDB_ATTR_FLAG_FROM_DB) for this ldb context
+
+ This is to permit correct reloads
+*/
+void ldb_schema_attribute_remove_flagged(struct ldb_context *ldb, unsigned int flag);
+int ldb_schema_attribute_fill_with_syntax(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *attribute,
+ unsigned flags,
+ const struct ldb_schema_syntax *syntax,
+ struct ldb_schema_attribute *a);
+
+const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname);
+void ldb_subclass_remove(struct ldb_context *ldb, const char *classname);
+int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass);
+
+/* The following definitions come from lib/ldb/common/ldb_utf8.c */
+char *ldb_casefold_default(void *context, TALLOC_CTX *mem_ctx, const char *s, size_t n);
+
+void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f);
+
+
+/* The following definitions come from lib/ldb/common/ldb_modules.c */
+
+const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string);
+int ldb_load_modules(struct ldb_context *ldb, const char *options[]);
+
+struct ldb_val ldb_binary_decode(TALLOC_CTX *mem_ctx, const char *str);
+
+
+/* The following definitions come from lib/ldb/common/ldb_options.c */
+
+const char *ldb_options_find(struct ldb_context *ldb, const char *options[],
+ const char *option_name);
+const char **ldb_options_copy(TALLOC_CTX *ctx, const char *options[]);
+
+/* The following definitions come from lib/ldb/common/ldb_ldif.c */
+
+struct ldif_read_file_state {
+ FILE *f;
+ size_t line_no;
+};
+
+struct ldb_ldif *ldb_ldif_read_file_state(struct ldb_context *ldb,
+ struct ldif_read_file_state *state);
+
+char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ const struct ldb_ldif *ldif);
+
+/*
+ * Get the LDB context in use on an LDB DN.
+ *
+ * This is helpful to the python LDB code, which may use as part of
+ * adding base and child components to an existing DN.
+ */
+struct ldb_context *ldb_dn_get_ldb_context(struct ldb_dn *dn);
+
+#define LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES 1
+
+/**
+ Determine whether any values in an element are also in another element,
+ and optionally fix that.
+
+ \param ldb an ldb context
+ \param mem_ctx a talloc context
+ \param el an element
+ \param other_el another element
+ \param options flags controlling the function behaviour
+
+ Without the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, return
+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS if the elements share values, and
+ LDB_SUCCESS if they don't. That is, determine whether there is an
+ intersection without changing anything.
+
+ With the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, any values in common
+ are removed from the first element and LDB_SUCCESS is returned.
+
+ LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown option.
+ LDB_ERR_INAPPROPRIATE_MATCHING means the elements differ in name.
+*/
+
+int ldb_msg_find_common_values(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message_element *el,
+ struct ldb_message_element *other_el,
+ uint32_t options);
+
+/**
+ Detect whether an element contains duplicate values
+
+ \param ldb a currently unused ldb_context struct
+ \param mem_ctx a talloc context
+ \param el the element to search
+ \param duplicate will point to a duplicate value if there are duplicates,
+ or NULL otherwise.
+ \param options is a flags field. All values are reserved.
+
+ \return an ldb error code. LDB_ERR_OPERATIONS_ERROR indicates an allocation
+ failure or an unknown option flag. Otherwise LDB_SUCCESS.
+
+ \note This search is case sensitive
+*/
+int ldb_msg_find_duplicate_val(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message_element *el,
+ struct ldb_val **duplicate,
+ uint32_t options);
+/**
+ Check if a particular message will match the given filter
+
+ \param ldb an ldb context
+ \param msg the message to be checked
+ \param tree the filter tree to check against
+ \param scope the scope to match against
+ (to avoid matching special DNs except on a base search)
+ \param matched a pointer to a boolean set true if it matches,
+ false otherwise
+
+ returns LDB_SUCCESS or an error
+
+ \note this is a recursive function, and does short-circuit evaluation
+ */
+int ldb_match_message(struct ldb_context *ldb,
+ const struct ldb_message *msg,
+ const struct ldb_parse_tree *tree,
+ enum ldb_scope scope, bool *matched);
+
+/*
+ check if the scope matches in a search result
+*/
+int ldb_match_scope(struct ldb_context *ldb,
+ struct ldb_dn *base,
+ struct ldb_dn *dn,
+ enum ldb_scope scope);
+
+/* Reallocate elements to drop any excess capacity. */
+void ldb_msg_shrink_to_fit(struct ldb_message *msg);
+
+/*
+ add the special distinguishedName element
+*/
+int ldb_msg_add_distinguished_name(struct ldb_message *msg);
+
+/**
+ * @brief Convert a character to uppercase with ASCII precedence.
+ *
+ * This will convert a character to uppercase. If the character is an ASCII
+ * character it will convert it to uppercase ASCII first and then fallback to
+ * localized toupper() from libc.
+ *
+ * @param c The character to convert.
+ *
+ * @return The converted character or c if the conversion was not possible.
+ */
+char ldb_ascii_toupper(char c);
+
+#endif
diff --git a/lib/ldb/ldb.pc.in b/lib/ldb/ldb.pc.in
new file mode 100644
index 0000000..aeba17a
--- /dev/null
+++ b/lib/ldb/ldb.pc.in
@@ -0,0 +1,16 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+modulesdir=@LDB_MODULESDIR@
+
+Name: ldb
+Description: An LDAP-like embedded database
+Version: @PACKAGE_VERSION@
+Requires.private: tdb
+Requires: talloc
+Libs: @LIB_RPATH@ -L${libdir} -lldb
+Libs.private: @LDAP_LIBS@
+Cflags: -I${includedir}
+Modulesdir: ${modulesdir}
+URL: http://ldb.samba.org/
diff --git a/lib/ldb/ldb_key_value/ldb_kv.c b/lib/ldb/ldb_key_value/ldb_kv.c
new file mode 100644
index 0000000..ef69e5e
--- /dev/null
+++ b/lib/ldb/ldb_key_value/ldb_kv.c
@@ -0,0 +1,2291 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2006-2008
+ Copyright (C) Matthias Dieter Wallnöfer 2009-2010
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_kv
+ *
+ * Component: ldb key value backend
+ *
+ * Description: core functions for ldb key value backend
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ *
+ * Modifications:
+ *
+ * - description: make the module use asynchronous calls
+ * date: Feb 2006
+ * Author: Simo Sorce
+ *
+ * - description: make it possible to use event contexts
+ * date: Jan 2008
+ * Author: Simo Sorce
+ *
+ * - description: fix up memory leaks and small bugs
+ * date: Oct 2009
+ * Author: Matthias Dieter Wallnöfer
+ */
+
+#include "ldb_kv.h"
+#include "ldb_private.h"
+#include "lib/util/attr.h"
+
+/*
+ prevent memory errors on callbacks
+*/
+struct ldb_kv_req_spy {
+ struct ldb_kv_context *ctx;
+};
+
+/*
+ * Determine if this key could hold a record. We allow the new GUID
+ * index, the old DN index and a possible future ID=
+ */
+bool ldb_kv_key_is_normal_record(struct ldb_val key)
+{
+ if (key.length < 4) {
+ return false;
+ }
+
+ /*
+ * @ records are not normal records, we don't want to index
+ * them nor search on them
+ */
+ if (key.length > 4 &&
+ memcmp(key.data, "DN=@", 4) == 0) {
+ return false;
+ }
+
+ /* All other DN= records are however */
+ if (memcmp(key.data, "DN=", 3) == 0) {
+ return true;
+ }
+
+ if (memcmp(key.data, "ID=", 3) == 0) {
+ return true;
+ }
+
+ if (key.length < sizeof(LDB_KV_GUID_KEY_PREFIX)) {
+ return false;
+ }
+
+ if (memcmp(key.data, LDB_KV_GUID_KEY_PREFIX,
+ sizeof(LDB_KV_GUID_KEY_PREFIX) - 1) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ form a ldb_val for a record key
+ caller frees
+
+ note that the key for a record can depend on whether the
+ dn refers to a case sensitive index record or not
+*/
+struct ldb_val ldb_kv_key_dn(TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn)
+{
+ struct ldb_val key;
+ char *key_str = NULL;
+ const char *dn_folded = NULL;
+
+ /*
+ most DNs are case insensitive. The exception is index DNs for
+ case sensitive attributes
+
+ there are 3 cases dealt with in this code:
+
+ 1) if the dn doesn't start with @ then uppercase the attribute
+ names and the attributes values of case insensitive attributes
+ 2) if the dn starts with @ then leave it alone -
+ the indexing code handles the rest
+ */
+
+ dn_folded = ldb_dn_get_casefold(dn);
+ if (!dn_folded) {
+ goto failed;
+ }
+
+ key_str = talloc_strdup(mem_ctx, "DN=");
+ if (!key_str) {
+ goto failed;
+ }
+
+ key_str = talloc_strdup_append_buffer(key_str, dn_folded);
+ if (!key_str) {
+ goto failed;
+ }
+
+ key.data = (uint8_t *)key_str;
+ key.length = strlen(key_str) + 1;
+
+ return key;
+
+failed:
+ errno = ENOMEM;
+ key.data = NULL;
+ key.length = 0;
+ return key;
+}
+
+/* The caller is to provide a correctly sized key */
+int ldb_kv_guid_to_key(const struct ldb_val *GUID_val,
+ struct ldb_val *key)
+{
+ const char *GUID_prefix = LDB_KV_GUID_KEY_PREFIX;
+ const int GUID_prefix_len = sizeof(LDB_KV_GUID_KEY_PREFIX) - 1;
+
+ if (key->length != (GUID_val->length+GUID_prefix_len)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ memcpy(key->data, GUID_prefix, GUID_prefix_len);
+ memcpy(&key->data[GUID_prefix_len],
+ GUID_val->data, GUID_val->length);
+ return LDB_SUCCESS;
+}
+
+/*
+ * The caller is to provide a correctly sized key, used only in
+ * the GUID index mode
+ */
+int ldb_kv_idx_to_key(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_val *idx_val,
+ struct ldb_val *key)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_dn *dn;
+
+ if (ldb_kv->cache->GUID_index_attribute != NULL) {
+ return ldb_kv_guid_to_key(idx_val, key);
+ }
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, idx_val);
+ if (dn == NULL) {
+ /*
+ * LDB_ERR_INVALID_DN_SYNTAX would just be confusing
+ * to the caller, as this in an invalid index value
+ */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* form the key */
+ *key = ldb_kv_key_dn(mem_ctx, dn);
+ TALLOC_FREE(dn);
+ if (!key->data) {
+ return ldb_module_oom(module);
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ form a TDB_DATA for a record key
+ caller frees mem_ctx, which may or may not have the key
+ as a child.
+
+ note that the key for a record can depend on whether a
+ GUID index is in use, or the DN is used as the key
+*/
+struct ldb_val ldb_kv_key_msg(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_val key;
+ const struct ldb_val *guid_val;
+ int ret;
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ return ldb_kv_key_dn(mem_ctx, msg->dn);
+ }
+
+ if (ldb_dn_is_special(msg->dn)) {
+ return ldb_kv_key_dn(mem_ctx, msg->dn);
+ }
+
+ guid_val =
+ ldb_msg_find_ldb_val(msg, ldb_kv->cache->GUID_index_attribute);
+ if (guid_val == NULL) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Did not find GUID attribute %s "
+ "in %s, required for TDB record "
+ "key in " LDB_KV_IDXGUID " mode.",
+ ldb_kv->cache->GUID_index_attribute,
+ ldb_dn_get_linearized(msg->dn));
+ errno = EINVAL;
+ key.data = NULL;
+ key.length = 0;
+ return key;
+ }
+
+ /* In this case, allocate with talloc */
+ key.data = talloc_size(mem_ctx, LDB_KV_GUID_KEY_SIZE);
+ if (key.data == NULL) {
+ errno = ENOMEM;
+ key.data = NULL;
+ key.length = 0;
+ return key;
+ }
+ key.length = talloc_get_size(key.data);
+
+ ret = ldb_kv_guid_to_key(guid_val, &key);
+
+ if (ret != LDB_SUCCESS) {
+ errno = EINVAL;
+ key.data = NULL;
+ key.length = 0;
+ return key;
+ }
+ return key;
+}
+
+/*
+ check special dn's have valid attributes
+ currently only @ATTRIBUTES is checked
+*/
+static int ldb_kv_check_special_dn(struct ldb_module *module,
+ const struct ldb_message *msg)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ unsigned int i, j;
+
+ if (! ldb_dn_is_special(msg->dn) ||
+ ! ldb_dn_check_special(msg->dn, LDB_KV_ATTRIBUTES)) {
+ return LDB_SUCCESS;
+ }
+
+ /* we have @ATTRIBUTES, let's check attributes are fine */
+ /* should we check that we deny multivalued attributes ? */
+ for (i = 0; i < msg->num_elements; i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, "distinguishedName") == 0) continue;
+
+ for (j = 0; j < msg->elements[i].num_values; j++) {
+ if (ldb_kv_check_at_attributes_values(
+ &msg->elements[i].values[j]) != 0) {
+ ldb_set_errstring(ldb, "Invalid attribute value in an @ATTRIBUTES entry");
+ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+ }
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ * Called after modifies and when starting a transaction. Checks target pack
+ * format version and current pack format version, which are set by cache_load,
+ * and repacks if necessary.
+ */
+static int ldb_kv_maybe_repack(struct ldb_kv_private *ldb_kv) {
+ /* Override option taken from ldb options */
+ if (ldb_kv->pack_format_override != 0) {
+ ldb_kv->target_pack_format_version =
+ ldb_kv->pack_format_override;
+ }
+
+ if (ldb_kv->pack_format_version !=
+ ldb_kv->target_pack_format_version) {
+ int r;
+ struct ldb_context *ldb = ldb_module_get_ctx(ldb_kv->module);
+ r = ldb_kv_repack(ldb_kv->module);
+ if (r != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Database repack failed.");
+ }
+ return r;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ we've made a modification to a dn - possibly reindex and
+ update sequence number
+*/
+static int ldb_kv_modified(struct ldb_module *module, struct ldb_dn *dn)
+{
+ int ret = LDB_SUCCESS;
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+
+ /* only allow modifies inside a transaction, otherwise the
+ * ldb is unsafe */
+ if (ldb_kv->kv_ops->transaction_active(ldb_kv) == false) {
+ ldb_set_errstring(ldb_module_get_ctx(module), "ltdb modify without transaction");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ldb_dn_is_special(dn) &&
+ (ldb_dn_check_special(dn, LDB_KV_INDEXLIST) ||
+ ldb_dn_check_special(dn, LDB_KV_ATTRIBUTES)) )
+ {
+ if (ldb_kv->warn_reindex) {
+ ldb_debug(ldb_module_get_ctx(module),
+ LDB_DEBUG_ERROR,
+ "Reindexing %s due to modification on %s",
+ ldb_kv->kv_ops->name(ldb_kv),
+ ldb_dn_get_linearized(dn));
+ }
+ ret = ldb_kv_reindex(module);
+ }
+
+ /* If the modify was to a normal record, or any special except @BASEINFO, update the seq number */
+ if (ret == LDB_SUCCESS &&
+ !(ldb_dn_is_special(dn) &&
+ ldb_dn_check_special(dn, LDB_KV_BASEINFO)) ) {
+ ret = ldb_kv_increase_sequence_number(module);
+ }
+
+ /* If the modify was to @OPTIONS, reload the cache */
+ if (ret == LDB_SUCCESS &&
+ ldb_dn_is_special(dn) &&
+ (ldb_dn_check_special(dn, LDB_KV_OPTIONS)) ) {
+ ret = ldb_kv_cache_reload(module);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ ldb_kv->reindex_failed = true;
+ }
+
+ return ret;
+}
+/*
+ store a record into the db
+*/
+int ldb_kv_store(struct ldb_module *module,
+ const struct ldb_message *msg,
+ int flgs)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_val key;
+ struct ldb_val ldb_data;
+ int ret = LDB_SUCCESS;
+ TALLOC_CTX *key_ctx = talloc_new(module);
+
+ if (key_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ if (ldb_kv->read_only) {
+ talloc_free(key_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ key = ldb_kv_key_msg(module, key_ctx, msg);
+ if (key.data == NULL) {
+ TALLOC_FREE(key_ctx);
+ return LDB_ERR_OTHER;
+ }
+
+ ret = ldb_pack_data(ldb_module_get_ctx(module),
+ msg, &ldb_data,
+ ldb_kv->pack_format_version);
+ if (ret == -1) {
+ TALLOC_FREE(key_ctx);
+ return LDB_ERR_OTHER;
+ }
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, ldb_data, flgs);
+ if (ret != 0) {
+ bool is_special = ldb_dn_is_special(msg->dn);
+ ret = ldb_kv->kv_ops->error(ldb_kv);
+
+ /*
+ * LDB_ERR_ENTRY_ALREADY_EXISTS means the DN, not
+ * the GUID, so re-map
+ */
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS && !is_special &&
+ ldb_kv->cache->GUID_index_attribute != NULL) {
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ goto done;
+ }
+
+done:
+ TALLOC_FREE(key_ctx);
+ talloc_free(ldb_data.data);
+
+ return ret;
+}
+
+
+/*
+ check if a attribute is a single valued, for a given element
+ */
+static bool ldb_kv_single_valued(const struct ldb_schema_attribute *a,
+ struct ldb_message_element *el)
+{
+ if (!a) return false;
+ if (el != NULL) {
+ if (el->flags & LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK) {
+ /* override from a ldb module, for example
+ used for the description field, which is
+ marked multi-valued in the schema but which
+ should not actually accept multiple
+ values */
+ return true;
+ }
+ if (el->flags & LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK) {
+ /* override from a ldb module, for example used for
+ deleted linked attribute entries */
+ return false;
+ }
+ }
+ if (a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Starts a sub transaction if they are supported by the backend
+ * and the ldb connection has not been opened in batch mode.
+ */
+static int ldb_kv_sub_transaction_start(struct ldb_kv_private *ldb_kv)
+{
+ int ret = LDB_SUCCESS;
+
+ if (ldb_kv->batch_mode) {
+ return ret;
+ }
+
+ ret = ldb_kv->kv_ops->begin_nested_write(ldb_kv);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_kv_index_sub_transaction_start(ldb_kv);
+ }
+ return ret;
+}
+
+/*
+ * Commits a sub transaction if they are supported by the backend
+ * and the ldb connection has not been opened in batch mode.
+ */
+static int ldb_kv_sub_transaction_commit(struct ldb_kv_private *ldb_kv)
+{
+ int ret = LDB_SUCCESS;
+
+ if (ldb_kv->batch_mode) {
+ return ret;
+ }
+
+ ret = ldb_kv_index_sub_transaction_commit(ldb_kv);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = ldb_kv->kv_ops->finish_nested_write(ldb_kv);
+ return ret;
+}
+
+/*
+ * Cancels a sub transaction if they are supported by the backend
+ * and the ldb connection has not been opened in batch mode.
+ */
+static int ldb_kv_sub_transaction_cancel(struct ldb_kv_private *ldb_kv)
+{
+ int ret = LDB_SUCCESS;
+
+ if (ldb_kv->batch_mode) {
+ return ret;
+ }
+
+ ret = ldb_kv_index_sub_transaction_cancel(ldb_kv);
+ if (ret != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(ldb_kv->module);
+ /*
+ * In the event of a failure we log the failure and continue
+ * as we need to cancel the database transaction.
+ */
+ ldb_debug(ldb,
+ LDB_DEBUG_ERROR,
+ __location__": ldb_kv_index_sub_transaction_cancel "
+ "failed: %s",
+ ldb_errstring(ldb));
+ }
+ ret = ldb_kv->kv_ops->abort_nested_write(ldb_kv);
+ return ret;
+}
+
+static int ldb_kv_add_internal(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ bool check_single_value)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ int ret = LDB_SUCCESS;
+ unsigned int i;
+ bool valid_dn = false;
+
+ /* Check the new DN is reasonable */
+ valid_dn = ldb_dn_validate(msg->dn);
+ if (valid_dn == false) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Invalid DN in ADD: %s",
+ ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
+
+ if (el->num_values == 0) {
+ ldb_asprintf_errstring(ldb, "attribute '%s' on '%s' specified, but with 0 values (illegal)",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ if (check_single_value && el->num_values > 1 &&
+ ldb_kv_single_valued(a, el)) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /* Do not check "@ATTRIBUTES" for duplicated values */
+ if (ldb_dn_is_special(msg->dn) &&
+ ldb_dn_check_special(msg->dn, LDB_KV_ATTRIBUTES)) {
+ continue;
+ }
+
+ if (check_single_value &&
+ !(el->flags &
+ LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) {
+ struct ldb_val *duplicate = NULL;
+
+ ret = ldb_msg_find_duplicate_val(ldb, discard_const(msg),
+ el, &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value '%.*s' on '%s' "
+ "provided more than once in ADD object",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ }
+ }
+
+ ret = ldb_kv_store(module, msg, TDB_INSERT);
+ if (ret != LDB_SUCCESS) {
+ /*
+ * Try really hard to get the right error code for
+ * a re-add situation, as this can matter!
+ */
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ int ret2;
+ struct ldb_dn *dn2 = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(module);
+ if (mem_ctx == NULL) {
+ return ldb_module_operr(module);
+ }
+ ret2 =
+ ldb_kv_search_base(module, mem_ctx, msg->dn, &dn2);
+ TALLOC_FREE(mem_ctx);
+ if (ret2 == LDB_SUCCESS) {
+ ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
+ }
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ ldb_asprintf_errstring(ldb,
+ "Entry %s already exists",
+ ldb_dn_get_linearized(msg->dn));
+ }
+ return ret;
+ }
+
+ ret = ldb_kv_index_add_new(module, ldb_kv, msg);
+ if (ret != LDB_SUCCESS) {
+ /*
+ * If we failed to index, delete the message again.
+ *
+ * This is particularly important for the GUID index
+ * case, which will only fail for a duplicate DN
+ * in the index add.
+ *
+ * Note that the caller may not cancel the transaction
+ * and this means the above add might really show up!
+ */
+ ldb_kv_delete_noindex(module, msg);
+ return ret;
+ }
+
+ ret = ldb_kv_modified(module, msg->dn);
+
+ /*
+ * To allow testing of the error recovery code in ldb_kv_add
+ * cmocka tests can define CMOCKA_UNIT_TEST_ADD_INTERNAL_FAIL
+ * to inject failures at this point.
+ */
+#ifdef CMOCKA_UNIT_TEST_ADD_INTERNAL_FAIL
+ CMOCKA_UNIT_TEST_ADD_INTERNAL_FAIL
+#endif
+
+ return ret;
+}
+
+/*
+ add a record to the database
+*/
+static int ldb_kv_add(struct ldb_kv_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int ret = LDB_SUCCESS;
+
+ if (ldb_kv->max_key_length != 0 &&
+ ldb_kv->cache->GUID_index_attribute == NULL &&
+ !ldb_dn_is_special(req->op.add.message->dn)) {
+ ldb_set_errstring(ldb_module_get_ctx(module),
+ "Must operate ldb_mdb in GUID "
+ "index mode, but " LDB_KV_IDXGUID " not set.");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ ret = ldb_kv_check_special_dn(module, req->op.add.message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ if (ldb_kv_cache_load(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_sub_transaction_start(ldb_kv);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = ldb_kv_add_internal(module, ldb_kv, req->op.add.message, true);
+ if (ret != LDB_SUCCESS) {
+ int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+ if (r != LDB_SUCCESS) {
+ ldb_debug(
+ ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ __location__
+ ": Unable to roll back sub transaction");
+ }
+ ldb_kv->operation_failed = true;
+ return ret;
+ }
+ ret = ldb_kv_sub_transaction_commit(ldb_kv);
+
+ return ret;
+}
+
+/*
+ delete a record from the database, not updating indexes (used for deleting
+ index records)
+*/
+int ldb_kv_delete_noindex(struct ldb_module *module,
+ const struct ldb_message *msg)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_val key;
+ int ret;
+ TALLOC_CTX *tdb_key_ctx = talloc_new(module);
+
+ if (tdb_key_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ if (ldb_kv->read_only) {
+ talloc_free(tdb_key_ctx);
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ key = ldb_kv_key_msg(module, tdb_key_ctx, msg);
+ if (!key.data) {
+ TALLOC_FREE(tdb_key_ctx);
+ return LDB_ERR_OTHER;
+ }
+
+ ret = ldb_kv->kv_ops->delete(ldb_kv, key);
+ TALLOC_FREE(tdb_key_ctx);
+
+ if (ret != 0) {
+ ret = ldb_kv->kv_ops->error(ldb_kv);
+ }
+
+ return ret;
+}
+
+static int ldb_kv_delete_internal(struct ldb_module *module, struct ldb_dn *dn)
+{
+ struct ldb_message *msg;
+ int ret = LDB_SUCCESS;
+
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* in case any attribute of the message was indexed, we need
+ to fetch the old record */
+ ret = ldb_kv_search_dn1(module, dn, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ /* not finding the old record is an error */
+ goto done;
+ }
+
+ ret = ldb_kv_delete_noindex(module, msg);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ /* remove any indexed attributes */
+ ret = ldb_kv_index_delete(module, msg);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ ret = ldb_kv_modified(module, dn);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+done:
+ talloc_free(msg);
+ /*
+ * To allow testing of the error recovery code in ldb_kv_delete
+ * cmocka tests can define CMOCKA_UNIT_TEST_DELETE_INTERNAL_FAIL
+ * to inject failures at this point.
+ */
+#ifdef CMOCKA_UNIT_TEST_DELETE_INTERNAL_FAIL
+ CMOCKA_UNIT_TEST_DELETE_INTERNAL_FAIL
+#endif
+ return ret;
+}
+
+/*
+ delete a record from the database
+*/
+static int ldb_kv_delete(struct ldb_kv_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int ret = LDB_SUCCESS;
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ if (ldb_kv_cache_load(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_sub_transaction_start(ldb_kv);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = ldb_kv_delete_internal(module, req->op.del.dn);
+ if (ret != LDB_SUCCESS) {
+ int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+ if (r != LDB_SUCCESS) {
+ ldb_debug(
+ ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ __location__
+ ": Unable to roll back sub transaction");
+ }
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ ldb_kv->operation_failed = true;
+ }
+ return ret;
+ }
+ ret = ldb_kv_sub_transaction_commit(ldb_kv);
+
+ return ret;
+}
+
+/*
+ find an element by attribute name. At the moment this does a linear search,
+ it should be re-coded to use a binary search once all places that modify
+ records guarantee sorted order
+
+ return the index of the first matching element if found, otherwise -1
+*/
+static int ldb_kv_find_element(const struct ldb_message *msg, const char *name)
+{
+ unsigned int i;
+ for (i=0;i<msg->num_elements;i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ add an element to an existing record. Assumes a elements array that we
+ can call re-alloc on, and assumes that we can reuse the data pointers from
+ the passed in additional values. Use with care!
+
+ returns 0 on success, -1 on failure (and sets errno)
+*/
+static int ldb_kv_msg_add_element(struct ldb_message *msg,
+ struct ldb_message_element *el)
+{
+ struct ldb_message_element *e2;
+ unsigned int i;
+
+ if (el->num_values == 0) {
+ /* nothing to do here - we don't add empty elements */
+ return 0;
+ }
+
+ e2 = talloc_realloc(msg, msg->elements, struct ldb_message_element,
+ msg->num_elements+1);
+ if (!e2) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ msg->elements = e2;
+
+ e2 = &msg->elements[msg->num_elements];
+
+ e2->name = el->name;
+ e2->flags = el->flags;
+ e2->values = talloc_array(msg->elements,
+ struct ldb_val, el->num_values);
+ if (!e2->values) {
+ errno = ENOMEM;
+ return -1;
+ }
+ for (i=0;i<el->num_values;i++) {
+ e2->values[i] = el->values[i];
+ }
+ e2->num_values = el->num_values;
+
+ ++msg->num_elements;
+
+ return 0;
+}
+
+/*
+ delete all elements having a specified attribute name
+*/
+static int ldb_kv_msg_delete_attribute(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ struct ldb_message *msg,
+ const char *name)
+{
+ int ret;
+ struct ldb_message_element *el;
+ bool is_special = ldb_dn_is_special(msg->dn);
+
+ if (!is_special && ldb_kv->cache->GUID_index_attribute != NULL &&
+ ldb_attr_cmp(name, ldb_kv->cache->GUID_index_attribute) == 0) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb,
+ "Must not modify GUID "
+ "attribute %s (used as DB index)",
+ ldb_kv->cache->GUID_index_attribute);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ el = ldb_msg_find_element(msg, name);
+ if (el == NULL) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ ret = ldb_kv_index_del_element(module, ldb_kv, msg, el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ talloc_free(el->values);
+ ldb_msg_remove_element(msg, el);
+ msg->elements = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element,
+ msg->num_elements);
+ return LDB_SUCCESS;
+}
+
+/*
+ delete all elements matching an attribute name/value
+
+ return LDB Error on failure
+*/
+static int ldb_kv_msg_delete_element(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ struct ldb_message *msg,
+ const char *name,
+ const struct ldb_val *val)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ unsigned int i;
+ int found, ret;
+ struct ldb_message_element *el;
+ const struct ldb_schema_attribute *a;
+
+ found = ldb_kv_find_element(msg, name);
+ if (found == -1) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ i = (unsigned int) found;
+ el = &(msg->elements[i]);
+
+ a = ldb_schema_attribute_by_name(ldb, el->name);
+
+ for (i=0;i<el->num_values;i++) {
+ bool matched;
+ if (a->syntax->operator_fn) {
+ ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
+ &el->values[i], val, &matched);
+ if (ret != LDB_SUCCESS) return ret;
+ } else {
+ matched = (a->syntax->comparison_fn(ldb, ldb,
+ &el->values[i], val) == 0);
+ }
+ if (matched) {
+ if (el->num_values == 1) {
+ return ldb_kv_msg_delete_attribute(
+ module, ldb_kv, msg, name);
+ }
+
+ ret =
+ ldb_kv_index_del_value(module, ldb_kv, msg, el, i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ARRAY_DEL_ELEMENT(el->values, i, el->num_values);
+ el->num_values--;
+
+ /* per definition we find in a canonicalised message an
+ attribute value only once. So we are finished here */
+ return LDB_SUCCESS;
+ }
+ }
+
+ /* Not found */
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+}
+
+/*
+ modify a record - internal interface
+
+ yuck - this is O(n^2). Luckily n is usually small so we probably
+ get away with it, but if we ever have really large attribute lists
+ then we'll need to look at this again
+
+ 'req' is optional, and is used to specify controls if supplied
+*/
+int ldb_kv_modify_internal(struct ldb_module *module,
+ const struct ldb_message *msg,
+ struct ldb_request *req)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_message *msg2;
+ unsigned int i, j;
+ int ret = LDB_SUCCESS, idx;
+ struct ldb_control *control_permissive = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(req);
+
+ if (mem_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ if (req) {
+ control_permissive = ldb_request_get_control(req,
+ LDB_CONTROL_PERMISSIVE_MODIFY_OID);
+ }
+
+ msg2 = ldb_msg_new(mem_ctx);
+ if (msg2 == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret = ldb_kv_search_dn1(module, msg->dn, msg2, 0);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ for (i=0; i<msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i], *el2;
+ struct ldb_val *vals;
+ const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
+ const char *dn;
+ uint32_t options = 0;
+ if (control_permissive != NULL) {
+ options |= LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
+ }
+
+ switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+
+ if (el->num_values == 0) {
+ ldb_asprintf_errstring(ldb,
+ "attribute '%s': attribute on '%s' specified, but with 0 values (illegal)",
+ el->name, ldb_dn_get_linearized(msg2->dn));
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+
+ /* make a copy of the array so that a permissive
+ * control can remove duplicates without changing the
+ * original values, but do not copy data as we do not
+ * need to keep it around once the operation is
+ * finished */
+ if (control_permissive) {
+ el = talloc(msg2, struct ldb_message_element);
+ if (!el) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ *el = msg->elements[i];
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ for (j = 0; j < el->num_values; j++) {
+ el->values[j] = msg->elements[i].values[j];
+ }
+ }
+
+ if (el->num_values > 1 && ldb_kv_single_valued(a, el)) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg2->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+
+ /* Checks if element already exists */
+ idx = ldb_kv_find_element(msg2, el->name);
+ if (idx == -1) {
+ if (ldb_kv_msg_add_element(msg2, el) != 0) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ ret = ldb_kv_index_add_element(
+ module, ldb_kv, msg2, el);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ } else {
+ j = (unsigned int) idx;
+ el2 = &(msg2->elements[j]);
+
+ /* We cannot add another value on a existing one
+ if the attribute is single-valued */
+ if (ldb_kv_single_valued(a, el)) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg2->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+
+ /* Check that values don't exist yet on multi-
+ valued attributes or aren't provided twice */
+ if (!(el->flags &
+ LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) {
+ struct ldb_val *duplicate = NULL;
+ ret = ldb_msg_find_common_values(ldb,
+ msg2,
+ el,
+ el2,
+ options);
+
+ if (ret ==
+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+ ldb_asprintf_errstring(ldb,
+ "attribute '%s': value "
+ "#%u on '%s' already "
+ "exists", el->name, j,
+ ldb_dn_get_linearized(msg2->dn));
+ goto done;
+ } else if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ ret = ldb_msg_find_duplicate_val(
+ ldb, msg2, el, &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value "
+ "'%.*s' on '%s' "
+ "provided more than "
+ "once in ADD",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+ }
+
+ /* Now combine existing and new values to a new
+ attribute record */
+ vals = talloc_realloc(msg2->elements,
+ el2->values, struct ldb_val,
+ el2->num_values + el->num_values);
+ if (vals == NULL) {
+ ldb_oom(ldb);
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ for (j=0; j<el->num_values; j++) {
+ vals[el2->num_values + j] =
+ ldb_val_dup(vals, &el->values[j]);
+ }
+
+ el2->values = vals;
+ el2->num_values += el->num_values;
+
+ ret = ldb_kv_index_add_element(
+ module, ldb_kv, msg2, el);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ }
+
+ break;
+
+ case LDB_FLAG_MOD_REPLACE:
+
+ if (el->num_values > 1 && ldb_kv_single_valued(a, el)) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg2->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+
+ /*
+ * We don't need to check this if we have been
+ * pre-screened by the repl_meta_data module
+ * in Samba, or someone else who can claim to
+ * know what they are doing.
+ */
+ if (!(el->flags & LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) {
+ struct ldb_val *duplicate = NULL;
+
+ ret = ldb_msg_find_duplicate_val(ldb, msg2, el,
+ &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value '%.*s' "
+ "on '%s' provided more than "
+ "once in REPLACE",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg2->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+ }
+
+ /* Checks if element already exists */
+ idx = ldb_kv_find_element(msg2, el->name);
+ if (idx != -1) {
+ j = (unsigned int) idx;
+ el2 = &(msg2->elements[j]);
+
+ /* we consider two elements to be
+ * equal only if the order
+ * matches. This allows dbcheck to
+ * fix the ordering on attributes
+ * where order matters, such as
+ * objectClass
+ */
+ if (ldb_msg_element_equal_ordered(el, el2)) {
+ continue;
+ }
+
+ /* Delete the attribute if it exists in the DB */
+ if (ldb_kv_msg_delete_attribute(
+ module, ldb_kv, msg2, el->name) != 0) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+ }
+
+ /* Recreate it with the new values */
+ if (ldb_kv_msg_add_element(msg2, el) != 0) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ret =
+ ldb_kv_index_add_element(module, ldb_kv, msg2, el);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ break;
+
+ case LDB_FLAG_MOD_DELETE:
+ dn = ldb_dn_get_linearized(msg2->dn);
+ if (dn == NULL) {
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ if (msg->elements[i].num_values == 0) {
+ /* Delete the whole attribute */
+ ret = ldb_kv_msg_delete_attribute(
+ module,
+ ldb_kv,
+ msg2,
+ msg->elements[i].name);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ if (control_permissive) {
+ ret = LDB_SUCCESS;
+ } else {
+ ldb_asprintf_errstring(ldb,
+ "attribute '%s': no such attribute for delete on '%s'",
+ msg->elements[i].name, dn);
+ }
+ }
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ } else {
+ /* Delete specified values from an attribute */
+ for (j=0; j < msg->elements[i].num_values; j++) {
+ ret = ldb_kv_msg_delete_element(
+ module,
+ ldb_kv,
+ msg2,
+ msg->elements[i].name,
+ &msg->elements[i].values[j]);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
+ control_permissive) {
+ ret = LDB_SUCCESS;
+ } else if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ ldb_asprintf_errstring(ldb,
+ "attribute '%s': no matching attribute value while deleting attribute on '%s'",
+ msg->elements[i].name, dn);
+ }
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ }
+ }
+ break;
+ default:
+ ldb_asprintf_errstring(ldb,
+ "attribute '%s': invalid modify flags on '%s': 0x%x",
+ msg->elements[i].name, ldb_dn_get_linearized(msg->dn),
+ msg->elements[i].flags & LDB_FLAG_MOD_MASK);
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ goto done;
+ }
+ }
+
+ ret = ldb_kv_store(module, msg2, TDB_MODIFY);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ ret = ldb_kv_modified(module, msg2->dn);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+done:
+ TALLOC_FREE(mem_ctx);
+ /*
+ * To allow testing of the error recovery code in ldb_kv_modify
+ * cmocka tests can define CMOCKA_UNIT_TEST_MODIFY_INTERNAL_FAIL
+ * to inject failures at this point.
+ */
+#ifdef CMOCKA_UNIT_TEST_MODIFY_INTERNAL_FAIL
+ CMOCKA_UNIT_TEST_MODIFY_INTERNAL_FAIL
+#endif
+ return ret;
+}
+
+/*
+ modify a record
+*/
+static int ldb_kv_modify(struct ldb_kv_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int ret = LDB_SUCCESS;
+
+ ret = ldb_kv_check_special_dn(module, req->op.mod.message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ if (ldb_kv_cache_load(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_sub_transaction_start(ldb_kv);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = ldb_kv_modify_internal(module, req->op.mod.message, req);
+ if (ret != LDB_SUCCESS) {
+ int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+ if (r != LDB_SUCCESS) {
+ ldb_debug(
+ ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ __location__
+ ": Unable to roll back sub transaction");
+ }
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ ldb_kv->operation_failed = true;
+ }
+ return ret;
+ }
+ ret = ldb_kv_sub_transaction_commit(ldb_kv);
+
+
+ return ret;
+}
+
+static int ldb_kv_rename_internal(struct ldb_module *module,
+ struct ldb_request *req,
+ struct ldb_message *msg)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int ret = LDB_SUCCESS;
+
+ /* Always delete first then add, to avoid conflicts with
+ * unique indexes. We rely on the transaction to make this
+ * atomic
+ */
+ ret = ldb_kv_delete_internal(module, msg->dn);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
+ if (msg->dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* We don't check single value as we can have more than 1 with
+ * deleted attributes. We could go through all elements but that's
+ * maybe not the most efficient way
+ */
+ ret = ldb_kv_add_internal(module, ldb_kv, msg, false);
+
+ /*
+ * To allow testing of the error recovery code in ldb_kv_rename
+ * cmocka tests can define CMOCKA_UNIT_TEST_RENAME_INTERNAL_FAIL
+ * to inject failures at this point.
+ */
+#ifdef CMOCKA_UNIT_TEST_RENAME_INTERNAL_FAIL
+ CMOCKA_UNIT_TEST_RENAME_INTERNAL_FAIL
+#endif
+ return ret;
+}
+
+/*
+ rename a record
+*/
+static int ldb_kv_rename(struct ldb_kv_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_request *req = ctx->req;
+ struct ldb_message *msg;
+ int ret = LDB_SUCCESS;
+ struct ldb_val key, key_old;
+ struct ldb_dn *db_dn;
+ bool valid_dn = false;
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ if (ldb_kv_cache_load(ctx->module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Check the new DN is reasonable */
+ valid_dn = ldb_dn_validate(req->op.rename.newdn);
+ if (valid_dn == false) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Invalid New DN: %s",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ /* we need to fetch the old record to re-add under the new name */
+ ret = ldb_kv_search_dn1(module, req->op.rename.olddn, msg, 0);
+ if (ret == LDB_ERR_INVALID_DN_SYNTAX) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Invalid Old DN: %s",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ return ret;
+ } else if (ret != LDB_SUCCESS) {
+ /* not finding the old record is an error */
+ return ret;
+ }
+
+ /* We need to, before changing the DB, check if the new DN
+ * exists, so we can return this error to the caller with an
+ * unmodified DB
+ *
+ * Even in GUID index mode we use ltdb_key_dn() as we are
+ * trying to figure out if this is just a case rename
+ */
+ key = ldb_kv_key_dn(msg, req->op.rename.newdn);
+ if (!key.data) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ key_old = ldb_kv_key_dn(msg, req->op.rename.olddn);
+ if (!key_old.data) {
+ talloc_free(msg);
+ talloc_free(key.data);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Only declare a conflict if the new DN already exists,
+ * and it isn't a case change on the old DN
+ */
+ if (key_old.length != key.length
+ || memcmp(key.data, key_old.data, key.length) != 0) {
+ ret = ldb_kv_search_base(
+ module, msg, req->op.rename.newdn, &db_dn);
+ if (ret == LDB_SUCCESS) {
+ ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+ } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ret = LDB_SUCCESS;
+ }
+ }
+
+ /* finding the new record already in the DB is an error */
+
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Entry %s already exists",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(key_old.data);
+ talloc_free(key.data);
+ talloc_free(msg);
+ return ret;
+ }
+
+ talloc_free(key_old.data);
+ talloc_free(key.data);
+
+
+ ret = ldb_kv_sub_transaction_start(ldb_kv);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+ ret = ldb_kv_rename_internal(module, req, msg);
+ if (ret != LDB_SUCCESS) {
+ int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+ if (r != LDB_SUCCESS) {
+ ldb_debug(
+ ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ __location__
+ ": Unable to roll back sub transaction");
+ }
+ talloc_free(msg);
+ ldb_kv->operation_failed = true;
+ return ret;
+ }
+ ret = ldb_kv_sub_transaction_commit(ldb_kv);
+ talloc_free(msg);
+
+ return ret;
+}
+
+static int ldb_kv_start_trans(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(ldb_kv->module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ /* Do not take out the transaction lock on a read-only DB */
+ if (ldb_kv->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ if (ldb_kv->kv_ops->begin_write(ldb_kv) != 0) {
+ return ldb_kv->kv_ops->error(ldb_kv);
+ }
+
+ ldb_kv_index_transaction_start(
+ module,
+ ldb_kv->index_transaction_cache_size);
+
+ ldb_kv->reindex_failed = false;
+ ldb_kv->operation_failed = false;
+
+ return LDB_SUCCESS;
+}
+
+/*
+ * Forward declaration to allow prepare_commit to in fact abort the
+ * transaction
+ */
+static int ldb_kv_del_trans(struct ldb_module *module);
+
+static int ldb_kv_prepare_commit(struct ldb_module *module)
+{
+ int ret;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ if (!ldb_kv->kv_ops->transaction_active(ldb_kv)) {
+ ldb_set_errstring(ldb_module_get_ctx(module),
+ "ltdb_prepare_commit() called "
+ "without transaction active");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Check if the last re-index failed.
+ *
+ * This can happen if for example a duplicate value was marked
+ * unique. We must not write a partial re-index into the DB.
+ */
+ if (ldb_kv->reindex_failed) {
+ /*
+ * We must instead abort the transaction so we get the
+ * old values and old index back
+ */
+ ldb_kv_del_trans(module);
+ ldb_set_errstring(ldb_module_get_ctx(module),
+ "Failure during re-index, so "
+ "transaction must be aborted.");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_index_transaction_commit(module);
+ if (ret != LDB_SUCCESS) {
+ ldb_kv->kv_ops->abort_write(ldb_kv);
+ return ret;
+ }
+
+ /*
+ * If GUID indexing was toggled in this transaction, we repack at
+ * format version 2 if GUID indexing was enabled, or version 1 if
+ * it was disabled.
+ */
+ ret = ldb_kv_maybe_repack(ldb_kv);
+ if (ret != LDB_SUCCESS) {
+ ldb_kv_del_trans(module);
+ ldb_set_errstring(ldb_module_get_ctx(module),
+ "Failure during re-pack, so "
+ "transaction must be aborted.");
+ return ret;
+ }
+
+ if (ldb_kv->kv_ops->prepare_write(ldb_kv) != 0) {
+ ret = ldb_kv->kv_ops->error(ldb_kv);
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ "Failure during "
+ "prepare_write): %s -> %s",
+ ldb_kv->kv_ops->errorstr(ldb_kv),
+ ldb_strerror(ret));
+ return ret;
+ }
+
+ ldb_kv->prepared_commit = true;
+
+ return LDB_SUCCESS;
+}
+
+static int ldb_kv_end_trans(struct ldb_module *module)
+{
+ int ret;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+
+ /*
+ * If in batch mode and there has been an operation failure
+ * rollback the transaction rather than committing it to avoid
+ * any possible corruption
+ */
+ if (ldb_kv->batch_mode && ldb_kv->operation_failed) {
+ ret = ldb_kv_del_trans( module);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ "An operation failed during a batch mode "
+ "transaction. The transaction could not"
+ "be rolled back, ldb_kv_del_trans "
+ "returned (%s, %s)",
+ ldb_kv->kv_ops->errorstr(ldb_kv),
+ ldb_strerror(ret));
+ } else {
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ "An operation failed during a batch mode "
+ "transaction, the transaction was "
+ "rolled back");
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (!ldb_kv->prepared_commit) {
+ ret = ldb_kv_prepare_commit(module);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ ldb_kv->prepared_commit = false;
+
+ if (ldb_kv->kv_ops->finish_write(ldb_kv) != 0) {
+ ret = ldb_kv->kv_ops->error(ldb_kv);
+ ldb_asprintf_errstring(
+ ldb_module_get_ctx(module),
+ "Failure during tdb_transaction_commit(): %s -> %s",
+ ldb_kv->kv_ops->errorstr(ldb_kv),
+ ldb_strerror(ret));
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int ldb_kv_del_trans(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+
+ if (ldb_kv_index_transaction_cancel(module) != 0) {
+ ldb_kv->kv_ops->abort_write(ldb_kv);
+ return ldb_kv->kv_ops->error(ldb_kv);
+ }
+
+ ldb_kv->kv_ops->abort_write(ldb_kv);
+ return LDB_SUCCESS;
+}
+
+/*
+ return sequenceNumber from @BASEINFO
+*/
+static int ldb_kv_sequence_number(struct ldb_kv_context *ctx,
+ struct ldb_extended **ext)
+{
+ struct ldb_context *ldb;
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_seqnum_request *seq;
+ struct ldb_seqnum_result *res;
+ struct ldb_message *msg = NULL;
+ struct ldb_dn *dn;
+ const char *date;
+ int ret = LDB_SUCCESS;
+
+ ldb = ldb_module_get_ctx(module);
+
+ seq = talloc_get_type(req->op.extended.data,
+ struct ldb_seqnum_request);
+ if (seq == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ if (ldb_kv->kv_ops->lock_read(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ res = talloc_zero(req, struct ldb_seqnum_result);
+ if (res == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ tmp_ctx = talloc_new(req);
+ if (tmp_ctx == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, ldb, LDB_KV_BASEINFO);
+ if (dn == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ ret = ldb_kv_search_dn1(module, dn, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ switch (seq->type) {
+ case LDB_SEQ_HIGHEST_SEQ:
+ res->seq_num = ldb_msg_find_attr_as_uint64(msg, LDB_KV_SEQUENCE_NUMBER, 0);
+ break;
+ case LDB_SEQ_NEXT:
+ res->seq_num = ldb_msg_find_attr_as_uint64(msg, LDB_KV_SEQUENCE_NUMBER, 0);
+ res->seq_num++;
+ break;
+ case LDB_SEQ_HIGHEST_TIMESTAMP:
+ date = ldb_msg_find_attr_as_string(msg, LDB_KV_MOD_TIMESTAMP, NULL);
+ if (date) {
+ res->seq_num = ldb_string_to_time(date);
+ } else {
+ res->seq_num = 0;
+ /* zero is as good as anything when we don't know */
+ }
+ break;
+ }
+
+ *ext = talloc_zero(req, struct ldb_extended);
+ if (*ext == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ (*ext)->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
+ (*ext)->data = talloc_steal(*ext, res);
+
+done:
+ talloc_free(tmp_ctx);
+
+ ldb_kv->kv_ops->unlock_read(module);
+ return ret;
+}
+
+static void ldb_kv_request_done(struct ldb_kv_context *ctx, int error)
+{
+ struct ldb_context *ldb;
+ struct ldb_request *req;
+ struct ldb_reply *ares;
+
+ ldb = ldb_module_get_ctx(ctx->module);
+ req = ctx->req;
+
+ /* if we already returned an error just return */
+ if (ldb_request_get_status(req) != LDB_SUCCESS) {
+ return;
+ }
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(ldb);
+ req->callback(req, NULL);
+ return;
+ }
+ ares->type = LDB_REPLY_DONE;
+ ares->error = error;
+
+ req->callback(req, ares);
+}
+
+static void ldb_kv_timeout(_UNUSED_ struct tevent_context *ev,
+ _UNUSED_ struct tevent_timer *te,
+ _UNUSED_ struct timeval t,
+ void *private_data)
+{
+ struct ldb_kv_context *ctx;
+ ctx = talloc_get_type(private_data, struct ldb_kv_context);
+
+ if (!ctx->request_terminated) {
+ /* request is done now */
+ ldb_kv_request_done(ctx, LDB_ERR_TIME_LIMIT_EXCEEDED);
+ }
+
+ if (ctx->spy) {
+ /* neutralize the spy */
+ ctx->spy->ctx = NULL;
+ ctx->spy = NULL;
+ }
+ talloc_free(ctx);
+}
+
+static void ldb_kv_request_extended_done(struct ldb_kv_context *ctx,
+ struct ldb_extended *ext,
+ int error)
+{
+ struct ldb_context *ldb;
+ struct ldb_request *req;
+ struct ldb_reply *ares;
+
+ ldb = ldb_module_get_ctx(ctx->module);
+ req = ctx->req;
+
+ /* if we already returned an error just return */
+ if (ldb_request_get_status(req) != LDB_SUCCESS) {
+ return;
+ }
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(ldb);
+ req->callback(req, NULL);
+ return;
+ }
+ ares->type = LDB_REPLY_DONE;
+ ares->response = ext;
+ ares->error = error;
+
+ req->callback(req, ares);
+}
+
+static void ldb_kv_handle_extended(struct ldb_kv_context *ctx)
+{
+ struct ldb_extended *ext = NULL;
+ int ret;
+
+ if (strcmp(ctx->req->op.extended.oid,
+ LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
+ /* get sequence number */
+ ret = ldb_kv_sequence_number(ctx, &ext);
+ } else {
+ /* not recognized */
+ ret = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
+ ldb_kv_request_extended_done(ctx, ext, ret);
+}
+
+static void ldb_kv_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *private_data)
+{
+ struct ldb_kv_context *ctx;
+ int ret;
+
+ ctx = talloc_get_type(private_data, struct ldb_kv_context);
+
+ if (ctx->request_terminated) {
+ goto done;
+ }
+
+ switch (ctx->req->operation) {
+ case LDB_SEARCH:
+ ret = ldb_kv_search(ctx);
+ break;
+ case LDB_ADD:
+ ret = ldb_kv_add(ctx);
+ break;
+ case LDB_MODIFY:
+ ret = ldb_kv_modify(ctx);
+ break;
+ case LDB_DELETE:
+ ret = ldb_kv_delete(ctx);
+ break;
+ case LDB_RENAME:
+ ret = ldb_kv_rename(ctx);
+ break;
+ case LDB_EXTENDED:
+ ldb_kv_handle_extended(ctx);
+ goto done;
+ default:
+ /* no other op supported */
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ if (!ctx->request_terminated) {
+ /* request is done now */
+ ldb_kv_request_done(ctx, ret);
+ }
+
+done:
+ if (ctx->spy) {
+ /* neutralize the spy */
+ ctx->spy->ctx = NULL;
+ ctx->spy = NULL;
+ }
+ talloc_free(ctx);
+}
+
+static int ldb_kv_request_destructor(void *ptr)
+{
+ struct ldb_kv_req_spy *spy =
+ talloc_get_type(ptr, struct ldb_kv_req_spy);
+
+ if (spy->ctx != NULL) {
+ spy->ctx->spy = NULL;
+ spy->ctx->request_terminated = true;
+ spy->ctx = NULL;
+ }
+
+ return 0;
+}
+
+static int ldb_kv_handle_request(struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct ldb_control *control_permissive;
+ struct ldb_context *ldb;
+ struct tevent_context *ev;
+ struct ldb_kv_context *ac;
+ struct tevent_timer *te;
+ struct timeval tv;
+ unsigned int i;
+
+ ldb = ldb_module_get_ctx(module);
+
+ control_permissive = ldb_request_get_control(req,
+ LDB_CONTROL_PERMISSIVE_MODIFY_OID);
+
+ for (i = 0; req->controls && req->controls[i]; i++) {
+ if (req->controls[i]->critical &&
+ req->controls[i] != control_permissive) {
+ ldb_asprintf_errstring(ldb, "Unsupported critical extension %s",
+ req->controls[i]->oid);
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+ }
+
+ if (req->starttime == 0 || req->timeout == 0) {
+ ldb_set_errstring(ldb, "Invalid timeout settings");
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+
+ ev = ldb_handle_get_event_context(req->handle);
+
+ ac = talloc_zero(ldb, struct ldb_kv_context);
+ if (ac == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ te = tevent_add_timer(ev, ac, tv, ldb_kv_callback, ac);
+ if (NULL == te) {
+ talloc_free(ac);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->timeout > 0) {
+ tv.tv_sec = req->starttime + req->timeout;
+ tv.tv_usec = 0;
+ ac->timeout_event =
+ tevent_add_timer(ev, ac, tv, ldb_kv_timeout, ac);
+ if (NULL == ac->timeout_event) {
+ talloc_free(ac);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ ac->timeout_timeval = tv;
+
+ /* set a spy so that we do not try to use the request context
+ * if it is freed before ltdb_callback fires */
+ ac->spy = talloc(req, struct ldb_kv_req_spy);
+ if (NULL == ac->spy) {
+ talloc_free(ac);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->spy->ctx = ac;
+
+ talloc_set_destructor((TALLOC_CTX *)ac->spy, ldb_kv_request_destructor);
+
+ return LDB_SUCCESS;
+}
+
+static int ldb_kv_init_rootdse(struct ldb_module *module)
+{
+ /* ignore errors on this - we expect it for non-sam databases */
+ ldb_mod_register_control(module, LDB_CONTROL_PERMISSIVE_MODIFY_OID);
+
+ /* there can be no module beyond the backend, just return */
+ return LDB_SUCCESS;
+}
+
+static int ldb_kv_lock_read(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ return ldb_kv->kv_ops->lock_read(module);
+}
+
+static int ldb_kv_unlock_read(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ return ldb_kv->kv_ops->unlock_read(module);
+}
+
+static const struct ldb_module_ops ldb_kv_ops = {
+ .name = "tdb",
+ .init_context = ldb_kv_init_rootdse,
+ .search = ldb_kv_handle_request,
+ .add = ldb_kv_handle_request,
+ .modify = ldb_kv_handle_request,
+ .del = ldb_kv_handle_request,
+ .rename = ldb_kv_handle_request,
+ .extended = ldb_kv_handle_request,
+ .start_transaction = ldb_kv_start_trans,
+ .end_transaction = ldb_kv_end_trans,
+ .prepare_commit = ldb_kv_prepare_commit,
+ .del_transaction = ldb_kv_del_trans,
+ .read_lock = ldb_kv_lock_read,
+ .read_unlock = ldb_kv_unlock_read,
+};
+
+int ldb_kv_init_store(struct ldb_kv_private *ldb_kv,
+ const char *name,
+ struct ldb_context *ldb,
+ const char *options[],
+ struct ldb_module **_module)
+{
+ if (getenv("LDB_WARN_UNINDEXED")) {
+ ldb_kv->warn_unindexed = true;
+ }
+
+ if (getenv("LDB_WARN_REINDEX")) {
+ ldb_kv->warn_reindex = true;
+ }
+
+ ldb_kv->sequence_number = 0;
+
+ ldb_kv->pid = getpid();
+
+ ldb_kv->pack_format_override = 0;
+
+ ldb_kv->module = ldb_module_new(ldb, ldb, name, &ldb_kv_ops);
+ if (!ldb_kv->module) {
+ ldb_oom(ldb);
+ talloc_free(ldb_kv);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ldb_module_set_private(ldb_kv->module, ldb_kv);
+ talloc_steal(ldb_kv->module, ldb_kv);
+
+ if (ldb_kv_cache_load(ldb_kv->module) != 0) {
+ ldb_asprintf_errstring(ldb, "Unable to load ltdb cache "
+ "records for backend '%s'", name);
+ talloc_free(ldb_kv->module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *_module = ldb_kv->module;
+ /*
+ * Set or override the maximum key length
+ *
+ * The ldb_mdb code will have set this to 511, but our tests
+ * set this even smaller (to make the tests more practical).
+ *
+ * This must only be used for the selftest as the length
+ * becomes encoded in the index keys.
+ */
+ {
+ const char *len_str =
+ ldb_options_find(ldb, options,
+ "max_key_len_for_self_test");
+ if (len_str != NULL) {
+ unsigned len = strtoul(len_str, NULL, 0);
+ ldb_kv->max_key_length = len;
+ }
+ }
+
+ /*
+ * Usually the presence of GUID indexing determines the pack format
+ * we use but in certain circumstances such as downgrading an
+ * MDB-backed database, we want to override the target pack format.
+ *
+ * We set/get opaques here because in the Samba partitions module,
+ * 'options' are not passed correctly so sub-databases can't see
+ * the options they need.
+ */
+ {
+ const char *pack_format_override =
+ ldb_options_find(ldb, options, "pack_format_override");
+ if (pack_format_override != NULL) {
+ int ret;
+ ldb_kv->pack_format_override =
+ strtoul(pack_format_override, NULL, 0);
+ ret = ldb_set_opaque(ldb,
+ "pack_format_override",
+ (void *)(intptr_t)ldb_kv->pack_format_override);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb_kv->module);
+ return ldb_module_operr(ldb_kv->module);
+ }
+ } else {
+ /*
+ * NULL -> 0 is fine, otherwise we get back
+ * the number we needed
+ */
+ ldb_kv->pack_format_override
+ = (intptr_t)ldb_get_opaque(ldb,
+ "pack_format_override");
+ }
+ }
+
+ /*
+ * Override full DB scans
+ *
+ * A full DB scan is expensive on a large database. This
+ * option is for testing to show that the full DB scan is not
+ * triggered.
+ */
+ {
+ const char *len_str =
+ ldb_options_find(ldb, options,
+ "disable_full_db_scan_for_self_test");
+ if (len_str != NULL) {
+ ldb_kv->disable_full_db_scan = true;
+ }
+ }
+
+ /*
+ * Set the size of the transaction index cache.
+ * If the ldb option "transaction_index_cache_size" is set use that
+ * otherwise use DEFAULT_INDEX_CACHE_SIZE
+ */
+ ldb_kv->index_transaction_cache_size = DEFAULT_INDEX_CACHE_SIZE;
+ {
+ const char *size = ldb_options_find(
+ ldb,
+ options,
+ "transaction_index_cache_size");
+ if (size != NULL) {
+ size_t cache_size = 0;
+ errno = 0;
+
+ cache_size = strtoul( size, NULL, 0);
+ if (cache_size == 0 || errno == ERANGE) {
+ ldb_debug(
+ ldb,
+ LDB_DEBUG_WARNING,
+ "Invalid transaction_index_cache_size "
+ "value [%s], using default(%d)\n",
+ size,
+ DEFAULT_INDEX_CACHE_SIZE);
+ } else {
+ ldb_kv->index_transaction_cache_size =
+ cache_size;
+ }
+ }
+ }
+ /*
+ * Set batch mode operation.
+ * This disables the nested sub transactions, and increases the
+ * chance of index corruption. If using this mode the transaction
+ * commit will be aborted if any operation fails.
+ */
+ {
+ const char *batch_mode = ldb_options_find(
+ ldb, options, "batch_mode");
+ if (batch_mode != NULL) {
+ ldb_kv->batch_mode = true;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb/ldb_key_value/ldb_kv.h b/lib/ldb/ldb_key_value/ldb_kv.h
new file mode 100644
index 0000000..78cbbec
--- /dev/null
+++ b/lib/ldb/ldb_key_value/ldb_kv.h
@@ -0,0 +1,344 @@
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "tdb.h"
+#include "ldb_module.h"
+
+#ifndef __LDB_KV_H__
+#define __LDB_KV_H__
+struct ldb_kv_private;
+typedef int (*ldb_kv_traverse_fn)(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val data,
+ void *ctx);
+
+struct kv_db_ops {
+ uint32_t options;
+
+ int (*store)(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val data,
+ int flags);
+ int (*delete)(struct ldb_kv_private *ldb_kv, struct ldb_val key);
+ int (*iterate)(struct ldb_kv_private *ldb_kv,
+ ldb_kv_traverse_fn fn,
+ void *ctx);
+ int (*update_in_iterate)(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val key2,
+ struct ldb_val data,
+ void *ctx);
+ int (*fetch_and_parse)(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ int (*parser)(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data),
+ void *ctx);
+ int (*iterate_range)(struct ldb_kv_private *ldb_kv,
+ struct ldb_val start_key,
+ struct ldb_val end_key,
+ ldb_kv_traverse_fn fn,
+ void *ctx);
+ int (*lock_read)(struct ldb_module *);
+ int (*unlock_read)(struct ldb_module *);
+ int (*begin_write)(struct ldb_kv_private *);
+ int (*prepare_write)(struct ldb_kv_private *);
+ int (*abort_write)(struct ldb_kv_private *);
+ int (*finish_write)(struct ldb_kv_private *);
+ int (*error)(struct ldb_kv_private *ldb_kv);
+ const char *(*errorstr)(struct ldb_kv_private *ldb_kv);
+ const char *(*name)(struct ldb_kv_private *ldb_kv);
+ bool (*has_changed)(struct ldb_kv_private *ldb_kv);
+ bool (*transaction_active)(struct ldb_kv_private *ldb_kv);
+ size_t (*get_size)(struct ldb_kv_private *ldb_kv);
+ int (*begin_nested_write)(struct ldb_kv_private *);
+ int (*finish_nested_write)(struct ldb_kv_private *);
+ int (*abort_nested_write)(struct ldb_kv_private *);
+};
+
+/* this private structure is used by the key value backends in the
+ ldb_context */
+struct ldb_kv_private {
+ const struct kv_db_ops *kv_ops;
+ struct ldb_module *module;
+ TDB_CONTEXT *tdb;
+ struct lmdb_private *lmdb_private;
+ unsigned int connect_flags;
+
+ unsigned long long sequence_number;
+ uint32_t pack_format_version;
+ uint32_t target_pack_format_version;
+ uint32_t pack_format_override;
+
+ /* the low level tdb seqnum - used to avoid loading BASEINFO when
+ possible */
+ int tdb_seqnum;
+
+ struct ldb_kv_cache {
+ struct ldb_message *indexlist;
+ bool one_level_indexes;
+ bool attribute_indexes;
+ const char *GUID_index_attribute;
+ const char *GUID_index_dn_component;
+ } *cache;
+
+
+ bool check_base;
+ bool disallow_dn_filter;
+ /*
+ * To improve the performance of batch operations we maintain a cache
+ * of index records, these entries get written to disk in the
+ * prepare_commit phase.
+ */
+ struct ldb_kv_idxptr *idxptr;
+ /*
+ * To ensure that the indexes in idxptr are consistent we cache any
+ * index updates during an operation, i.e. ldb_kv_add, ldb_kv_delete ...
+ * Once the changes to the data record have been committed to disk
+ * the contents of this cache are copied to idxptr
+ */
+ struct ldb_kv_idxptr *nested_idx_ptr;
+ /*
+ * If batch mode is set the sub transactions and index caching
+ * wrapping individual operations is disabled.
+ * This is to improve the performance of large batch operations
+ * i.e. domain joins.
+ */
+ bool batch_mode;
+ /*
+ * Has an operation failed, if true and we're in batch_mode
+ * the transaction commit will fail.
+ */
+ bool operation_failed;
+
+ bool prepared_commit;
+ int read_lock_count;
+
+ bool warn_unindexed;
+ bool warn_reindex;
+
+ bool read_only;
+
+ bool reindex_failed;
+
+ const struct ldb_schema_syntax *GUID_index_syntax;
+
+ /*
+ * Maximum index key length. If non zero keys longer than this length
+ * will be truncated for non unique indexes. Keys for unique indexes
+ * greater than this length will be rejected.
+ */
+ unsigned max_key_length;
+
+ /*
+ * To allow testing that ensures the DB does not fall back
+ * to a full scan
+ */
+ bool disable_full_db_scan;
+
+ /*
+ * The PID that opened this database so we don't work in a
+ * fork()ed child.
+ */
+ pid_t pid;
+
+ /*
+ * The size to be used for the index transaction cache
+ */
+ size_t index_transaction_cache_size;
+};
+
+struct ldb_kv_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ /*
+ * Required as we might not get to the event loop before the
+ * timeout, so we need some old-style cooperative multitasking
+ * here.
+ */
+ struct timeval timeout_timeval;
+
+ /* Used to throttle calls to gettimeofday() */
+ size_t timeout_counter;
+
+ bool request_terminated;
+ struct ldb_kv_req_spy *spy;
+
+ /* search stuff */
+ const struct ldb_parse_tree *tree;
+ struct ldb_dn *base;
+ enum ldb_scope scope;
+ const char * const *attrs;
+ struct tevent_timer *timeout_event;
+
+ /* error handling */
+ int error;
+};
+
+struct ldb_kv_reindex_context {
+ int error;
+ uint32_t count;
+};
+
+struct ldb_kv_repack_context {
+ int error;
+ uint32_t count;
+ bool normal_record_seen;
+ uint32_t old_version;
+};
+
+
+/* special record types */
+#define LDB_KV_INDEX "@INDEX"
+#define LDB_KV_INDEXLIST "@INDEXLIST"
+#define LDB_KV_IDX "@IDX"
+#define LDB_KV_IDXVERSION "@IDXVERSION"
+#define LDB_KV_IDXATTR "@IDXATTR"
+#define LDB_KV_IDXONE "@IDXONE"
+#define LDB_KV_IDXDN "@IDXDN"
+#define LDB_KV_IDXGUID "@IDXGUID"
+#define LDB_KV_IDX_DN_GUID "@IDX_DN_GUID"
+
+/*
+ * This will be used to indicate when a new, yet to be developed
+ * sub-database version of the indices are in use, to ensure we do
+ * not load future databases unintentionally.
+ */
+
+#define LDB_KV_IDX_LMDB_SUBDB "@IDX_LMDB_SUBDB"
+
+#define LDB_KV_BASEINFO "@BASEINFO"
+#define LDB_KV_OPTIONS "@OPTIONS"
+#define LDB_KV_ATTRIBUTES "@ATTRIBUTES"
+
+/* special attribute types */
+#define LDB_KV_SEQUENCE_NUMBER "sequenceNumber"
+#define LDB_KV_CHECK_BASE "checkBaseOnSearch"
+#define LDB_KV_DISALLOW_DN_FILTER "disallowDNFilter"
+#define LDB_KV_MOD_TIMESTAMP "whenChanged"
+#define LDB_KV_OBJECTCLASS "objectClass"
+
+/* DB keys */
+#define LDB_KV_GUID_KEY_PREFIX "GUID="
+#define LDB_KV_GUID_SIZE 16
+#define LDB_KV_GUID_KEY_SIZE (LDB_KV_GUID_SIZE + sizeof(LDB_KV_GUID_KEY_PREFIX) - 1)
+
+/* LDB KV options */
+/*
+ * This allows pointers to be referenced after the callback to any variant of
+ * iterate or fetch_and_parse -- as long as an overall read lock is held.
+ */
+#define LDB_KV_OPTION_STABLE_READ_LOCK 0x00000001
+
+/*
+ * The following definitions come from lib/ldb/ldb_key_value/ldb_kv_cache.c
+ */
+
+int ldb_kv_cache_reload(struct ldb_module *module);
+int ldb_kv_cache_load(struct ldb_module *module);
+int ldb_kv_increase_sequence_number(struct ldb_module *module);
+int ldb_kv_check_at_attributes_values(const struct ldb_val *value);
+
+/*
+ * The following definitions come from lib/ldb/ldb_key_value/ldb_kv_index.c
+ */
+
+/*
+ * The default size of the in memory TDB used to cache index records
+ * The value chosen gives a prime modulo for the hash table and keeps the
+ * tdb memory overhead under 4 kB
+ */
+#define DEFAULT_INDEX_CACHE_SIZE 491
+
+struct ldb_parse_tree;
+
+int ldb_kv_search_indexed(struct ldb_kv_context *ctx, uint32_t *);
+int ldb_kv_index_add_new(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg);
+int ldb_kv_index_delete(struct ldb_module *module,
+ const struct ldb_message *msg);
+int ldb_kv_index_del_element(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el);
+int ldb_kv_index_add_element(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el);
+int ldb_kv_index_del_value(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el,
+ unsigned int v_idx);
+int ldb_kv_reindex(struct ldb_module *module);
+int ldb_kv_repack(struct ldb_module *module);
+int ldb_kv_index_transaction_start(
+ struct ldb_module *module,
+ size_t cache_size);
+int ldb_kv_index_transaction_commit(struct ldb_module *module);
+int ldb_kv_index_transaction_cancel(struct ldb_module *module);
+int ldb_kv_key_dn_from_idx(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_val *key);
+
+/*
+ * The following definitions come from lib/ldb/ldb_key_value/ldb_kv_search.c
+ */
+int ldb_kv_search_dn1(struct ldb_module *module,
+ struct ldb_dn *dn,
+ struct ldb_message *msg,
+ unsigned int unpack_flags);
+int ldb_kv_search_base(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_dn **ret_dn);
+int ldb_kv_search_key(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_val ldb_key,
+ struct ldb_message *msg,
+ unsigned int unpack_flags);
+int ldb_kv_filter_attrs_in_place(struct ldb_message *msg,
+ const char *const *attrs);
+int ldb_kv_search(struct ldb_kv_context *ctx);
+
+/*
+ * The following definitions come from lib/ldb/ldb_key_value/ldb_kv.c */
+/*
+ * Determine if this key could hold a normal record. We allow the new
+ * GUID index, the old DN index and a possible future ID= but not
+ * DN=@.
+ */
+bool ldb_kv_key_is_normal_record(struct ldb_val key);
+struct ldb_val ldb_kv_key_dn(TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn);
+struct ldb_val ldb_kv_key_msg(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg);
+int ldb_kv_guid_to_key(const struct ldb_val *GUID_val,
+ struct ldb_val *key);
+int ldb_kv_idx_to_key(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_val *idx_val,
+ struct ldb_val *key);
+int ldb_kv_store(struct ldb_module *module,
+ const struct ldb_message *msg,
+ int flgs);
+int ldb_kv_modify_internal(struct ldb_module *module,
+ const struct ldb_message *msg,
+ struct ldb_request *req);
+int ldb_kv_delete_noindex(struct ldb_module *module,
+ const struct ldb_message *msg);
+int ldb_kv_init_store(struct ldb_kv_private *ldb_kv,
+ const char *name,
+ struct ldb_context *ldb,
+ const char *options[],
+ struct ldb_module **_module);
+int ldb_kv_index_sub_transaction_start(struct ldb_kv_private *ldb_kv);
+int ldb_kv_index_sub_transaction_cancel(struct ldb_kv_private *ldb_kv);
+int ldb_kv_index_sub_transaction_commit(struct ldb_kv_private *ldb_kv);
+#endif /* __LDB_KV_H__ */
diff --git a/lib/ldb/ldb_key_value/ldb_kv_cache.c b/lib/ldb/ldb_key_value/ldb_kv_cache.c
new file mode 100644
index 0000000..b1c136d
--- /dev/null
+++ b/lib/ldb/ldb_key_value/ldb_kv_cache.c
@@ -0,0 +1,697 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb key value cache functions
+ *
+ * Description: cache special records in a ldb/tdb
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_kv.h"
+#include "ldb_private.h"
+
+#define LDB_KV_FLAG_CASE_INSENSITIVE (1<<0)
+#define LDB_KV_FLAG_INTEGER (1<<1)
+#define LDB_KV_FLAG_UNIQUE_INDEX (1<<2)
+#define LDB_KV_FLAG_ORDERED_INTEGER (1<<3)
+
+/* valid attribute flags */
+static const struct {
+ const char *name;
+ int value;
+} ldb_kv_valid_attr_flags[] = {
+ { "CASE_INSENSITIVE", LDB_KV_FLAG_CASE_INSENSITIVE },
+ { "INTEGER", LDB_KV_FLAG_INTEGER },
+ { "ORDERED_INTEGER", LDB_KV_FLAG_ORDERED_INTEGER },
+ { "HIDDEN", 0 },
+ { "UNIQUE_INDEX", LDB_KV_FLAG_UNIQUE_INDEX},
+ { "NONE", 0 },
+ { NULL, 0 }
+};
+
+/*
+ de-register any special handlers for @ATTRIBUTES
+*/
+static void ldb_kv_attributes_unload(struct ldb_module *module)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ ldb_schema_attribute_remove_flagged(ldb, LDB_ATTR_FLAG_FROM_DB);
+
+}
+
+/*
+ add up the attrib flags for a @ATTRIBUTES element
+*/
+static int ldb_kv_attributes_flags(struct ldb_message_element *el, unsigned *v)
+{
+ unsigned int i;
+ unsigned value = 0;
+ for (i=0;i<el->num_values;i++) {
+ unsigned int j;
+ for (j = 0; ldb_kv_valid_attr_flags[j].name; j++) {
+ if (strcmp(ldb_kv_valid_attr_flags[j].name,
+ (char *)el->values[i].data) == 0) {
+ value |= ldb_kv_valid_attr_flags[j].value;
+ break;
+ }
+ }
+ if (ldb_kv_valid_attr_flags[j].name == NULL) {
+ return -1;
+ }
+ }
+ *v = value;
+ return 0;
+}
+
+static int ldb_schema_attribute_compare(const void *p1, const void *p2)
+{
+ const struct ldb_schema_attribute *sa1 = (const struct ldb_schema_attribute *)p1;
+ const struct ldb_schema_attribute *sa2 = (const struct ldb_schema_attribute *)p2;
+ return ldb_attr_cmp(sa1->name, sa2->name);
+}
+
+/*
+ register any special handlers from @ATTRIBUTES
+*/
+static int ldb_kv_attributes_load(struct ldb_module *module)
+{
+ struct ldb_schema_attribute *attrs;
+ struct ldb_context *ldb;
+ struct ldb_message *attrs_msg = NULL;
+ struct ldb_dn *dn;
+ unsigned int i;
+ unsigned int num_loaded_attrs = 0;
+ int r;
+
+ ldb = ldb_module_get_ctx(module);
+
+ if (ldb->schema.attribute_handler_override) {
+ /* we skip loading the @ATTRIBUTES record when a module is supplying
+ its own attribute handling */
+ return 0;
+ }
+
+ attrs_msg = ldb_msg_new(module);
+ if (attrs_msg == NULL) {
+ goto failed;
+ }
+
+ dn = ldb_dn_new(module, ldb, LDB_KV_ATTRIBUTES);
+ if (dn == NULL) goto failed;
+
+ r = ldb_kv_search_dn1(module,
+ dn,
+ attrs_msg,
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC |
+ LDB_UNPACK_DATA_FLAG_NO_DN);
+ talloc_free(dn);
+ if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
+ goto failed;
+ }
+ if (r == LDB_ERR_NO_SUCH_OBJECT || attrs_msg->num_elements == 0) {
+ TALLOC_FREE(attrs_msg);
+ return 0;
+ }
+
+ attrs = talloc_array(attrs_msg,
+ struct ldb_schema_attribute,
+ attrs_msg->num_elements
+ + ldb->schema.num_attributes);
+ if (attrs == NULL) {
+ goto failed;
+ }
+
+ memcpy(attrs,
+ ldb->schema.attributes,
+ sizeof(ldb->schema.attributes[0]) * ldb->schema.num_attributes);
+
+ /* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
+ but its close enough for now */
+ for (i=0;i<attrs_msg->num_elements;i++) {
+ unsigned flags = 0, attr_flags = 0;
+ const char *syntax;
+ const struct ldb_schema_syntax *s;
+ const struct ldb_schema_attribute *a =
+ ldb_schema_attribute_by_name(ldb,
+ attrs_msg->elements[i].name);
+ if (a != NULL && a->flags & LDB_ATTR_FLAG_FIXED) {
+ /* Must already be set in the array, and kept */
+ continue;
+ }
+
+ if (ldb_kv_attributes_flags(&attrs_msg->elements[i], &flags) !=
+ 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Invalid @ATTRIBUTES element for '%s'",
+ attrs_msg->elements[i].name);
+ goto failed;
+ }
+
+ if (flags & LDB_KV_FLAG_UNIQUE_INDEX) {
+ attr_flags = LDB_ATTR_FLAG_UNIQUE_INDEX;
+ }
+ flags &= ~LDB_KV_FLAG_UNIQUE_INDEX;
+
+ /* These are not currently flags, each is exclusive */
+ if (flags == LDB_KV_FLAG_CASE_INSENSITIVE) {
+ syntax = LDB_SYNTAX_DIRECTORY_STRING;
+ } else if (flags == LDB_KV_FLAG_INTEGER) {
+ syntax = LDB_SYNTAX_INTEGER;
+ } else if (flags == LDB_KV_FLAG_ORDERED_INTEGER) {
+ syntax = LDB_SYNTAX_ORDERED_INTEGER;
+ } else if (flags == 0) {
+ syntax = LDB_SYNTAX_OCTET_STRING;
+ } else {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Invalid flag combination 0x%x for '%s' "
+ "in @ATTRIBUTES",
+ flags, attrs_msg->elements[i].name);
+ goto failed;
+ }
+
+ s = ldb_standard_syntax_by_name(ldb, syntax);
+ if (s == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Invalid attribute syntax '%s' for '%s' "
+ "in @ATTRIBUTES",
+ syntax, attrs_msg->elements[i].name);
+ goto failed;
+ }
+
+ attr_flags |= LDB_ATTR_FLAG_ALLOCATED | LDB_ATTR_FLAG_FROM_DB;
+
+ r = ldb_schema_attribute_fill_with_syntax(ldb,
+ attrs,
+ attrs_msg->elements[i].name,
+ attr_flags, s,
+ &attrs[num_loaded_attrs + ldb->schema.num_attributes]);
+ if (r != 0) {
+ goto failed;
+ }
+ num_loaded_attrs++;
+ }
+
+ attrs = talloc_realloc(attrs_msg,
+ attrs, struct ldb_schema_attribute,
+ num_loaded_attrs + ldb->schema.num_attributes);
+ if (attrs == NULL) {
+ goto failed;
+ }
+ TYPESAFE_QSORT(attrs, num_loaded_attrs + ldb->schema.num_attributes,
+ ldb_schema_attribute_compare);
+ talloc_unlink(ldb, ldb->schema.attributes);
+ ldb->schema.attributes = talloc_steal(ldb, attrs);
+ ldb->schema.num_attributes = num_loaded_attrs + ldb->schema.num_attributes;
+ TALLOC_FREE(attrs_msg);
+
+ return 0;
+failed:
+ TALLOC_FREE(attrs_msg);
+ return -1;
+}
+
+/*
+ register any index records we find for the DB
+*/
+static int ldb_kv_index_load(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_dn *indexlist_dn;
+ int r, lmdb_subdb_version;
+
+ if (ldb->schema.index_handler_override) {
+ /*
+ * we skip loading the @INDEXLIST record when a module is
+ * supplying its own attribute handling
+ */
+ ldb_kv->cache->attribute_indexes = true;
+ ldb_kv->cache->one_level_indexes =
+ ldb->schema.one_level_indexes;
+ ldb_kv->cache->GUID_index_attribute =
+ ldb->schema.GUID_index_attribute;
+ ldb_kv->cache->GUID_index_dn_component =
+ ldb->schema.GUID_index_dn_component;
+ return 0;
+ }
+
+ talloc_free(ldb_kv->cache->indexlist);
+
+ ldb_kv->cache->indexlist = ldb_msg_new(ldb_kv->cache);
+ if (ldb_kv->cache->indexlist == NULL) {
+ return -1;
+ }
+ ldb_kv->cache->one_level_indexes = false;
+ ldb_kv->cache->attribute_indexes = false;
+
+ indexlist_dn = ldb_dn_new(ldb_kv, ldb, LDB_KV_INDEXLIST);
+ if (indexlist_dn == NULL) {
+ return -1;
+ }
+
+ r = ldb_kv_search_dn1(module,
+ indexlist_dn,
+ ldb_kv->cache->indexlist,
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC |
+ LDB_UNPACK_DATA_FLAG_NO_DN);
+ TALLOC_FREE(indexlist_dn);
+
+ if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
+ return -1;
+ }
+
+ if (ldb_msg_find_element(ldb_kv->cache->indexlist, LDB_KV_IDXONE) !=
+ NULL) {
+ ldb_kv->cache->one_level_indexes = true;
+ }
+ if (ldb_msg_find_element(ldb_kv->cache->indexlist, LDB_KV_IDXATTR) !=
+ NULL) {
+ ldb_kv->cache->attribute_indexes = true;
+ }
+ ldb_kv->cache->GUID_index_attribute = ldb_msg_find_attr_as_string(
+ ldb_kv->cache->indexlist, LDB_KV_IDXGUID, NULL);
+ ldb_kv->cache->GUID_index_dn_component = ldb_msg_find_attr_as_string(
+ ldb_kv->cache->indexlist, LDB_KV_IDX_DN_GUID, NULL);
+
+ lmdb_subdb_version = ldb_msg_find_attr_as_int(
+ ldb_kv->cache->indexlist, LDB_KV_IDX_LMDB_SUBDB, 0);
+
+ if (lmdb_subdb_version != 0) {
+ ldb_set_errstring(ldb,
+ "FATAL: This ldb_mdb database has "
+ "been written in a new version of LDB "
+ "using a sub-database index that "
+ "is not understood by ldb "
+ LDB_VERSION);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ initialise the baseinfo record
+*/
+static int ldb_kv_baseinfo_init(struct ldb_module *module)
+{
+ struct ldb_context *ldb;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_message *msg;
+ struct ldb_message_element el;
+ struct ldb_val val;
+ int ret;
+ /* the initial sequence number must be different from the one
+ set in ltdb_cache_free(). Thanks to Jon for pointing this
+ out. */
+ const char *initial_sequence_number = "1";
+
+ ldb = ldb_module_get_ctx(module);
+
+ ldb_kv->sequence_number = atof(initial_sequence_number);
+
+ msg = ldb_msg_new(ldb_kv);
+ if (msg == NULL) {
+ goto failed;
+ }
+
+ msg->num_elements = 1;
+ msg->elements = &el;
+ msg->dn = ldb_dn_new(msg, ldb, LDB_KV_BASEINFO);
+ if (!msg->dn) {
+ goto failed;
+ }
+ el.name = talloc_strdup(msg, LDB_KV_SEQUENCE_NUMBER);
+ if (!el.name) {
+ goto failed;
+ }
+ el.values = &val;
+ el.num_values = 1;
+ el.flags = 0;
+ val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number);
+ if (!val.data) {
+ goto failed;
+ }
+ val.length = 1;
+
+ ret = ldb_kv_store(module, msg, TDB_INSERT);
+
+ talloc_free(msg);
+
+ return ret;
+
+failed:
+ talloc_free(msg);
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+ free any cache records
+ */
+static void ldb_kv_cache_free(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+
+ ldb_kv->sequence_number = 0;
+ talloc_free(ldb_kv->cache);
+ ldb_kv->cache = NULL;
+}
+
+/*
+ force a cache reload
+*/
+int ldb_kv_cache_reload(struct ldb_module *module)
+{
+ ldb_kv_attributes_unload(module);
+ ldb_kv_cache_free(module);
+ return ldb_kv_cache_load(module);
+}
+static int get_pack_format_version(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data)
+{
+ uint32_t *v = (uint32_t *) private_data;
+ return ldb_unpack_get_format(&data, v);
+}
+
+/*
+ load the cache records
+*/
+int ldb_kv_cache_load(struct ldb_module *module)
+{
+ struct ldb_context *ldb;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_dn *baseinfo_dn = NULL, *options_dn = NULL;
+ uint64_t seq;
+ struct ldb_message *baseinfo = NULL, *options = NULL;
+ const struct ldb_schema_attribute *a;
+ bool have_write_txn = false;
+ int r;
+ struct ldb_val key;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* a very fast check to avoid extra database reads */
+ if (ldb_kv->cache != NULL && !ldb_kv->kv_ops->has_changed(ldb_kv)) {
+ return 0;
+ }
+
+ if (ldb_kv->cache == NULL) {
+ ldb_kv->cache = talloc_zero(ldb_kv, struct ldb_kv_cache);
+ if (ldb_kv->cache == NULL)
+ goto failed;
+ }
+
+ baseinfo = ldb_msg_new(ldb_kv->cache);
+ if (baseinfo == NULL) goto failed;
+
+ baseinfo_dn = ldb_dn_new(baseinfo, ldb, LDB_KV_BASEINFO);
+ if (baseinfo_dn == NULL) goto failed;
+
+ r = ldb_kv->kv_ops->lock_read(module);
+ if (r != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ key = ldb_kv_key_dn(baseinfo, baseinfo_dn);
+ if (!key.data) {
+ goto failed_and_unlock;
+ }
+
+ /* Read packing format from first 4 bytes of @BASEINFO record */
+ r = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key,
+ get_pack_format_version,
+ &ldb_kv->pack_format_version);
+
+ /* possibly initialise the baseinfo */
+ if (r == LDB_ERR_NO_SUCH_OBJECT) {
+
+ /* Give up the read lock, try again with a write lock */
+ r = ldb_kv->kv_ops->unlock_read(module);
+ if (r != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ if (ldb_kv->kv_ops->begin_write(ldb_kv) != 0) {
+ goto failed;
+ }
+
+ have_write_txn = true;
+
+ /*
+ * We need to write but haven't figured out packing format yet.
+ * Just go with version 1 and we'll repack if we got it wrong.
+ */
+ ldb_kv->pack_format_version = LDB_PACKING_FORMAT;
+ ldb_kv->target_pack_format_version = LDB_PACKING_FORMAT;
+
+ /* error handling for ltdb_baseinfo_init() is by
+ looking for the record again. */
+ ldb_kv_baseinfo_init(module);
+
+ } else if (r != LDB_SUCCESS) {
+ goto failed_and_unlock;
+ }
+
+ /* OK now we definitely have a @BASEINFO record so fetch it */
+ r = ldb_kv_search_dn1(module, baseinfo_dn, baseinfo, 0);
+ if (r != LDB_SUCCESS) {
+ goto failed_and_unlock;
+ }
+
+ /* Ignore the result, and update the sequence number */
+ ldb_kv->kv_ops->has_changed(ldb_kv);
+
+ /* if the current internal sequence number is the same as the one
+ in the database then assume the rest of the cache is OK */
+ seq = ldb_msg_find_attr_as_uint64(baseinfo, LDB_KV_SEQUENCE_NUMBER, 0);
+ if (seq == ldb_kv->sequence_number) {
+ goto done;
+ }
+ ldb_kv->sequence_number = seq;
+
+ /* Read an interpret database options */
+
+ options = ldb_msg_new(ldb_kv->cache);
+ if (options == NULL) goto failed_and_unlock;
+
+ options_dn = ldb_dn_new(options, ldb, LDB_KV_OPTIONS);
+ if (options_dn == NULL) goto failed_and_unlock;
+
+ r = ldb_kv_search_dn1(module, options_dn, options, 0);
+ talloc_free(options_dn);
+ if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
+ goto failed_and_unlock;
+ }
+
+ /* set flags if they do exist */
+ if (r == LDB_SUCCESS) {
+ ldb_kv->check_base =
+ ldb_msg_find_attr_as_bool(options, LDB_KV_CHECK_BASE, false);
+ ldb_kv->disallow_dn_filter = ldb_msg_find_attr_as_bool(
+ options, LDB_KV_DISALLOW_DN_FILTER, false);
+ } else {
+ ldb_kv->check_base = false;
+ ldb_kv->disallow_dn_filter = false;
+ }
+
+ /*
+ * ltdb_attributes_unload() calls internally talloc_free() on
+ * any non-fixed elements in ldb->schema.attributes.
+ *
+ * NOTE WELL: This is per-ldb, not per module, so overwrites
+ * the handlers across all databases when used under Samba's
+ * partition module.
+ */
+ ldb_kv_attributes_unload(module);
+
+ if (ldb_kv_index_load(module, ldb_kv) == -1) {
+ goto failed_and_unlock;
+ }
+
+ /*
+ * NOTE WELL: This is per-ldb, not per module, so overwrites
+ * the handlers across all databases when used under Samba's
+ * partition module.
+ */
+ if (ldb_kv_attributes_load(module) == -1) {
+ goto failed_and_unlock;
+ }
+
+ /*
+ * Initialise packing version and GUID index syntax, and force the
+ * two to travel together, ie a GUID indexed database must use V2
+ * packing format and a DN indexed database must use V1.
+ */
+ ldb_kv->GUID_index_syntax = NULL;
+ if (ldb_kv->cache->GUID_index_attribute != NULL) {
+ ldb_kv->target_pack_format_version = LDB_PACKING_FORMAT_V2;
+
+ /*
+ * Now the attributes are loaded, set the guid_index_syntax.
+ * This can't fail, it will return a default at worst
+ */
+ a = ldb_schema_attribute_by_name(
+ ldb, ldb_kv->cache->GUID_index_attribute);
+ ldb_kv->GUID_index_syntax = a->syntax;
+ } else {
+ ldb_kv->target_pack_format_version = LDB_PACKING_FORMAT;
+ }
+
+done:
+ if (have_write_txn) {
+ if (ldb_kv->kv_ops->finish_write(ldb_kv) != 0) {
+ goto failed;
+ }
+ } else {
+ ldb_kv->kv_ops->unlock_read(module);
+ }
+
+ talloc_free(options);
+ talloc_free(baseinfo);
+ return 0;
+
+failed_and_unlock:
+ if (have_write_txn) {
+ ldb_kv->kv_ops->abort_write(ldb_kv);
+ } else {
+ ldb_kv->kv_ops->unlock_read(module);
+ }
+
+failed:
+ talloc_free(options);
+ talloc_free(baseinfo);
+ return -1;
+}
+
+
+/*
+ increase the sequence number to indicate a database change
+*/
+int ldb_kv_increase_sequence_number(struct ldb_module *module)
+{
+ struct ldb_context *ldb;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct ldb_message *msg;
+ struct ldb_message_element el[2];
+ struct ldb_val val;
+ struct ldb_val val_time;
+ time_t t = time(NULL);
+ char *s = NULL;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ msg = ldb_msg_new(ldb_kv);
+ if (msg == NULL) {
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ s = talloc_asprintf(msg, "%llu", ldb_kv->sequence_number + 1);
+ if (!s) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->num_elements = ARRAY_SIZE(el);
+ msg->elements = el;
+ msg->dn = ldb_dn_new(msg, ldb, LDB_KV_BASEINFO);
+ if (msg->dn == NULL) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ el[0].name = talloc_strdup(msg, LDB_KV_SEQUENCE_NUMBER);
+ if (el[0].name == NULL) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ el[0].values = &val;
+ el[0].num_values = 1;
+ el[0].flags = LDB_FLAG_MOD_REPLACE;
+ val.data = (uint8_t *)s;
+ val.length = strlen(s);
+
+ el[1].name = talloc_strdup(msg, LDB_KV_MOD_TIMESTAMP);
+ if (el[1].name == NULL) {
+ talloc_free(msg);
+ errno = ENOMEM;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ el[1].values = &val_time;
+ el[1].num_values = 1;
+ el[1].flags = LDB_FLAG_MOD_REPLACE;
+
+ s = ldb_timestring(msg, t);
+ if (s == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ val_time.data = (uint8_t *)s;
+ val_time.length = strlen(s);
+
+ ret = ldb_kv_modify_internal(module, msg, NULL);
+
+ talloc_free(msg);
+
+ if (ret == LDB_SUCCESS) {
+ ldb_kv->sequence_number += 1;
+ }
+
+ /* updating the tdb_seqnum here avoids us reloading the cache
+ records due to our own modification */
+ ldb_kv->kv_ops->has_changed(ldb_kv);
+
+ return ret;
+}
+
+int ldb_kv_check_at_attributes_values(const struct ldb_val *value)
+{
+ unsigned int i;
+
+ for (i = 0; ldb_kv_valid_attr_flags[i].name != NULL; i++) {
+ if ((strcmp(ldb_kv_valid_attr_flags[i].name,
+ (char *)value->data) == 0)) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c
new file mode 100644
index 0000000..3f1a847
--- /dev/null
+++ b/lib/ldb/ldb_key_value/ldb_kv_index.c
@@ -0,0 +1,4018 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004-2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb key value backend - indexing
+ *
+ * Description: indexing routines for ldb key value backend
+ *
+ * Author: Andrew Tridgell
+ */
+
+/*
+
+LDB Index design and choice of key:
+=======================================
+
+LDB has index records held as LDB objects with a special record like:
+
+dn: @INDEX:attr:value
+
+value may be base64 encoded, if it is deemed not printable:
+
+dn: @INDEX:attr::base64-value
+
+In each record, there is two possible formats:
+
+The original format is:
+-----------------------
+
+dn: @INDEX:NAME:DNSUPDATEPROXY
+@IDXVERSION: 2
+@IDX: CN=DnsUpdateProxy,CN=Users,DC=addom,DC=samba,DC=example,DC=com
+
+In this format, @IDX is multi-valued, one entry for each match
+
+The corresponding entry is stored in a TDB record with key:
+
+DN=CN=DNSUPDATEPROXY,CN=USERS,DC=ADDOM,DC=SAMBA,DC=EXAMPLE,DC=COM
+
+(This allows a scope BASE search to directly find the record via
+a simple casefold of the DN).
+
+The original mixed-case DN is stored in the entry itself.
+
+
+The new 'GUID index' format is:
+-------------------------------
+
+dn: @INDEX:NAME:DNSUPDATEPROXY
+@IDXVERSION: 3
+@IDX: <binary GUID>[<binary GUID>[...]]
+
+The binary guid is 16 bytes, as bytes and not expanded as hexadecimal
+or pretty-printed. The GUID is chosen from the message to be stored
+by the @IDXGUID attribute on @INDEXLIST.
+
+If there are multiple values the @IDX value simply becomes longer,
+in multiples of 16.
+
+The corresponding entry is stored in a TDB record with key:
+
+GUID=<binary GUID>
+
+This allows a very quick translation between the fixed-length index
+values and the TDB key, while separating entries from other data
+in the TDB, should they be unlucky enough to start with the bytes of
+the 'DN=' prefix.
+
+Additionally, this allows a scope BASE search to directly find the
+record via a simple match on a GUID= extended DN, controlled via
+@IDX_DN_GUID on @INDEXLIST
+
+Exception for special @ DNs:
+
+@BASEINFO, @INDEXLIST and all other special DNs are stored as per the
+original format, as they are never referenced in an index and are used
+to bootstrap the database.
+
+
+Control points for choice of index mode
+---------------------------------------
+
+The choice of index and TDB key mode is made based (for example, from
+Samba) on entries in the @INDEXLIST DN:
+
+dn: @INDEXLIST
+@IDXGUID: objectGUID
+@IDX_DN_GUID: GUID
+
+By default, the original DN format is used.
+
+
+Control points for choosing indexed attributes
+----------------------------------------------
+
+@IDXATTR controls if an attribute is indexed
+
+dn: @INDEXLIST
+@IDXATTR: samAccountName
+@IDXATTR: nETBIOSName
+
+
+C Override functions
+--------------------
+
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+ const char *GUID_index_attribute,
+ const char *GUID_index_dn_component)
+
+This is used, particularly in combination with the below, instead of
+the @IDXGUID and @IDX_DN_GUID values in @INDEXLIST.
+
+void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
+ bool one_level_indexes);
+void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
+ ldb_attribute_handler_override_fn_t override,
+ void *private_data);
+
+When the above two functions are called in combination, the @INDEXLIST
+values are not read from the DB, so
+ldb_schema_set_override_GUID_index() must be called.
+
+*/
+
+#include "ldb_kv.h"
+#include "../ldb_tdb/ldb_tdb.h"
+#include "ldb_private.h"
+#include "lib/util/binsearch.h"
+#include "lib/util/attr.h"
+
+struct dn_list {
+ unsigned int count;
+ struct ldb_val *dn;
+ /*
+ * Do not optimise the intersection of this list,
+ * we must never return an entry not in this
+ * list. This allows the index for
+ * SCOPE_ONELEVEL to be trusted.
+ */
+ bool strict;
+};
+
+struct ldb_kv_idxptr {
+ /*
+ * In memory tdb to cache the index updates performed during a
+ * transaction. This improves the performance of operations like
+ * re-index and join
+ */
+ struct tdb_context *itdb;
+ int error;
+};
+
+enum key_truncation {
+ KEY_NOT_TRUNCATED,
+ KEY_TRUNCATED,
+};
+
+static int ldb_kv_write_index_dn_guid(struct ldb_module *module,
+ const struct ldb_message *msg,
+ int add);
+static int ldb_kv_index_dn_base_dn(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ struct ldb_dn *base_dn,
+ struct dn_list *dn_list,
+ enum key_truncation *truncation);
+
+static void ldb_kv_dn_list_sort(struct ldb_kv_private *ldb_kv,
+ struct dn_list *list);
+
+/* we put a @IDXVERSION attribute on index entries. This
+ allows us to tell if it was written by an older version
+*/
+#define LDB_KV_INDEXING_VERSION 2
+
+#define LDB_KV_GUID_INDEXING_VERSION 3
+
+static unsigned ldb_kv_max_key_length(struct ldb_kv_private *ldb_kv)
+{
+ if (ldb_kv->max_key_length == 0) {
+ return UINT_MAX;
+ }
+ return ldb_kv->max_key_length;
+}
+
+/* enable the idxptr mode when transactions start */
+int ldb_kv_index_transaction_start(
+ struct ldb_module *module,
+ size_t cache_size)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ ldb_kv->idxptr = talloc_zero(ldb_kv, struct ldb_kv_idxptr);
+ if (ldb_kv->idxptr == NULL) {
+ return ldb_oom(ldb_module_get_ctx(module));
+ }
+
+ ldb_kv->idxptr->itdb = tdb_open(
+ NULL,
+ cache_size,
+ TDB_INTERNAL,
+ O_RDWR,
+ 0);
+ if (ldb_kv->idxptr->itdb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ see if two ldb_val structures contain exactly the same data
+ return -1 or 1 for a mismatch, 0 for match
+*/
+static int ldb_val_equal_exact_for_qsort(const struct ldb_val *v1,
+ const struct ldb_val *v2)
+{
+ if (v1->length > v2->length) {
+ return -1;
+ }
+ if (v1->length < v2->length) {
+ return 1;
+ }
+ return memcmp(v1->data, v2->data, v1->length);
+}
+
+/*
+ see if two ldb_val structures contain exactly the same data
+ return -1 or 1 for a mismatch, 0 for match
+*/
+static int ldb_val_equal_exact_ordered(const struct ldb_val v1,
+ const struct ldb_val *v2)
+{
+ if (v1.length > v2->length) {
+ return -1;
+ }
+ if (v1.length < v2->length) {
+ return 1;
+ }
+ return memcmp(v1.data, v2->data, v1.length);
+}
+
+
+/*
+ find a entry in a dn_list, using a ldb_val. Uses a case sensitive
+ binary-safe comparison for the 'dn' returns -1 if not found
+
+ This is therefore safe when the value is a GUID in the future
+ */
+static int ldb_kv_dn_list_find_val(struct ldb_kv_private *ldb_kv,
+ const struct dn_list *list,
+ const struct ldb_val *v)
+{
+ unsigned int i;
+ struct ldb_val *exact = NULL, *next = NULL;
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ for (i=0; i<list->count; i++) {
+ if (ldb_val_equal_exact(&list->dn[i], v) == 1) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ BINARY_ARRAY_SEARCH_GTE(list->dn, list->count,
+ *v, ldb_val_equal_exact_ordered,
+ exact, next);
+ if (exact == NULL) {
+ return -1;
+ }
+ /* Not required, but keeps the compiler quiet */
+ if (next != NULL) {
+ return -1;
+ }
+
+ i = exact - list->dn;
+ return i;
+}
+
+/*
+ find a entry in a dn_list. Uses a case sensitive comparison with the dn
+ returns -1 if not found
+ */
+static int ldb_kv_dn_list_find_msg(struct ldb_kv_private *ldb_kv,
+ struct dn_list *list,
+ const struct ldb_message *msg)
+{
+ struct ldb_val v;
+ const struct ldb_val *key_val;
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ const char *dn_str = ldb_dn_get_linearized(msg->dn);
+ v.data = discard_const_p(unsigned char, dn_str);
+ v.length = strlen(dn_str);
+ } else {
+ key_val = ldb_msg_find_ldb_val(
+ msg, ldb_kv->cache->GUID_index_attribute);
+ if (key_val == NULL) {
+ return -1;
+ }
+ v = *key_val;
+ }
+ return ldb_kv_dn_list_find_val(ldb_kv, list, &v);
+}
+
+/*
+ this is effectively a cast function, but with lots of paranoia
+ checks and also copes with CPUs that are fussy about pointer
+ alignment
+ */
+static struct dn_list *ldb_kv_index_idxptr(struct ldb_module *module,
+ TDB_DATA rec)
+{
+ struct dn_list *list;
+ if (rec.dsize != sizeof(void *)) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Bad data size for idxptr %u", (unsigned)rec.dsize);
+ return NULL;
+ }
+ /* note that we can't just use a cast here, as rec.dptr may
+ not be aligned sufficiently for a pointer. A cast would cause
+ platforms like some ARM CPUs to crash */
+ memcpy(&list, rec.dptr, sizeof(void *));
+ list = talloc_get_type(list, struct dn_list);
+ if (list == NULL) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Bad type '%s' for idxptr",
+ talloc_get_name(list));
+ return NULL;
+ }
+ return list;
+}
+
+enum dn_list_will_be_read_only {
+ DN_LIST_MUTABLE = 0,
+ DN_LIST_WILL_BE_READ_ONLY = 1,
+};
+
+/*
+ return the @IDX list in an index entry for a dn as a
+ struct dn_list
+ */
+static int ldb_kv_dn_list_load(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ struct ldb_dn *dn,
+ struct dn_list *list,
+ enum dn_list_will_be_read_only read_only)
+{
+ struct ldb_message *msg;
+ int ret, version;
+ struct ldb_message_element *el;
+ TDB_DATA rec = {0};
+ struct dn_list *list2;
+ bool from_primary_cache = false;
+ TDB_DATA key = {0};
+
+ list->dn = NULL;
+ list->count = 0;
+ list->strict = false;
+
+ /*
+ * See if we have an in memory index cache
+ */
+ if (ldb_kv->idxptr == NULL) {
+ goto normal_index;
+ }
+
+ key.dptr = discard_const_p(unsigned char, ldb_dn_get_linearized(dn));
+ key.dsize = strlen((char *)key.dptr);
+
+ /*
+ * Have we cached this index record?
+ * If we have a nested transaction cache try that first.
+ * then try the transaction cache.
+ * if the record is not cached it will need to be read from disk.
+ */
+ if (ldb_kv->nested_idx_ptr != NULL) {
+ rec = tdb_fetch(ldb_kv->nested_idx_ptr->itdb, key);
+ }
+ if (rec.dptr == NULL) {
+ from_primary_cache = true;
+ rec = tdb_fetch(ldb_kv->idxptr->itdb, key);
+ }
+ if (rec.dptr == NULL) {
+ goto normal_index;
+ }
+
+ /* we've found an in-memory index entry */
+ list2 = ldb_kv_index_idxptr(module, rec);
+ if (list2 == NULL) {
+ free(rec.dptr);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ free(rec.dptr);
+
+ /*
+ * If this is a read only transaction the indexes will not be
+ * changed so we don't need a copy in the event of a rollback
+ *
+ * In this case make an early return
+ */
+ if (read_only == DN_LIST_WILL_BE_READ_ONLY) {
+ *list = *list2;
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * record was read from the sub transaction cache, so we have
+ * already copied the primary cache record
+ */
+ if (!from_primary_cache) {
+ *list = *list2;
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * No index sub transaction active, so no need to cache a copy
+ */
+ if (ldb_kv->nested_idx_ptr == NULL) {
+ *list = *list2;
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * There is an active index sub transaction, and the record was
+ * found in the primary index transaction cache. A copy of the
+ * record needs be taken to prevent the original entry being
+ * altered, until the index sub transaction is committed.
+ */
+
+ {
+ struct ldb_val *dns = NULL;
+ size_t x = 0;
+
+ dns = talloc_array(
+ list,
+ struct ldb_val,
+ list2->count);
+ if (dns == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ for (x = 0; x < list2->count; x++) {
+ dns[x].length = list2->dn[x].length;
+ dns[x].data = talloc_memdup(
+ dns,
+ list2->dn[x].data,
+ list2->dn[x].length);
+ if (dns[x].data == NULL) {
+ TALLOC_FREE(dns);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ list->dn = dns;
+ list->count = list2->count;
+ }
+ return LDB_SUCCESS;
+
+ /*
+ * Index record not found in the caches, read it from the
+ * database.
+ */
+normal_index:
+ msg = ldb_msg_new(list);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_search_dn1(module,
+ dn,
+ msg,
+ LDB_UNPACK_DATA_FLAG_NO_DN |
+ /*
+ * The entry point ldb_kv_search_indexed is
+ * only called from the read-locked
+ * ldb_kv_search.
+ */
+ LDB_UNPACK_DATA_FLAG_READ_LOCKED);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ el = ldb_msg_find_element(msg, LDB_KV_IDX);
+ if (!el) {
+ talloc_free(msg);
+ return LDB_SUCCESS;
+ }
+
+ version = ldb_msg_find_attr_as_int(msg, LDB_KV_IDXVERSION, 0);
+
+ /*
+ * we avoid copying the strings by stealing the list. We have
+ * to steal msg onto el->values (which looks odd) because
+ * the memory is allocated on msg, not on each value.
+ */
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ /* check indexing version number */
+ if (version != LDB_KV_INDEXING_VERSION) {
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_ERROR,
+ "Wrong DN index version %d "
+ "expected %d for %s",
+ version, LDB_KV_INDEXING_VERSION,
+ ldb_dn_get_linearized(dn));
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_steal(el->values, msg);
+ list->dn = talloc_steal(list, el->values);
+ list->count = el->num_values;
+ } else {
+ unsigned int i;
+ if (version != LDB_KV_GUID_INDEXING_VERSION) {
+ /* This is quite likely during the DB startup
+ on first upgrade to using a GUID index */
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_ERROR,
+ "Wrong GUID index version %d "
+ "expected %d for %s",
+ version, LDB_KV_GUID_INDEXING_VERSION,
+ ldb_dn_get_linearized(dn));
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (el->num_values == 0) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if ((el->values[0].length % LDB_KV_GUID_SIZE) != 0) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ list->count = el->values[0].length / LDB_KV_GUID_SIZE;
+ list->dn = talloc_array(list, struct ldb_val, list->count);
+ if (list->dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * The actual data is on msg.
+ */
+ talloc_steal(list->dn, msg);
+ for (i = 0; i < list->count; i++) {
+ list->dn[i].data
+ = &el->values[0].data[i * LDB_KV_GUID_SIZE];
+ list->dn[i].length = LDB_KV_GUID_SIZE;
+ }
+ }
+
+ /* We don't need msg->elements any more */
+ talloc_free(msg->elements);
+ return LDB_SUCCESS;
+}
+
+int ldb_kv_key_dn_from_idx(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_val *ldb_key)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ int ret;
+ int index = 0;
+ enum key_truncation truncation = KEY_NOT_TRUNCATED;
+ struct dn_list *list = talloc(mem_ctx, struct dn_list);
+ if (list == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_index_dn_base_dn(module, ldb_kv, dn, list, &truncation);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(list);
+ return ret;
+ }
+
+ if (list->count == 0) {
+ TALLOC_FREE(list);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ if (list->count > 1 && truncation == KEY_NOT_TRUNCATED) {
+ const char *dn_str = ldb_dn_get_linearized(dn);
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__
+ ": Failed to read DN index "
+ "against %s for %s: too many "
+ "values (%u > 1)",
+ ldb_kv->cache->GUID_index_attribute,
+ dn_str,
+ list->count);
+ TALLOC_FREE(list);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ if (list->count > 0 && truncation == KEY_TRUNCATED) {
+ /*
+ * DN key has been truncated, need to inspect the actual
+ * records to locate the actual DN
+ */
+ unsigned int i;
+ index = -1;
+ for (i=0; i < list->count; i++) {
+ uint8_t guid_key[LDB_KV_GUID_KEY_SIZE];
+ struct ldb_val key = {
+ .data = guid_key,
+ .length = sizeof(guid_key)
+ };
+ const int flags = LDB_UNPACK_DATA_FLAG_NO_ATTRS;
+ struct ldb_message *rec = ldb_msg_new(ldb);
+ if (rec == NULL) {
+ TALLOC_FREE(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_idx_to_key(
+ module, ldb_kv, ldb, &list->dn[i], &key);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(list);
+ TALLOC_FREE(rec);
+ return ret;
+ }
+
+ ret =
+ ldb_kv_search_key(module, ldb_kv, key, rec, flags);
+ if (key.data != guid_key) {
+ TALLOC_FREE(key.data);
+ }
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /*
+ * the record has disappeared?
+ * yes, this can happen
+ */
+ TALLOC_FREE(rec);
+ continue;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ /* an internal error */
+ TALLOC_FREE(rec);
+ TALLOC_FREE(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * We found the actual DN that we wanted from in the
+ * multiple values that matched the index
+ * (due to truncation), so return that.
+ *
+ */
+ if (ldb_dn_compare(dn, rec->dn) == 0) {
+ index = i;
+ TALLOC_FREE(rec);
+ break;
+ }
+ }
+
+ /*
+ * We matched the index but the actual DN we wanted
+ * was not here.
+ */
+ if (index == -1) {
+ TALLOC_FREE(list);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ }
+
+ /* The ldb_key memory is allocated by the caller */
+ ret = ldb_kv_guid_to_key(&list->dn[index], ldb_key);
+ TALLOC_FREE(list);
+
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+
+/*
+ save a dn_list into a full @IDX style record
+ */
+static int ldb_kv_dn_list_store_full(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ struct ldb_dn *dn,
+ struct dn_list *list)
+{
+ struct ldb_message *msg;
+ int ret;
+
+ msg = ldb_msg_new(module);
+ if (!msg) {
+ return ldb_module_oom(module);
+ }
+
+ msg->dn = dn;
+
+ if (list->count == 0) {
+ ret = ldb_kv_delete_noindex(module, msg);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ret = LDB_SUCCESS;
+ }
+ TALLOC_FREE(msg);
+ return ret;
+ }
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ ret = ldb_msg_add_fmt(msg, LDB_KV_IDXVERSION, "%u",
+ LDB_KV_INDEXING_VERSION);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(msg);
+ return ldb_module_oom(module);
+ }
+ } else {
+ ret = ldb_msg_add_fmt(msg, LDB_KV_IDXVERSION, "%u",
+ LDB_KV_GUID_INDEXING_VERSION);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(msg);
+ return ldb_module_oom(module);
+ }
+ }
+
+ if (list->count > 0) {
+ struct ldb_message_element *el;
+
+ ret = ldb_msg_add_empty(msg, LDB_KV_IDX, LDB_FLAG_MOD_ADD, &el);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(msg);
+ return ldb_module_oom(module);
+ }
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ el->values = list->dn;
+ el->num_values = list->count;
+ } else {
+ struct ldb_val v;
+ unsigned int i;
+ el->values = talloc_array(msg,
+ struct ldb_val, 1);
+ if (el->values == NULL) {
+ TALLOC_FREE(msg);
+ return ldb_module_oom(module);
+ }
+
+ v.data = talloc_array_size(el->values,
+ list->count,
+ LDB_KV_GUID_SIZE);
+ if (v.data == NULL) {
+ TALLOC_FREE(msg);
+ return ldb_module_oom(module);
+ }
+
+ v.length = talloc_get_size(v.data);
+
+ for (i = 0; i < list->count; i++) {
+ if (list->dn[i].length !=
+ LDB_KV_GUID_SIZE) {
+ TALLOC_FREE(msg);
+ return ldb_module_operr(module);
+ }
+ memcpy(&v.data[LDB_KV_GUID_SIZE*i],
+ list->dn[i].data,
+ LDB_KV_GUID_SIZE);
+ }
+ el->values[0] = v;
+ el->num_values = 1;
+ }
+ }
+
+ ret = ldb_kv_store(module, msg, TDB_REPLACE);
+ TALLOC_FREE(msg);
+ return ret;
+}
+
+/*
+ save a dn_list into the database, in either @IDX or internal format
+ */
+static int ldb_kv_dn_list_store(struct ldb_module *module,
+ struct ldb_dn *dn,
+ struct dn_list *list)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ TDB_DATA rec = {0};
+ TDB_DATA key = {0};
+
+ int ret = LDB_SUCCESS;
+ struct dn_list *list2 = NULL;
+ struct ldb_kv_idxptr *idxptr = NULL;
+
+ key.dptr = discard_const_p(unsigned char, ldb_dn_get_linearized(dn));
+ if (key.dptr == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ key.dsize = strlen((char *)key.dptr);
+
+ /*
+ * If there is an index sub transaction active, update the
+ * sub transaction index cache. Otherwise update the
+ * primary index cache
+ */
+ if (ldb_kv->nested_idx_ptr != NULL) {
+ idxptr = ldb_kv->nested_idx_ptr;
+ } else {
+ idxptr = ldb_kv->idxptr;
+ }
+ /*
+ * Get the cache entry for the index
+ *
+ * As the value in the cache is a pointer to a dn_list we update
+ * the dn_list directly.
+ *
+ */
+ rec = tdb_fetch(idxptr->itdb, key);
+ if (rec.dptr != NULL) {
+ list2 = ldb_kv_index_idxptr(module, rec);
+ if (list2 == NULL) {
+ free(rec.dptr);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ free(rec.dptr);
+ /* Now put the updated pointer back in the cache */
+ if (list->dn == NULL) {
+ list2->dn = NULL;
+ list2->count = 0;
+ } else {
+ list2->dn = talloc_steal(list2, list->dn);
+ list2->count = list->count;
+ }
+ return LDB_SUCCESS;
+ }
+
+ list2 = talloc(idxptr, struct dn_list);
+ if (list2 == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ list2->dn = talloc_steal(list2, list->dn);
+ list2->count = list->count;
+
+ rec.dptr = (uint8_t *)&list2;
+ rec.dsize = sizeof(void *);
+
+
+ /*
+ * This is not a store into the main DB, but into an in-memory
+ * TDB, so we don't need a guard on ltdb->read_only
+ *
+ * Also as we directly update the in memory dn_list for existing
+ * cache entries we must be adding a new entry to the cache.
+ */
+ ret = tdb_store(idxptr->itdb, key, rec, TDB_INSERT);
+ if (ret != 0) {
+ return ltdb_err_map( tdb_error(idxptr->itdb));
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ traverse function for storing the in-memory index entries on disk
+ */
+static int ldb_kv_index_traverse_store(_UNUSED_ struct tdb_context *tdb,
+ TDB_DATA key,
+ TDB_DATA data,
+ void *state)
+{
+ struct ldb_module *module = state;
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ struct ldb_dn *dn;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_val v;
+ struct dn_list *list;
+
+ list = ldb_kv_index_idxptr(module, data);
+ if (list == NULL) {
+ ldb_kv->idxptr->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ v.data = key.dptr;
+ v.length = strnlen((char *)key.dptr, key.dsize);
+
+ dn = ldb_dn_from_ldb_val(module, ldb, &v);
+ if (dn == NULL) {
+ ldb_asprintf_errstring(ldb, "Failed to parse index key %*.*s as an LDB DN", (int)v.length, (int)v.length, (const char *)v.data);
+ ldb_kv->idxptr->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ ldb_kv->idxptr->error =
+ ldb_kv_dn_list_store_full(module, ldb_kv, dn, list);
+ talloc_free(dn);
+ if (ldb_kv->idxptr->error != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/* cleanup the idxptr mode when transaction commits */
+int ldb_kv_index_transaction_commit(struct ldb_module *module)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ int ret;
+
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ ldb_reset_err_string(ldb);
+
+ if (ldb_kv->idxptr->itdb) {
+ tdb_traverse(
+ ldb_kv->idxptr->itdb, ldb_kv_index_traverse_store, module);
+ tdb_close(ldb_kv->idxptr->itdb);
+ }
+
+ ret = ldb_kv->idxptr->error;
+ if (ret != LDB_SUCCESS) {
+ if (!ldb_errstring(ldb)) {
+ ldb_set_errstring(ldb, ldb_strerror(ret));
+ }
+ ldb_asprintf_errstring(ldb, "Failed to store index records in transaction commit: %s", ldb_errstring(ldb));
+ }
+
+ talloc_free(ldb_kv->idxptr);
+ ldb_kv->idxptr = NULL;
+ return ret;
+}
+
+/* cleanup the idxptr mode when transaction cancels */
+int ldb_kv_index_transaction_cancel(struct ldb_module *module)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ if (ldb_kv->idxptr && ldb_kv->idxptr->itdb) {
+ tdb_close(ldb_kv->idxptr->itdb);
+ }
+ TALLOC_FREE(ldb_kv->idxptr);
+ if (ldb_kv->nested_idx_ptr && ldb_kv->nested_idx_ptr->itdb) {
+ tdb_close(ldb_kv->nested_idx_ptr->itdb);
+ }
+ TALLOC_FREE(ldb_kv->nested_idx_ptr);
+ return LDB_SUCCESS;
+}
+
+
+/*
+ return the dn key to be used for an index
+ the caller is responsible for freeing
+*/
+static struct ldb_dn *ldb_kv_index_key(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_kv_private *ldb_kv,
+ const char *attr,
+ const struct ldb_val *value,
+ const struct ldb_schema_attribute **ap,
+ enum key_truncation *truncation)
+{
+ struct ldb_dn *ret;
+ struct ldb_val v;
+ const struct ldb_schema_attribute *a = NULL;
+ char *attr_folded = NULL;
+ const char *attr_for_dn = NULL;
+ int r;
+ bool should_b64_encode;
+
+ unsigned int max_key_length = ldb_kv_max_key_length(ldb_kv);
+ size_t key_len = 0;
+ size_t attr_len = 0;
+ const size_t indx_len = sizeof(LDB_KV_INDEX) - 1;
+ unsigned frmt_len = 0;
+ const size_t additional_key_length = 4;
+ unsigned int num_separators = 3; /* Estimate for overflow check */
+ const size_t min_data = 1;
+ const size_t min_key_length = additional_key_length
+ + indx_len + num_separators + min_data;
+ struct ldb_val empty;
+
+ /*
+ * Accept a NULL value as a request for a key with no value. This is
+ * different from passing an empty value, which might be given
+ * significance by some canonicalise functions.
+ */
+ bool empty_val = value == NULL;
+ if (empty_val) {
+ empty.length = 0;
+ empty.data = discard_const_p(unsigned char, "");
+ value = &empty;
+ }
+
+ if (attr[0] == '@') {
+ attr_for_dn = attr;
+ v = *value;
+ if (ap != NULL) {
+ *ap = NULL;
+ }
+ } else {
+ attr_folded = ldb_attr_casefold(ldb, attr);
+ if (!attr_folded) {
+ return NULL;
+ }
+
+ attr_for_dn = attr_folded;
+
+ a = ldb_schema_attribute_by_name(ldb, attr);
+ if (ap) {
+ *ap = a;
+ }
+
+ if (empty_val) {
+ v = *value;
+ } else {
+ ldb_attr_handler_t fn;
+ if (a->syntax->index_format_fn &&
+ ldb_kv->cache->GUID_index_attribute != NULL) {
+ fn = a->syntax->index_format_fn;
+ } else {
+ fn = a->syntax->canonicalise_fn;
+ }
+ r = fn(ldb, ldb, value, &v);
+ if (r != LDB_SUCCESS) {
+ const char *errstr = ldb_errstring(ldb);
+ /* canonicalisation can be refused. For
+ example, a attribute that takes wildcards
+ will refuse to canonicalise if the value
+ contains a wildcard */
+ ldb_asprintf_errstring(ldb,
+ "Failed to create "
+ "index key for "
+ "attribute '%s':%s%s%s",
+ attr, ldb_strerror(r),
+ (errstr?":":""),
+ (errstr?errstr:""));
+ talloc_free(attr_folded);
+ return NULL;
+ }
+ }
+ }
+ attr_len = strlen(attr_for_dn);
+
+ /*
+ * Check if there is any hope this will fit into the DB.
+ * Overflow here is not actually critical the code below
+ * checks again to make the printf and the DB does another
+ * check for too long keys
+ */
+ if (max_key_length - attr_len < min_key_length) {
+ ldb_asprintf_errstring(
+ ldb,
+ __location__ ": max_key_length "
+ "is too small (%u) < (%u)",
+ max_key_length,
+ (unsigned)(min_key_length + attr_len));
+ talloc_free(attr_folded);
+ return NULL;
+ }
+
+ /*
+ * ltdb_key_dn() makes something 4 bytes longer, it adds a leading
+ * "DN=" and a trailing string terminator
+ */
+ max_key_length -= additional_key_length;
+
+ /*
+ * We do not base 64 encode a DN in a key, it has already been
+ * casefolded and linearized, that is good enough. That already
+ * avoids embedded NUL etc.
+ */
+ if (ldb_kv->cache->GUID_index_attribute != NULL) {
+ if (strcmp(attr, LDB_KV_IDXDN) == 0) {
+ should_b64_encode = false;
+ } else if (strcmp(attr, LDB_KV_IDXONE) == 0) {
+ /*
+ * We can only change the behaviour for IDXONE
+ * when the GUID index is enabled
+ */
+ should_b64_encode = false;
+ } else {
+ should_b64_encode
+ = ldb_should_b64_encode(ldb, &v);
+ }
+ } else {
+ should_b64_encode = ldb_should_b64_encode(ldb, &v);
+ }
+
+ if (should_b64_encode) {
+ size_t vstr_len = 0;
+ char *vstr = ldb_base64_encode(mem_ctx, (char *)v.data, v.length);
+ if (!vstr) {
+ talloc_free(attr_folded);
+ return NULL;
+ }
+ vstr_len = strlen(vstr);
+ /*
+ * Overflow here is not critical as we only use this
+ * to choose the printf truncation
+ */
+ key_len = num_separators + indx_len + attr_len + vstr_len;
+ if (key_len > max_key_length) {
+ size_t excess = key_len - max_key_length;
+ frmt_len = vstr_len - excess;
+ *truncation = KEY_TRUNCATED;
+ /*
+ * Truncated keys are placed in a separate key space
+ * from the non truncated keys
+ * Note: the double hash "##" is not a typo and
+ * indicates that the following value is base64 encoded
+ */
+ ret = ldb_dn_new_fmt(mem_ctx, ldb, "%s#%s##%.*s",
+ LDB_KV_INDEX, attr_for_dn,
+ frmt_len, vstr);
+ } else {
+ frmt_len = vstr_len;
+ *truncation = KEY_NOT_TRUNCATED;
+ /*
+ * Note: the double colon "::" is not a typo and
+ * indicates that the following value is base64 encoded
+ */
+ ret = ldb_dn_new_fmt(mem_ctx, ldb, "%s:%s::%.*s",
+ LDB_KV_INDEX, attr_for_dn,
+ frmt_len, vstr);
+ }
+ talloc_free(vstr);
+ } else {
+ /* Only need two separators */
+ num_separators = 2;
+
+ /*
+ * Overflow here is not critical as we only use this
+ * to choose the printf truncation
+ */
+ key_len = num_separators + indx_len + attr_len + (int)v.length;
+ if (key_len > max_key_length) {
+ size_t excess = key_len - max_key_length;
+ frmt_len = v.length - excess;
+ *truncation = KEY_TRUNCATED;
+ /*
+ * Truncated keys are placed in a separate key space
+ * from the non truncated keys
+ */
+ ret = ldb_dn_new_fmt(mem_ctx, ldb, "%s#%s#%.*s",
+ LDB_KV_INDEX, attr_for_dn,
+ frmt_len, (char *)v.data);
+ } else {
+ frmt_len = v.length;
+ *truncation = KEY_NOT_TRUNCATED;
+ ret = ldb_dn_new_fmt(mem_ctx, ldb, "%s:%s:%.*s",
+ LDB_KV_INDEX, attr_for_dn,
+ frmt_len, (char *)v.data);
+ }
+ }
+
+ if (value != NULL && v.data != value->data && !empty_val) {
+ talloc_free(v.data);
+ }
+ talloc_free(attr_folded);
+
+ return ret;
+}
+
+/*
+ see if a attribute value is in the list of indexed attributes
+*/
+static bool ldb_kv_is_indexed(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const char *attr)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ unsigned int i;
+ struct ldb_message_element *el;
+
+ if ((ldb_kv->cache->GUID_index_attribute != NULL) &&
+ (ldb_attr_cmp(attr, ldb_kv->cache->GUID_index_attribute) == 0)) {
+ /* Implicitly covered, this is the index key */
+ return false;
+ }
+ if (ldb->schema.index_handler_override) {
+ const struct ldb_schema_attribute *a
+ = ldb_schema_attribute_by_name(ldb, attr);
+
+ if (a == NULL) {
+ return false;
+ }
+
+ if (a->flags & LDB_ATTR_FLAG_INDEXED) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ if (!ldb_kv->cache->attribute_indexes) {
+ return false;
+ }
+
+ el = ldb_msg_find_element(ldb_kv->cache->indexlist, LDB_KV_IDXATTR);
+ if (el == NULL) {
+ return false;
+ }
+
+ /* TODO: this is too expensive! At least use a binary search */
+ for (i=0; i<el->num_values; i++) {
+ if (ldb_attr_cmp((char *)el->values[i].data, attr) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ in the following logic functions, the return value is treated as
+ follows:
+
+ LDB_SUCCESS: we found some matching index values
+
+ LDB_ERR_NO_SUCH_OBJECT: we know for sure that no object matches
+
+ LDB_ERR_OPERATIONS_ERROR: indexing could not answer the call,
+ we'll need a full search
+ */
+
+/*
+ return a list of dn's that might match a simple indexed search (an
+ equality search only)
+ */
+static int ldb_kv_index_dn_simple(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *dn;
+ int ret;
+ enum key_truncation truncation = KEY_NOT_TRUNCATED;
+
+ ldb = ldb_module_get_ctx(module);
+
+ list->count = 0;
+ list->dn = NULL;
+
+ /* if the attribute isn't in the list of indexed attributes then
+ this node needs a full search */
+ if (!ldb_kv_is_indexed(module, ldb_kv, tree->u.equality.attr)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * the attribute is indexed. Pull the list of DNs that match the
+ * search criterion
+ *
+ * list is used as a memory context as it has a shorter life
+ * than 'ldb'. Regardless we talloc_free() 'dn' below.
+ */
+ dn = ldb_kv_index_key(ldb,
+ list,
+ ldb_kv,
+ tree->u.equality.attr,
+ &tree->u.equality.value,
+ NULL,
+ &truncation);
+ /*
+ * We ignore truncation here and allow multi-valued matches
+ * as ltdb_search_indexed will filter out the wrong one in
+ * ltdb_index_filter() which calls ldb_match_message().
+ */
+ if (!dn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_dn_list_load(module, ldb_kv, dn, list,
+ DN_LIST_WILL_BE_READ_ONLY);
+ talloc_free(dn);
+ return ret;
+}
+
+static bool list_union(struct ldb_context *ldb,
+ struct ldb_kv_private *ldb_kv,
+ struct dn_list *list,
+ struct dn_list *list2);
+
+/*
+ return a list of dn's that might match a leaf indexed search
+ */
+static int ldb_kv_index_dn_leaf(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list)
+{
+ if (ldb_kv->disallow_dn_filter &&
+ (ldb_attr_cmp(tree->u.equality.attr, "dn") == 0)) {
+ /* in AD mode we do not support "(dn=...)" search filters */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
+ if (tree->u.equality.attr[0] == '@') {
+ /* Do not allow a indexed search against an @ */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
+ if (ldb_attr_dn(tree->u.equality.attr) == 0) {
+ enum key_truncation truncation = KEY_NOT_TRUNCATED;
+ bool valid_dn = false;
+ struct ldb_dn *dn
+ = ldb_dn_from_ldb_val(list,
+ ldb_module_get_ctx(module),
+ &tree->u.equality.value);
+ if (dn == NULL) {
+ /* If we can't parse it, no match */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
+
+ valid_dn = ldb_dn_validate(dn);
+ if (valid_dn == false) {
+ /* If we can't parse it, no match */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * Re-use the same code we use for a SCOPE_BASE
+ * search
+ *
+ * We can't call TALLOC_FREE(dn) as this must belong
+ * to list for the memory to remain valid.
+ */
+ return ldb_kv_index_dn_base_dn(
+ module, ldb_kv, dn, list, &truncation);
+ /*
+ * We ignore truncation here and allow multi-valued matches
+ * as ltdb_search_indexed will filter out the wrong one in
+ * ltdb_index_filter() which calls ldb_match_message().
+ */
+
+ } else if ((ldb_kv->cache->GUID_index_attribute != NULL) &&
+ (ldb_attr_cmp(tree->u.equality.attr,
+ ldb_kv->cache->GUID_index_attribute) == 0)) {
+ int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ list->dn = talloc_array(list, struct ldb_val, 1);
+ if (list->dn == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /*
+ * We need to go via the canonicalise_fn() to
+ * ensure we get the index in binary, rather
+ * than a string
+ */
+ ret = ldb_kv->GUID_index_syntax->canonicalise_fn(
+ ldb, list->dn, &tree->u.equality.value, &list->dn[0]);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ list->count = 1;
+ return LDB_SUCCESS;
+ }
+
+ return ldb_kv_index_dn_simple(module, ldb_kv, tree, list);
+}
+
+
+/*
+ list intersection
+ list = list & list2
+*/
+static bool list_intersect(struct ldb_kv_private *ldb_kv,
+ struct dn_list *list,
+ const struct dn_list *list2)
+{
+ const struct dn_list *short_list, *long_list;
+ struct dn_list *list3;
+ unsigned int i;
+
+ if (list->count == 0) {
+ /* 0 & X == 0 */
+ return true;
+ }
+ if (list2->count == 0) {
+ /* X & 0 == 0 */
+ list->count = 0;
+ list->dn = NULL;
+ return true;
+ }
+
+ /*
+ * In both of the below we check for strict and in that
+ * case do not optimise the intersection of this list,
+ * we must never return an entry not in this
+ * list. This allows the index for
+ * SCOPE_ONELEVEL to be trusted.
+ */
+
+ /* the indexing code is allowed to return a longer list than
+ what really matches, as all results are filtered by the
+ full expression at the end - this shortcut avoids a lot of
+ work in some cases */
+ if (list->count < 2 && list2->count > 10 && list2->strict == false) {
+ return true;
+ }
+ if (list2->count < 2 && list->count > 10 && list->strict == false) {
+ list->count = list2->count;
+ list->dn = list2->dn;
+ /* note that list2 may not be the parent of list2->dn,
+ as list2->dn may be owned by ltdb->idxptr. In that
+ case we expect this reparent call to fail, which is
+ OK */
+ talloc_reparent(list2, list, list2->dn);
+ return true;
+ }
+
+ if (list->count > list2->count) {
+ short_list = list2;
+ long_list = list;
+ } else {
+ short_list = list;
+ long_list = list2;
+ }
+
+ list3 = talloc_zero(list, struct dn_list);
+ if (list3 == NULL) {
+ return false;
+ }
+
+ list3->dn = talloc_array(list3, struct ldb_val,
+ MIN(list->count, list2->count));
+ if (!list3->dn) {
+ talloc_free(list3);
+ return false;
+ }
+ list3->count = 0;
+
+ for (i=0;i<short_list->count;i++) {
+ /* For the GUID index case, this is a binary search */
+ if (ldb_kv_dn_list_find_val(
+ ldb_kv, long_list, &short_list->dn[i]) != -1) {
+ list3->dn[list3->count] = short_list->dn[i];
+ list3->count++;
+ }
+ }
+
+ list->strict |= list2->strict;
+ list->dn = talloc_steal(list, list3->dn);
+ list->count = list3->count;
+ talloc_free(list3);
+
+ return true;
+}
+
+
+/*
+ list union
+ list = list | list2
+*/
+static bool list_union(struct ldb_context *ldb,
+ struct ldb_kv_private *ldb_kv,
+ struct dn_list *list,
+ struct dn_list *list2)
+{
+ struct ldb_val *dn3;
+ unsigned int i = 0, j = 0, k = 0;
+
+ if (list2->count == 0) {
+ /* X | 0 == X */
+ return true;
+ }
+
+ if (list->count == 0) {
+ /* 0 | X == X */
+ list->count = list2->count;
+ list->dn = list2->dn;
+ /* note that list2 may not be the parent of list2->dn,
+ as list2->dn may be owned by ltdb->idxptr. In that
+ case we expect this reparent call to fail, which is
+ OK */
+ talloc_reparent(list2, list, list2->dn);
+ return true;
+ }
+
+ /*
+ * Sort the lists (if not in GUID DN mode) so we can do
+ * the de-duplication during the merge
+ *
+ * NOTE: This can sort the in-memory index values, as list or
+ * list2 might not be a copy!
+ */
+ ldb_kv_dn_list_sort(ldb_kv, list);
+ ldb_kv_dn_list_sort(ldb_kv, list2);
+
+ dn3 = talloc_array(list, struct ldb_val, list->count + list2->count);
+ if (!dn3) {
+ ldb_oom(ldb);
+ return false;
+ }
+
+ while (i < list->count || j < list2->count) {
+ int cmp;
+ if (i >= list->count) {
+ cmp = 1;
+ } else if (j >= list2->count) {
+ cmp = -1;
+ } else {
+ cmp = ldb_val_equal_exact_ordered(list->dn[i],
+ &list2->dn[j]);
+ }
+
+ if (cmp < 0) {
+ /* Take list */
+ dn3[k] = list->dn[i];
+ i++;
+ k++;
+ } else if (cmp > 0) {
+ /* Take list2 */
+ dn3[k] = list2->dn[j];
+ j++;
+ k++;
+ } else {
+ /* Equal, take list */
+ dn3[k] = list->dn[i];
+ i++;
+ j++;
+ k++;
+ }
+ }
+
+ list->dn = dn3;
+ list->count = k;
+
+ return true;
+}
+
+static int ldb_kv_index_dn(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list);
+
+/*
+ process an OR list (a union)
+ */
+static int ldb_kv_index_dn_or(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list)
+{
+ struct ldb_context *ldb;
+ unsigned int i;
+
+ ldb = ldb_module_get_ctx(module);
+
+ list->dn = NULL;
+ list->count = 0;
+
+ for (i=0; i<tree->u.list.num_elements; i++) {
+ struct dn_list *list2;
+ int ret;
+
+ list2 = talloc_zero(list, struct dn_list);
+ if (list2 == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_index_dn(
+ module, ldb_kv, tree->u.list.elements[i], list2);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* X || 0 == X */
+ talloc_free(list2);
+ continue;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ /* X || * == * */
+ talloc_free(list2);
+ return ret;
+ }
+
+ if (!list_union(ldb, ldb_kv, list, list2)) {
+ talloc_free(list2);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ if (list->count == 0) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ NOT an index results
+ */
+static int ldb_kv_index_dn_not(_UNUSED_ struct ldb_module *module,
+ _UNUSED_ struct ldb_kv_private *ldb_kv,
+ _UNUSED_ const struct ldb_parse_tree *tree,
+ _UNUSED_ struct dn_list *list)
+{
+ /* the only way to do an indexed not would be if we could
+ negate the not via another not or if we knew the total
+ number of database elements so we could know that the
+ existing expression covered the whole database.
+
+ instead, we just give up, and rely on a full index scan
+ (unless an outer & manages to reduce the list)
+ */
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+ * These things are unique, so avoid a full scan if this is a search
+ * by GUID, DN or a unique attribute
+ */
+static bool ldb_kv_index_unique(struct ldb_context *ldb,
+ struct ldb_kv_private *ldb_kv,
+ const char *attr)
+{
+ const struct ldb_schema_attribute *a;
+ if (ldb_kv->cache->GUID_index_attribute != NULL) {
+ if (ldb_attr_cmp(attr, ldb_kv->cache->GUID_index_attribute) ==
+ 0) {
+ return true;
+ }
+ }
+ if (ldb_attr_dn(attr) == 0) {
+ return true;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, attr);
+ if (a->flags & LDB_ATTR_FLAG_UNIQUE_INDEX) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ process an AND expression (intersection)
+ */
+static int ldb_kv_index_dn_and(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list)
+{
+ struct ldb_context *ldb;
+ unsigned int i;
+ bool found;
+
+ ldb = ldb_module_get_ctx(module);
+
+ list->dn = NULL;
+ list->count = 0;
+
+ /* in the first pass we only look for unique simple
+ equality tests, in the hope of avoiding having to look
+ at any others */
+ for (i=0; i<tree->u.list.num_elements; i++) {
+ const struct ldb_parse_tree *subtree = tree->u.list.elements[i];
+ int ret;
+
+ if (subtree->operation != LDB_OP_EQUALITY ||
+ !ldb_kv_index_unique(
+ ldb, ldb_kv, subtree->u.equality.attr)) {
+ continue;
+ }
+
+ ret = ldb_kv_index_dn(module, ldb_kv, subtree, list);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* 0 && X == 0 */
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ if (ret == LDB_SUCCESS) {
+ /* a unique index match means we can
+ * stop. Note that we don't care if we return
+ * a few too many objects, due to later
+ * filtering */
+ return LDB_SUCCESS;
+ }
+ }
+
+ /* now do a full intersection */
+ found = false;
+
+ for (i=0; i<tree->u.list.num_elements; i++) {
+ const struct ldb_parse_tree *subtree = tree->u.list.elements[i];
+ struct dn_list *list2;
+ int ret;
+
+ list2 = talloc_zero(list, struct dn_list);
+ if (list2 == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ ret = ldb_kv_index_dn(module, ldb_kv, subtree, list2);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* X && 0 == 0 */
+ list->dn = NULL;
+ list->count = 0;
+ talloc_free(list2);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ /* this didn't adding anything */
+ talloc_free(list2);
+ continue;
+ }
+
+ if (!found) {
+ talloc_reparent(list2, list, list->dn);
+ list->dn = list2->dn;
+ list->count = list2->count;
+ found = true;
+ } else if (!list_intersect(ldb_kv, list, list2)) {
+ talloc_free(list2);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (list->count == 0) {
+ list->dn = NULL;
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ if (list->count < 2) {
+ /* it isn't worth loading the next part of the tree */
+ return LDB_SUCCESS;
+ }
+ }
+
+ if (!found) {
+ /* none of the attributes were indexed */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+struct ldb_kv_ordered_index_context {
+ struct ldb_module *module;
+ int error;
+ struct dn_list *dn_list;
+};
+
+static int traverse_range_index(_UNUSED_ struct ldb_kv_private *ldb_kv,
+ _UNUSED_ struct ldb_val key,
+ struct ldb_val data,
+ void *state)
+{
+
+ struct ldb_context *ldb;
+ struct ldb_kv_ordered_index_context *ctx =
+ (struct ldb_kv_ordered_index_context *)state;
+ struct ldb_module *module = ctx->module;
+ struct ldb_message_element *el = NULL;
+ struct ldb_message *msg = NULL;
+ int version;
+ size_t dn_array_size, additional_length;
+ unsigned int i;
+
+ ldb = ldb_module_get_ctx(module);
+
+ msg = ldb_msg_new(module);
+
+ ctx->error = ldb_unpack_data_flags(ldb, &data, msg,
+ LDB_UNPACK_DATA_FLAG_NO_DN);
+
+ if (ctx->error != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ctx->error;
+ }
+
+ el = ldb_msg_find_element(msg, LDB_KV_IDX);
+ if (!el) {
+ talloc_free(msg);
+ return LDB_SUCCESS;
+ }
+
+ version = ldb_msg_find_attr_as_int(msg, LDB_KV_IDXVERSION, 0);
+
+ /*
+ * we avoid copying the strings by stealing the list. We have
+ * to steal msg onto el->values (which looks odd) because
+ * the memory is allocated on msg, not on each value.
+ */
+ if (version != LDB_KV_GUID_INDEXING_VERSION) {
+ /* This is quite likely during the DB startup
+ on first upgrade to using a GUID index */
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_ERROR, __location__
+ ": Wrong GUID index version %d expected %d",
+ version, LDB_KV_GUID_INDEXING_VERSION);
+ talloc_free(msg);
+ ctx->error = LDB_ERR_OPERATIONS_ERROR;
+ return ctx->error;
+ }
+
+ if (el->num_values == 0) {
+ talloc_free(msg);
+ ctx->error = LDB_ERR_OPERATIONS_ERROR;
+ return ctx->error;
+ }
+
+ if ((el->values[0].length % LDB_KV_GUID_SIZE) != 0
+ || el->values[0].length == 0) {
+ talloc_free(msg);
+ ctx->error = LDB_ERR_OPERATIONS_ERROR;
+ return ctx->error;
+ }
+
+ dn_array_size = talloc_array_length(ctx->dn_list->dn);
+
+ additional_length = el->values[0].length / LDB_KV_GUID_SIZE;
+
+ if (ctx->dn_list->count + additional_length < ctx->dn_list->count) {
+ talloc_free(msg);
+ ctx->error = LDB_ERR_OPERATIONS_ERROR;
+ return ctx->error;
+ }
+
+ if ((ctx->dn_list->count + additional_length) >= dn_array_size) {
+ size_t new_array_length;
+
+ if (dn_array_size * 2 < dn_array_size) {
+ talloc_free(msg);
+ ctx->error = LDB_ERR_OPERATIONS_ERROR;
+ return ctx->error;
+ }
+
+ new_array_length = MAX(ctx->dn_list->count + additional_length,
+ dn_array_size * 2);
+
+ ctx->dn_list->dn = talloc_realloc(ctx->dn_list,
+ ctx->dn_list->dn,
+ struct ldb_val,
+ new_array_length);
+ }
+
+ if (ctx->dn_list->dn == NULL) {
+ talloc_free(msg);
+ ctx->error = LDB_ERR_OPERATIONS_ERROR;
+ return ctx->error;
+ }
+
+ /*
+ * The actual data is on msg.
+ */
+ talloc_steal(ctx->dn_list->dn, msg);
+ for (i = 0; i < additional_length; i++) {
+ ctx->dn_list->dn[i + ctx->dn_list->count].data
+ = &el->values[0].data[i * LDB_KV_GUID_SIZE];
+ ctx->dn_list->dn[i + ctx->dn_list->count].length = LDB_KV_GUID_SIZE;
+
+ }
+
+ ctx->dn_list->count += additional_length;
+
+ talloc_free(msg->elements);
+
+ return LDB_SUCCESS;
+}
+
+/*
+ * >= and <= indexing implemented using lexicographically sorted keys
+ *
+ * We only run this in GUID indexing mode and when there is no write
+ * transaction (only implicit read locks are being held). Otherwise, we would
+ * have to deal with the in-memory index cache.
+ *
+ * We rely on the implementation of index_format_fn on a schema syntax which
+ * will can help us to construct keys which can be ordered correctly, and we
+ * terminate using schema agnostic start and end keys.
+ *
+ * index_format_fn must output values which can be memcmp-able to produce the
+ * correct ordering as defined by the schema syntax class.
+ */
+static int ldb_kv_index_dn_ordered(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list, bool ascending)
+{
+ enum key_truncation truncation = KEY_NOT_TRUNCATED;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ struct ldb_val ldb_key = { 0 }, ldb_key2 = { 0 };
+ struct ldb_val start_key, end_key;
+ struct ldb_dn *key_dn = NULL;
+ const struct ldb_schema_attribute *a = NULL;
+
+ struct ldb_kv_ordered_index_context ctx;
+ int ret;
+
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ if (!ldb_kv_is_indexed(module, ldb_kv, tree->u.comparison.attr)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* bail out if we're in a transaction, full search instead. */
+ if (ldb_kv->kv_ops->transaction_active(ldb_kv)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ldb_kv->disallow_dn_filter &&
+ (ldb_attr_cmp(tree->u.comparison.attr, "dn") == 0)) {
+ /* in AD mode we do not support "(dn=...)" search filters */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
+ if (tree->u.comparison.attr[0] == '@') {
+ /* Do not allow a indexed search against an @ */
+ list->dn = NULL;
+ list->count = 0;
+ return LDB_SUCCESS;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, tree->u.comparison.attr);
+
+ /*
+ * If there's no index format function defined for this attr, then
+ * the lexicographic order in the database doesn't correspond to the
+ * attr's ordering, so we can't use the iterate_range op.
+ */
+ if (a->syntax->index_format_fn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ key_dn = ldb_kv_index_key(ldb, tmp_ctx, ldb_kv, tree->u.comparison.attr,
+ &tree->u.comparison.value,
+ NULL, &truncation);
+ if (!key_dn) {
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ } else if (truncation == KEY_TRUNCATED) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ __location__
+ ": ordered index violation: key dn truncated: %s\n",
+ ldb_dn_get_linearized(key_dn));
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ldb_key = ldb_kv_key_dn(tmp_ctx, key_dn);
+ talloc_free(key_dn);
+ if (ldb_key.data == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ key_dn = ldb_kv_index_key(ldb, tmp_ctx,
+ ldb_kv, tree->u.comparison.attr,
+ NULL, NULL, &truncation);
+ if (!key_dn) {
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ } else if (truncation == KEY_TRUNCATED) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ __location__
+ ": ordered index violation: key dn truncated: %s\n",
+ ldb_dn_get_linearized(key_dn));
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_key2 = ldb_kv_key_dn(tmp_ctx, key_dn);
+ talloc_free(key_dn);
+ if (ldb_key2.data == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * In order to avoid defining a start and end key for the search, we
+ * notice that each index key is of the form:
+ *
+ * DN=@INDEX:<ATTRIBUTE>:<VALUE>\0.
+ *
+ * We can simply make our start key DN=@INDEX:<ATTRIBUTE>: and our end
+ * key DN=@INDEX:<ATTRIBUTE>; to return all index entries for a
+ * particular attribute.
+ *
+ * Our LMDB backend uses the default memcmp for key comparison.
+ */
+
+ /* Eliminate NUL byte at the end of the empty key */
+ ldb_key2.length--;
+
+ if (ascending) {
+ /* : becomes ; for pseudo end-key */
+ ldb_key2.data[ldb_key2.length-1]++;
+ start_key = ldb_key;
+ end_key = ldb_key2;
+ } else {
+ start_key = ldb_key2;
+ end_key = ldb_key;
+ }
+
+ ctx.module = module;
+ ctx.error = 0;
+ ctx.dn_list = list;
+ ctx.dn_list->count = 0;
+ ctx.dn_list->dn = talloc_zero_array(ctx.dn_list, struct ldb_val, 2);
+
+ ret = ldb_kv->kv_ops->iterate_range(ldb_kv, start_key, end_key,
+ traverse_range_index, &ctx);
+
+ if (ret != LDB_SUCCESS || ctx.error != LDB_SUCCESS) {
+ TALLOC_FREE(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ TYPESAFE_QSORT(ctx.dn_list->dn, ctx.dn_list->count,
+ ldb_val_equal_exact_for_qsort);
+
+ TALLOC_FREE(tmp_ctx);
+
+ return LDB_SUCCESS;
+}
+
+static int ldb_kv_index_dn_greater(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list)
+{
+ return ldb_kv_index_dn_ordered(module,
+ ldb_kv,
+ tree,
+ list, true);
+}
+
+static int ldb_kv_index_dn_less(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list)
+{
+ return ldb_kv_index_dn_ordered(module,
+ ldb_kv,
+ tree,
+ list, false);
+}
+
+/*
+ return a list of matching objects using a one-level index
+ */
+static int ldb_kv_index_dn_attr(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const char *attr,
+ struct ldb_dn *dn,
+ struct dn_list *list,
+ enum key_truncation *truncation)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *key;
+ struct ldb_val val;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* work out the index key from the parent DN */
+ val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(dn));
+ if (val.data == NULL) {
+ const char *dn_str = ldb_dn_get_linearized(dn);
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__
+ ": Failed to get casefold DN "
+ "from: %s",
+ dn_str);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ val.length = strlen((char *)val.data);
+
+ /*
+ * We use list as a TALLOC_CTX to provide a shorter-lived
+ * memory context than ldb, even as the result is freed with
+ * the talloc_free(key) below.
+ */
+ key = ldb_kv_index_key(ldb, list, ldb_kv, attr, &val, NULL, truncation);
+ if (!key) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_dn_list_load(module, ldb_kv, key, list,
+ DN_LIST_WILL_BE_READ_ONLY);
+ talloc_free(key);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (list->count == 0) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ return a list of matching objects using a one-level index
+ */
+static int ldb_kv_index_dn_one(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ struct ldb_dn *parent_dn,
+ struct dn_list *list,
+ enum key_truncation *truncation)
+{
+ int ret = ldb_kv_index_dn_attr(
+ module, ldb_kv, LDB_KV_IDXONE, parent_dn, list, truncation);
+ if (ret == LDB_SUCCESS) {
+ /*
+ * Ensure we do not shortcut on intersection for this
+ * list. We must never be lazy and return an entry
+ * not in this list. This allows the index for
+ * SCOPE_ONELEVEL to be trusted.
+ */
+
+ list->strict = true;
+ }
+ return ret;
+}
+
+/*
+ return a list of matching objects using the DN index
+ */
+static int ldb_kv_index_dn_base_dn(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ struct ldb_dn *base_dn,
+ struct dn_list *dn_list,
+ enum key_truncation *truncation)
+{
+ const struct ldb_val *guid_val = NULL;
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
+ if (dn_list->dn == NULL) {
+ return ldb_module_oom(module);
+ }
+ dn_list->dn[0].data = discard_const_p(unsigned char,
+ ldb_dn_get_linearized(base_dn));
+ if (dn_list->dn[0].data == NULL) {
+ talloc_free(dn_list->dn);
+ return ldb_module_oom(module);
+ }
+ dn_list->dn[0].length = strlen((char *)dn_list->dn[0].data);
+ dn_list->count = 1;
+
+ return LDB_SUCCESS;
+ }
+
+ if (ldb_kv->cache->GUID_index_dn_component != NULL) {
+ guid_val = ldb_dn_get_extended_component(
+ base_dn, ldb_kv->cache->GUID_index_dn_component);
+ }
+
+ if (guid_val != NULL) {
+ dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
+ if (dn_list->dn == NULL) {
+ return ldb_module_oom(module);
+ }
+ dn_list->dn[0].data = guid_val->data;
+ dn_list->dn[0].length = guid_val->length;
+ dn_list->count = 1;
+
+ return LDB_SUCCESS;
+ }
+
+ return ldb_kv_index_dn_attr(
+ module, ldb_kv, LDB_KV_IDXDN, base_dn, dn_list, truncation);
+}
+
+/*
+ return a list of dn's that might match a indexed search or
+ an error. return LDB_ERR_NO_SUCH_OBJECT for no matches, or LDB_SUCCESS for matches
+ */
+static int ldb_kv_index_dn(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_parse_tree *tree,
+ struct dn_list *list)
+{
+ int ret = LDB_ERR_OPERATIONS_ERROR;
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ ret = ldb_kv_index_dn_and(module, ldb_kv, tree, list);
+ break;
+
+ case LDB_OP_OR:
+ ret = ldb_kv_index_dn_or(module, ldb_kv, tree, list);
+ break;
+
+ case LDB_OP_NOT:
+ ret = ldb_kv_index_dn_not(module, ldb_kv, tree, list);
+ break;
+
+ case LDB_OP_EQUALITY:
+ ret = ldb_kv_index_dn_leaf(module, ldb_kv, tree, list);
+ break;
+
+ case LDB_OP_GREATER:
+ ret = ldb_kv_index_dn_greater(module, ldb_kv, tree, list);
+ break;
+
+ case LDB_OP_LESS:
+ ret = ldb_kv_index_dn_less(module, ldb_kv, tree, list);
+ break;
+
+ case LDB_OP_SUBSTRING:
+ case LDB_OP_PRESENT:
+ case LDB_OP_APPROX:
+ case LDB_OP_EXTENDED:
+ /* we can't index with fancy bitops yet */
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ filter a candidate dn_list from an indexed search into a set of results
+ extracting just the given attributes
+*/
+static int ldb_kv_index_filter(struct ldb_kv_private *ldb_kv,
+ const struct dn_list *dn_list,
+ struct ldb_kv_context *ac,
+ uint32_t *match_count,
+ enum key_truncation scope_one_truncation)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ struct ldb_message *msg;
+ unsigned int i;
+ unsigned int num_keys = 0;
+ uint8_t previous_guid_key[LDB_KV_GUID_KEY_SIZE] = {0};
+ struct ldb_val *keys = NULL;
+
+ /*
+ * We have to allocate the key list (rather than just walk the
+ * caller supplied list) as the callback could change the list
+ * (by modifying an indexed attribute hosted in the in-memory
+ * index cache!)
+ */
+ keys = talloc_array(ac, struct ldb_val, dn_list->count);
+ if (keys == NULL) {
+ return ldb_module_oom(ac->module);
+ }
+
+ if (ldb_kv->cache->GUID_index_attribute != NULL) {
+ /*
+ * We speculate that the keys will be GUID based and so
+ * pre-fill in enough space for a GUID (avoiding a pile of
+ * small allocations)
+ */
+ struct guid_tdb_key {
+ uint8_t guid_key[LDB_KV_GUID_KEY_SIZE];
+ } *key_values = NULL;
+
+ key_values = talloc_array(keys,
+ struct guid_tdb_key,
+ dn_list->count);
+
+ if (key_values == NULL) {
+ talloc_free(keys);
+ return ldb_module_oom(ac->module);
+ }
+ for (i = 0; i < dn_list->count; i++) {
+ keys[i].data = key_values[i].guid_key;
+ keys[i].length = sizeof(key_values[i].guid_key);
+ }
+ } else {
+ for (i = 0; i < dn_list->count; i++) {
+ keys[i].data = NULL;
+ keys[i].length = 0;
+ }
+ }
+
+ for (i = 0; i < dn_list->count; i++) {
+ int ret;
+
+ ret = ldb_kv_idx_to_key(
+ ac->module, ldb_kv, keys, &dn_list->dn[i], &keys[num_keys]);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(keys);
+ return ret;
+ }
+
+ if (ldb_kv->cache->GUID_index_attribute != NULL) {
+ /*
+ * If we are in GUID index mode, then the dn_list is
+ * sorted. If we got a duplicate, forget about it, as
+ * otherwise we would send the same entry back more
+ * than once.
+ *
+ * This is needed in the truncated DN case, or if a
+ * duplicate was forced in via
+ * LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
+ */
+
+ if (memcmp(previous_guid_key,
+ keys[num_keys].data,
+ sizeof(previous_guid_key)) == 0) {
+ continue;
+ }
+
+ memcpy(previous_guid_key,
+ keys[num_keys].data,
+ sizeof(previous_guid_key));
+ }
+ num_keys++;
+ }
+
+
+ /*
+ * Now that the list is a safe copy, send the callbacks
+ */
+ for (i = 0; i < num_keys; i++) {
+ int ret;
+ bool matched;
+
+ /*
+ * Check the time every 64 records, to reduce calls to
+ * gettimeofday(). This is a compromise, not all
+ * calls to ldb_match_message() will take the same
+ * time, most will run quickly but by luck it might be
+ * possible to have 64 records that are slow, doing a
+ * recursive search via LDAP_MATCHING_RULE_IN_CHAIN.
+ *
+ * Thankfully this is after index processing so only
+ * on the subset that matches some index (but still
+ * possibly a big one like objectclass=user)
+ */
+ if (i % 64 == 0) {
+ struct timeval now = tevent_timeval_current();
+ int timeval_cmp = tevent_timeval_compare(&ac->timeout_timeval,
+ &now);
+
+ /*
+ * The search has taken too long. This is the
+ * most likely place for our time to expire,
+ * as we are checking the records after the
+ * index set intersection. This is now the
+ * slow process of checking if the records
+ * actually match.
+ *
+ * The tevent based timeout is not likely to
+ * be hit, sadly, as we don't run an event
+ * loop.
+ *
+ * While we are indexed and most of the work
+ * should have been done already, the
+ * ldb_match_* calls can be quite expensive if
+ * the caller uses LDAP_MATCHING_RULE_IN_CHAIN
+ */
+ if (timeval_cmp <= 0) {
+ talloc_free(keys);
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+ }
+
+ msg = ldb_msg_new(ac);
+ if (!msg) {
+ talloc_free(keys);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret =
+ ldb_kv_search_key(ac->module,
+ ldb_kv,
+ keys[i],
+ msg,
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC |
+ /*
+ * The entry point ldb_kv_search_indexed is
+ * only called from the read-locked
+ * ldb_kv_search.
+ */
+ LDB_UNPACK_DATA_FLAG_READ_LOCKED);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /*
+ * the record has disappeared? yes, this can
+ * happen if the entry is deleted by something
+ * operating in the callback (not another
+ * process, as we have a read lock)
+ */
+ talloc_free(msg);
+ continue;
+ }
+
+ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
+ /* an internal error */
+ talloc_free(keys);
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * We trust the index for LDB_SCOPE_ONELEVEL
+ * unless the index key has been truncated.
+ *
+ * LDB_SCOPE_BASE is not passed in by our only caller.
+ */
+ if (ac->scope != LDB_SCOPE_ONELEVEL ||
+ !ldb_kv->cache->one_level_indexes ||
+ scope_one_truncation != KEY_NOT_TRUNCATED)
+ {
+ /*
+ * The redaction callback may be expensive to call if it
+ * fetches a security descriptor. Check the DN early and
+ * bail out if it doesn't match the base.
+ */
+ if (!ldb_match_scope(ldb, ac->base, msg->dn, ac->scope)) {
+ talloc_free(msg);
+ continue;
+ }
+ }
+
+ if (ldb->redact.callback != NULL) {
+ ret = ldb->redact.callback(ldb->redact.module, ac->req, msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+ }
+
+ ret = ldb_match_message(ldb, msg, ac->tree,
+ ac->scope, &matched);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(keys);
+ talloc_free(msg);
+ return ret;
+ }
+ if (!matched) {
+ talloc_free(msg);
+ continue;
+ }
+
+ ret = ldb_msg_add_distinguished_name(msg);
+ if (ret == -1) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* filter the attributes that the user wants */
+ ret = ldb_kv_filter_attrs_in_place(msg, ac->attrs);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(keys);
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_msg_shrink_to_fit(msg);
+
+ /* Ensure the message elements are all talloc'd. */
+ ret = ldb_msg_elements_take_ownership(msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(keys);
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_module_send_entry(ac->req, msg, NULL);
+ if (ret != LDB_SUCCESS) {
+ /* Regardless of success or failure, the msg
+ * is the callbacks responsibility, and should
+ * not be talloc_free()'ed */
+ ac->request_terminated = true;
+ talloc_free(keys);
+ return ret;
+ }
+
+ (*match_count)++;
+ }
+
+ TALLOC_FREE(keys);
+ return LDB_SUCCESS;
+}
+
+/*
+ sort a DN list
+ */
+static void ldb_kv_dn_list_sort(struct ldb_kv_private *ltdb,
+ struct dn_list *list)
+{
+ if (list->count < 2) {
+ return;
+ }
+
+ /* We know the list is sorted when using the GUID index */
+ if (ltdb->cache->GUID_index_attribute != NULL) {
+ return;
+ }
+
+ TYPESAFE_QSORT(list->dn, list->count,
+ ldb_val_equal_exact_for_qsort);
+}
+
+/*
+ search the database with a LDAP-like expression using indexes
+ returns -1 if an indexed search is not possible, in which
+ case the caller should call ltdb_search_full()
+*/
+int ldb_kv_search_indexed(struct ldb_kv_context *ac, uint32_t *match_count)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(ac->module), struct ldb_kv_private);
+ struct dn_list *dn_list;
+ int ret;
+ enum ldb_scope index_scope;
+ enum key_truncation scope_one_truncation = KEY_NOT_TRUNCATED;
+
+ /* see if indexing is enabled */
+ if (!ldb_kv->cache->attribute_indexes &&
+ !ldb_kv->cache->one_level_indexes && ac->scope != LDB_SCOPE_BASE) {
+ /* fallback to a full search */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ dn_list = talloc_zero(ac, struct dn_list);
+ if (dn_list == NULL) {
+ return ldb_module_oom(ac->module);
+ }
+
+ /*
+ * For the purposes of selecting the switch arm below, if we
+ * don't have a one-level index then treat it like a subtree
+ * search
+ */
+ if (ac->scope == LDB_SCOPE_ONELEVEL &&
+ !ldb_kv->cache->one_level_indexes) {
+ index_scope = LDB_SCOPE_SUBTREE;
+ } else {
+ index_scope = ac->scope;
+ }
+
+ switch (index_scope) {
+ case LDB_SCOPE_BASE:
+ /*
+ * The only caller will have filtered the operation out
+ * so we should never get here
+ */
+ return ldb_operr(ldb);
+
+ case LDB_SCOPE_ONELEVEL:
+
+ /*
+ * First, load all the one-level child objects (regardless of
+ * whether they match the search filter or not). The database
+ * maintains a one-level index, so retrieving this is quick.
+ */
+ ret = ldb_kv_index_dn_one(ac->module,
+ ldb_kv,
+ ac->base,
+ dn_list,
+ &scope_one_truncation);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(dn_list);
+ return ret;
+ }
+
+ /*
+ * If we have too many children, running ldb_kv_index_filter()
+ * over all the child objects can be quite expensive. So next
+ * we do a separate indexed query using the search filter.
+ *
+ * This should be quick, but it may return objects that are not
+ * the direct one-level child objects we're interested in.
+ *
+ * We only do this in the GUID index mode, which is
+ * O(n*log(m)) otherwise the intersection below will
+ * be too costly at O(n*m).
+ *
+ * We don't set a heuristic for 'too many' but instead
+ * do it always and rely on the index lookup being
+ * fast enough in the small case.
+ */
+ if (ldb_kv->cache->GUID_index_attribute != NULL) {
+ struct dn_list *indexed_search_result
+ = talloc_zero(ac, struct dn_list);
+ if (indexed_search_result == NULL) {
+ talloc_free(dn_list);
+ return ldb_module_oom(ac->module);
+ }
+
+ if (!ldb_kv->cache->attribute_indexes) {
+ talloc_free(indexed_search_result);
+ talloc_free(dn_list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Try to do an indexed database search
+ */
+ ret = ldb_kv_index_dn(
+ ac->module, ldb_kv, ac->tree,
+ indexed_search_result);
+
+ /*
+ * We can stop if we're sure the object doesn't exist
+ */
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(indexed_search_result);
+ talloc_free(dn_list);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ /*
+ * Once we have a successful search result, we
+ * intersect it with the one-level children (dn_list).
+ * This should give us exactly the result we're after
+ * (we still need to run ldb_kv_index_filter() to
+ * handle potential index truncation cases).
+ *
+ * The indexed search may fail because we don't support
+ * indexing on that type of search operation, e.g.
+ * matching against '*'. In which case we fall through
+ * and run ldb_kv_index_filter() over all the one-level
+ * children (which is still better than bailing out here
+ * and falling back to a full DB scan).
+ */
+ if (ret == LDB_SUCCESS) {
+ if (!list_intersect(ldb_kv,
+ dn_list,
+ indexed_search_result)) {
+ talloc_free(indexed_search_result);
+ talloc_free(dn_list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ }
+ break;
+
+ case LDB_SCOPE_SUBTREE:
+ case LDB_SCOPE_DEFAULT:
+ if (!ldb_kv->cache->attribute_indexes) {
+ talloc_free(dn_list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /*
+ * Here we load the index for the tree. We have no
+ * index for the subtree.
+ */
+ ret = ldb_kv_index_dn(ac->module, ldb_kv, ac->tree, dn_list);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(dn_list);
+ return ret;
+ }
+ break;
+ }
+
+ /*
+ * It is critical that this function do the re-filter even
+ * on things found by the index as the index can over-match
+ * in cases of truncation (as well as when it decides it is
+ * not worth further filtering)
+ *
+ * If this changes, then the index code above would need to
+ * pass up a flag to say if any index was truncated during
+ * processing as the truncation here refers only to the
+ * SCOPE_ONELEVEL index.
+ */
+ ret = ldb_kv_index_filter(
+ ldb_kv, dn_list, ac, match_count, scope_one_truncation);
+ talloc_free(dn_list);
+ return ret;
+}
+
+/**
+ * @brief Add a DN in the index list of a given attribute name/value pair
+ *
+ * This function will add the DN in the index list for the index for
+ * the given attribute name and value.
+ *
+ * @param[in] module A ldb_module structure
+ *
+ * @param[in] dn The string representation of the DN as it
+ * will be stored in the index entry
+ *
+ * @param[in] el A ldb_message_element array, one of the entry
+ * referred by the v_idx is the attribute name and
+ * value pair which will be used to construct the
+ * index name
+ *
+ * @param[in] v_idx The index of element in the el array to use
+ *
+ * @return An ldb error code
+ */
+static int ldb_kv_index_add1(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el,
+ int v_idx)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *dn_key;
+ int ret;
+ const struct ldb_schema_attribute *a;
+ struct dn_list *list;
+ unsigned alloc_len;
+ enum key_truncation truncation = KEY_TRUNCATED;
+
+
+ ldb = ldb_module_get_ctx(module);
+
+ list = talloc_zero(module, struct dn_list);
+ if (list == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ dn_key = ldb_kv_index_key(ldb,
+ list,
+ ldb_kv,
+ el->name,
+ &el->values[v_idx],
+ &a,
+ &truncation);
+ if (!dn_key) {
+ talloc_free(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /*
+ * Samba only maintains unique indexes on the objectSID and objectGUID
+ * so if a unique index key exceeds the maximum length there is a
+ * problem.
+ */
+ if ((truncation == KEY_TRUNCATED) && (a != NULL &&
+ (a->flags & LDB_ATTR_FLAG_UNIQUE_INDEX ||
+ (el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX)))) {
+
+ ldb_asprintf_errstring(
+ ldb,
+ __location__ ": unique index key on %s in %s, "
+ "exceeds maximum key length of %u (encoded).",
+ el->name,
+ ldb_dn_get_linearized(msg->dn),
+ ldb_kv->max_key_length);
+ talloc_free(list);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ ret = ldb_kv_dn_list_load(module, ldb_kv, dn_key, list,
+ DN_LIST_MUTABLE);
+ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
+ talloc_free(list);
+ return ret;
+ }
+
+ /*
+ * Check for duplicates in the @IDXDN DN -> GUID record
+ *
+ * This is very normal, it just means a duplicate DN creation
+ * was attempted, so don't set the error string or print scary
+ * messages.
+ */
+ if (list->count > 0 &&
+ ldb_attr_cmp(el->name, LDB_KV_IDXDN) == 0 &&
+ truncation == KEY_NOT_TRUNCATED) {
+
+ talloc_free(list);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+
+ } else if (list->count > 0
+ && ldb_attr_cmp(el->name, LDB_KV_IDXDN) == 0) {
+
+ /*
+ * At least one existing entry in the DN->GUID index, which
+ * arises when the DN indexes have been truncated
+ *
+ * So need to pull the DN's to check if it's really a duplicate
+ */
+ unsigned int i;
+ for (i=0; i < list->count; i++) {
+ uint8_t guid_key[LDB_KV_GUID_KEY_SIZE];
+ struct ldb_val key = {
+ .data = guid_key,
+ .length = sizeof(guid_key)
+ };
+ const int flags = LDB_UNPACK_DATA_FLAG_NO_ATTRS;
+ struct ldb_message *rec = ldb_msg_new(ldb);
+ if (rec == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_idx_to_key(
+ module, ldb_kv, ldb, &list->dn[i], &key);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(list);
+ TALLOC_FREE(rec);
+ return ret;
+ }
+
+ ret =
+ ldb_kv_search_key(module, ldb_kv, key, rec, flags);
+ if (key.data != guid_key) {
+ TALLOC_FREE(key.data);
+ }
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /*
+ * the record has disappeared?
+ * yes, this can happen
+ */
+ talloc_free(rec);
+ continue;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ /* an internal error */
+ TALLOC_FREE(rec);
+ TALLOC_FREE(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /*
+ * The DN we are trying to add to the DB and index
+ * is already here, so we must deny the addition
+ */
+ if (ldb_dn_compare(msg->dn, rec->dn) == 0) {
+ TALLOC_FREE(rec);
+ TALLOC_FREE(list);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ }
+ }
+
+ /*
+ * Check for duplicates in unique indexes
+ *
+ * We don't need to do a loop test like the @IDXDN case
+ * above as we have a ban on long unique index values
+ * at the start of this function.
+ */
+ if (list->count > 0 &&
+ ((a != NULL
+ && (a->flags & LDB_ATTR_FLAG_UNIQUE_INDEX ||
+ (el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX))))) {
+ /*
+ * We do not want to print info about a possibly
+ * confidential DN that the conflict was with in the
+ * user-visible error string
+ */
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ __location__
+ ": unique index violation on %s in %s, "
+ "conflicts with %*.*s in %s",
+ el->name, ldb_dn_get_linearized(msg->dn),
+ (int)list->dn[0].length,
+ (int)list->dn[0].length,
+ list->dn[0].data,
+ ldb_dn_get_linearized(dn_key));
+ } else {
+ /* This can't fail, gives a default at worst */
+ const struct ldb_schema_attribute *attr =
+ ldb_schema_attribute_by_name(
+ ldb, ldb_kv->cache->GUID_index_attribute);
+ struct ldb_val v;
+ ret = attr->syntax->ldif_write_fn(ldb, list,
+ &list->dn[0], &v);
+ if (ret == LDB_SUCCESS) {
+ ldb_debug(ldb,
+ LDB_DEBUG_WARNING,
+ __location__
+ ": unique index violation on %s in "
+ "%s, conflicts with %s %*.*s in %s",
+ el->name,
+ ldb_dn_get_linearized(msg->dn),
+ ldb_kv->cache->GUID_index_attribute,
+ (int)v.length,
+ (int)v.length,
+ v.data,
+ ldb_dn_get_linearized(dn_key));
+ }
+ }
+ ldb_asprintf_errstring(ldb,
+ __location__ ": unique index violation "
+ "on %s in %s",
+ el->name,
+ ldb_dn_get_linearized(msg->dn));
+ talloc_free(list);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /* overallocate the list a bit, to reduce the number of
+ * realloc triggered copies */
+ alloc_len = ((list->count+1)+7) & ~7;
+ list->dn = talloc_realloc(list, list->dn, struct ldb_val, alloc_len);
+ if (list->dn == NULL) {
+ talloc_free(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ const char *dn_str = ldb_dn_get_linearized(msg->dn);
+ list->dn[list->count].data
+ = (uint8_t *)talloc_strdup(list->dn, dn_str);
+ if (list->dn[list->count].data == NULL) {
+ talloc_free(list);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ list->dn[list->count].length = strlen(dn_str);
+ } else {
+ const struct ldb_val *key_val;
+ struct ldb_val *exact = NULL, *next = NULL;
+ key_val = ldb_msg_find_ldb_val(
+ msg, ldb_kv->cache->GUID_index_attribute);
+ if (key_val == NULL) {
+ talloc_free(list);
+ return ldb_module_operr(module);
+ }
+
+ if (key_val->length != LDB_KV_GUID_SIZE) {
+ talloc_free(list);
+ return ldb_module_operr(module);
+ }
+
+ BINARY_ARRAY_SEARCH_GTE(list->dn, list->count,
+ *key_val, ldb_val_equal_exact_ordered,
+ exact, next);
+
+ /*
+ * Give a warning rather than fail, this could be a
+ * duplicate value in the record allowed by a caller
+ * forcing in the value with
+ * LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
+ */
+ if (exact != NULL && truncation == KEY_NOT_TRUNCATED) {
+ /* This can't fail, gives a default at worst */
+ const struct ldb_schema_attribute *attr =
+ ldb_schema_attribute_by_name(
+ ldb, ldb_kv->cache->GUID_index_attribute);
+ struct ldb_val v;
+ ret = attr->syntax->ldif_write_fn(ldb, list,
+ exact, &v);
+ if (ret == LDB_SUCCESS) {
+ ldb_debug(ldb,
+ LDB_DEBUG_WARNING,
+ __location__
+ ": duplicate attribute value in %s "
+ "for index on %s, "
+ "duplicate of %s %*.*s in %s",
+ ldb_dn_get_linearized(msg->dn),
+ el->name,
+ ldb_kv->cache->GUID_index_attribute,
+ (int)v.length,
+ (int)v.length,
+ v.data,
+ ldb_dn_get_linearized(dn_key));
+ }
+ }
+
+ if (next == NULL) {
+ next = &list->dn[list->count];
+ } else {
+ memmove(&next[1], next,
+ sizeof(*next) * (list->count - (next - list->dn)));
+ }
+ *next = ldb_val_dup(list->dn, key_val);
+ if (next->data == NULL) {
+ talloc_free(list);
+ return ldb_module_operr(module);
+ }
+ }
+ list->count++;
+
+ ret = ldb_kv_dn_list_store(module, dn_key, list);
+
+ talloc_free(list);
+
+ return ret;
+}
+
+/*
+ add index entries for one elements in a message
+ */
+static int ldb_kv_index_add_el(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el)
+{
+ unsigned int i;
+ for (i = 0; i < el->num_values; i++) {
+ int ret = ldb_kv_index_add1(module, ldb_kv, msg, el, i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ add index entries for all elements in a message
+ */
+static int ldb_kv_index_add_all(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg)
+{
+ struct ldb_message_element *elements = msg->elements;
+ unsigned int i;
+ const char *dn_str;
+ int ret;
+
+ if (ldb_dn_is_special(msg->dn)) {
+ return LDB_SUCCESS;
+ }
+
+ dn_str = ldb_dn_get_linearized(msg->dn);
+ if (dn_str == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_write_index_dn_guid(module, msg, 1);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (!ldb_kv->cache->attribute_indexes) {
+ /* no indexed fields */
+ return LDB_SUCCESS;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ if (!ldb_kv_is_indexed(module, ldb_kv, elements[i].name)) {
+ continue;
+ }
+ ret = ldb_kv_index_add_el(module, ldb_kv, msg, &elements[i]);
+ if (ret != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb,
+ __location__ ": Failed to re-index %s in %s - %s",
+ elements[i].name, dn_str,
+ ldb_errstring(ldb));
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ insert a DN index for a message
+*/
+static int ldb_kv_modify_index_dn(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_dn *dn,
+ const char *index,
+ int add)
+{
+ struct ldb_message_element el;
+ struct ldb_val val;
+ int ret;
+
+ val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(dn));
+ if (val.data == NULL) {
+ const char *dn_str = ldb_dn_get_linearized(dn);
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__ ": Failed to modify %s "
+ "against %s in %s: failed "
+ "to get casefold DN",
+ index,
+ ldb_kv->cache->GUID_index_attribute,
+ dn_str);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ val.length = strlen((char *)val.data);
+ el.name = index;
+ el.values = &val;
+ el.num_values = 1;
+
+ if (add) {
+ ret = ldb_kv_index_add1(module, ldb_kv, msg, &el, 0);
+ } else { /* delete */
+ ret = ldb_kv_index_del_value(module, ldb_kv, msg, &el, 0);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ const char *dn_str = ldb_dn_get_linearized(dn);
+ ldb_asprintf_errstring(ldb,
+ __location__ ": Failed to modify %s "
+ "against %s in %s - %s",
+ index,
+ ldb_kv->cache->GUID_index_attribute,
+ dn_str,
+ ldb_errstring(ldb));
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ insert a one level index for a message
+*/
+static int ldb_kv_index_onelevel(struct ldb_module *module,
+ const struct ldb_message *msg,
+ int add)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ struct ldb_dn *pdn;
+ int ret;
+
+ /* We index for ONE Level only if requested */
+ if (!ldb_kv->cache->one_level_indexes) {
+ return LDB_SUCCESS;
+ }
+
+ pdn = ldb_dn_get_parent(module, msg->dn);
+ if (pdn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret =
+ ldb_kv_modify_index_dn(module, ldb_kv, msg, pdn, LDB_KV_IDXONE, add);
+
+ talloc_free(pdn);
+
+ return ret;
+}
+
+/*
+ insert a one level index for a message
+*/
+static int ldb_kv_write_index_dn_guid(struct ldb_module *module,
+ const struct ldb_message *msg,
+ int add)
+{
+ int ret;
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+
+ /* We index for DN only if using a GUID index */
+ if (ldb_kv->cache->GUID_index_attribute == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ ret = ldb_kv_modify_index_dn(
+ module, ldb_kv, msg, msg->dn, LDB_KV_IDXDN, add);
+
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Entry %s already exists",
+ ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
+ return ret;
+}
+
+/*
+ add the index entries for a new element in a record
+ The caller guarantees that these element values are not yet indexed
+*/
+int ldb_kv_index_add_element(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el)
+{
+ if (ldb_dn_is_special(msg->dn)) {
+ return LDB_SUCCESS;
+ }
+ if (!ldb_kv_is_indexed(module, ldb_kv, el->name)) {
+ return LDB_SUCCESS;
+ }
+ return ldb_kv_index_add_el(module, ldb_kv, msg, el);
+}
+
+/*
+ add the index entries for a new record
+*/
+int ldb_kv_index_add_new(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg)
+{
+ int ret;
+
+ if (ldb_dn_is_special(msg->dn)) {
+ return LDB_SUCCESS;
+ }
+
+ ret = ldb_kv_index_add_all(module, ldb_kv, msg);
+ if (ret != LDB_SUCCESS) {
+ /*
+ * Because we can't trust the caller to be doing
+ * transactions properly, clean up any index for this
+ * entry rather than relying on a transaction
+ * cleanup
+ */
+
+ ldb_kv_index_delete(module, msg);
+ return ret;
+ }
+
+ ret = ldb_kv_index_onelevel(module, msg, 1);
+ if (ret != LDB_SUCCESS) {
+ /*
+ * Because we can't trust the caller to be doing
+ * transactions properly, clean up any index for this
+ * entry rather than relying on a transaction
+ * cleanup
+ */
+ ldb_kv_index_delete(module, msg);
+ return ret;
+ }
+ return ret;
+}
+
+
+/*
+ delete an index entry for one message element
+*/
+int ldb_kv_index_del_value(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el,
+ unsigned int v_idx)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *dn_key;
+ const char *dn_str;
+ int ret, i;
+ unsigned int j;
+ struct dn_list *list;
+ struct ldb_dn *dn = msg->dn;
+ enum key_truncation truncation = KEY_NOT_TRUNCATED;
+
+ ldb = ldb_module_get_ctx(module);
+
+ dn_str = ldb_dn_get_linearized(dn);
+ if (dn_str == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (dn_str[0] == '@') {
+ return LDB_SUCCESS;
+ }
+
+ /*
+ * ldb is being used as the memory context to ldb_kv_index_key
+ * as dn_key itself is also used as the TALLOC_CTX for the
+ * rest of this function.
+ */
+ dn_key = ldb_kv_index_key(ldb,
+ ldb,
+ ldb_kv,
+ el->name,
+ &el->values[v_idx],
+ NULL,
+ &truncation);
+ /*
+ * We ignore key truncation in ltdb_index_add1() so
+ * match that by ignoring it here as well
+ *
+ * Multiple values are legitimate and accepted
+ */
+ if (!dn_key) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ list = talloc_zero(dn_key, struct dn_list);
+ if (list == NULL) {
+ talloc_free(dn_key);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_dn_list_load(module, ldb_kv, dn_key, list,
+ DN_LIST_MUTABLE);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* it wasn't indexed. Did we have an earlier error? If we did then
+ its gone now */
+ talloc_free(dn_key);
+ return LDB_SUCCESS;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(dn_key);
+ return ret;
+ }
+
+ /*
+ * Find one of the values matching this message to remove
+ */
+ i = ldb_kv_dn_list_find_msg(ldb_kv, list, msg);
+ if (i == -1) {
+ /* nothing to delete */
+ talloc_free(dn_key);
+ return LDB_SUCCESS;
+ }
+
+ j = (unsigned int) i;
+ ARRAY_DEL_ELEMENT(list->dn, j, list->count);
+ list->count--;
+ if (list->count == 0) {
+ talloc_free(list->dn);
+ list->dn = NULL;
+ } else {
+ list->dn = talloc_realloc(list, list->dn, struct ldb_val, list->count);
+ }
+
+ ret = ldb_kv_dn_list_store(module, dn_key, list);
+
+ talloc_free(dn_key);
+
+ return ret;
+}
+
+/*
+ delete the index entries for a element
+ return -1 on failure
+*/
+int ldb_kv_index_del_element(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_message *msg,
+ struct ldb_message_element *el)
+{
+ const char *dn_str;
+ int ret;
+ unsigned int i;
+
+ if (!ldb_kv->cache->attribute_indexes) {
+ /* no indexed fields */
+ return LDB_SUCCESS;
+ }
+
+ dn_str = ldb_dn_get_linearized(msg->dn);
+ if (dn_str == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (dn_str[0] == '@') {
+ return LDB_SUCCESS;
+ }
+
+ if (!ldb_kv_is_indexed(module, ldb_kv, el->name)) {
+ return LDB_SUCCESS;
+ }
+ for (i = 0; i < el->num_values; i++) {
+ ret = ldb_kv_index_del_value(module, ldb_kv, msg, el, i);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ delete the index entries for a record
+ return -1 on failure
+*/
+int ldb_kv_index_delete(struct ldb_module *module,
+ const struct ldb_message *msg)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ int ret;
+ unsigned int i;
+
+ if (ldb_dn_is_special(msg->dn)) {
+ return LDB_SUCCESS;
+ }
+
+ ret = ldb_kv_index_onelevel(module, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_kv_write_index_dn_guid(module, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (!ldb_kv->cache->attribute_indexes) {
+ /* no indexed fields */
+ return LDB_SUCCESS;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ ret = ldb_kv_index_del_element(
+ module, ldb_kv, msg, &msg->elements[i]);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+
+/*
+ traversal function that deletes all @INDEX records in the in-memory
+ TDB.
+
+ This does not touch the actual DB, that is done at transaction
+ commit, which in turn greatly reduces DB churn as we will likely
+ be able to do a direct update into the old record.
+*/
+static int delete_index(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ _UNUSED_ struct ldb_val data,
+ void *state)
+{
+ struct ldb_module *module = state;
+ const char *dnstr = "DN=" LDB_KV_INDEX ":";
+ struct dn_list list;
+ struct ldb_dn *dn;
+ struct ldb_val v;
+ int ret;
+
+ if (strncmp((char *)key.data, dnstr, strlen(dnstr)) != 0) {
+ return 0;
+ }
+ /* we need to put a empty list in the internal tdb for this
+ * index entry */
+ list.dn = NULL;
+ list.count = 0;
+
+ /* the offset of 3 is to remove the DN= prefix. */
+ v.data = key.data + 3;
+ v.length = strnlen((char *)key.data, key.length) - 3;
+
+ dn = ldb_dn_from_ldb_val(ldb_kv, ldb_module_get_ctx(module), &v);
+
+ /*
+ * This does not actually touch the DB quite yet, just
+ * the in-memory index cache
+ */
+ ret = ldb_kv_dn_list_store(module, dn, &list);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Unable to store null index for %s\n",
+ ldb_dn_get_linearized(dn));
+ talloc_free(dn);
+ return -1;
+ }
+ talloc_free(dn);
+ return 0;
+}
+
+/*
+ traversal function that adds @INDEX records during a re index TODO wrong comment
+*/
+static int re_key(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val val,
+ void *state)
+{
+ struct ldb_context *ldb;
+ struct ldb_kv_reindex_context *ctx =
+ (struct ldb_kv_reindex_context *)state;
+ struct ldb_module *module = ldb_kv->module;
+ struct ldb_message *msg;
+ int ret;
+ struct ldb_val key2;
+ bool is_record;
+
+ ldb = ldb_module_get_ctx(module);
+
+ is_record = ldb_kv_key_is_normal_record(key);
+ if (is_record == false) {
+ return 0;
+ }
+
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
+ return -1;
+ }
+
+ ret = ldb_unpack_data(ldb, &val, msg);
+ if (ret != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %s\n",
+ ldb_dn_get_linearized(msg->dn));
+ ctx->error = ret;
+ talloc_free(msg);
+ return -1;
+ }
+
+ if (msg->dn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Refusing to re-index as GUID "
+ "key %*.*s with no DN\n",
+ (int)key.length, (int)key.length,
+ (char *)key.data);
+ talloc_free(msg);
+ return -1;
+ }
+
+ /* check if the DN key has changed, perhaps due to the case
+ insensitivity of an element changing, or a change from DN
+ to GUID keys */
+ key2 = ldb_kv_key_msg(module, msg, msg);
+ if (key2.data == NULL) {
+ /* probably a corrupt record ... darn */
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s",
+ ldb_dn_get_linearized(msg->dn));
+ talloc_free(msg);
+ return 0;
+ }
+ if (key.length != key2.length ||
+ (memcmp(key.data, key2.data, key.length) != 0)) {
+ ldb_kv->kv_ops->update_in_iterate(
+ ldb_kv, key, key2, val, ctx);
+ }
+ talloc_free(key2.data);
+
+ talloc_free(msg);
+
+ ctx->count++;
+ if (ctx->count % 10000 == 0) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ "Reindexing: re-keyed %u records so far",
+ ctx->count);
+ }
+
+ return 0;
+}
+
+/*
+ traversal function that adds @INDEX records during a re index
+*/
+static int re_index(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val val,
+ void *state)
+{
+ struct ldb_context *ldb;
+ struct ldb_kv_reindex_context *ctx =
+ (struct ldb_kv_reindex_context *)state;
+ struct ldb_module *module = ldb_kv->module;
+ struct ldb_message *msg;
+ int ret;
+ bool is_record;
+
+ ldb = ldb_module_get_ctx(module);
+
+ is_record = ldb_kv_key_is_normal_record(key);
+ if (is_record == false) {
+ return 0;
+ }
+
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
+ return -1;
+ }
+
+ ret = ldb_unpack_data(ldb, &val, msg);
+ if (ret != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %s\n",
+ ldb_dn_get_linearized(msg->dn));
+ ctx->error = ret;
+ talloc_free(msg);
+ return -1;
+ }
+
+ if (msg->dn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Refusing to re-index as GUID "
+ "key %*.*s with no DN\n",
+ (int)key.length, (int)key.length,
+ (char *)key.data);
+ talloc_free(msg);
+ return -1;
+ }
+
+ ret = ldb_kv_index_onelevel(module, msg, 1);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Adding special ONE LEVEL index failed (%s)!",
+ ldb_dn_get_linearized(msg->dn));
+ talloc_free(msg);
+ return -1;
+ }
+
+ ret = ldb_kv_index_add_all(module, ldb_kv, msg);
+
+ if (ret != LDB_SUCCESS) {
+ ctx->error = ret;
+ talloc_free(msg);
+ return -1;
+ }
+
+ talloc_free(msg);
+
+ ctx->count++;
+ if (ctx->count % 10000 == 0) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ "Reindexing: re-indexed %u records so far",
+ ctx->count);
+ }
+
+ return 0;
+}
+
+/*
+ * Convert the 4-byte pack format version to a number that's slightly
+ * more intelligible to a user e.g. version 0, 1, 2, etc.
+ */
+static uint32_t displayable_pack_version(uint32_t version) {
+ if (version < LDB_PACKING_FORMAT_NODN) {
+ return version; /* unknown - can't convert */
+ }
+
+ return (version - LDB_PACKING_FORMAT_NODN);
+}
+
+static int re_pack(struct ldb_kv_private *ldb_kv,
+ _UNUSED_ struct ldb_val key,
+ struct ldb_val val,
+ void *state)
+{
+ struct ldb_context *ldb;
+ struct ldb_message *msg;
+ struct ldb_module *module = ldb_kv->module;
+ struct ldb_kv_repack_context *ctx =
+ (struct ldb_kv_repack_context *)state;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
+ return -1;
+ }
+
+ ret = ldb_unpack_data(ldb, &val, msg);
+ if (ret != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Repack: unpack failed: %s\n",
+ ldb_dn_get_linearized(msg->dn));
+ ctx->error = ret;
+ talloc_free(msg);
+ return -1;
+ }
+
+ ret = ldb_kv_store(module, msg, TDB_MODIFY);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Repack: store failed: %s\n",
+ ldb_dn_get_linearized(msg->dn));
+ ctx->error = ret;
+ talloc_free(msg);
+ return -1;
+ }
+
+ /*
+ * Warn the user that we're repacking the first time we see a normal
+ * record. This means we never warn if we're repacking a database with
+ * only @ records. This is because during database initialisation,
+ * we might repack as initial settings are written out, and we don't
+ * want to spam the log.
+ */
+ if ((!ctx->normal_record_seen) && (!ldb_dn_is_special(msg->dn))) {
+ ldb_debug(ldb, LDB_DEBUG_ALWAYS_LOG,
+ "Repacking database from v%u to v%u format "
+ "(first record %s)",
+ displayable_pack_version(ctx->old_version),
+ displayable_pack_version(ldb_kv->pack_format_version),
+ ldb_dn_get_linearized(msg->dn));
+ ctx->normal_record_seen = true;
+ }
+
+ ctx->count++;
+ if (ctx->count % 10000 == 0) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ "Repack: re-packed %u records so far",
+ ctx->count);
+ }
+
+ talloc_free(msg);
+ return 0;
+}
+
+int ldb_kv_repack(struct ldb_module *module)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_kv_repack_context ctx;
+ int ret;
+
+ ctx.old_version = ldb_kv->pack_format_version;
+ ctx.count = 0;
+ ctx.error = LDB_SUCCESS;
+ ctx.normal_record_seen = false;
+
+ ldb_kv->pack_format_version = ldb_kv->target_pack_format_version;
+
+ /* Iterate all database records and repack them in the new format */
+ ret = ldb_kv->kv_ops->iterate(ldb_kv, re_pack, &ctx);
+ if (ret < 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Repack traverse failed: %s",
+ ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ctx.error != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Repack failed: %s",
+ ldb_errstring(ldb));
+ return ctx.error;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ force a complete reindex of the database
+*/
+int ldb_kv_reindex(struct ldb_module *module)
+{
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ int ret;
+ struct ldb_kv_reindex_context ctx;
+ size_t index_cache_size = 0;
+
+ /*
+ * Only triggered after a modification, but make clear we do
+ * not re-index a read-only DB
+ */
+ if (ldb_kv->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ if (ldb_kv_cache_reload(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Ensure we read (and so remove) the entries from the real
+ * DB, no values stored so far are any use as we want to do a
+ * re-index
+ */
+ ldb_kv_index_transaction_cancel(module);
+ if (ldb_kv->nested_idx_ptr != NULL) {
+ ldb_kv_index_sub_transaction_cancel(ldb_kv);
+ }
+
+ /*
+ * Calculate the size of the index cache needed for
+ * the re-index. If specified always use the
+ * ldb_kv->index_transaction_cache_size otherwise use the maximum
+ * of the size estimate or the DEFAULT_INDEX_CACHE_SIZE
+ */
+ if (ldb_kv->index_transaction_cache_size > 0) {
+ index_cache_size = ldb_kv->index_transaction_cache_size;
+ } else {
+ index_cache_size = ldb_kv->kv_ops->get_size(ldb_kv);
+ if (index_cache_size < DEFAULT_INDEX_CACHE_SIZE) {
+ index_cache_size = DEFAULT_INDEX_CACHE_SIZE;
+ }
+ }
+
+ /*
+ * Note that we don't start an index sub transaction for re-indexing
+ */
+ ret = ldb_kv_index_transaction_start(module, index_cache_size);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* first traverse the database deleting any @INDEX records by
+ * putting NULL entries in the in-memory tdb
+ */
+ ret = ldb_kv->kv_ops->iterate(ldb_kv, delete_index, module);
+ if (ret < 0) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "index deletion traverse failed: %s",
+ ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ctx.error = 0;
+ ctx.count = 0;
+
+ ret = ldb_kv->kv_ops->iterate(ldb_kv, re_key, &ctx);
+ if (ret < 0) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "key correction traverse failed: %s",
+ ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ctx.error != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "reindexing failed: %s", ldb_errstring(ldb));
+ return ctx.error;
+ }
+
+ ctx.error = 0;
+ ctx.count = 0;
+
+ /* now traverse adding any indexes for normal LDB records */
+ ret = ldb_kv->kv_ops->iterate(ldb_kv, re_index, &ctx);
+ if (ret < 0) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "reindexing traverse failed: %s",
+ ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ctx.error != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ ldb_asprintf_errstring(ldb, "reindexing failed: %s", ldb_errstring(ldb));
+ return ctx.error;
+ }
+
+ if (ctx.count > 10000) {
+ ldb_debug(ldb_module_get_ctx(module),
+ LDB_DEBUG_WARNING,
+ "Reindexing: re_index successful on %s, "
+ "final index write-out will be in transaction commit",
+ ldb_kv->kv_ops->name(ldb_kv));
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ * Copy the contents of the nested transaction index cache record to the
+ * transaction index cache.
+ *
+ * During this 'commit' of the subtransaction to the main transaction
+ * (cache), care must be taken to free any existing index at the top
+ * level because otherwise we would leak memory.
+ */
+static int ldb_kv_sub_transaction_traverse(
+ struct tdb_context *tdb,
+ TDB_DATA key,
+ TDB_DATA data,
+ void *state)
+{
+ struct ldb_module *module = state;
+ struct ldb_kv_private *ldb_kv = talloc_get_type(
+ ldb_module_get_private(module), struct ldb_kv_private);
+ TDB_DATA rec = {0};
+ struct dn_list *index_in_subtransaction = NULL;
+ struct dn_list *index_in_top_level = NULL;
+ int ret = 0;
+
+ /*
+ * This unwraps the pointer in the DB into a pointer in
+ * memory, we are abusing TDB as a hash map, not a linearised
+ * database store
+ */
+ index_in_subtransaction = ldb_kv_index_idxptr(module, data);
+ if (index_in_subtransaction == NULL) {
+ ldb_kv->idxptr->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ /*
+ * Do we already have an entry in the primary transaction cache
+ * If so free it's dn_list and replace it with the dn_list from
+ * the secondary cache
+ *
+ * The TDB and so the fetched rec contains NO DATA, just a
+ * pointer to data held in memory.
+ */
+ rec = tdb_fetch(ldb_kv->idxptr->itdb, key);
+ if (rec.dptr != NULL) {
+ index_in_top_level = ldb_kv_index_idxptr(module, rec);
+ free(rec.dptr);
+ if (index_in_top_level == NULL) {
+ abort();
+ }
+ /*
+ * We had this key at the top level. However we made a copy
+ * at the sub-transaction level so that we could possibly
+ * roll back. We have to free the top level index memory
+ * otherwise we would leak
+ */
+ if (index_in_top_level->count > 0) {
+ TALLOC_FREE(index_in_top_level->dn);
+ }
+ index_in_top_level->dn
+ = talloc_steal(index_in_top_level,
+ index_in_subtransaction->dn);
+ index_in_top_level->count = index_in_subtransaction->count;
+ return 0;
+ }
+
+ index_in_top_level = talloc(ldb_kv->idxptr, struct dn_list);
+ if (index_in_top_level == NULL) {
+ ldb_kv->idxptr->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+ index_in_top_level->dn
+ = talloc_steal(index_in_top_level,
+ index_in_subtransaction->dn);
+ index_in_top_level->count = index_in_subtransaction->count;
+
+ rec.dptr = (uint8_t *)&index_in_top_level;
+ rec.dsize = sizeof(void *);
+
+
+ /*
+ * This is not a store into the main DB, but into an in-memory
+ * TDB, so we don't need a guard on ltdb->read_only
+ */
+ ret = tdb_store(ldb_kv->idxptr->itdb, key, rec, TDB_INSERT);
+ if (ret != 0) {
+ ldb_kv->idxptr->error = ltdb_err_map(
+ tdb_error(ldb_kv->idxptr->itdb));
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Initialise the index cache for a sub transaction.
+ */
+int ldb_kv_index_sub_transaction_start(struct ldb_kv_private *ldb_kv)
+{
+ ldb_kv->nested_idx_ptr = talloc_zero(ldb_kv, struct ldb_kv_idxptr);
+ if (ldb_kv->nested_idx_ptr == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * We use a tiny hash size for the sub-database (11).
+ *
+ * The sub-transaction is only for one record at a time, we
+ * would use a linked list but that would make the code even
+ * more complex when manipulating the index, as it would have
+ * to know if we were in a nested transaction (normal
+ * operations) or the top one (a reindex).
+ */
+ ldb_kv->nested_idx_ptr->itdb =
+ tdb_open(NULL, 11, TDB_INTERNAL, O_RDWR, 0);
+ if (ldb_kv->nested_idx_ptr->itdb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ * Clear the contents of the nested transaction index cache when the nested
+ * transaction is cancelled.
+ */
+int ldb_kv_index_sub_transaction_cancel(struct ldb_kv_private *ldb_kv)
+{
+ if (ldb_kv->nested_idx_ptr != NULL) {
+ tdb_close(ldb_kv->nested_idx_ptr->itdb);
+ TALLOC_FREE(ldb_kv->nested_idx_ptr);
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ * Commit a nested transaction,
+ * Copy the contents of the nested transaction index cache to the
+ * transaction index cache.
+ */
+int ldb_kv_index_sub_transaction_commit(struct ldb_kv_private *ldb_kv)
+{
+ int ret = 0;
+
+ if (ldb_kv->nested_idx_ptr == NULL) {
+ return LDB_SUCCESS;
+ }
+ if (ldb_kv->nested_idx_ptr->itdb == NULL) {
+ return LDB_SUCCESS;
+ }
+ tdb_traverse(
+ ldb_kv->nested_idx_ptr->itdb,
+ ldb_kv_sub_transaction_traverse,
+ ldb_kv->module);
+ tdb_close(ldb_kv->nested_idx_ptr->itdb);
+ ldb_kv->nested_idx_ptr->itdb = NULL;
+
+ ret = ldb_kv->nested_idx_ptr->error;
+ if (ret != LDB_SUCCESS) {
+ struct ldb_context *ldb = ldb_module_get_ctx(ldb_kv->module);
+ if (!ldb_errstring(ldb)) {
+ ldb_set_errstring(ldb, ldb_strerror(ret));
+ }
+ ldb_asprintf_errstring(
+ ldb,
+ __location__": Failed to update index records in "
+ "sub transaction commit: %s",
+ ldb_errstring(ldb));
+ }
+ TALLOC_FREE(ldb_kv->nested_idx_ptr);
+ return ret;
+}
diff --git a/lib/ldb/ldb_key_value/ldb_kv_search.c b/lib/ldb/ldb_key_value/ldb_kv_search.c
new file mode 100644
index 0000000..5dbbae6
--- /dev/null
+++ b/lib/ldb/ldb_key_value/ldb_kv_search.c
@@ -0,0 +1,795 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb search functions
+ *
+ * Description: functions to search ldb+tdb databases
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "ldb_kv.h"
+#include "ldb_private.h"
+#include "lib/util/attr.h"
+/*
+ search the database for a single simple dn.
+ return LDB_ERR_NO_SUCH_OBJECT on record-not-found
+ and LDB_SUCCESS on success
+*/
+int ldb_kv_search_base(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_dn **ret_dn)
+{
+ int exists;
+ int ret;
+ struct ldb_message *msg = NULL;
+
+ if (ldb_dn_is_null(dn)) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ /*
+ * We can't use tdb_exists() directly on a key when the TDB
+ * key is the GUID one, not the DN based one. So we just do a
+ * normal search and avoid most of the allocation with the
+ * LDB_UNPACK_DATA_FLAG_NO_ATTRS flag
+ */
+ msg = ldb_msg_new(module);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_kv_search_dn1(module, dn, msg, LDB_UNPACK_DATA_FLAG_NO_ATTRS);
+ if (ret == LDB_SUCCESS) {
+ const char *dn_linearized
+ = ldb_dn_get_linearized(dn);
+ const char *msg_dn_linearized
+ = ldb_dn_get_linearized(msg->dn);
+
+ if (strcmp(dn_linearized, msg_dn_linearized) == 0) {
+ /*
+ * Re-use the full incoming DN for
+ * subtree checks
+ */
+ *ret_dn = dn;
+ } else {
+ /*
+ * Use the string DN from the unpack, so that
+ * we have a case-exact match of the base
+ */
+ *ret_dn = talloc_steal(mem_ctx, msg->dn);
+ }
+ exists = true;
+ } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ exists = false;
+ } else {
+ talloc_free(msg);
+ return ret;
+ }
+ talloc_free(msg);
+ if (exists) {
+ return LDB_SUCCESS;
+ }
+ return LDB_ERR_NO_SUCH_OBJECT;
+}
+
+struct ldb_kv_parse_data_unpack_ctx {
+ struct ldb_message *msg;
+ struct ldb_module *module;
+ struct ldb_kv_private *ldb_kv;
+ unsigned int unpack_flags;
+};
+
+static int ldb_kv_parse_data_unpack(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data)
+{
+ struct ldb_kv_parse_data_unpack_ctx *ctx = private_data;
+ int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
+ struct ldb_val data_parse = data;
+
+ struct ldb_kv_private *ldb_kv = ctx->ldb_kv;
+
+ if ((ldb_kv->kv_ops->options & LDB_KV_OPTION_STABLE_READ_LOCK) &&
+ (ctx->unpack_flags & LDB_UNPACK_DATA_FLAG_READ_LOCKED) &&
+ !ldb_kv->kv_ops->transaction_active(ldb_kv)) {
+ /*
+ * In the case where no transactions are active and
+ * we're in a read-lock, we can point directly into
+ * database memory.
+ *
+ * The database can't be changed underneath us and we
+ * will duplicate this data in the call to filter.
+ *
+ * This is seen in:
+ * - ldb_kv_index_filter
+ * - ldb_kv_search_and_return_base
+ */
+ } else {
+ /*
+ * In every other case, since unpack doesn't memdup, we need
+ * to at least do a memdup on the whole data buffer as that
+ * may change later and the caller needs a stable result.
+ *
+ * During transactions, pointers could change and in
+ * TDB, there just aren't the same guarantees.
+ */
+ data_parse.data = talloc_memdup(ctx->msg,
+ data.data,
+ data.length);
+ if (data_parse.data == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Unable to allocate data(%d) for %*.*s\n",
+ (int)data.length,
+ (int)key.length, (int)key.length, key.data);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ ret = ldb_unpack_data_flags(ldb, &data_parse,
+ ctx->msg, ctx->unpack_flags);
+ if (ret == -1) {
+ if (data_parse.data != data.data) {
+ talloc_free(data_parse.data);
+ }
+
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ __location__ ": Invalid data for index %*.*s\n",
+ (int)key.length, (int)key.length, key.data);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return ret;
+}
+
+/*
+ search the database for a single simple dn, returning all attributes
+ in a single message
+
+ return LDB_ERR_NO_SUCH_OBJECT on record-not-found
+ and LDB_SUCCESS on success
+*/
+int ldb_kv_search_key(struct ldb_module *module,
+ struct ldb_kv_private *ldb_kv,
+ const struct ldb_val ldb_key,
+ struct ldb_message *msg,
+ unsigned int unpack_flags)
+{
+ int ret;
+ struct ldb_kv_parse_data_unpack_ctx ctx = {
+ .msg = msg,
+ .module = module,
+ .unpack_flags = unpack_flags,
+ .ldb_kv = ldb_kv
+ };
+
+ memset(msg, 0, sizeof(*msg));
+
+ msg->num_elements = 0;
+ msg->elements = NULL;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(
+ ldb_kv, ldb_key, ldb_kv_parse_data_unpack, &ctx);
+
+ if (ret == -1) {
+ ret = ldb_kv->kv_ops->error(ldb_kv);
+ if (ret == LDB_SUCCESS) {
+ /*
+ * Just to be sure we don't turn errors
+ * into success
+ */
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return ret;
+ } else if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ search the database for a single simple dn, returning all attributes
+ in a single message
+
+ return LDB_ERR_NO_SUCH_OBJECT on record-not-found
+ and LDB_SUCCESS on success
+*/
+int ldb_kv_search_dn1(struct ldb_module *module,
+ struct ldb_dn *dn,
+ struct ldb_message *msg,
+ unsigned int unpack_flags)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int ret;
+ uint8_t guid_key[LDB_KV_GUID_KEY_SIZE];
+ struct ldb_val key = {
+ .data = guid_key,
+ .length = sizeof(guid_key)
+ };
+ TALLOC_CTX *tdb_key_ctx = NULL;
+
+ bool valid_dn = ldb_dn_validate(dn);
+ if (valid_dn == false) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ "Invalid Base DN: %s",
+ ldb_dn_get_linearized(dn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ if (ldb_kv->cache->GUID_index_attribute == NULL ||
+ ldb_dn_is_special(dn)) {
+
+ tdb_key_ctx = talloc_new(msg);
+ if (!tdb_key_ctx) {
+ return ldb_module_oom(module);
+ }
+
+ /* form the key */
+ key = ldb_kv_key_dn(tdb_key_ctx, dn);
+ if (!key.data) {
+ TALLOC_FREE(tdb_key_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else {
+ /*
+ * Look in the index to find the key for this DN.
+ *
+ * the tdb_key memory is allocated above, msg is just
+ * used for internal memory.
+ *
+ */
+ ret = ldb_kv_key_dn_from_idx(module, ldb_kv, msg, dn, &key);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ ret = ldb_kv_search_key(module, ldb_kv, key, msg, unpack_flags);
+
+ TALLOC_FREE(tdb_key_ctx);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if ((unpack_flags & LDB_UNPACK_DATA_FLAG_NO_DN) == 0) {
+ if (!msg->dn) {
+ msg->dn = ldb_dn_copy(msg, dn);
+ }
+ if (!msg->dn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ * filter the specified list of attributes from msg,
+ * adding requested attributes, and perhaps all for *.
+ * The DN will not be added if it is missing.
+ */
+int ldb_kv_filter_attrs_in_place(struct ldb_message *msg,
+ const char *const *attrs)
+{
+ return ldb_filter_attrs_in_place(msg, attrs);
+}
+
+/*
+ search function for a non-indexed search
+ */
+static int search_func(_UNUSED_ struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val val,
+ void *state)
+{
+ struct ldb_context *ldb;
+ struct ldb_kv_context *ac;
+ struct ldb_message *msg;
+ struct timeval now;
+ int ret, timeval_cmp;
+ bool matched;
+
+ ac = talloc_get_type(state, struct ldb_kv_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ /*
+ * We want to skip @ records early in a search full scan
+ *
+ * @ records like @IDXLIST are only available via a base
+ * search on the specific name but the method by which they
+ * were excluded was expensive, after the unpack the DN is
+ * exploded and ldb_match_msg_error() would reject it for
+ * failing to match the scope.
+ *
+ * ldb_kv_key_is_normal_record() uses the fact that @ records
+ * have the DN=@ prefix on their TDB/LMDB key to quickly
+ * exclude them from consideration.
+ *
+ * (any other non-records are also excluded by the same key
+ * match)
+ */
+
+ if (ldb_kv_key_is_normal_record(key) == false) {
+ return 0;
+ }
+
+ /*
+ * Check the time every 64 records, to reduce calls to
+ * gettimeofday(). This is a compromise, not all calls to
+ * ldb_match_message() will take the same time, most will fail
+ * quickly but by luck it might be possible to have 64 records
+ * that are slow, doing a recursive search via
+ * LDAP_MATCHING_RULE_IN_CHAIN.
+ */
+ if (ac->timeout_counter++ % 64 == 0) {
+ now = tevent_timeval_current();
+ timeval_cmp = tevent_timeval_compare(&ac->timeout_timeval,
+ &now);
+
+ /*
+ * The search has taken too long. This is the most
+ * likely place for our time to expire, as we are in
+ * an un-indexed search and we return the data from
+ * within this loop. The tevent based timeout is not
+ * likely to be hit, sadly.
+ *
+ * ldb_match_msg_error() can be quite expensive if a
+ * LDAP_MATCHING_RULE_IN_CHAIN extended match was
+ * specified.
+ */
+ if (timeval_cmp <= 0) {
+ ac->error = LDB_ERR_TIME_LIMIT_EXCEEDED;
+ return -1;
+ }
+ }
+
+ msg = ldb_msg_new(ac);
+ if (!msg) {
+ ac->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ /* unpack the record */
+ ret = ldb_unpack_data_flags(ldb, &val, msg,
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
+ if (ret == -1) {
+ talloc_free(msg);
+ ac->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ if (!msg->dn) {
+ msg->dn = ldb_dn_new(msg, ldb,
+ (char *)key.data + 3);
+ if (msg->dn == NULL) {
+ talloc_free(msg);
+ ac->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+ }
+
+ /*
+ * The redaction callback may be expensive to call if it fetches a
+ * security descriptor. Check the DN early and bail out if it doesn't
+ * match the base.
+ */
+ if (!ldb_match_scope(ldb, ac->base, msg->dn, ac->scope)) {
+ talloc_free(msg);
+ return 0;
+ }
+
+ if (ldb->redact.callback != NULL) {
+ ret = ldb->redact.callback(ldb->redact.module, ac->req, msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+ }
+
+ /* see if it matches the given expression */
+ ret = ldb_match_message(ldb, msg,
+ ac->tree, ac->scope, &matched);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ ac->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+ if (!matched) {
+ talloc_free(msg);
+ return 0;
+ }
+
+ ret = ldb_msg_add_distinguished_name(msg);
+ if (ret == -1) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* filter the attributes that the user wants */
+ ret = ldb_kv_filter_attrs_in_place(msg, ac->attrs);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ ac->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ ldb_msg_shrink_to_fit(msg);
+
+ /* Ensure the message elements are all talloc'd. */
+ ret = ldb_msg_elements_take_ownership(msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ ac->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ ret = ldb_module_send_entry(ac->req, msg, NULL);
+ if (ret != LDB_SUCCESS) {
+ ac->request_terminated = true;
+ /* the callback failed, abort the operation */
+ ac->error = LDB_ERR_OPERATIONS_ERROR;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Key pointing to just before the first GUID indexed record for
+ * iterate_range
+ */
+struct ldb_val start_of_db_key = {.data=discard_const_p(uint8_t, "GUID<"),
+ .length=6};
+/*
+ * Key pointing to just after the last GUID indexed record for
+ * iterate_range
+ */
+struct ldb_val end_of_db_key = {.data=discard_const_p(uint8_t, "GUID>"),
+ .length=6};
+
+/*
+ search the database with a LDAP-like expression.
+ this is the "full search" non-indexed variant
+*/
+static int ldb_kv_search_full(struct ldb_kv_context *ctx)
+{
+ void *data = ldb_module_get_private(ctx->module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int ret;
+
+ /*
+ * If the backend has an iterate_range op, use it to start the search
+ * at the first GUID indexed record, skipping the indexes section.
+ */
+ ctx->error = LDB_SUCCESS;
+ ret = ldb_kv->kv_ops->iterate_range(ldb_kv,
+ start_of_db_key,
+ end_of_db_key,
+ search_func,
+ ctx);
+ if (ret == LDB_ERR_OPERATIONS_ERROR) {
+ /*
+ * If iterate_range isn't defined, it'll return an error,
+ * so just iterate over the whole DB.
+ */
+ ret = ldb_kv->kv_ops->iterate(ldb_kv, search_func, ctx);
+ }
+
+ if (ret < 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ctx->error;
+}
+
+static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv,
+ struct ldb_kv_context *ctx)
+{
+ struct ldb_message *msg;
+ struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
+ const char *dn_linearized;
+ const char *msg_dn_linearized;
+ int ret;
+ bool matched;
+
+ msg = ldb_msg_new(ctx);
+ if (!msg) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_kv_search_dn1(ctx->module,
+ ctx->base,
+ msg,
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC |
+ LDB_UNPACK_DATA_FLAG_READ_LOCKED);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ if (ldb_kv->check_base == false) {
+ /*
+ * In this case, we are done, as no base
+ * checking is allowed in this DB
+ */
+ talloc_free(msg);
+ return LDB_SUCCESS;
+ }
+ ldb_asprintf_errstring(ldb,
+ "No such Base DN: %s",
+ ldb_dn_get_linearized(ctx->base));
+ }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ if (ldb->redact.callback != NULL) {
+ ret = ldb->redact.callback(ldb->redact.module, ctx->req, msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+ }
+
+ /*
+ * We use this, not ldb_match_msg_error() as we know
+ * we matched on the scope BASE, as we just fetched
+ * the base DN
+ */
+
+ ret = ldb_match_message(ldb, msg,
+ ctx->tree,
+ ctx->scope,
+ &matched);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+ if (!matched) {
+ talloc_free(msg);
+ return LDB_SUCCESS;
+ }
+
+ dn_linearized = ldb_dn_get_linearized(ctx->base);
+ msg_dn_linearized = ldb_dn_get_linearized(msg->dn);
+
+ if (strcmp(dn_linearized, msg_dn_linearized) == 0) {
+ /*
+ * If the DN is exactly the same string, then
+ * re-use the full incoming DN for the
+ * returned result, as it has already been
+ * casefolded
+ */
+ struct ldb_dn *dn = ldb_dn_copy(msg, ctx->base);
+ if (dn != NULL) {
+ msg->dn = dn;
+ }
+ }
+
+ ret = ldb_msg_add_distinguished_name(msg);
+ if (ret == -1) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * filter the attributes that the user wants.
+ */
+ ret = ldb_kv_filter_attrs_in_place(msg, ctx->attrs);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_msg_shrink_to_fit(msg);
+
+ /* Ensure the message elements are all talloc'd. */
+ ret = ldb_msg_elements_take_ownership(msg);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Remove any extended components, we just want the casefold components
+ */
+ ldb_dn_remove_extended_components(msg->dn);
+
+ ret = ldb_module_send_entry(ctx->req, msg, NULL);
+ if (ret != LDB_SUCCESS) {
+ /* Regardless of success or failure, the msg
+ * is the callbacks responsibility, and should
+ * not be talloc_free()'ed */
+ ctx->request_terminated = true;
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ search the database with a LDAP-like expression.
+ choses a search method
+*/
+int ldb_kv_search(struct ldb_kv_context *ctx)
+{
+ struct ldb_context *ldb;
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ if (ldb_kv->kv_ops->lock_read(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ldb_kv_cache_load(module) != 0) {
+ ldb_kv->kv_ops->unlock_read(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.tree == NULL) {
+ ldb_kv->kv_ops->unlock_read(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ctx->tree = req->op.search.tree;
+ ctx->scope = req->op.search.scope;
+ ctx->base = req->op.search.base;
+ ctx->attrs = req->op.search.attrs;
+
+ if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) {
+
+ /* Check what we should do with a NULL dn */
+ switch (req->op.search.scope) {
+ case LDB_SCOPE_BASE:
+ ldb_asprintf_errstring(ldb,
+ "NULL Base DN invalid for a base search");
+ ret = LDB_ERR_INVALID_DN_SYNTAX;
+ break;
+ case LDB_SCOPE_ONELEVEL:
+ ldb_asprintf_errstring(ldb,
+ "NULL Base DN invalid for a one-level search");
+ ret = LDB_ERR_INVALID_DN_SYNTAX;
+ break;
+ case LDB_SCOPE_SUBTREE:
+ default:
+ /* We accept subtree searches from a NULL base DN, ie over the whole DB */
+ ret = LDB_SUCCESS;
+ }
+ } else if (req->op.search.scope == LDB_SCOPE_BASE) {
+
+ /*
+ * If we are LDB_SCOPE_BASE, do just one search and
+ * return early. This is critical to ensure we do not
+ * go into the index code for special DNs, as that
+ * will try to look up an index record for a special
+ * record (which doesn't exist).
+ */
+ ret = ldb_kv_search_and_return_base(ldb_kv, ctx);
+
+ ldb_kv->kv_ops->unlock_read(module);
+
+ return ret;
+
+ } else if (ldb_kv->check_base) {
+ /*
+ * This database has been marked as
+ * 'checkBaseOnSearch', so do a spot check of the base
+ * dn. Also optimise the subsequent filter by filling
+ * in the ctx->base to be exactly case correct
+ */
+ ret = ldb_kv_search_base(
+ module, ctx, req->op.search.base, &ctx->base);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ldb_asprintf_errstring(ldb,
+ "No such Base DN: %s",
+ ldb_dn_get_linearized(req->op.search.base));
+ }
+
+ } else if (ldb_dn_validate(req->op.search.base) == false) {
+
+ /* We don't want invalid base DNs here */
+ ldb_asprintf_errstring(ldb,
+ "Invalid Base DN: %s",
+ ldb_dn_get_linearized(req->op.search.base));
+ ret = LDB_ERR_INVALID_DN_SYNTAX;
+
+ } else {
+ /* If we are not checking the base DN life is easy */
+ ret = LDB_SUCCESS;
+ }
+
+ if (ret == LDB_SUCCESS) {
+ uint32_t match_count = 0;
+
+ ret = ldb_kv_search_indexed(ctx, &match_count);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* Not in the index, therefore OK! */
+ ret = LDB_SUCCESS;
+
+ }
+ /* Check if we got just a normal error.
+ * In that case proceed to a full search unless we got a
+ * callback error */
+ if (!ctx->request_terminated && ret != LDB_SUCCESS) {
+ /* Not indexed, so we need to do a full scan */
+ if (ldb_kv->warn_unindexed ||
+ ldb_kv->disable_full_db_scan) {
+ /* useful for debugging when slow performance
+ * is caused by unindexed searches */
+ char *expression = ldb_filter_from_tree(ctx, ctx->tree);
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb FULL SEARCH: %s SCOPE: %s DN: %s",
+ expression,
+ req->op.search.scope==LDB_SCOPE_BASE?"base":
+ req->op.search.scope==LDB_SCOPE_ONELEVEL?"one":
+ req->op.search.scope==LDB_SCOPE_SUBTREE?"sub":"UNKNOWN",
+ ldb_dn_get_linearized(req->op.search.base));
+
+ talloc_free(expression);
+ }
+
+ if (match_count != 0) {
+ /* the indexing code gave an error
+ * after having returned at least one
+ * entry. This means the indexes are
+ * corrupt or a database record is
+ * corrupt. We cannot continue with a
+ * full search or we may return
+ * duplicate entries
+ */
+ ldb_kv->kv_ops->unlock_read(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ldb_kv->disable_full_db_scan) {
+ ldb_set_errstring(ldb,
+ "ldb FULL SEARCH disabled");
+ ldb_kv->kv_ops->unlock_read(module);
+ return LDB_ERR_INAPPROPRIATE_MATCHING;
+ }
+
+ ret = ldb_kv_search_full(ctx);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(ldb, "Indexed and full searches both failed!\n");
+ }
+ }
+ }
+
+ ldb_kv->kv_ops->unlock_read(module);
+
+ return ret;
+}
diff --git a/lib/ldb/ldb_ldap/ldb_ldap.c b/lib/ldb/ldb_ldap/ldb_ldap.c
new file mode 100644
index 0000000..7545a58
--- /dev/null
+++ b/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -0,0 +1,967 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Simo Sorce 2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_ldap
+ *
+ * Component: ldb ldap backend
+ *
+ * Description: core files for LDAP backend
+ *
+ * Author: Andrew Tridgell
+ *
+ * Modifications:
+ *
+ * - description: make the module use asynchronous calls
+ * date: Feb 2006
+ * author: Simo Sorce
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_module.h"
+#include "ldb_private.h"
+
+#define LDAP_DEPRECATED 1
+#include <ldap.h>
+
+struct lldb_private {
+ LDAP *ldap;
+};
+
+struct lldb_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ struct lldb_private *lldb;
+
+ struct ldb_control **controls;
+ int msgid;
+};
+
+static int lldb_ldap_to_ldb(int err) {
+ /* Ldap errors and ldb errors are defined to the same values */
+ return err;
+}
+
+/*
+ convert a ldb_message structure to a list of LDAPMod structures
+ ready for ldap_add() or ldap_modify()
+*/
+static LDAPMod **lldb_msg_to_mods(void *mem_ctx, const struct ldb_message *msg, int use_flags)
+{
+ LDAPMod **mods;
+ unsigned int i, j;
+ int num_mods = 0;
+
+ /* allocate maximum number of elements needed */
+ mods = talloc_array(mem_ctx, LDAPMod *, msg->num_elements+1);
+ if (!mods) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mods[0] = NULL;
+
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+
+ mods[num_mods] = talloc(mods, LDAPMod);
+ if (!mods[num_mods]) {
+ goto failed;
+ }
+ mods[num_mods+1] = NULL;
+ mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
+ if (use_flags) {
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ mods[num_mods]->mod_op |= LDAP_MOD_ADD;
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
+ break;
+ }
+ }
+ mods[num_mods]->mod_type = discard_const_p(char, el->name);
+ mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods],
+ struct berval *,
+ 1+el->num_values);
+ if (!mods[num_mods]->mod_vals.modv_bvals) {
+ goto failed;
+ }
+
+ for (j=0;j<el->num_values;j++) {
+ mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals,
+ struct berval);
+ if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
+ goto failed;
+ }
+ mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = (char *)el->values[j].data;
+ mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
+ }
+ mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
+ num_mods++;
+ }
+
+ return mods;
+
+failed:
+ talloc_free(mods);
+ return NULL;
+}
+
+/*
+ add a single set of ldap message values to a ldb_message
+*/
+static int lldb_add_msg_attr(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ const char *attr, struct berval **bval)
+{
+ int count, i, ret;
+ struct ldb_message_element *el;
+
+ count = ldap_count_values_len(bval);
+
+ if (count <= 0) {
+ return -1;
+ }
+
+ ret = ldb_msg_add_empty(msg, attr, 0, &el);
+ if (ret != LDB_SUCCESS) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ el->values = talloc_array(msg->elements, struct ldb_val, count);
+ if (!el->values) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (i=0;i<count;i++) {
+ /* we have to ensure this is null terminated so that
+ ldb_msg_find_attr_as_string() can work */
+ el->values[i].data = talloc_size(el->values, bval[i]->bv_len+1);
+ if (!el->values[i].data) {
+ errno = ENOMEM;
+ return -1;
+ }
+ memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
+ el->values[i].data[bval[i]->bv_len] = 0;
+ el->values[i].length = bval[i]->bv_len;
+ el->num_values++;
+ }
+
+ return 0;
+}
+
+/*
+ search for matching records
+*/
+static int lldb_search(struct lldb_context *lldb_ac)
+{
+ struct ldb_context *ldb;
+ struct lldb_private *lldb = lldb_ac->lldb;
+ struct ldb_module *module = lldb_ac->module;
+ struct ldb_request *req = lldb_ac->req;
+ struct timeval tv;
+ int ldap_scope;
+ char *search_base;
+ char *expression;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ if (!req->callback || !req->context) {
+ ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.tree == NULL) {
+ ldb_set_errstring(ldb, "Invalid expression parse tree");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->controls != NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!");
+ }
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base);
+ if (req->op.search.base == NULL) {
+ search_base = talloc_strdup(lldb_ac, "");
+ }
+ if (search_base == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree);
+ if (expression == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ switch (req->op.search.scope) {
+ case LDB_SCOPE_BASE:
+ ldap_scope = LDAP_SCOPE_BASE;
+ break;
+ case LDB_SCOPE_ONELEVEL:
+ ldap_scope = LDAP_SCOPE_ONELEVEL;
+ break;
+ default:
+ ldap_scope = LDAP_SCOPE_SUBTREE;
+ break;
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ if (req->timeout > 0) {
+ tv.tv_sec = req->timeout;
+ }
+
+ ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope,
+ expression,
+ discard_const_p(char *, req->op.search.attrs),
+ 0,
+ NULL,
+ NULL,
+ &tv,
+ LDAP_NO_LIMIT,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ add a record
+*/
+static int lldb_add(struct lldb_context *lldb_ac)
+{
+ struct ldb_context *ldb;
+ struct lldb_private *lldb = lldb_ac->lldb;
+ struct ldb_module *module = lldb_ac->module;
+ struct ldb_request *req = lldb_ac->req;
+ LDAPMod **mods;
+ char *dn;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ mods = lldb_msg_to_mods(lldb_ac, req->op.add.message, 0);
+ if (mods == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ dn = ldb_dn_alloc_linearized(lldb_ac, req->op.add.message->dn);
+ if (dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldap_add_ext(lldb->ldap, dn, mods,
+ NULL,
+ NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ modify a record
+*/
+static int lldb_modify(struct lldb_context *lldb_ac)
+{
+ struct ldb_context *ldb;
+ struct lldb_private *lldb = lldb_ac->lldb;
+ struct ldb_module *module = lldb_ac->module;
+ struct ldb_request *req = lldb_ac->req;
+ LDAPMod **mods;
+ char *dn;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1);
+ if (mods == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ dn = ldb_dn_alloc_linearized(lldb_ac, req->op.mod.message->dn);
+ if (dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldap_modify_ext(lldb->ldap, dn, mods,
+ NULL,
+ NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ delete a record
+*/
+static int lldb_delete(struct lldb_context *lldb_ac)
+{
+ struct ldb_context *ldb;
+ struct lldb_private *lldb = lldb_ac->lldb;
+ struct ldb_module *module = lldb_ac->module;
+ struct ldb_request *req = lldb_ac->req;
+ char *dnstr;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn);
+
+ ret = ldap_delete_ext(lldb->ldap, dnstr,
+ NULL,
+ NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+/*
+ rename a record
+*/
+static int lldb_rename(struct lldb_context *lldb_ac)
+{
+ struct ldb_context *ldb;
+ struct lldb_private *lldb = lldb_ac->lldb;
+ struct ldb_module *module = lldb_ac->module;
+ struct ldb_request *req = lldb_ac->req;
+ const char *rdn_name;
+ const struct ldb_val *rdn_val;
+ char *old_dn;
+ char *newrdn;
+ char *parentdn;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn);
+ if (old_dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
+ rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);
+
+ if ((rdn_name != NULL) && (rdn_val != NULL)) {
+ newrdn = talloc_asprintf(lldb_ac, "%s=%s", rdn_name,
+ rdn_val->length > 0 ? ldb_dn_escape_value(lldb_ac, *rdn_val) : "");
+ } else {
+ newrdn = talloc_strdup(lldb_ac, "");
+ }
+ if (!newrdn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ parentdn = ldb_dn_alloc_linearized(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn));
+ if (!parentdn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn,
+ 1, NULL, NULL,
+ &lldb_ac->msgid);
+
+ if (ret != LDAP_SUCCESS) {
+ ldb_set_errstring(ldb, ldap_err2string(ret));
+ }
+
+ return lldb_ldap_to_ldb(ret);
+}
+
+static int lldb_start_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int lldb_end_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static int lldb_del_trans(struct ldb_module *module)
+{
+ /* TODO implement a local transaction mechanism here */
+
+ return LDB_SUCCESS;
+}
+
+static void lldb_request_done(struct lldb_context *ac,
+ struct ldb_control **ctrls, int error)
+{
+ struct ldb_request *req;
+ struct ldb_reply *ares;
+
+ req = ac->req;
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(ldb_module_get_ctx(ac->module));
+ req->callback(req, NULL);
+ return;
+ }
+ ares->type = LDB_REPLY_DONE;
+ ares->controls = talloc_steal(ares, ctrls);
+ ares->error = error;
+
+ req->callback(req, ares);
+}
+
+/* return false if the request is still in progress
+ * return true if the request is completed
+ */
+static bool lldb_parse_result(struct lldb_context *ac, LDAPMessage *result)
+{
+ struct ldb_context *ldb;
+ struct lldb_private *lldb = ac->lldb;
+ LDAPControl **serverctrlsp = NULL;
+ char **referralsp = NULL;
+ char *matcheddnp = NULL;
+ char *errmsgp = NULL;
+ LDAPMessage *msg;
+ int type;
+ struct ldb_message *ldbmsg = NULL;
+ char *referral;
+ bool callback_failed;
+ bool request_done;
+ bool lret;
+ unsigned int i;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ type = ldap_msgtype(result);
+ callback_failed = false;
+ request_done = false;
+
+ switch (type) {
+ case LDAP_RES_SEARCH_ENTRY:
+
+ msg = ldap_first_entry(lldb->ldap, result);
+ if (msg != NULL) {
+ BerElement *berptr = NULL;
+ char *attr, *dn;
+
+ ldbmsg = ldb_msg_new(ac);
+ if (!ldbmsg) {
+ ldb_oom(ldb);
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+
+ dn = ldap_get_dn(lldb->ldap, msg);
+ if (!dn) {
+ ldb_oom(ldb);
+ talloc_free(ldbmsg);
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+ ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, dn);
+ if ( ! ldb_dn_validate(ldbmsg->dn)) {
+ ldb_asprintf_errstring(ldb, "Invalid DN '%s' in reply", dn);
+ talloc_free(ldbmsg);
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ ldap_memfree(dn);
+ break;
+ }
+ ldap_memfree(dn);
+ /* loop over all attributes */
+ for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
+ attr;
+ attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
+ struct berval **bval;
+ bval = ldap_get_values_len(lldb->ldap, msg, attr);
+
+ if (bval) {
+ lldb_add_msg_attr(ldb, ldbmsg, attr, bval);
+ ldap_value_free_len(bval);
+ }
+ }
+ if (berptr) ber_free(berptr, 0);
+
+ ret = ldb_module_send_entry(ac->req, ldbmsg, NULL /* controls not yet supported */);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "entry send failed: %s",
+ ldb_errstring(ldb));
+ callback_failed = true;
+ }
+ } else {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+ break;
+
+ case LDAP_RES_SEARCH_REFERENCE:
+
+ ret = ldap_parse_reference(lldb->ldap, result,
+ &referralsp, &serverctrlsp, 0);
+ if (ret != LDAP_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "ldap reference parse error: %s : %s",
+ ldap_err2string(ret), errmsgp);
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+ if (referralsp == NULL) {
+ ldb_asprintf_errstring(ldb, "empty ldap referrals list");
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+
+ for (i = 0; referralsp[i]; i++) {
+ referral = talloc_strdup(ac, referralsp[i]);
+
+ ret = ldb_module_send_referral(ac->req, referral);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "referral send failed: %s",
+ ldb_errstring(ldb));
+ callback_failed = true;
+ break;
+ }
+ }
+ break;
+
+ case LDAP_RES_SEARCH_RESULT:
+ case LDAP_RES_MODIFY:
+ case LDAP_RES_ADD:
+ case LDAP_RES_DELETE:
+ case LDAP_RES_MODDN:
+
+ if (ldap_parse_result(lldb->ldap, result, &ret,
+ &matcheddnp, &errmsgp,
+ &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "ldap parse error for type %d: %s : %s",
+ type, ldap_err2string(ret), errmsgp);
+ break;
+ }
+
+ if (serverctrlsp != NULL) {
+ /* FIXME: transform the LDAPControl list into an ldb_control one */
+ ac->controls = NULL;
+ }
+
+ request_done = true;
+ break;
+
+ default:
+ ldb_asprintf_errstring(ldb, "unknown ldap return type: %d", type);
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+
+ if (ret != LDB_SUCCESS) {
+
+ /* if the callback failed the caller will have freed the
+ * request. Just return and don't try to use it */
+ if (callback_failed) {
+
+ /* tell lldb_wait to remove the request from the
+ * queue */
+ lret = true;
+ goto free_and_return;
+ }
+
+ request_done = true;
+ }
+
+ if (request_done) {
+ lldb_request_done(ac, ac->controls, ret);
+ lret = true;
+ goto free_and_return;
+ }
+
+ lret = false;
+
+free_and_return:
+
+ if (matcheddnp) ldap_memfree(matcheddnp);
+ if (errmsgp && *errmsgp) {
+ ldb_set_errstring(ldb, errmsgp);
+ }
+ if (errmsgp) {
+ ldap_memfree(errmsgp);
+ }
+ if (referralsp) ldap_value_free(referralsp);
+ if (serverctrlsp) ldap_controls_free(serverctrlsp);
+
+ ldap_msgfree(result);
+
+ return lret;
+}
+
+static void lldb_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *private_data)
+{
+ struct lldb_context *ac;
+ ac = talloc_get_type(private_data, struct lldb_context);
+
+ lldb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED);
+}
+
+static void lldb_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *private_data)
+{
+ struct lldb_context *ac;
+ struct tevent_timer *lte;
+ struct timeval tv;
+ LDAPMessage *result;
+ int lret;
+
+ ac = talloc_get_type(private_data, struct lldb_context);
+
+ if (!ac->msgid) {
+ lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
+ return;
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ lret = ldap_result(ac->lldb->ldap, ac->msgid, 0, &tv, &result);
+ if (lret == 0) {
+ goto respin;
+ }
+ if (lret == -1) {
+ lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
+ return;
+ }
+
+ if ( ! lldb_parse_result(ac, result)) {
+ goto respin;
+ }
+
+ return;
+
+respin:
+ tv.tv_sec = 0;
+ tv.tv_usec = 100;
+ lte = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
+ if (NULL == lte) {
+ lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
+ }
+}
+
+static bool lldb_dn_is_special(struct ldb_request *req)
+{
+ struct ldb_dn *dn = NULL;
+
+ switch (req->operation) {
+ case LDB_ADD:
+ dn = req->op.add.message->dn;
+ break;
+ case LDB_MODIFY:
+ dn = req->op.mod.message->dn;
+ break;
+ case LDB_DELETE:
+ dn = req->op.del.dn;
+ break;
+ case LDB_RENAME:
+ dn = req->op.rename.olddn;
+ break;
+ default:
+ break;
+ }
+
+ if (dn && ldb_dn_is_special(dn)) {
+ return true;
+ }
+ return false;
+}
+
+static void lldb_auto_done_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *private_data)
+{
+ struct lldb_context *ac;
+
+ ac = talloc_get_type(private_data, struct lldb_context);
+ lldb_request_done(ac, NULL, LDB_SUCCESS);
+}
+
+static int lldb_handle_request(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct lldb_private *lldb;
+ struct lldb_context *ac;
+ struct tevent_context *ev;
+ struct tevent_timer *te;
+ struct timeval tv;
+ int ret;
+
+ lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
+ ldb = ldb_module_get_ctx(module);
+
+ if (req->starttime == 0 || req->timeout == 0) {
+ ldb_set_errstring(ldb, "Invalid timeout settings");
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+
+ ev = ldb_get_event_context(ldb);
+ if (NULL == ev) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac = talloc_zero(ldb, struct lldb_context);
+ if (ac == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+ ac->lldb = lldb;
+ ac->msgid = 0;
+
+ if (lldb_dn_is_special(req)) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ te = tevent_add_timer(ev, ac, tv,
+ lldb_auto_done_callback, ac);
+ if (NULL == te) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+ }
+
+ switch (ac->req->operation) {
+ case LDB_SEARCH:
+ ret = lldb_search(ac);
+ break;
+ case LDB_ADD:
+ ret = lldb_add(ac);
+ break;
+ case LDB_MODIFY:
+ ret = lldb_modify(ac);
+ break;
+ case LDB_DELETE:
+ ret = lldb_delete(ac);
+ break;
+ case LDB_RENAME:
+ ret = lldb_rename(ac);
+ break;
+ default:
+ /* no other op supported */
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ lldb_request_done(ac, NULL, ret);
+ return ret;
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ te = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
+ if (NULL == te) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->timeout > 0) {
+ tv.tv_sec = req->starttime + req->timeout;
+ tv.tv_usec = 0;
+ te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
+ if (NULL == te) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+static const struct ldb_module_ops lldb_ops = {
+ .name = "ldap",
+ .search = lldb_handle_request,
+ .add = lldb_handle_request,
+ .modify = lldb_handle_request,
+ .del = lldb_handle_request,
+ .rename = lldb_handle_request,
+ .request = lldb_handle_request,
+ .start_transaction = lldb_start_trans,
+ .end_transaction = lldb_end_trans,
+ .del_transaction = lldb_del_trans,
+};
+
+
+static int lldb_destructor(struct lldb_private *lldb)
+{
+ ldap_unbind(lldb->ldap);
+ return 0;
+}
+
+
+/*
+ optionally perform a bind
+ */
+static int lldb_bind(struct ldb_module *module,
+ const char *options[])
+{
+ const char *bind_mechanism;
+ struct lldb_private *lldb;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ int ret;
+
+ bind_mechanism = ldb_options_find(ldb, options, "bindMech");
+ if (bind_mechanism == NULL) {
+ /* no bind wanted */
+ return LDB_SUCCESS;
+ }
+
+ lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
+
+ if (strcmp(bind_mechanism, "simple") == 0) {
+ const char *bind_id, *bind_secret;
+
+ bind_id = ldb_options_find(ldb, options, "bindID");
+ bind_secret = ldb_options_find(ldb, options, "bindSecret");
+ if (bind_id == NULL || bind_secret == NULL) {
+ ldb_asprintf_errstring(ldb, "simple bind requires bindID and bindSecret");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldap_simple_bind_s(lldb->ldap, bind_id, bind_secret);
+ if (ret != LDAP_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "bind failed: %s", ldap_err2string(ret));
+ return ret;
+ }
+ return LDB_SUCCESS;
+ }
+
+ ldb_asprintf_errstring(ldb, "bind failed: unknown mechanism %s", bind_mechanism);
+ return LDB_ERR_INAPPROPRIATE_AUTHENTICATION;
+}
+
+/*
+ connect to the database
+*/
+static int lldb_connect(struct ldb_context *ldb,
+ const char *url,
+ unsigned int flags,
+ const char *options[],
+ struct ldb_module **_module)
+{
+ struct ldb_module *module;
+ struct lldb_private *lldb;
+ int version = 3;
+ int ret;
+
+ module = ldb_module_new(ldb, ldb, "ldb_ldap backend", &lldb_ops);
+ if (!module) return LDB_ERR_OPERATIONS_ERROR;
+
+ lldb = talloc_zero(module, struct lldb_private);
+ if (!lldb) {
+ ldb_oom(ldb);
+ goto failed;
+ }
+ ldb_module_set_private(module, lldb);
+
+ ret = ldap_initialize(&lldb->ldap, url);
+ if (ret != LDAP_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s",
+ url, ldap_err2string(ret));
+ goto failed;
+ }
+
+ talloc_set_destructor(lldb, lldb_destructor);
+
+ ret = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
+ if (ret != LDAP_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s",
+ ldap_err2string(ret));
+ goto failed;
+ }
+
+ *_module = module;
+
+ ret = lldb_bind(module, options);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+
+ return LDB_SUCCESS;
+
+failed:
+ talloc_free(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+ initialise the module
+ */
+int ldb_ldap_init(const char *version)
+{
+ int ret, i;
+ const char *names[] = { "ldap", "ldaps", "ldapi", NULL };
+ LDB_MODULE_CHECK_VERSION(version);
+ for (i=0; names[i]; i++) {
+ ret = ldb_register_backend(names[i], lldb_connect, false);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb/ldb_ldb/ldb_ldb.c b/lib/ldb/ldb_ldb/ldb_ldb.c
new file mode 100644
index 0000000..a5a3612
--- /dev/null
+++ b/lib/ldb/ldb_ldb/ldb_ldb.c
@@ -0,0 +1,80 @@
+/*
+ * ldb connection and module initialisation
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "ldb_private.h"
+#include "../ldb_tdb/ldb_tdb.h"
+#ifdef HAVE_LMDB
+#include "../ldb_mdb/ldb_mdb.h"
+#endif /* HAVE_LMDB */
+
+/*
+ connect to the database
+*/
+static int lldb_connect(struct ldb_context *ldb,
+ const char *url,
+ unsigned int flags,
+ const char *options[],
+ struct ldb_module **module)
+{
+ const char *path;
+ int ret;
+
+ /*
+ * Check and remove the url prefix
+ */
+ if (strchr(url, ':')) {
+ if (strncmp(url, "ldb://", 6) != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Invalid ldb URL '%s'", url);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ path = url+6;
+ } else {
+ path = url;
+ }
+
+ /*
+ * Don't create the database if it's not there
+ */
+ flags |= LDB_FLG_DONT_CREATE_DB;
+#ifdef HAVE_LMDB
+ /*
+ * Try opening the database as an lmdb
+ */
+ ret = lmdb_connect(ldb, path, flags, options, module);
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (ret != LDB_ERR_UNAVAILABLE) {
+ return ret;
+ }
+
+ /*
+ * Not mdb so try as tdb
+ */
+#endif /* HAVE_LMDB */
+ ret = ltdb_connect(ldb, path, flags, options, module);
+ return ret;
+}
+
+int ldb_ldb_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_backend("ldb", lldb_connect, false);
+}
diff --git a/lib/ldb/ldb_map/ldb_map.c b/lib/ldb/ldb_map/ldb_map.c
new file mode 100644
index 0000000..c7b0c22
--- /dev/null
+++ b/lib/ldb/ldb_map/ldb_map.c
@@ -0,0 +1,1153 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+ Copyright (C) Simo Sorce 2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb ldb_map module
+ *
+ * Description: Map portions of data into a different format on a
+ * remote partition.
+ *
+ * Author: Jelmer Vernooij, Martin Kuehl
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_map.h"
+#include "ldb_map_private.h"
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+/* Description of the provided ldb requests:
+ - special attribute 'isMapped'
+
+ - search:
+ - if parse tree can be split
+ - search remote records w/ remote attrs and parse tree
+ - otherwise
+ - enumerate all remote records
+ - for each remote result
+ - map remote result to local message
+ - search local result
+ - is present
+ - merge local into remote result
+ - run callback on merged result
+ - otherwise
+ - run callback on remote result
+
+ - add:
+ - split message into local and remote part
+ - if local message is not empty
+ - add isMapped to local message
+ - add local message
+ - add remote message
+
+ - modify:
+ - split message into local and remote part
+ - if local message is not empty
+ - add isMapped to local message
+ - search for local record
+ - if present
+ - modify local record
+ - otherwise
+ - add local message
+ - modify remote record
+
+ - delete:
+ - search for local record
+ - if present
+ - delete local record
+ - delete remote record
+
+ - rename:
+ - search for local record
+ - if present
+ - rename local record
+ - modify local isMapped
+ - rename remote record
+*/
+
+
+
+/* Private data structures
+ * ======================= */
+
+/* Global private data */
+/* Extract mappings from private data. */
+const struct ldb_map_context *map_get_context(struct ldb_module *module)
+{
+ const struct map_private *data = talloc_get_type(ldb_module_get_private(module), struct map_private);
+ return data->context;
+}
+
+/* Create a generic request context. */
+struct map_context *map_init_context(struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct map_context *ac;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ac = talloc_zero(req, struct map_context);
+ if (ac == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return NULL;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ return ac;
+}
+
+/* Dealing with DNs for different partitions
+ * ========================================= */
+
+/* Check whether any data should be stored in the local partition. */
+bool map_check_local_db(struct ldb_module *module)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+
+ if (!data->remote_base_dn || !data->local_base_dn) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Copy a DN with the base DN of the local partition. */
+static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
+{
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_copy(mem_ctx, dn);
+ if ( ! ldb_dn_validate(new_dn)) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ /* may be we don't need to rebase at all */
+ if ( ! data->remote_base_dn || ! data->local_base_dn) {
+ return new_dn;
+ }
+
+ if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->remote_base_dn))) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ if ( ! ldb_dn_add_base(new_dn, data->local_base_dn)) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ return new_dn;
+}
+
+/* Copy a DN with the base DN of the remote partition. */
+static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
+{
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_copy(mem_ctx, dn);
+ if ( ! ldb_dn_validate(new_dn)) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ /* may be we don't need to rebase at all */
+ if ( ! data->remote_base_dn || ! data->local_base_dn) {
+ return new_dn;
+ }
+
+ if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->local_base_dn))) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ if ( ! ldb_dn_add_base(new_dn, data->remote_base_dn)) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+
+ return new_dn;
+}
+
+/* Run a request and make sure it targets the remote partition. */
+/* TODO: free old DNs and messages? */
+int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
+ struct ldb_message *msg;
+
+ ldb = ldb_module_get_ctx(module);
+
+ switch (request->operation) {
+ case LDB_SEARCH:
+ if (request->op.search.base) {
+ request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base);
+ } else {
+ request->op.search.base = data->remote_base_dn;
+ /* TODO: adjust scope? */
+ }
+ break;
+
+ case LDB_ADD:
+ msg = ldb_msg_copy_shallow(request, request->op.add.message);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
+ request->op.add.message = msg;
+ break;
+
+ case LDB_MODIFY:
+ msg = ldb_msg_copy_shallow(request, request->op.mod.message);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
+ request->op.mod.message = msg;
+ break;
+
+ case LDB_DELETE:
+ request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn);
+ break;
+
+ case LDB_RENAME:
+ request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn);
+ request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn);
+ break;
+
+ default:
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Invalid remote request!");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(module, request);
+}
+
+
+/* Finding mappings for attributes and objectClasses
+ * ================================================= */
+
+/* Find an objectClass mapping by the local name. */
+static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) {
+ if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) {
+ return &data->objectclass_maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Find an objectClass mapping by the remote name. */
+static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) {
+ if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) {
+ return &data->objectclass_maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Find an attribute mapping by the local name. */
+const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) {
+ return &data->attribute_maps[i];
+ }
+ }
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) {
+ return &data->attribute_maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Find an attribute mapping by the remote name. */
+const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name)
+{
+ const struct ldb_map_attribute *map;
+ const struct ldb_map_attribute *wildcard = NULL;
+ unsigned int i, j;
+
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ map = &data->attribute_maps[i];
+ if (ldb_attr_cmp(map->local_name, "*") == 0) {
+ wildcard = &data->attribute_maps[i];
+ }
+
+ switch (map->type) {
+ case LDB_MAP_IGNORE:
+ break;
+
+ case LDB_MAP_KEEP:
+ if (ldb_attr_cmp(map->local_name, name) == 0) {
+ return map;
+ }
+ break;
+
+ case LDB_MAP_RENAME:
+ case LDB_MAP_RENDROP:
+ case LDB_MAP_CONVERT:
+ if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) {
+ return map;
+ }
+ break;
+
+ case LDB_MAP_GENERATE:
+ for (j = 0; map->u.generate.remote_names[j]; j++) {
+ if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) {
+ return map;
+ }
+ }
+ break;
+ }
+ }
+
+ /* We didn't find it, so return the wildcard record if one was configured */
+ return wildcard;
+}
+
+
+/* Mapping attributes
+ * ================== */
+
+/* Check whether an attribute will be mapped into the remote partition. */
+bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr)
+{
+ const struct ldb_map_attribute *map = map_attr_find_local(data, attr);
+
+ if (map == NULL) {
+ return false;
+ }
+ if (map->type == LDB_MAP_IGNORE) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Map an attribute name into the remote partition. */
+const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
+{
+ if (map == NULL) {
+ return talloc_strdup(mem_ctx, attr);
+ }
+
+ switch (map->type) {
+ case LDB_MAP_KEEP:
+ return talloc_strdup(mem_ctx, attr);
+
+ case LDB_MAP_RENAME:
+ case LDB_MAP_RENDROP:
+ case LDB_MAP_CONVERT:
+ return talloc_strdup(mem_ctx, map->u.rename.remote_name);
+
+ default:
+ return NULL;
+ }
+}
+
+/* Map an attribute name back into the local partition. */
+const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
+{
+ if (map == NULL) {
+ return talloc_strdup(mem_ctx, attr);
+ }
+
+ if (map->type == LDB_MAP_KEEP) {
+ return talloc_strdup(mem_ctx, attr);
+ }
+
+ return talloc_strdup(mem_ctx, map->local_name);
+}
+
+
+/* Merge two lists of attributes into a single one. */
+int map_attrs_merge(struct ldb_module *module, void *mem_ctx,
+ const char ***attrs, const char * const *more_attrs)
+{
+ unsigned int i, j, k;
+
+ for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ;
+ for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ;
+
+ *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1);
+ if (*attrs == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ for (k = 0; k < j; k++) {
+ (*attrs)[i + k] = more_attrs[k];
+ }
+
+ (*attrs)[i+k] = NULL;
+
+ return 0;
+}
+
+/* Mapping ldb values
+ * ================== */
+
+/* Map an ldb value into the remote partition. */
+struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx,
+ const struct ldb_map_attribute *map, const struct ldb_val *val)
+{
+ if (map && (map->type == LDB_MAP_CONVERT) && (map->u.convert.convert_local)) {
+ return map->u.convert.convert_local(module, mem_ctx, val);
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+/* Map an ldb value back into the local partition. */
+struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx,
+ const struct ldb_map_attribute *map, const struct ldb_val *val)
+{
+ if (map && (map->type == LDB_MAP_CONVERT) && (map->u.convert.convert_remote)) {
+ return map->u.convert.convert_remote(module, mem_ctx, val);
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+
+/* Mapping DNs
+ * =========== */
+
+/* Check whether a DN is below the local baseDN. */
+bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+
+ if (!data->local_base_dn) {
+ return true;
+ }
+
+ return ldb_dn_compare_base(data->local_base_dn, dn) == 0;
+}
+
+/* Map a DN into the remote partition. */
+struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
+ struct ldb_dn *newdn;
+ const struct ldb_map_attribute *map;
+ enum ldb_map_attr_type map_type;
+ const char *name;
+ struct ldb_val value;
+ int i, ret;
+
+ if (dn == NULL) {
+ return NULL;
+ }
+
+ ldb = ldb_module_get_ctx(module);
+
+ newdn = ldb_dn_copy(mem_ctx, dn);
+ if (newdn == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ /* For each RDN, map the component name and possibly the value */
+ for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
+ map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i));
+
+ /* Unknown attribute - leave this RDN as is and hope the best... */
+ if (map == NULL) {
+ map_type = LDB_MAP_KEEP;
+ } else {
+ map_type = map->type;
+ }
+
+ switch (map_type) {
+ case LDB_MAP_IGNORE:
+ case LDB_MAP_GENERATE:
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "LDB_MAP_IGNORE/LDB_MAP_GENERATE attribute '%s' "
+ "used in DN!", ldb_dn_get_component_name(dn, i));
+ goto failed;
+
+ case LDB_MAP_CONVERT:
+ if (map->u.convert.convert_local == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "'convert_local' not set for attribute '%s' "
+ "used in DN!", ldb_dn_get_component_name(dn, i));
+ goto failed;
+ }
+
+ FALL_THROUGH;
+ case LDB_MAP_KEEP:
+ case LDB_MAP_RENAME:
+ case LDB_MAP_RENDROP:
+ name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i));
+ if (name == NULL) goto failed;
+
+ value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i));
+ if (value.data == NULL) goto failed;
+
+ ret = ldb_dn_set_component(newdn, i, name, value);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ break;
+ }
+ }
+
+ return newdn;
+
+failed:
+ talloc_free(newdn);
+ return NULL;
+}
+
+/* Map a DN into the local partition. */
+struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
+ struct ldb_dn *newdn;
+ const struct ldb_map_attribute *map;
+ enum ldb_map_attr_type map_type;
+ const char *name;
+ struct ldb_val value;
+ int i, ret;
+
+ if (dn == NULL) {
+ return NULL;
+ }
+
+ ldb = ldb_module_get_ctx(module);
+
+ newdn = ldb_dn_copy(mem_ctx, dn);
+ if (newdn == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ /* For each RDN, map the component name and possibly the value */
+ for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
+ map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i));
+
+ /* Unknown attribute - leave this RDN as is and hope the best... */
+ if (map == NULL) {
+ map_type = LDB_MAP_KEEP;
+ } else {
+ map_type = map->type;
+ }
+
+ switch (map_type) {
+ case LDB_MAP_IGNORE:
+ case LDB_MAP_GENERATE:
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "LDB_MAP_IGNORE/LDB_MAP_GENERATE attribute '%s' "
+ "used in DN!", ldb_dn_get_component_name(dn, i));
+ goto failed;
+
+ case LDB_MAP_CONVERT:
+ if (map->u.convert.convert_remote == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "'convert_remote' not set for attribute '%s' "
+ "used in DN!", ldb_dn_get_component_name(dn, i));
+ goto failed;
+ }
+
+ FALL_THROUGH;
+ case LDB_MAP_KEEP:
+ case LDB_MAP_RENAME:
+ case LDB_MAP_RENDROP:
+ name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i));
+ if (name == NULL) goto failed;
+
+ value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i));
+ if (value.data == NULL) goto failed;
+
+ ret = ldb_dn_set_component(newdn, i, name, value);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ break;
+ }
+ }
+
+ return newdn;
+
+failed:
+ talloc_free(newdn);
+ return NULL;
+}
+
+/* Map a DN and its base into the local partition. */
+/* TODO: This should not be required with GUIDs. */
+struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_dn *dn1, *dn2;
+
+ dn1 = ldb_dn_rebase_local(mem_ctx, data, dn);
+ dn2 = ldb_dn_map_remote(module, mem_ctx, dn1);
+
+ talloc_free(dn1);
+ return dn2;
+}
+
+
+/* Converting DNs and objectClasses (as ldb values)
+ * ================================================ */
+
+/* Map a DN contained in an ldb value into the remote partition. */
+static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *dn, *newdn;
+ struct ldb_val newval;
+
+ ldb = ldb_module_get_ctx(module);
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
+ if (! ldb_dn_validate(dn)) {
+ newval.length = 0;
+ newval.data = NULL;
+ talloc_free(dn);
+ return newval;
+ }
+ newdn = ldb_dn_map_local(module, mem_ctx, dn);
+ talloc_free(dn);
+
+ newval.length = 0;
+ newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
+ if (newval.data) {
+ newval.length = strlen((char *)newval.data);
+ }
+ talloc_free(newdn);
+
+ return newval;
+}
+
+/* Map a DN contained in an ldb value into the local partition. */
+static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *dn, *newdn;
+ struct ldb_val newval;
+
+ ldb = ldb_module_get_ctx(module);
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
+ if (! ldb_dn_validate(dn)) {
+ newval.length = 0;
+ newval.data = NULL;
+ talloc_free(dn);
+ return newval;
+ }
+ newdn = ldb_dn_map_remote(module, mem_ctx, dn);
+ talloc_free(dn);
+
+ newval.length = 0;
+ newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
+ if (newval.data) {
+ newval.length = strlen((char *)newval.data);
+ }
+ talloc_free(newdn);
+
+ return newval;
+}
+
+/* Map an objectClass into the remote partition. */
+static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char *name = (char *)val->data;
+ const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name);
+ struct ldb_val newval;
+
+ if (map) {
+ newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name);
+ newval.length = strlen((char *)newval.data);
+ return newval;
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+/* Generate a remote message with a mapped objectClass. */
+static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
+ struct ldb_message_element *el, *oc;
+ struct ldb_val val;
+ bool found_extensibleObject = false;
+ unsigned int i;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* Find old local objectClass */
+ oc = ldb_msg_find_element(old, "objectClass");
+ if (oc == NULL) {
+ return;
+ }
+
+ /* Prepare new element */
+ el = talloc_zero(remote, struct ldb_message_element);
+ if (el == NULL) {
+ ldb_oom(ldb);
+ return; /* TODO: fail? */
+ }
+
+ /* Copy local objectClass element, reverse space for an extra value */
+ el->num_values = oc->num_values + 1;
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ ldb_oom(ldb);
+ return; /* TODO: fail? */
+ }
+
+ /* Copy local element name "objectClass" */
+ el->name = talloc_strdup(el, local_attr);
+
+ /* Convert all local objectClasses */
+ for (i = 0; i < el->num_values - 1; i++) {
+ el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]);
+ if (ldb_attr_cmp((char *)el->values[i].data, data->add_objectclass) == 0) {
+ found_extensibleObject = true;
+ }
+ }
+
+ if (!found_extensibleObject) {
+ val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
+ val.length = strlen((char *)val.data);
+
+ /* Append additional objectClass data->add_objectclass */
+ el->values[i] = val;
+ } else {
+ el->num_values--;
+ }
+
+ /* Add new objectClass to remote message */
+ ret = ldb_msg_add(remote, el, 0);
+ if (ret != LDB_SUCCESS) {
+ ldb_oom(ldb);
+ return;
+ }
+}
+
+/* Map an objectClass into the local partition. */
+static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char *name = (char *)val->data;
+ const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name);
+ struct ldb_val newval;
+
+ if (map) {
+ newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name);
+ newval.length = strlen((char *)newval.data);
+ return newval;
+ }
+
+ return ldb_val_dup(mem_ctx, val);
+}
+
+/* Generate a local message with a mapped objectClass. */
+static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
+ struct ldb_message_element *el, *oc;
+ struct ldb_val val;
+ unsigned int i;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* Find old remote objectClass */
+ oc = ldb_msg_find_element(remote, "objectClass");
+ if (oc == NULL) {
+ return NULL;
+ }
+
+ /* Prepare new element */
+ el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ ldb_oom(ldb);
+ return NULL;
+ }
+
+ /* Copy remote objectClass element */
+ el->num_values = oc->num_values;
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ ldb_oom(ldb);
+ return NULL;
+ }
+
+ /* Copy remote element name "objectClass" */
+ el->name = talloc_strdup(el, local_attr);
+
+ /* Convert all remote objectClasses */
+ for (i = 0; i < el->num_values; i++) {
+ el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);
+ }
+
+ val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
+ val.length = strlen((char *)val.data);
+
+ /* Remove last value if it was the string in data->add_objectclass (eg samba4top, extensibleObject) */
+ if (ldb_val_equal_exact(&val, &el->values[i-1])) {
+ el->num_values--;
+ el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ ldb_oom(ldb);
+ return NULL;
+ }
+ }
+
+ return el;
+}
+
+static const struct ldb_map_attribute objectclass_convert_map = {
+ .local_name = "objectClass",
+ .type = LDB_MAP_CONVERT,
+ .u = {
+ .convert = {
+ .remote_name = "objectClass",
+ .convert_local = map_objectclass_convert_local,
+ .convert_remote = map_objectclass_convert_remote,
+ },
+ },
+};
+
+
+/* Mappings for searches on objectClass= assuming a one-to-one
+ * mapping. Needed because this is a generate operator for the
+ * add/modify code */
+static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx,
+ struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+
+ return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_convert_map);
+}
+
+/* Auxiliary request construction
+ * ============================== */
+
+/* Build a request to search a record by its DN. */
+struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, struct ldb_parse_tree *tree, void *context, ldb_map_callback_t callback)
+{
+ struct ldb_parse_tree *search_tree;
+ struct ldb_context *ldb;
+ struct ldb_request *req;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (tree) {
+ search_tree = tree;
+ } else {
+ search_tree = ldb_parse_tree(ac, NULL);
+ if (search_tree == NULL) {
+ return NULL;
+ }
+ }
+
+ ret = ldb_build_search_req_ex(&req, ldb, ac,
+ dn, LDB_SCOPE_BASE,
+ search_tree, attrs,
+ NULL,
+ context, callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(req);
+ if (ret != LDB_SUCCESS) {
+ return NULL;
+ }
+
+ return req;
+}
+
+/* Build a request to update the 'IS_MAPPED' attribute */
+struct ldb_request *map_build_fixup_req(struct map_context *ac,
+ struct ldb_dn *olddn,
+ struct ldb_dn *newdn,
+ void *context,
+ ldb_map_callback_t callback)
+{
+ struct ldb_context *ldb;
+ struct ldb_request *req;
+ struct ldb_message *msg;
+ const char *dn;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ /* Prepare message */
+ msg = ldb_msg_new(ac);
+ if (msg == NULL) {
+ map_oom(ac->module);
+ return NULL;
+ }
+
+ /* Update local 'IS_MAPPED' to the new remote DN */
+ msg->dn = ldb_dn_copy(msg, olddn);
+ dn = ldb_dn_alloc_linearized(msg, newdn);
+ if ( ! dn || ! ldb_dn_validate(msg->dn)) {
+ goto failed;
+ }
+ if (ldb_msg_append_string(msg, IS_MAPPED, dn, LDB_FLAG_MOD_REPLACE) != 0) {
+ goto failed;
+ }
+
+ /* Prepare request */
+ ret = ldb_build_mod_req(&req, ldb,
+ ac, msg, NULL,
+ context, callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(req);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+ talloc_steal(req, msg);
+
+ return req;
+failed:
+ talloc_free(msg);
+ return NULL;
+}
+
+/* Module initialization
+ * ===================== */
+
+
+/* Builtin mappings for DNs and objectClasses */
+static const struct ldb_map_attribute builtin_attribute_maps[] = {
+ {
+ .local_name = "dn",
+ .type = LDB_MAP_CONVERT,
+ .u = {
+ .convert = {
+ .remote_name = "dn",
+ .convert_local = ldb_dn_convert_local,
+ .convert_remote = ldb_dn_convert_remote,
+ },
+ },
+ },
+ {
+ .local_name = NULL,
+ }
+};
+
+static const struct ldb_map_attribute objectclass_attribute_map = {
+ .local_name = "objectClass",
+ .type = LDB_MAP_GENERATE,
+ .convert_operator = map_objectclass_convert_operator,
+ .u = {
+ .generate = {
+ .remote_names = { "objectClass", NULL },
+ .generate_local = map_objectclass_generate_local,
+ .generate_remote = map_objectclass_generate_remote,
+ },
+ },
+};
+
+
+/* Find the special 'MAP_DN_NAME' record and store local and remote
+ * base DNs in private data. */
+static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
+{
+ static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL };
+ struct ldb_context *ldb;
+ struct ldb_dn *dn;
+ struct ldb_message *msg;
+ struct ldb_result *res;
+ int ret;
+
+ if (!name) {
+ data->local_base_dn = NULL;
+ data->remote_base_dn = NULL;
+ return LDB_SUCCESS;
+ }
+
+ ldb = ldb_module_get_ctx(module);
+
+ dn = ldb_dn_new_fmt(data, ldb, "%s=%s", MAP_DN_NAME, name);
+ if ( ! ldb_dn_validate(dn)) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Failed to construct '%s' DN!", MAP_DN_NAME);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_search(ldb, data, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
+ talloc_free(dn);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (res->count == 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "No results for '%s=%s'!", MAP_DN_NAME, name);
+ talloc_free(res);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ if (res->count > 1) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Too many results for '%s=%s'!", MAP_DN_NAME, name);
+ talloc_free(res);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ msg = res->msgs[0];
+ data->local_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_FROM);
+ data->remote_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_TO);
+ talloc_free(res);
+
+ return LDB_SUCCESS;
+}
+
+/* Store attribute maps and objectClass maps in private data. */
+static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data,
+ const struct ldb_map_attribute *attrs,
+ const struct ldb_map_objectclass *ocls,
+ const char * const *wildcard_attributes)
+{
+ unsigned int i, j, last;
+ last = 0;
+
+ /* Count specified attribute maps */
+ for (i = 0; attrs[i].local_name; i++) /* noop */ ;
+ /* Count built-in attribute maps */
+ for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ;
+
+ /* Store list of attribute maps */
+ data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+2);
+ if (data->attribute_maps == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Specified ones go first */
+ for (i = 0; attrs[i].local_name; i++) {
+ data->attribute_maps[last] = attrs[i];
+ last++;
+ }
+
+ /* Built-in ones go last */
+ for (i = 0; builtin_attribute_maps[i].local_name; i++) {
+ data->attribute_maps[last] = builtin_attribute_maps[i];
+ last++;
+ }
+
+ if (data->add_objectclass) {
+ /* ObjectClass one is very last, if required */
+ data->attribute_maps[last] = objectclass_attribute_map;
+ last++;
+ } else if (ocls) {
+ data->attribute_maps[last] = objectclass_convert_map;
+ last++;
+ }
+
+ /* Ensure 'local_name == NULL' for the last entry */
+ memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute));
+
+ /* Store list of objectClass maps */
+ data->objectclass_maps = ocls;
+
+ data->wildcard_attributes = wildcard_attributes;
+
+ return LDB_SUCCESS;
+}
+
+/* Initialize global private data. */
+_PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs,
+ const struct ldb_map_objectclass *ocls,
+ const char * const *wildcard_attributes,
+ const char *add_objectclass,
+ const char *name)
+{
+ struct map_private *data;
+ int ret;
+
+ /* Prepare private data */
+ data = talloc_zero(module, struct map_private);
+ if (data == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_module_set_private(module, data);
+
+ data->context = talloc_zero(data, struct ldb_map_context);
+ if (!data->context) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Store local and remote baseDNs */
+ ret = map_init_dns(module, data->context, name);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(data);
+ return ret;
+ }
+
+ data->context->add_objectclass = add_objectclass;
+
+ /* Store list of attribute and objectClass maps */
+ ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(data);
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb/ldb_map/ldb_map.h b/lib/ldb/ldb_map/ldb_map.h
new file mode 100644
index 0000000..46ef3cc
--- /dev/null
+++ b/lib/ldb/ldb_map/ldb_map.h
@@ -0,0 +1,174 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __LDB_MAP_H__
+#define __LDB_MAP_H__
+
+#include "ldb_module.h"
+
+/* ldb_map is a skeleton LDB module that can be used for any other modules
+ * that need to map attributes.
+ *
+ * The term 'remote' in this header refers to the connection where the
+ * original schema is used on while 'local' means the local connection
+ * that any upper layers will use.
+ *
+ * All local attributes will have to have a definition. Not all remote
+ * attributes need a definition as LDB is a lot less strict than LDAP
+ * (in other words, sending unknown attributes to an LDAP server hurts us,
+ * while returning too many attributes in ldb_search() doesn't)
+ */
+
+
+/* Name of the internal attribute pointing from the local to the
+ * remote part of a record */
+#define IS_MAPPED "isMapped"
+
+
+struct ldb_map_context;
+
+/* convert a local ldb_val to a remote ldb_val */
+typedef struct ldb_val (*ldb_map_convert_func) (struct ldb_module *module, void *mem_ctx, const struct ldb_val *val);
+
+#define LDB_MAP_MAX_REMOTE_NAMES 10
+
+/* map from local to remote attribute */
+struct ldb_map_attribute {
+ const char *local_name; /* local name */
+
+ enum ldb_map_attr_type {
+ LDB_MAP_IGNORE, /* Ignore this local attribute. Doesn't exist remotely. */
+ LDB_MAP_KEEP, /* Keep as is. Same name locally and remotely. */
+ LDB_MAP_RENAME, /* Simply rename the attribute. Name changes, data is the same */
+ LDB_MAP_CONVERT, /* Rename + convert data */
+ LDB_MAP_GENERATE, /* Use generate function for generating new name/data.
+ Used for generating attributes based on
+ multiple remote attributes. */
+ LDB_MAP_RENDROP /* Rename the attribute. Strip from Add requests. */
+ } type;
+
+ /* if set, will be called for search expressions that contain this attribute */
+ int (*convert_operator)(struct ldb_module *, TALLOC_CTX *ctx, struct ldb_parse_tree **ntree, const struct ldb_parse_tree *otree);
+
+ union {
+ struct {
+ const char *remote_name;
+ } rename;
+
+ struct {
+ const char *remote_name;
+
+ /* Convert local to remote data */
+ ldb_map_convert_func convert_local;
+
+ /* Convert remote to local data */
+ /* an entry can have convert_remote set to NULL, as long as there as an entry with the same local_name
+ * that is non-NULL before it. */
+ ldb_map_convert_func convert_remote;
+ } convert;
+
+ struct {
+ /* Generate the local attribute from remote message */
+ struct ldb_message_element *(*generate_local)(struct ldb_module *, TALLOC_CTX *mem_ctx, const char *remote_attr, const struct ldb_message *remote);
+
+ /* Update remote message with information from local message */
+ void (*generate_remote)(struct ldb_module *, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local);
+
+ /* Name(s) for this attribute on the remote server. This is an array since
+ * one local attribute's data can be split up into several attributes
+ * remotely */
+ const char *remote_names[LDB_MAP_MAX_REMOTE_NAMES];
+
+ /* Names of additional remote attributes
+ * required for the generation. NULL
+ * indicates that `local_attr' suffices. */
+ /*
+#define LDB_MAP_MAX_SELF_ATTRIBUTES 10
+ const char *self_attrs[LDB_MAP_MAX_SELF_ATTRIBUTES];
+ */
+ } generate;
+ } u;
+};
+
+
+#define LDB_MAP_MAX_SUBCLASSES 10
+#define LDB_MAP_MAX_MUSTS 10
+#define LDB_MAP_MAX_MAYS 50
+
+/* map from local to remote objectClass */
+struct ldb_map_objectclass {
+ const char *local_name;
+ const char *remote_name;
+ const char *base_classes[LDB_MAP_MAX_SUBCLASSES];
+ const char *musts[LDB_MAP_MAX_MUSTS];
+ const char *mays[LDB_MAP_MAX_MAYS];
+};
+
+
+/* private context data */
+struct ldb_map_context {
+ struct ldb_map_attribute *attribute_maps;
+ /* NOTE: Always declare base classes first here */
+ const struct ldb_map_objectclass *objectclass_maps;
+
+ /* Remote (often operational) attributes that should be added
+ * to any wildcard search */
+ const char * const *wildcard_attributes;
+
+ /* ObjectClass (if any) to be added to remote attributes on add */
+ const char *add_objectclass;
+
+ /* struct ldb_context *mapped_ldb; */
+ struct ldb_dn *local_base_dn;
+ struct ldb_dn *remote_base_dn;
+};
+
+/* Global private data */
+struct map_private {
+ void *caller_private;
+ struct ldb_map_context *context;
+};
+
+/* Initialize global private data. */
+int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs,
+ const struct ldb_map_objectclass *ocls,
+ const char * const *wildcard_attributes,
+ const char *add_objectclass,
+ const char *name);
+
+int ldb_map_add(struct ldb_module *module, struct ldb_request *req);
+int ldb_map_search(struct ldb_module *module, struct ldb_request *req);
+int ldb_map_rename(struct ldb_module *module, struct ldb_request *req);
+int ldb_map_delete(struct ldb_module *module, struct ldb_request *req);
+int ldb_map_modify(struct ldb_module *module, struct ldb_request *req);
+
+#define LDB_MAP_OPS \
+ .add = ldb_map_add, \
+ .modify = ldb_map_modify, \
+ .del = ldb_map_delete, \
+ .rename = ldb_map_rename, \
+ .search = ldb_map_search,
+
+#endif /* __LDB_MAP_H__ */
diff --git a/lib/ldb/ldb_map/ldb_map_inbound.c b/lib/ldb/ldb_map/ldb_map_inbound.c
new file mode 100644
index 0000000..50b9427
--- /dev/null
+++ b/lib/ldb/ldb_map/ldb_map_inbound.c
@@ -0,0 +1,844 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+ Copyright (C) Simo Sorce <idra@samba.org> 2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_map.h"
+#include "ldb_map_private.h"
+
+
+/* Mapping message elements
+ * ======================== */
+
+/* Map a message element into the remote partition. */
+static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old)
+{
+ struct ldb_message_element *el;
+ unsigned int i;
+
+ el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ el->num_values = old->num_values;
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ map_oom(module);
+ return NULL;
+ }
+
+ el->name = map_attr_map_local(el, map, old->name);
+
+ for (i = 0; i < el->num_values; i++) {
+ el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
+ }
+
+ return el;
+}
+
+/* Add a message element either to a local or to a remote message,
+ * depending on whether it goes into the local or remote partition. */
+static int ldb_msg_el_partition(struct ldb_module *module, enum ldb_request_type optype, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
+ struct ldb_message_element *el=NULL;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+ /* Unknown attribute: ignore */
+ if (map == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Not mapping attribute '%s': no mapping found",
+ old->name);
+ goto local;
+ }
+
+ switch (map->type) {
+ case LDB_MAP_RENDROP:
+ if (optype != LDB_ADD) {
+ /* do the same as LDB_MAP_RENAME */
+ el = ldb_msg_el_map_local(module, remote, map, old);
+ break;
+ }
+
+ FALL_THROUGH;
+ case LDB_MAP_IGNORE:
+ goto local;
+
+ case LDB_MAP_CONVERT:
+ if (map->u.convert.convert_local == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Not mapping attribute '%s': "
+ "'convert_local' not set",
+ map->local_name);
+ goto local;
+ }
+
+ FALL_THROUGH;
+ case LDB_MAP_KEEP:
+ case LDB_MAP_RENAME:
+ el = ldb_msg_el_map_local(module, remote, map, old);
+ break;
+
+ case LDB_MAP_GENERATE:
+ if (map->u.generate.generate_remote == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Not mapping attribute '%s': "
+ "'generate_remote' not set",
+ map->local_name);
+ goto local;
+ }
+
+ /* TODO: if this attr requires context:
+ * make sure all context attrs are mappable (in 'names')
+ * make sure all context attrs have already been mapped?
+ * maybe postpone generation until they have been mapped?
+ */
+
+ map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
+ return 0;
+ }
+
+ if (el == NULL) {
+ return -1;
+ }
+
+ return ldb_msg_add(remote, el, old->flags);
+
+local:
+ el = talloc(local, struct ldb_message_element);
+ if (el == NULL) {
+ map_oom(module);
+ return -1;
+ }
+
+ *el = *old; /* copy the old element */
+
+ return ldb_msg_add(local, el, old->flags);
+}
+
+/* Mapping messages
+ * ================ */
+
+/* Check whether a message will be (partially) mapped into the remote partition. */
+static bool ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ bool ret;
+ unsigned int i;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ ret = map_attr_check_remote(data, msg->elements[i].name);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return false;
+}
+
+/* Split message elements that stay in the local partition from those
+ * that are mapped into the remote partition. */
+static int ldb_msg_partition(struct ldb_module *module, enum ldb_request_type optype, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
+{
+ /* const char * const names[]; */
+ struct ldb_context *ldb;
+ unsigned int i;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ for (i = 0; i < msg->num_elements; i++) {
+ /* Skip 'IS_MAPPED' */
+ if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Skipping attribute '%s'",
+ msg->elements[i].name);
+ continue;
+ }
+
+ ret = ldb_msg_el_partition(module, optype, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+
+static int map_add_do_local(struct map_context *ac);
+static int map_modify_do_local(struct map_context *ac);
+static int map_delete_do_local(struct map_context *ac);
+static int map_rename_do_local(struct map_context *ac);
+static int map_rename_do_fixup(struct map_context *ac);
+static int map_rename_local_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+
+
+/*****************************************************************************
+ * COMMON INBOUND functions
+*****************************************************************************/
+
+/* Store the DN of a single search result in context. */
+static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct map_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ /* We are interested only in the single reply */
+ switch(ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* We have already found a remote DN */
+ if (ac->local_dn) {
+ ldb_set_errstring(ldb,
+ "Too many results!");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* Store local DN */
+ ac->local_dn = talloc_steal(ac, ares->message->dn);
+ break;
+
+ case LDB_REPLY_DONE:
+
+ switch (ac->req->operation) {
+ case LDB_MODIFY:
+ ret = map_modify_do_local(ac);
+ break;
+ case LDB_DELETE:
+ ret = map_delete_do_local(ac);
+ break;
+ case LDB_RENAME:
+ ret = map_rename_do_local(ac);
+ break;
+ default:
+ /* if we get here we have definitely a problem */
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ break;
+ default:
+ /* ignore referrals */
+ break;
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
+
+/* Build a request to search the local record by its DN. */
+static int map_search_self_req(struct ldb_request **req,
+ struct map_context *ac,
+ struct ldb_dn *dn)
+{
+ /* attrs[] is returned from this function in
+ * ac->search_req->op.search.attrs, so it must be static, as
+ * otherwise the compiler can put it on the stack */
+ static const char * const attrs[] = { IS_MAPPED, NULL };
+ struct ldb_parse_tree *tree;
+
+ /* Limit search to records with 'IS_MAPPED' present */
+ tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
+ if (tree == NULL) {
+ map_oom(ac->module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *req = map_search_base_req(ac, dn, attrs, tree,
+ ac, map_search_self_callback);
+ if (*req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int map_op_local_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct map_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* Do the remote request. */
+ ret = ldb_next_remote_request(ac->module, ac->remote_req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int map_op_remote_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_context *ldb;
+ struct map_context *ac;
+
+ ac = talloc_get_type(req->context, struct map_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+}
+
+
+/*****************************************************************************
+ * ADD operations
+*****************************************************************************/
+
+
+/* Add a record. */
+int ldb_map_add(struct ldb_module *module, struct ldb_request *req)
+{
+ const struct ldb_message *msg = req->op.add.message;
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ struct ldb_message *remote_msg;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+ if (!ldb_dn_check_local(module, msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping needed, fail */
+ if (!ldb_msg_check_remote(module, msg)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare context and handle */
+ ac = map_init_context(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+
+ /* Prepare the local message */
+ ac->local_msg = ldb_msg_new(ac);
+ if (ac->local_msg == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->local_msg->dn = msg->dn;
+
+ /* Prepare the remote message */
+ remote_msg = ldb_msg_new(ac);
+ if (remote_msg == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
+
+ /* Split local from remote message */
+ ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg);
+
+ /* Prepare the remote operation */
+ ret = ldb_build_add_req(&ac->remote_req, ldb,
+ ac, remote_msg,
+ req->controls,
+ ac, map_op_remote_callback,
+ req);
+ LDB_REQ_SET_LOCATION(ac->remote_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if ((ac->local_msg->num_elements == 0) ||
+ ( ! map_check_local_db(ac->module))) {
+ /* No local data or db, just run the remote request */
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+ }
+
+ /* Store remote DN in 'IS_MAPPED' */
+ /* TODO: use GUIDs here instead */
+ ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED,
+ remote_msg->dn);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return map_add_do_local(ac);
+}
+
+/* Add the local record. */
+static int map_add_do_local(struct map_context *ac)
+{
+ struct ldb_request *local_req;
+ struct ldb_context *ldb;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ /* Prepare the local operation */
+ ret = ldb_build_add_req(&local_req, ldb, ac,
+ ac->local_msg,
+ ac->req->controls,
+ ac,
+ map_op_local_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(local_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return ldb_next_request(ac->module, local_req);
+}
+
+/*****************************************************************************
+ * MODIFY operations
+*****************************************************************************/
+
+/* Modify a record. */
+int ldb_map_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ const struct ldb_message *msg = req->op.mod.message;
+ struct ldb_request *search_req = NULL;
+ struct ldb_message *remote_msg;
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+ if (!ldb_dn_check_local(module, msg->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping needed, skip to next module */
+ /* TODO: What if the remote part exists, the local doesn't,
+ * and this request wants to modify local data and thus
+ * add the local record? */
+ if (!ldb_msg_check_remote(module, msg)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare context and handle */
+ ac = map_init_context(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare the local message */
+ ac->local_msg = ldb_msg_new(ac);
+ if (ac->local_msg == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->local_msg->dn = msg->dn;
+
+ /* Prepare the remote message */
+ remote_msg = ldb_msg_new(ac->remote_req);
+ if (remote_msg == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
+
+ /* Split local from remote message */
+ ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg);
+
+ /* Prepare the remote operation */
+ ret = ldb_build_mod_req(&ac->remote_req, ldb,
+ ac, remote_msg,
+ req->controls,
+ ac, map_op_remote_callback,
+ req);
+ LDB_REQ_SET_LOCATION(ac->remote_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if ((ac->local_msg->num_elements == 0) ||
+ ( ! map_check_local_db(ac->module))) {
+ /* No local data or db, just run the remote request */
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+ }
+
+ /* prepare the search operation */
+ ret = map_search_self_req(&search_req, ac, msg->dn);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(module, search_req);
+}
+
+/* Modify the local record. */
+static int map_modify_do_local(struct map_context *ac)
+{
+ struct ldb_request *local_req;
+ struct ldb_context *ldb;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (ac->local_dn == NULL) {
+ /* No local record present, add it instead */
+ /* Add local 'IS_MAPPED' */
+ /* TODO: use GUIDs here instead */
+ ret = ldb_msg_append_linearized_dn(ac->local_msg, IS_MAPPED,
+ ac->remote_req->op.mod.message->dn,
+ LDB_FLAG_MOD_ADD);
+ if (ret != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare the local operation */
+ ret = ldb_build_add_req(&local_req, ldb, ac,
+ ac->local_msg,
+ ac->req->controls,
+ ac,
+ map_op_local_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(local_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else {
+ /* Prepare the local operation */
+ ret = ldb_build_mod_req(&local_req, ldb, ac,
+ ac->local_msg,
+ ac->req->controls,
+ ac,
+ map_op_local_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(local_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return ldb_next_request(ac->module, local_req);
+}
+
+/*****************************************************************************
+ * DELETE operations
+*****************************************************************************/
+
+/* Delete a record. */
+int ldb_map_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_request *search_req;
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.del.dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified).
+ * Skip to next module */
+ if (!ldb_dn_check_local(module, req->op.del.dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* Prepare context and handle */
+ ac = map_init_context(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare the remote operation */
+ ret = ldb_build_del_req(&ac->remote_req, ldb, ac,
+ ldb_dn_map_local(module, ac, req->op.del.dn),
+ req->controls,
+ ac,
+ map_op_remote_callback,
+ req);
+ LDB_REQ_SET_LOCATION(ac->remote_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* No local db, just run the remote request */
+ if (!map_check_local_db(ac->module)) {
+ /* Do the remote request. */
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+ }
+
+ /* Prepare the search operation */
+ ret = map_search_self_req(&search_req, ac, req->op.del.dn);
+ if (ret != LDB_SUCCESS) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(module, search_req);
+}
+
+/* Delete the local record. */
+static int map_delete_do_local(struct map_context *ac)
+{
+ struct ldb_request *local_req;
+ struct ldb_context *ldb;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ /* No local record, continue remotely */
+ if (ac->local_dn == NULL) {
+ /* Do the remote request. */
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+ }
+
+ /* Prepare the local operation */
+ ret = ldb_build_del_req(&local_req, ldb, ac,
+ ac->req->op.del.dn,
+ ac->req->controls,
+ ac,
+ map_op_local_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(local_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return ldb_next_request(ac->module, local_req);
+}
+
+/*****************************************************************************
+ * RENAME operations
+*****************************************************************************/
+
+/* Rename a record. */
+int ldb_map_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_request *search_req = NULL;
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.rename.olddn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested (perhaps no DN mapping specified).
+ * Skip to next module */
+ if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
+ (!ldb_dn_check_local(module, req->op.rename.newdn))) {
+ return ldb_next_request(module, req);
+ }
+
+ /* Rename into/out of the mapped partition requested, bail out */
+ if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
+ !ldb_dn_check_local(module, req->op.rename.newdn)) {
+ return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
+ }
+
+ /* Prepare context and handle */
+ ac = map_init_context(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare the remote operation */
+ ret = ldb_build_rename_req(&ac->remote_req, ldb, ac,
+ ldb_dn_map_local(module, ac, req->op.rename.olddn),
+ ldb_dn_map_local(module, ac, req->op.rename.newdn),
+ req->controls,
+ ac, map_op_remote_callback,
+ req);
+ LDB_REQ_SET_LOCATION(ac->remote_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* No local db, just run the remote request */
+ if (!map_check_local_db(ac->module)) {
+ /* Do the remote request. */
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+ }
+
+ /* Prepare the search operation */
+ ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
+ if (ret != LDB_SUCCESS) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(module, search_req);
+}
+
+/* Rename the local record. */
+static int map_rename_do_local(struct map_context *ac)
+{
+ struct ldb_request *local_req;
+ struct ldb_context *ldb;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ /* No local record, continue remotely */
+ if (ac->local_dn == NULL) {
+ /* Do the remote request. */
+ return ldb_next_remote_request(ac->module, ac->remote_req);
+ }
+
+ /* Prepare the local operation */
+ ret = ldb_build_rename_req(&local_req, ldb, ac,
+ ac->req->op.rename.olddn,
+ ac->req->op.rename.newdn,
+ ac->req->controls,
+ ac,
+ map_rename_local_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(local_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(ac->module, local_req);
+}
+
+static int map_rename_local_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct map_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* proceed with next step */
+ ret = map_rename_do_fixup(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* Update the local 'IS_MAPPED' attribute. */
+static int map_rename_do_fixup(struct map_context *ac)
+{
+ struct ldb_request *local_req;
+
+ /* Prepare the fixup operation */
+ /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
+ local_req = map_build_fixup_req(ac,
+ ac->req->op.rename.newdn,
+ ac->remote_req->op.rename.newdn,
+ ac,
+ map_op_local_callback);
+ if (local_req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(ac->module, local_req);
+}
diff --git a/lib/ldb/ldb_map/ldb_map_outbound.c b/lib/ldb/ldb_map/ldb_map_outbound.c
new file mode 100644
index 0000000..e86e29a
--- /dev/null
+++ b/lib/ldb/ldb_map/ldb_map_outbound.c
@@ -0,0 +1,1422 @@
+/*
+ ldb database mapping module
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
+ Copyright (C) Simo Sorce <idra@samba.org> 2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_map.h"
+#include "ldb_map_private.h"
+
+
+/* Mapping attributes
+ * ================== */
+
+/* Select attributes that stay in the local partition. */
+static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char **result;
+ unsigned int i, last;
+
+ if (attrs == NULL)
+ return NULL;
+
+ last = 0;
+ result = talloc_array(mem_ctx, const char *, 1);
+ if (result == NULL) {
+ goto failed;
+ }
+ result[0] = NULL;
+
+ for (i = 0; attrs[i]; i++) {
+ /* Wildcards and ignored attributes are kept locally */
+ if ((ldb_attr_cmp(attrs[i], "*") == 0) ||
+ (!map_attr_check_remote(data, attrs[i]))) {
+ result = talloc_realloc(mem_ctx, result, const char *, last+2);
+ if (result == NULL) {
+ goto failed;
+ }
+
+ result[last] = talloc_strdup(result, attrs[i]);
+ result[last+1] = NULL;
+ last++;
+ }
+ }
+
+ return result;
+
+failed:
+ talloc_free(result);
+ map_oom(module);
+ return NULL;
+}
+
+/* Collect attributes that are mapped into the remote partition. */
+static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx,
+ const char * const *attrs)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char **result;
+ const struct ldb_map_attribute *map;
+ const char *name=NULL;
+ unsigned int i, j, last;
+ int ret;
+
+ last = 0;
+ result = talloc_array(mem_ctx, const char *, 1);
+ if (result == NULL) {
+ goto failed;
+ }
+ result[0] = NULL;
+
+ for (i = 0; attrs[i]; i++) {
+ /* Wildcards are kept remotely, too */
+ if (ldb_attr_cmp(attrs[i], "*") == 0) {
+ const char **new_attrs = NULL;
+ ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+ ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ attrs = new_attrs;
+ break;
+ }
+ }
+
+ for (i = 0; attrs[i]; i++) {
+ /* Wildcards are kept remotely, too */
+ if (ldb_attr_cmp(attrs[i], "*") == 0) {
+ /* Add all 'include in wildcard' attributes */
+ name = attrs[i];
+ goto named;
+ }
+
+ /* Add remote names of mapped attrs */
+ map = map_attr_find_local(data, attrs[i]);
+ if (map == NULL) {
+ continue;
+ }
+
+ switch (map->type) {
+ case LDB_MAP_IGNORE:
+ continue;
+
+ case LDB_MAP_KEEP:
+ name = attrs[i];
+ goto named;
+
+ case LDB_MAP_RENAME:
+ case LDB_MAP_RENDROP:
+ case LDB_MAP_CONVERT:
+ name = map->u.rename.remote_name;
+ goto named;
+
+ case LDB_MAP_GENERATE:
+ /* Add all remote names of "generate" attrs */
+ for (j = 0; map->u.generate.remote_names[j]; j++) {
+ result = talloc_realloc(mem_ctx, result, const char *, last+2);
+ if (result == NULL) {
+ goto failed;
+ }
+
+ result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
+ result[last+1] = NULL;
+ last++;
+ }
+ continue;
+ }
+
+ named: /* We found a single remote name, add that */
+ result = talloc_realloc(mem_ctx, result, const char *, last+2);
+ if (result == NULL) {
+ goto failed;
+ }
+
+ result[last] = talloc_strdup(result, name);
+ result[last+1] = NULL;
+ last++;
+ }
+
+ return result;
+
+failed:
+ talloc_free(result);
+ map_oom(module);
+ return NULL;
+}
+
+/* Split attributes that stay in the local partition from those that
+ * are mapped into the remote partition. */
+static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs)
+{
+ *local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
+ *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs);
+
+ return 0;
+}
+
+/* Mapping message elements
+ * ======================== */
+
+/* Add an element to a message, overwriting any old identically named elements. */
+static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
+{
+ struct ldb_message_element *old;
+ unsigned j;
+ old = ldb_msg_find_element(msg, el->name);
+
+ /* no local result, add as new element */
+ if (old == NULL) {
+ if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ else {
+ talloc_free(old->values);
+ }
+
+ old->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
+ old->num_values = el->num_values;
+ if (old->values == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* copy the values into the element */
+ for (j=0;j<el->num_values;j++) {
+ old->values[j] = ldb_val_dup(old->values, &el->values[j]);
+ if (old->values[j].data == NULL && el->values[j].length != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return 0;
+}
+
+/* Map a message element back into the local partition. */
+static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module,
+ void *mem_ctx,
+ const struct ldb_map_attribute *map,
+ const char *attr_name,
+ const struct ldb_message_element *old)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const char *local_attr_name = attr_name;
+ struct ldb_message_element *el;
+ unsigned int i;
+
+ el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ map_oom(module);
+ return NULL;
+ }
+
+ el->values = talloc_array(el, struct ldb_val, old->num_values);
+ if (el->values == NULL) {
+ talloc_free(el);
+ map_oom(module);
+ return NULL;
+ }
+
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ struct ldb_map_attribute *am = &data->attribute_maps[i];
+ if (((am->type == LDB_MAP_RENAME || am->type == LDB_MAP_RENDROP) &&
+ !strcmp(am->u.rename.remote_name, attr_name))
+ || (am->type == LDB_MAP_CONVERT &&
+ !strcmp(am->u.convert.remote_name, attr_name))) {
+
+ local_attr_name = am->local_name;
+ break;
+ }
+ }
+
+ el->name = talloc_strdup(el, local_attr_name);
+ if (el->name == NULL) {
+ talloc_free(el);
+ map_oom(module);
+ return NULL;
+ }
+
+ for (i = 0; i < old->num_values; i++) {
+ el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
+ /* Conversions might fail, in which case bail */
+ if (!el->values[i].data) {
+ talloc_free(el);
+ return NULL;
+ }
+ el->num_values++;
+ }
+
+ return el;
+}
+
+/* Merge a remote message element into a local message. */
+static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local,
+ struct ldb_message *remote, const char *attr_name)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map;
+ struct ldb_message_element *old, *el=NULL;
+ const char *remote_name = NULL;
+ struct ldb_context *ldb;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* We handle wildcards in ldb_msg_el_merge_wildcard */
+ if (ldb_attr_cmp(attr_name, "*") == 0) {
+ return LDB_SUCCESS;
+ }
+
+ map = map_attr_find_local(data, attr_name);
+
+ /* Unknown attribute in remote message:
+ * skip, attribute was probably auto-generated */
+ if (map == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ switch (map->type) {
+ case LDB_MAP_IGNORE:
+ break;
+ case LDB_MAP_CONVERT:
+ remote_name = map->u.convert.remote_name;
+ break;
+ case LDB_MAP_KEEP:
+ remote_name = attr_name;
+ break;
+ case LDB_MAP_RENAME:
+ case LDB_MAP_RENDROP:
+ remote_name = map->u.rename.remote_name;
+ break;
+ case LDB_MAP_GENERATE:
+ break;
+ }
+
+ switch (map->type) {
+ case LDB_MAP_IGNORE:
+ return LDB_SUCCESS;
+
+ case LDB_MAP_CONVERT:
+ if (map->u.convert.convert_remote == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Skipping attribute '%s': "
+ "'convert_remote' not set",
+ attr_name);
+ return LDB_SUCCESS;
+ }
+
+ FALL_THROUGH;
+ case LDB_MAP_KEEP:
+ case LDB_MAP_RENAME:
+ case LDB_MAP_RENDROP:
+ old = ldb_msg_find_element(remote, remote_name);
+ if (old) {
+ el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
+ } else {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+ break;
+
+ case LDB_MAP_GENERATE:
+ if (map->u.generate.generate_local == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Skipping attribute '%s': "
+ "'generate_local' not set",
+ attr_name);
+ return LDB_SUCCESS;
+ }
+
+ el = map->u.generate.generate_local(module, local, attr_name, remote);
+ if (!el) {
+ /* Generation failure is probably due to lack of source attributes */
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+ break;
+ }
+
+ if (el == NULL) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
+ return ldb_msg_replace(local, el);
+}
+
+/* Handle wildcard parts of merging a remote message element into a local message. */
+static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local,
+ struct ldb_message *remote)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
+ struct ldb_message_element *el=NULL;
+ unsigned int i;
+ int ret;
+
+ /* Perhaps we have a mapping for "*" */
+ if (map && map->type == LDB_MAP_KEEP) {
+ /* We copy everything over, and hope that anything with a
+ more specific rule is overwritten */
+ for (i = 0; i < remote->num_elements; i++) {
+ el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name,
+ &remote->elements[i]);
+ if (el == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_msg_replace(local, el);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+
+ /* Now walk the list of possible mappings, and apply each */
+ for (i = 0; data->attribute_maps[i].local_name; i++) {
+ ret = ldb_msg_el_merge(module, local, remote,
+ data->attribute_maps[i].local_name);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ continue;
+ } else if (ret) {
+ return ret;
+ } else {
+ continue;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* Mapping messages
+ * ================ */
+
+/* Merge two local messages into a single one. */
+static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < msg2->num_elements; i++) {
+ ret = ldb_msg_replace(msg1, &msg2->elements[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* Merge a local and a remote message into a single local one. */
+static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local,
+ struct ldb_message *remote)
+{
+ unsigned int i;
+ int ret;
+ const char * const *attrs = ac->all_attrs;
+ if (!attrs) {
+ ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ for (i = 0; attrs && attrs[i]; i++) {
+ if (ldb_attr_cmp(attrs[i], "*") == 0) {
+ ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
+ if (ret) {
+ return ret;
+ }
+ break;
+ }
+ }
+
+ /* Try to map each attribute back;
+ * Add to local message is possible,
+ * Overwrite old local attribute if necessary */
+ for (i = 0; attrs && attrs[i]; i++) {
+ ret = ldb_msg_el_merge(ac->module, local, remote,
+ attrs[i]);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ } else if (ret) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* Mapping search results
+ * ====================== */
+
+/* Map a search result back into the local partition. */
+static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares)
+{
+ struct ldb_message *msg;
+ struct ldb_dn *dn;
+ int ret;
+
+ /* There is no result message, skip */
+ if (ares->type != LDB_REPLY_ENTRY) {
+ return 0;
+ }
+
+ /* Create a new result message */
+ msg = ldb_msg_new(ares);
+ if (msg == NULL) {
+ map_oom(ac->module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Merge remote message into new message */
+ ret = ldb_msg_merge_remote(ac, msg, ares->message);
+ if (ret) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ /* Create corresponding local DN */
+ dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
+ if (dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg->dn = dn;
+
+ /* Store new message with new DN as the result */
+ talloc_free(ares->message);
+ ares->message = msg;
+
+ return 0;
+}
+
+/* Mapping parse trees
+ * =================== */
+
+/* Check whether a parse tree can safely be split in two. */
+static bool ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree)
+{
+ const struct ldb_parse_tree *subtree = tree;
+ bool negate = false;
+
+ while (subtree) {
+ switch (subtree->operation) {
+ case LDB_OP_NOT:
+ negate = !negate;
+ subtree = subtree->u.isnot.child;
+ continue;
+
+ case LDB_OP_AND:
+ return !negate; /* if negate: False */
+
+ case LDB_OP_OR:
+ return negate; /* if negate: True */
+
+ default:
+ return true; /* simple parse tree */
+ }
+ }
+
+ return true; /* no parse tree */
+}
+
+/* Collect a list of attributes required to match a given parse tree. */
+static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree)
+{
+ const char *attr = NULL;
+ const char **new_attrs;
+ unsigned int i;
+ int ret;
+
+ if (tree == NULL) {
+ return 0;
+ }
+
+ switch (tree->operation) {
+ case LDB_OP_OR:
+ case LDB_OP_AND: /* attributes stored in list of subtrees */
+ for (i = 0; i < tree->u.list.num_elements; i++) {
+ ret = ldb_parse_tree_collect_attrs(module, mem_ctx,
+ attrs, tree->u.list.elements[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+ return 0;
+
+ case LDB_OP_NOT: /* attributes stored in single subtree */
+ return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
+
+ default: /* single attribute in tree */
+ attr = ldb_parse_tree_get_attr(tree);
+ new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, attr);
+ if (new_attrs == NULL) {
+ return ldb_module_oom(module);
+ }
+ talloc_free(*attrs);
+ *attrs = new_attrs;
+ return 0;
+ }
+}
+
+static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
+
+/* Select a negated subtree that queries attributes in the local partition */
+static int map_subtree_select_local_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ struct ldb_parse_tree *child;
+ int ret;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Generate new subtree */
+ ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ /* Prune tree without subtree */
+ if (child == NULL) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ (*new)->u.isnot.child = child;
+
+ return ret;
+}
+
+/* Select a list of subtrees that query attributes in the local partition */
+static int map_subtree_select_local_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ unsigned int i, j;
+ int ret=0;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare list of subtrees */
+ (*new)->u.list.num_elements = 0;
+ (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
+ if ((*new)->u.list.elements == NULL) {
+ map_oom(module);
+ talloc_free(*new);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Generate new list of subtrees */
+ j = 0;
+ for (i = 0; i < tree->u.list.num_elements; i++) {
+ struct ldb_parse_tree *child = NULL;
+ ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ if (child) {
+ (*new)->u.list.elements[j] = child;
+ j++;
+ }
+ }
+
+ /* Prune tree without subtrees */
+ if (j == 0) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ /* Fix subtree list size */
+ (*new)->u.list.num_elements = j;
+ (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
+
+ return ret;
+}
+
+/* Select a simple subtree that queries attributes in the local partition */
+static int map_subtree_select_local_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return 0;
+}
+
+/* Select subtrees that query attributes in the local partition */
+static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+
+ if (tree == NULL) {
+ return 0;
+ }
+
+ if (tree->operation == LDB_OP_NOT) {
+ return map_subtree_select_local_not(module, mem_ctx, new, tree);
+ }
+
+ if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
+ return map_subtree_select_local_list(module, mem_ctx, new, tree);
+ }
+
+ if (map_attr_check_remote(data, tree->u.equality.attr)) {
+ *new = NULL;
+ return 0;
+ }
+
+ return map_subtree_select_local_simple(module, mem_ctx, new, tree);
+}
+
+static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
+
+/* Collect a negated subtree that queries attributes in the remote partition */
+static int map_subtree_collect_remote_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ struct ldb_parse_tree *child;
+ int ret;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Generate new subtree */
+ ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ /* Prune tree without subtree */
+ if (child == NULL) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ (*new)->u.isnot.child = child;
+
+ return ret;
+}
+
+/* Collect a list of subtrees that query attributes in the remote partition */
+static int map_subtree_collect_remote_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ unsigned int i, j;
+ int ret=0;
+
+ /* Prepare new tree */
+ *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
+ if (*new == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare list of subtrees */
+ (*new)->u.list.num_elements = 0;
+ (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
+ if ((*new)->u.list.elements == NULL) {
+ map_oom(module);
+ talloc_free(*new);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Generate new list of subtrees */
+ j = 0;
+ for (i = 0; i < tree->u.list.num_elements; i++) {
+ struct ldb_parse_tree *child;
+ ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
+ if (ret) {
+ talloc_free(*new);
+ return ret;
+ }
+
+ if (child) {
+ (*new)->u.list.elements[j] = child;
+ j++;
+ }
+ }
+
+ /* Prune tree without subtrees */
+ if (j == 0) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ /* Fix subtree list size */
+ (*new)->u.list.num_elements = j;
+ (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
+
+ return ret;
+}
+
+/* Collect a simple subtree that queries attributes in the remote partition */
+int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map)
+{
+ const char *attr;
+
+ /* Prepare new tree */
+ *new = talloc(mem_ctx, struct ldb_parse_tree);
+ if (*new == NULL) {
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ **new = *tree;
+
+ if (map->type == LDB_MAP_KEEP) {
+ /* Nothing to do here */
+ return 0;
+ }
+
+ /* Store attribute and value in new tree */
+ switch (tree->operation) {
+ case LDB_OP_PRESENT:
+ attr = map_attr_map_local(*new, map, tree->u.present.attr);
+ (*new)->u.present.attr = attr;
+ break;
+ case LDB_OP_SUBSTRING:
+ {
+ attr = map_attr_map_local(*new, map, tree->u.substring.attr);
+ (*new)->u.substring.attr = attr;
+ break;
+ }
+ case LDB_OP_EQUALITY:
+ attr = map_attr_map_local(*new, map, tree->u.equality.attr);
+ (*new)->u.equality.attr = attr;
+ break;
+ case LDB_OP_LESS:
+ case LDB_OP_GREATER:
+ case LDB_OP_APPROX:
+ attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
+ (*new)->u.comparison.attr = attr;
+ break;
+ case LDB_OP_EXTENDED:
+ attr = map_attr_map_local(*new, map, tree->u.extended.attr);
+ (*new)->u.extended.attr = attr;
+ break;
+ default: /* unknown kind of simple subtree */
+ talloc_free(*new);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (attr == NULL) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+
+ if (map->type == LDB_MAP_RENAME || map->type == LDB_MAP_RENDROP) {
+ /* Nothing more to do here, the attribute has been renamed */
+ return 0;
+ }
+
+ /* Store attribute and value in new tree */
+ switch (tree->operation) {
+ case LDB_OP_PRESENT:
+ break;
+ case LDB_OP_SUBSTRING:
+ {
+ int i;
+ /* Map value */
+ (*new)->u.substring.chunks = NULL;
+ for (i=0; tree->u.substring.chunks && tree->u.substring.chunks[i]; i++) {
+ (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2);
+ if (!(*new)->u.substring.chunks) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+ (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
+ if (!(*new)->u.substring.chunks[i]) {
+ talloc_free(*new);
+ *new = NULL;
+ return 0;
+ }
+ *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]);
+ (*new)->u.substring.chunks[i+1] = NULL;
+ }
+ break;
+ }
+ case LDB_OP_EQUALITY:
+ (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
+ break;
+ case LDB_OP_LESS:
+ case LDB_OP_GREATER:
+ case LDB_OP_APPROX:
+ (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
+ break;
+ case LDB_OP_EXTENDED:
+ (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value);
+ (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id);
+ break;
+ default: /* unknown kind of simple subtree */
+ talloc_free(*new);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return 0;
+}
+
+/* Collect subtrees that query attributes in the remote partition */
+static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
+{
+ const struct ldb_map_context *data = map_get_context(module);
+ const struct ldb_map_attribute *map;
+ struct ldb_context *ldb;
+
+ ldb = ldb_module_get_ctx(module);
+
+ if (tree == NULL) {
+ return 0;
+ }
+
+ if (tree->operation == LDB_OP_NOT) {
+ return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
+ }
+
+ if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
+ return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
+ }
+
+ if (!map_attr_check_remote(data, tree->u.equality.attr)) {
+ *new = NULL;
+ return 0;
+ }
+
+ map = map_attr_find_local(data, tree->u.equality.attr);
+ if (map == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (map->convert_operator) {
+ return map->convert_operator(module, mem_ctx, new, tree);
+ }
+
+ if (map->type == LDB_MAP_GENERATE) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
+ "Skipping attribute '%s': "
+ "'convert_operator' not set",
+ tree->u.equality.attr);
+ *new = NULL;
+ return 0;
+ }
+
+ return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map);
+}
+
+/* Split subtrees that query attributes in the local partition from
+ * those that query the remote partition. */
+static int ldb_parse_tree_partition(struct ldb_module *module,
+ void *mem_ctx,
+ struct ldb_parse_tree **local_tree,
+ struct ldb_parse_tree **remote_tree,
+ const struct ldb_parse_tree *tree)
+{
+ int ret;
+
+ *local_tree = NULL;
+ *remote_tree = NULL;
+
+ /* No original tree */
+ if (tree == NULL) {
+ return 0;
+ }
+
+ /* Generate local tree */
+ ret = map_subtree_select_local(module, mem_ctx, local_tree, tree);
+ if (ret) {
+ return ret;
+ }
+
+ /* Generate remote tree */
+ ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree);
+ if (ret) {
+ talloc_free(*local_tree);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Collect a list of attributes required either explicitly from a
+ * given list or implicitly from a given parse tree; split the
+ * collected list into local and remote parts. */
+static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac,
+ const char * const *search_attrs,
+ const struct ldb_parse_tree *tree)
+{
+ void *tmp_ctx;
+ const char **tree_attrs;
+ const char **remote_attrs;
+ const char **local_attrs;
+ int ret;
+
+ /* There is no tree, just partition the searched attributes */
+ if (tree == NULL) {
+ ret = map_attrs_partition(module, ac,
+ &local_attrs, &remote_attrs, search_attrs);
+ if (ret == 0) {
+ ac->local_attrs = local_attrs;
+ ac->remote_attrs = remote_attrs;
+ ac->all_attrs = search_attrs;
+ }
+ return ret;
+ }
+
+ /* Create context for temporary memory */
+ tmp_ctx = talloc_new(ac);
+ if (tmp_ctx == NULL) {
+ goto oom;
+ }
+
+ /* Prepare list of attributes from tree */
+ tree_attrs = talloc_array(tmp_ctx, const char *, 1);
+ if (tree_attrs == NULL) {
+ talloc_free(tmp_ctx);
+ goto oom;
+ }
+ tree_attrs[0] = NULL;
+
+ /* Collect attributes from tree */
+ ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
+ if (ret) {
+ goto done;
+ }
+
+ /* Merge attributes from search operation */
+ ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
+ if (ret) {
+ goto done;
+ }
+
+ /* Split local from remote attributes */
+ ret = map_attrs_partition(module, ac, &local_attrs,
+ &remote_attrs, tree_attrs);
+
+ if (ret == 0) {
+ ac->local_attrs = local_attrs;
+ ac->remote_attrs = remote_attrs;
+ talloc_steal(ac, tree_attrs);
+ ac->all_attrs = tree_attrs;
+ }
+done:
+ /* Free temporary memory */
+ talloc_free(tmp_ctx);
+ return ret;
+
+oom:
+ map_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+
+/* Outbound requests: search
+ * ========================= */
+
+static int map_remote_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+static int map_local_merge_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+static int map_search_local(struct map_context *ac);
+
+static int map_save_entry(struct map_context *ac, struct ldb_reply *ares)
+{
+ struct map_reply *mr;
+
+ mr = talloc_zero(ac, struct map_reply);
+ if (mr == NULL) {
+ map_oom(ac->module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ mr->remote = talloc_steal(mr, ares);
+ if (ac->r_current) {
+ ac->r_current->next = mr;
+ } else {
+ /* first entry */
+ ac->r_list = mr;
+ }
+ ac->r_current = mr;
+
+ return LDB_SUCCESS;
+}
+
+/* Pass a merged search result up the callback chain. */
+int map_return_entry(struct map_context *ac, struct ldb_reply *ares)
+{
+ struct ldb_message_element *el;
+ const char * const *attrs;
+ struct ldb_context *ldb;
+ unsigned int i;
+ int ret;
+ bool matched;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ /* Merged result doesn't match original query, skip */
+ ret = ldb_match_msg_error(ldb, ares->message,
+ ac->req->op.search.tree,
+ ac->req->op.search.base,
+ ac->req->op.search.scope,
+ &matched);
+ if (ret != LDB_SUCCESS) return ret;
+ if (!matched) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
+ "Skipping record '%s': "
+ "doesn't match original search",
+ ldb_dn_get_linearized(ares->message->dn));
+ return LDB_SUCCESS;
+ }
+
+ /* Limit result to requested attrs */
+ if (ac->req->op.search.attrs &&
+ (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) {
+
+ attrs = ac->req->op.search.attrs;
+ i = 0;
+
+ while (i < ares->message->num_elements) {
+
+ el = &ares->message->elements[i];
+ if ( ! ldb_attr_in_list(attrs, el->name)) {
+ ldb_msg_remove_element(ares->message, el);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ return ldb_module_send_entry(ac->req, ares->message, ares->controls);
+}
+
+/* Search a record. */
+int ldb_map_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_parse_tree *remote_tree;
+ struct ldb_parse_tree *local_tree;
+ struct ldb_request *remote_req;
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ const char *wildcard[] = { "*", NULL };
+ const char * const *attrs;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* if we're not yet initialized, go to the next module */
+ if (!ldb_module_get_private(module))
+ return ldb_next_request(module, req);
+
+ /* Do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.search.base)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* No mapping requested, skip to next module */
+ if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
+ return ldb_next_request(module, req);
+ }
+
+ /* TODO: How can we be sure about which partition we are
+ * targeting when there is no search base? */
+
+ /* Prepare context and handle */
+ ac = map_init_context(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* It is easier to deal with the two different ways of
+ * expressing the wildcard in the same codepath */
+ attrs = req->op.search.attrs;
+ if (attrs == NULL) {
+ attrs = wildcard;
+ }
+
+ /* Split local from remote attrs */
+ ret = map_attrs_collect_and_partition(module, ac,
+ attrs, req->op.search.tree);
+ if (ret) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Split local from remote tree */
+ ret = ldb_parse_tree_partition(module, ac,
+ &local_tree, &remote_tree,
+ req->op.search.tree);
+ if (ret) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (((local_tree != NULL) && (remote_tree != NULL)) &&
+ (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
+ /* The query can't safely be split, enumerate the remote partition */
+ local_tree = NULL;
+ remote_tree = NULL;
+ }
+
+ if (local_tree == NULL) {
+ /* Construct default local parse tree */
+ local_tree = talloc_zero(ac, struct ldb_parse_tree);
+ if (local_tree == NULL) {
+ map_oom(ac->module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ local_tree->operation = LDB_OP_PRESENT;
+ local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
+ }
+ if (remote_tree == NULL) {
+ /* Construct default remote parse tree */
+ remote_tree = ldb_parse_tree(ac, NULL);
+ if (remote_tree == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ ac->local_tree = local_tree;
+
+ /* Prepare the remote operation */
+ ret = ldb_build_search_req_ex(&remote_req, ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ remote_tree,
+ ac->remote_attrs,
+ req->controls,
+ ac, map_remote_search_callback,
+ req);
+ LDB_REQ_SET_LOCATION(remote_req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_remote_request(module, remote_req);
+}
+
+/* Now, search the local part of a remote search result. */
+static int map_remote_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct map_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct map_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_REFERRAL:
+
+ /* ignore referrals */
+ talloc_free(ares);
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_ENTRY:
+
+ /* Map result record into a local message */
+ ret = map_reply_remote(ac, ares);
+ if (ret) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* if we have no local db, then we can just return the reply to
+ * the upper layer, otherwise we must save it and process it
+ * when all replies have been gathered */
+ if ( ! map_check_local_db(ac->module)) {
+ ret = map_return_entry(ac, ares);
+ } else {
+ ret = map_save_entry(ac,ares);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ break;
+
+ case LDB_REPLY_DONE:
+
+ if ( ! map_check_local_db(ac->module)) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+ }
+
+ /* reset the pointer to the start of the list */
+ ac->r_current = ac->r_list;
+
+ /* no entry just return */
+ if (ac->r_current == NULL) {
+ ret = ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+ talloc_free(ares);
+ return ret;
+ }
+
+ ac->remote_done_ares = talloc_steal(ac, ares);
+
+ ret = map_search_local(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int map_search_local(struct map_context *ac)
+{
+ struct ldb_request *search_req;
+
+ if (ac->r_current == NULL || ac->r_current->remote == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Prepare local search request */
+ /* TODO: use GUIDs here instead? */
+ search_req = map_search_base_req(ac,
+ ac->r_current->remote->message->dn,
+ NULL, NULL,
+ ac, map_local_merge_callback);
+ if (search_req == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(ac->module, search_req);
+}
+
+/* Merge the remote and local parts of a search result. */
+int map_local_merge_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_context *ldb;
+ struct map_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct map_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* We have already found a local record */
+ if (ac->r_current->local) {
+ talloc_free(ares);
+ ldb_set_errstring(ldb, "ldb_map: Too many results!");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* Store local result */
+ ac->r_current->local = talloc_steal(ac->r_current, ares);
+
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore referrals */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
+ /* We don't need the local 'ares', but we will use the remote one from below */
+ talloc_free(ares);
+
+ /* No local record found, map and send remote record */
+ if (ac->r_current->local != NULL) {
+ /* Merge remote into local message */
+ ret = ldb_msg_merge_local(ac->module,
+ ac->r_current->local->message,
+ ac->r_current->remote->message);
+ if (ret == LDB_SUCCESS) {
+ ret = map_return_entry(ac, ac->r_current->local);
+ }
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ } else {
+ ret = map_return_entry(ac, ac->r_current->remote);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+ }
+
+ if (ac->r_current->next != NULL) {
+ ac->r_current = ac->r_current->next;
+ if (ac->r_current->remote->type == LDB_REPLY_ENTRY) {
+ ret = map_search_local(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+ break;
+ }
+ }
+
+ /* ok we are done with all search, finally it is time to
+ * finish operations for this module */
+ return ldb_module_done(ac->req,
+ ac->remote_done_ares->controls,
+ ac->remote_done_ares->response,
+ ac->remote_done_ares->error);
+ }
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb/ldb_map/ldb_map_private.h b/lib/ldb/ldb_map/ldb_map_private.h
new file mode 100644
index 0000000..aaf96e9
--- /dev/null
+++ b/lib/ldb/ldb_map/ldb_map_private.h
@@ -0,0 +1,96 @@
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+
+/* A handy macro to report Out of Memory conditions */
+#define map_oom(module) ldb_set_errstring(ldb_module_get_ctx(module), talloc_asprintf(module, "Out of Memory"));
+
+/* The type of search callback functions */
+typedef int (*ldb_map_callback_t)(struct ldb_request *, struct ldb_reply *);
+
+/* The special DN from which the local and remote base DNs are fetched */
+#define MAP_DN_NAME "@MAP"
+#define MAP_DN_FROM "@FROM"
+#define MAP_DN_TO "@TO"
+
+/* Private data structures
+ * ======================= */
+
+struct map_reply {
+ struct map_reply *next;
+ struct ldb_reply *remote;
+ struct ldb_reply *local;
+};
+
+/* Context data for mapped requests */
+struct map_context {
+
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ struct ldb_dn *local_dn;
+ const struct ldb_parse_tree *local_tree;
+ const char * const *local_attrs;
+ const char * const *remote_attrs;
+ const char * const *all_attrs;
+
+ struct ldb_message *local_msg;
+ struct ldb_request *remote_req;
+
+ struct map_reply *r_list;
+ struct map_reply *r_current;
+
+ /* The response containing any controls the remote server gave */
+ struct ldb_reply *remote_done_ares;
+};
+
+/* Common operations
+ * ================= */
+
+/* The following definitions come from lib/ldb/modules/ldb_map.c */
+const struct ldb_map_context *map_get_context(struct ldb_module *module);
+struct map_context *map_init_context(struct ldb_module *module,
+ struct ldb_request *req);
+
+int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request);
+
+bool map_check_local_db(struct ldb_module *module);
+bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr);
+bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn);
+
+const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name);
+const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name);
+
+const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr);
+const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr);
+int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attrs, const char * const *more_attrs);
+
+struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val);
+struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val);
+
+struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn);
+struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn);
+struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn);
+
+struct ldb_request *map_search_base_req(struct map_context *ac,
+ struct ldb_dn *dn,
+ const char * const *attrs,
+ struct ldb_parse_tree *tree,
+ void *context,
+ ldb_map_callback_t callback);
+struct ldb_request *map_build_fixup_req(struct map_context *ac,
+ struct ldb_dn *olddn,
+ struct ldb_dn *newdn,
+ void *context,
+ ldb_map_callback_t callback);
+int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx,
+ struct ldb_parse_tree **new,
+ const struct ldb_parse_tree *tree,
+ const struct ldb_map_attribute *map);
+int map_return_fatal_error(struct ldb_request *req,
+ struct ldb_reply *ares);
+int map_return_normal_error(struct ldb_request *req,
+ struct ldb_reply *ares,
+ int error);
+
+int map_return_entry(struct map_context *ac, struct ldb_reply *ares);
diff --git a/lib/ldb/ldb_mdb/ldb_mdb.c b/lib/ldb/ldb_mdb/ldb_mdb.c
new file mode 100644
index 0000000..e979cfa
--- /dev/null
+++ b/lib/ldb/ldb_mdb/ldb_mdb.c
@@ -0,0 +1,1151 @@
+/*
+ ldb database library using mdb back end
+
+ Copyright (C) Jakub Hrozek 2014
+ Copyright (C) Catalyst.Net Ltd 2017
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb_mdb.h"
+#include "../ldb_key_value/ldb_kv.h"
+#include "include/dlinklist.h"
+
+#define MDB_URL_PREFIX "mdb://"
+#define MDB_URL_PREFIX_SIZE (sizeof(MDB_URL_PREFIX)-1)
+
+#define LDB_MDB_MAX_KEY_LENGTH 511
+
+#define GIGABYTE (1024*1024*1024)
+
+int ldb_mdb_err_map(int lmdb_err)
+{
+ switch (lmdb_err) {
+ case MDB_SUCCESS:
+ return LDB_SUCCESS;
+ case EIO:
+ return LDB_ERR_OPERATIONS_ERROR;
+#ifdef EBADE
+ case EBADE:
+#endif
+ case MDB_INCOMPATIBLE:
+ case MDB_CORRUPTED:
+ case MDB_INVALID:
+ return LDB_ERR_UNAVAILABLE;
+ case MDB_BAD_TXN:
+ case MDB_BAD_VALSIZE:
+#ifdef MDB_BAD_DBI
+ case MDB_BAD_DBI:
+#endif
+ case MDB_PANIC:
+ case EINVAL:
+ return LDB_ERR_PROTOCOL_ERROR;
+ case MDB_MAP_FULL:
+ case MDB_DBS_FULL:
+ case MDB_READERS_FULL:
+ case MDB_TLS_FULL:
+ case MDB_TXN_FULL:
+ case EAGAIN:
+ return LDB_ERR_BUSY;
+ case MDB_KEYEXIST:
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ case MDB_NOTFOUND:
+ case ENOENT:
+ return LDB_ERR_NO_SUCH_OBJECT;
+ case EACCES:
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ default:
+ break;
+ }
+ return LDB_ERR_OTHER;
+}
+
+#define ldb_mdb_error(ldb, ecode) lmdb_error_at(ldb, ecode, __FILE__, __LINE__)
+static int lmdb_error_at(struct ldb_context *ldb,
+ int ecode,
+ const char *file,
+ int line)
+{
+ int ldb_err = ldb_mdb_err_map(ecode);
+ char *reason = mdb_strerror(ecode);
+ ldb_asprintf_errstring(ldb,
+ "(%d) - %s at %s:%d",
+ ecode,
+ reason,
+ file,
+ line);
+ return ldb_err;
+}
+
+static bool lmdb_transaction_active(struct ldb_kv_private *ldb_kv)
+{
+ return ldb_kv->lmdb_private->txlist != NULL;
+}
+
+static MDB_txn *lmdb_trans_get_tx(struct lmdb_trans *ltx)
+{
+ if (ltx == NULL) {
+ return NULL;
+ }
+
+ return ltx->tx;
+}
+
+static void trans_push(struct lmdb_private *lmdb, struct lmdb_trans *ltx)
+{
+ if (lmdb->txlist) {
+ talloc_steal(lmdb->txlist, ltx);
+ }
+
+ DLIST_ADD(lmdb->txlist, ltx);
+}
+
+static void trans_finished(struct lmdb_private *lmdb, struct lmdb_trans *ltx)
+{
+ DLIST_REMOVE(lmdb->txlist, ltx);
+ talloc_free(ltx);
+}
+
+
+static struct lmdb_trans *lmdb_private_trans_head(struct lmdb_private *lmdb)
+{
+ struct lmdb_trans *ltx;
+
+ ltx = lmdb->txlist;
+ return ltx;
+}
+
+
+static MDB_txn *get_current_txn(struct lmdb_private *lmdb)
+{
+ MDB_txn *txn = NULL;
+
+ txn = lmdb_trans_get_tx(lmdb_private_trans_head(lmdb));
+ if (txn != NULL) {
+ return txn;
+ }
+ if (lmdb->read_txn != NULL) {
+ return lmdb->read_txn;
+ }
+ lmdb->error = MDB_BAD_TXN;
+ ldb_set_errstring(lmdb->ldb, __location__":No active transaction\n");
+ return NULL;
+}
+
+static int lmdb_store(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val data,
+ int flags)
+{
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ MDB_val mdb_key;
+ MDB_val mdb_data;
+ int mdb_flags;
+ MDB_txn *txn = NULL;
+ MDB_dbi dbi = 0;
+
+ if (ldb_kv->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ txn = lmdb_trans_get_tx(lmdb_private_trans_head(lmdb));
+ if (txn == NULL) {
+ ldb_debug(lmdb->ldb, LDB_DEBUG_FATAL, "No transaction");
+ lmdb->error = MDB_PANIC;
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ lmdb->error = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ mdb_key.mv_size = key.length;
+ mdb_key.mv_data = key.data;
+
+ mdb_data.mv_size = data.length;
+ mdb_data.mv_data = data.data;
+
+ if (flags == TDB_INSERT) {
+ mdb_flags = MDB_NOOVERWRITE;
+ } else if (flags == TDB_MODIFY) {
+ /*
+ * Modifying a record, ensure that it exists.
+ * This mimics the TDB semantics
+ */
+ MDB_val value;
+ lmdb->error = mdb_get(txn, dbi, &mdb_key, &value);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+ mdb_flags = 0;
+ } else {
+ mdb_flags = 0;
+ }
+
+ lmdb->error = mdb_put(txn, dbi, &mdb_key, &mdb_data, mdb_flags);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ return ldb_mdb_err_map(lmdb->error);
+}
+
+static int lmdb_delete(struct ldb_kv_private *ldb_kv, struct ldb_val key)
+{
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ MDB_val mdb_key;
+ MDB_txn *txn = NULL;
+ MDB_dbi dbi = 0;
+
+ if (ldb_kv->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ txn = lmdb_trans_get_tx(lmdb_private_trans_head(lmdb));
+ if (txn == NULL) {
+ ldb_debug(lmdb->ldb, LDB_DEBUG_FATAL, "No transaction");
+ lmdb->error = MDB_PANIC;
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ lmdb->error = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ mdb_key.mv_size = key.length;
+ mdb_key.mv_data = key.data;
+
+ lmdb->error = mdb_del(txn, dbi, &mdb_key, NULL);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+ return ldb_mdb_err_map(lmdb->error);
+}
+
+static int lmdb_traverse_fn(struct ldb_kv_private *ldb_kv,
+ ldb_kv_traverse_fn fn,
+ void *ctx)
+{
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ MDB_val mdb_key;
+ MDB_val mdb_data;
+ MDB_txn *txn = NULL;
+ MDB_dbi dbi = 0;
+ MDB_cursor *cursor = NULL;
+ int ret;
+
+ txn = get_current_txn(lmdb);
+ if (txn == NULL) {
+ ldb_debug(lmdb->ldb, LDB_DEBUG_FATAL, "No transaction");
+ lmdb->error = MDB_PANIC;
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ lmdb->error = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ lmdb->error = mdb_cursor_open(txn, dbi, &cursor);
+ if (lmdb->error != MDB_SUCCESS) {
+ goto done;
+ }
+
+ while ((lmdb->error = mdb_cursor_get(
+ cursor, &mdb_key,
+ &mdb_data, MDB_NEXT)) == MDB_SUCCESS) {
+
+ struct ldb_val key = {
+ .length = mdb_key.mv_size,
+ .data = mdb_key.mv_data,
+ };
+ struct ldb_val data = {
+ .length = mdb_data.mv_size,
+ .data = mdb_data.mv_data,
+ };
+
+ ret = fn(ldb_kv, key, data, ctx);
+ if (ret != 0) {
+ /*
+ * NOTE: This DOES NOT set lmdb->error!
+ *
+ * This means that the caller will get success.
+ * This matches TDB traverse behaviour, where callbacks
+ * may terminate the traverse, but do not change the
+ * return code from success.
+ *
+ * Callers SHOULD store their own error codes.
+ */
+ goto done;
+ }
+ }
+ if (lmdb->error == MDB_NOTFOUND) {
+ lmdb->error = MDB_SUCCESS;
+ }
+done:
+ if (cursor != NULL) {
+ mdb_cursor_close(cursor);
+ }
+
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+ return ldb_mdb_err_map(lmdb->error);
+}
+
+static int lmdb_update_in_iterate(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val key2,
+ struct ldb_val data,
+ void *state)
+{
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ struct ldb_val copy;
+ int ret = LDB_SUCCESS;
+
+ /*
+ * Need to take a copy of the data as the delete operation alters the
+ * data, as it is in private lmdb memory.
+ */
+ copy.length = data.length;
+ copy.data = talloc_memdup(ldb_kv, data.data, data.length);
+ if (copy.data == NULL) {
+ lmdb->error = MDB_PANIC;
+ return ldb_oom(lmdb->ldb);
+ }
+
+ lmdb->error = lmdb_delete(ldb_kv, key);
+ if (lmdb->error != MDB_SUCCESS) {
+ ldb_debug(
+ lmdb->ldb,
+ LDB_DEBUG_ERROR,
+ "Failed to delete %*.*s "
+ "for rekey as %*.*s: %s",
+ (int)key.length, (int)key.length,
+ (const char *)key.data,
+ (int)key2.length, (int)key2.length,
+ (const char *)key.data,
+ mdb_strerror(lmdb->error));
+ ret = ldb_mdb_error(lmdb->ldb, lmdb->error);
+ goto done;
+ }
+
+ lmdb->error = lmdb_store(ldb_kv, key2, copy, 0);
+ if (lmdb->error != MDB_SUCCESS) {
+ ldb_debug(
+ lmdb->ldb,
+ LDB_DEBUG_ERROR,
+ "Failed to rekey %*.*s as %*.*s: %s",
+ (int)key.length, (int)key.length,
+ (const char *)key.data,
+ (int)key2.length, (int)key2.length,
+ (const char *)key.data,
+ mdb_strerror(lmdb->error));
+ ret = ldb_mdb_error(lmdb->ldb, lmdb->error);
+ goto done;
+ }
+
+done:
+ if (copy.data != NULL) {
+ TALLOC_FREE(copy.data);
+ copy.length = 0;
+ }
+
+ /*
+ * Explicitly invalidate the data, as the delete has done this
+ */
+ data.length = 0;
+ data.data = NULL;
+
+ return ret;
+}
+
+/* Handles only a single record */
+static int lmdb_parse_record(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ int (*parser)(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data),
+ void *ctx)
+{
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ MDB_val mdb_key;
+ MDB_val mdb_data;
+ MDB_txn *txn = NULL;
+ MDB_dbi dbi;
+ struct ldb_val data;
+
+ txn = get_current_txn(lmdb);
+ if (txn == NULL) {
+ ldb_debug(lmdb->ldb, LDB_DEBUG_FATAL, "No transaction active");
+ lmdb->error = MDB_PANIC;
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ lmdb->error = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ mdb_key.mv_size = key.length;
+ mdb_key.mv_data = key.data;
+
+ lmdb->error = mdb_get(txn, dbi, &mdb_key, &mdb_data);
+ if (lmdb->error != MDB_SUCCESS) {
+ /* TODO closing a handle should not even be necessary */
+ mdb_dbi_close(lmdb->env, dbi);
+ if (lmdb->error == MDB_NOTFOUND) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ if (lmdb->error == MDB_CORRUPTED) {
+ ldb_debug(lmdb->ldb, LDB_DEBUG_ERROR,
+ __location__
+ ": MDB corrupted for key [%*.*s]\n",
+ (int)key.length,
+ (int)key.length,
+ key.data);
+ }
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+ data.data = mdb_data.mv_data;
+ data.length = mdb_data.mv_size;
+
+ /* TODO closing a handle should not even be necessary */
+ mdb_dbi_close(lmdb->env, dbi);
+
+ return parser(key, data, ctx);
+}
+
+/*
+ * Exactly the same as iterate, except we have a start key and an end key
+ * (which are both included in the results if present).
+ *
+ * If start > end, return MDB_PANIC.
+ */
+static int lmdb_iterate_range(struct ldb_kv_private *ldb_kv,
+ struct ldb_val start_key,
+ struct ldb_val end_key,
+ ldb_kv_traverse_fn fn,
+ void *ctx)
+{
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ MDB_val mdb_key;
+ MDB_val mdb_data;
+ MDB_txn *txn = NULL;
+ MDB_dbi dbi = 0;
+ MDB_cursor *cursor = NULL;
+ int ret;
+
+ MDB_val mdb_s_key;
+ MDB_val mdb_e_key;
+
+ txn = get_current_txn(lmdb);
+ if (txn == NULL) {
+ ldb_debug(lmdb->ldb, LDB_DEBUG_FATAL, "No transaction");
+ lmdb->error = MDB_PANIC;
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ lmdb->error = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ mdb_s_key.mv_size = start_key.length;
+ mdb_s_key.mv_data = start_key.data;
+
+ mdb_e_key.mv_size = end_key.length;
+ mdb_e_key.mv_data = end_key.data;
+
+ if (mdb_cmp(txn, dbi, &mdb_s_key, &mdb_e_key) > 0) {
+ lmdb->error = MDB_PANIC;
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ lmdb->error = mdb_cursor_open(txn, dbi, &cursor);
+ if (lmdb->error != MDB_SUCCESS) {
+ goto done;
+ }
+
+ lmdb->error = mdb_cursor_get(cursor, &mdb_s_key, &mdb_data, MDB_SET_RANGE);
+
+ if (lmdb->error != MDB_SUCCESS) {
+ if (lmdb->error == MDB_NOTFOUND) {
+ lmdb->error = MDB_SUCCESS;
+ }
+ goto done;
+ } else {
+ struct ldb_val key = {
+ .length = mdb_s_key.mv_size,
+ .data = mdb_s_key.mv_data,
+ };
+ struct ldb_val data = {
+ .length = mdb_data.mv_size,
+ .data = mdb_data.mv_data,
+ };
+
+ if (mdb_cmp(txn, dbi, &mdb_s_key, &mdb_e_key) > 0) {
+ goto done;
+ }
+
+ ret = fn(ldb_kv, key, data, ctx);
+ if (ret != 0) {
+ /*
+ * NOTE: This DOES NOT set lmdb->error!
+ *
+ * This means that the caller will get success.
+ * This matches TDB traverse behaviour, where callbacks
+ * may terminate the traverse, but do not change the
+ * return code from success.
+ *
+ * Callers SHOULD store their own error codes.
+ */
+ goto done;
+ }
+ }
+
+ while ((lmdb->error = mdb_cursor_get(
+ cursor, &mdb_key,
+ &mdb_data, MDB_NEXT)) == MDB_SUCCESS) {
+
+ struct ldb_val key = {
+ .length = mdb_key.mv_size,
+ .data = mdb_key.mv_data,
+ };
+ struct ldb_val data = {
+ .length = mdb_data.mv_size,
+ .data = mdb_data.mv_data,
+ };
+
+ if (mdb_cmp(txn, dbi, &mdb_key, &mdb_e_key) > 0) {
+ goto done;
+ }
+
+ ret = fn(ldb_kv, key, data, ctx);
+ if (ret != 0) {
+ /*
+ * NOTE: This DOES NOT set lmdb->error!
+ *
+ * This means that the caller will get success.
+ * This matches TDB traverse behaviour, where callbacks
+ * may terminate the traverse, but do not change the
+ * return code from success.
+ *
+ * Callers SHOULD store their own error codes.
+ */
+ goto done;
+ }
+ }
+ if (lmdb->error == MDB_NOTFOUND) {
+ lmdb->error = MDB_SUCCESS;
+ }
+done:
+ if (cursor != NULL) {
+ mdb_cursor_close(cursor);
+ }
+
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+ return ldb_mdb_err_map(lmdb->error);
+}
+
+static int lmdb_lock_read(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ pid_t pid = getpid();
+
+ if (pid != lmdb->pid) {
+ ldb_asprintf_errstring(
+ lmdb->ldb,
+ __location__": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ lmdb->pid,
+ pid);
+ lmdb->error = MDB_BAD_TXN;
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ lmdb->error = MDB_SUCCESS;
+ if (lmdb_transaction_active(ldb_kv) == false &&
+ ldb_kv->read_lock_count == 0) {
+ lmdb->error = mdb_txn_begin(lmdb->env,
+ NULL,
+ MDB_RDONLY,
+ &lmdb->read_txn);
+ }
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ ldb_kv->read_lock_count++;
+ return ldb_mdb_err_map(lmdb->error);
+}
+
+static int lmdb_unlock_read(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+
+ if (lmdb_transaction_active(ldb_kv) == false &&
+ ldb_kv->read_lock_count == 1) {
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ mdb_txn_commit(lmdb->read_txn);
+ lmdb->read_txn = NULL;
+ ldb_kv->read_lock_count--;
+ return LDB_SUCCESS;
+ }
+ ldb_kv->read_lock_count--;
+ return LDB_SUCCESS;
+}
+
+static int lmdb_transaction_start(struct ldb_kv_private *ldb_kv)
+{
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ struct lmdb_trans *ltx;
+ struct lmdb_trans *ltx_head;
+ MDB_txn *tx_parent;
+ pid_t pid = getpid();
+
+ /* Do not take out the transaction lock on a read-only DB */
+ if (ldb_kv->read_only) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ ltx = talloc_zero(lmdb, struct lmdb_trans);
+ if (ltx == NULL) {
+ return ldb_oom(lmdb->ldb);
+ }
+
+ if (pid != lmdb->pid) {
+ ldb_asprintf_errstring(
+ lmdb->ldb,
+ __location__": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ lmdb->pid,
+ pid);
+ lmdb->error = MDB_BAD_TXN;
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ /*
+ * Clear out any stale readers
+ */
+ {
+ int stale = 0;
+ mdb_reader_check(lmdb->env, &stale);
+ if (stale > 0) {
+ ldb_debug(
+ lmdb->ldb,
+ LDB_DEBUG_ERROR,
+ "LMDB Stale readers, deleted (%d)",
+ stale);
+ }
+ }
+
+
+
+ ltx_head = lmdb_private_trans_head(lmdb);
+
+ tx_parent = lmdb_trans_get_tx(ltx_head);
+
+ lmdb->error = mdb_txn_begin(lmdb->env, tx_parent, 0, &ltx->tx);
+ if (lmdb->error != MDB_SUCCESS) {
+ return ldb_mdb_error(lmdb->ldb, lmdb->error);
+ }
+
+ trans_push(lmdb, ltx);
+
+ return ldb_mdb_err_map(lmdb->error);
+}
+
+static int lmdb_transaction_cancel(struct ldb_kv_private *ldb_kv)
+{
+ struct lmdb_trans *ltx;
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+
+ ltx = lmdb_private_trans_head(lmdb);
+ if (ltx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ mdb_txn_abort(ltx->tx);
+ trans_finished(lmdb, ltx);
+ return LDB_SUCCESS;
+}
+
+static int lmdb_transaction_prepare_commit(struct ldb_kv_private *ldb_kv)
+{
+ /* No need to prepare a commit */
+ return LDB_SUCCESS;
+}
+
+static int lmdb_transaction_commit(struct ldb_kv_private *ldb_kv)
+{
+ struct lmdb_trans *ltx;
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+
+ ltx = lmdb_private_trans_head(lmdb);
+ if (ltx == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lmdb->error = mdb_txn_commit(ltx->tx);
+ trans_finished(lmdb, ltx);
+
+ return lmdb->error;
+}
+
+static int lmdb_error(struct ldb_kv_private *ldb_kv)
+{
+ return ldb_mdb_err_map(ldb_kv->lmdb_private->error);
+}
+
+static const char *lmdb_errorstr(struct ldb_kv_private *ldb_kv)
+{
+ return mdb_strerror(ldb_kv->lmdb_private->error);
+}
+
+static const char *lmdb_name(struct ldb_kv_private *ldb_kv)
+{
+ return "lmdb";
+}
+
+static bool lmdb_changed(struct ldb_kv_private *ldb_kv)
+{
+ /*
+ * lmdb does no provide a quick way to determine if the database
+ * has changed. This function always returns true.
+ *
+ * Note that tdb uses a sequence number that allows this function
+ * to be implemented efficiently.
+ */
+ return true;
+}
+
+/*
+ * Get the number of records in the database.
+ *
+ * The mdb_env_stat call returns an accurate count, so we return the actual
+ * number of records in the database rather than an estimate.
+ */
+static size_t lmdb_get_size(struct ldb_kv_private *ldb_kv)
+{
+
+ struct MDB_stat stats = {0};
+ struct lmdb_private *lmdb = ldb_kv->lmdb_private;
+ int ret = 0;
+
+ ret = mdb_env_stat(lmdb->env, &stats);
+ if (ret != 0) {
+ return 0;
+ }
+ return stats.ms_entries;
+}
+
+/*
+ * Start a sub transaction
+ * As lmdb supports nested transactions we can start a new transaction
+ */
+static int lmdb_nested_transaction_start(struct ldb_kv_private *ldb_kv)
+{
+ int ret = lmdb_transaction_start(ldb_kv);
+ return ret;
+}
+
+/*
+ * Commit a sub transaction
+ * As lmdb supports nested transactions we can commit the nested transaction
+ */
+static int lmdb_nested_transaction_commit(struct ldb_kv_private *ldb_kv)
+{
+ int ret = lmdb_transaction_commit(ldb_kv);
+ return ret;
+}
+
+/*
+ * Cancel a sub transaction
+ * As lmdb supports nested transactions we can cancel the nested transaction
+ */
+static int lmdb_nested_transaction_cancel(struct ldb_kv_private *ldb_kv)
+{
+ int ret = lmdb_transaction_cancel(ldb_kv);
+ return ret;
+}
+
+static struct kv_db_ops lmdb_key_value_ops = {
+ .options = LDB_KV_OPTION_STABLE_READ_LOCK,
+
+ .store = lmdb_store,
+ .delete = lmdb_delete,
+ .iterate = lmdb_traverse_fn,
+ .update_in_iterate = lmdb_update_in_iterate,
+ .fetch_and_parse = lmdb_parse_record,
+ .iterate_range = lmdb_iterate_range,
+ .lock_read = lmdb_lock_read,
+ .unlock_read = lmdb_unlock_read,
+ .begin_write = lmdb_transaction_start,
+ .prepare_write = lmdb_transaction_prepare_commit,
+ .finish_write = lmdb_transaction_commit,
+ .abort_write = lmdb_transaction_cancel,
+ .error = lmdb_error,
+ .errorstr = lmdb_errorstr,
+ .name = lmdb_name,
+ .has_changed = lmdb_changed,
+ .transaction_active = lmdb_transaction_active,
+ .get_size = lmdb_get_size,
+ .begin_nested_write = lmdb_nested_transaction_start,
+ .finish_nested_write = lmdb_nested_transaction_commit,
+ .abort_nested_write = lmdb_nested_transaction_cancel,
+};
+
+static const char *lmdb_get_path(const char *url)
+{
+ const char *path;
+
+ /* parse the url */
+ if (strchr(url, ':')) {
+ if (strncmp(url, MDB_URL_PREFIX, MDB_URL_PREFIX_SIZE) != 0) {
+ return NULL;
+ }
+ path = url + MDB_URL_PREFIX_SIZE;
+ } else {
+ path = url;
+ }
+
+ return path;
+}
+
+static int lmdb_pvt_destructor(struct lmdb_private *lmdb)
+{
+ struct lmdb_trans *ltx = NULL;
+
+ /* Check if this is a forked child */
+ if (getpid() != lmdb->pid) {
+ int fd = 0;
+ /*
+ * We cannot call mdb_env_close or commit any transactions,
+ * otherwise they might appear finished in the parent.
+ *
+ */
+
+ if (mdb_env_get_fd(lmdb->env, &fd) == 0) {
+ close(fd);
+ }
+
+ /* Remove the pointer, so that no access should occur */
+ lmdb->env = NULL;
+
+ return 0;
+ }
+
+ /*
+ * Close the read transaction if it's open
+ */
+ if (lmdb->read_txn != NULL) {
+ mdb_txn_abort(lmdb->read_txn);
+ }
+
+ if (lmdb->env == NULL) {
+ return 0;
+ }
+
+ /*
+ * Abort any currently active transactions
+ */
+ ltx = lmdb_private_trans_head(lmdb);
+ while (ltx != NULL) {
+ mdb_txn_abort(ltx->tx);
+ trans_finished(lmdb, ltx);
+ ltx = lmdb_private_trans_head(lmdb);
+ }
+ lmdb->env = NULL;
+
+ return 0;
+}
+
+struct mdb_env_wrap {
+ struct mdb_env_wrap *next, *prev;
+ dev_t device;
+ ino_t inode;
+ MDB_env *env;
+ pid_t pid;
+};
+
+static struct mdb_env_wrap *mdb_list;
+
+/* destroy the last connection to an mdb */
+static int mdb_env_wrap_destructor(struct mdb_env_wrap *w)
+{
+ mdb_env_close(w->env);
+ DLIST_REMOVE(mdb_list, w);
+ return 0;
+}
+
+static int lmdb_open_env(TALLOC_CTX *mem_ctx,
+ MDB_env **env,
+ struct ldb_context *ldb,
+ const char *path,
+ const size_t env_map_size,
+ unsigned int flags)
+{
+ int ret;
+ unsigned int mdb_flags = MDB_NOSUBDIR|MDB_NOTLS;
+ /*
+ * MDB_NOSUBDIR implies there is a separate file called path and a
+ * separate lockfile called path-lock
+ */
+
+ struct mdb_env_wrap *w;
+ struct stat st;
+ pid_t pid = getpid();
+ int fd = 0;
+ unsigned v;
+
+ if (stat(path, &st) == 0) {
+ for (w=mdb_list;w;w=w->next) {
+ if (st.st_dev == w->device &&
+ st.st_ino == w->inode &&
+ pid == w->pid) {
+ /*
+ * We must have only one MDB_env per process
+ */
+ if (!talloc_reference(mem_ctx, w)) {
+ return ldb_oom(ldb);
+ }
+ *env = w->env;
+ return LDB_SUCCESS;
+ }
+ }
+ }
+
+ w = talloc(mem_ctx, struct mdb_env_wrap);
+ if (w == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ ret = mdb_env_create(env);
+ if (ret != 0) {
+ ldb_asprintf_errstring(
+ ldb,
+ "Could not create MDB environment %s: %s\n",
+ path,
+ mdb_strerror(ret));
+ return ldb_mdb_err_map(ret);
+ }
+
+ if (env_map_size > 0) {
+ ret = mdb_env_set_mapsize(*env, env_map_size);
+ if (ret != 0) {
+ ldb_asprintf_errstring(
+ ldb,
+ "Could not set MDB mmap() size to %llu "
+ "on %s: %s\n",
+ (unsigned long long)(env_map_size),
+ path,
+ mdb_strerror(ret));
+ TALLOC_FREE(w);
+ return ldb_mdb_err_map(ret);
+ }
+ }
+
+ mdb_env_set_maxreaders(*env, 100000);
+ /*
+ * As we ensure that there is only one MDB_env open per database per
+ * process. We can not use the MDB_RDONLY flag, as another ldb may be
+ * opened in read write mode
+ */
+ if (flags & LDB_FLG_NOSYNC) {
+ mdb_flags |= MDB_NOSYNC;
+ }
+ ret = mdb_env_open(*env, path, mdb_flags, 0644);
+ if (ret != 0) {
+ ldb_asprintf_errstring(ldb,
+ "Could not open DB %s: %s\n",
+ path, mdb_strerror(ret));
+ TALLOC_FREE(w);
+ return ldb_mdb_err_map(ret);
+ }
+
+ {
+ MDB_envinfo stat = {0};
+ ret = mdb_env_info (*env, &stat);
+ if (ret != 0) {
+ ldb_asprintf_errstring(
+ ldb,
+ "Could not get MDB environment stats %s: %s\n",
+ path,
+ mdb_strerror(ret));
+ return ldb_mdb_err_map(ret);
+ }
+ }
+
+ ret = mdb_env_get_fd(*env, &fd);
+ if (ret != 0) {
+ ldb_asprintf_errstring(ldb,
+ "Could not obtain DB FD %s: %s\n",
+ path, mdb_strerror(ret));
+ TALLOC_FREE(w);
+ return ldb_mdb_err_map(ret);
+ }
+
+ /* Just as for TDB: on exec, don't inherit the fd */
+ v = fcntl(fd, F_GETFD, 0);
+ if (v == -1) {
+ TALLOC_FREE(w);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = fcntl(fd, F_SETFD, v | FD_CLOEXEC);
+ if (ret == -1) {
+ TALLOC_FREE(w);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (fstat(fd, &st) != 0) {
+ ldb_asprintf_errstring(
+ ldb,
+ "Could not stat %s:\n",
+ path);
+ TALLOC_FREE(w);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ w->env = *env;
+ w->device = st.st_dev;
+ w->inode = st.st_ino;
+ w->pid = pid;
+
+ talloc_set_destructor(w, mdb_env_wrap_destructor);
+
+ DLIST_ADD(mdb_list, w);
+
+ return LDB_SUCCESS;
+
+}
+
+static int lmdb_pvt_open(struct lmdb_private *lmdb,
+ struct ldb_context *ldb,
+ const char *path,
+ const size_t env_map_size,
+ unsigned int flags)
+{
+ int ret;
+ int lmdb_max_key_length;
+
+ if (flags & LDB_FLG_DONT_CREATE_DB) {
+ struct stat st;
+ if (stat(path, &st) != 0) {
+ return LDB_ERR_UNAVAILABLE;
+ }
+ }
+
+ ret = lmdb_open_env(lmdb, &lmdb->env, ldb, path, env_map_size, flags);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Close when lmdb is released */
+ talloc_set_destructor(lmdb, lmdb_pvt_destructor);
+
+ /* Store the original pid during the LMDB open */
+ lmdb->pid = getpid();
+
+ lmdb_max_key_length = mdb_env_get_maxkeysize(lmdb->env);
+
+ /* This will never happen, but if it does make sure to freak out */
+ if (lmdb_max_key_length < LDB_MDB_MAX_KEY_LENGTH) {
+ return ldb_operr(ldb);
+ }
+
+ return LDB_SUCCESS;
+}
+
+int lmdb_connect(struct ldb_context *ldb,
+ const char *url,
+ unsigned int flags,
+ const char *options[],
+ struct ldb_module **_module)
+{
+ const char *path = NULL;
+ struct lmdb_private *lmdb = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ int ret;
+ size_t env_map_size = 0;
+
+ /*
+ * We hold locks, so we must use a private event context
+ * on each returned handle
+ */
+ ldb_set_require_private_event_context(ldb);
+
+ path = lmdb_get_path(url);
+ if (path == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid mdb URL '%s'", url);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_kv = talloc_zero(ldb, struct ldb_kv_private);
+ if (!ldb_kv) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ lmdb = talloc_zero(ldb_kv, struct lmdb_private);
+ if (lmdb == NULL) {
+ TALLOC_FREE(ldb_kv);
+ return ldb_oom(ldb);
+ }
+ lmdb->ldb = ldb;
+ ldb_kv->kv_ops = &lmdb_key_value_ops;
+
+ {
+ const char *size = ldb_options_find(
+ ldb, ldb->options, "lmdb_env_size");
+ if (size != NULL) {
+ env_map_size = strtoull(size, NULL, 0);
+ }
+ }
+
+ ret = lmdb_pvt_open(lmdb, ldb, path, env_map_size, flags);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(ldb_kv);
+ return ret;
+ }
+
+ ldb_kv->lmdb_private = lmdb;
+ if (flags & LDB_FLG_RDONLY) {
+ ldb_kv->read_only = true;
+ }
+
+ /*
+ * This maximum length becomes encoded in the index values so
+ * must never change even if LMDB starts to allow longer keys.
+ * The override option is max_key_len_for_self_test, and is
+ * used for testing only.
+ */
+ ldb_kv->max_key_length = LDB_MDB_MAX_KEY_LENGTH;
+
+ return ldb_kv_init_store(
+ ldb_kv, "ldb_mdb backend", ldb, options, _module);
+}
diff --git a/lib/ldb/ldb_mdb/ldb_mdb.h b/lib/ldb/ldb_mdb/ldb_mdb.h
new file mode 100644
index 0000000..8f21493
--- /dev/null
+++ b/lib/ldb/ldb_mdb/ldb_mdb.h
@@ -0,0 +1,60 @@
+/*
+ ldb database library using mdb back end - transaction operations
+
+ Copyright (C) Jakub Hrozek 2015
+ Copyright (C) Catalyst.Net Ltd 2017
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LDB_MDB_H_
+#define _LDB_MDB_H_
+
+#include "ldb_private.h"
+#include <lmdb.h>
+
+struct lmdb_private {
+ struct ldb_context *ldb;
+ MDB_env *env;
+
+ struct lmdb_trans *txlist;
+
+ struct ldb_mdb_metadata {
+ struct ldb_message *attributes;
+ unsigned seqnum;
+ } *meta;
+ int error;
+ MDB_txn *read_txn;
+
+ pid_t pid;
+
+};
+
+struct lmdb_trans {
+ struct lmdb_trans *next;
+ struct lmdb_trans *prev;
+
+ MDB_txn *tx;
+};
+
+int ldb_mdb_err_map(int lmdb_err);
+int lmdb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[],
+ struct ldb_module **_module);
+
+#endif /* _LDB_MDB_H_ */
diff --git a/lib/ldb/ldb_mdb/ldb_mdb_init.c b/lib/ldb/ldb_mdb/ldb_mdb_init.c
new file mode 100644
index 0000000..339c3f2
--- /dev/null
+++ b/lib/ldb/ldb_mdb/ldb_mdb_init.c
@@ -0,0 +1,31 @@
+/*
+ ldb database library using mdb back end
+
+ Copyright (C) Jakub Hrozek 2014
+ Copyright (C) Catalyst.Net Ltd 2017
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb_mdb.h"
+
+int ldb_mdb_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_backend("mdb", lmdb_connect, false);
+}
diff --git a/lib/ldb/ldb_sqlite3/README b/lib/ldb/ldb_sqlite3/README
new file mode 100644
index 0000000..6cda0a7
--- /dev/null
+++ b/lib/ldb/ldb_sqlite3/README
@@ -0,0 +1,7 @@
+trees.ps contains an explanation of the Genealogical Representation of Trees
+in Databases which is being used in ldb_sqlite3. Note that we use fgID
+representation with 4 bytes per level, so we can represent 6.5E+08 subclasses
+of any object class. This should be adequate for our purposes. :-)
+
+The following document is the primary basis for the schema currently being
+used here: http://www.research.ibm.com/journal/sj/392/shi.html
diff --git a/lib/ldb/ldb_sqlite3/base160.c b/lib/ldb/ldb_sqlite3/base160.c
new file mode 100644
index 0000000..7ad39f7
--- /dev/null
+++ b/lib/ldb/ldb_sqlite3/base160.c
@@ -0,0 +1,154 @@
+/*
+ base160 code used by ldb_sqlite3
+
+ Copyright (C) 2004 Derrell Lipman
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+ * ldb_sqlite3_base160()
+ *
+ * Convert an integer value to a string containing the base 160 representation
+ * of the integer. We always convert to a string representation that is 4
+ * bytes in length, and we always null terminate.
+ *
+ * Parameters:
+ * val --
+ * The value to be converted
+ *
+ * result --
+ * Buffer in which the result is to be placed
+ *
+ * Returns:
+ * nothing
+ */
+static unsigned char base160tab[161] =
+{
+ 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , /* 0-9 */
+ 58 , 59 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , /* : ; A-H */
+ 73 , 74 , 75 , 76 , 77 , 78 , 79 , 80 , 81 , 82 , /* I-R */
+ 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 97 , 98 , /* S-Z , a-b */
+ 99 , 100, 101, 102, 103, 104, 105, 106, 107, 108, /* c-l */
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, /* m-v */
+ 119, 120, 121, 122, 160, 161, 162, 163, 164, 165, /* w-z, latin1 */
+ 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, /* latin1 */
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, /* latin1 */
+ 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, /* latin1 */
+ 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, /* latin1 */
+ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, /* latin1 */
+ 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, /* latin1 */
+ 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, /* latin1 */
+ 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, /* latin1 */
+ 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* latin1 */
+ '\0'
+};
+
+
+/*
+ * lsqlite3_base160()
+ *
+ * Convert an unsigned long integer into a base160 representation of the
+ * number.
+ *
+ * Parameters:
+ * val --
+ * value to be converted
+ *
+ * result --
+ * character array, 5 bytes long, into which the base160 representation
+ * will be placed. The result will be a four-digit representation of the
+ * number (with leading zeros prepended as necessary), and null
+ * terminated.
+ *
+ * Returns:
+ * Nothing
+ */
+void
+lsqlite3_base160(unsigned long val,
+ unsigned char result[5])
+{
+ int i;
+
+ for (i = 3; i >= 0; i--) {
+
+ result[i] = base160tab[val % 160];
+ val /= 160;
+ }
+
+ result[4] = '\0';
+}
+
+
+/*
+ * lsqlite3_base160Next()
+ *
+ * Retrieve the next-greater number in the base160 sequence for the terminal
+ * tree node (the last four digits). Only one tree level (four digits) are
+ * operated on.
+ *
+ * Parameters:
+ * base160 -- a character array containing either an empty string (in which
+ * case no operation is performed), or a string of base160 digits
+ * with a length of a multiple of four digits.
+ *
+ * Upon return, the trailing four digits (one tree level) will
+ * have been incremented by 1.
+ *
+ * Returns:
+ * base160 -- the modified array
+ */
+char *
+lsqlite3_base160Next(char base160[])
+{
+ int i;
+ int len;
+ unsigned char * pTab;
+ char * pBase160 = base160;
+
+ /*
+ * We need a minimum of four digits, and we will always get a multiple of
+ * four digits.
+ */
+ if ((len = strlen(pBase160)) >= 4)
+ {
+ pBase160 += strlen(pBase160) - 1;
+
+ /* We only carry through four digits: one level in the tree */
+ for (i = 0; i < 4; i++) {
+
+ /* What base160 value does this digit have? */
+ pTab = strchr(base160tab, *pBase160);
+
+ /* Is there a carry? */
+ if (pTab < base160tab + sizeof(base160tab) - 1) {
+
+ /* Nope. Just increment this value and we're done. */
+ *pBase160 = *++pTab;
+ break;
+ } else {
+
+ /*
+ * There's a carry. This value gets base160tab[0], we
+ * decrement the buffer pointer to get the next higher-order
+ * digit, and continue in the loop.
+ */
+ *pBase160-- = base160tab[0];
+ }
+ }
+ }
+
+ return base160;
+}
diff --git a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
new file mode 100644
index 0000000..26c7023
--- /dev/null
+++ b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
@@ -0,0 +1,1958 @@
+/*
+ ldb database library
+
+ Copyright (C) Derrell Lipman 2005
+ Copyright (C) Simo Sorce 2005-2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb sqlite3 backend
+ *
+ * Description: core files for SQLITE3 backend
+ *
+ * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend)
+ */
+
+#include "ldb_module.h"
+
+#include <sqlite3.h>
+
+struct lsqlite3_private {
+ int trans_count;
+ char **options;
+ sqlite3 *sqlite;
+};
+
+struct lsql_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ /* search stuff */
+ long long current_eid;
+ const char * const * attrs;
+ struct ldb_reply *ares;
+
+ bool callback_failed;
+ struct tevent_timer *timeout_event;
+};
+
+/*
+ * Macros used throughout
+ */
+
+#ifndef FALSE
+# define FALSE (0)
+# define TRUE (! FALSE)
+#endif
+
+#define RESULT_ATTR_TABLE "temp_result_attrs"
+
+
+/* for testing, define to nothing, (create non-temporary table) */
+#define TEMPTAB "TEMPORARY"
+
+/*
+ * Static variables
+ */
+sqlite3_stmt * stmtGetEID = NULL;
+
+static char *lsqlite3_tprintf(TALLOC_CTX *mem_ctx, const char *fmt, ...)
+{
+ char *str, *ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ str = sqlite3_vmprintf(fmt, ap);
+ va_end(ap);
+
+ if (str == NULL) return NULL;
+
+ ret = talloc_strdup(mem_ctx, str);
+ if (ret == NULL) {
+ sqlite3_free(str);
+ return NULL;
+ }
+
+ sqlite3_free(str);
+ return ret;
+}
+
+static char base160tab[161] = {
+ 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */
+ 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */
+ 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */
+ 83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 ,97 ,98 , /* S-Z , a-b */
+ 99 ,100,101,102,103,104,105,106,107,108, /* c-l */
+ 109,110,111,112,113,114,115,116,117,118, /* m-v */
+ 119,120,121,122,160,161,162,163,164,165, /* w-z, latin1 */
+ 166,167,168,169,170,171,172,173,174,175, /* latin1 */
+ 176,177,178,179,180,181,182,183,184,185, /* latin1 */
+ 186,187,188,189,190,191,192,193,194,195, /* latin1 */
+ 196,197,198,199,200,201,202,203,204,205, /* latin1 */
+ 206,207,208,209,210,211,212,213,214,215, /* latin1 */
+ 216,217,218,219,220,221,222,223,224,225, /* latin1 */
+ 226,227,228,229,230,231,232,233,234,235, /* latin1 */
+ 236,237,238,239,240,241,242,243,244,245, /* latin1 */
+ 246,247,248,249,250,251,252,253,254,255, /* latin1 */
+ '\0'
+};
+
+
+/*
+ * base160()
+ *
+ * Convert an unsigned long integer into a base160 representation of the
+ * number.
+ *
+ * Parameters:
+ * val --
+ * value to be converted
+ *
+ * result --
+ * character array, 5 bytes long, into which the base160 representation
+ * will be placed. The result will be a four-digit representation of the
+ * number (with leading zeros prepended as necessary), and null
+ * terminated.
+ *
+ * Returns:
+ * Nothing
+ */
+static void
+base160_sql(sqlite3_context * hContext,
+ int argc,
+ sqlite3_value ** argv)
+{
+ int i;
+ long long val;
+ char result[5];
+
+ val = sqlite3_value_int64(argv[0]);
+
+ for (i = 3; i >= 0; i--) {
+
+ result[i] = base160tab[val % 160];
+ val /= 160;
+ }
+
+ result[4] = '\0';
+
+ sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT);
+}
+
+
+/*
+ * base160next_sql()
+ *
+ * This function enhances sqlite by adding a "base160_next()" function which is
+ * accessible via queries.
+ *
+ * Retrieve the next-greater number in the base160 sequence for the terminal
+ * tree node (the last four digits). Only one tree level (four digits) is
+ * operated on.
+ *
+ * Input:
+ * A character string: either an empty string (in which case no operation is
+ * performed), or a string of base160 digits with a length of a multiple of
+ * four digits.
+ *
+ * Output:
+ * Upon return, the trailing four digits (one tree level) will have been
+ * incremented by 1.
+ */
+static void
+base160next_sql(sqlite3_context * hContext,
+ int argc,
+ sqlite3_value ** argv)
+{
+ int i;
+ int len;
+ char * pTab;
+ char * pBase160 = strdup((const char *)sqlite3_value_text(argv[0]));
+ char * pStart = pBase160;
+
+ /*
+ * We need a minimum of four digits, and we will always get a multiple
+ * of four digits.
+ */
+ if (pBase160 != NULL &&
+ (len = strlen(pBase160)) >= 4 &&
+ len % 4 == 0) {
+
+ if (pBase160 == NULL) {
+
+ sqlite3_result_null(hContext);
+ return;
+ }
+
+ pBase160 += strlen(pBase160) - 1;
+
+ /* We only carry through four digits: one level in the tree */
+ for (i = 0; i < 4; i++) {
+
+ /* What base160 value does this digit have? */
+ pTab = strchr(base160tab, *pBase160);
+
+ /* Is there a carry? */
+ if (pTab < base160tab + sizeof(base160tab) - 1) {
+
+ /*
+ * Nope. Just increment this value and we're
+ * done.
+ */
+ *pBase160 = *++pTab;
+ break;
+ } else {
+
+ /*
+ * There's a carry. This value gets
+ * base160tab[0], we decrement the buffer
+ * pointer to get the next higher-order digit,
+ * and continue in the loop.
+ */
+ *pBase160-- = base160tab[0];
+ }
+ }
+
+ sqlite3_result_text(hContext,
+ pStart,
+ strlen(pStart),
+ free);
+ } else {
+ sqlite3_result_value(hContext, argv[0]);
+ if (pBase160 != NULL) {
+ free(pBase160);
+ }
+ }
+}
+
+static char *parsetree_to_sql(struct ldb_module *module,
+ void *mem_ctx,
+ const struct ldb_parse_tree *t)
+{
+ struct ldb_context *ldb;
+ const struct ldb_schema_attribute *a;
+ struct ldb_val value, subval;
+ char *wild_card_string;
+ char *child, *tmp;
+ char *ret = NULL;
+ char *attr;
+ unsigned int i;
+
+ ldb = ldb_module_get_ctx(module);
+
+ switch(t->operation) {
+ case LDB_OP_AND:
+
+ tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]);
+ if (tmp == NULL) return NULL;
+
+ for (i = 1; i < t->u.list.num_elements; i++) {
+
+ child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]);
+ if (child == NULL) return NULL;
+
+ tmp = talloc_asprintf_append(tmp, " INTERSECT %s ", child);
+ if (tmp == NULL) return NULL;
+ }
+
+ ret = talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )\n", tmp);
+
+ return ret;
+
+ case LDB_OP_OR:
+
+ tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]);
+ if (tmp == NULL) return NULL;
+
+ for (i = 1; i < t->u.list.num_elements; i++) {
+
+ child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]);
+ if (child == NULL) return NULL;
+
+ tmp = talloc_asprintf_append(tmp, " UNION %s ", child);
+ if (tmp == NULL) return NULL;
+ }
+
+ return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s ) ", tmp);
+
+ case LDB_OP_NOT:
+
+ child = parsetree_to_sql(module, mem_ctx, t->u.isnot.child);
+ if (child == NULL) return NULL;
+
+ return talloc_asprintf(mem_ctx,
+ "SELECT eid FROM ldb_entry "
+ "WHERE eid NOT IN ( %s ) ", child);
+
+ case LDB_OP_EQUALITY:
+ /*
+ * For simple searches, we want to retrieve the list of EIDs that
+ * match the criteria.
+ */
+ attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
+ if (attr == NULL) return NULL;
+ a = ldb_schema_attribute_by_name(ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.equality.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ if (strcasecmp(t->u.equality.attr, "dn") == 0) {
+ /* DN query is a special ldb case */
+ const char *cdn = ldb_dn_get_casefold(
+ ldb_dn_new(mem_ctx, ldb,
+ (const char *)value.data));
+ if (cdn == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_entry "
+ "WHERE norm_dn = '%q'", cdn);
+
+ } else {
+ /* A normal query. */
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND norm_attr_value = '%q'",
+ attr,
+ value.data);
+
+ }
+
+ case LDB_OP_SUBSTRING:
+
+ wild_card_string = talloc_strdup(mem_ctx,
+ (t->u.substring.start_with_wildcard)?"*":"");
+ if (wild_card_string == NULL) return NULL;
+
+ for (i = 0; t->u.substring.chunks[i]; i++) {
+ wild_card_string = talloc_asprintf_append(wild_card_string, "%s*",
+ t->u.substring.chunks[i]->data);
+ if (wild_card_string == NULL) return NULL;
+ }
+
+ if ( ! t->u.substring.end_with_wildcard ) {
+ /* remove last wildcard */
+ wild_card_string[strlen(wild_card_string) - 1] = '\0';
+ }
+
+ attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr);
+ if (attr == NULL) return NULL;
+ a = ldb_schema_attribute_by_name(ldb, attr);
+
+ subval.data = (void *)wild_card_string;
+ subval.length = strlen(wild_card_string) + 1;
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, mem_ctx, &(subval), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND norm_attr_value GLOB '%q'",
+ attr,
+ value.data);
+
+ case LDB_OP_GREATER:
+ attr = ldb_attr_casefold(mem_ctx, t->u.comparison.attr);
+ if (attr == NULL) return NULL;
+ a = ldb_schema_attribute_by_name(ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.comparison.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ",
+ attr,
+ value.data,
+ attr);
+
+ case LDB_OP_LESS:
+ attr = ldb_attr_casefold(mem_ctx, t->u.comparison.attr);
+ if (attr == NULL) return NULL;
+ a = ldb_schema_attribute_by_name(ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.comparison.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ",
+ attr,
+ value.data,
+ attr);
+
+ case LDB_OP_PRESENT:
+ if (strcasecmp(t->u.present.attr, "dn") == 0) {
+ return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry");
+ }
+
+ attr = ldb_attr_casefold(mem_ctx, t->u.present.attr);
+ if (attr == NULL) return NULL;
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' ",
+ attr);
+
+ case LDB_OP_APPROX:
+ attr = ldb_attr_casefold(mem_ctx, t->u.comparison.attr);
+ if (attr == NULL) return NULL;
+ a = ldb_schema_attribute_by_name(ldb, attr);
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, mem_ctx, &(t->u.comparison.value), &value);
+ if (value.data == NULL) {
+ return NULL;
+ }
+
+ return lsqlite3_tprintf(mem_ctx,
+ "SELECT eid FROM ldb_attribute_values "
+ "WHERE norm_attr_name = '%q' "
+ "AND ldap_compare(norm_attr_value, '~%', 'q', '%q') ",
+ attr,
+ value.data,
+ attr);
+
+ case LDB_OP_EXTENDED:
+#warning "work out how to handle bitops"
+ return NULL;
+
+ default:
+ break;
+ };
+
+ /* should never occur */
+ abort();
+ return NULL;
+}
+
+/*
+ * query_int()
+ *
+ * This function is used for the common case of queries that return a single
+ * integer value.
+ *
+ * NOTE: If more than one value is returned by the query, all but the first
+ * one will be ignored.
+ */
+static int
+query_int(const struct lsqlite3_private * lsqlite3,
+ long long * pRet,
+ const char * pSql,
+ ...)
+{
+ int ret;
+ int bLoop;
+ char * p;
+ sqlite3_stmt * pStmt;
+ va_list args;
+
+ /* Begin access to variable argument list */
+ va_start(args, pSql);
+
+ /* Format the query */
+ if ((p = sqlite3_vmprintf(pSql, args)) == NULL) {
+ va_end(args);
+ return SQLITE_NOMEM;
+ }
+
+ /*
+ * Prepare and execute the SQL statement. Loop allows retrying on
+ * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes,
+ * requiring retrying the operation.
+ */
+ for (bLoop = TRUE; bLoop; ) {
+
+ /* Compile the SQL statement into sqlite virtual machine */
+ if ((ret = sqlite3_prepare(lsqlite3->sqlite,
+ p,
+ -1,
+ &pStmt,
+ NULL)) == SQLITE_SCHEMA) {
+ if (stmtGetEID != NULL) {
+ sqlite3_finalize(stmtGetEID);
+ stmtGetEID = NULL;
+ }
+ continue;
+ } else if (ret != SQLITE_OK) {
+ break;
+ }
+
+ /* One row expected */
+ if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) {
+ if (stmtGetEID != NULL) {
+ sqlite3_finalize(stmtGetEID);
+ stmtGetEID = NULL;
+ }
+ (void) sqlite3_finalize(pStmt);
+ continue;
+ } else if (ret != SQLITE_ROW) {
+ (void) sqlite3_finalize(pStmt);
+ break;
+ }
+
+ /* Get the value to be returned */
+ *pRet = sqlite3_column_int64(pStmt, 0);
+
+ /* Free the virtual machine */
+ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) {
+ if (stmtGetEID != NULL) {
+ sqlite3_finalize(stmtGetEID);
+ stmtGetEID = NULL;
+ }
+ continue;
+ } else if (ret != SQLITE_OK) {
+ (void) sqlite3_finalize(pStmt);
+ break;
+ }
+
+ /*
+ * Normal condition is only one time through loop. Loop is
+ * rerun in error conditions, via "continue", above.
+ */
+ bLoop = FALSE;
+ }
+
+ /* All done with variable argument list */
+ va_end(args);
+
+
+ /* Free the memory we allocated for our query string */
+ sqlite3_free(p);
+
+ return ret;
+}
+
+/*
+ * This is a bad hack to support ldap style comparisons within sqlite.
+ * val is the attribute in the row currently under test
+ * func is the desired test "<=" ">=" "~" ":"
+ * cmp is the value to compare against (eg: "test")
+ * attr is the attribute name the value of which we want to test
+ */
+
+static void lsqlite3_compare(sqlite3_context *ctx, int argc,
+ sqlite3_value **argv)
+{
+ struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx);
+ const char *val = (const char *)sqlite3_value_text(argv[0]);
+ const char *func = (const char *)sqlite3_value_text(argv[1]);
+ const char *cmp = (const char *)sqlite3_value_text(argv[2]);
+ const char *attr = (const char *)sqlite3_value_text(argv[3]);
+ const struct ldb_schema_attribute *a;
+ struct ldb_val valX;
+ struct ldb_val valY;
+ int ret;
+
+ switch (func[0]) {
+ /* greater */
+ case '>': /* >= */
+ a = ldb_schema_attribute_by_name(ldb, attr);
+ valX.data = (uint8_t *)cmp;
+ valX.length = strlen(cmp);
+ valY.data = (uint8_t *)val;
+ valY.length = strlen(val);
+ ret = a->syntax->comparison_fn(ldb, ldb, &valY, &valX);
+ if (ret >= 0)
+ sqlite3_result_int(ctx, 1);
+ else
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ /* lesser */
+ case '<': /* <= */
+ a = ldb_schema_attribute_by_name(ldb, attr);
+ valX.data = (uint8_t *)cmp;
+ valX.length = strlen(cmp);
+ valY.data = (uint8_t *)val;
+ valY.length = strlen(val);
+ ret = a->syntax->comparison_fn(ldb, ldb, &valY, &valX);
+ if (ret <= 0)
+ sqlite3_result_int(ctx, 1);
+ else
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ /* approx */
+ case '~':
+ /* TODO */
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ /* bitops */
+ case ':':
+ /* TODO */
+ sqlite3_result_int(ctx, 0);
+ return;
+
+ default:
+ break;
+ }
+
+ sqlite3_result_error(ctx, "Value must start with a special operation char (<>~:)!", -1);
+ return;
+}
+
+
+/* rename a record */
+static int lsqlite3_safe_rollback(sqlite3 *sqlite)
+{
+ char *errmsg;
+ int ret;
+
+ /* execute */
+ ret = sqlite3_exec(sqlite, "ROLLBACK;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_safe_rollback: Error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+/* return an eid as result */
+static int lsqlite3_eid_callback(void *result, int col_num, char **cols, char **names)
+{
+ long long *eid = (long long *)result;
+
+ if (col_num != 1) return SQLITE_ABORT;
+ if (strcasecmp(names[0], "eid") != 0) return SQLITE_ABORT;
+
+ *eid = atoll(cols[0]);
+ return SQLITE_OK;
+}
+
+/*
+ * add a single set of ldap message values to a ldb_message
+ */
+static int lsqlite3_search_callback(void *result, int col_num, char **cols, char **names)
+{
+ struct ldb_context *ldb;
+ struct lsql_context *ac;
+ struct ldb_message *msg;
+ long long eid;
+ unsigned int i;
+ int ret;
+
+ ac = talloc_get_type(result, struct lsql_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ /* eid, dn, attr_name, attr_value */
+ if (col_num != 4) return SQLITE_ABORT;
+
+ eid = atoll(cols[0]);
+
+ if (ac->ares) {
+ msg = ac->ares->message;
+ }
+
+ if (eid != ac->current_eid) { /* here begin a new entry */
+
+ /* call the async callback for the last entry
+ * except the first time */
+ if (ac->current_eid != 0) {
+ ret = ldb_msg_normalize(ldb, ac->req, msg, &msg);
+ if (ret != LDB_SUCCESS) {
+ return SQLITE_ABORT;
+ }
+
+ ret = ldb_module_send_entry(ac->req, msg, NULL);
+ if (ret != LDB_SUCCESS) {
+ ac->callback_failed = true;
+ /* free msg object */
+ TALLOC_FREE(msg);
+ return SQLITE_ABORT;
+ }
+
+ /* free msg object */
+ TALLOC_FREE(msg);
+ }
+
+ /* start over */
+ ac->ares = talloc_zero(ac, struct ldb_reply);
+ if (!ac->ares) return SQLITE_ABORT;
+
+ msg = ldb_msg_new(ac->ares);
+ if (!msg) return SQLITE_ABORT;
+
+ ac->ares->type = LDB_REPLY_ENTRY;
+ ac->current_eid = eid;
+ }
+
+ if (msg->dn == NULL) {
+ msg->dn = ldb_dn_new(msg, ldb, cols[1]);
+ if (msg->dn == NULL)
+ return SQLITE_ABORT;
+ }
+
+ if (ac->attrs) {
+ int found = 0;
+ for (i = 0; ac->attrs[i]; i++) {
+ if (strcasecmp(cols[2], ac->attrs[i]) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) goto done;
+ }
+
+ if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) {
+ return SQLITE_ABORT;
+ }
+
+done:
+ ac->ares->message = msg;
+ return SQLITE_OK;
+}
+
+
+/*
+ * lsqlite3_get_eid()
+ * lsqlite3_get_eid_ndn()
+ *
+ * These functions are used for the very common case of retrieving an EID value
+ * given a (normalized) DN.
+ */
+
+static long long lsqlite3_get_eid_ndn(sqlite3 *sqlite, void *mem_ctx, const char *norm_dn)
+{
+ char *errmsg;
+ char *query;
+ long long eid = -1;
+ long long ret;
+
+ /* get object eid */
+ query = lsqlite3_tprintf(mem_ctx, "SELECT eid "
+ "FROM ldb_entry "
+ "WHERE norm_dn = '%q';", norm_dn);
+ if (query == NULL) return -1;
+
+ ret = sqlite3_exec(sqlite, query, lsqlite3_eid_callback, &eid, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_get_eid: Fatal Error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+
+ return eid;
+}
+
+static long long lsqlite3_get_eid(struct lsqlite3_private *lsqlite3,
+ struct ldb_dn *dn)
+{
+ TALLOC_CTX *local_ctx;
+ long long eid = -1;
+ char *cdn;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(dn)) {
+ return -1;
+ }
+
+ /* create a local ctx */
+ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_get_eid local context");
+ if (local_ctx == NULL) {
+ return -1;
+ }
+
+ cdn = ldb_dn_alloc_casefold(local_ctx, dn);
+ if (!cdn) goto done;
+
+ eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn);
+
+done:
+ talloc_free(local_ctx);
+ return eid;
+}
+
+/*
+ * Interface functions referenced by lsqlite3_ops
+ */
+
+/* search for matching records, by tree */
+int lsql_search(struct lsql_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ struct lsqlite3_private *lsqlite3;
+ struct ldb_context *ldb;
+ char *norm_basedn;
+ char *sqlfilter;
+ char *errmsg;
+ char *query = NULL;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ if ((( ! ldb_dn_is_valid(req->op.search.base)) ||
+ ldb_dn_is_null(req->op.search.base)) &&
+ (req->op.search.scope == LDB_SCOPE_BASE ||
+ req->op.search.scope == LDB_SCOPE_ONELEVEL)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.base) {
+ norm_basedn = ldb_dn_alloc_casefold(ctx, req->op.search.base);
+ if (norm_basedn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ } else norm_basedn = talloc_strdup(ctx, "");
+
+ /* Convert filter into a series of SQL conditions (constraints) */
+ sqlfilter = parsetree_to_sql(module, ctx, req->op.search.tree);
+
+ switch(req->op.search.scope) {
+ case LDB_SCOPE_DEFAULT:
+ case LDB_SCOPE_SUBTREE:
+ if (*norm_basedn != '\0') {
+ query = lsqlite3_tprintf(ctx,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE (ldb_entry.norm_dn GLOB('*,%q')\n"
+ " OR ldb_entry.norm_dn = '%q')\n"
+ " AND ldb_entry.eid IN\n"
+ " (%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ norm_basedn,
+ norm_basedn,
+ sqlfilter);
+ } else {
+ query = lsqlite3_tprintf(ctx,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE ldb_entry.eid IN\n"
+ " (%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ sqlfilter);
+ }
+
+ break;
+
+ case LDB_SCOPE_BASE:
+ query = lsqlite3_tprintf(ctx,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE ldb_entry.norm_dn = '%q'\n"
+ " AND ldb_entry.eid IN\n"
+ " (%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ norm_basedn,
+ sqlfilter);
+ break;
+
+ case LDB_SCOPE_ONELEVEL:
+ query = lsqlite3_tprintf(ctx,
+ "SELECT entry.eid,\n"
+ " entry.dn,\n"
+ " av.attr_name,\n"
+ " av.attr_value\n"
+ " FROM ldb_entry AS entry\n"
+
+ " LEFT OUTER JOIN ldb_attribute_values AS av\n"
+ " ON av.eid = entry.eid\n"
+
+ " WHERE entry.eid IN\n"
+ " (SELECT DISTINCT ldb_entry.eid\n"
+ " FROM ldb_entry\n"
+ " WHERE norm_dn GLOB('*,%q')\n"
+ " AND NOT norm_dn GLOB('*,*,%q')\n"
+ " AND ldb_entry.eid IN\n(%s)\n"
+ " )\n"
+
+ " ORDER BY entry.eid ASC;",
+ norm_basedn,
+ norm_basedn,
+ sqlfilter);
+ break;
+ }
+
+ if (query == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* * /
+ printf ("%s\n", query);
+ / * */
+
+ ctx->current_eid = 0;
+ ctx->attrs = req->op.search.attrs;
+ ctx->ares = NULL;
+
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
+ ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, ctx, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* complete the last message if any */
+ if (ctx->ares) {
+ ret = ldb_msg_normalize(ldb, ctx->ares,
+ ctx->ares->message,
+ &ctx->ares->message);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_module_send_entry(req, ctx->ares->message, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+
+ return LDB_SUCCESS;
+}
+
+/* add a record */
+static int lsql_add(struct lsql_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ struct lsqlite3_private *lsqlite3;
+ struct ldb_context *ldb;
+ struct ldb_message *msg = req->op.add.message;
+ long long eid;
+ char *dn, *ndn;
+ char *errmsg;
+ char *query;
+ unsigned int i;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ /* See if this is an ltdb special */
+ if (ldb_dn_is_special(msg->dn)) {
+/*
+ struct ldb_dn *c;
+ c = ldb_dn_new(local_ctx, ldb, "@INDEXLIST");
+ if (ldb_dn_compare(ldb, msg->dn, c) == 0) {
+#warning "should we handle indexes somehow ?"
+ ret = LDB_ERR_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+*/
+ /* Others return an error */
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ /* create linearized and normalized dns */
+ dn = ldb_dn_alloc_linearized(ctx, msg->dn);
+ ndn = ldb_dn_alloc_casefold(ctx, msg->dn);
+ if (dn == NULL || ndn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ query = lsqlite3_tprintf(ctx,
+ /* Add new entry */
+ "INSERT OR ABORT INTO ldb_entry "
+ "('dn', 'norm_dn') "
+ "VALUES ('%q', '%q');",
+ dn, ndn);
+ if (query == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, ctx, ndn);
+ if (eid == -1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+ const struct ldb_schema_attribute *a;
+ char *attr;
+ unsigned int j;
+
+ /* Get a case-folded copy of the attribute name */
+ attr = ldb_attr_casefold(ctx, el->name);
+ if (attr == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, el->name);
+
+ if (el->num_value == 0) {
+ ldb_asprintf_errstring(ldb, "attribute %s on %s specified, but with 0 values (illegal)",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /* For each value of the specified attribute name... */
+ for (j = 0; j < el->num_values; j++) {
+ struct ldb_val value;
+ char *insert;
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, ctx, &(el->values[j]), &value);
+ if (value.data == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ insert = lsqlite3_tprintf(ctx,
+ "INSERT OR ROLLBACK INTO ldb_attribute_values "
+ "('eid', 'attr_name', 'norm_attr_name',"
+ " 'attr_value', 'norm_attr_value') "
+ "VALUES ('%lld', '%q', '%q', '%q', '%q');",
+ eid, el->name, attr,
+ el->values[j].data, value.data);
+ if (insert == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* modify a record */
+static int lsql_modify(struct lsql_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ struct lsqlite3_private *lsqlite3;
+ struct ldb_context *ldb;
+ struct ldb_message *msg = req->op.mod.message;
+ long long eid;
+ char *errmsg;
+ unsigned int i;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ /* See if this is an ltdb special */
+ if (ldb_dn_is_special(msg->dn)) {
+ /* Others return an error */
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ eid = lsqlite3_get_eid(lsqlite3, msg->dn);
+ if (eid == -1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+ const struct ldb_schema_attribute *a;
+ unsigned int flags = el->flags & LDB_FLAG_MOD_MASK;
+ char *attr;
+ char *mod;
+ unsigned int j;
+
+ /* Get a case-folded copy of the attribute name */
+ attr = ldb_attr_casefold(ctx, el->name);
+ if (attr == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, el->name);
+
+ switch (flags) {
+
+ case LDB_FLAG_MOD_REPLACE:
+ struct ldb_val *duplicate = NULL;
+
+ ret = ldb_msg_find_duplicate_val(ldb, el, el,
+ &duplicate, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (duplicate != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "attribute '%s': value '%.*s' "
+ "on '%s' provided more than "
+ "once in REPLACE",
+ el->name,
+ (int)duplicate->length,
+ duplicate->data,
+ ldb_dn_get_linearized(msg2->dn));
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+
+ /* remove all attributes before adding the replacements */
+ mod = lsqlite3_tprintf(ctx,
+ "DELETE FROM ldb_attribute_values "
+ "WHERE eid = '%lld' "
+ "AND norm_attr_name = '%q';",
+ eid, attr);
+ if (mod == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* MISSING break is INTENTIONAL */
+
+ case LDB_FLAG_MOD_ADD:
+
+ if (el->num_values == 0) {
+ ldb_asprintf_errstring(ldb, "attribute %s on %s specified, but with 0 values (illegal)",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /* For each value of the specified attribute name... */
+ for (j = 0; j < el->num_values; j++) {
+ struct ldb_val value;
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, ctx, &(el->values[j]), &value);
+ if (value.data == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ mod = lsqlite3_tprintf(ctx,
+ "INSERT OR ROLLBACK INTO ldb_attribute_values "
+ "('eid', 'attr_name', 'norm_attr_name',"
+ " 'attr_value', 'norm_attr_value') "
+ "VALUES ('%lld', '%q', '%q', '%q', '%q');",
+ eid, el->name, attr,
+ el->values[j].data, value.data);
+
+ if (mod == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ break;
+
+ case LDB_FLAG_MOD_DELETE:
+#warning "We should throw an error if the attribute we are trying to delete does not exist!"
+ if (el->num_values == 0) {
+ mod = lsqlite3_tprintf(ctx,
+ "DELETE FROM ldb_attribute_values "
+ "WHERE eid = '%lld' "
+ "AND norm_attr_name = '%q';",
+ eid, attr);
+ if (mod == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ /* For each value of the specified attribute name... */
+ for (j = 0; j < el->num_values; j++) {
+ struct ldb_val value;
+
+ /* Get a canonicalised copy of the data */
+ a->syntax->canonicalise_fn(ldb, ctx, &(el->values[j]), &value);
+ if (value.data == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ mod = lsqlite3_tprintf(ctx,
+ "DELETE FROM ldb_attribute_values "
+ "WHERE eid = '%lld' "
+ "AND norm_attr_name = '%q' "
+ "AND norm_attr_value = '%q';",
+ eid, attr, value.data);
+
+ if (mod == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* delete a record */
+static int lsql_delete(struct lsql_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ struct lsqlite3_private *lsqlite3;
+ struct ldb_context *ldb;
+ long long eid;
+ char *errmsg;
+ char *query;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ eid = lsqlite3_get_eid(lsqlite3, req->op.del.dn);
+ if (eid == -1) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ query = lsqlite3_tprintf(ctx,
+ /* Delete entry */
+ "DELETE FROM ldb_entry WHERE eid = %lld; "
+ /* Delete attributes */
+ "DELETE FROM ldb_attribute_values WHERE eid = %lld; ",
+ eid, eid);
+ if (query == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* rename a record */
+static int lsql_rename(struct lsql_context *ctx)
+{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
+ struct lsqlite3_private *lsqlite3;
+ struct ldb_context *ldb;
+ char *new_dn, *new_cdn, *old_cdn;
+ char *errmsg;
+ char *query;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ /* create linearized and normalized dns */
+ old_cdn = ldb_dn_alloc_casefold(ctx, req->op.rename.olddn);
+ new_cdn = ldb_dn_alloc_casefold(ctx, req->op.rename.newdn);
+ new_dn = ldb_dn_alloc_linearized(ctx, req->op.rename.newdn);
+ if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* build the SQL query */
+ query = lsqlite3_tprintf(ctx,
+ "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' "
+ "WHERE norm_dn = '%q';",
+ new_dn, new_cdn, old_cdn);
+ if (query == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* execute */
+ ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ ldb_set_errstring(ldb, errmsg);
+ free(errmsg);
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int lsql_start_trans(struct ldb_module * module)
+{
+ int ret;
+ char *errmsg;
+ struct lsqlite3_private *lsqlite3;
+
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ if (lsqlite3->trans_count == 0) {
+ ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_start_trans: error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+ };
+
+ lsqlite3->trans_count++;
+
+ return 0;
+}
+
+static int lsql_end_trans(struct ldb_module *module)
+{
+ int ret;
+ char *errmsg;
+ struct lsqlite3_private *lsqlite3;
+
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ if (lsqlite3->trans_count > 0) {
+ lsqlite3->trans_count--;
+ } else return -1;
+
+ if (lsqlite3->trans_count == 0) {
+ ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3_end_trans: error: %s\n", errmsg);
+ free(errmsg);
+ }
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int lsql_del_trans(struct ldb_module *module)
+{
+ struct lsqlite3_private *lsqlite3;
+
+ lsqlite3 = talloc_get_type(ldb_module_get_private(module),
+ struct lsqlite3_private);
+
+ if (lsqlite3->trans_count > 0) {
+ lsqlite3->trans_count--;
+ } else return -1;
+
+ if (lsqlite3->trans_count == 0) {
+ return lsqlite3_safe_rollback(lsqlite3->sqlite);
+ }
+
+ return -1;
+}
+
+static int destructor(struct lsqlite3_private *lsqlite3)
+{
+ if (lsqlite3->sqlite) {
+ sqlite3_close(lsqlite3->sqlite);
+ }
+ return 0;
+}
+
+static void lsql_request_done(struct lsql_context *ctx, int error)
+{
+ struct ldb_context *ldb;
+ struct ldb_request *req;
+ struct ldb_reply *ares;
+
+ ldb = ldb_module_get_ctx(ctx->module);
+ req = ctx->req;
+
+ /* if we already returned an error just return */
+ if (ldb_request_get_status(req) != LDB_SUCCESS) {
+ return;
+ }
+
+ ares = talloc_zero(req, struct ldb_reply);
+ if (!ares) {
+ ldb_oom(ldb);
+ req->callback(req, NULL);
+ return;
+ }
+ ares->type = LDB_REPLY_DONE;
+ ares->error = error;
+
+ req->callback(req, ares);
+}
+
+static void lsql_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *private_data)
+{
+ struct lsql_context *ctx;
+ ctx = talloc_get_type(private_data, struct lsql_context);
+
+ lsql_request_done(ctx, LDB_ERR_TIME_LIMIT_EXCEEDED);
+}
+
+static void lsql_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *private_data)
+{
+ struct lsql_context *ctx;
+ int ret;
+
+ ctx = talloc_get_type(private_data, struct lsql_context);
+
+ switch (ctx->req->operation) {
+ case LDB_SEARCH:
+ ret = lsql_search(ctx);
+ break;
+ case LDB_ADD:
+ ret = lsql_add(ctx);
+ break;
+ case LDB_MODIFY:
+ ret = lsql_modify(ctx);
+ break;
+ case LDB_DELETE:
+ ret = lsql_delete(ctx);
+ break;
+ case LDB_RENAME:
+ ret = lsql_rename(ctx);
+ break;
+/* TODO:
+ case LDB_EXTENDED:
+ ret = lsql_extended(ctx);
+ break;
+ */
+ default:
+ /* no other op supported */
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ if (!ctx->callback_failed) {
+ /* Once we are done, we do not need timeout events */
+ talloc_free(ctx->timeout_event);
+ lsql_request_done(ctx, ret);
+ }
+}
+
+static int lsql_handle_request(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct tevent_context *ev;
+ struct lsql_context *ac;
+ struct tevent_timer *te;
+ struct timeval tv;
+
+ if (ldb_check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
+ if (req->starttime == 0 || req->timeout == 0) {
+ ldb_set_errstring(ldb, "Invalid timeout settings");
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+
+ ldb = ldb_module_get_ctx(module);
+ ev = ldb_get_event_context(ldb);
+
+ ac = talloc_zero(req, struct lsql_context);
+ if (ac == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ te = tevent_add_timer(ev, ac, tv, lsql_callback, ac);
+ if (NULL == te) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->timeout > 0) {
+ tv.tv_sec = req->starttime + req->timeout;
+ tv.tv_usec = 0;
+ ac->timeout_event = tevent_add_timer(ev, ac, tv, lsql_timeout, ac);
+ if (NULL == ac->timeout_event) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+/*
+ * Table of operations for the sqlite3 backend
+ */
+static const struct ldb_module_ops lsqlite3_ops = {
+ .name = "sqlite",
+ .search = lsql_handle_request,
+ .add = lsql_handle_request,
+ .modify = lsql_handle_request,
+ .del = lsql_handle_request,
+ .rename = lsql_handle_request,
+ .extended = lsql_handle_request,
+ .start_transaction = lsql_start_trans,
+ .end_transaction = lsql_end_trans,
+ .del_transaction = lsql_del_trans,
+};
+
+/*
+ * Static functions
+ */
+
+static int initialize(struct lsqlite3_private *lsqlite3,
+ struct ldb_context *ldb, const char *url,
+ unsigned int flags)
+{
+ TALLOC_CTX *local_ctx;
+ long long queryInt;
+ int rollback = 0;
+ char *errmsg;
+ char *schema;
+ int ret;
+
+ /* create a local ctx */
+ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context");
+ if (local_ctx == NULL) {
+ return -1;
+ }
+
+ schema = lsqlite3_tprintf(local_ctx,
+
+
+ "CREATE TABLE ldb_info AS "
+ " SELECT 'LDB' AS database_type,"
+ " '1.0' AS version;"
+
+ /*
+ * The entry table holds the information about an entry.
+ * This table is used to obtain the EID of the entry and to
+ * support scope=one and scope=base. The parent and child
+ * table is included in the entry table since all the other
+ * attributes are dependent on EID.
+ */
+ "CREATE TABLE ldb_entry "
+ "("
+ " eid INTEGER PRIMARY KEY AUTOINCREMENT,"
+ " dn TEXT UNIQUE NOT NULL,"
+ " norm_dn TEXT UNIQUE NOT NULL"
+ ");"
+
+
+ "CREATE TABLE ldb_object_classes"
+ "("
+ " class_name TEXT PRIMARY KEY,"
+ " parent_class_name TEXT,"
+ " tree_key TEXT UNIQUE,"
+ " max_child_num INTEGER DEFAULT 0"
+ ");"
+
+ /*
+ * We keep a full listing of attribute/value pairs here
+ */
+ "CREATE TABLE ldb_attribute_values"
+ "("
+ " eid INTEGER REFERENCES ldb_entry,"
+ " attr_name TEXT,"
+ " norm_attr_name TEXT,"
+ " attr_value TEXT,"
+ " norm_attr_value TEXT "
+ ");"
+
+
+ /*
+ * Indexes
+ */
+ "CREATE INDEX ldb_attribute_values_eid_idx "
+ " ON ldb_attribute_values (eid);"
+
+ "CREATE INDEX ldb_attribute_values_name_value_idx "
+ " ON ldb_attribute_values (attr_name, norm_attr_value);"
+
+
+
+ /*
+ * Triggers
+ */
+
+ "CREATE TRIGGER ldb_object_classes_insert_tr"
+ " AFTER INSERT"
+ " ON ldb_object_classes"
+ " FOR EACH ROW"
+ " BEGIN"
+ " UPDATE ldb_object_classes"
+ " SET tree_key = COALESCE(tree_key, "
+ " ("
+ " SELECT tree_key || "
+ " (SELECT base160(max_child_num + 1)"
+ " FROM ldb_object_classes"
+ " WHERE class_name = "
+ " new.parent_class_name)"
+ " FROM ldb_object_classes "
+ " WHERE class_name = new.parent_class_name "
+ " ));"
+ " UPDATE ldb_object_classes "
+ " SET max_child_num = max_child_num + 1"
+ " WHERE class_name = new.parent_class_name;"
+ " END;"
+
+ /*
+ * Table initialization
+ */
+
+ "INSERT INTO ldb_object_classes "
+ " (class_name, tree_key) "
+ " VALUES "
+ " ('TOP', '0001');");
+
+ /* Skip protocol indicator of url */
+ if (strncmp(url, "sqlite3://", 10) != 0) {
+ return SQLITE_MISUSE;
+ }
+
+ /* Update pointer to just after the protocol indicator */
+ url += 10;
+
+ /* Try to open the (possibly empty/non-existent) database */
+ if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* In case this is a new database, enable auto_vacuum */
+ ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA auto_vacuum = 1;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3 initializaion error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+
+ if (flags & LDB_FLG_NOSYNC) {
+ /* DANGEROUS */
+ ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3 initializaion error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+ }
+
+ /* */
+
+ /* Establish a busy timeout of 30 seconds */
+ if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite,
+ 30000)) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Create a function, callable from sql, to increment a tree_key */
+ if ((ret =
+ sqlite3_create_function(lsqlite3->sqlite,/* handle */
+ "base160_next", /* function name */
+ 1, /* number of args */
+ SQLITE_ANY, /* preferred text type */
+ NULL, /* user data */
+ base160next_sql, /* called func */
+ NULL, /* step func */
+ NULL /* final func */
+ )) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Create a function, callable from sql, to convert int to base160 */
+ if ((ret =
+ sqlite3_create_function(lsqlite3->sqlite,/* handle */
+ "base160", /* function name */
+ 1, /* number of args */
+ SQLITE_ANY, /* preferred text type */
+ NULL, /* user data */
+ base160_sql, /* called func */
+ NULL, /* step func */
+ NULL /* final func */
+ )) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Create a function, callable from sql, to perform various comparisons */
+ if ((ret =
+ sqlite3_create_function(lsqlite3->sqlite, /* handle */
+ "ldap_compare", /* function name */
+ 4, /* number of args */
+ SQLITE_ANY, /* preferred text type */
+ ldb , /* user data */
+ lsqlite3_compare, /* called func */
+ NULL, /* step func */
+ NULL /* final func */
+ )) != SQLITE_OK) {
+ return ret;
+ }
+
+ /* Begin a transaction */
+ ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3: initialization error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+ rollback = 1;
+
+ /* Determine if this is a new database. No tables means it is. */
+ if (query_int(lsqlite3,
+ &queryInt,
+ "SELECT COUNT(*)\n"
+ " FROM sqlite_master\n"
+ " WHERE type = 'table';") != 0) {
+ goto failed;
+ }
+
+ if (queryInt == 0) {
+ /*
+ * Create the database schema
+ */
+ ret = sqlite3_exec(lsqlite3->sqlite, schema, NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3 initializaion error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+ } else {
+ /*
+ * Ensure that the database we opened is one of ours
+ */
+ if (query_int(lsqlite3,
+ &queryInt,
+ "SELECT "
+ " (SELECT COUNT(*) = 2"
+ " FROM sqlite_master "
+ " WHERE type = 'table' "
+ " AND name IN "
+ " ("
+ " 'ldb_entry', "
+ " 'ldb_object_classes' "
+ " ) "
+ " ) "
+ " AND "
+ " (SELECT 1 "
+ " FROM ldb_info "
+ " WHERE database_type = 'LDB' "
+ " AND version = '1.0'"
+ " );") != 0 ||
+ queryInt != 1) {
+
+ /* It's not one that we created. See ya! */
+ goto failed;
+ }
+ }
+
+ /* Commit the transaction */
+ ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg);
+ if (ret != SQLITE_OK) {
+ if (errmsg) {
+ printf("lsqlite3: iniialization error: %s\n", errmsg);
+ free(errmsg);
+ }
+ goto failed;
+ }
+
+ return SQLITE_OK;
+
+failed:
+ if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite);
+ sqlite3_close(lsqlite3->sqlite);
+ return -1;
+}
+
+/*
+ * connect to the database
+ */
+static int lsqlite3_connect(struct ldb_context *ldb,
+ const char *url,
+ unsigned int flags,
+ const char *options[],
+ struct ldb_module **_module)
+{
+ struct ldb_module *module;
+ struct lsqlite3_private *lsqlite3;
+ unsigned int i;
+ int ret;
+
+ module = ldb_module_new(ldb, ldb, "ldb_sqlite3 backend", &lsqlite3_ops);
+ if (!module) return LDB_ERR_OPERATIONS_ERROR;
+
+ lsqlite3 = talloc(module, struct lsqlite3_private);
+ if (!lsqlite3) {
+ goto failed;
+ }
+
+ lsqlite3->sqlite = NULL;
+ lsqlite3->options = NULL;
+ lsqlite3->trans_count = 0;
+
+ ret = initialize(lsqlite3, ldb, url, flags);
+ if (ret != SQLITE_OK) {
+ goto failed;
+ }
+
+ talloc_set_destructor(lsqlite3, destructor);
+
+ ldb_module_set_private(module, lsqlite3);
+
+ if (options) {
+ /*
+ * take a copy of the options array, so we don't have to rely
+ * on the caller keeping it around (it might be dynamic)
+ */
+ for (i=0;options[i];i++) ;
+
+ lsqlite3->options = talloc_array(lsqlite3, char *, i+1);
+ if (!lsqlite3->options) {
+ goto failed;
+ }
+
+ for (i=0;options[i];i++) {
+
+ lsqlite3->options[i+1] = NULL;
+ lsqlite3->options[i] =
+ talloc_strdup(lsqlite3->options, options[i]);
+ if (!lsqlite3->options[i]) {
+ goto failed;
+ }
+ }
+ }
+
+ *_module = module;
+ return LDB_SUCCESS;
+
+failed:
+ if (lsqlite3 && lsqlite3->sqlite != NULL) {
+ (void) sqlite3_close(lsqlite3->sqlite);
+ }
+ talloc_free(lsqlite3);
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+int ldb_sqlite3_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_backend("sqlite3", lsqlite3_connect, false);
+}
diff --git a/lib/ldb/ldb_sqlite3/schema b/lib/ldb/ldb_sqlite3/schema
new file mode 100644
index 0000000..ab7c5cc
--- /dev/null
+++ b/lib/ldb/ldb_sqlite3/schema
@@ -0,0 +1,328 @@
+ -- ------------------------------------------------------
+
+ PRAGMA auto_vacuum=1;
+
+ -- ------------------------------------------------------
+
+ BEGIN EXCLUSIVE;
+
+ -- ------------------------------------------------------
+
+ CREATE TABLE ldb_info AS
+ SELECT 'LDB' AS database_type,
+ '1.0' AS version;
+
+ /*
+ * Get the next USN value with:
+ * BEGIN EXCLUSIVE;
+ * UPDATE usn SET value = value + 1;
+ * SELECT value FROM usn;
+ * COMMIT;
+ */
+ CREATE TABLE usn
+ (
+ value INTEGER
+ );
+
+ CREATE TABLE ldb_object
+ (
+ /* tree_key is auto-generated by the insert trigger */
+ tree_key TEXT PRIMARY KEY,
+
+ parent_tree_key TEXT,
+ dn TEXT,
+
+ attr_name TEXT REFERENCES ldb_attributes,
+ attr_value TEXT,
+
+ /*
+ * object_type can take on these values (to date):
+ * 1: object is a node of a DN
+ * 2: object is an attribute/value pair of its parent DN
+ */
+ object_type INTEGER,
+
+ /*
+ * if object_type is 1, the node can have children.
+ * this tracks the maximum previously assigned child
+ * number so we can generate a new unique tree key for
+ * a new child object. note that this is always incremented,
+ * so if children are deleted, this will not represent
+ * the _number_ of children.
+ */
+ max_child_num INTEGER,
+
+ /*
+ * Automatically maintained meta-data (a gift for metze)
+ */
+ object_guid TEXT UNIQUE,
+ timestamp INTEGER, -- originating_time
+ invoke_id TEXT, -- GUID: originating_invocation_id
+ usn INTEGER, -- hyper: originating_usn
+
+ /* do not allow duplicate name/value pairs */
+ UNIQUE (parent_tree_key, attr_name, attr_value, object_type)
+ );
+
+ CREATE TABLE ldb_attributes
+ (
+ attr_name TEXT PRIMARY KEY,
+ parent_tree_key TEXT,
+
+ objectclass_p BOOLEAN DEFAULT 0,
+
+ case_insensitive_p BOOLEAN DEFAULT 0,
+ wildcard_p BOOLEAN DEFAULT 0,
+ hidden_p BOOLEAN DEFAULT 0,
+ integer_p BOOLEAN DEFAULT 0,
+
+ /* tree_key is auto-generated by the insert trigger */
+ tree_key TEXT, -- null if not a object/sub class
+ -- level 1 if an objectclass
+ -- level 1-n if a subclass
+ max_child_num INTEGER
+ );
+
+ -- ------------------------------------------------------
+
+ CREATE INDEX ldb_object_dn_idx
+ ON ldb_object (dn);
+
+ CREATE INDEX ldb_attributes_tree_key_ids
+ ON ldb_attributes (tree_key);
+
+ -- ------------------------------------------------------
+
+ /* Gifts for metze. Automatically updated meta-data */
+ CREATE TRIGGER ldb_object_insert_tr
+ AFTER INSERT
+ ON ldb_object
+ FOR EACH ROW
+ BEGIN
+ UPDATE ldb_object
+ SET max_child_num = max_child_num + 1
+ WHERE tree_key = new.parent_tree_key;
+ UPDATE usn SET value = value + 1;
+ UPDATE ldb_object
+ SET tree_key =
+ (SELECT
+ new.tree_key ||
+ base160(SELECT max_child_num
+ FROM ldb_object
+ WHERE tree_key =
+ new.parent_tree_key));
+ max_child_num = 0,
+ object_guid = random_guid(),
+ timestamp = strftime('%s', 'now'),
+ usn = (SELECT value FROM usn);
+ WHERE tree_key = new.tree_key;
+ END;
+
+ CREATE TRIGGER ldb_object_update_tr
+ AFTER UPDATE
+ ON ldb_object
+ FOR EACH ROW
+ BEGIN
+ UPDATE usn SET value = value + 1;
+ UPDATE ldb_object
+ SET timestamp = strftime('%s', 'now'),
+ usn = (SELECT value FROM usn);
+ WHERE tree_key = new.tree_key;
+ END;
+
+ CREATE TRIGGER ldb_attributes_insert_tr
+ AFTER INSERT
+ ON ldb_attributes
+ FOR EACH ROW
+ BEGIN
+ UPDATE ldb_attributes
+ SET max_child_num = max_child_num + 1
+ WHERE tree_key = new.parent_tree_key;
+ UPDATE ldb_attributes
+ SET tree_key =
+ (SELECT
+ new.tree_key ||
+ base160(SELECT max_child_num
+ FROM ldb_attributes
+ WHERE tree_key =
+ new.parent_tree_key));
+ max_child_num = 0
+ WHERE tree_key = new.tree_key;
+ END;
+
+
+ -- ------------------------------------------------------
+
+ /* Initialize usn */
+ INSERT INTO usn (value) VALUES (0);
+
+ /* Create root object */
+ INSERT INTO ldb_object
+ (tree_key, parent_tree_key,
+ dn,
+ object_type, max_child_num)
+ VALUES ('', NULL,
+ '',
+ 1, 0);
+
+ /* We need an implicit "top" level object class */
+ INSERT INTO ldb_attributes (attr_name,
+ parent_tree_key)
+ SELECT 'top', '';
+
+ -- ------------------------------------------------------
+
+ COMMIT;
+
+ -- ------------------------------------------------------
+
+/*
+ * dn: o=University of Michigan,c=US
+ * objectclass: organization
+ * objectclass: domainRelatedObject
+ */
+-- newDN
+BEGIN;
+
+INSERT OR IGNORE INTO ldb_object
+ (parent_tree_key
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('',
+ 'c=US',
+ 'c', 'US', 1, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key,
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('0001',
+ 'o=University of Michigan,c=US',
+ 'o', 'University of Michigan', 1, 0);
+
+-- newObjectClass
+INSERT OR IGNORE INTO ldb_attributes
+ (attr_name, parent_tree_key, objectclass_p)
+ VALUES
+ ('objectclass', '', 1);
+
+INSERT INTO ldb_object
+ (parent_tree_key,
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001',
+ NULL,
+ 'objectclass', 'organization', 2, 0);
+
+INSERT OR IGNORE INTO ldb_attributes
+ (attr_name, parent_tree_key, objectclass_p)
+ VALUES
+ ('objectclass', '', 1);
+
+INSERT INTO ldb_object
+ (parent_tree_key,
+ dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001',
+ NULL,
+ 'objectclass', 'domainRelatedObject', 2, 0);
+
+COMMIT;
+
+
+/*
+ * dn: o=University of Michigan,c=US
+ * l: Ann Arbor, Michigan
+ * st: Michigan
+ * o: University of Michigan
+ * o: UMICH
+ * seeAlso:
+ * telephonenumber: +1 313 764-1817
+ */
+-- addAttrValuePair
+BEGIN;
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'l', 'Ann Arbor, Michigan', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'st', 'Michigan', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'o', 'University of Michigan', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'o', 'UMICH', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'seeAlso', '', 2, 0);
+
+INSERT INTO ldb_object
+ (parent_tree_key, dn,
+ attr_name, attr_value, object_type, max_child_num)
+ VALUES ('00010001', NULL,
+ 'telephonenumber', '+1 313 764-1817', 2, 0);
+
+COMMIT;
+
+-- ----------------------------------------------------------------------
+
+/*
+ * dn: @ATTRIBUTES
+ * uid: CASE_INSENSITIVE WILDCARD
+ * cn: CASE_INSENSITIVE
+ * ou: CASE_INSENSITIVE
+ * dn: CASE_INSENSITIVE
+ */
+-- newAttribute
+
+BEGIN;
+
+INSERT OR IGNORE INTO ldb_attributes
+ (attr_name, parent_tree_key, objectclass_p)
+ VALUES
+ ('uid', '', 0);
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 1,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'uid'
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 0,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'cn'
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 0,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'ou'
+
+UPDATE ldb_attributes
+ SET case_insensitive_p = 1,
+ wildcard_p = 0,
+ hidden_p = 0,
+ integer_p = 0
+ WHERE attr_name = 'dn'
+
diff --git a/lib/ldb/ldb_sqlite3/trees.ps b/lib/ldb/ldb_sqlite3/trees.ps
new file mode 100644
index 0000000..433a064
--- /dev/null
+++ b/lib/ldb/ldb_sqlite3/trees.ps
@@ -0,0 +1,1760 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software
+%%Title: trees.dvi
+%%Pages: 7
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 596 842
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -f trees.dvi
+%DVIPSParameters: dpi=600, compressed
+%DVIPSSource: TeX output 2000.05.06:2055
+%%BeginProcSet: texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+%%EndProcSet
+TeXDict begin 39158280 55380996 1000 600 600 (trees.dvi)
+@start
+%DVIPSBitmapFont: Fa cmr10 10 6
+/Fa 6 55 df<146014E0EB01C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B
+120F90C7FCA25A121EA2123EA35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A2
+6C7EA26C7E1378A27F7F130E7FEB0380EB01C0EB00E01460135278BD20>40
+D<12C07E12707E7E7E120F6C7E6C7EA26C7E6C7EA21378A2137C133C133E131EA2131F7F
+A21480A3EB07C0A6EB03E0B2EB07C0A6EB0F80A31400A25B131EA2133E133C137C1378A2
+5BA2485A485AA2485A48C7FC120E5A5A5A5A5A13527CBD20>I<15301578B3A6007FB812
+F8B912FCA26C17F8C80078C8FCB3A6153036367BAF41>43 D<EB03F8EB1FFF90387E0FC0
+9038F803E03901E000F0484813780007147C48487FA248C77EA2481580A3007EEC0FC0A6
+00FE15E0B3007E15C0A4007F141F6C1580A36C15006D5B000F143EA26C6C5B6C6C5B6C6C
+485A6C6C485A90387E0FC0D91FFFC7FCEB03F8233A7DB72A>48 D<EB01C013031307131F
+13FFB5FCA2131F1200B3B3A8497E007FB512F0A31C3879B72A>I<EC3FC0903801FFF001
+0713FC90380FE03E90383F800790387E001F49EB3F804848137F485AA2485A000FEC3F00
+49131E001F91C7FCA2485AA3127F90C9FCEB01FC903807FF8039FF1E07E090383801F049
+6C7E01607F01E0137E497FA249148016C0151FA290C713E0A57EA56C7E16C0A2121FED3F
+807F000F15006C6C5B15FE6C6C5B6C6C485A3900FE07F090383FFFC06D90C7FCEB03FC23
+3A7DB72A>54 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fb cmr7 7 3
+/Fb 3 55 df<EB3F803801FFF03803E0F83807803C48487E001E7F003E1480A2003C1307
+007C14C0A400FC14E0AE007C14C0A36CEB0F80A36CEB1F006C131E6C6C5A3803E0F86CB4
+5A38003F801B277EA521>48 D<13381378EA01F8121F12FE12E01200B3AB487EB512F8A2
+15267BA521>I<EB0FE0EB3FF8EBF81C3801E0063803C01F48485AEA0F005A121E003E13
+1E91C7FC5AA21304EB3FC038FCFFF038FDC078EB003CB4133E48131E141FA2481480A412
+7CA4003C1400123E001E131E143E6C133C6C6C5A3803C1F03801FFC06C6CC7FC19277DA5
+21>54 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fc cmmi10 10 1
+/Fc 1 69 df<0103B7FC4916E018F8903B0007F80007FE4BEB00FFF03F80020FED1FC018
+0F4B15E0F007F0021F1503A24B15F81801143F19FC5DA2147FA292C8FCA25C18035CA213
+0119F84A1507A2130319F04A150FA2010717E0181F4A16C0A2010FEE3F80A24AED7F0018
+7E011F16FE4D5A4A5D4D5A013F4B5A4D5A4A4A5A057FC7FC017F15FEEE03FC91C7EA0FF0
+49EC7FC0B8C8FC16FC16C03E397DB845>68 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fd ectt1000 10 73
+/Fd 73 126 df<D807801307D81FE0EB0F80151F487E486C133F1600007C5CD8FCFC137E
+EAF87C15FE5D14015DA21403D8FCFC5BEA7CF8007F13075D383FF00FD81FE05BA2380780
+1FC75B143F92C7FCA25C147E14FE5CA213015CA213035C13075CA2130F5C131FEC800FED
+3FC0013FEB7FE0140049EBFFF0017E13F9A2D9FE0113F801FC13F0A2120113F8120313F0
+15F90007010013F05B000F14FF49EB7FE0A20007EC3FC06C48EB0F0025417DB92C>37
+D<EA0F80EA1FE0EA3FF0127F13F8A213FCA2123F121F120FEA007CA313FC13F8A2120113
+F01203EA07E0A2EA0FC0EA3F80127FEAFF005A12F812700E1D71B22C>39
+D<143814FC13011303EB07F8EB0FF0EB1FC0EB3F80EB7F0013FE485A485A5B12075B120F
+5B485AA2123F90C7FCA25A127EA312FE5AAC7E127EA3127F7EA27F121FA26C7E7F12077F
+12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB07F8EB03FC130113001438164272B92C>
+I<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E6C7E6C7E137F7F1480131F14C0130FEB07E0
+A214F01303A214F81301A314FC1300AC130114F8A3130314F0A2130714E0A2EB0FC0131F
+1480133F14005B13FE485A485A485A485AEA3FC0485A48C7FC5A5A1270164279B92C>I<
+EB0380497EA60020140800F8143E00FE14FE00FF13C1EBC7C7EBE7CF003FB512F8000F14
+E0000314806C140038007FFCA248B5FC481480000F14E0003F14F839FFE7CFFEEBC7C7EB
+07C100FE13C000F8143E0020140800001400A66D5A1F247AAA2C>I<147014F8AF003FB6
+12E0B712F8A4C700F8C7FCB0147025267DAB2C>I<EA0F80EA1FE0EA3FF0EA7FF8A213FC
+A3123F121F120F120013F8A21201EA03F01207EA1FE0EA7FC0EAFF80130012FC12700E17
+718A2C>I<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F000B0B708A2C>46
+D<1507ED0F80A2151F16005D153E157E157CA215FC5D14015D14035D14075D140F5D141F
+92C7FC5C143EA2147E147C14FC5C13015C13035C13075C130F5C131F91C8FC5B133EA213
+7E137C13FC5B12015B12035B12075B120F5B121F90C9FCA25A123E127E127C12FC5AA212
+7021417BB92C>I<EB03F8EB0FFE90383FFF80497F90B57E3901FE0FF03903F803F84848
+6C7EEBE0004848137EA248487FA248C7EA1F80A2003E140F007E15C0A3007C140700FC15
+E0AC6C140F007E15C0A46CEC1F80A36C6CEB3F00A26C6C137E6D13FE00075CEBF0016C6C
+485A3901FE0FF06CB55A6D5B6D5BD90FFEC7FCEB03F823357CB32C>I<1307497EA2131F
+A2133F137F13FF5A1207127FB5FC13DF139FEA7C1F1200B3AE007FB512E0B612F0A36C14
+E01C3477B32C>I<EB0FF890387FFF8048B512E00007804814FC391FF80FFE393FE001FF
+903880007F48C7EA3F80007E141F00FE15C0150F6C15E01507A3127E123CC8FCA2150F16
+C0151F1680153F16005D15FE4A5A14034A5A4A5A4A5A4A5AECFF804948C7FC495A495A49
+5AEB3FE0EB7F8049C8FC485A4848EB03C04848EB07E0EA1FE0485A48B6FCB7FCA36C15C0
+23347CB32C>I<000FB512FE4880A35D0180C8FCADEB83FE90389FFF8090B512E015F881
+9038FE03FE9038F000FF01C07F49EB3F8090C7121F6C15C0C8120FA2ED07E0A4123C127E
+B4FC150F16C0A248141F007EEC3F80007FEC7F006C6C5B6D485A391FF80FFC6CB55A6C5C
+000114C06C6C90C7FCEB0FF823347CB22C>53 D<EC3FC0903801FFF801077F011F7F497F
+90387FE07F9039FF003F804848137FEA03F8485A5B000FEC3F004848131E4990C7FC123F
+90C9FCA25A127EEB03FE90381FFF80D8FC7F13E000FDB57EB67E9038FE07FC9038F001FE
+9038C0007F49EB3F8090C7121F16C048140F16E01507A3127EA47E150F6D14C0001F141F
+6D1480000F143F6DEB7F003907F801FE3903FE07FC6CB55A6C5C6D5B011F1380D907FCC7
+FC23357CB32C>I<1278B712C016E0A316C000FCC7EA3F80ED7F0015FE00785CC712014A
+5A4A5A5D140F5D4A5A143F92C7FC5C147E14FE5C13015CA2495AA213075CA3495AA4495A
+A5133F91C8FCAA131E23357CB32C>I<EA0F80EA1FC0EA3FE0EA7FF0A5EA3FE0EA1FC0EA
+0F80C7FCAEEA0F80EA1FE0EA3FF0EA7FF8A213FCA3123F121F120F120013F8A21201EA03
+F01207EA1FE0EA7FC0EAFF80130012FC12700E3071A32C>59 D<1502ED0F80151F157F15
+FF913803FE00EC0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390
+C8FCEA07FCEA1FF8EA3FE0EAFF8090C9FCA27FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE0
+6D7EEB07FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157F151F150FED
+0200212A7BAD2C>I<007FB612F0B712F8A36C15F0CAFCA8007FB612F0B712F8A36C15F0
+25127DA12C>I<122012F87EB4FC7FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07
+FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157FA215FF913803FE00EC
+0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1F
+F8EA3FE0EAFF8090C9FC12FC5A1220212A7BAD2C>I<14FE497EA4497FA214EFA2130781
+A214C7A2010F7FA314C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA3
+4880A29038F8003FA34848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC
+497E27347EB32C>65 D<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F015
+03A2ED01F8A6ED03F0A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001F
+E0ED07F0ED03F81501ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612
+E016C0B712806CECFE0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD49
+13FFEBFF813901FE007F4848131FD807F0130F1507485A491303485A150148C7FCA25A00
+7EEC00F01600A212FE5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C
+130716E0D803FC131F6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F001001380
+25357DB32C>I<007FB5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED
+0FE0A2150716F0150316F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0
+153FED7F80EDFF00EC03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0
+B712F8A37E3903F00001A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FC
+A5163C167EA8007FB612FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803
+F0C7FCA716781600A515F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C
+7E26337EB22C>I<903901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC
+01497E4848137F4848133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE
+5AA8913803FFF84A13FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D
+137F6C7E6C6C13FF6D5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC2635
+7DB32C>I<D87FFEEBFFFCB54813FEA36C486C13FCD807E0EB0FC0B190B6FCA59038E000
+0FB3D87FFEEBFFFCB54813FEA36C486C13FC27337EB22C>I<007FB512F8B612FCA36C14
+F839000FC000B3B3A5007FB512F8B612FCA36C14F81E3379B22C>I<D87FFCEB7FF8486C
+EBFFFCA36C48EB7FF8D807C0EB1F80153FED7F00157E5D4A5A14034A5A5D4A5A4A5A143F
+4AC7FC147E5CEBC1F813C3EBC7FCA2EBCFFEEBDFBEEBFFBF141F01FE7F496C7E13F86E7E
+EBF00301E07FEBC001816E7EA2157E153E153F811680ED0FC0A2ED07E0D87FFCEB1FFC48
+6CEB3FFEA36C48EB1FFC27337EB22C>75 D<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0
+ED01F8A8007FB6FCB7FCA36C15F025337DB22C>I<D87FE0EB0FFC486CEB1FFEA26D133F
+007F15FC000F15E001BC137BA4019E13F3A3EB9F01A2018F13E3A21483A2018713C314C7
+A201831383A214EFA201811303A214FFEB80FEA3147C14381400ACD87FF0EB1FFC486CEB
+3FFEA36C48EB1FFC27337EB22C>I<D87FF0EB7FFC486CEBFFFEA27F007FEC7FFCD807FE
+EB07C013DEA213DF13CFA2148013C714C0A213C314E0A213C114F0A213C014F8A2147CA3
+143EA2141E141FA2140F1587A2140715C7A2140315E71401A215F71400A215FFD87FFC13
+7F487E153FA26C48EB1F8027337EB22C>I<EB7FFF0003B512E0000F14F848804880EBE0
+03EB800048C7127FA2007E80A300FE158048141FB3A86C143FA2007E1500A3007F5CA26C
+6C13FEEBF00790B5FC6C5C6C5C000314E0C66C90C7FC21357BB32C>I<007FB512C0B612
+F88115FF6C15802603F00013C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2
+ED0FE0ED3FC015FF90B61280160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337E
+B22C>I<EB7FFF0003B512E0000F14F848804880EBF007EB800048C7127FA2007E80A300
+FE158048141FB3A7EB01F0EB03F800FE143F267E01FC1300A2EB00FE007F5C147FD83F80
+13FEEBF03F90B5FC6C5C6C5C000314E0C67E90380007F0A26E7EA26E7EA26E7EA2157FA2
+153E21407BB32C>I<387FFFFCB67E15E015F86C803907E007FE1401EC007F6F7E151FA2
+6F7EA64B5AA2153F4BC7FCEC01FE140790B55A5D15E081819038E007FCEC01FE1400157F
+81A8160FEE1F80A5D87FFEEB1FBFB5ECFF00815E6C486D5AC8EA01F029347EB22C>I<90
+381FF80790B5EA0F804814CF000714FF5A381FF01F383FC003497E48C7FC007E147F00FE
+143F5A151FA46CEC0F00007E91C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C
+14F06C6C7F01077F9038007FFEEC07FF02001380153FED1FC0A2ED0FE0A20078140712FC
+A56CEC0FC0A26CEC1F806D133F01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0
+D8700790C7FC23357CB32C>I<007FB612FCB712FEA43AFC007E007EA70078153CC71400
+B3AF90383FFFFCA2497F6D5BA227337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C
+13C03B03F00001F800B3AF6D130300015DA26D130700005D6D130F017F495A6D6C485AEC
+E0FF6DB5C7FC6D5B010313F86D5B9038003F802B3480B22C>I<D87FFCEB7FFC486CEBFF
+FEA36C48EB7FFCD80FC0EB07E06D130F000715C0A36D131F00031580A36D133F00011500
+A36D5B0000147EA4017E5BA46D485AA490381F83F0A4010F5B14C7A301075BA214EFA201
+035BA214FFA26D90C7FCA46D5A27347EB22C>I<D87FF0EB07FF486C491380A36C486D13
+00001FC8127CA46C6C5CA76C6C495AA4143E147FA33A03E0FF83E0A214F7A201E113C3A3
+000101E35BA201F113C701F313E7A314C1A200005DA201F713F71480A301FF13FF017F91
+C7FC4A7EA4013E133E29347FB22C>I<3A3FFF03FFE0484913F0148714076C6D13E03A01
+F800FE007F0000495A13FE017E5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D
+90C7FCA26D5AA26D5AA2497EA2497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB
+7F01017E7FEBFE00497F0001147E49137F000380491480151FD87FFEEBFFFC6D5AB514FE
+6C15FC497E27337EB22C>I<D87FFCEB7FFC486CEBFFFEA36C48EB7FFCD807F0EB0FC015
+1F000315806D133F12016DEB7F0012006D137E017E13FE017F5BEB3F01EC81F8131FEC83
+F0EB0FC314C7903807E7E0A201035B14EF6DB45AA292C7FC7F5C147EB0903807FFE0497F
+A36D5B27337EB22C>I<387FFFFCB512FEA314FC00FCC7FCB3B3B3B512FC14FEA36C13FC
+17416FB92C>91 D<127012F8A27E127C127E123E123F7EA27F120F7F12077F12037F1201
+7F12007F137C137E133EA2133F7F80130F80130780130380130180130080147C147E143E
+A2143F8081140F81140781140381140181140081157CA2157E153E153F811680150FA2ED
+070021417BB92C>I<387FFFFCB512FEA37EC7127EB3B3B3387FFFFEB5FCA36C13FC1741
+7DB92C>I<EB07C0EB1FF0EB7FFC48B5FC000714C0001F14F0397FFC7FFC39FFF01FFEEB
+C007EB0001007CEB007C003014181F0C7AAE2C>I<007FB6FCB71280A46C150021067B7D
+2C>I<1338137CEA01FC1203EA07F813F0EA0FC0EA1F80A2EA3F00123E127E127CA212FC
+5AA3EAFFC013E013F013F8A2127FA2123F13F0EA1FE0EA07C00E1D72B82C>I<3801FFF0
+000713FE001F6D7E15E048809038C01FF81407EC01FC381F80000006C77EC8127EA3ECFF
+FE131F90B5FC1203120F48EB807E383FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003
+383FE01F6CB612FC6C15FE6C14BF0001EBFE1F3A003FF007FC27247CA32C>I<EA7FF048
+7EA3127F1201AAEC1FE0ECFFF801FB13FE90B6FC16809138F07FC09138801FE091380007
+F049EB03F85BED01FC491300A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F
+9138801FE09138E07FC091B51280160001FB5B01F813F83900F03FC027337FB22C>I<90
+3803FFE0011F13F8017F13FE48B5FC48804848C6FCEA0FF0485A49137E4848131890C9FC
+5A127EA25AA8127EA2127F6C140F6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A
+6C5C6C6C5B011F13E0010390C7FC21247AA32C>I<EC0FFE4A7EA380EC003FAAEB07F8EB
+3FFE90B512BF4814FF5A3807FC0F380FF00348487E497E48487F90C7FC007E80A212FE5A
+A87E007E5CA2007F5C6C7E5C6C6C5A380FF0073807FC1F6CB612FC6CECBFFE6C143FEB3F
+FC90390FF01FFC27337DB22C>I<EB03FE90381FFFC0017F13F048B57E48803907FE03FE
+390FF800FFD81FE0EB3F805B4848EB1FC090C7120F5A007E15E015075AB7FCA416C000FC
+C9FC7E127EA2127F6CEC03C06DEB07E06C7ED80FF0130F6C6CEB3FC001FF13FF000190B5
+12806C1500013F13FC010F13F00101138023247CA32C>I<ED03F8903907F80FFC90391F
+FE3FFE017FB6FC48B7FC48ECFE7F9038FC0FF82607F003133E3A0FE001FC1CD9C0001300
+001F8049137EA66D13FE000F5CEBE0016C6C485A3903FC0FF048B5FC5D481480D99FFEC7
+FCEB87F80180C8FCA37F6C7E90B512F06C14FE48ECFF804815E04815F03A3FC0001FF848
+C7EA03FC007E1400007C157C00FC157E48153EA46C157E007E15FCD87F801303D83FE0EB
+0FF8D81FFCEB7FF06CB612E0000315806C1500D8003F13F8010713C028387EA42C>103
+D<EA7FF0487EA3127F1201AAEC1FE0EC7FFC9038F9FFFE01FB7F90B6FC9138F03F80ECC0
+1F02807FEC000F5B5BA25BB3267FFFE0B5FCB500F11480A36C01E0140029337FB22C>I<
+1307EB1FC0A2497EA36D5AA20107C7FC90C8FCA7387FFFC080B5FC7EA2EA0007B3A8007F
+B512FCB612FEA36C14FC1F3479B32C>I<EA7FE0487EA3127F1201AA91381FFFF04A13F8
+A36E13F0913800FE004A5A4A5A4A5A4A5A4A5A4A5A4AC7FC14FEEBF1FC13F3EBF7FE90B5
+FCA2EC9F80EC0FC001FE7FEBFC07496C7E496C7E811400157E811680151F3A7FFFC0FFFC
+B500E113FEA36C01C013FC27337EB22C>107 D<387FFFE0B57EA37EEA0003B3B3A5007F
+B61280B712C0A36C158022337BB22C>I<3A7F83F007E09039CFFC1FF83AFFDFFE3FFCD8
+7FFF13FF91B57E3A07FE1FFC3E01FCEBF83F496C487E01F013E001E013C0A301C01380B3
+3B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87FFC4913F0023F137F2D2481A32C>I<397F
+F01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC00019038F03F80ECC01F02807FEC000F5B
+5BA25BB3267FFFE0B5FCB500F11480A36C01E0140029247FA32C>I<EB07FCEB1FFF017F
+13C048B512F048803907FC07FC390FF001FE48486C7E0180133F003F158090C7121F007E
+EC0FC0A348EC07E0A76C140F007E15C0A2007F141F6C15806D133F6C6CEB7F006D5B6C6C
+485A3907FC07FC6CB55A6C5C6C6C13C0011F90C7FCEB07FC23247CA32C>I<397FF01FE0
+39FFF8FFF801FB13FE90B6FC6C158000019038F07FC09138801FE091380007F049EB03F8
+5BED01FC491300A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE0
+9138E07FC091B51280160001FB5B01F813F8EC3FC091C8FCAD387FFFE0B57EA36C5B2736
+7FA32C>I<903903FC078090391FFF0FC0017F13CF48B512EF4814FF3807FE07380FF001
+48487E49137F4848133F90C7FC48141F127E150F5AA87E007E141FA26C143F7F6C6C137F
+6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C138F6D130FEB07F890C7FCAD0203B5FC4A
+1480A36E140029367DA32C>I<D87FFEEB3FC0B53801FFF0020713F8021F13FC6C5B3900
+3F7FE1ECFF019138FC00F84A13704A13005CA25C5CA391C8FCAF007FB512E0B67EA36C5C
+26247EA32C>I<90387FF8700003B512F8120F5A5A387FC00F387E00034813015AA36CEB
+00F0007F140013F0383FFFC06C13FE6CEBFF80000314E0C66C13F8010113FCEB0007EC00
+FE0078147F00FC143F151F7EA26C143F6D133E6D13FE9038F007FC90B5FC15F815E000F8
+148039701FFC0020247AA32C>I<131E133FA9007FB6FCB71280A36C1500D8003FC8FCB1
+ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6DB51280160001035B6D13F89038003FE023
+2E7EAD2C>I<3A7FF003FF80486C487FA3007F7F0001EB000FB3A3151FA2153F6D137F39
+00FE03FF90B7FC6D15807F6D13CF902603FE07130029247FA32C>I<3A3FFF03FFF04801
+8713F8A36C010313F03A00FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC090
+3807EF80EB03FF6D90C7FC5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83
+E090381F01F0013F7FEB7E00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC
+140127247EA32C>120 D<3A7FFF01FFFCB5008113FE148314816C010113FC3A03E0000F
+806C7E151F6D140012005D6D133E137C017E137E013E137CA2013F13FC6D5BA2EB0F815D
+A2EB07C1ECC3E0A2EB03E3ECE7C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA2
+14FC5CA2EA0C01003F5BEA7F83EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E0
+27367EA32C>I<15FF02071380141F147F91B512004913C04AC7FCEB03F85CB31307EB1F
+E013FF007F5BB55A49C8FC6D7E6C7FC67F131FEB07F01303B380EB01FEECFFC06D13FF6E
+1380141F14070200130021417BB92C>123 D<127812FCB3B3B3A9127806416DB92C>I<EA
+7FC0EAFFF813FE6D7E6C7FC67F131FEB07F01303B380EB01FEECFFC06D13FF6E1380141F
+147F91B512004913C04AC7FCEB03F85CB31307EB1FE013FF007F5BB55A49C8FC13F8EA7F
+C021417BB92C>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fe ecti1000 10 33
+/Fe 33 122 df<EE3FFC4BB51280923907E007C092391F8001E0DB3F0013F0037E13034B
+1307A24A5A18E04A48EB038094C7FCA314075DA4140F5DA3010FB7FCA25F903A001F8000
+7EA217FE023F5C92C7FCA216015F5C147E16035FA214FE4A13075FA30101140F5F4AECC1
+C0A2161F1783010316805CA2EF870013074A5CEE0F8EEE079EEE03FC010FEC00F04A91C7
+FCA35C131FA2001C90CAFC127E5BEAFE3E133C137CEAF878EA78F0EA3FE0EA0F80344C82
+BA2F>28 D<150C151C153815F0EC01E0EC03C0EC0780EC0F00141E5C147C5C5C495A1303
+495A5C130F49C7FCA2133EA25BA25BA2485AA212035B12075BA2120F5BA2121FA290C8FC
+A25AA2123EA2127EA2127CA412FC5AAD1278A57EA3121C121EA2120E7EA26C7E6C7EA212
+001E5274BD22>40 D<140C140E80EC0380A2EC01C015E0A2140015F0A21578A4157C153C
+AB157CA715FCA215F8A21401A215F0A21403A215E0A21407A215C0140F1580A2141F1500
+A2143EA25CA25CA2495AA2495A5C1307495A91C7FC5B133E133C5B5B485A12035B48C8FC
+120E5A12785A12C01E527FBD22>I<4B7EA3150393C8FCA35D1506A3150E150CA3151C15
+18A315381530A31570B912E0A2C80060C8FC15E05DA314015DA3140392C9FCA35C1406A3
+140E140CA3141C1418A2333275AD40>43 D<EA03C0EA07F0120F121F13F8A313F0EA07B0
+EA003013701360A213E013C01201EA038013005A120E5A5A5A5A5A0D197A8819>I<120E
+EA3F80127F12FFA31300127E123C0909778819>46 D<0103B612FEEFFFC018F0903B0007
+F8000FF84BEB03FCEF00FE020F157FF03F804B141F19C0021F150F19E05D1807143F19F0
+5DA2147FA292C8FCA25C180F5CA2130119E04A151FA2130319C04A153FA201071780187F
+4A1600A2010F16FEA24A4A5A60011F15034D5A4A5D4D5A013F4B5A173F4A4AC7FC17FC01
+7FEC03F84C5A91C7EA1FC04949B45A007F90B548C8FCB712F016803C397CB83F>68
+D<0103B512F8A390390007F8005DA2140FA25DA2141FA25DA2143FA25DA2147FA292C7FC
+A25CA25CA21301A25CA21303A25CA21307A25CA2130FA25CA2131FA25CA2133FA25CA213
+7FA291C8FC497EB6FCA25C25397CB820>73 D<0107B512FCA25E9026000FF8C7FC5D5D14
+1FA25DA2143FA25DA2147FA292C8FCA25CA25CA21301A25CA21303A25CA21307A25CA213
+0F170C4A141CA2011F153C17384A1478A2013F157017F04A14E01601017F140317C091C7
+1207160F49EC1F80163F4914FF000102071300B8FCA25E2E397BB834>76
+D<ED03FE92383FFFC09238FC07F0913903E001F891390F80007C023FC77E027E8002F815
+804948EC0FC0EB07E04948EC07E0131F4A15F049C81203137E01FE16F8485AA2485AA248
+5AA2120F5B001F16075B123FA34848ED0FF0A448C9EA1FE0A3EF3FC0A21880177F18005F
+5F16015F6C4B5A4C5AA24C5A6C4B5A6D4A5A001F93C7FC6D147E000F5D6C6CEB03F06C6C
+495A6C6CEB0F806C6C013FC8FC90383F01FC90381FFFE0010190C9FC353D74BA40>79
+D<ED03FE92383FFFC09238FC07F0913903E001F891390FC0007C023FC77E027E804A1580
+D901F0EC0FC013074948EC07E0495A4A15F049C8FC49150301FE16F8485AA2485AA2485A
+A2120F491507121FA2485AA34848ED0FF0A448C9EA1FE0A3EF3FC0A21880177F4817005F
+5F16015F007F4B5A5F91380F800791393FE00FE06C903970601FC0902680E0305B261F81
+C049C7FC913880187ED80FC35C3A07E30019F00003EC1FE0D801FB14806CB46C48C8FC90
+263F81FC13186DB45A01010138133890C7003C1330177017F05FED3E03ED3F07EEFFC05F
+A294C7FC5E6F5A6F5AED07E0354B74BA40>81 D<92383FC00E913901FFF01C020713FC91
+391FC07E3C91393F001F7C027CEB0FF84A130749481303495A4948EB01F0A2495AA2011F
+15E091C7FCA34915C0A36E90C7FCA2806D7E14FCECFF806D13F015FE6D6D7E6D14E00100
+80023F7F14079138007FFC150F15031501A21500A2167C120EA3001E15FC5EA3003E4A5A
+A24B5AA2007F4A5A4B5A6D49C7FC6D133ED8F9F013FC39F8FC03F839F07FFFE0D8E01F13
+8026C003FCC8FC2F3D7ABA2F>83 D<0007B812E0A25AD9F800EB001F01C049EB07C0485A
+D900011403121E001C5C003C17801403123800785C00701607140700F01700485CA2140F
+C792C7FC5DA2141FA25DA2143FA25DA2147FA292C9FCA25CA25CA21301A25CA21303A25C
+A21307A25CA2130FA25CEB3FF0007FB512F8B6FCA2333971B83B>I<14F8EB07FE90381F
+871C90383E03FE137CEBF801120148486C5A485A120FEBC001001F5CA2EA3F801403007F
+5C1300A21407485C5AA2140F5D48ECC1C0A2141F15831680143F1587007C017F1300ECFF
+076C485B9038038F8E391F0F079E3907FE03FC3901F000F0222677A42A>97
+D<133FEA1FFFA3C67E137EA313FE5BA312015BA312035BA31207EBE0F8EBE7FE9038EF0F
+80390FFC07C013F89038F003E013E0D81FC013F0A21380A2123F1300A214075A127EA214
+0F12FE4814E0A2141F15C05AEC3F80A215005C147E5C387801F8007C5B383C03E0383E07
+C0381E1F80D80FFEC7FCEA01F01C3B77B926>I<147F903803FFC090380FC1E090381F00
+70017E13784913383901F801F83803F003120713E0120FD81FC013F091C7FC485AA2127F
+90C8FCA35A5AA45AA3153015381578007C14F0007EEB01E0003EEB03C0EC0F806CEB3E00
+380F81F83803FFE0C690C7FC1D2677A426>I<ED01F815FFA3150316F0A21507A216E0A2
+150FA216C0A2151FA21680A2153FA202F81300EB07FE90381F877F90383E03FF017C5BEB
+F80112013803F00048485B120FEBC001121F5DEA3F801403127F01005BA214075A485CA2
+140FA248ECC1C0A2141F15C3ED8380143F1587007C017F1300ECFF076C485B9038038F8E
+391F0F079E3907FE03FC3901F000F0253B77B92A>I<147F903803FFC090380FC1E09038
+3F00F0017E13785B485A485A485A120F4913F8001F14F0383F8001EC07E0EC1F80397F81
+FF00EBFFF8148090C8FC5A5AA55AA21530007C14381578007E14F0003EEB01E0EC03C06C
+EB0F806CEB3E00380781F83803FFE0C690C7FC1D2677A426>I<ED07C0ED1FF0ED3E38ED
+7C3CEDF8FC15F9140115F1020313F8EDF0F0160014075DA4140F5DA4141F5D010FB512C0
+5B16809039003F800092C7FCA45C147EA414FE5CA413015CA413035CA413075CA4130F5C
+A3131F5CA391C8FC5B121CEA7E3EA2EAFE3C137C1378EAF8F01278EA3FC0EA0F80264C82
+BA19>I<EC07C0EC3FF09138FC38E0903901F01FF0EB03E0903807C00FEB0F80011F1307
+D93F0013E05B017E130F13FE4914C01201151F1203491480A2153F1207491400A25DA249
+137EA215FEA25D00031301140314076C6C485A0000131FEB787BEB3FF390380FC3F0EB00
+031407A25DA2140F5D121C007E131F5D00FE49C7FC147E5C387801F8387C07E0381FFF80
+D803FEC8FC24367CA426>I<EB03F0EA01FFA3EA00075CA3130F5CA3131F5CA3133F91C8
+FCA35B90387E07F0EC1FFCEC783E9038FFE01F02C01380EC800F1400485A16C05B49EB1F
+8012035BA2153F000715005BA25D000F147E5B15FE5D121FD98001131C15F8163C003F01
+031338010013F0A216704814E0007E15F016E0EDE1C000FE903801E38048903800FF0000
+38143C263B7BB92A>I<EB01C0EB07E014F0130F14E01307EB038090C7FCAB13F0EA03FC
+EA071EEA0E1F121CA212385B1270A25BEAF07E12E013FEC65AA212015B1203A25B12075B
+A2000F13E013C013C1001F13C01381A2EB83801303EB0700A2130E6C5AEA07F8EA01E014
+3879B619>I<EB0FC0EA07FFA3EA001F1480A2133FA21400A25BA2137EA213FEA25BA212
+01A25BA21203A25BA21207A25BA2120FA25BA2121FA25BA2123FA290C7FCA25AA2EA7E0E
+A212FE131EEAFC1CA2133C133812F81378EA7870EA7CE0121FEA0F80123B79B915>108
+D<D801E001FEEB07F03C07F803FF801FFC3C0E3C0F07C0783E3C1E3E3C03E1E01F261C1F
+78D9F3C013803C383FF001F7800F02E01400007801C013FE007018C002805B4A4848EB1F
+80EAF07FD8E07E5CA200000207143F01FE1700495CA2030F5C0001177E495C18FE031F5C
+120349DA8001131C18F8033F153C00070403133849020013F0A24B1570000F17E049017E
+15F019E003FEECE1C0001FEE01E34949903800FF000007C70038143C3E2679A444>I<D8
+01E013FE3A07F803FF803A0E3C0F07C03A1E3E3C03E0261C1F787F39383FF00114E00078
+13C000708114804A485AEAF07FEAE07EA20000140701FE5C5BA2150F00015D5B151F5E12
+034990383F8380160316070007027F130049137EA2160E000F147C49141E161C5E001FEC
+3C7849EB1FE00007C7EA0780292679A42F>I<147F903803FFC090380FC1F090381F00F8
+017E137C5B4848137E4848133E0007143F5B120F485AA2485A157F127F90C7FCA215FF5A
+4814FEA2140115FC5AEC03F8A2EC07F015E0140F007C14C0007EEB1F80003EEB3F00147E
+6C13F8380F83F03803FFC0C648C7FC202677A42A>I<9039078007C090391FE03FF09039
+3CF0787C903938F8E03E9038787FC00170497EECFF00D9F0FE148013E05CEA01E113C15C
+A2D80003143FA25CA20107147FA24A1400A2010F5C5E5C4B5A131F5EEC80035E013F495A
+6E485A5E6E48C7FC017F133EEC70FC90387E3FF0EC0F8001FEC9FCA25BA21201A25BA212
+03A25B1207B512C0A3293580A42A>I<3903C003F0390FF01FFC391E783C0F381C7C703A
+3C3EE03F8038383FC0EB7F800078150000701300151CD8F07E90C7FCEAE0FE5BA2120012
+015BA312035BA312075BA3120F5BA3121F5BA3123F90C9FC120E212679A423>114
+D<14FE903807FF8090380F83C090383E00E04913F00178137001F813F00001130313F0A2
+15E00003EB01C06DC7FC7FEBFFC06C13F814FE6C7F6D13807F010F13C01300143F141F14
+0F123E127E00FE1480A348EB1F0012E06C133E00705B6C5B381E03E06CB45AD801FEC7FC
+1C267AA422>I<EB0380EB07C0130FA4131F1480A3133F1400A35B137E007FB5FCA2B6FC
+3800FC00A312015BA312035BA312075BA3120F5BA3121FEB801CA2143C003F1338EB0078
+147014F014E0EB01C0EA3E03381F0780380F0F00EA07FCEA01F0183579B31C>I<01F013
+0ED803FC133FD8071EEB7F80EA0E1F121C123C0038143F49131F0070140FA25BD8F07E14
+0000E08013FEC6485B150E12015B151E0003141C5BA2153C000714385B5DA35DA24A5A14
+0300035C6D48C7FC0001130E3800F83CEB7FF8EB0FC0212679A426>118
+D<903907E007C090391FF81FF89039787C383C9038F03E703A01E01EE0FE3803C01F0180
+13C0D8070014FC481480000E1570023F1300001E91C7FC121CA2C75AA2147EA214FEA25C
+A21301A24A1370A2010314F016E0001C5B007E1401010714C000FEEC0380010F1307010E
+EB0F0039781CF81E9038387C3C393FF03FF03907C00FC027267CA427>120
+D<13F0D803FCEB01C0D8071EEB03E0D80E1F1307121C123C0038140F4914C01270A24913
+1FD8F07E148012E013FEC648133F160012015B5D0003147E5BA215FE00075C5BA214015D
+A314035D14070003130FEBF01F3901F87FE038007FF7EB1FC7EB000F5DA2141F003F5C48
+133F92C7FC147E147C007E13FC387001F8EB03E06C485A383C1F80D80FFEC8FCEA03F023
+3679A428>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Ff cmsy10 10 1
+/Ff 1 16 df<EB1FF0EBFFFE487F000714C04814E04814F04814F8A24814FCA3B612FEA9
+6C14FCA36C14F8A26C14F06C14E06C14C0000114006C5BEB1FF01F1F7BA42A>15
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fg ecbx1000 10 36
+/Fg 36 119 df<913803FFC0027F13F00103B512FC010FEB00FED93FF8133FD97FE0EBFF
+8049485A5A1480484A13C04A6C1380A36F1300167E93C7FCA592383FFFC0B8FCA4000390
+C7FCB3ABB5D8FC3F13FFA4303A7EB935>28 D<B61280A819087F9620>45
+D<EA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3FE0EA0F800D0D798C1B>I<141E143E
+14FE1307137FB5FCA3138FEA000FB3B3A5007FB61280A4213679B530>49
+D<EB0FFE90387FFFC048B512F0000714FC390FE03FFF261F800F1380263F000313C0D87F
+8014E0EBE00100FF6D13F07FA2ED7FF8A46C5A6C5A0006C7FCC8FCEDFFF0A216E05C16C0
+4A138016004A5A4A5AEC1FF05D4A5A4AC7FC14FE495AD903F01378495A495A495A49C712
+F8017C14F05B49130148B6FC5A5A5A5A5A4815E0B7FCA425367BB530>I<EC0FF8ECFFFE
+0103EBFF8090390FF80FC090393FE003E090397F8001F09038FF000F48EC1FF84848133F
+485A120F5B121FA2003FEC1FF0ED0FE0484890C7FCA31408EC7FF039FFF1FFFC01F313FF
+D9F78013809039FF007FC049EB3FE04914F0ED1FF85B16FCA34914FEA4127FA5123F16FC
+A26C7E16F8000F143F6D14F0000715E06C6CEB7FC03A01FF81FF806C90B51200013F13FC
+010F13F00101138027377CB530>54 D<EA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3F
+E0EA0F80C7FCABEA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3FE0EA0F800D2579A41B
+>58 D<B812C017FC17FF18C028007FF000037F04007F717E717E171F84A2717EA74D5AA2
+60173F4D5A4D5A4C13C0040F5B91B600FCC7FCA2EFFF8002F0C713F0EF3FF8717E717E71
+7E19807113C0A319E0A719C0A25F4D138019005FEF7FFE4C485AB912F018C095C7FC17F0
+3B397DB844>66 D<DB3FFCEB01C00203B5EAC003021FECF00791B6EAFC0F01039039FC00
+FF3F4901C0EB1FFFD91FFEC77E49481403D97FF080494880485B48177F4849153F4890C9
+FC181F485A180F123F5B1807127FA24993C7FC12FFAD127F7FF003C0123FA27F001F1707
+A26C6C1780180F6C6D16006C6D5D6C173E6C6D157ED97FF85D6D6C4A5A6DB44A5A010701
+C0EB0FE06D01FCEBFF80010090B548C7FC021F14F8020314E09126003FFEC8FC3A3B7BB9
+45>I<B87E17F817FF18C028007FF8000713F09338007FF8EF1FFE717E050313807113C0
+A27113E0F07FF0A2F03FF8A219FC181FA219FEA419FFAC19FEA419FC183FA219F8187F19
+F0F0FFE0A24D13C04D13804D1300EF1FFEEF7FFC933807FFF0B912C095C7FC17FC178040
+397DB849>I<B612FCA439007FF800B3B3ADB612FCA41E397DB824>73
+D<B7FCA426007FF8C9FCB3ACEF0780A5170F1800A35FA25FA25F5F5E5EEE0FFE167FB8FC
+A431397DB839>76 D<B500F80403B512F06E5EA26E5ED8007FF1E000A2D97BFF161EA201
+796D5DA201786D5DA26E6C5DA36E6C4A5AA26E6C4A5AA26E6C4A5AA26E6C4A5AA26E6C14
+1EA36E6D5BA26E6D5BA26F6C5BA26F6C485AA36F6C485AA26F6C485AA26F6C48C7FCA292
+3803FF1EA36F13BCA26F13F8A2705AA2705AA213FCB500FC6D4848B612F0A2EE0F80EE07
+0054397DB85B>I<B500FC0203B512F0A28080C66C6D90390003F0006F6E5A81017B7F13
+798101787F6E7E6E7E6E7F6E7FA26E7F6E7F6E7F6E7F6F7E153F826F13806F13C06F13E0
+6F13F06F13F88117FCEE7FFEEE3FFF7013817013C17013E18218F17013F97013FDEF7FFF
+8383A28383838383187FA2183F181F01FC160FB500FC150718031801A244397DB84B>I<
+EDFFF8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD91FFC010113C0D93FF0
+6D6C7E49486E7E49486E7E48496E7E48834890C86C7EA248486F1380A248486F13C0A200
+3F18E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A26D5D001F18C0A26C6C
+4B13806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC49485A6DB401075B0107D9
+C01F90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B7BB948>I<B8FC17F0
+17FEEFFF8028007FF8000F13C0040113E07013F0EF7FF8EF3FFCA2EF1FFEA218FFA818FE
+A2EF3FFCA2EF7FF8EFFFF04C13E0040F13C091B7120017FC17E002F8C9FCB3A4B612FCA4
+38397DB841>I<EDFFF8020FEBFF80027F14F0903A01FFE03FFC010790380007FFD91FFC
+010113C049486D7FD97FE0EC3FF049486E7E488348496E7E4890C86C7EA248486F1380A2
+001F18C04981003F18E0A3007F18F04981A300FF18F8AC007F18F0A36D5D003F18E0A36C
+6C4B13C0A2000FDA1FC014806C6C90267FF0071300EDFFF86C903A81F07C0FFE6C903AC3
+C01E1FFC6CDA800F5BD97FE3ECBFF0D93FF36DB45AD91FFF5D010701C091C7FC01019038
+F01FFC6D6CB500F01308020F6E131C0200EBF9FC92260001FE133C9438FF80FC18FF8219
+F8A28319F0A27113E0A27113C0711380711300EF01FC3E4A7BB948>I<D907FF130E013F
+EBE01E90B5EAF83E0003ECFE7E3A07FC01FFFE390FF0001F4848130F4848130349130100
+7F140090C8FC167E5A163EA27F161E7F7F6D91C7FC13FC387FFFE014FEECFFF06C14FE6F
+7E6C816C15F06C816C81C681133F010F801301D9000F1480EC007F030F13C01503818100
+F0157FA3163FA27E17807E167F6C16007E6D14FE01E0495A01F813039039FF801FF800FC
+90B512E0D8F83F5CD8F00749C7FC39E0007FF02A3B7BB935>83 D<B600FC011FB512C0A4
+26007FF8C8381FC000725AB3B3181F013F94C7FC8060011F163E6D6C157E187C6D6C15FC
+6D6D495A6D6DEB07F06D01F0EB1FE0DA7FFEEBFFC0021FB6C8FC02075C020014F0030F13
+80423A7DB849>85 D<B600F00103B512E0A4C601F0C83807F0006E5E017F5F6E150FA201
+3F5F6E151F011F94C7FC6E5D6D163E6F147E6D167CA26F14FC6D5E6F13016D5E6F13036D
+5E811707027F5D6F130F023F5D6F131F021F92C8FC815F6E143EEE807E6E147CEEC0FC6E
+5C16E016E16E5C16F36E5C16FF6F5BA36F5BA26F90C9FCA26F5AA36F5AA26F5AA26F5A43
+3A7EB848>I<B6D8E01FB500FC90383FFFFCA4000101F0C7D83FFCC8EA7E006C71153C17
+1F6E197C017F701578836E7014F8013F6F5E6E1801011F4B6D5CA26E18036D4B6D5CA26D
+6D496D495A173C6F170F6D037C6D91C7FCEF787F6F5F6D4B6C6C131E816D02016E5BEFE0
+1F03F8177C027F01036E13784D7E03FCEE80F8023F49486C5C15FE021F010FEDC1E04D7E
+03FF16C36E49EDE3C0041E7F049E15F76E01BC6D5C04FC15FF6E95C8FC4C80A26E5F4C14
+3F6E5F4C141FA2037F5E4C140FA26F486E5AA2031F5E93C812036F5E5E3A7EB863>I<13
+FFB5FCA412077EAF4AB47E020F13F0023F13FC9138FE03FFDAF00013804AEB7FC00280EB
+3FE091C713F0EE1FF8A217FC160FA217FEAA17FCA3EE1FF8A217F06E133F6EEB7FE06E14
+C0903AFDF001FF80903AF8FC07FE009039F03FFFF8D9E00F13E0D9C00390C7FC2F3A7EB9
+35>98 D<EE7F80ED7FFFA4150381AF903801FF81010F13F1013F13FD9038FFC07F0003EB
+001FD807FC1307000F8048487F5B123FA2485AA312FFAA127FA27F123FA26C6C5B000F5C
+6C6C5B6C6C4913C02701FF80FD13FE39007FFFF9011F13E1010113012F3A7DB935>100
+D<903803FF80011F13F0017F13FC3901FF83FE3A03FE007F804848133F484814C0001FEC
+1FE05B003FEC0FF0A2485A16F8150712FFA290B6FCA301E0C8FCA4127FA36C7E1678121F
+6C6C14F86D14F000071403D801FFEB0FE06C9038C07FC06DB51200010F13FC010113E025
+257DA42C>I<EC1FF0903801FFFC010713FF90391FF87F8090383FE0FFD9FFC113C0A248
+1381A24813016E1380A2ED3E0092C7FCA8B6FCA4000390C8FCB3ABB512FEA4223A7DB91D
+>I<161FD907FEEBFFC090387FFFE348B6EAEFE02607FE07138F260FF801131F48486C13
+8F003F15CF4990387FC7C0EEC000007F81A6003F5DA26D13FF001F5D6C6C4890C7FC3907
+FE07FE48B512F86D13E0261E07FEC8FC90CAFCA2123E123F7F6C7E90B512F8EDFF8016E0
+6C15F86C816C815A001F81393FC0000F48C8138048157F5A163FA36C157F6C16006D5C6C
+6C495AD81FF0EB07FCD807FEEB3FF00001B612C06C6C91C7FC010713F02B377DA530>I<
+EA01F0EA07FC487EA2487EA56C5AA26C5AEA01F0C8FCA913FF127FA412077EB3A9B512F8
+A4153B7DBA1B>105 D<13FFB5FCA412077EAF92380FFFE0A4923803FC0016F0ED0FE0ED
+1F804BC7FC157E5DEC03F8EC07E04A5A141FEC7FE04A7E8181A2ECCFFEEC0FFF496C7F80
+6E7F6E7F82157F6F7E6F7E82150F82B5D8F83F13F8A42D3A7EB932>107
+D<13FFB5FCA412077EB3B3ACB512FCA4163A7DB91B>I<01FED97FE0EB0FFC00FF902601
+FFFC90383FFF80020701FF90B512E0DA1F81903983F03FF0DA3C00903887801F000749DA
+CF007F00034914DE6D48D97FFC6D7E4A5CA24A5CA291C75BB3A3B5D8FC1FB50083B512F0
+A44C257DA451>I<01FEEB7FC000FF903803FFF8020F13FE91381F03FFDA3C0113800007
+13780003497E6D4814C05CA25CA291C7FCB3A3B5D8FC3F13FFA430257DA435>I<903801
+FFC0010F13F8017F13FFD9FF807F3A03FE003FE048486D7E48486D7E48486D7EA2003F81
+491303007F81A300FF1680A9007F1600A3003F5D6D1307001F5DA26C6C495A6C6C495A6C
+6C495A6C6C6CB45A6C6CB5C7FC011F13FC010113C029257DA430>I<9038FE03F000FFEB
+0FFEEC3FFF91387C7F809138F8FFC000075B6C6C5A5CA29138807F80ED3F00150C92C7FC
+91C8FCB3A2B512FEA422257EA427>114 D<90383FF0383903FFFEF8000F13FF381FC00F
+383F0003007E1301007C130012FC15787E7E6D130013FCEBFFE06C13FCECFF806C14C06C
+14F06C14F81203C614FC131F9038007FFE140700F0130114007E157E7E157C6C14FC6C14
+F8EB80019038F007F090B512C000F8140038E01FF81F257DA426>I<130FA55BA45BA25B
+5BA25A1207001FEBFFE0B6FCA3000390C7FCB21578A815F86CEB80F014816CEBC3E09038
+3FFFC06D1380903803FE001D357EB425>I<B539F001FFF8A4000390C7EA1F00161E6E13
+3E6C153C6E137C6C15786E13F8017F5CECF001013F5C14F8011F495AA2ECFC07010F5CEC
+FE0F010791C7FC6E5A6D131E15BE6D13BC15FC6D5BA36E5AA26E5AA26E5AA26E5AA22D25
+7EA432>118 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fh ecrm1000 10 89
+/Fh 89 126 df<486C1360000314E039070001C0000EEB038048EB070000181306003813
+0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0
+A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80
+3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7
+12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I<B81280
+A2290280962A>21 D<DA0FF813FC91397FFF07FF903B01F807DF83C0903A07E001FF0F90
+3B1F8007FE1FE090393F000FFC137E16F85B9338F007804848010790C7FC1503ACB812F8
+A32801F80003F0C7FCB3AB486C497E267FFFE0B512F0A3333B7FBA30>27
+D<EC0FF8EC7FFE903901F80780903907E001C090391F8000E090383F0007017E497EA25B
+A2485A6F5AED018092C8FCA9ED03F0B7FCA33901F8000F1503B3AA486C497E267FFFE0B5
+12C0A32A3B7FBA2E>I<DA0FF0EB1FF0DA7FFEEBFFFC903B01F80F83F00F903C07E001CF
+C00380903C1F8000FF0001C090273F0007FE130F017E4948497EA2495CA248485C03076E
+5A03030203C7FC95C8FCA9F007E0BAFCA33C01F80003F0001F1807B3AA486C496C497E26
+7FFFE0B500C1B51280A3413B7FBA45>30 D<EB0380A3EB0FF0EB7FFE48B512803903F38F
+C03907C381E0390F8380F0D81F031338123E003C141C007C140C150E0078143E00F814FE
+1481A400FCEB80FC157800FE140012FF127F13C313E3EA3FFF6C7F14F86C13FE6CEBFF80
+000114C06C14E0013F13F01303ECBFF8148FEC83FC1481A2EC80FE157E123C12FF153EA4
+12FE00F8143C00E0147C12600070147815F8003814F0003C1381001EEB83E0000FEB87C0
+3907E39F803901FFFE006C5BEB1FE0EB0380A41F437BBD2A>36 D<141FEC7FC0903801F0
+E0903803C0600107137090380F803090381F00381518A25BA2133E133F15381530A21570
+5D5D140190381F838092CAFC1487148E02DC49B51280EB0FF85C4A9039003FF8000107ED
+0FC06E5D71C7FC6E140E010F150CD91DFC141C01391518D970FE143801E015302601C07F
+1470D803805D00076D6C5BD80F00EBC00148011F5C4890380FE003003E6E48C8FC007E90
+3807F8060203130E00FE6E5A6E6C5A1400ED7F706C4B13036F5A6F7E6C6C6D6C5B701306
+6C6C496C130E6DD979FE5B281FF001F07F133C3C07F80FE03FC0F86CB539800FFFF0C690
+26FE000313C0D91FF0D9007FC7FC393E7DBB41>38 D<121C127FEAFF80A213C0A3127F12
+1C1200A412011380A2120313005A1206120E5A5A5A12600A1979B917>I<146014E0EB01
+C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B120F90C7FCA25A121EA2123E
+A35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A26C7EA26C7E1378A27F7F130E
+7FEB0380EB01C0EB00E01460135278BD20>I<12C07E12707E7E7E120F6C7E6C7EA26C7E
+6C7EA21378A2137C133C133E131EA2131F7FA21480A3EB07C0A6EB03E0B2EB07C0A6EB0F
+80A31400A25B131EA2133E133C137C1378A25BA2485A485AA2485A48C7FC120E5A5A5A5A
+5A13527CBD20>I<1530B3A8B912FCA2C80030C8FCB3A836367BAF41>43
+D<121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A1206120E5A5A5A
+12600A19798817>I<B512FCA516057F941C>I<121C127FEAFF80A5EA7F00121C09097988
+17>I<1506A2150E150CA2151C151815381530A215701560A215E015C0A214011580A214
+0315005C1406A2140E140CA2141C1418A214381430A21470146014E05CA213015CA21303
+91C7FCA25B1306A2130E130C131C1318A213381330A213701360A213E05BA212015B1203
+90C8FCA25A1206A2120E120CA2121C1218A21238123012701260A212E05AA21F537BBD2A
+>I<EB03F8EB1FFF90387E0FC09038F803E03901E000F0484813780007147C48487FA248
+C77EA2481580A3007EEC0FC0A500FE15E0B3007E15C0A4007F141F6C1580A36C1500A26C
+6C133EA26C6C5B6C6C5BEBF0013900F803E090387E0FC0D91FFFC7FCEB03F823397DB62A
+>I<EB01C013031307131F13FFB5FCA2131F1200B3B3A7497E007FB512F0A31C3779B62A>
+I<EB0FF0EB7FFE48B57E3903E03FE0390F000FF0001E6D7E001C6D7E486D7E5A6E7E1260
+12FE6CEC7F807FA56CC7FC121CC8FCEDFF00A25D14015D14035D4A5A4A5A5D4A5A4AC7FC
+147E5C495A14E0495A495A49C8FC011EEB01805B5B49130348481400485A485A90C75A48
+B6FC5A5A485CB6FCA321377CB62A>I<EB07F8EB3FFF90B512C03901F80FF03903C007F8
+48486C7E390E0001FEEA0F80391FE000FF7FA56C5A6C5AC7485AA25D14035D4A5A5DEC0F
+80027FC7FCEB1FFCECFF809038000FE06E7EEC01FC816E7EED7F80A216C0A2153F16E0A2
+121EEA7F80A2487EA316C0157F491480007EC7FC0070ECFF006C495A121E390F8003F839
+07F00FF00001B512C06C6C90C7FCEB0FF823397DB62A>I<1538A2157815F8A214011403
+1407A2140F141F141B14331473146314C313011483EB030313071306130C131C13181330
+1370136013C01201EA038013005A120E120C5A123812305A12E0B712F8A3C73803F800AA
+4A7E0103B512F8A325387EB72A>I<0006140CD80780133C9038F003F890B5FC5D5D1580
+92C7FC14FC38067FE090C9FCAAEB07F8EB1FFE9038780F809038E007E03907C003F0496C
+7E130000066D7E81C8FC8181A21680A4121C127F5A7FA390C713005D12FC00605C12704A
+5A6C5C6C1303001E495A6C6C485A3907E03F800001B5C7FC38007FFCEB1FE021397CB62A
+>I<EC3FC0903801FFF0010713FC90380FE03E90383F800790387E001F49EB3F80484813
+7F485A12075B000FEC3F0049131E001F91C7FC5B123FA3127F90C9FCEB01FC903807FF80
+39FF1E07E090383801F0496C7E01607F01E0137E497F16805BED1FC0A390C713E0A57EA4
+7F123F16C0A2001FEC3F807F000F15006D5B000714FE6C6C5B6C6C485A3900FE07F09038
+7FFFC0011F90C7FCEB03FC23397DB62A>I<12301238123E003FB612E0A316C05A168016
+000070C712060060140E5D5D00E014304814705D5DC712014A5A4AC7FC1406140E5CA25C
+1478147014F05C1301A213035C1307A2130FA3131F5CA2133FA5137FA96DC8FC131E233A
+7BB72A>I<EB03F8EB1FFF017F13C09038FC07F03901E001F83903C0007C4848133C90C7
+123E48141E000E141F001E80A3121FA26D5B6D131E7FD80FF85B6D137C01FF13786C6D5A
+6CEBE3E0ECF780C601FFC7FC6D5A6D6C7E010F13E0013F7F01F97F3901E07FFE48486C7E
+380F800F48486C1380001E010113C0487F007C143F0078EC1FE0150F00F81407481403A2
+1501A36C15C0A200781403007C15806C14076CEC0F006C6C131ED807E0137C3903F803F0
+C6B55A013F1380D907FCC7FC23397DB62A>I<EB03F8EB1FFF017F13C03901FC07E04848
+6C7E3907E001F8000F6D7E4848137E5B003F80A248C71380A25AED1FC0A516E0A56C143F
+A36C7E157F121F6C6C13FF6C6C13DF000313013901F0039F3900FC0F1FD93FFC13C0EB07
+F090C7FCA2153F1680A216005D120F486C137E486C5BA24A5A4A5A49485A381F000F001C
+EB1F80260F807FC7FC3807FFFE000113F838003FC023397DB62A>I<121C127FEAFF80A5
+EA7F00121CC7FCB2121C127FEAFF80A5EA7F00121C092479A317>I<121C127FEAFF80A5
+EA7F00121CC7FCB2121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A
+1206120E5A5A5A12600A3479A317>I<EF01C0EF0780EF1E0017F8EE03E0040FC7FC163C
+16F0ED03C0030FC8FC153CEC01F0EC07C0021EC9FC1478EB01E0EB0780011ECAFC13F8EA
+03E0000FCBFC123C12F0A2123C120FEA03E0EA00F8131EEB0780EB01E0EB0078141EEC07
+C0EC01F0EC003C150FED03C0ED00F0163C160FEE03E0EE00F8171EEF0780EF01C0322E79
+AB41>I<007FB812F8B912FCCCFCB0B912FC6C17F836147B9E41>I<12E01278121EEA07C0
+EA01F0EA003C130FEB03C0EB00F0143C140FEC03E0EC00F8151EED0780ED01E0ED007816
+1EEE07C0EE01F0EE003C170FEF03C0A2EF0F00173CEE01F0EE07C0041EC7FC1678ED01E0
+ED0780031EC8FC15F8EC03E0020FC9FC143C14F0EB03C0010FCAFC133CEA01F0EA07C000
+1ECBFC127812E0322E79AB41>I<EB3FE03801FFFE3907C03F80390E000FC0003CEB07F0
+00301303007014F8007C130100FE14FC7EA4127E003CEB03F8C7FCEC07F0A2EC0FE0EC1F
+80EC3F00147E147C5C495A5C495A5CA249C7FCA31306AA90C8FCA8130EEB3F80497EA56D
+5A010EC7FC1E3B7CBA27>I<1538A3157CA315FEA34A7EA34A6C7EA202077FEC063FA202
+0E7FEC0C1FA2021C7FEC180FA202387FEC3007A202707FEC6003A202C07F1501A2D90180
+7F81A249C77F167FA20106810107B6FCA24981010CC7121FA2496E7EA3496E7EA3496E7E
+A213E0707E1201486C81D80FFC02071380B56C90B512FEA3373C7DBB3E>65
+D<B712E016FC16FF0001903980007FC06C90C7EA1FE0707E707E707EA2707EA283A75F16
+035F4C5A4C5A4C5A4C5AEEFF8091B500FCC7FCA291C7EA7F80EE1FE0EE07F0707E707E83
+707EA21880177F18C0A7188017FFA24C13005F16034C5AEE1FF8486DEB7FF0B812C094C7
+FC16F832397DB83B>I<913A01FF800180020FEBE003027F13F8903A01FF807E07903A03
+FC000F0FD90FF0EB039F4948EB01DFD93F80EB00FF49C8127F01FE153F12014848151F48
+48150FA248481507A2485A1703123F5B007F1601A35B00FF93C7FCAD127F6DED0180A312
+3F7F001F160318006C7E5F6C7E17066C6C150E6C6C5D00001618017F15386D6C5CD91FE0
+5C6D6CEB03C0D903FCEB0F80902701FF803FC7FC9039007FFFFC020F13F002011380313D
+7BBA3C>I<B712C016F816FE000190398001FF806C90C7EA3FE0EE0FF0EE03F8707E707E
+177FA2EF3F8018C0171F18E0170F18F0A3EF07F8A418FCAC18F8A4EF0FF0A218E0A2171F
+18C0EF3F80A2EF7F0017FE4C5A4C5AEE0FF0EE3FE0486DEBFF80B8C7FC16F816C036397D
+B83F>I<B812FEA3000190388000076C90C8FC173F838383A383A31880170116C0A394C7
+FCA31501A21503150F91B5FCA3EC000F15031501A21500A21860A318E093C712C0A41701
+A3EF0380A21707A2170F173F177F486D903807FF00B9FCA333397EB838>I<B812F8A300
+01903880001F6C90C71201EE00FC177C173C171CA2170CA4170E1706A2ED0180A21700A4
+1503A21507151F91B5FCA3EC001F15071503A21501A692C8FCAD4813C0B612C0A32F397D
+B836>I<DBFF8013C0020FEBF001023F13FC9139FF803F03903A03FC000787D90FF0EB03
+CF4948EB00EF4948147F4948143F49C8121F485A4848150F48481507A248481503A2485A
+1701123F5B007F1600A448481600AB93B6FCA26C7E9338007FE0EF3FC0A2123F7F121FA2
+6C7EA26C7EA26C7E6C7E6C6C157F6D7E6D6C14FF6D6C14EFD90FF8EB03C7D903FEEB0783
+903A00FFC03F0191393FFFFC00020F01F0130002001380383D7CBA41>I<B648B512FEA3
+0001902680000313006C90C76C5AB3A491B6FCA391C71201B3A6486D497EB648B512FEA3
+37397DB83E>I<B612C0A3C6EBC0006D5AB3B3AD497EB612C0A31A397EB81E>I<013FB512
+E0A39039001FFC00EC07F8B3B3A3123FEA7F80EAFFC0A44A5A1380D87F005B0070131F6C
+5C6C495A6C49C7FC380781FC3801FFF038007F80233B7DB82B>I<B649B5FCA300010180
+9038007FF06C90C8EA3F80053EC7FC173C17385F5F4C5A4C5A4CC8FC160E5E5E5E5E4B5A
+ED0780030EC9FC5D153E157E15FF5C4A7F4A6C7E140E4A6C7E4A6C7E14704A6C7E4A6C7E
+14804A6C7E6F7EA26F7F707EA2707E707EA2707EA2707E707EA2707E707F8484486D497F
+B6011FEBFF80A339397DB841>I<B612E0A3000101C0C8FC6C90C9FCB3AD1718A5173817
+30A31770A317F0A216011603160FEE1FE0486D13FFB8FCA32D397DB834>I<B5933807FF
+F86E5DA20001F0FC002600DFC0ED1BF8A2D9CFE01533A3D9C7F01563A3D9C3F815C3A2D9
+C1FCEC0183A3D9C0FEEC0303A2027F1406A36E6C130CA36E6C1318A26E6C1330A36E6C13
+60A26E6C13C0A3913901FC0180A3913900FE0300A2ED7F06A3ED3F8CA2ED1FD8A3ED0FF0
+A3486C6D5A487ED80FFC6D48497EB500C00203B512F8A2ED018045397DB84C>I<B59138
+07FFFE8080C69238007FE06EEC1F80D9DFF0EC0F001706EBCFF8EBC7FCA2EBC3FEEBC1FF
+A201C07F6E7EA26E7E6E7E81140F6E7E8114036E7E168080ED7FC016E0153FED1FF0ED0F
+F8A2ED07FCED03FEA2ED01FF6F1386A2EE7FC6EE3FE6A2EE1FF6EE0FFEA216071603A216
+011600A2177E486C153E487ED80FFC151EB500C0140EA2170637397DB83E>I<EC03FF02
+1F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F049C76C7E01FE
+6E7E48486E7E49157E0003167F4848ED3F80A24848ED1FC0A2001F17E049150F003F17F0
+A3007F17F8491507A300FF17FCAC007F17F86D150FA3003F17F0A26C6CED1FE0A36C6CED
+3FC0000717806D157F000317006C6C15FEA26C6C4A5A017F4A5A6D6C495A6D6C495AD907
+E0EB1F80D903F8017FC7FC903900FE01FC91381FFFE0020390C8FC363D7BBA41>I<B712
+C016FC16FF0001D9800013C06C90C7EA1FE0707EEE03F883707EA2707EA21880A71800A2
+4C5AA24C5A5FEE0FF04C5AEEFF8091B548C7FC16F091CAFCB3A5487FB6FCA331397EB838
+>I<EC03FF021F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F0
+49C76C7E01FE6E7E48486E7EA24848157F0007178049153F000F17C049151F001F17E0A2
+4848ED0FF0A3007F17F8A2491507A200FF17FCAC007F17F8A26D150FA2003F17F0A26C6C
+ED1FE0A36C6CED3FC00007027C14804AB4FC3C03F80383807F003B01FC0701C0FEEC0E00
+2600FE0CEBE1FC017FEC63F8D93F8CEB77F0D91FCCEB3FE0D907EE14806DB449C7FC0100
+D981FC130CEC1FFF0203131C91C7001E131C161F183CEF807CEFC0F8EE0FFFA318F08218
+E07013C07013809338007E00364B7BBA41>I<B612FEEDFFE016F8000190388007FE6C90
+C76C7EEE3FC0707E707E707EA2707EA283A65FA24C5AA24C5A4C5AEE3F8004FFC8FCED07
+FC91B512E05E9138000FF0ED03F8ED00FE82707E707EA2161F83A583A6F00180A217F816
+0F1803486D01071400B66D6C5A04011306933800FE0ECAEA3FFCEF07F0393B7DB83D>I<
+D90FF813C090383FFE0190B512813903F807E33907E000F74848137F4848133F48C7121F
+003E140F007E1407A2007C140312FC1501A36C1400A37E6D14006C7E7F13F86CB47E6C13
+F8ECFF806C14E06C14F86C14FEC680013F1480010714C0EB007F020713E0EC007FED3FF0
+151F150FED07F8A200C01403A21501A37EA216F07E15036C15E06C14076C15C06C140F6D
+EB1F80D8FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190C7FC253D7CBA2E>I<
+003FB812E0A3D9C003EB001F273E0001FE130348EE01F00078160000701770A300601730
+A400E01738481718A4C71600B3B0913807FF80011FB612E0A335397DB83C>I<B6903807
+FFFEA3000101809038007FE06C90C8EA1F80EF0F001706B3B2170E6D150C80171C133F17
+186D6C14385F6D6C14F06D6C5C6D6C495A6D6CEB07806D6C49C7FC91387F807E91381FFF
+F8020713E09138007F80373B7DB83E>I<B500FC91387FFF80A30003018091380FFC006C
+90C8EA07E0715A6C705A6E1403017F93C7FCA280013F1506A26E140E011F150C80010F5D
+A28001075DA26E147001031560A26D6C5CA2806D4A5AA2ED8003027F91C8FCA291383FC0
+06A215E0021F5BA2EDF01C020F1318A26E6C5AA215FC02035BA2EDFEE002015BA26E6C5A
+A36FC9FCA3153EA2151CA3393B7EB83E>I<B5D8FC07B5D8F001B5FCA30007902780001F
+FEC7EA1FF86C48C7D80FF8EC07E000010307ED03C01B807F6C6F6C1500A26E5F017F6E6C
+1406A280013F4A6C5CA280011F4A6D5BEE067FA26D6C010E6D5BEE0C3FA26D6C011C6D5B
+EE181FA26D6C6F5BEE300FA26D6C6F485AEE6007A26D6C4CC7FC9338C003FCA203805D91
+3B7F818001FE06A203C1150EDA3FC3C7EAFF0CA203E3151CDA1FE6EC7F98A215F6DA0FFC
+EC3FF0A302075E4B141FA202035E4B140FA202015E4B1407A2020093C8FC4B80503B7EB8
+55>I<B500FE91383FFFE0A3000301E0913807FE00C649EC03F0017F6F5A606D6C5D6D6C
+140395C7FC6D6C1406A26D6C5C6D6C141C17186D6C143817306D6D5B6E6C13E05F91383F
+E0015F91381FF003DA0FF890C8FC1606913807FC0E160C913803FE1C913801FF185E6E13
+B016E0157F6F5AB3A24B7E023FB512C0A33B397FB83E>89 D<003FB7FCA39039FC0001FE
+01C0130349495A003EC7FC003C4A5A5E0038141F00784A5A12704B5A5E006014FF4A90C7
+FCA24A5A5DC712074A5AA24A5A5D143F4A5AA24A5A92C8FC5B495AA2495A5C130F4948EB
+0180A2495A5C137F495A16034890C7FC5B1203485AEE0700485A495C001F5D48485C5E48
+48495A49130FB8FCA329397BB833>I<EAFFFCA2EAFC00B3B3B3B3A7EAFFFCA20E5379BD
+17>I<EAFFFCA21200B3B3B3B3A712FFA20E537FBD17>93 D<007FB81280B912C0A26C17
+803204797041>95 D<EB1FE0EBFFFC3803E03F3907000F80390F8007E0486C6C7E13E06E
+7EA26E7E6C5A6C5AC8FCA4147FEB07FFEB3FE0EBFE00EA03F8EA0FF0EA1FC0123F485A90
+C7FC160C12FEA31401A26C13036CEB077C903980063E18383FC01E3A0FE0781FF03A03FF
+F00FE03A007F8007C026277DA52A>97 D<EA03F012FFA3120F1203B0EC1FE0EC7FF89038
+F1E03E9039F3801F809039F7000FC001FEEB07E049EB03F049EB01F85BED00FCA216FEA2
+167E167FAA167E16FEA216FC15016D14F8ED03F07F01EEEB07E001C6EB0FC09039C7801F
+00903881E07E903800FFF8C7EA1FC0283B7EB92E>I<EB03FC90381FFF8090387E03E039
+01F80070484813F83907E001FC380FC003A2EA1F80123F90380001F848EB00F01500A212
+7E12FEAA127E127FA26C14067F001F140E6D130C000F141C6C6C13386C6C13706C6C13E0
+39007C07C090381FFF00EB07F81F277DA525>I<ED0FC0EC03FFA3EC003F150FB0EB03F8
+EB1FFF90387E078F9038F801EF3903F0007F4848133F4848131FA24848130F123F90C7FC
+5AA2127E12FEAA127E127FA27EA26C6C131FA26C6C133F6C6C137F6C6CEBEFF03A01F801
+CFFF39007C078F90381FFE0FD907F813C0283B7DB92E>I<EB07F8EB1FFF90387C0FC039
+01F803E03903F001F0D807E013F8380FC0004848137CA248C7127E153E5A153F127E12FE
+A3B7FCA248C8FCA5127EA2127FA26C14037F001F14076C6C13060007140E6D131CD801F0
+13386C6C137090387E03E090381FFF80903803FC0020277EA525>I<147E903803FF8090
+380FC1E0EB1F8790383F0FF0137EA213FCA23901F803C091C7FCADB512FCA3D801F8C7FC
+B3AB487E387FFFF8A31C3B7FBA19>I<ED03F090390FF00FF890393FFC3C3C9039F81F70
+7C3901F00FE03903E007C03A07C003E010000FECF000A248486C7EA86C6C485AA200075C
+6C6C485A6D485A6D48C7FC38073FFC38060FF0000EC9FCA4120FA213C06CB512C015F86C
+14FE6CECFF804815C03A0F80007FE048C7EA0FF0003E140348140116F8481400A56C1401
+007C15F06CEC03E0003F1407D80F80EB0F80D807E0EB3F003901FC01FC39007FFFF00107
+90C7FC26387EA52A>I<EA03F012FFA3120F1203B0EC0FF0EC3FFCECF03F9039F1C01F80
+9039F3800FC0EBF70013FE496D7EA25BA35BB3A3486C497EB500C1B51280A3293A7EB92E
+>I<EA0380EA0FE0487EA56C5AEA0380C8FCAAEA03F012FFA312071203B3AA487EB512C0
+A312387EB717>I<EB01C0EB07F0EB0FF8A5EB07F0EB01C090C7FCAAEB01F813FFA31307
+1301B3B3A2123C127E00FF13F01303A214E038FE07C0127C383C0F00EA0FFEEA03F81549
+84B719>I<EA03F012FFA3120F1203B1913801FFFCA39138007FC01600157C15705D4A5A
+4A5A4AC7FC141E1438147814FC13F1EBF3FEEBF73F01FE7FEBF81F496C7E8114076E7E6E
+7E811400157E157F811680ED1FC0486CEB3FF0B500C0B5FCA3283A7EB92C>I<EA03F012
+FFA3120F1203B3B3AD487EB512C0A3123A7EB917>I<2703F00FF0EB1FE000FFD93FFCEB
+7FF8913AF03F01E07E903BF1C01F83803F3D0FF3800FC7001F802603F70013CE01FE14DC
+49D907F8EB0FC0A2495CA3495CB3A3486C496CEB1FE0B500C1B50083B5FCA340257EA445
+>I<3903F00FF000FFEB3FFCECF03F9039F1C01F803A0FF3800FC03803F70013FE496D7E
+A25BA35BB3A3486C497EB500C1B51280A329257EA42E>I<EB03FE90380FFF8090383E03
+E09038F800F84848137C48487F48487F4848EB0F80001F15C090C712074815E0A2007EEC
+03F0A400FE15F8A9007E15F0A2007F14076C15E0A26C6CEB0FC0000F15806D131F6C6CEB
+3F006C6C137EC66C13F890387E03F090381FFFC0D903FEC7FC25277EA52A>I<3903F01F
+E000FFEB7FF89038F1E07E9039F3801F803A07F7000FC0D803FEEB07E049EB03F04914F8
+49130116FC150016FEA3167FAA16FEA3ED01FCA26DEB03F816F06D13076DEB0FE001F614
+C09039F7803F009038F1E07E9038F0FFF8EC1FC091C8FCAB487EB512C0A328357EA42E>
+I<D903F813C090381FFE0190387E07819038FC01C33903F000E300071477484813374913
+3F001F141F485A150F48C7FCA312FEAA127FA37E6D131F121F6D133F120F6C6C137F6C6C
+13EF3901F801CF39007E078F90381FFE0FEB07F890C7FCABED1FE00203B5FCA328357DA4
+2C>I<3807E01F00FFEB7FC09038E1E3E09038E387F0380FE707EA03E613EE9038EC03E0
+9038FC0080491300A45BB3A2487EB512F0A31C257EA421>I<EBFF03000313E7380F80FF
+381E003F487F487F00707F12F0A2807EA27EB490C7FCEA7FE013FF6C13E06C13F86C7F00
+037FC67F01071380EB007F141F00C0EB0FC01407A26C1303A37E15806C13077EEC0F00B4
+131E38F3C07C38E1FFF038C03F801A277DA521>I<1318A51338A31378A313F812011203
+1207001FB5FCB6FCA2D801F8C7FCB215C0A93800FC011580EB7C03017E13006D5AEB0FFE
+EB01F81A347FB220>I<D803F0EB07E000FFEB01FFA3000FEB001F00031407B3A4150FA3
+151F12016D133F0000EC77F86D9038E7FF8090383F03C790381FFF87903A03FC07E00029
+267EA42E>I<B538803FFEA33A0FF8000FF06C48EB07E00003EC03C06D148000011500A2
+6C6C1306A26D130E017E130CA26D5BA2EC8038011F1330A26D6C5AA214E001075BA29038
+03F180A3D901FBC7FCA214FF6D5AA2147CA31438A227257EA32C>I<B53A1FFFE03FFEA3
+260FF8009038000FF86C48017EEB03E018C00003023EEB0180A26C6C013FEB0300A36C6C
+EC8006156FA2017E9038EFC00C15C7171CD93F01EBE01815830281EBF038D91F83143015
+0102C3EBF87090260FC6001360A2D907E66D5A02EC137CA2D903FCEB7F804A133FA20101
+92C7FC4A7FA20100141E4A130E0260130C37257EA33C>I<B538807FFFA33A03FE003FF0
+0001EC1F80000092C7FC017E131C6D13186D6C5AECC070010F5B6D6C5AECF180EB03FB6D
+B4C8FC6D5AA2147F804A7E8114CF903801C7E090380383F090380703F8EB0601496C7E01
+1C137E49137F01787F496D7E486C80000FEC3FF0D8FFFE90B51280A329247FA32C>I<B5
+38803FFEA33A0FF8000FF06C48EB07C00003EC03806C7E16007F00001406A2017E5BA213
+7F6D5BA26D6C5AA2ECC070010F1360A26D6C5AA214F101035BA2D901FBC7FCA214FF6D5A
+A2147CA31438A21430A214701460A25CA2EA7C0100FE5B130391C8FC1306EAFC0EEA701C
+6C5AEA1FF0EA0FC027357EA32C>I<003FB512FCA2EB8003D83E0013F8003CEB07F00038
+EB0FE012300070EB1FC0EC3F800060137F150014FE495AA2C6485A495AA2495A495A495A
+A290387F000613FEA2485A485A0007140E5B4848130C4848131CA24848133C48C7127C48
+EB03FC90B5FCA21F247EA325>I<EC01F8140FEC3F80ECFC00495A495A495AA2130F5CB3
+A7131F5C133F49C7FC13FEEA03F8EA7FE048C8FCEA7FE0EA03F8EA00FE137F6D7E131F80
+130FB3A7801307A26D7E6D7E6D7EEC3F80EC0FF814011D537ABD2A>I<126012F0B3B3B3
+B3A91260045377BD17>I<12FCEAFFC0EA07F0EA01FCEA007E7F80131F80130FB3A78013
+07806D7E6D7EEB007EEC1FF0EC07F8EC1FF0EC7E00495A495A495A5C130F5CB3A7131F5C
+133F91C7FC137E485AEA07F0EAFFC000FCC8FC1D537ABD2A>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fi ecbx1440 14.4 34
+/Fi 34 118 df<EE7FFC031FB57E4AB612E0020715F8023F9038C00FFC913AFFFC0001FE
+4901F0EB007F010701C0EB03FF4949497F4990C75A5B5C495A4D7F01FF6F5B5CA27190C7
+FC715AEF00F895C8FCAA0407B512C0BAFCA5C601F8C7120F83B3B3A6B6D8F807B612C0A5
+42547DD349>28 D<B712E0AB230B7F9F2C>45 D<151E153E15FE1403140F147FEB07FF00
+03B5FCB6FCA3EBF87FEAFC00C7FCB3B3B3A6007FB712FCA52E4E76CD42>49
+D<EC1FFE49B512F0010F14FC013FECFF804915E02701FF803F7F2703FC000713FCD807F0
+01017F48486D7FD81F806E138048C87E7013C0D87FE016E001F8806D16F000FF817F7013
+F8A56C5AA26C5A6C5AEA0380C914F05EA218E05E18C05E18804C13005F4C5A4C5A5F4B5B
+4B5B4B5B94C7FCED0FFC4B5A4B5AED7FC04B5A4A90C8FCEC03FC4A5A4A4814F84A5A4A5A
+4AC8FC02FEEC01F0495A495A495A5CD90F80140349C8FC013E1507017FB7FC90B812E05A
+5A5A5A5A5A5AB9FC18C0A4354E7ACD42>I<913807FFC0027F13FC0103B67E010F15E090
+261FF80313F890267FC0007F01FEC7EA3FFE48488148486E138013FE486C6C6D13C08048
+17E080A66C5B18C06C5B6C90C75AD80038168090C8FC4C1300A24C5A5F4C5A4B5B4B13C0
+030F5BDB7FFEC7FC91387FFFF816C016FCEEFF80DA000313E09238007FF8EE3FFE707E70
+138018C07013E018F07013F8A218FC82A218FEA3EA03C0EA0FF0EA3FFC487EA2B5FCA218
+FCA25E18F8A26C4816F0495C4916E0D83FE04A13C06C485CD80FF04A1380D807FE91387F
+FE003B03FFE003FFFC6C90B65A6C6C15E0010F92C7FC010114FCD9001F1380374F7BCD42
+>I<17FC1601A216031607160FA2161F163F167FA216FF5D5DA25D5D5D167F153E157E15
+FC15F8EC01F01403EC07E015C0EC0F80141FEC3F00143E5C14FC495A5C495A1307495A5C
+49C7FC5B137E137C5B1201485A5B485A120F485A90C8FC123E127E5ABA1280A5C901FCC7
+FCAF021FB71280A5394F7CCE42>I<486C150601F0153E01FEEC01FED9FFF0133F91B65A
+5F5F5F5F5F94C7FC16FC5E16E093C8FC15FC01F0138091CAFCAC913807FF80023F13F891
+B512FE01F36E7E9026FFFC0113E09139E0007FF891C76C7E496E7E01F86E7E5B70138049
+16C0C9FC18E08218F0A418F8A31203EA0FE0EA3FF8487EA212FF7FA218F0A25B5E6C4816
+E05B01C016C06CC85A18806C6C4A13007FD80FF04A5A6C6CECFFFCD803FE4913F02701FF
+E00F5B6C6CB612806D92C7FC010F14F8010114C09026003FFCC8FC354F7ACD42>I<EA07
+E0EA1FF8EA3FFCEA7FFEA2B5FCA6EA7FFEA2EA3FFCEA1FF8EA07E0C7FCB3A3EA07E0EA1F
+F8EA3FFCEA7FFEA2B5FCA6EA7FFEA2EA3FFCEA1FF8EA07E0103576B425>58
+D<932603FFF01407047F01FF5C0307B600E05B033F03F85B92B700FE5B02039126C003FF
+5B020F01F8C7EA3FC1023F01C0EC0FE391B5C80003B5FC4901FC814949814901E082011F
+498249498292CA7E4948834948835A4A83485B4885A2484984A2485B87A2485B87A25AA2
+98C8FC91CFFCA2B5FCAE7E067FB7128080A37E95C76C90C7FC807EA36C7FA26C7FA26C7F
+7E806C7F137F6D7E816D6D93B5FC01077F6D01F85D6D7F6D01FF5D023F01E0EC0FEF020F
+01FCEC3FE30203903AFFE001FF81020091B6C6FC033F03FC133F030703F0130FDB007F02
+801303040301F8CAFC595479D267>71 D<B81280A5D8000701F0C7FCB3B3B3B2B81280A5
+29527DD130>73 D<B812E0A5D8000F01E0CAFCB3B3A91AF8A419011AF0A51903A31907A2
+190F1AE0191FA2193F197F19FF60180760187F0503B5FCBB12C0A545527CD14F>76
+D<B600F84BB612FC818181A2D800076E91C7383FE00070EE0F80828214DF02CF7F02C77F
+8202C37F14C102C0806F7F836F7F816F7F6F7F83816F7F6F80707F8482707F707F707F84
+82707F7080717F8583717F717F85717F83717F7114801AC07213E0847213F07213F81AFC
+7213FE847213FF72148F1BCF7313EF857313FF85A285858585A286868686A286868686EB
+1FF0B600FE177F1B3F1B1F1B0FA25E527CD167>78 D<B912FCF0FFE019FE737E1AE0D800
+0F01E0C7003F7F060313FC06007F737E7313807313C07313E0851BF0A21BF885A21BFCA9
+1BF8A3611BF0A21BE04F13C0614F13804F13004F5A060713F8063F5B92B812C097C7FC19
+F8198003E0CBFCB3AEB712FEA54E527CD15A>80 D<93381FFF800303B512FC033FECFFC0
+92B712F00207D9F80113FE021F903AC0003FFF804A48C700077FDAFFF8020113F049496E
+7F49496F7E49496F7E49496F7E4990C96C7F4948707F4948707F01FF854849707F4A8248
+86A24849717E48864A83A2481B80A248497113C0A4481BE0A291CB7EA3B51AF0AF6C1BE0
+A36E5FA26C1BC0A36C1B806E5FA26C1B006E5F6C62A26C6DD903FC4A5A6CDB0FFF5D6E49
+EBC0016C4B01E05C6D6C90277E07F0035B6E9039F801F807902A3FFF01F000780F5B6D04
+7C5C6DD981E06D4890C7FC6D01E191381F7FFE010101F1EDFFF86DD9F9F06D5BDA3FFF16
+C06E6D013F5B02079027FE01FFFEC8FC020190B612F8DA003F4B141003071838DB001FEB
+83F893C7EA03FC1C7885726C14F8F2C003F2F01F97B512F084A31CE085A27314C01C8085
+1C00735B735B735B735B9638003FC0556A79D263>I<B912E018FF19F019FE737ED80007
+01F0C714E0060F7F060313FC06007F737E737F8587737FA28785A287A863A26163636163
+4F90C8FC4F5A4F5A06035B060F13E095B5128092B748C9FC19F019C019F09226F0000713
+FC050013FF063F7F727F727F727F727FA2727FA28486A886A71D707513F8A2851C017301
+C013F0A273EBE003B86C6D9038F007E0739038FC1FC0070190B51280736C1400080F5BCE
+13F85D537CD162>I<DA0FFE141C91B500F0133C010702FC137C011F02FF13FC017F15C1
+9026FFF00113E148903980001FFB4890C7EA07FFD807FC14014848804848153F171F4848
+150FA2007F1607491503A2170112FFA217007FA26D167CA27F7F6D93C7FC6C7E14C014F8
+ECFF806C14F8EDFFC06C15FC6CEDFF8017F06C16FC6C826C707E6C836D82011F82010782
+13016D6C81020781EC007F030380ED003F040314801600173F837113C0838312F883A383
+7EA319807EA26C5E19007F6D4B5A7F6D4B5A01FC4B5A6D151FD9FFC04A5AD97FF8ECFFE0
+28FE1FFF80075B010790B6C7FCD8FC0115FC486C6C14F048010F14C0489026007FFCC8FC
+3A5479D249>I<003FBB12FCA59126C0007FEB000301FCC7ED003FD87FF0F00FFE491807
+49180349180190C81600A2007E1A7EA3007C1A3EA500FC1A3F481A1FA6C91700B3B3AC49
+B912C0A550517BD05B>I<EC3FFE0107B512E0011F14FC017F14FF2701FFC00F13C02703
+FE00037F486C01007F6E6D7E486D80707EA2707EA3707F6C5B6C90C7FC6C5AC9FCA60307
+B5FC0203B6FC147F0103B7FC011FEBF00F017F1300EBFFFC000313F04813C0485B4890C7
+FC5A5B485AF081F012FF5BA35EA26D5C127F6D5C003F03F713C36DD901E314E06CD9C007
+14FF00079026F01F8114C06C90B5C61480C602FC6D1300011F01F0EB3FFC01010180EB07
+F03C387CB642>97 D<913803FFE0023F13FE91B67E010315E0010F9038003FF8D93FFCEB
+07FC4948497E4948131F4849497E485B485BA24890C7FC5A5B003F6F5A705A705A007F92
+C8FC5BA312FFAD127F7FA3123F7F6CEE0F80A26C6D141F18006C6D5C6C6D143E6C6D147E
+6C6D5C6D6C495A6DB4EB07F0010F9038C01FE06D90B5128001014AC7FCD9003F13F80203
+138031387CB63A>99 D<943803FF80040FB5FCA5EE003F170FB3A4913803FF80023F13F8
+49B512FE0107ECFF8F011F9038C03FEF90273FFE0007B5FCD97FF8130149487F48498048
+4980484980488291C8FC5A5B123FA2127F5BA312FFAD127FA37F123FA3121F7F6C5E6C6D
+5C5F6C6D91B5FC6C6D5B6C6D4914E0D97FFCD90FEFEBFF80D91FFFEB7F8F010790B5120F
+010114FC6D6C13E00207010049C7FC41547CD249>I<913807FF80027F13F849B512FE01
+076E7E011F010313E0903A3FFC007FF0D97FF06D7E49486D7E4849130F48496D7E488248
+90C77E1880485A82003F17C0A3485A18E082A212FFA290B8FCA401FCCAFCA6127FA37F12
+3FA2EF03E06C7E17076C17C06C6D140F18806C6D141F6C6DEC3F006C6D147ED97FFC495A
+D91FFFEB07F86D9038E03FF0010390B512C001005D023F01FCC7FC020113E033387CB63C
+>I<ED1FF8913803FFFE020FEBFF80023F14C09139FFF83FE001039038E0FFF049138049
+010113F85BEB3FFEA2EB7FFCA26F13F0495AEE7FE0EE1F8093C7FCAEB712C0A5C601F8C8
+FCB3B3A7B612FEA52D547CD328>I<DA1FFE14FE49B539E007FF80010FDAFC1F13C0013F
+DAFF7F13E090267FF807EBFF072701FFE001EBF07F48497E484990387FF83F91C7003F14
+C048EEFC1F489338FE070049021F90C7FCA2003F82A9001F5EA26D143F6C5E6C5E6E137F
+6C6D495A6C6D485B6CD9F80713804890B6C8FCD803EF14FC01C114E02707C01FFEC9FC49
+CBFCA2487EA37FA27F13FC90B612FE6CEDFFF017FCEFFF806C8318F06C836C837F48B87E
+1207D80FFCC700037F4848EC003F4848150F48486F138083485A83A56D5D007F18006D5D
+003F5F6C6C4B5A01FE153FD807FFED7FF06C01C049485AC601FC011F1380013FB648C7FC
+010F15F8010115C0D9000F01F8C8FC3B4F7CB542>I<EB3FF8B5FCA51203C6FCB3A4EE1F
+FC93B57E030314E0030F14F892391FC07FFC92397E003FFE03F86D7EECF9F04B6D7FECFB
+C0ECFF8092C76C7FA25CA25CA45CB3ACB6D8F807B612C0A542537CD249>I<133FEBFFC0
+487F487FA2487FA66C5BA26C5B6C5B013FC7FC90C8FCAEEB1FF8B5FCA512017EB3B3A6B6
+12F0A51C547CD324>I<EB3FF8B5FCA51203C6FCB3B3B3B1B612F8A51D537CD224>108
+D<D93FF0D91FF84AB47EB591B56C010F13F8030302E0013F13FE030F6E90B6FCDB3F8090
+27F803F80F7F922A7E007FFC07E0077F000302F890283FFE0F80037FC6D9F1F0011F4948
+7EDAF3E0DAFF3E814B153CDAF7805D92C76C496D7F14FF4A5EA24A5EA34A5EB3ADB6D8F8
+0FB66CB612F8A565367BB56E>I<D93FF0EB1FFCB591B57E030314E0030F14F892391FC0
+7FFC92397E003FFE000302F86D7EC6EBF1F04B6D7FECF3C0ECF78092C76C7F14FF5CA25C
+A45CB3ACB6D8F807B612C0A542367CB549>I<913801FFC0023F13FE91B67E010315E001
+0F018013F8903A3FFC001FFED97FF0EB07FF49486D7F48496D7F48496D7F91C8127F4883
+488349153F001F83A2003F8349151FA2007F83A400FF1880AC007F1800A3003F5F6D153F
+A2001F5FA26C6C4B5AA26C6D4A5A6C5F6C6D495B6C6D495B6D6C4990C7FCD93FFCEB1FFE
+6DB46CB45A010790B512F0010115C0D9003F49C8FC020313E039387CB642>I<D93FF8EB
+7FF0B50107B5FC031F14C0037F14F09126F9FF0013FCDAFFF8EB3FFF000302E0010F7FC6
+02806D7F92C76C7F4A824A804A6E7F85187F85A2183F85A4721380AD4E1300A44E5AA261
+18FF616E5C616E4A5B6E4A5B6F495B03E04990C7FC6FEB7FFE913AF9FE01FFF802F8B65A
+033F14C0030749C8FC030013E093CAFCB1B612F8A5414D7DB549>I<90393FF001FCB590
+380FFF804B13E0037F13F09238FE1FF89138F1F83F00019138F07FFC6CEBF3E015C0ECF7
+80A2ECFF00EE3FF84AEB1FF0EE0FE093C7FC5CA45CB3ABB612FEA52E367DB535>114
+D<903903FFC00E011FEBFC1E90B6127E000315FE3907FE003FD80FF0130F484813034848
+1301491300127F90C8127EA248153EA27FA27F01F091C7FC13FCEBFF806C13FEECFFF06C
+14FE6F7E6C15E06C816C15FC6C81C681133F010F15801301D9000F14C0EC003F030713E0
+150100F880167F6C153FA2161F7EA217C07E6D143F17807F6DEC7F0001F85C6DEB03FE90
+39FF801FFC486CB512F0D8F81F14C0D8F00791C7FC39E0007FF02B387CB634>I<147CA6
+14FCA41301A31303A21307A2130F131F133F137F13FF1203000F90B512FEB7FCA426007F
+FCC8FCB3A9EE0F80ABEE1F006D7EA2011F143E806D6D5A6DEBC1F86DEBFFF001005C023F
+1380DA03FEC7FC294D7ECB33>I<D93FF8913801FFC0B50207B5FCA50003ED001FC61607
+B3AE5FA35FA25F137F5F6D6C14F7DC01E713F06D6CD907C7EBFFC0903A0FFF801F876D90
+B51207010114FC6D6C13F0020701C091C7FC42377CB549>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fj ecrm0900 9 5
+/Fj 5 109 df<123C127E12FFA4127E123C08087A8715>46 D<EB7F803803FFF0380F80
+FC381C003E003F133F6D6C7E6E7EA26E7EEA1F00C7FCA4EB01FF131FEBFF873803FC07EA
+0FF0EA1FC0EA3F80127F13004815C05AA3140FA26C131F6C133B3A3F8071F180391FC1E1
+FF2607FFC013003900FE003C22237DA126>97 D<EA03F012FFA312071203AEEC3F80ECFF
+E09038F3C0F89038F7007E01FE7F49EB1F8049EB0FC05BED07E016F0A2150316F8AA16F0
+150716E0A2ED0FC07F6DEB1F8001ECEB3F0001CF137C90388381F8903801FFE0C76CC7FC
+25357EB32B>I<EA03F012FFA312071203AEEC1FC0EC7FF09038F1E0FC9038F3807C9038
+F7007E13FE497FA25BA25BB3486CEB7F80B538C7FFFCA326347EB32B>104
+D<EA07E012FFA3120F1207B3B3A7EA0FF0B5FCA310347EB315>108
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fk ecbx0900 9 7
+/Fk 7 117 df<ED1F80A24B7EA24B7EA34B7EA24A7FA34A7FA24A7F15CFA2020F7F1587
+021F801503023F80EC3E01A2027E80EC7C0002FC804A137FA20101814A133F0103814A13
+1FA249B67EA24981A290271F8000077F91C77EA24982013E80017E82017C80A201FC8249
+157FB500F0013FB512F0A43C347DB343>65 D<EB7FFE0003B512E04814F8390FF00FFC39
+1FF803FF806E138016C0157F6C5A6C5AEA0180C8FCEC7FFF010FB5FC90B6FC0003EBF07F
+000F1300EA1FF8485A485A485A5BA315FF7F007F5B6D4813E03A3FF80FBFFF000FB5121F
+0003EBFC0F39007FE00728217EA02B>97 D<EA01FC12FFA4120F1207ADEC0FF8EC7FFF01
+FDB512C09039FFF01FF09138800FF84A6C7E496D7E496D7EA2178081A217C0A91780A25D
+1700A26D495A6D495A6E485A9039F7E03FF001E1B512C0D9C07F90C7FC9038801FF02A34
+7DB331>I<903807FF80013F13F090B512FC3903FE01FE4848487EEA0FF8EA1FF0EA3FE0
+A2007F6D5A496C5A153000FF91C7FCA9127F7FA2003FEC07807F6C6C130F000FEC1F00D8
+07FE133E3903FF80FCC6EBFFF8013F13E0010790C7FC21217DA027>I<3901F81F8000FF
+EB7FF0ECFFF89038F9E3FC9038FBC7FE380FFF876C1307A213FEEC03FCEC01F8EC006049
+1300B1B512F0A41F217EA024>114 D<9038FFE1C0000713FF5A383F803F387E000F1407
+5A14037EA26C6CC7FC13FCEBFFE06C13FC806CEBFF80000F14C06C14E0C6FC010F13F0EB
+007F140F00F0130714037EA26C14E06C13076CEB0FC09038C01F8090B5120000F913FC38
+E03FE01C217DA023>I<133CA5137CA313FCA21201A212031207001FB51280B6FCA3D807
+FCC7FCB0EC03C0A79038FE078012033901FF0F006C13FEEB3FFCEB0FF01A2F7EAE22>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fl ecrm1200 12 25
+/Fl 25 122 df<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A3120113
+80120313005A1206120E5A5A5A12600B1D78891B>44 D<14FF010713E090381F81F89038
+3E007C01FC133F4848EB1F8049130F4848EB07C04848EB03E0A2000F15F0491301001F15
+F8A2003F15FCA390C8FC4815FEA54815FFB3A46C15FEA56D1301003F15FCA3001F15F8A2
+6C6CEB03F0A36C6CEB07E0000315C06D130F6C6CEB1F806C6CEB3F00013E137C90381F81
+F8903807FFE0010090C7FC28447CC131>48 D<EB03FE90381FFFC0017F13F03901F80FFC
+3903C001FE48486C7E000EC7EA7F8048EC3FC0ED1FE04815F00030140F007015F8006014
+07126CB415FC7F7F1503A46C4813076CC7FCC8FC16F8A2150F16F0151F16E0A2ED3FC0ED
+7F8016005D5D4A5A4A5A4A5A5D4A5A4A5A4AC7FC147C5C5C495A495A495A49C7120C131E
+5B013814185B5B485A4848143848C81230000E1570001FB612F0A25A5AB712E0A326427B
+C131>50 D<EC07FCEC3FFF91B512C0903903FC03E0903907E000F0D91FC0133849C71258
+017EEB01FC01FE1303491307485A485AA24848EB03F8000FEC01F092C7FC485AA3485AA3
+127FA29038007F80903801FFF090380780FC39FF0E003E49EB1F8049EB0FC049EB07E013
+6001E0EB03F04914F8150116FC5BED00FEA390C812FFA47EA57F123FA216FE121F15016D
+14FC120FED03F86C7EED07F06C6C14E06C6CEB0FC06C6CEB1F80017EEB3F0090383F80FE
+90380FFFF8010313E00100138028447CC131>54 D<16C04B7EA34B7EA34B7EA34B7EA3ED
+19FEA3ED30FFA203707FED607FA203E07FEDC03FA2020180ED801FA2DA03007F160FA202
+06801607A24A6D7EA34A6D7EA34A6D7EA20270810260147FA202E08191B7FCA249820280
+C7121FA249C87F170FA20106821707A2496F7EA3496F7EA3496F7EA201788313F8486C83
+D80FFF03037FB500E0027FEBFFC0A342477DC649>65 D<B8FC17E017FC00019039C00003
+FF6C6C4801007FEF3FC0717E717E717E84170384170184A760A21703601707604D5A4D5A
+EF7FC04DC7FCEE03FEEE3FF091B65A17FC0280C7B47EEF1FC0EF0FF0717E717E717E717E
+1980187F19C0A2183F19E0A8F07FC0A2198018FF4D1300A24D5AEF0FFC4D5AEF7FE04848
+6C903803FFC0B9C7FC17FC17C03B447CC345>I<B712FEEEFFE017F800019039C00007FE
+6C6C48903800FF80EF3FC0EF0FF0717E717EEF00FE8484F03F80F01FC0A2F00FE019F018
+0719F8A2180319FCA3F001FEA419FFAD19FEA3180319FCA319F8180719F0180F19E0A2F0
+1FC0F03F80A2F07F0018FE4D5A4D5AEF0FF0EF3FE0EFFF8048486C010790C7FCB812FC17
+E04CC8FC40447CC34A>68 D<B56C933807FFFC6E5EA20001F1FE0026006FE0EE1BF8A3D9
+67F01633A2D963F81663A3D961FC16C3A3D960FEED0183A2027FED0303A36E6C1406A36E
+6C140CA26E6C1418A36E6C1430A36E6C1460A26E6C14C0A36E6CEB0180A3037FEB0300A2
+92383F8006A36F6C5AA36F6C5AA26F6C5AA36F6C5AA36F6C5AA26FB45AA370C7FC13F0A2
+486C143ED80FFFEF0FFEB500F0011C0107B512FCA34E447BC359>77
+D<003FB912F8A3903BF0001FF8001F01806D481303003EC7150048187C0078183CA20070
+181CA30060180CA5481806A5C81600B3B3A54B7EED7FFE49B77EA33F447DC346>84
+D<B600C0010FB5FCA3000101E0C813F026007F80ED1F80F00F00A21806B3B3A7180E6D6C
+150CA2181C131F6E1518010F163818306D6C1570606D6C14016D6C5D6D6CEC0780027F4A
+C7FC6E6C131EDA1FE0137C913907FC03F00201B55A6E6C1380DB07FCC8FC40467CC349>
+I<EB07FC90383FFF809038F80FE03903C003F048C66C7E000E6D7ED80FC0137E486C137F
+6D6D7EA36F7EA26C5AEA0380C8FCA4EC0FFF49B5FC90380FFE1FEB3FC0EBFF00EA03FC48
+5A485A485A485A127F5B176048C7FCA3153FA36D137F007F14EF6D9038C7E0C0003F1301
+3A1FE00783F13B07F81E03FF802701FFFC0113003A001FE0007C2B2E7CAC31>97
+D<EC7F80903803FFF090380FC07C90383F000F01FCEB03804848EB01C00003140F4848EB
+1FE049133F120F485AA2485AED1FC0007FEC070092C7FCA290C9FC5AAB7E7FA2123F1630
+7F001F15706C6C146016E06C6C14C06C6C13010001EC03806C6CEB0700013F131E90381F
+C078903807FFF001001380242E7DAC2B>99 D<167FED3FFFA315018182B3EC7F80903803
+FFF090380FC07C90383F000E017E1307496D5AD803F87F48487F5B000F81485AA2485AA2
+127FA290C8FC5AAB7E7FA2123FA26C7EA2000F5D7F6C6C5B00035C6C6C9038077F806C6C
+010E13C0013F011C13FE90380FC0F8903803FFE09026007F0013002F467DC436>I<EB01
+FE903807FFC090381F03F090387E00FC49137E48487F485A4848EB1F80000F15C049130F
+121F484814E01507A2007F15F090C7FCA25AA390B6FCA290C9FCA67EA27FA2123F16306C
+7E1670000F15606D14E06C6C14C0000314016C6CEB03806C6CEB0700013E131E90381F80
+F8903803FFE0010090C7FC242E7DAC2B>I<EE0F80D901FCEB7FE0903A0FFF81F0F09039
+3F07E3819039FC01FF033A01F800FE014848017E13E00007027FC7FC497F000F8149131F
+001F81A9000F5D6D133F000792C7FC6D5B0003147E6C6C5B6D485A3903BF07E090380FFF
+80260701FCC8FC90CAFCA25AA37F6C7E7F90B512F86C14FF16E06C15F86C6C8048B67E3A
+07C0000FFF48481300003FC8EA3F80003E151F48ED0FC0A2481507A56C150F007C168000
+7E151F003E16006C153E6C6C5CD807E0495AD801F8EB07E0D8007FEB3F8090261FFFFEC7
+FC010113E02C427DAC31>103 D<EA01E0EA07F8A2487EA46C5AA2EA01E0C8FCADEA01FC
+12FFA3120712031201B3B0487EB512F8A315437DC21C>105 D<EA01FC12FFA312071203
+1201B3B3B3A5487EB512F8A315457DC41C>108 D<3901FC01FE00FF903807FFC091381E
+07F091383801F8000701707F0003EBE0002601FDC07F5C01FF147F91C7FCA25BA35BB3A8
+486CECFF80B5D8F83F13FEA32F2C7DAB36>110 D<EC7F80903803FFF090380FC0FC9038
+3E001F496D7E496D7E48486D7E48486D7E48486D7E000F81A24848147E003F157FA290C8
+7E481680A44816C0AA6C1680A26D147F003F1600A2001F157E6D14FE000F5D6D13010007
+5D6C6C495A6C6C495A6C6C495A013E49C7FC90381FC0FE903807FFF89038007F802A2E7D
+AC31>I<3903F803F000FFEB1FFCEC3C3EEC707F0007EBE0FF3803F9C000015B13FBEC00
+7E153C01FF13005BA45BB3A748B4FCB512FEA3202C7DAB26>114
+D<90383FE0183901FFFC383907E01F78390F0003F8001E1301481300007C1478127800F8
+1438A21518A27EA27E6C6C13006C7E13FC383FFFE06C13FC6C13FF6C14C06C14E0C614F0
+011F13F81300EC0FFC140300C0EB01FE1400157E7E153EA27EA36C143C6C147C15786C14
+F86CEB01F039F38003E039F1F00F8039E07FFE0038C00FF01F2E7DAC26>I<1306A5130E
+A4131EA3133E137EA213FE12011207001FB512F0B6FCA2C648C7FCB3A4150CAA017E131C
+017F1318A26D133890381F8030ECC070903807E0E0903801FFC09038007F001E3E7EBC26
+>I<D801FC147F00FFEC3FFFA300071401000380000181B3A85EA35DA212006D5B017E90
+38077F80017F010E13C06D011C13FE90380FC078903803FFF09026007F8013002F2D7DAB
+36>I<B539F001FFFCA3000790C7EA7FE06C48EC1F8000011600160E1200160C017F5CA2
+80013F5CA26E1370011F146080010F5CA2ECF00101075CA26D6C48C7FCA26E5A01011306
+A26D6C5AA214FF6E5AA215B8EC3FB015F06E5AA36E5AA26E5AA36EC8FC2E2C7EAA33>I<
+B539F001FFFCA3000790C7EA7FE06C48EC1F8000011600160E0000150C6D141C6D1418A2
+6E1338013F1430A26D6C5BA26E13E0010F5CA26D6C485AA2ECF803010391C7FCA2903801
+FC06A2ECFE0E0100130CA2EC7F18A215B8EC3FB0A2EC1FE0A36E5AA26E5AA36EC8FCA214
+06A35CA25CA2123C007E5BB4FC5CA25CEAFE01387C0380D87007C9FCEA3C1EEA0FFCEA03
+F02E3F7EAA33>121 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fm ecbx1200 12 47
+/Fm 47 123 df<0118140C017C143E01FC147E48485C4848495A495C4848495A4848495A
+001F140F90C75B003E4AC7FCA2003C141E007C143E0078143CA200F8147CA2481478D8F1
+F014F8D8F7FCEB7BFEB46CEB7FFF6D1580028014C0A36C80A36C806C496C13806C486D13
+006C486D5AD801F0EB00F82A2283C427>16 D<D807C0EB03E0D81FF0EB0FF8486C497E48
+6C497E486C497E6D1580A3028014C0A36C806C80D81FF7EB0FFBD807C7EB03E3D80007EB
+0003010F1407A291C71380A249140F011E1500013E5CA249143E01FC147E49147C48485C
+4848495A000714034848495A4848495A90C75B000C0206C7FC2A2281C427>I<ED0FFF4A
+B512C0020F14F0027F80903A01FFF803FC499038C000FE010FEB00034948497E49485B5C
+495A4C138001FF6E13005CA3705AEE01F893C8FCA74BB51280B9FCA5C69038E00003B3B0
+007FD9FFC1B6FCA538467EC53E>28 D<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA
+3FF8EA1FF0EA07C00F0F788E1F>46 D<EC3FF849B5FC010F14E0013F14F890397FF01FFC
+9039FFC007FE4890380001FF48486D1380000716C049147F000F16E049143F001F16F0A2
+003F16F8A249141F007F16FCA600FF16FEB3A3007F16FCA56C6CEC3FF8A3001F16F0A200
+0F16E06D147F000716C06D14FF6C6C4913806C6D4813006C6D485A90397FF01FFC6DB55A
+010F14E0010314809026003FF8C7FC2F427CC038>48 D<EC03C01407141F147FEB03FF13
+3FB6FCA413C3EA0003B3B3ADB712FCA5264177C038>I<ECFFE0010F13FE013F6D7E90B6
+12E0000315F82607FC0313FE3A0FE0007FFFD81F806D138048C7000F13C0488001C015E0
+01F07F00FF6E13F07F17F881A46C5A6C5A6C5AC9FC17F05DA217E05D17C04B13804B1300
+A2ED1FFC4B5A5E4B5A4B5A4A90C7FC4A5A4A5AEC0FF04A5AEC3F804AC7127814FE495A49
+4814F8D907E014F0495A495A49C8FC017C140149140348B7FC4816E05A5A5A5A5AB8FC17
+C0A42D417BC038>I<ECFFF0010713FF011F14C0017F14F049C66C7ED803F8EB3FFED807
+E06D7E81D80FF86D138013FE001F16C07FA66C5A6C4815806C485BC814005D5E4B5A4B5A
+4B5A4A5B020F1380902607FFFEC7FC15F815FF16C090C713F0ED3FFCED0FFEEEFF80816F
+13C017E0A26F13F0A217F8A3EA0FC0EA3FF0487EA2487EA217F0A25D17E06C5A494913C0
+5BD83F80491380D81FF0491300D80FFEEBFFFE6CB612F800015D6C6C14C0011F49C7FC01
+0113E02D427BC038>I<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715
+C7EC0F87EC1F07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B
+485A485A485A120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A53141
+7DC038>I<0007150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8
+FC01C0C9FCAAEC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E
+01F06D13804915C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317
+F05B5D6C4815E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEB
+FFFC6CB612F0C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0
+027F13FC49B6FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE04849
+5A5A1400485A120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381F
+FF8000FF017F13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C0
+5B6F13E0A24915F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D
+4913806C018014006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC903800
+3FF02D427BC038>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A248168000
+7EC8EA3F00007C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A
+5A14035D14074A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A
+6D5A2F447AC238>I<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07
+C0C7FCAEEA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07C00F2C78AB
+1F>58 D<1A60F101F01907191FF17FC0953801FF00F007FCF01FF0F07FC04D48C7FCEF07
+FCEF3FF0EFFFC0040390C8FCEE0FFCEE3FE0EEFF80DB03FEC9FCED0FF8ED3FE0EDFF80DA
+07FECAFCEC1FF8EC7FE0903801FF80D907FCCBFCEB1FF0EB7FC04848CCFCEA07FCEA1FF0
+EA7FC048CDFCA2EA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FC903801FF809038
+007FE0EC1FF8EC07FE913800FF80ED3FE0ED0FF8ED03FE923800FF80EE3FE0EE0FFCEE03
+FF040013C0EF3FF0EF07FCEF01FF9438007FC0F01FF0F007FCF001FF9538007FC0F11FF0
+19071901F10060444277B957>60 D<126012F812FE6C7EEA3FE0EA0FF8EA03FEC66C7EEB
+3FE0EB0FF8EB03FE903800FFC0EC3FF0EC0FFCEC03FF9138007FC0ED1FF0ED07FCED01FF
+9238007FC0EE1FF0EE07FE933801FF809338007FE0EF1FF8EF03FE943800FF80F03FE0F0
+0FF8F003FE953800FF80F13FE0F10FF0A2F13FE0F1FF80953803FE00F00FF8F03FE0F0FF
+80DD03FEC7FCEF1FF8EF7FE0933801FF80DC07FEC8FCEE1FF0EE7FC04B48C9FCED07FCED
+1FF0ED7FC0DA03FFCAFCEC0FFCEC3FF0ECFFC0D903FECBFCEB0FF8EB3FE0EBFF80D803FE
+CCFCEA0FF8EA3FE0EAFF8048CDFC12F81260444277B957>62 D<923803FFF0037FEBFF80
+0203B612F0020F15FC913A3FFC000FFFDAFFC0010013C0D903FEC8EA1FF0D907F0ED03F8
+D91FC0ED00FE4948167F017ECAEA1F8049717E4848717E49DAFF8013034848010F01F06D
+7E4848013F01FC6D7E92B6FC4848489026C07F80137C49489026001FC0133C484948D907
+E0133E001E49486D6C131E003E49480101141F023F913800FFE0003C4A82007C017F1880
+007819074A5AA300F81AC04848491603AB6C6C7F12781B801A076E7E127C003C133F003E
+6E1700021F4A5C001E6D6C5B001F6D6C49EBF01E6C6D6C011F143E6D6CD9C07F6D5A6C6C
+6C90B5383FFFF8033FD9FC0F5B6C6C010FD9F0035B6C6C0100903980007F806D91CBFC6C
+7E137E6D7E6D6CEF7FC0D907F0EE03FFD903FE043F1300902600FFC0913803FFF8DA3FFC
+49B512C0020FB748C7FC020316E0DA007F02FCC8FC030349C9FC4A477AC557>64
+D<EE1F80A24C7EA24C7EA34C7EA24B7FA34B7FA24B7FA34B7F169F031F80161F82033F80
+ED3E07037E80157C8203FC804B7E02018115F0820203814B137F0207815D173F020F814B
+7F021F8292C77EA24A82023E80027E82027FB7FCA291B87EA2498302F0C8FCA20103834A
+157F0107834A153FA249488284011F8491C97E4984133E017E82B6020FB612F0A54C457C
+C455>I<B9FC18F018FE727E19E026003FFCC700077F05017F716C7E727E727EA2721380
+A37213C0A74E1380A24E1300A24E5A4E5A4E5A4D5B05075B94B5128091B700FCC7FC18F0
+18FF19E002FCC7000113F8716C7EF01FFE727E7213801AC07213E0A27213F0A31AF8A71A
+F0A2601AE0604E13C0604E138095B5120005075BBA12F86119C04EC7FC18E045447CC350
+>I<DCFFF01470031F01FF14F04AB6EAE0010207EDF803023FEDFE0791B539E001FF0F49
+49C7EA3F9F010701F0EC0FFF4901C0804990C87E4948814948814948167F4849163F4849
+161F5A4A160F485B19074890CAFC19035A5BA2007F1801A34994C7FC12FFAE127F7F1AF0
+A2123FA27F6C18011AE06C7F19036C6D17C06E16077E6C6DEE0F806C6DEE1F006D6C5E6D
+6C167E6D6C6C5D6D6D4A5A6D01F0EC07F0010101FEEC1FE06D903AFFF001FF80023F90B6
+C7FC020715FC020115F0DA001F1480030001F8C8FC44467AC451>I<B9FC18F018FE727E
+19E026003FFEC7001F13F805017F9438003FFF060F7F727F727F727F84737E737EA2737E
+A2737EA21B80A2851BC0A51BE0AD1BC0A51B8061A21B006162193F624F5A19FF624E5B06
+075B4E5B063F90C7FC4DB45A050F13F8BA5A19C04EC8FC18F095C9FC4B447CC356>I<B7
+12E0A5D8001F90C7FCB3B3B3A4B712E0A523447DC32A>73 D<B500FE067FB512806E95B6
+FCA26F5EA2D8003F50C7FC013D6DEE03DFA2013C6DEE079FA26E6CEE0F1FA26E6C161EA2
+6E6C163CA36E6C1678A26E6C16F0A26E6DEC01E0A26E6DEC03C0A36E6DEC0780A26F6CEC
+0F00A26F6C141EA26F6C5CA36F6C5CA26F6C5CA26F6D485AA26F6D485AA26F6D485AA370
+6C48C7FCA293383FF81EA2706C5AA2706C5AA3706C5AA2705BA2705BA2705BA2B6057FB6
+128071C7FCA2173E171C61447CC36A>77 D<923807FFC092B512FE0207ECFFC0021F15F0
+91267FFE0013FC902601FFF0EB1FFF01070180010313C04990C76C7FD91FFC6E6C7E4948
+6F7E49486F7E01FF8348496F7E48496F1380A248496F13C0A24890C96C13E0A24819F049
+82003F19F8A3007F19FC49177FA400FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19
+F0A26E5D6C19E0A26C6D4B13C06C19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D
+6C4A5B6D01C001075B6D01F0011F5B010101FE90B5C7FC6D90B65A023F15F8020715C002
+004AC8FC030713C047467AC454>79 D<DAFFE0131C010701FE133C013F9038FF807C90B6
+EAE0FC4815F9489038801FFF3907FC00014848EB007F4848143F4848140F491407007F15
+035B1601160012FF177CA27FA26D153C7F7F6D92C7FC6C7EEBFFE014FE6CEBFFF015FF6C
+15E016FC6C816C6F7E6C826C826C6C81011F810107811300020F80140003077FED007F82
+040F1380828212F082A282A27EA218007EA26C5D6C5E6D14036D5D6D140701F84A5A01FF
+EC3FF002F8EBFFE0486CB65AD8FC1F92C7FCD8F80714FC48C614F0480107138031467AC4
+3E>83 D<007FBA12E0BB12F0A46C19E04406776757>95 D<903801FFE0011F13FE017F6D
+7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C5AEA00F0
+90C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0481380381FFE00485A5B
+127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F0007EBFFF8
+6CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97 D<EB7FC0B5FCA512037EB1ED0FF892
+B57E02C314E002CF14F89139DFC03FFC9139FF000FFE02FCEB03FF4A6D13804A15C04A6D
+13E05CEF7FF0A218F8173FA318FCAC18F8A2177F18F0A3EFFFE06E15C06E5B6E49138002
+7C491300496C495A903AFC1FC07FFC496CB512F0D9F00314C049C691C7FCC8EA1FF03646
+7DC43E>I<EC3FFC49B512C0010F14F0013F14FC90397FF003FE9039FFC001FF0003495A
+48494813805B120F485AA2485A6F1300007F6E5AED00784991C7FCA212FFAC6C7EA3123F
+6DEC03C0A26C6C1407000F16806D140F6C6DEB1F006C6D133E6C01F05B3A007FFC03F86D
+B55A010F14C0010391C7FC9038003FF82A2F7CAD32>I<EE03FEED07FFA5ED001F160FB1
+EC3FE0903803FFFC010FEBFF8F013F14CF9039FFF807FF48EBC00148903880007F4890C7
+123F4848141F49140F121F485AA3127F5BA212FFAC127FA37F123FA26C6C141FA26C6C14
+3F0007157F6C6C91B5FC6CD9C00314FC6C9038F01FEF6DB5128F011FEBFE0F010713F890
+26007FC0EBF80036467CC43E>I<EC3FF80103B57E010F14E0013F8090397FF83FF89039
+FFC007FC48496C7E48496C7E48486D1380485A001FED7FC05B003FED3FE0A2127F5B17F0
+161F12FFA290B7FCA401F0C9FCA5127FA27FA2123F17F06C7E16016C6C15E06C6C14036C
+6DEB07C06C6DEB0F806C01F0EB3F0090397FFE01FE011FB55A010714F0010114C0902600
+1FFEC7FC2C2F7DAD33>I<EDFF80020F13E0027F13F049B512F849EB8FFC90390FFE0FFE
+90381FFC1F14F8133FEB7FF0A2ED0FFCEBFFE0ED03F0ED00C01600ABB612F8A5C601E0C7
+FCB3B0007FEBFFE0A527467DC522>I<DAFFE0137E010F9039FE03FF80013FEBFF8F90B8
+12C048D9C07F133F489038001FF84848EB0FFC4848903907FE1F80001F9238FF0F00496D
+90C7FCA2003F82A8001F93C7FCA26D5B000F5D6C6C495A6C6C495A6C9038C07FF04890B5
+5A1680D8078F49C8FC018013E0000F90CAFCA47F7F7F90B612C016FC6CEDFF8017E06C82
+6C16FC7E000382000F82D81FF0C77ED83FC014074848020113808248C9FC177FA46D15FF
+007F17006D5C6C6C4A5A6C6C4A5AD80FFEEC3FF83B07FFC001FFF0000190B612C06C6C92
+C7FC010F14F8D9007F90C8FC32427DAC38>I<EB7FC0B5FCA512037EB1ED07FE92383FFF
+8092B512E002C114F89139C7F03FFC9138CF801F9139DF000FFE14DE14FC4A6D7E5CA25C
+A35CB3A7B60083B512FEA537457CC43E>I<137C48B4FC4813804813C0A24813E0A56C13
+C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520>
+I<EB7FC0B5FCA512037EB3B3B3A3B61280A519457CC420>108 D<90277F8007FEEC0FFC
+B590263FFFC090387FFF8092B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D
+8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7E
+A24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7CAC5E>I<90397F8007FEB59038
+3FFF8092B512E0028114F8913987F03FFC91388F801F000390399F000FFE6C139E14BC02
+F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>I<EC1FFC49B512C0010714F001
+1F14FC90397FF80FFF9026FFC0017F48496C7F4848C7EA3FE000078248486E7E49140F00
+1F82A2003F82491407007F82A400FF1780AA007F1700A46C6C4A5AA2001F5E6D141F000F
+5E6C6C4A5AA26C6C6CEBFFE06C6D485B27007FF80F90C7FC6DB55A010F14F8010114C090
+26001FFCC8FC312F7DAD38>I<90397FC00FF8B590B57E02C314E002CF14F89139DFC03F
+FC9139FF001FFE000301FCEB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF
+3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07F
+FC02CFB512F002C314C002C091C7FCED1FF092C9FCADB67EA536407DAC3E>I<DA3FE013
+1E902603FFFC133E010F01FF137E013F1480903AFFF80FE0FE489038E003F148EBC00148
+90388000FB4890C7127F49143F001F151F485A160F5B127FA3485AAC6C7EA46C7EA26C6C
+141F163F6C6C147F6C15FF6C6D5A6C9038E003EF6C9038F01FCF6DB5128F011FEBFE0F01
+0313F89038007FC091C7FCAD0307B512FCA536407CAC3B>I<90387F807FB53881FFE002
+8313F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED
+01E092C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391FFC038090B51287000314FF120F
+381FF003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387F
+FFF014FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000
+F0143FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A
+00FC5CD8F03F13E026E007FEC7FC232F7CAD2C>I<EB01E0A51303A41307A2130FA2131F
+A2133F137F13FF1203000F90B51280B7FCA4C601E0C7FCB3A3ED01E0A9150302F013C013
+7F150790393FF80F8090391FFC1F006DB5FC6D13FC01015B9038003FE023407EBE2C>I<
+D97FC049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F7
+13FE9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I<B690
+3803FFFCA5000101E09038003E006C163C80017F5D8017F8013F5D6E1301011F5D6E1303
+010F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8
+F8023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA26E5AA21578362C7EAB3B>
+I<B500FE90383FFFF0A5C601F0903803E0006D6C495A6D6C495A011F4AC7FC6E5B6D6C13
+7E6DEB807C6D6D5A6DEBC1F0EDE3E06DEBF7C06EB45A806E90C8FC5D6E7E6E7F6E7FA24A
+7F4A7F8291381F3FFCEC3E1F027C7F4A6C7E49486C7F01036D7F49487E02C08049486C7F
+49C76C7E013E6E7E017E141FB500E090B512FCA5362C7EAB3B>120
+D<001FB71280A49026FC001F130001E0495A5B49495A90C7485A48495B123E4A5B4A5B00
+3C495BA24A90C7FC4A5A4A5AC7FC4A5A495B495BA2495B499038800780491300A2495A49
+48130F49481400A2485B48495B485BA248495B4890C75A48485C15034848EB1FFEB7FCA4
+292C7DAB32>122 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fn ecrm1728 17.28 8
+/Fn 8 117 df<B912F018FF19E019F8C601FCC8EA7FFED93FF892380FFF80011F04017F
+9538007FF0F11FF8737EF103FE737E737F747E747E747E1A0F87747E1A0387747EA27413
+80A2F37FC0A21CE01B3FA21CF0A21B1F1CF8A31CFCA21B0FA41CFEAF1CFCA51B1F1CF8A4
+F33FF0A21CE0A21B7F1CC01BFF1C80A2501300A2505A505AA2505A505A505A505A1AFF4F
+5B4F90C7FCF107FCF11FF8F17FF0953801FFC0013F04075BD9FFFCDB7FFEC8FCBA12F819
+E096C9FC18F0576278E167>68 D<BB12FCA4C601FCC8120FD93FF89238007FFE011F171F
+190719031900A21A7E1A3EA21A1EA21A1F86A486A6F20380A318E0A297C7FCA61701A417
+031707170F171F17FF91B7FCA402F8C7FC171F170F170717031701A41700A895C9FCB3A5
+80133F90B57EB712E0A4496278E158>70 D<EC3FE0903803FFFE010F6D7E90393FC03FE0
+90397C000FF801F0EB03FC48486D7E48486D7E48486E7E48C86C7E7F01F06E7E487E6D6E
+7EA3707EA36C5AEA03E0C9FCA6167FED7FFF020FB5FC91387FF807903801FF80903807FC
+00EB1FF0EB7FC0495AD803FEC7FC485A120F5B485A485AA24848EE01C0A312FF5BA2160F
+A3161F6D141B007F153B16736D17806C6C9138E1FC03001FEC03C16C6C903A0780FE0700
+D807FE49486C5A2701FF807CEB7FFE6C6CB4486D5A011F01E06D5A010390C7EA07E03A41
+79BF43>97 D<ED1FE0EDFFF8020313FE91380FF03F91391FC01F8091383F807F91397F00
+FFC014FE1301495A5C0107EC7F80A24948EB1E0093C7FCA2495AB3A5B712E0A426001FE0
+C8FCB3B3B0497EEB7FFC003FB512FEA42A657DE429>102 D<1378EA01FE487E487FA66C
+90C7FC6C5AEA007890C8FCB3A2EB0780EA0FFFB5FCA41203C6FCA2137FB3B3AC497E487F
+B61280A4195F7BDE25>105 D<010FEB07F8D80FFFEB1FFEB590387FFF809238F81FC091
+3801E03F913903C07FE00003EB0780C6EB0F00140E6D5A0218EB3FC00238EB1F800230EB
+0600027090C7FCA2146014E0A25CA55CB3B0497E4813F0B612F8A42B3F7BBE34>114
+D<9138FFC003010FEBF807017FEBFE0F3A01FF003F9FD803F0EB07DF48486DB4FCD80F80
+1300001F8148C8FC003E81007E81127C00FC81A4827EA27E7F6C7E6D91C7FC13F8EA3FFE
+381FFFE06C13FF15F0000314FE6C6E7E6C6C14E0011F14F801078001008002077FDA003F
+13801507030113C0ED007F00E0ED3FE0161F17F06C150F1607A36C1503A37EA26C16E016
+077E17C06D140F6D15806D141FD8FDF0EC3F00D8F8F8147E017C495A3AF01F801FF06DB5
+12C0D8E00391C7FC39C0007FF02C417CBF35>I<1470A714F0A51301A31303A21307A213
+0FA2131F133F137F13FF1203000F90B6FCB8FCA326000FF0C8FCB3AEEE01C0AE6D6CEB03
+80A316076D6C14005E6D6C130E6D6C131E6E6C5A91383FE0F86EB45A020713C0020090C7
+FC2A597ED734>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fo ecbx1728 17.28 18
+/Fo 18 117 df<BB7E1AFCF2FFC01BF01BFED8000191C8001F6D7E070014E0081F7F0807
+13FC08017F747F093F7F757F757F757F757F757F757FA2767E1E80881EC0881EE0881EF0
+A2881EF8A31EFC88A31EFEA61EFFB01EFEA61EFCA2641EF8A31EF064A21EE0641EC0641E
+80521300A2525A515B515BA2515B515B093F5B515B504848C7FC08075B081F5B97B512E0
+070F1480BC48C8FC1BF81BC008FCC9FC1A8068627BE177>68 D<942603FFF8151C94B66C
+143C040F03F0147C047F03FC14FC0303B81301030FDAC00113C0033F01F8C7381FF00392
+B500C0913807F807020349C83801FE0F020F01F89238007F1F4A01E0EE3FBF4A49EE0FFF
+91B5CA7E494983494983494983495B4949187F4B183F491A1F495B90B5CC120FA2484919
+075A4A19035A4A19015AA24A19005AA348491A7CA35A9AC8FCA35CA2B5FCB07EA26E043F
+B81280A47E96C7000701FCC7FCA26C7FA37E80A27E807E807E6C7FA26D7F6D7F7F816D7F
+6D6D5F6D7F6D6D5F6D6D7E023F6D5E6E01F05E6E6DEEFE7F020301FF923801FC3F020002
+C0913807F80F033F01FC91381FF007030F903BFFE001FFC001030391B6EA8000DB007F4B
+C7123C040F03F8140C040003C091C8FC050301F8CBFC696677E37A>71
+D<BA12E0F1FF801AF81AFF1BC0D8000191C7000114F0DE000F13FC070313FF070080083F
+7F747F747F747F747FA2747F88A28986A389A865A35091C8FCA26462646462505B505B50
+138097B5C9FC070313FC070F5B4EB512C093B8CAFC1AF81AC01AF893C7000713FE06006D
+7E073F7F7313F007077F737F87737F85888688A2747FAA88A91F707614F8A286A2746D13
+011FF086746D13037614E0B800FE6EED07C0746CEBC00F759038F07F80090F90B5120009
+035CCF6C13F80A0313E06D647BE173>82 D<001FBD12F0A59126F8000191C7123F4801C0
+060713F849C71700491A7F01F01A1F491A0F491A07A2491A03A290C81801A2007EF300FC
+A4007C1C7CA7481C3EA5C91900B3B3B3A5023FB912F8A55F617AE06C>84
+D<913803FFF0027F13FF0103B612E0010F15F890263FFC0013FED97FC090381FFF8049C7
+6C7F4801C06D7F486D6D7F6E6D7F48836E7F84177F84A36C496E7FA26C5B6C5B013FC8FC
+90C9FCA75F0307B6FC4AB7FC141F91B5EAF03F0103EBFE00010F13F0013F1380D9FFFEC7
+FC485B485B485B485B485B485BA24890C8FC1A7CA2485AA35FA394B5FC7F6C5D6EEB03DF
+6CDB07CFEBC0F86C6DEB0F8F6C6DD91F07EBF3F06C01F8017E14FF6C9027FE01FC0314E0
+C690B5D8F00114C0013F9126C0007F1380010791C7383FFE009026003FF8EC07F846437B
+C14D>97 D<903807FF80B6FCA5C6FC7F7FB3A9933801FFE0041F13FE047FEBFFC00381B6
+12F0922687FC0113FC923A9FE0003FFEDBBF8090380FFF8003FEC76C7F4B6E7F4B6E7F4B
+6E7F4B824B157F4B82737EA21B80851BC0A31BE085A41BF0AE1BE0A44F13C0A31B80A24F
+1300A262197F6F5E6F4B5A4E5B6F4A5BDAFCF84A5BDAF87E4A5B4A6C4A90C7FC9126E01F
+C0EB7FFC913BC00FF803FFF8DA8003B612E091C71580013E023F01FCC8FC90C800031380
+4C657CE356>I<ED1FFF4AB512F8020F14FF027F15C0902701FFF80013F04901E0EB0FF8
+010F0180EB03FC4990C7EA0FFE49484A7E49485C4948168048495C5A5C5A485BA2487013
+005C48705A715AEF03F04893C8FC91CBFCA4B5FCAE7EA280A27EA36C7FF003E07E6E1507
+6C18C06E150F6C18806C6D151F6C6DED3F006D6C157E6D6C15FE6D6D495A6D6D495A6D01
+F0EB0FE0010101FEEB7FC06D6CB6C7FC021F14FC020314E09126001FFEC8FC3B437BC145
+>I<ED3FFE0203B512E0021F14FC027F14FF902701FFF80F13C00107D9C0037F4990C77F
+49486E7E49486E7E49486E7E49486E7E5A48496E13805A4A16C0488219E0485B834818F0
+A34890C8FCA27113F8A3B5FCA391B8FCA491CBFCA67EA4807EA27E19F8806C17016C18F0
+806C17036C6DED07E06E16C06C170F6D6CED1F806D6CED3F006D6C6C14FE01076DEB03FC
+6D01F8EB0FF8010001FFEB7FE0023F90B51280020F4AC7FC020114F8DA000F13803D437C
+C146>101 D<EEFFE0031F13FC92B6FC02031580020F9038E03FC04A903800FFE091267F
+FE0113F04A485A49494813F84913F04913E0A25B15C05B7013F04913807013E09338007F
+80EF1E0094C7FCB1B8FCA5D8003F0180C8FCB3B3B2B712F8A535657CE42F>I<F13F8091
+2601FFF0903801FFE0021F01FF010713F091B6D8E01F13F801039238F87FCF010F903BC0
+7FFEFC0FFC903B1FFE000FFFF0D97FFC6DEBE01F49486D140F48496D13F01AF848496DEB
+F807489438FC01E096C7FC48496E7EA44883A96C5FA46C6D4A5AA26C5F6C6D495BA26C6D
+495B6D6C495B6D6C4990C8FC903A7FFFC07FFE017B90B512F801F015E0021F91C9FC0001
+010113F049CCFC1203A27FA37FA27F7F6D7E91B612FCEFFFE06C17FCF0FF806C18E0856D
+17FC6D836D837F017F188048BA12C000070180C712074848C96C13E04848160F48481603
+4982007F19F084485A197FA56D17FF007F19E0A26D5E6C6C4C13C0001F19806D5E6C6C4C
+1300000301C0ED3FFC6C01F0EDFFF826007FFC020313E090261FFFE0017F1380010790B6
+48C7FC010116F8D9001F1580DA007F01E0C8FC46607CC14D>I<EB0FE0EB3FF8497E497E
+487FA24880A76C91C7FCA26C5B6D5A6D5AEB0FE090C9FCB1903807FF80007FB5FCA5C6FC
+7F7FB3B3B0B712C0A522657CE42A>105 D<903807FF80B6FCA5C6FC7F7FB3B3B3B3AFB7
+12E0A523647CE32A>108 D<D90FFFEC7FF8B60103B5FC040F14E0043F80DC7F0113FC92
+2601F8007FC6DA03E06D7E6D49487F6D49488193C77E031E825D153803788003708215F0
+5DA35DA35DB3B3A2B7D8E03FB612F8A54D417BC056>110 D<92381FFF804AB512F8020F
+14FF023F15C09126FFFC0313F001039039E0007FFC490180EB1FFED91FFEC73807FF8049
+486E7F49486E7F49486E7F48496F7EA248496F7E4884A248496F7EA2481980A24819C091
+C97EA24819E0A5B518F0AD6C19E0A46C6D4B13C0A36C1980A26C6D4B1300A26C606E157F
+6C606C6D4B5A6C606D6C4A5B6D6C4A5B6D6C4A5B6D6C6C011F90C7FC010301E0EB7FFC6D
+9039FC03FFF86D6CB612E0020F92C8FC020114F8DA001F138044437CC14D>I<903B07FF
+8001FFE0B6011F13FE047FEBFFC00381B612F0922687FC0313FC923A9FE0007FFEC6DABF
+806D6C7E6D01FEC7000F7F6D496E7F4B824B6E7F4B6E7F4B804B82737EA21B80851BC0A2
+851BE0A4851BF0AE4F13E0A41BC061A21B80A24F1300A24F5AA26F4A5B6F4A5B626F4A5B
+6F4A5B03FE4A5B03BF027F90C7FCDB9FC0EBFFFC92268FF8075B0383B612E00380158004
+3F01FCC8FC0403138093CBFCB3A4B712E0A54C5D7CC056>I<D90FFFEB07F8B6EB3FFF4C
+13804BB512E0923903F83FF0923907E07FF8C691380F80FF6D020113FC6D131E153E153C
+1578A21570DBF00013F8EF7FF04BEB3FE0EF0F8094C7FC5DA65DB3B1B712F8A536417DC0
+3E>114 D<DA7FFC131C0107B5EAC03C011FECF0FC90B612FD489038C003FFD807FEC712
+7FD80FF8143F49140F4848140748481403A248481401A2160012FFA26D157CA27F7F7F6D
+92C7FCEBFF806C13F0ECFFC015FE6CECFFC016F86C15FE6C6F7E6C826C826C826C82013F
+81010F81010181EB003F02011580EC000F1500041F13C000F88182826C8182A26C167FA3
+7E18807F17FF6D16007F6D4A5A7F6D4A5A6DEC0FF86D6C495A3BFE1FF001FFE0486CB612
+80D8F8034AC7FC48C614F048010F90C8FC32437BC13D>I<EC07C0A6140FA5141FA3143F
+A2147FA214FF5BA25B5B5B5B137F48B5FC000F91B512F8B8FCA4D8001F01C0C7FCB3B017
+1FAD6D153E81A26D157C816D15F86D7F6D9038FC01F091397FFF07E06EEBFFC0020F1480
+0203EBFE009138003FF8305C7DDA3C>I E
+%EndDVIPSBitmapFont
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+%%PaperSize: A4
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 290 639 a Fo(Genealogical)56 b(Represen)l(tation)e(of)f(T)-13
+b(rees)52 b(in)g(Databases)1686 822 y Fn(First)46 b(Draft)1247
+1063 y Fm(Miguel)36 b(Sofer)i(<mig@utdt.edu>)1359 1179
+y Fl(Univ)m(ersidad)33 b(T)-8 b(orcuato)33 b(Di)f(T)-8
+b(ella)1728 1295 y(Buenos)33 b(Aires)1797 1411 y(Argen)m(tina)1746
+1606 y(Ma)m(y)h(6,)e(2000)1839 1905 y Fk(Abstract)441
+2035 y Fj(blah)25 b(blah)h(.)13 b(.)g(.)118 2310 y Fi(1)131
+b(In)l(tro)t(duction)118 2491 y Fh(T)-7 b(rees)28 b(are)h(a)g(v)n(ery)f
+(frequen)n(t)h(data)f(structure.)41 b(They)30 b(are)e(the)h(natural)g
+(represen)n(tation)e(for)i(instance)g(for)f(organiza-)118
+2591 y(tional)f(c)n(harts,)g(threaded)g(discussion)g(groups,)f(some)h
+(bills)g(of)h(materials,)e(.)14 b(.)g(.)243 2691 y(A)n(t)28
+b(least)f(t)n(w)n(o)f(alternativ)n(e)h(represen)n(tations)e(for)i
+(trees)g(in)h(RDBMs)g(are)e(kno)n(wn)h(and)h(used:)220
+2857 y(1.)41 b Fg(P)m(oin)m(ters:)k Fh(a)31 b(\034eld)h(in)h(the)f(c)n
+(hild)g(record)e(references)h(the)h(paren)n(t)f(no)r(de.)50
+b(This)32 b(seems)g(to)f(b)r(e)i(the)f(canonical)326
+2956 y(represen)n(tation.)38 b(Some)29 b(DB)g(engines)f(pro)n(vide)g
+(sp)r(ecial)g(SQL)g(extensions)g(to)h(simplify)g(tree)g(searc)n(hes;)e
+(Oracle)326 3056 y(tree)d(extensions)g(are)g(an)h(example)f(\(see)h
+(for)f(instance)g([1]\);)i(DB2's)f(WITH)g(can)f(b)r(e)i(used)e(for)h
+(this)g(purp)r(ose)f(to)r(o)326 3156 y(\(see)j([3],)g(pp)h(139-162\).)
+220 3322 y(2.)41 b Fg(Nested)35 b(Sets:)43 b Fh(t)n(w)n(o)30
+b(n)n(umeric)h(\034elds)g(in)g(ev)n(ery)f(no)r(de)h(record)f(co)r(de)h
+(the)g(tree)g(structure.)47 b(I)31 b(can't)g(pro)n(vide)f(a)326
+3421 y(b)r(etter)e(or)e(briefer)h(description)g(of)h(this)g(metho)r(d)g
+(than)f(the)h(four)f(articles)g([2].)118 3587 y(These)g(t)n(w)n(o)g
+(metho)r(ds)h(o\033er)f(di\033eren)n(t)h(adv)-5 b(an)n(tages)25
+b(and)j(disadv)-5 b(an)n(tages:)243 3753 y Ff(\017)41
+b Fh(P)n(oin)n(ters)30 b(are)g(extremely)g(e\036cien)n(t)h(for)f(no)r
+(de)h(insertion)f(and/or)g(deletion,)h(but)h(require)e(recursiv)n(e)f
+(table)i(ac-)326 3853 y(cesses)e(to)h(searc)n(h)f(the)h(tree)g(\(I)h
+(do)f(not)g(kno)n(w)f(the)i(implemen)n(tation)f(details)g(of)g(the)h
+(Oracle)e(tree)g(extensions,)326 3953 y(whic)n(h)e(as)g(far)g(as)g(I)g
+(kno)n(w)g(ma)n(y)g(solv)n(e)f(this)i(problem)f(in)n(ternally;)g(they)g
+(de\034nitely)h(solv)n(e)f(it)g(for)g(the)h(end)g(user\).)243
+4119 y Ff(\017)41 b Fh(Nested)30 b(sets)g(are)f(v)n(ery)f(e\036cien)n
+(t)i(for)g(tree)f(searc)n(hes,)g(but)i(are)e(rather)f(exp)r(ensiv)n(e)i
+(for)f(no)r(de)h(insertion)f(and/or)326 4218 y(deletion:)37
+b(they)27 b(require)g(up)r(dating)g(p)r(oten)n(tially)h(man)n(y)f(no)r
+(des.)243 4384 y(W)-7 b(e)30 b(prop)r(ose)f(here)h(a)g(di\033eren)n(t)h
+(represen)n(tation,)e(based)g(on)i(no)r(de)f(iden)n(ti\034ers)g(whic)n
+(h)g(are)f(\020genealogical)f(iden)n(ti-)118 4484 y(\034ers\021:)44
+b(they)32 b(con)n(tain)f(the)h(complete)f(genealogy)f(of)h(the)h(no)r
+(de,)h(i.e.,)g(the)f(list)g(of)g(ancestors)d(up)j(to)g(the)g(ro)r(ot)f
+(of)g(the)118 4584 y(tree.)243 4683 y(This)j(allo)n(ws)f(to)i(replace)e
+(man)n(y)h(searc)n(hes)f(in)h(database)g(tables)g(with)h(string)f(op)r
+(erations)f(on)h(the)h(index.)58 b(The)118 4783 y(result,)24
+b(as)f(explained)h(in)g(Section)g(3)f(is)h(that)g(tree)f(searc)n(hes)f
+(pro)r(ceed)h(at)h(\020nested)f(sets\021)30 b(sp)r(eed,)25
+b(while)f(no)r(de)g(insertions)118 4882 y(and)k(deletions)f(are)f(as)h
+(fast)h(as)f(with)h(p)r(oin)n(ters.)243 4982 y(The)i(ob)n(vious)f(do)n
+(wnside)h(of)h(the)g(metho)r(d)g(is)f(that)h(the)g(primary)f(k)n(ey)f
+(in)i(the)g(tree)f(needs)h(to)f(b)r(e)h(a)g(v)-5 b(ariable)29
+b(size)118 5082 y(text)j(\034eld,)h(and)f(that)g(the)g(iden)n
+(ti\034ers)f(ma)n(y)g(b)r(e)i(extremelly)e(long)g(for)g(deep)h(trees.)
+49 b(W)-7 b(e)32 b(will)g(pro)n(vide)e(estimates)i(of)118
+5181 y(the)c(size)f(required)g(as)g(a)g(function)h(of)g(the)f
+(magnitude)h(of)f(the)h(tree.)1987 5653 y(1)p eop
+%%Page: 2 2
+2 1 bop 118 291 a Fi(2)131 b(Genealogical)45 b(iden)l(ti\034ers)g(for)f
+(trees)118 489 y Fm(2.1)112 b(De\034nition)118 642 y
+Fh(W)-7 b(e)28 b(de\034ne)g Fe(gene)l(alo)l(gic)l(al)k(identi\034ers)j
+Fh(recursiv)n(ely)25 b(as)i(follo)n(ws:)326 808 y Fg(De\034nition:)59
+b Fe(The)42 b(gene)l(alo)l(gic)l(al)h(identi\034er)f(\(gID\))e(of)i(a)f
+(no)l(de)h(is)f(obtaine)l(d)h(by)g(app)l(ending)g(a)f(child)326
+908 y(identi\034er)30 b(to)g(the)g(gene)l(alo)l(gic)l(al)h
+(identi\034er)g(of)f(the)g(p)l(ar)l(ent)f(no)l(de.)243
+1074 y Fh(Remark)40 b(that)h(genealogical)e(iden)n(ti\034ers)i(are)f
+(rather)g(w)n(ell)h(kno)n(wn)f(and)h(used;)48 b(common)41
+b(examples)f(are)g(the)118 1174 y(\020path+\034le-name\021)33
+b(in)28 b(a)f(computer)g(\034le)h(system)f(and)h(the)f(URLs)h(within)g
+(a)f(WWW.)243 1273 y(The)d(name)g(\020genealogical)e(iden)n
+(ti\034er\021)30 b(is)24 b(suggested)g(b)n(y)g(the)g(fact)h(that)f(the)
+h(v)-5 b(alue)24 b(of)g(the)h(iden)n(ti\034er)f(con)n(tains)f(the)118
+1373 y(complete)30 b(genealogy)d(of)j(the)g(no)r(de:)41
+b(it)30 b(con)n(tains)e(as)h(a)h(substring)f(the)h(gID)f(of)h(its)g
+(father,)g(whic)n(h)f(in)h(turn)g(con)n(tains)118 1472
+y(as)d(a)g(substring)g(the)h(gID)g(of)f(the)h(grandfather,)e(.)14
+b(.)g(.)243 1572 y(The)27 b(ro)r(ot)g(no)r(de)h(of)f(the)h(tree)f(has)g
+(a)h(gID)f(with)h(v)-5 b(alue)28 b(\021)34 b(\(the)28
+b(empt)n(y)g(string\),)f(as)g(it)h(has)f(no)g(paren)n(t.)118
+1804 y Fm(2.2)112 b(Child)36 b(iden)m(ti\034ers)118 1958
+y Fh(The)26 b(ob)n(vious)e(c)n(hild)i(iden)n(ti\034er)g(is)f(a)h
+(zero-based)d(coun)n(ter:)35 b(iden)n(tify)26 b(the)h(c)n(hild)e(b)n(y)
+h(the)g(n)n(um)n(b)r(er)f(of)h(older)f(brethren)g(it)118
+2057 y(has.)243 2157 y(W)-7 b(e)25 b(could)f(represen)n(t)g(the)h(coun)
+n(ter)f(in)h(base)f(10;)h(this)g(ho)n(w)n(ev)n(er)e(is)i(extremely)f(w)
+n(asteful)g(of)h(resources.)34 b(It)25 b(is)g(m)n(uc)n(h)118
+2257 y(b)r(etter)33 b(to)f(represen)n(t)f(the)h(coun)n(ter)g(in)g(as)g
+(large)e(a)i(base)g(as)f(p)r(ossible:)46 b(in)n(terpret)32
+b(as)f(n)n(um)n(b)r(ers)h(a)g(set)g(of)g(c)n(haracters)118
+2356 y(larger)26 b(than)h({0,1,.)14 b(.)g(.)g(9}.)243
+2456 y(As)26 b(tree)f(op)r(erations)f(will)i(in)n(v)n(olv)n(e)f(string)
+g(op)r(erations)f(on)i(the)g(indices,)g(in)g(order)f(to)g(a)n(v)n(oid)g
+(a)g(\020quoting)g(hell\021)33 b(it)26 b(is)118 2555
+y(desirable)d(to)h(a)n(v)n(oid)e(using)h(an)n(y)g(c)n(haracter)f(with)i
+(a)g(sp)r(ecial)f(meaning)h(in)g(LIKE)g(expressions)e(or)g(regular)g
+(expressions;)118 2655 y(i.e.,)28 b(w)n(e)f(will)h(not)f(use)h(an)n(y)f
+(of)g(the)h(sym)n(b)r(ols)70 b Fd(.)44 b(*)f(^)g(\\)g([)g(])g({)h(})f
+(\()g(\))g(<)g(>)71 b Fh(?)37 b(|)28 b(&)f($)243 2755
+y(W)-7 b(e)28 b(prop)r(ose)e(to)h(reserv)n(e)f(also)g(/)i(as)f(a)g
+(separator)e(\(see)i(\020V)-7 b(ariable)27 b(Sized)g(gID\021)34
+b(b)r(elo)n(w\).)243 2854 y(If)g(w)n(e)f(limit)i(ourselv)n(es)d(to)i
+(ascii)f(c)n(haracters,)g(and)h(a)n(v)n(oid)e(to)i(b)r(e)g(safe)f(a)h
+(lot)g(of)g(other)f(c)n(haracters,)g(w)n(e)g(can)h(use)118
+2954 y(n)n(um)n(b)r(ers)27 b(in)h(base)f(64)g(b)n(y)g(represen)n(ting)
+243 3120 y Ff(\017)41 b Fh(0-9)26 b(with)i('0'-'9')f(\(dec)g(ascii)g
+(co)r(de)h(48-57\))243 3286 y Ff(\017)41 b Fh(10)26 b(with)i(':')37
+b(\(dec)28 b(ascii)f(co)r(de)h(58\))243 3452 y Ff(\017)41
+b Fh(11)26 b(with)i(';')g(\(dec)g(ascii)f(co)r(de)g(59\))243
+3618 y Ff(\017)41 b Fh(12-37)25 b(with)j('A'-'Z')g(\(dec)f(ascii)g(co)r
+(de)h(65-90\))243 3784 y Ff(\017)41 b Fh(38-63)25 b(with)j('a'-'z')f
+(\(dec)h(ascii)f(co)r(de)g(97-122\))118 3950 y(By)g(using)g(base)f(64,)
+h(up)g(to)h(4096)d(c)n(hildren)i(can)f(b)r(e)i(represen)n(ted)e(using)h
+(t)n(w)n(o)f(suc)n(h)h(digits,)g(up)h(to)f(262144)d(with)k(three)118
+4050 y(digits,)g(and)f(up)h(to)f(16777216)d(with)k(four)f(digits.)243
+4149 y(If)37 b(the)g(RDBMs)g(supp)r(orts)f(in)n(ternational)g(c)n
+(haracters,)h(it)g(is)g(p)r(ossible)f(to)h(further)f(increase)g(the)h
+(base;)k(as)36 b(an)118 4249 y(example,)30 b(b)n(y)f(using)g(the)h(95)f
+(additional)g(c)n(haracters)e(of)i(the)h(latin-1)f(c)n(haracter)e(set,)
+k(w)n(e)e(could)g(co)r(de)g(n)n(um)n(b)r(ers)g(in)h(a)118
+4349 y(base)f(up)g(to)g(160)f(\025)g(remark)g(that)h(ev)n(ery)f(single)
+h(digit)g(is)g(still)h(one)e(b)n(yte)h(in)h(this)f(represen)n(tation.)
+40 b(This)29 b(means)f(that)118 4448 y(w)n(e)f(expand)h(the)f(sym)n(b)r
+(ols)g(ab)r(o)n(v)n(e)f(b)n(y)i(represen)n(ting)243 4614
+y Ff(\017)41 b Fh(64-159)25 b(with)j(dec)f(latin1)g(co)r(de)h(160-255)
+243 4780 y(In)23 b(base)g(160,)g(up)g(to)h(25600)d(c)n(hildren)i(can)f
+(b)r(e)i(represen)n(ted)e(using)h(t)n(w)n(o)g(digits,)h(up)g(to)f
+(4096000)d(with)k(three)f(digits,)118 4880 y(and)28 b(up)f(to)h
+(6.5E+08)e(with)i(four)f(digits.)243 4980 y(Remark)g(that)h(base)f(con)
+n(v)n(ersions)f(only)h(need)i(to)e(b)r(e)i(p)r(erformed)e(at)h
+(insertion)g(time,)g(when)h(the)f(index)g(of)g(a)g(new)118
+5079 y(no)r(de)g(is)f(computed.)37 b(They)28 b(will)f(therefore)g(only)
+g(ha)n(v)n(e)f(an)i(impact)f(on)h(insertion)f(timings.)1987
+5653 y(2)p eop
+%%Page: 3 3
+3 2 bop 118 291 a Fm(2.3)112 b(Coun)m(ters:)50 b(\020delimited\021)44
+b(vs.)51 b(\020\034xed)38 b(size\021)118 444 y Fh(The)33
+b(standard)g(represen)n(tation)e(of)i(gID)h(uses)e(a)h(v)-5
+b(ariable)32 b(size)h(c)n(hild)h(iden)n(ti\034er,)g(and)f(delimiters)g
+(to)h(separate)d(the)118 543 y(gID)f(of)g(the)h(c)n(hild)f(no)r(de)g
+(from)f(the)i(gID)f(of)g(its)g(paren)n(t.)43 b(F)-7 b(or)30
+b(example,)g(w)n(e)g(can)f(represen)n(t)g(the)i(\034fth)g(c)n(hild)f
+(of)g(no)r(de)118 643 y('/23/27/1')24 b(as)j('/23/27/1/4'.)32
+b(Let)c(us)f(call)g(this)h(a)f Fg(vgID)h Fh(represen)n(tation)e(\(V)-7
+b(ariable)27 b(Size)h(Genealogical)d(ID\).)243 743 y(This)30
+b(represen)n(tation)f(allo)n(ws)f(for)i(an)n(y)g(n)n(um)n(b)r(er)g(of)g
+(c)n(hildren)g(of)h(a)f(no)r(de,)h(sub)5 b(ject)30 b(only)g(to)g(the)h
+(limitations)f(the)118 842 y(RDBMS)e(ma)n(y)f(ha)n(v)n(e)f(as)h(to)h
+(the)g(length)f(of)h(a)f(v)-5 b(ariable)27 b(sized)g(string.)243
+942 y(Alternativ)n(ely)-7 b(,)24 b(w)n(e)f(could)h(c)n(ho)r(ose)f(to)h
+(limit)g(from)g(the)g(outset)g(the)g(quan)n(tit)n(y)g(of)f(c)n(hildren)
+h(that)g(a)g(no)r(de)g(ma)n(y)f(ha)n(v)n(e;)118 1042
+y(this)28 b(limit)g(w)n(ould)f(dep)r(end)i(of)e(course)f(on)i(the)g
+(application.)36 b(Let)27 b(us)h(call)f(this)h(a)f Fg(fgID)h
+Fh(represen)n(tation.)243 1141 y(F)-7 b(or)25 b(example,)h(if)g(no)g
+(no)r(de)f(is)h(allo)n(w)n(ed)f(to)g(ha)n(v)n(e)g(more)g(than)h(25600)d
+(c)n(hildren,)j(w)n(e)g(could)f(represen)n(t)g(the)h(coun)n(ters)118
+1241 y(alw)n(a)n(ys)36 b(with)i(2)f(digits.)67 b(The)38
+b(no)r(de)f(whic)n(h)h(w)n(as)f(previously)f('/23/27/1/4')d(is)k(no)n
+(w)g('23270104'.)64 b(If)38 b(w)n(e)f(require)118 1340
+y(a)g(three)g(digit)h(represen)n(tation)d(of)i(no)r(des)g(\(up)h(to)f
+(ab)r(out)h(4)f(million)g(c)n(hildren\),)j(then)d(it)h(will)g(b)r(e)f
+(represen)n(ted)f(as)118 1440 y('023027001004'.)118 1672
+y Fm(2.4)112 b(Ordering)37 b(of)h(no)s(des)118 1825 y
+Fh(F)-7 b(or)35 b(some)g(applications)g(it)h(is)f(necessary)f(to)i
+(obtain)f(subtrees)g(ordered)f(according)g(to)i(some)f(sp)r(ecial)g
+(rules.)60 b(F)-7 b(or)118 1925 y(instance:)220 2090
+y(1.)41 b(the)34 b(complete)g(subtree)f(starting)g(at)h(a)f(no)r(de)h
+(is)g(listed)g(immediately)g(after)f(the)i(no)r(de)f(in)g(question)f
+(\(\020depth)326 2189 y(\034rst\021\))220 2354 y(2.)41
+b(no)r(des)27 b(with)h(a)f(common)g(paren)n(t)g(are)g(listed)g(c)n
+(hronologically)243 2519 y(F)-7 b(or)39 b(instance,)k(the)d(displa)n(y)
+f(of)h(an)f(organization)f(c)n(hart)h(is)g(usually)h(required)e(to)i
+(satisfy)g(at)f(least)h(the)g(\034rst)118 2619 y(condition.)h(In)29
+b(a)g(threaded)f(discussion)h(group)e(one)i(wishes)g(to)f(satisfy)h(b)r
+(oth)h(conditions)e(to)h(displa)n(y)f(the)h(messages)118
+2718 y(in)20 b(a)g(thread)g(\025)f(the)i(threads)e(themselv)n(es)h
+(\(i.e.,)i(c)n(hildren)e(of)g(the)g(ro)r(ot)f(no)r(de\))i(are)e
+(usually)g(listed)i(in)f(in)n(v)n(erse)f(c)n(hronolical)118
+2818 y(order.)243 2917 y(T)-7 b(o)35 b(mak)n(e)f(a)h(particular)f
+(ordering)g(e\036cien)n(t,)j(it)f(w)n(ould)f(b)r(e)h(a)f(nice)g
+(feature)g(if)h(it)g(could)f(b)r(e)h(made)f(to)g(coincide)118
+3017 y(with)28 b(a)f(lexicographic)f(ordering)f(of)j(the)g(indices)f
+(\025i.e.,)g(as)g(pro)r(duced)g(b)n(y)h(an)f(\020ORDER)h(BY)f(id)h
+(ASC\021)35 b(in)27 b(SQL.)h(The)118 3117 y(lexicographic)d(ordering)h
+(of)h(fgID)h(satis\034es)e(b)r(oth)i(conditions.)36 b(The)27
+b(lexicographic)f(ordering)f(of)i(vgID)g(as)g(describ)r(ed)118
+3216 y(ab)r(o)n(v)n(e)34 b(satis\034es)g(the)h(\034rst)g(requisite)f
+(if)i(the)f(separator)d(has)j(the)g(minimal)g(binary)g(represen)n
+(tation)e(of)i(all)f(allo)n(w)n(ed)118 3316 y(sym)n(b)r(ols)c(in)h(an)f
+(index)h(\025)f(this)h(is)g(wh)n(y)f(w)n(e)g(reserv)n(ed)f(/)h(for)g
+(the)i(separator.)43 b(But)31 b(the)g(second)f(prop)r(ert)n(y)g(is)g
+(missing:)118 3416 y(for)d(instance,)g(the)h(index)g('/1/10')d(is)j
+(lexicographically)d(b)r(efore)i('/1/2'.)243 3515 y(If)c(the)h(second)e
+(prop)r(ert)n(y)g(is)i(also)e(required)g(for)h(vgID,)g(w)n(e)f(can)h
+(sp)r(ecify)h(the)f(c)n(hild)h(iden)n(ti\034ers)e(with)i(coun)n(ters)e
+(built)118 3615 y(in)28 b(the)g(follo)n(wing)e(w)n(a)n(y:)36
+b(represen)n(t)26 b(a)h(n)n(um)n(b)r(er)h(b)n(y)f(a)g(string)g(of)g
+(digits,)h(where)243 3779 y Ff(\017)41 b Fh(the)25 b(\034rst)g(digit)h
+Fc(D)896 3791 y Fb(0)958 3779 y Fh(represen)n(ts)e(the)i(length)f(in)h
+(digits)f(of)g(the)h(decimal)f(expansion)f(of)i(the)f(n)n(um)n(b)r(er,)
+h(min)n(us)f(one)243 3945 y Ff(\017)41 b Fh(the)28 b(follo)n(wing)e
+Fa(\()p Fc(D)920 3957 y Fb(0)976 3945 y Fa(+)18 b(1\))27
+b Fh(digits)h(are)e(the)i(decimal)g(expansion)e(of)i(the)g(n)n(um)n(b)r
+(er)118 4109 y(Let)g(us)f(call)h(these)f(iden)n(ti\034ers)g
+Fg(m-vgID)p Fh(,)g(\020m\021)34 b(for)27 b(mo)r(di\034ed.)243
+4209 y(As)e(an)f(example,)h(the)g(no)r(de)g(whic)n(h)g(w)n(as)f
+(previously)f(represen)n(ted)h(b)n(y)g(/15/3/182)d(will,)k(after)g
+(this)g(mo)r(di\034cation,)118 4309 y(ha)n(v)n(e)h(the)i(index)g
+(/115/03/2182.)243 4408 y(The)37 b(lexicographic)f(ordering)g(of)i
+(m-vgID)f(is)h(the)g(desired)f(ordering)f(of)h(the)h(tree)g(no)r(des.)
+67 b(The)38 b(cost)f(of)g(this)118 4508 y(prop)r(ert)n(y)31
+b(is)i(that)f(\(a\))h(the)g(ID)f(are)g(no)n(w)g(longer,)g(\(b\))h(no)f
+(no)r(de)g(can)g(ha)n(v)n(e)g(more)f(than)i Fa(160)3106
+4478 y Fb(160)3240 4508 y Fh(c)n(hildren)f(\(actually)-7
+b(,)118 4607 y(this)32 b(is)g(a)f(non-issue\),)h(and)f(\(c\))h(the)g
+(index)g(structure)f(is)h(redundan)n(t,)g(some)f(formally)f(correct)h
+(indices)g(are)g(in)n(v)-5 b(alid)118 4707 y(\025e.g.,)24
+b(/316/013/11.)30 b(The)24 b(third)g(issue)g(can)g(b)r(e)g(addressed)f
+(b)n(y)g(k)n(eeping)g(a)h(strict)g(con)n(trol)e(on)i(the)g(generation)f
+(of)h(new)118 4807 y(indices)k(to)f(insure)g(that)h(all)f(indices)h
+(are)e(formally)h(correct.)243 4906 y(The)32 b(issue)f(of)h(the)g(rev)n
+(erse)e(c)n(hronological)f(indexing)j(of)f(threads)h(in)g(threaded)f
+(discussion)g(groups)g(can)g(b)r(e)h(ad-)118 5006 y(dressed)d(easily)f
+(enough)h(in)h(fgID:)f(coun)n(t)g(\020do)n(wn\021)36
+b(instead)29 b(of)g(\020up\021)36 b(the)30 b(c)n(hildren)f(of)g(the)h
+(ro)r(ot)e(no)r(de)i(\025)f(this)h(implies)118 5106 y(only)e(an)g
+(inconsequen)n(tial)f(mo)r(di\034cation)h(of)g(the)g(no)r(de)h
+(insertion)e(routine,)h(as)g(sho)n(wn)f(b)r(elo)n(w.)38
+b(The)29 b(problem)e(is)h(less)118 5205 y(trivial)i(with)g(vgID;)h(in)f
+(this)h(case,)f(ma)n(yb)r(e)f(a)h(thread)g(iden)n(ti\034er)g(should)g
+(b)r(e)h(k)n(ept)f(in)g(a)g(di\033eren)n(t)g(\034eld)h(-)f(i.e.,)h
+(repre-)118 5305 y(sen)n(ting)h(the)h(structure)f(as)g(a)h(forest)f
+(rather)f(than)i(a)f(tree,)i(where)e(the)h(thread_id)f(\034eld)h
+(selects)f(the)h(\020tree\021)38 b(in)33 b(the)118 5404
+y(forest.)1987 5653 y(3)p eop
+%%Page: 4 4
+4 3 bop 118 291 a Fi(3)131 b(T)-11 b(ree)45 b(op)t(erations)e(using)h
+(genealogical)g(indices)118 472 y Fh(In)32 b(this)f(section)g(w)n(e)g
+(sho)n(w)g(ho)n(w)g(to)g(implemen)n(t)h(v)-5 b(arious)30
+b(tree)h(op)r(erations)f(using)h(gID)g(as)g(the)h(primary)e(k)n(ey)h
+(in)g(the)118 572 y(no)r(de)d(table.)243 672 y(Some)h(implemen)n
+(tation)h(issues)g(are)f(relev)-5 b(an)n(t)29 b(here,)h(esp)r(ecially)f
+(concerning)g(the)h(utilisation)g(of)g(indices)g(b)n(y)f(the)118
+771 y(DB)f(engine.)243 871 y(W)-7 b(e)28 b(discuss)f(a)g(tree)g
+(represen)n(ted)f(in)i(a)f(table)h(of)f(the)h(form)326
+1034 y Fd(CREATE)41 b(TABLE)g(tree)h(\()456 1134 y(gid)304
+b(text)42 b(PRIMARY)f(KEY,)456 1234 y(nchildren)f(integer)h(DEFAULT)f
+(0,)456 1333 y(\\ldots)h(the)i(actual)e(node)h(data)326
+1433 y(\);)118 1597 y Fh(The)26 b(\034eld)g(\020nc)n(hildren\021)32
+b(is)26 b(a)f(coun)n(ter)g(for)g(the)i(n)n(um)n(b)r(er)e(of)h(c)n
+(hildren)f(that)h(the)h(no)r(de)f(has)f Fe(ever)35 b
+Fh(had;)27 b(w)n(e)e(assume)g(here)118 1696 y(it)j(is)g(not)f(up)r
+(dated)h(when)g(no)r(des)f(or)g(subtrees)g(are)f(deleted.)243
+1796 y(Section)h(4)g(pro)n(vides)f(a)i(complete)f(implemen)n(tation)h
+(of)f(these)h(op)r(erations)e(for)h(fgID)h(in)g(P)n(ostgreSQL.)118
+2028 y Fm(3.1)112 b(Computing)37 b(the)g(lev)m(el)f(of)h(a)h(no)s(de)
+118 2181 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations)g(\(no)g(table)g
+(ac)l(c)l(ess\))243 2280 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r
+(eration,)f(no)i(table)f(access)g(is)g(required.)243
+2460 y Ff(\017)41 b Fg(vgID:)27 b Fh(coun)n(t)h(the)g(n)n(um)n(b)r(er)f
+(of)g(separators)e(\('/'\))j(in)g(the)g(PK)243 2625 y
+Ff(\017)41 b Fg(fgID:)27 b Fh(coun)n(t)g(the)h(n)n(um)n(b)r(er)g(of)f
+(c)n(haracters)e(in)j(the)g(PK,)g(divide)g(b)n(y)f(the)h(\034xed)f
+(size)h(of)f(the)h(coun)n(ters.)118 2857 y Fm(3.2)112
+b(Selecting)36 b(or)h(deleting)f(a)i(subtree)118 3010
+y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243
+3173 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g
+(/26/5/7)e(is)i(selected)g(b)n(y)508 3338 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('/26/5/7\045')d(AND)j(id)h(<)g('/26/5/70')243
+3503 y Ff(\017)e Fg(m-vgID:)26 b Fh(The)h(subtree)h(ro)r(oted)e(at)i
+(/126/05/07)22 b(is)28 b(selected)f(b)n(y)508 3668 y
+Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07\045')243
+3833 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g
+(260507)e(is)i(selected)h(b)n(y)508 3997 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('260507\045')118 4229 y Fm(3.3)112
+b(Selecting)36 b(the)h(direct)f(c)m(hildren)g(of)i(a)g(no)s(de)118
+4382 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243
+4562 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h
+(/26/5/7)c(are)j(selected)g(b)n(y)508 4727 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('/26/5/7/\045')d(AND)j(id)h(NOT)f(LIKE)g
+('26/5/7/\045/\045')243 4892 y Ff(\017)f Fg(m-vgID:)26
+b Fh(The)h(direct)h(c)n(hildren)f(of)g(/26/5/7)e(are)h(selected)i(b)n
+(y)508 5056 y Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07/\045')37
+b(AND)43 b(id)f(NOT)h(LIKE)f('/126/05/07/\045/\045)o(')243
+5221 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h
+(260507)c(are)j(selected)g(b)n(y)508 5386 y Fd(...)43
+b(WHERE)e(id)i(LIKE)f('260507\045')d(AND)k(char_length\(id\))37
+b(=)43 b(\(char_length\('26)o(05)o(07')o(\)+)o(2\))1987
+5653 y Fh(4)p eop
+%%Page: 5 5
+5 4 bop 118 291 a Fm(3.4)112 b(Inserting)37 b(a)h(no)s(de)g(or)f(a)h
+(subtree)118 444 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l
+(e)l(e)f(+)h(string)f(and)h(math)g(op)l(er)l(ations)243
+543 y Fh(Insertion)f(is)g(a)h(pro)r(cedural)e(op)r(eration.)42
+b(As)30 b(eac)n(h)f(RDBMS)h(has)f(a)h(di\033eren)n(t)f(w)n(a)n(y)g(of)g
+(de\034ning)h(pro)r(cedures,)f(w)n(e)118 643 y(will)f(just)g(describ)r
+(e)f(here)g(the)h(necessary)e(steps.)37 b(Examples)27
+b(for)g(P)n(ostgreSQL)f(are)h(pro)n(vided)f(in)i(4.)243
+743 y(In)22 b(order)f(to)h(insert)g(a)g(new)g(c)n(hild)h(of)f
+(\020daddy\021)28 b(\(either)23 b(one)f(of)g(/26/5/7,)e(/126/05/07)d
+(or)22 b(260507)d(in)k(the)f(examples)118 842 y(ab)r(o)n(v)n(e\))27
+b(y)n(ou)f(ha)n(v)n(e)h(to)220 1008 y(1.)41 b(add)27
+b(one)g(to)h(the)g(n)n(um)n(b)r(er)f(of)g(c)n(hildren)h(of)f
+(\020daddy\021)508 1174 y Fd(UPDATE)41 b(tree)h(SET)h(nchildren)c(=)k
+(\(nchildren)d(+)j(1\))g(WHERE)e(ID)i(=)g(``daddy'';)220
+1340 y Fh(2.)e(enco)r(de)27 b(the)h(n)n(um)n(b)r(er)f(of)g(c)n(hildren)
+g(of)h(\020daddy\021)33 b(in)28 b(base)f(160,)f(bring)h(it)h(to)f(the)h
+(correct)e(format)h(dep)r(ending)h(on)326 1440 y(the)c(v)-5
+b(arian)n(t)23 b(of)h(gID)g(\(pad)g(with)h(0)e(or)g(not,)i(prep)r(end)f
+(a)g(digit)g(coun)n(ter)f(or)g(not,)i(prep)r(end)f(/)g(or)f(not,)i
+(coun)n(t)e(do)n(wn)326 1540 y(or)j(up,)i(.)14 b(.)g(.)g(\))37
+b(and)28 b(app)r(end)f(it)h(to)g(daddy's)f(gID)g(to)h(obtain)f(the)h
+(new)g(no)r(de's)f(gID.)220 1706 y(3.)41 b(insert)27
+b(the)h(new)f(no)r(de)243 1872 y(When)35 b(inserting)g(a)f(subtree,)j
+(the)e(index)g(of)g(the)h(ro)r(ot)e(of)h(the)g(subtree)g(has)f(to)h(b)r
+(e)h(computed)f(as)f(ab)r(o)n(v)n(e,)i(and)118 1971 y(prep)r(ended)28
+b(to)f(the)h(index)g(of)f(eac)n(h)g(no)r(de)h(of)f(the)h(subtree)f(b)r
+(efore)h(insertion.)243 2071 y(Remark)e(that)i(only)f(the)h(paren)n(t)f
+(no)r(de)h(has)f(to)g(b)r(e)h(up)r(dated)g(on)f(insertion.)118
+2303 y Fm(3.5)112 b(Selecting)36 b(the)h(ancestors)h(of)g(a)g(no)s(de)
+118 2457 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243
+2556 y Fh(Y)-7 b(ou)27 b(can)g(sp)r(ecify)h(all)g(ancestors)d(of)j(a)f
+(no)r(de)h(in)f(a)h(single)f(SQL)g(statemen)n(t;)g(for)g(instance)h
+(for)f(vgID)326 2722 y Fd(...)42 b(WHERE)f('/25/6/7')f(LIKE)i(\(id)g
+(||)h('/\045'\))f(AND)g(id)h(<)g('/25/6/7')118 2888 y
+Fh(The)31 b(second)e(part)h(of)h(the)g(clause,)f(while)h(logically)e
+(redundan)n(t,)h(is)h(a)f(\020hin)n(t\021)37 b(to)30
+b(the)h(optimizer.)45 b(A)n(t)31 b(least)f(in)g(P)n(ost-)118
+2988 y(greSQL,)c(without)i(it)g(the)g(optimizer)f(will)h(c)n(ho)r(ose)e
+(a)i(sequen)n(tial)e(scan)h(of)h(the)g(table)f(and)h(disregard)d(the)j
+(index.)118 3220 y Fm(3.6)112 b(Selecting)36 b(all)g(lea)m(v)m(es)118
+3374 y Fg(Cost:)h Fe(sc)l(an)30 b(of)g(the)g(tr)l(e)l(e)243
+3473 y Fh(A)e(leaf)f(is)g(a)h(no)r(de)f(without)h(descendan)n(ts:)36
+b(it)28 b(has)f(0)g(c)n(hildren.)37 b(Hence)326 3639
+y Fd(...)42 b(WHERE)f(nchildren)f(=)j(0)118 3805 y Fh(If)28
+b(this)g(t)n(yp)r(e)g(of)f(query)g(is)h(often)f(necessary)-7
+b(,)26 b(y)n(ou)h(ma)n(y)g(b)r(e)h(w)n(ell)f(advised)g(to)g(k)n(eep)g
+(an)h(index)f(on)h(tree\(nc)n(hildren\).)118 4038 y Fm(3.7)112
+b(Determining)35 b(if)i(A)g(is)g(a)h(descendan)m(t)g(of)g(B)118
+4191 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations,)h(no)f(table)g(ac)l
+(c)l(ess)243 4291 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r(eration)f
+(on)i(the)g(indices,)f(no)g(table)h(access)e(is)i(necessary)-7
+b(.)118 4565 y Fi(4)131 b(Putting)45 b(it)f(all)h(together:)57
+b(a)44 b(P)l(ostgreSQL)f(implemen)l(tation)118 4747 y
+Fh(h)n(ttp://www.p)r(ostgresql.org/mhonarc/pgsq)o(l-sql/)o(20)o(00)o
+(-0)o(4/)o(msg0)o(02)o(67)o(.h)n(tml)243 4847 y(W)-7
+b(e)30 b(describ)r(e)g(here)g(a)g(small)f(pac)n(k)-5
+b(age)29 b(that)i(can)e(b)r(e)i(used)f(for)g(implemen)n(ting)g(gID)g
+(on)g(P)n(ostgreSQL.)f(It)i(can)e(b)r(e)118 4946 y(found)f(at)f(<h)n
+(ttp://...>)243 5046 y(The)21 b(pac)n(k)-5 b(age)21 b(uses)g(the)h(pro)
+r(cedural)e(language)h(PL/PGsql.)35 b(A)22 b(b)r(etter)g(implemen)n
+(tation)g(w)n(ould)f(probably)g(de\034ne)118 5145 y(the)28
+b(gID)g(as)f(new)g(P)n(ostgres)f(t)n(yp)r(es,)i(and)f(co)r(de)g(all)h
+(this)g(in)f(C.)243 5245 y(The)g(\034les)h(should)f(b)r(e)h(loaded)f
+(in)h(alphab)r(etical)f(order.)1987 5653 y(5)p eop
+%%Page: 6 6
+6 5 bop 118 291 a Fm(4.1)112 b(tree0_enco)s(ding.sql)118
+444 y Fh(This)28 b(\034le)f(de\034nes)h(and)f(p)r(opulates)h(the)f
+(table)h(_b160_digits)d(of)j(\020digits\021)33 b(in)28
+b(base)f(160,)326 604 y Fd(CREATE)41 b(TABLE)g(\\_b160\\_digits)d
+(\(deci)j(integer,)f(code)i(char\);)118 764 y Fh(and)28
+b(the)f(t)n(w)n(o)g(functions)326 924 y Fd(CREATE)41
+b(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er\))d(RETURNS)j(string)
+413 1024 y(AS)j('....')e(LANGUAGE)f('plpgsql';)326 1124
+y(CREATE)h(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er,)o(in)o(te)o
+(ger)o(\))d(RETURNS)k(string)413 1223 y(AS)i('....')e(LANGUAGE)f
+('plpgsql';)118 1384 y Fh(The)22 b(\034rst)h(function)f(returns)g(a)g
+(v)-5 b(ariable)21 b(size)h(enco)r(ding;)i(the)f(second)e(a)h(\034xed)h
+(size)f(enco)r(ding)g(\(the)h(second)e(parameter)118
+1483 y(is)g(the)h(size\),)g(and)f(raises)e(an)i(exception)g(if)h(the)f
+(n)n(um)n(b)r(er)g(is)g(to)r(o)g(large)e(to)i(b)r(e)h(represen)n(ted)e
+(with)h(the)h(requested)e(n)n(um)n(b)r(er)118 1583 y(of)28
+b(digits.)118 1814 y Fm(4.2)112 b(tree1_de\034ne.sql)118
+1967 y Fh(This)28 b(\034le)f(pro)n(vides)f(a)i(function)326
+2127 y Fd(CREATE)41 b(FUNCTION)f(_tree_create\(tex)o(t,)o(in)o(teg)o
+(er)o(,t)o(ext)o(,t)o(ex)o(t\))d(RETURNS)k(bpchar)413
+2227 y(AS)i('....')e(LANGUAGE)f('plpgsql';)118 2387 y
+Fh(that)e(creates)f(a)h(tree)f(infrastructure)g(of)h(either)g(fgID)g
+(or)f(vgID.)h(Assuming)f(y)n(ou)g(ha)n(v)n(e)g(a)h(table)f(\020m)n
+(ytable\021)44 b(with)118 2487 y(primary)26 b(k)n(ey)h(\020m)n
+(yid\021,)g(then)h(calling)326 2647 y Fd(SELECT)41 b(_tree_create\('m)o
+(yt)o(ree)o(',)o(2,')o(my)o(ta)o(ble)o(',)o('m)o(yid)o('\))o(;)118
+2807 y Fh(will)28 b(cause:)220 2967 y(1.)41 b(the)28
+b(creation)e(of)i(a)f(table)508 3131 y Fd(CREATE)41 b(TABLE)h
+(mytree_bkg\()683 3230 y(gid)g(text)g(PRIMARY)e(KEY,)683
+3330 y(nchildren)f(int,)683 3429 y(sid)j(integer)f(REFERENCES)e
+(mytable\(myid\))508 3529 y(\);)508 3629 y(CREATE)i(UNIQUE)g(INDEX)h
+(mytree_bkg_sid)37 b(ON)43 b(mytree_bkg\(sid\);)326 3792
+y Fh(for)27 b(the)h(tree)f(structure.)220 3955 y(2.)41
+b(the)28 b(creation)e(of)i(a)f(view)508 4118 y Fd(CREATE)41
+b(VIEW)h(mytree)f(AS)639 4218 y(SELECT)g(t.gid,n.*)900
+4317 y(FROM)h(mytable)f(n,)i(mytree_bkg)c(t)900 4417
+y(WHERE)j(t.sid=n.myid;)326 4580 y Fh(with:)35 b(a)23
+b(trigger)e(on)i(UPD)n(A)-7 b(TE)25 b(that)e(blo)r(c)n(ks)g(up)r
+(dating)g(the)h(gid)f(and)g(allo)n(ws)f(up)r(dating)h(the)g(no)r(de)h
+(data,)f(a)g(rule)326 4680 y(on)k(DELETE)i(that)f(deletes)f(the)h
+(corresp)r(onding)e(en)n(try)h(b)r(oth)h(in)g(m)n(ytree_bkg)d(and)j(m)n
+(ytable,)f(and)g(a)g(trigger)326 4779 y(ON)h(INSER)-7
+b(T)30 b(that)f(raises)e(an)h(exception)g(and)g(informs)h(the)f(user)g
+(to)h(use)f(the)h(insertion)f(function)h(describ)r(ed)326
+4879 y(b)r(elo)n(w.)220 5042 y(3.)41 b(t)n(w)n(o)26 b(insertion)h
+(functions)h(that)g(compute)g(automatically)e(the)i(gID)g(of)f(the)h
+(new)g(no)r(de:)425 5205 y Ff(\017)41 b Fh(a)27 b(function)i(m)n
+(ytree_insert\(text,text,in)n(teger,text\))d(for)h(insertion)g(sim)n
+(ultaneosly)f(in)i(b)r(oth)g(tables:)508 5305 y(m)n
+(ytree_insert\('2201','hello',0,'not)15 b(m)n(uc)n(h'\))j(inserts)g(a)g
+(new)g(c)n(hild)h(of)f(2201)f(with)h(data1='hello',)h(data2=0)508
+5404 y(and)28 b(data3='not)e(m)n(uc)n(h')1987 5653 y(6)p
+eop
+%%Page: 7 7
+7 6 bop 425 291 a Ff(\017)41 b Fh(a)27 b(function)i(m)n
+(ytree_insert_no)r(de\(text,in)n(teger\))c(for)i(insertion)g(in)h(m)n
+(ytree_bkg)508 390 y(m)n(ytree_insert\('2201',25\))c(inserts)j(in)h(m)n
+(ytree_bkg)e(a)h(new)h(c)n(hild)f(of)h(2201)d(with)j(sid=25)220
+556 y(4.)41 b(a)27 b(function)h(m)n(ytree_mo)n(v)n(e\(text,text\))e
+(that)i(mo)n(v)n(es)e(subtrees:)326 656 y(m)n(ytree_mo)n(v)n
+(e\('2201','23'\))d(mo)n(v)n(es)j(the)i(subtree)f(ro)r(oted)g(at)g
+(2201)f(to)h(a)h(place)f(b)r(elo)n(w)g(23)f(\(ma)n(yb)r(e)i(2307\))220
+822 y(5.)41 b(a)c(function)g(m)n(ytree_len\(\))g(that)h(returns)e(the)i
+(length)f(of)g(the)h(enco)r(dings)f(used)g(in)h(the)f(gID)g(\(2)h
+(here;)j(0)c(if)326 922 y(v)-5 b(ariable)26 b(size\).)118
+1196 y Fi(5)131 b(Non-tree)44 b(hierarc)l(hies)118 1378
+y Fh(sequence)22 b(as)f(id,)j(table)e(with)h(\(id,g-index\))f(with)g(p)
+r(ossibly)g(man)n(y)g(g-indices)f(for)h(eac)n(h)f(id)h(\(if)h(TOO)f
+(man)n(y)-7 b(,)23 b(bad)f(mo)r(del:)118 1478 y(list)28
+b(all)f(genealogies,)f(i.e.,)h(paths)h(from)f(the)h(ro)r(ot\))118
+1752 y Fi(References)160 1934 y Fh([1])41 b(Philip)28
+b(Greenspun,)g Fe(T)-6 b(r)l(e)l(es)29 b(in)h(Or)l(acle)g(SQL)p
+Fh(,)d(in)h Fg(SQL)k(for)g(W)-8 b(eb)31 b(Nerds)289 2033
+y Fh(<h)n(ttp://photo.net/sql/trees.h)n(tml>)160 2200
+y([2])41 b(Jo)r(e)27 b(Celk)n(o,)f Fe(SQL)j(for)i(Smarties)p
+Fh(,)d(in)g Fg(DBMS)j(Online)p Fh(,)26 b(Marc)n(h)h(to)g(June)h(1996)
+289 2299 y(<h)n(ttp://www.dbmsmag.com/9603d06.h)n(tml>)289
+2399 y(<h)n(ttp://www.dbmsmag.com/9604d06.h)n(tml>)289
+2498 y(<h)n(ttp://www.dbmsmag.com/9605d06.h)n(tml>)289
+2598 y(<h)n(ttp://www.dbmsmag.com/9606d06.h)n(tml>)160
+2764 y([3])41 b(Graeme)26 b(Birc)n(hall,)h Fg(DB2)32
+b(UDB)g(V6.1)f(SQL)h(Co)s(okb)s(o)s(ok)p Fh(,)289 2864
+y(<h)n(ttp://ourw)n(orld.compuserv)n(e.com/homepag)o(es/)o(Gra)o
+(eme_Bir)o(c)n(ha)o(ll/HTM_CO)o(OK)o(.HTM>)1987 5653
+y(7)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
new file mode 100644
index 0000000..242fdef
--- /dev/null
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -0,0 +1,593 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2006-2008
+ Copyright (C) Matthias Dieter Wallnöfer 2009-2010
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_tdb
+ *
+ * Component: ldb tdb backend
+ *
+ * Description: core functions for tdb backend
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ *
+ * Modifications:
+ *
+ * - description: make the module use asynchronous calls
+ * date: Feb 2006
+ * Author: Simo Sorce
+ *
+ * - description: make it possible to use event contexts
+ * date: Jan 2008
+ * Author: Simo Sorce
+ *
+ * - description: fix up memory leaks and small bugs
+ * date: Oct 2009
+ * Author: Matthias Dieter Wallnöfer
+ */
+
+#include "ldb_tdb.h"
+#include "ldb_private.h"
+#include "../ldb_key_value/ldb_kv.h"
+#include <tdb.h>
+
+/*
+ lock the database for read - use by ltdb_search and ltdb_sequence_number
+*/
+static int ltdb_lock_read(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ int tdb_ret = 0;
+ int ret;
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ if (tdb_transaction_active(ldb_kv->tdb) == false &&
+ ldb_kv->read_lock_count == 0) {
+ tdb_ret = tdb_lockall_read(ldb_kv->tdb);
+ }
+ if (tdb_ret == 0) {
+ ldb_kv->read_lock_count++;
+ return LDB_SUCCESS;
+ }
+ ret = ltdb_err_map(tdb_error(ldb_kv->tdb));
+ if (ret == LDB_SUCCESS) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+ ldb_debug_set(ldb_module_get_ctx(module),
+ LDB_DEBUG_FATAL,
+ "Failure during ltdb_lock_read(): %s -> %s",
+ tdb_errorstr(ldb_kv->tdb),
+ ldb_strerror(ret));
+ return ret;
+}
+
+/*
+ unlock the database after a ltdb_lock_read()
+*/
+static int ltdb_unlock_read(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ldb_kv_private *ldb_kv =
+ talloc_get_type(data, struct ldb_kv_private);
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+ if (!tdb_transaction_active(ldb_kv->tdb) &&
+ ldb_kv->read_lock_count == 1) {
+ tdb_unlockall_read(ldb_kv->tdb);
+ ldb_kv->read_lock_count--;
+ return 0;
+ }
+ ldb_kv->read_lock_count--;
+ return 0;
+}
+
+static int ltdb_store(struct ldb_kv_private *ldb_kv,
+ struct ldb_val ldb_key,
+ struct ldb_val ldb_data,
+ int flags)
+{
+ TDB_DATA key = {
+ .dptr = ldb_key.data,
+ .dsize = ldb_key.length
+ };
+ TDB_DATA data = {
+ .dptr = ldb_data.data,
+ .dsize = ldb_data.length
+ };
+ bool transaction_active = tdb_transaction_active(ldb_kv->tdb);
+ if (transaction_active == false){
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+ return tdb_store(ldb_kv->tdb, key, data, flags);
+}
+
+static int ltdb_error(struct ldb_kv_private *ldb_kv)
+{
+ return ltdb_err_map(tdb_error(ldb_kv->tdb));
+}
+
+static const char *ltdb_errorstr(struct ldb_kv_private *ldb_kv)
+{
+ return tdb_errorstr(ldb_kv->tdb);
+}
+
+static int ltdb_delete(struct ldb_kv_private *ldb_kv, struct ldb_val ldb_key)
+{
+ TDB_DATA tdb_key = {
+ .dptr = ldb_key.data,
+ .dsize = ldb_key.length
+ };
+ bool transaction_active = tdb_transaction_active(ldb_kv->tdb);
+ if (transaction_active == false){
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+ return tdb_delete(ldb_kv->tdb, tdb_key);
+}
+
+static int ltdb_transaction_start(struct ldb_kv_private *ldb_kv)
+{
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(ldb_kv->module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ return tdb_transaction_start(ldb_kv->tdb);
+}
+
+static int ltdb_transaction_cancel(struct ldb_kv_private *ldb_kv)
+{
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(ldb_kv->module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ return tdb_transaction_cancel(ldb_kv->tdb);
+}
+
+static int ltdb_transaction_prepare_commit(struct ldb_kv_private *ldb_kv)
+{
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(ldb_kv->module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ return tdb_transaction_prepare_commit(ldb_kv->tdb);
+}
+
+static int ltdb_transaction_commit(struct ldb_kv_private *ldb_kv)
+{
+ pid_t pid = getpid();
+
+ if (ldb_kv->pid != pid) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(ldb_kv->module),
+ __location__
+ ": Reusing ldb opened by pid %d in "
+ "process %d\n",
+ ldb_kv->pid,
+ pid);
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ return tdb_transaction_commit(ldb_kv->tdb);
+}
+struct kv_ctx {
+ ldb_kv_traverse_fn kv_traverse_fn;
+ void *ctx;
+ struct ldb_kv_private *ldb_kv;
+ int (*parser)(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data);
+ int parser_ret;
+};
+
+static int ltdb_traverse_fn_wrapper(struct tdb_context *tdb,
+ TDB_DATA tdb_key,
+ TDB_DATA tdb_data,
+ void *ctx)
+{
+ struct kv_ctx *kv_ctx = ctx;
+ struct ldb_val key = {
+ .length = tdb_key.dsize,
+ .data = tdb_key.dptr,
+ };
+ struct ldb_val data = {
+ .length = tdb_data.dsize,
+ .data = tdb_data.dptr,
+ };
+ return kv_ctx->kv_traverse_fn(kv_ctx->ldb_kv, key, data, kv_ctx->ctx);
+}
+
+static int ltdb_traverse_fn(struct ldb_kv_private *ldb_kv,
+ ldb_kv_traverse_fn fn,
+ void *ctx)
+{
+ struct kv_ctx kv_ctx = {
+ .kv_traverse_fn = fn, .ctx = ctx, .ldb_kv = ldb_kv};
+ if (tdb_transaction_active(ldb_kv->tdb)) {
+ return tdb_traverse(
+ ldb_kv->tdb, ltdb_traverse_fn_wrapper, &kv_ctx);
+ } else {
+ return tdb_traverse_read(
+ ldb_kv->tdb, ltdb_traverse_fn_wrapper, &kv_ctx);
+ }
+}
+
+static int ltdb_update_in_iterate(struct ldb_kv_private *ldb_kv,
+ struct ldb_val ldb_key,
+ struct ldb_val ldb_key2,
+ struct ldb_val ldb_data,
+ void *state)
+{
+ int tdb_ret;
+ struct ldb_context *ldb;
+ struct ldb_kv_reindex_context *ctx =
+ (struct ldb_kv_reindex_context *)state;
+ struct ldb_module *module = ldb_kv->module;
+ TDB_DATA key = {
+ .dptr = ldb_key.data,
+ .dsize = ldb_key.length
+ };
+ TDB_DATA key2 = {
+ .dptr = ldb_key2.data,
+ .dsize = ldb_key2.length
+ };
+ TDB_DATA data = {
+ .dptr = ldb_data.data,
+ .dsize = ldb_data.length
+ };
+
+ ldb = ldb_module_get_ctx(module);
+
+ tdb_ret = tdb_delete(ldb_kv->tdb, key);
+ if (tdb_ret != 0) {
+ ldb_debug(ldb,
+ LDB_DEBUG_ERROR,
+ "Failed to delete %*.*s "
+ "for rekey as %*.*s: %s",
+ (int)key.dsize,
+ (int)key.dsize,
+ (const char *)key.dptr,
+ (int)key2.dsize,
+ (int)key2.dsize,
+ (const char *)key.dptr,
+ tdb_errorstr(ldb_kv->tdb));
+ ctx->error = ltdb_err_map(tdb_error(ldb_kv->tdb));
+ return -1;
+ }
+ tdb_ret = tdb_store(ldb_kv->tdb, key2, data, 0);
+ if (tdb_ret != 0) {
+ ldb_debug(ldb,
+ LDB_DEBUG_ERROR,
+ "Failed to rekey %*.*s as %*.*s: %s",
+ (int)key.dsize,
+ (int)key.dsize,
+ (const char *)key.dptr,
+ (int)key2.dsize,
+ (int)key2.dsize,
+ (const char *)key.dptr,
+ tdb_errorstr(ldb_kv->tdb));
+ ctx->error = ltdb_err_map(tdb_error(ldb_kv->tdb));
+ return -1;
+ }
+ return tdb_ret;
+}
+
+static int ltdb_parse_record_wrapper(TDB_DATA tdb_key,
+ TDB_DATA tdb_data,
+ void *ctx)
+{
+ struct kv_ctx *kv_ctx = ctx;
+ struct ldb_val key = {
+ .length = tdb_key.dsize,
+ .data = tdb_key.dptr,
+ };
+ struct ldb_val data = {
+ .length = tdb_data.dsize,
+ .data = tdb_data.dptr,
+ };
+
+ kv_ctx->parser_ret = kv_ctx->parser(key, data, kv_ctx->ctx);
+ return kv_ctx->parser_ret;
+}
+
+static int ltdb_parse_record(struct ldb_kv_private *ldb_kv,
+ struct ldb_val ldb_key,
+ int (*parser)(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data),
+ void *ctx)
+{
+ struct kv_ctx kv_ctx = {.parser = parser, .ctx = ctx, .ldb_kv = ldb_kv};
+ TDB_DATA key = {
+ .dptr = ldb_key.data,
+ .dsize = ldb_key.length
+ };
+ int ret;
+
+ if (tdb_transaction_active(ldb_kv->tdb) == false &&
+ ldb_kv->read_lock_count == 0) {
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ ret = tdb_parse_record(
+ ldb_kv->tdb, key, ltdb_parse_record_wrapper, &kv_ctx);
+ if (kv_ctx.parser_ret != LDB_SUCCESS) {
+ return kv_ctx.parser_ret;
+ } else if (ret == 0) {
+ return LDB_SUCCESS;
+ }
+ return ltdb_err_map(tdb_error(ldb_kv->tdb));
+}
+
+static int ltdb_iterate_range(struct ldb_kv_private *ldb_kv,
+ struct ldb_val start_key,
+ struct ldb_val end_key,
+ ldb_kv_traverse_fn fn,
+ void *ctx)
+{
+ /*
+ * We do not implement this operation because we do not know how to
+ * iterate from one key to the next (in a sorted fashion).
+ *
+ * We could mimic it potentially, but it would violate boundaries of
+ * knowledge (data type representation).
+ */
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static const char *ltdb_name(struct ldb_kv_private *ldb_kv)
+{
+ return tdb_name(ldb_kv->tdb);
+}
+
+static bool ltdb_changed(struct ldb_kv_private *ldb_kv)
+{
+ int seq = tdb_get_seqnum(ldb_kv->tdb);
+ bool has_changed = (seq != ldb_kv->tdb_seqnum);
+
+ ldb_kv->tdb_seqnum = seq;
+
+ return has_changed;
+}
+
+static bool ltdb_transaction_active(struct ldb_kv_private *ldb_kv)
+{
+ return tdb_transaction_active(ldb_kv->tdb);
+}
+
+/*
+ * Get an estimate of the number of records in a tdb database.
+ *
+ * This implementation will overestimate the number of records in a sparsely
+ * populated database. The size estimate is only used for allocating
+ * an in memory tdb to cache index records during a reindex, overestimating
+ * the contents is acceptable, and preferable to underestimating
+ */
+#define RECORD_SIZE 500
+static size_t ltdb_get_size(struct ldb_kv_private *ldb_kv)
+{
+ size_t map_size = tdb_map_size(ldb_kv->tdb);
+ size_t size = map_size / RECORD_SIZE;
+
+ return size;
+}
+
+/*
+ * Start a sub transaction
+ * As TDB does not currently support nested transactions, we do nothing and
+ * return LDB_SUCCESS
+ */
+static int ltdb_nested_transaction_start(struct ldb_kv_private *ldb_kv)
+{
+ return LDB_SUCCESS;
+}
+
+/*
+ * Commit a sub transaction
+ * As TDB does not currently support nested transactions, we do nothing and
+ * return LDB_SUCCESS
+ */
+static int ltdb_nested_transaction_commit(struct ldb_kv_private *ldb_kv)
+{
+ return LDB_SUCCESS;
+}
+
+/*
+ * Cancel a sub transaction
+ * As TDB does not currently support nested transactions, we do nothing and
+ * return LDB_SUCCESS
+ */
+static int ltdb_nested_transaction_cancel(struct ldb_kv_private *ldb_kv)
+{
+ return LDB_SUCCESS;
+}
+
+static const struct kv_db_ops key_value_ops = {
+ /* No support for any additional features */
+ .options = 0,
+
+ .store = ltdb_store,
+ .delete = ltdb_delete,
+ .iterate = ltdb_traverse_fn,
+ .update_in_iterate = ltdb_update_in_iterate,
+ .fetch_and_parse = ltdb_parse_record,
+ .iterate_range = ltdb_iterate_range,
+ .lock_read = ltdb_lock_read,
+ .unlock_read = ltdb_unlock_read,
+ .begin_write = ltdb_transaction_start,
+ .prepare_write = ltdb_transaction_prepare_commit,
+ .finish_write = ltdb_transaction_commit,
+ .abort_write = ltdb_transaction_cancel,
+ .error = ltdb_error,
+ .errorstr = ltdb_errorstr,
+ .name = ltdb_name,
+ .has_changed = ltdb_changed,
+ .transaction_active = ltdb_transaction_active,
+ .get_size = ltdb_get_size,
+ .begin_nested_write = ltdb_nested_transaction_start,
+ .finish_nested_write = ltdb_nested_transaction_commit,
+ .abort_nested_write = ltdb_nested_transaction_cancel,
+};
+
+/*
+ connect to the database
+*/
+int ltdb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[],
+ struct ldb_module **_module)
+{
+ const char *path;
+ int tdb_flags, open_flags;
+ struct ldb_kv_private *ldb_kv;
+
+ /*
+ * We hold locks, so we must use a private event context
+ * on each returned handle
+ */
+ ldb_set_require_private_event_context(ldb);
+
+ /* parse the url */
+ if (strchr(url, ':')) {
+ if (strncmp(url, "tdb://", 6) != 0) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Invalid tdb URL '%s'", url);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ path = url+6;
+ } else {
+ path = url;
+ }
+
+ tdb_flags = TDB_DEFAULT | TDB_SEQNUM | TDB_DISALLOW_NESTING;
+
+ /* check for the 'nosync' option */
+ if (flags & LDB_FLG_NOSYNC) {
+ tdb_flags |= TDB_NOSYNC;
+ }
+
+ /* and nommap option */
+ if (flags & LDB_FLG_NOMMAP) {
+ tdb_flags |= TDB_NOMMAP;
+ }
+
+ ldb_kv = talloc_zero(ldb, struct ldb_kv_private);
+ if (!ldb_kv) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (flags & LDB_FLG_RDONLY) {
+ /*
+ * This is weird, but because we can only have one tdb
+ * in this process, and the other one could be
+ * read-write, we can't use the tdb readonly. Plus a
+ * read only tdb prohibits the all-record lock.
+ */
+ open_flags = O_RDWR;
+
+ ldb_kv->read_only = true;
+
+ } else if (flags & LDB_FLG_DONT_CREATE_DB) {
+ /*
+ * This is used by ldbsearch to prevent creation of the database
+ * if the name is wrong
+ */
+ open_flags = O_RDWR;
+ } else {
+ /*
+ * This is the normal case
+ */
+ open_flags = O_CREAT | O_RDWR;
+ }
+
+ ldb_kv->kv_ops = &key_value_ops;
+
+ errno = 0;
+ /* note that we use quite a large default hash size */
+ ldb_kv->tdb = ltdb_wrap_open(ldb_kv,
+ path,
+ 10000,
+ tdb_flags,
+ open_flags,
+ ldb_get_create_perms(ldb),
+ ldb);
+ if (!ldb_kv->tdb) {
+ ldb_asprintf_errstring(ldb,
+ "Unable to open tdb '%s': %s", path, strerror(errno));
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Unable to open tdb '%s': %s", path, strerror(errno));
+ talloc_free(ldb_kv);
+ if (errno == EACCES || errno == EPERM) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_kv_init_store(
+ ldb_kv, "ldb_tdb backend", ldb, options, _module);
+}
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
new file mode 100644
index 0000000..5395d42
--- /dev/null
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -0,0 +1,16 @@
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "tdb.h"
+#include "ldb_module.h"
+
+TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn);
+int ltdb_err_map(enum TDB_ERROR tdb_code);
+
+struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *path, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ struct ldb_context *ldb);
+int ltdb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[],
+ struct ldb_module **_module);
diff --git a/lib/ldb/ldb_tdb/ldb_tdb_err_map.c b/lib/ldb/ldb_tdb/ldb_tdb_err_map.c
new file mode 100644
index 0000000..41e5318
--- /dev/null
+++ b/lib/ldb/ldb_tdb/ldb_tdb_err_map.c
@@ -0,0 +1,84 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2006-2008
+ Copyright (C) Matthias Dieter Wallnöfer 2009-2010
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_tdb
+ *
+ * Component: ldb tdb backend
+ *
+ * Description: core functions for tdb backend
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ *
+ * Modifications:
+ *
+ * - description: make the module use asynchronous calls
+ * date: Feb 2006
+ * Author: Simo Sorce
+ *
+ * - description: make it possible to use event contexts
+ * date: Jan 2008
+ * Author: Simo Sorce
+ *
+ * - description: fix up memory leaks and small bugs
+ * date: Oct 2009
+ * Author: Matthias Dieter Wallnöfer
+ */
+
+#include "ldb_tdb.h"
+#include <tdb.h>
+
+/*
+ map a tdb error code to a ldb error code
+*/
+int ltdb_err_map(enum TDB_ERROR tdb_code)
+{
+ switch (tdb_code) {
+ case TDB_SUCCESS:
+ return LDB_SUCCESS;
+ case TDB_ERR_CORRUPT:
+ case TDB_ERR_OOM:
+ case TDB_ERR_EINVAL:
+ return LDB_ERR_OPERATIONS_ERROR;
+ case TDB_ERR_IO:
+ return LDB_ERR_PROTOCOL_ERROR;
+ case TDB_ERR_LOCK:
+ case TDB_ERR_NOLOCK:
+ return LDB_ERR_BUSY;
+ case TDB_ERR_LOCK_TIMEOUT:
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ case TDB_ERR_EXISTS:
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ case TDB_ERR_NOEXIST:
+ return LDB_ERR_NO_SUCH_OBJECT;
+ case TDB_ERR_RDONLY:
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ default:
+ break;
+ }
+ return LDB_ERR_OTHER;
+}
diff --git a/lib/ldb/ldb_tdb/ldb_tdb_init.c b/lib/ldb/ldb_tdb/ldb_tdb_init.c
new file mode 100644
index 0000000..b18c98a
--- /dev/null
+++ b/lib/ldb/ldb_tdb/ldb_tdb_init.c
@@ -0,0 +1,59 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2006-2008
+ Copyright (C) Matthias Dieter Wallnöfer 2009-2010
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb_tdb
+ *
+ * Component: ldb tdb backend
+ *
+ * Description: core functions for tdb backend
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ *
+ * Modifications:
+ *
+ * - description: make the module use asynchronous calls
+ * date: Feb 2006
+ * Author: Simo Sorce
+ *
+ * - description: make it possible to use event contexts
+ * date: Jan 2008
+ * Author: Simo Sorce
+ *
+ * - description: fix up memory leaks and small bugs
+ * date: Oct 2009
+ * Author: Matthias Dieter Wallnöfer
+ */
+
+#include "ldb_tdb.h"
+#include "ldb_private.h"
+
+int ldb_tdb_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_backend("tdb", ltdb_connect, false);
+}
diff --git a/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
new file mode 100644
index 0000000..bc702a2
--- /dev/null
+++ b/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
@@ -0,0 +1,162 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb_tdb.h"
+#include "dlinklist.h"
+
+static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+ va_list ap;
+ const char *name = tdb_name(tdb);
+ struct ldb_context *ldb = talloc_get_type(tdb_get_logging_private(tdb), struct ldb_context);
+ enum ldb_debug_level ldb_level;
+ char *message;
+
+ if (ldb == NULL)
+ return;
+
+ va_start(ap, fmt);
+ message = talloc_vasprintf(ldb, fmt, ap);
+ va_end(ap);
+
+ switch (level) {
+ case TDB_DEBUG_FATAL:
+ ldb_level = LDB_DEBUG_FATAL;
+ break;
+ case TDB_DEBUG_ERROR:
+ ldb_level = LDB_DEBUG_ERROR;
+ break;
+ case TDB_DEBUG_WARNING:
+ ldb_level = LDB_DEBUG_WARNING;
+ break;
+ case TDB_DEBUG_TRACE:
+ ldb_level = LDB_DEBUG_TRACE;
+ break;
+ default:
+ ldb_level = LDB_DEBUG_FATAL;
+ }
+
+ ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message);
+ talloc_free(message);
+}
+
+/*
+ the purpose of this code is to work around the braindead posix locking
+ rules, to allow us to have a ldb open more than once while allowing
+ locking to work
+
+ TDB2 handles multiple opens, so we don't have this problem there.
+*/
+
+struct ltdb_wrap {
+ struct ltdb_wrap *next, *prev;
+ struct tdb_context *tdb;
+ dev_t device;
+ ino_t inode;
+ pid_t pid;
+};
+
+static struct ltdb_wrap *tdb_list;
+
+/* destroy the last connection to a tdb */
+static int ltdb_wrap_destructor(struct ltdb_wrap *w)
+{
+ tdb_close(w->tdb);
+ DLIST_REMOVE(tdb_list, w);
+ return 0;
+}
+
+/*
+ wrapped connection to a tdb database. The caller should _not_ free
+ this as it is not a talloc structure (as tdb does not use talloc
+ yet). It will auto-close when the caller frees the mem_ctx that is
+ passed to this call
+ */
+struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *path, int hash_size,
+ int tdb_flags,
+ int open_flags, mode_t mode,
+ struct ldb_context *ldb)
+{
+ struct ltdb_wrap *w;
+ struct tdb_logging_context lctx;
+ struct stat st;
+
+ if (stat(path, &st) == 0) {
+ for (w=tdb_list;w;w=w->next) {
+ if (st.st_dev == w->device && st.st_ino == w->inode) {
+ pid_t pid = getpid();
+ int ret;
+ if (!talloc_reference(mem_ctx, w)) {
+ return NULL;
+ }
+ if (w->pid != pid) {
+ ret = tdb_reopen(w->tdb);
+ if (ret != 0) {
+ /*
+ * Avoid use-after-free:
+ * on fail the TDB
+ * is closed!
+ */
+ DLIST_REMOVE(tdb_list,
+ w);
+ return NULL;
+ }
+ w->pid = pid;
+ }
+ return w->tdb;
+ }
+ }
+ }
+
+ w = talloc(mem_ctx, struct ltdb_wrap);
+ if (w == NULL) {
+ return NULL;
+ }
+
+ lctx.log_fn = ltdb_log_fn;
+ lctx.log_private = ldb;
+ w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode,
+ &lctx, NULL);
+ if (w->tdb == NULL) {
+ talloc_free(w);
+ return NULL;
+ }
+
+ if (fstat(tdb_fd(w->tdb), &st) != 0) {
+ tdb_close(w->tdb);
+ talloc_free(w);
+ return NULL;
+ }
+
+ w->device = st.st_dev;
+ w->inode = st.st_ino;
+ w->pid = getpid();
+
+ talloc_set_destructor(w, ltdb_wrap_destructor);
+
+ DLIST_ADD(tdb_list, w);
+
+ return w->tdb;
+}
diff --git a/lib/ldb/mainpage.dox b/lib/ldb/mainpage.dox
new file mode 100644
index 0000000..bbd8d9c
--- /dev/null
+++ b/lib/ldb/mainpage.dox
@@ -0,0 +1,80 @@
+/**
+
+\mainpage ldb
+
+\section Overview
+
+ldb is a LDAP-like embedded database. It is not at all LDAP standards
+compliant, so if you want a standards compliant database then please
+see the excellent <a href="http://www.openldap.org/">OpenLDAP</a>
+project.<p>
+
+What ldb does is provide a fast database with an LDAP-like API
+designed to be used within an application. In some ways it can be seen
+as a intermediate solution between key-value pair databases and a real
+LDAP database.<p>
+
+ldb is the database engine used in Samba4.
+
+\section Features
+
+The main features that separate ldb from other solutions are:
+ - Safe multi-reader, multi-writer, using byte range locking
+ - LDAP-like API
+ - fast operation
+ - choice of local tdb, local sqlite3 or remote LDAP backends
+ - integration with <a href="http://talloc.samba.org">talloc</a>
+ - schema-less operation, for trivial setup
+ - modules for extensions (such as schema support)
+ - easy setup of indexes and attribute properties
+ - ldbedit tool for database editing (reminiscent of 'vipw')
+ - ldif for import/export
+
+\section Documentation
+
+ldb has limited programmer and administrator documentation:
+ - a list of <a href="globals_func.html">functions</a>
+ - a list of <a href="examples.html">examples</a>
+ - a list of <a href="annotated.html">data structures</a>
+ - a list of <a href="globals_defs.html">constants</a>
+
+If you need more information than is presented in this document, you
+may wish to look at the source code, especially the source code in the
+<a href="http://samba.org/ftp/unpacked/samba4/source/lib/ldb/tools/">tools directory</a>.
+
+ldb makes use of the LDAP Data Interchange Format (LDIF), which is
+documented in <a href="http://www.ietf.org/rfc/rfc2849.txt">RFC
+2849</a>.
+
+\section Support
+
+ldb does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+\section Download
+
+You can download the latest release either via rsync or anonymous
+svn. To fetch via svn use the following commands:
+
+\verbatim
+ svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/ldb ldb
+ svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/tdb tdb
+ svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/talloc talloc
+\endverbatim
+
+To fetch via rsync use these commands:
+
+\verbatim
+ rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/ldb .
+ rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/tdb .
+ rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/talloc .
+\endverbatim
+
+\section Credits
+
+ldb is another product of the prolific <a href="http://samba.org/~tridge/">Andrew Tridgell</a>.
+
+*/
diff --git a/lib/ldb/man/ldb.3.xml b/lib/ldb/man/ldb.3.xml
new file mode 100644
index 0000000..1c0a2ec
--- /dev/null
+++ b/lib/ldb/man/ldb.3.xml
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldb.3">
+
+<refmeta>
+ <refentrytitle>ldb</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo class="source">LDB</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">1.1</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+ <refname>ldb</refname>
+ <refclass>The Samba Project</refclass>
+ <refpurpose>A light-weight database library</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <synopsis>#include &lt;ldb.h&gt;</synopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>description</title>
+
+ <para>
+ldb is a light weight embedded database library and API. With a
+programming interface that is very similar to LDAP, ldb can store its
+data either in a tdb(3) database or in a real LDAP database.
+ </para>
+
+ <para>
+When used with the tdb backend ldb does not require any database
+daemon. Instead, ldb function calls are processed immediately by the
+ldb library, which does IO directly on the database, while allowing
+multiple readers/writers using operating system byte range locks. This
+leads to an API with very low overheads, often resulting in speeds of
+more than 10x what can be achieved with a more traditional LDAP
+architecture.
+ </para>
+
+ <para>
+In a taxonomy of databases ldb would sit half way between key/value
+pair databases (such as berkeley db or tdb) and a full LDAP
+database. With a structured attribute oriented API like LDAP and good
+indexing capabilities, ldb can be used for quite sophisticated
+applications that need a light weight database, without the
+administrative overhead of a full LDAP installation.
+ </para>
+
+ <para>
+Included with ldb are a number of useful command line tools for
+manipulating a ldb database. These tools are similar in style to the
+equivalent ldap command line tools.
+ </para>
+
+ <para>
+In its default mode of operation with a tdb backend, ldb can also be
+seen as a "schema-less LDAP". By default ldb does not require a
+schema, which greatly reduces the complexity of getting started with
+ldb databases. As the complexity of you application grows you can take
+advantage of some of the optional schema-like attributes that ldb
+offers, or you can migrate to using the full LDAP api while keeping
+your exiting ldb code.
+ </para>
+
+ <para>
+If you are new to ldb, then I suggest starting with the manual pages
+for ldbsearch(1) and ldbedit(1), and experimenting with a local
+database. Then I suggest you look at the ldb_connect(3) and
+ldb_search(3) manual pages.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>TOOLS</title>
+
+ <itemizedlist>
+ <listitem><para>
+ <application>ldbsearch(1)</application>
+ - command line ldb search utility
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbedit(1)</application>
+ - edit all or part of a ldb database using your favourite editor
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbadd(1)</application>
+ - add records to a ldb database using LDIF formatted input
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbdel(1)</application>
+ - delete records from a ldb database
+ </para></listitem>
+
+ <listitem><para>
+ <application>ldbmodify(1)</application>
+ - modify records in a ldb database using LDIF formatted input
+ </para></listitem>
+ </itemizedlist>
+</refsect1>
+
+<refsect1>
+ <title>FUNCTIONS</title>
+
+ <itemizedlist>
+ <listitem><para>
+ <function>ldb_connect(3)</function>
+ - connect to a ldb backend
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_search(3)</function>
+ - perform a database search
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_add(3)</function>
+ - add a record to the database
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_delete(3)</function>
+ - delete a record from the database
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_modify(3)</function>
+ - modify a record in the database
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_errstring(3)</function>
+ - retrieve extended error information from the last operation
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_write(3)</function>
+ - write a LDIF formatted message
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_write_file(3)</function>
+ - write a LDIF formatted message to a file
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read(3)</function>
+ - read a LDIF formatted message
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read_free(3)</function>
+ - free the result of a ldb_ldif_read()
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read_file(3)</function>
+ - read a LDIF message from a file
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_ldif_read_string(3)</function>
+ - read a LDIF message from a string
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_msg_find_element(3)</function>
+ - find an element in a ldb_message
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_val_equal_exact(3)</function>
+ - compare two ldb_val structures
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_msg_find_val(3)</function>
+ - find an element by value
+ </para></listitem>
+
+ <listitem><para>
+ <function>ldb_msg_add_empty(3)</function>
+ - add an empty message element to a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_add(3)</function>
+ - add a non-empty message element to a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_element_compare(3)</function>
+ - compare two ldb_message_element structures
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_int(3)</function>
+ - return an integer value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_uint(3)</function>
+ - return an unsigned integer value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_double(3)</function>
+ - return a double value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_msg_find_string(3)</function>
+ - return a string value from a ldb_message
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_set_alloc(3)</function>
+ - set the memory allocation function to be used by ldb
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_set_debug(3)</function>
+ - set a debug handler to be used by ldb
+ </para></listitem>
+
+
+ <listitem><para>
+ <function>ldb_set_debug_stderr(3)</function>
+ - set a debug handler for stderr output
+ </para></listitem>
+ </itemizedlist>
+</refsect1>
+
+<refsect1>
+ <title>Author</title>
+
+ <para>
+ ldb was written by
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>
+ldb is released under the GNU Lesser General Public License version 2
+or later. Please see the file COPYING for license details.
+ </para>
+</refsect1>
+</refentry>
diff --git a/lib/ldb/man/ldbadd.1.xml b/lib/ldb/man/ldbadd.1.xml
new file mode 100644
index 0000000..4736b3b
--- /dev/null
+++ b/lib/ldb/man/ldbadd.1.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbadd.1">
+
+<refmeta>
+ <refentrytitle>ldbadd</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">LDB</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">1.1</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbadd</refname>
+ <refpurpose>Command-line utility for adding records to an LDB</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbadd</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">ldif-file1</arg>
+ <arg choice="opt">ldif-file2</arg>
+ <arg choice="opt">...</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbadd adds records to an ldb(3) database. It reads
+ the ldif(5) files specified on the command line and adds
+ the records from these files to the LDB database, which is specified
+ by the -H option or the LDB_URL environment variable.
+ </para>
+
+ <para>If - is specified as a ldb file, the ldif input is read from
+ standard input.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(3) for details.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overridden by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 1.1 of LDB.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(3), ldbmodify, ldbdel, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/lib/ldb/man/ldbdel.1.xml b/lib/ldb/man/ldbdel.1.xml
new file mode 100644
index 0000000..c4cd450
--- /dev/null
+++ b/lib/ldb/man/ldbdel.1.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbdel.1">
+
+<refmeta>
+ <refentrytitle>ldbdel</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">LDB</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">1.1</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbdel</refname>
+ <refpurpose>Command-line program for deleting LDB records</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbdel</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">dn</arg>
+ <arg choice="opt">...</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbdel deletes records from an ldb(3) database.
+ It deletes the records identified by the dn's specified
+ on the command-line. </para>
+
+ <para>ldbdel uses either the database that is specified with
+ the -H option or the database specified by the LDB_URL environment
+ variable.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(3) for details.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overridden by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 1.1 of LDB.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(3), ldbmodify, ldbadd, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>ldbdel was written by Andrew Tridgell.</para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/lib/ldb/man/ldbedit.1.xml b/lib/ldb/man/ldbedit.1.xml
new file mode 100644
index 0000000..627d20c
--- /dev/null
+++ b/lib/ldb/man/ldbedit.1.xml
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbedit.1">
+
+ <refmeta>
+ <refentrytitle>ldbedit</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">LDB</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">1.1</refmiscinfo>
+ </refmeta>
+
+
+ <refnamediv>
+ <refname>ldbedit</refname>
+ <refpurpose>Edit LDB databases using your preferred editor</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbedit</command>
+ <arg choice="opt">-?</arg>
+ <arg choice="opt">--usage</arg>
+ <arg choice="opt">-s base|one|sub</arg>
+ <arg choice="opt">-b basedn</arg>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-e editor</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">expression</arg>
+ <arg rep="repeat" choice="opt">attributes</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbedit is a utility that allows you to edit LDB entries (in
+ tdb files, sqlite files or LDAP servers) using your preferred editor.
+ ldbedit generates an LDIF file based on your query, allows you to edit
+ the LDIF, and then merges that LDIF back into the LDB backend.
+ </para>
+
+</refsect1>
+
+
+ <refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-?</term>
+ <term>--help</term>
+ <listitem>
+ <para>
+ Show list of available options, and a phrase describing what that option
+ does.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>--usage</term>
+ <listitem>
+ <para>
+ Show list of available options. This is similar to the help option,
+ however it does not provide any description, and is hence shorter.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem>
+ <para>
+ LDB URL to connect to. For a tdb database,
+ this will be of the form
+ tdb://<replaceable>filename</replaceable>.
+ For a LDAP connection over unix domain
+ sockets, this will be of the form
+ ldapi://<replaceable>socket</replaceable>. For
+ a (potentially remote) LDAP connection over
+ TCP, this will be of the form
+ ldap://<replaceable>hostname</replaceable>. For
+ an SQLite database, this will be of the form
+ sqlite://<replaceable>filename</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s one|sub|base</term>
+ <listitem><para>Search scope to use. One-level, subtree or base.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a</term>
+ <term>-all</term>
+ <listitem>
+ <para>Edit all records. This allows you to
+ apply the same change to a number of records
+ at once. You probably want to combine this
+ with an expression of the form
+ "objectclass=*".
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-e editor</term>
+ <term>--editor editor</term>
+ <listitem>
+ <para>Specify the editor that should be used (overrides
+ the VISUAL and EDITOR environment
+ variables). If this option is not used, and
+ neither VISUAL nor EDITOR environment variables
+ are set, then the vi editor will be used.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-b basedn</term>
+ <listitem><para>Specify Base Distinguished Name to use.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-v</term>
+ <term>--verbose</term>
+ <listitem>
+ <para>Make ldbedit more verbose about the
+ operations that are being performed. Without
+ this option, ldbedit will only provide a
+ summary change line.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </refsect1>
+
+ <refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>LDB_URL</term>
+ <listitem>
+ <para>LDB URL to connect to. This can be
+ overridden by using the -H command-line option.)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>VISUAL and EDITOR</term>
+ <listitem>
+ <para>
+ Environment variables used to determine what
+ editor to use. VISUAL takes precedence over
+ EDITOR, and both are overridden by the
+ -e command-line option.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </refsect1>
+
+ <refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 1.1 of LDB.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(3), ldbmodify(1), ldbdel(1), ldif(5), vi(1)</para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ ldb was written by
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+ If you wish to report a problem or make a suggestion then please see
+ the <ulink url="http://ldb.samba.org/"/> web site for
+ current contact and maintainer information.
+ </para>
+
+ <para>
+ This manpage was written by Jelmer Vernooij and updated
+ by Brad Hards.
+ </para>
+
+ </refsect1>
+
+</refentry>
diff --git a/lib/ldb/man/ldbmodify.1.xml b/lib/ldb/man/ldbmodify.1.xml
new file mode 100644
index 0000000..ddeeee7
--- /dev/null
+++ b/lib/ldb/man/ldbmodify.1.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbmodify.1">
+
+<refmeta>
+ <refentrytitle>ldbmodify</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">LDB</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">1.1</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbmodify</refname>
+ <refpurpose>Modify records in a LDB database</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbmodify</command>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">ldif-file</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>
+ ldbmodify changes, adds and deletes records in a LDB database.
+ The changes that should be made to the LDB database are read from
+ the specified LDIF-file. If - is specified as the filename, input is read from stdin.
+ </para>
+
+ <para>For now, see ldapmodify(1) for details on the LDIF file format.</para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(3) for details.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overridden by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 1.1 of LDB.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(3), ldbedit</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/lib/ldb/man/ldbrename.1.xml b/lib/ldb/man/ldbrename.1.xml
new file mode 100644
index 0000000..897c40e
--- /dev/null
+++ b/lib/ldb/man/ldbrename.1.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbrename.1">
+
+<refmeta>
+ <refentrytitle>ldbrename</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">LDB</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">1.1</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbrename</refname>
+ <refpurpose>Edit LDB databases using your favorite editor</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbrename</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-o options</arg>
+ <arg choice="req">olddn</arg>
+ <arg choice="req">newdn</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbrename is a utility that allows you to rename trees in
+ an LDB database based by DN. This utility takes
+ two arguments: the original
+ DN name of the top element and the DN to change it to.
+ </para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(3) for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o options</term>
+ <listitem><para>Extra ldb options, such as
+ modules.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overridden by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 1.1 of LDB.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(3), ldbmodify, ldbdel, ldif(5)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/lib/ldb/man/ldbsearch.1.xml b/lib/ldb/man/ldbsearch.1.xml
new file mode 100644
index 0000000..b853992
--- /dev/null
+++ b/lib/ldb/man/ldbsearch.1.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="ldbsearch.1">
+
+<refmeta>
+ <refentrytitle>ldbsearch</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">LDB</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">1.1</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ldbsearch</refname>
+ <refpurpose>Search for records in a LDB database</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ldbsearch</command>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-s base|one|sub</arg>
+ <arg choice="opt">-b basedn</arg>
+ <arg chioce="opt">-i</arg>
+ <arg choice="opt">-H LDB-URL</arg>
+ <arg choice="opt">expression</arg>
+ <arg choice="opt">attributes</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ldbsearch searches a LDB database for records matching the
+ specified expression (see the ldapsearch(1) manpage for
+ a description of the expression format). For each
+ record, the specified attributes are printed.
+ </para>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Show list of available options.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H &lt;ldb-url&gt;</term>
+ <listitem><para>
+ LDB URL to connect to. See ldb(3) for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s one|sub|base</term>
+ <listitem><para>Search scope to use. One-level, subtree or base.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i</term>
+ <listitem><para>Read search expressions from stdin. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-b basedn</term>
+ <listitem><para>Specify Base DN to use.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>ENVIRONMENT</title>
+
+ <variablelist>
+ <varlistentry><term>LDB_URL</term>
+ <listitem><para>LDB URL to connect to (can be overridden by using the
+ -H command-line option.)</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 1.1 of LDB.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>ldb(3), ldbedit(1)</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> ldb was written by
+ <ulink url="https://www.samba.org/~tridge/">Andrew Tridgell</ulink>.
+ </para>
+
+ <para>
+If you wish to report a problem or make a suggestion then please see
+the <ulink url="http://ldb.samba.org/"/> web site for
+current contact and maintainer information.
+ </para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/lib/ldb/modules/asq.c b/lib/ldb/modules/asq.c
new file mode 100644
index 0000000..4eba941
--- /dev/null
+++ b/lib/ldb/modules/asq.c
@@ -0,0 +1,410 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005-2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb attribute scoped query control module
+ *
+ * Description: this module searches all the objects pointed by
+ * the DNs contained in the references attribute
+ *
+ * Author: Simo Sorce
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_module.h"
+
+struct asq_context {
+
+ enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
+
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ struct ldb_asq_control *asq_ctrl;
+
+ const char * const *req_attrs;
+ char *req_attribute;
+ enum {
+ ASQ_CTRL_SUCCESS = 0,
+ ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
+ ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
+ ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
+ } asq_ret;
+
+ struct ldb_reply *base_res;
+
+ struct ldb_request **reqs;
+ unsigned int num_reqs;
+ unsigned int cur_req;
+
+ struct ldb_control **controls;
+};
+
+static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct asq_context *ac;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ac = talloc_zero(req, struct asq_context);
+ if (ac == NULL) {
+ ldb_oom(ldb);
+ return NULL;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ return ac;
+}
+
+static int asq_search_continue(struct asq_context *ac);
+
+static int asq_search_terminate(struct asq_context *ac)
+{
+ struct ldb_asq_control *asq;
+ unsigned int i;
+
+ if (ac->controls) {
+ for (i = 0; ac->controls[i]; i++) /* count em */ ;
+ } else {
+ i = 0;
+ }
+
+ ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
+
+ if (ac->controls == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->controls[i] = talloc(ac->controls, struct ldb_control);
+ if (ac->controls[i] == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
+ ac->controls[i]->critical = 0;
+
+ asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
+ if (asq == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ asq->result = ac->asq_ret;
+
+ ac->controls[i]->data = asq;
+
+ ac->controls[i + 1] = NULL;
+
+ return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
+}
+
+static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct asq_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct asq_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ ac->base_res = talloc_move(ac, &ares);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore referrals */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
+
+ talloc_free(ares);
+
+ /* next step */
+ ret = asq_search_continue(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ break;
+
+ }
+ return LDB_SUCCESS;
+}
+
+static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct asq_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct asq_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* pass the message up to the original callback as we
+ * do not have to elaborate on it any further */
+ ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore referrals */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
+
+ talloc_free(ares);
+
+ ret = asq_search_continue(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ break;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
+{
+ struct ldb_context *ldb;
+ const char **base_attrs;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ ac->req_attrs = ac->req->op.search.attrs;
+ ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
+ if (ac->req_attribute == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ base_attrs = talloc_array(ac, const char *, 2);
+ if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
+ if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ base_attrs[1] = NULL;
+
+ ret = ldb_build_search_req(base_req, ldb, ac,
+ ac->req->op.search.base,
+ LDB_SCOPE_BASE,
+ NULL,
+ (const char * const *)base_attrs,
+ NULL,
+ ac, asq_base_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
+{
+ struct ldb_context *ldb;
+ struct ldb_control **saved_controls;
+ struct ldb_control *control;
+ struct ldb_dn *dn;
+ struct ldb_message_element *el;
+ unsigned int i;
+ int ret;
+
+ if (ac->base_res == NULL) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
+ /* no values found */
+ if (el == NULL) {
+ ac->asq_ret = ASQ_CTRL_SUCCESS;
+ *terminated = true;
+ return asq_search_terminate(ac);
+ }
+
+ ac->num_reqs = el->num_values;
+ ac->cur_req = 0;
+ ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
+ if (ac->reqs == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+
+ dn = ldb_dn_new(ac, ldb,
+ (const char *)el->values[i].data);
+ if ( ! ldb_dn_validate(dn)) {
+ ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
+ *terminated = true;
+ return asq_search_terminate(ac);
+ }
+
+ ret = ldb_build_search_req_ex(&ac->reqs[i],
+ ldb, ac,
+ dn, LDB_SCOPE_BASE,
+ ac->req->op.search.tree,
+ ac->req_attrs,
+ ac->req->controls,
+ ac, asq_reqs_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* remove the ASQ control itself */
+ control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
+ if (!ldb_save_controls(control, ac->reqs[i], &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int asq_search_continue(struct asq_context *ac)
+{
+ bool terminated = false;
+ int ret;
+
+ switch (ac->step) {
+ case ASQ_SEARCH_BASE:
+
+ /* build up the requests call chain */
+ ret = asq_build_multiple_requests(ac, &terminated);
+ if (ret != LDB_SUCCESS || terminated) {
+ return ret;
+ }
+
+ ac->step = ASQ_SEARCH_MULTI;
+
+ return ldb_next_request(ac->module, ac->reqs[ac->cur_req]);
+
+ case ASQ_SEARCH_MULTI:
+
+ ac->cur_req++;
+
+ if (ac->cur_req == ac->num_reqs) {
+ /* done */
+ return asq_search_terminate(ac);
+ }
+
+ return ldb_next_request(ac->module, ac->reqs[ac->cur_req]);
+ }
+
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int asq_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_request *base_req;
+ struct ldb_control *control;
+ struct asq_context *ac;
+ int ret;
+
+ /* check if there's an ASQ control */
+ control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ ac = asq_context_init(module, req);
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* check the search is well formed */
+ if (req->op.search.scope != LDB_SCOPE_BASE) {
+ ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
+ return asq_search_terminate(ac);
+ }
+
+ ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
+ if (!ac->asq_ctrl) {
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ ret = asq_build_first_request(ac, &base_req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ac->step = ASQ_SEARCH_BASE;
+
+ return ldb_next_request(ac->module, base_req);
+}
+
+static int asq_init(struct ldb_module *module)
+{
+ struct ldb_context *ldb;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!");
+ }
+
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_asq_module_ops = {
+ .name = "asq",
+ .search = asq_search,
+ .init_context = asq_init
+};
+
+int ldb_asq_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_module(&ldb_asq_module_ops);
+}
diff --git a/lib/ldb/modules/paged_searches.c b/lib/ldb/modules/paged_searches.c
new file mode 100644
index 0000000..315a17a
--- /dev/null
+++ b/lib/ldb/modules/paged_searches.c
@@ -0,0 +1,391 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005-2008
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: paged_searches
+ *
+ * Component: ldb paged searches module
+ *
+ * Description: this module detects if the remote ldap server supports
+ * paged results and use them to transparently access all objects
+ *
+ * Author: Simo Sorce
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_module.h"
+
+#define PS_DEFAULT_PAGE_SIZE 500
+/* 500 objects per query seem to be a decent compromise
+ * the default AD limit per request is 1000 entries */
+
+struct private_data {
+
+ bool paged_supported;
+};
+
+struct ps_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ bool pending;
+
+ char **saved_referrals;
+ unsigned int num_referrals;
+
+ struct ldb_request *down_req;
+};
+
+static int check_ps_continuation(struct ps_context *ac, struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_context *ldb;
+ struct ldb_control *rep_control, *req_control;
+ struct ldb_paged_control *paged_rep_control = NULL, *paged_req_control = NULL;
+ ldb = ldb_module_get_ctx(ac->module);
+
+ rep_control = ldb_reply_get_control(ares, LDB_CONTROL_PAGED_RESULTS_OID);
+ if (rep_control) {
+ paged_rep_control = talloc_get_type(rep_control->data, struct ldb_paged_control);
+ }
+
+ req_control = ldb_request_get_control(req, LDB_CONTROL_PAGED_RESULTS_OID);
+ if (req_control == NULL || req_control->data == NULL) {
+ ldb_set_errstring(ldb, "paged_searches: control is missing or malformed");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ paged_req_control = talloc_get_type(req_control->data, struct ldb_paged_control);
+
+ if (!rep_control || !paged_rep_control) {
+ if (paged_req_control->cookie) {
+ /* something wrong here - why give us a control back befre, but not one now? */
+ ldb_set_errstring(ldb, "paged_searches: ERROR: We got back a control from a previous page, but this time no control was returned!");
+ return LDB_ERR_OPERATIONS_ERROR;
+ } else {
+ /* No cookie received yet, valid to just return the full data set */
+
+ /* we are done */
+ ac->pending = false;
+ return LDB_SUCCESS;
+ }
+ }
+
+ if (paged_rep_control->cookie_len == 0) {
+ /* we are done */
+ ac->pending = false;
+ return LDB_SUCCESS;
+ }
+
+ /* more processing required */
+ /* let's fill in the request control with the new cookie */
+ /* if there's a reply control we must find a request
+ * control matching it */
+
+ if (paged_req_control->cookie) {
+ talloc_free(paged_req_control->cookie);
+ }
+
+ paged_req_control->cookie = talloc_memdup(req_control,
+ paged_rep_control->cookie,
+ paged_rep_control->cookie_len);
+ paged_req_control->cookie_len = paged_rep_control->cookie_len;
+
+ ac->pending = true;
+ return LDB_SUCCESS;
+}
+
+static int store_referral(struct ps_context *ac, char *referral)
+{
+ ac->saved_referrals = talloc_realloc(ac, ac->saved_referrals, char *, ac->num_referrals + 2);
+ if (!ac->saved_referrals) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->saved_referrals[ac->num_referrals] = talloc_strdup(ac->saved_referrals, referral);
+ if (!ac->saved_referrals[ac->num_referrals]) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->num_referrals++;
+ ac->saved_referrals[ac->num_referrals] = NULL;
+
+ return LDB_SUCCESS;
+}
+
+static int send_referrals(struct ps_context *ac)
+{
+ struct ldb_reply *ares;
+ int ret;
+ unsigned int i;
+
+ for (i = 0; i < ac->num_referrals; i++) {
+ ares = talloc_zero(ac->req, struct ldb_reply);
+ if (!ares) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ares->type = LDB_REPLY_REFERRAL;
+ ares->referral = ac->saved_referrals[i];
+
+ ret = ldb_module_send_referral(ac->req, ares->referral);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int ps_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ps_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct ps_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ ret = store_referral(ac, ares->referral);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ break;
+
+ case LDB_REPLY_DONE:
+
+ ret = check_ps_continuation(ac, req, ares);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ if (ac->pending) {
+
+ ret = ldb_next_request(ac->module, ac->down_req);
+
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+
+ } else {
+
+ /* send referrals */
+ ret = send_referrals(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+
+ /* send REPLY_DONE */
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+ }
+ break;
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
+
+static int ps_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct private_data *private_data;
+ struct ps_context *ac;
+ struct ldb_paged_control *control;
+ int ret;
+
+ private_data = talloc_get_type(ldb_module_get_private(module), struct private_data);
+ ldb = ldb_module_get_ctx(module);
+
+ /* check if paging is supported */
+ if (!private_data || !private_data->paged_supported) {
+ /* do not touch this request paged controls not
+ * supported or we
+ * are just not setup yet */
+ return ldb_next_request(module, req);
+ }
+
+ ac = talloc_zero(req, struct ps_context);
+ if (ac == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+ ac->pending = false;
+ ac->saved_referrals = NULL;
+ ac->num_referrals = 0;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ control = talloc(ac, struct ldb_paged_control);
+ if (!control) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ control->size = PS_DEFAULT_PAGE_SIZE;
+ control->cookie = NULL;
+ control->cookie_len = 0;
+
+ ret = ldb_build_search_req_ex(&ac->down_req, ldb, ac,
+ ac->req->op.search.base,
+ ac->req->op.search.scope,
+ ac->req->op.search.tree,
+ ac->req->op.search.attrs,
+ ac->req->controls,
+ ac,
+ ps_callback,
+ ac->req);
+ LDB_REQ_SET_LOCATION(ac->down_req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_request_add_control(ac->down_req, LDB_CONTROL_PAGED_RESULTS_OID,
+ true, control);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ talloc_steal(ac->down_req, control);
+
+ return ldb_next_request(ac->module, ac->down_req);
+}
+
+static int check_supported_paged(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct private_data *data;
+
+ data = talloc_get_type(req->context, struct private_data);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (ldb_msg_check_string_attribute(ares->message,
+ "supportedControl",
+ LDB_CONTROL_PAGED_RESULTS_OID)) {
+ data->paged_supported = true;
+ }
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ break;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
+
+static int ps_init(struct ldb_module *module)
+{
+ struct ldb_context *ldb;
+ static const char *attrs[] = { "supportedControl", NULL };
+ struct private_data *data;
+ struct ldb_dn *base;
+ int ret;
+ struct ldb_request *req;
+
+ ldb = ldb_module_get_ctx(module);
+
+ data = talloc(module, struct private_data);
+ if (data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ data->paged_supported = false;
+
+ ldb_module_set_private(module, data);
+
+ base = ldb_dn_new(module, ldb, "");
+ if (base == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_build_search_req(&req, ldb, module,
+ base, LDB_SCOPE_BASE,
+ "(objectClass=*)",
+ attrs, NULL,
+ data, check_supported_paged,
+ NULL);
+ LDB_REQ_SET_LOCATION(req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_next_request(module, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ talloc_free(base);
+ talloc_free(req);
+
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_paged_searches_module_ops = {
+ .name = "paged_searches",
+ .search = ps_search,
+ .init_context = ps_init
+};
+
+int ldb_paged_searches_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_module(&ldb_paged_searches_module_ops);
+}
diff --git a/lib/ldb/modules/rdn_name.c b/lib/ldb/modules/rdn_name.c
new file mode 100644
index 0000000..a49ce62
--- /dev/null
+++ b/lib/ldb/modules/rdn_name.c
@@ -0,0 +1,596 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Bartlett 2005-2009
+ Copyright (C) Simo Sorce 2006-2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: rdn_name
+ *
+ * Component: ldb rdn name module
+ *
+ * Description: keep a consistent name attribute on objects manpulations
+ *
+ * Author: Andrew Bartlett
+ *
+ * Modifications:
+ * - made the module async
+ * Simo Sorce Mar 2006
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_module.h"
+
+struct rename_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ struct ldb_reply *ares;
+};
+
+static int rdn_name_add_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct rename_context *ac;
+
+ ac = talloc_get_type(req->context, struct rename_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ return ldb_module_send_referral(ac->req, ares->referral);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+}
+
+static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct ldb_request *down_req;
+ struct rename_context *ac;
+ struct ldb_message *msg;
+ struct ldb_message_element *attribute;
+ const struct ldb_schema_attribute *a;
+ const char *rdn_name;
+ const struct ldb_val *rdn_val_p;
+ struct ldb_val rdn_val;
+ unsigned int i;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ ac = talloc_zero(req, struct rename_context);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ msg = ldb_msg_copy_shallow(req, req->op.add.message);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(msg->dn);
+ if (rdn_name == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
+ if (rdn_val_p == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (rdn_val_p->length == 0) {
+ ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
+ ldb_dn_get_linearized(req->op.add.message->dn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ rdn_val = ldb_val_dup(msg, rdn_val_p);
+
+ /* Perhaps someone above us tried to set this? Then ignore it */
+ ldb_msg_remove_attr(msg, "name");
+
+ ret = ldb_msg_add_value(msg, "name", &rdn_val, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, rdn_name);
+ if (a == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ attribute = ldb_msg_find_element(msg, rdn_name);
+ if (!attribute) {
+ /* add entry with normalised RDN information if possible */
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
+ ret = ldb_msg_add_value(msg, a->name, &rdn_val, NULL);
+ } else {
+ ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL);
+ }
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ } else {
+ /* normalise attribute name if possible */
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
+ attribute->name = a->name;
+ }
+ /* normalise attribute value */
+ for (i = 0; i < attribute->num_values; i++) {
+ bool matched;
+ if (a->syntax->operator_fn) {
+ ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
+ &rdn_val, &attribute->values[i], &matched);
+ if (ret != LDB_SUCCESS) return ret;
+ } else {
+ matched = (a->syntax->comparison_fn(ldb, msg,
+ &rdn_val, &attribute->values[i]) == 0);
+ }
+ if (matched) {
+ /* overwrite so it matches in case */
+ attribute->values[i] = rdn_val;
+ break;
+ }
+ }
+ if (i == attribute->num_values) {
+ char *rdn_errstring = talloc_asprintf(ac,
+ "RDN mismatch on %s: %s (%.*s) should match one of:",
+ ldb_dn_get_linearized(msg->dn), rdn_name,
+ (int)rdn_val.length, (const char *)rdn_val.data);
+ for (i = 0; i < attribute->num_values; i++) {
+ talloc_asprintf_addbuf(
+ &rdn_errstring, " (%.*s)",
+ (int)attribute->values[i].length,
+ (const char *)attribute->values[i].data);
+ }
+ ldb_set_errstring(ldb, rdn_errstring);
+ /* Match AD's error here */
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ }
+
+ ret = ldb_build_add_req(&down_req, ldb, req,
+ msg,
+ req->controls,
+ ac, rdn_name_add_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ talloc_steal(down_req, msg);
+
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
+}
+
+static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct rename_context *ac;
+
+ ac = talloc_get_type(req->context, struct rename_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ return ldb_module_send_referral(ac->req, ares->referral);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ /* the only supported reply right now is a LDB_REPLY_DONE */
+ if (ares->type != LDB_REPLY_DONE) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* send saved controls eventually */
+ return ldb_module_done(ac->req, ac->ares->controls,
+ ac->ares->response, LDB_SUCCESS);
+}
+
+static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_context *ldb;
+ struct rename_context *ac;
+ struct ldb_request *mod_req;
+ const char *rdn_name;
+ const struct ldb_schema_attribute *a = NULL;
+ const struct ldb_val *rdn_val_p;
+ struct ldb_val rdn_val;
+ struct ldb_message *msg;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct rename_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!ares) {
+ goto error;
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ return ldb_module_send_referral(ac->req, ares->referral);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ /* the only supported reply right now is a LDB_REPLY_DONE */
+ if (ares->type != LDB_REPLY_DONE) {
+ goto error;
+ }
+
+ /* save reply for caller */
+ ac->ares = talloc_steal(ac, ares);
+
+ msg = ldb_msg_new(ac);
+ if (msg == NULL) {
+ goto error;
+ }
+ msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
+ if (msg->dn == NULL) {
+ goto error;
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
+ if (rdn_name == NULL) {
+ goto error;
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, rdn_name);
+ if (a == NULL) {
+ goto error;
+ }
+
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
+ rdn_name = a->name;
+ }
+
+ rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
+ if (rdn_val_p == NULL) {
+ goto error;
+ }
+ if (rdn_val_p->length == 0) {
+ ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
+ ldb_dn_get_linearized(req->op.rename.olddn));
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_NAMING_VIOLATION);
+ }
+ rdn_val = ldb_val_dup(msg, rdn_val_p);
+
+ if (ldb_msg_append_value(msg, rdn_name, &rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ goto error;
+ }
+ if (ldb_msg_append_value(msg, "name", &rdn_val, LDB_FLAG_MOD_REPLACE) != 0) {
+ goto error;
+ }
+
+ ret = ldb_build_mod_req(&mod_req, ldb,
+ ac, msg, NULL,
+ ac, rdn_modify_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ talloc_steal(mod_req, msg);
+
+ /* go on with the call chain */
+ return ldb_next_request(ac->module, mod_req);
+
+error:
+ return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+}
+
+static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ struct rename_context *ac;
+ struct ldb_request *down_req;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.rename.newdn)) {
+ return ldb_next_request(module, req);
+ }
+
+ ac = talloc_zero(req, struct rename_context);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ ret = ldb_build_rename_req(&down_req,
+ ldb,
+ ac,
+ req->op.rename.olddn,
+ req->op.rename.newdn,
+ req->controls,
+ ac,
+ rdn_rename_callback,
+ req);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* rename first, modify "name" if rename is ok */
+ return ldb_next_request(module, down_req);
+}
+
+static int rdn_recalculate_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
+
+ talloc_steal(up_req, req);
+ return up_req->callback(up_req, ares);
+}
+
+static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ const struct ldb_val *rdn_val_p;
+ struct ldb_message_element *e = NULL;
+ struct ldb_control *recalculate_rdn_control = NULL;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.mod.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ recalculate_rdn_control = ldb_request_get_control(req,
+ LDB_CONTROL_RECALCULATE_RDN_OID);
+ if (recalculate_rdn_control != NULL) {
+ struct ldb_message *msg = NULL;
+ const char *rdn_name = NULL;
+ struct ldb_val rdn_val;
+ const struct ldb_schema_attribute *a = NULL;
+ struct ldb_request *mod_req = NULL;
+ int ret;
+ struct ldb_message_element *rdn_del = NULL;
+ struct ldb_message_element *name_del = NULL;
+
+ recalculate_rdn_control->critical = false;
+
+ msg = ldb_msg_copy_shallow(req, req->op.mod.message);
+ if (msg == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ /*
+ * The caller must pass a dummy 'name' attribute
+ * in order to bypass some high level checks.
+ *
+ * We just remove it and check nothing is left.
+ */
+ ldb_msg_remove_attr(msg, "name");
+
+ if (msg->num_elements != 0) {
+ return ldb_module_operr(module);
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(msg->dn);
+ if (rdn_name == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ a = ldb_schema_attribute_by_name(ldb, rdn_name);
+ if (a == NULL) {
+ return ldb_module_operr(module);
+ }
+
+ if (a->name != NULL && strcmp(a->name, "*") != 0) {
+ rdn_name = a->name;
+ }
+
+ rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
+ if (rdn_val_p == NULL) {
+ return ldb_module_oom(module);
+ }
+ rdn_val = ldb_val_dup(msg, rdn_val_p);
+ if (rdn_val.length == 0) {
+ return ldb_module_oom(module);
+ }
+
+ /*
+ * This is a bit tricky:
+ *
+ * We want _DELETE elements (as "rdn_del" and "name_del" without
+ * values) first, followed by _ADD (with the real names)
+ * elements (with values). Then we fix up the "rdn_del" and
+ * "name_del" attributes.
+ */
+
+ ret = ldb_msg_add_empty(msg, "rdn_del", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+ ret = ldb_msg_append_value(msg, rdn_name, &rdn_val, LDB_FLAG_MOD_ADD);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+
+ ret = ldb_msg_add_empty(msg, "name_del", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+ ret = ldb_msg_append_value(msg, "name", &rdn_val, LDB_FLAG_MOD_ADD);
+ if (ret != 0) {
+ return ldb_module_oom(module);
+ }
+
+ rdn_del = ldb_msg_find_element(msg, "rdn_del");
+ if (rdn_del == NULL) {
+ return ldb_module_operr(module);
+ }
+ rdn_del->name = talloc_strdup(msg->elements, rdn_name);
+ if (rdn_del->name == NULL) {
+ return ldb_module_oom(module);
+ }
+ name_del = ldb_msg_find_element(msg, "name_del");
+ if (name_del == NULL) {
+ return ldb_module_operr(module);
+ }
+ name_del->name = talloc_strdup(msg->elements, "name");
+ if (name_del->name == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ ret = ldb_build_mod_req(&mod_req, ldb,
+ req, msg, NULL,
+ req, rdn_recalculate_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(req, NULL, NULL, ret);
+ }
+ talloc_steal(mod_req, msg);
+
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_RECALCULATE_RDN_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(req, NULL, NULL, ret);
+ }
+ ret = ldb_request_add_control(mod_req,
+ LDB_CONTROL_PERMISSIVE_MODIFY_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(req, NULL, NULL, ret);
+ }
+
+ /* go on with the call chain */
+ return ldb_next_request(module, mod_req);
+ }
+
+ rdn_val_p = ldb_dn_get_rdn_val(req->op.mod.message->dn);
+ if (rdn_val_p == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (rdn_val_p->length == 0) {
+ ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
+ ldb_dn_get_linearized(req->op.mod.message->dn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ e = ldb_msg_find_element(req->op.mod.message, "distinguishedName");
+ if (e != NULL) {
+ ldb_asprintf_errstring(ldb, "Modify of 'distinguishedName' on %s not permitted, must use 'rename' operation instead",
+ ldb_dn_get_linearized(req->op.mod.message->dn));
+ if (LDB_FLAG_MOD_TYPE(e->flags) == LDB_FLAG_MOD_REPLACE) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ } else {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ if (ldb_msg_find_element(req->op.mod.message, "name")) {
+ ldb_asprintf_errstring(ldb, "Modify of 'name' on %s not permitted, must use 'rename' operation instead",
+ ldb_dn_get_linearized(req->op.mod.message->dn));
+ return LDB_ERR_NOT_ALLOWED_ON_RDN;
+ }
+
+ if (ldb_msg_find_element(req->op.mod.message, ldb_dn_get_rdn_name(req->op.mod.message->dn))) {
+ ldb_asprintf_errstring(ldb, "Modify of RDN '%s' on %s not permitted, must use 'rename' operation instead",
+ ldb_dn_get_rdn_name(req->op.mod.message->dn), ldb_dn_get_linearized(req->op.mod.message->dn));
+ return LDB_ERR_NOT_ALLOWED_ON_RDN;
+ }
+
+ /* All OK, they kept their fingers out of the special attributes */
+ return ldb_next_request(module, req);
+}
+
+static int rdn_name_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_context *ldb;
+ const char *rdn_name;
+ const struct ldb_val *rdn_val_p;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.search.base)) {
+ return ldb_next_request(module, req);
+ }
+
+ rdn_name = ldb_dn_get_rdn_name(req->op.search.base);
+ rdn_val_p = ldb_dn_get_rdn_val(req->op.search.base);
+ if ((rdn_name != NULL) && (rdn_val_p == NULL)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if ((rdn_val_p != NULL) && (rdn_val_p->length == 0)) {
+ ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
+ ldb_dn_get_linearized(req->op.search.base));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ return ldb_next_request(module, req);
+}
+
+static const struct ldb_module_ops ldb_rdn_name_module_ops = {
+ .name = "rdn_name",
+ .add = rdn_name_add,
+ .modify = rdn_name_modify,
+ .rename = rdn_name_rename,
+ .search = rdn_name_search
+};
+
+int ldb_rdn_name_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_module(&ldb_rdn_name_module_ops);
+}
diff --git a/lib/ldb/modules/skel.c b/lib/ldb/modules/skel.c
new file mode 100644
index 0000000..1ce3ec1
--- /dev/null
+++ b/lib/ldb/modules/skel.c
@@ -0,0 +1,147 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb skel module
+ *
+ * Description: example module
+ *
+ * Author: Simo Sorce
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_module.h"
+
+struct private_data {
+
+ char *some_private_data;
+};
+
+/* search */
+static int skel_search(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* add */
+static int skel_add(struct ldb_module *module, struct ldb_request *req){
+ return ldb_next_request(module, req);
+}
+
+/* modify */
+static int skel_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* delete */
+static int skel_delete(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* rename */
+static int skel_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+/* start a transaction */
+static int skel_start_trans(struct ldb_module *module)
+{
+ return ldb_next_start_trans(module);
+}
+
+/* end a transaction */
+static int skel_end_trans(struct ldb_module *module)
+{
+ return ldb_next_end_trans(module);
+}
+
+/* delete a transaction */
+static int skel_del_trans(struct ldb_module *module)
+{
+ return ldb_next_del_trans(module);
+}
+
+static int skel_destructor(struct ldb_module *ctx)
+{
+ struct private_data *data;
+
+ data = talloc_get_type(ldb_module_get_private(ctx), struct private_data);
+
+ /* put your clean-up functions here */
+ if (data->some_private_data) talloc_free(data->some_private_data);
+
+ return 0;
+}
+
+static int skel_request(struct ldb_module *module, struct ldb_request *req)
+{
+ return ldb_next_request(module, req);
+}
+
+static int skel_init(struct ldb_module *module)
+{
+ struct ldb_context *ldb;
+ struct private_data *data;
+
+ ldb = ldb_module_get_ctx(module);
+
+ data = talloc(module, struct private_data);
+ if (data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ data->some_private_data = NULL;
+ ldb_module_set_private(module, data);
+
+ talloc_set_destructor (module, skel_destructor);
+
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_skel_module_ops = {
+ .name = "skel",
+ .init_context = skel_init,
+ .search = skel_search,
+ .add = skel_add,
+ .modify = skel_modify,
+ .del = skel_delete,
+ .rename = skel_rename,
+ .request = skel_request,
+ .start_transaction = skel_start_trans,
+ .end_transaction = skel_end_trans,
+ .del_transaction = skel_del_trans,
+};
+
+int ldb_skel_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_module(&ldb_skel_module_ops);
+}
diff --git a/lib/ldb/modules/sort.c b/lib/ldb/modules/sort.c
new file mode 100644
index 0000000..cb6f8df
--- /dev/null
+++ b/lib/ldb/modules/sort.c
@@ -0,0 +1,402 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005-2008
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb server side sort control module
+ *
+ * Description: this module sorts the results of a search
+ *
+ * Author: Simo Sorce
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb_module.h"
+
+struct opaque {
+ struct ldb_context *ldb;
+ const struct ldb_attrib_handler *h;
+ const char *attribute;
+ int reverse;
+ int result;
+};
+
+struct sort_context {
+ struct ldb_module *module;
+
+ const char *attributeName;
+ const char *orderingRule;
+ int reverse;
+
+ struct ldb_request *req;
+ struct ldb_message **msgs;
+ char **referrals;
+ unsigned int num_msgs;
+ unsigned int num_refs;
+ const char *extra_sort_key;
+
+ const struct ldb_schema_attribute *a;
+ int sort_result;
+};
+
+static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc)
+{
+ struct ldb_control **controls;
+ struct ldb_sort_resp_control *resp;
+ unsigned int i;
+
+ if (*ctrls) {
+ controls = *ctrls;
+ for (i = 0; controls[i]; i++);
+ controls = talloc_realloc(mem_ctx, controls, struct ldb_control *, i + 2);
+ } else {
+ i = 0;
+ controls = talloc_array(mem_ctx, struct ldb_control *, 2);
+ }
+ if (! controls )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ *ctrls = controls;
+
+ controls[i+1] = NULL;
+ controls[i] = talloc(controls, struct ldb_control);
+ if (! controls[i] )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ controls[i]->oid = LDB_CONTROL_SORT_RESP_OID;
+ controls[i]->critical = 0;
+
+ resp = talloc(controls[i], struct ldb_sort_resp_control);
+ if (! resp )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ resp->result = result;
+ resp->attr_desc = talloc_strdup(resp, desc);
+
+ if (! resp->attr_desc )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ controls[i]->data = resp;
+
+ return LDB_SUCCESS;
+}
+
+static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
+{
+ struct sort_context *ac = talloc_get_type(opaque, struct sort_context);
+ struct ldb_message_element *el1, *el2;
+ struct ldb_context *ldb;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (ac->sort_result != 0) {
+ /* an error occurred previously,
+ * let's exit the sorting by returning always 0 */
+ return 0;
+ }
+
+ el1 = ldb_msg_find_element(*msg1, ac->attributeName);
+ el2 = ldb_msg_find_element(*msg2, ac->attributeName);
+
+ if (!el1 && el2) {
+ return 1;
+ }
+ if (el1 && !el2) {
+ return -1;
+ }
+ if (!el1 && !el2) {
+ return 0;
+ }
+
+ if (ac->reverse)
+ return ac->a->syntax->comparison_fn(ldb, ac, &el2->values[0], &el1->values[0]);
+
+ return ac->a->syntax->comparison_fn(ldb, ac, &el1->values[0], &el2->values[0]);
+}
+
+static int server_sort_results(struct sort_context *ac)
+{
+ struct ldb_context *ldb;
+ struct ldb_reply *ares;
+ unsigned int i;
+ int ret;
+
+ ldb = ldb_module_get_ctx(ac->module);
+
+ ac->a = ldb_schema_attribute_by_name(ldb, ac->attributeName);
+ ac->sort_result = 0;
+
+ LDB_TYPESAFE_QSORT(ac->msgs, ac->num_msgs, ac, sort_compare);
+
+ if (ac->sort_result != LDB_SUCCESS) {
+ return ac->sort_result;
+ }
+
+ for (i = 0; i < ac->num_msgs; i++) {
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ares->type = LDB_REPLY_ENTRY;
+ ares->message = talloc_move(ares, &ac->msgs[i]);
+ if (ac->extra_sort_key) {
+ ldb_msg_remove_attr(ares->message, ac->extra_sort_key);
+ }
+ ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ for (i = 0; i < ac->num_refs; i++) {
+ ares = talloc_zero(ac, struct ldb_reply);
+ if (!ares) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ares->type = LDB_REPLY_REFERRAL;
+ ares->referral = talloc_move(ares, &ac->referrals[i]);
+
+ ret = ldb_module_send_referral(ac->req, ares->referral);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int server_sort_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct sort_context *ac;
+ struct ldb_context *ldb;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct sort_context);
+ ldb = ldb_module_get_ctx(ac->module);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2);
+ if (! ac->msgs) {
+ talloc_free(ares);
+ ldb_oom(ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ac->msgs[ac->num_msgs] = talloc_steal(ac->msgs, ares->message);
+ ac->num_msgs++;
+ ac->msgs[ac->num_msgs] = NULL;
+
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2);
+ if (! ac->referrals) {
+ talloc_free(ares);
+ ldb_oom(ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ac->referrals[ac->num_refs] = talloc_steal(ac->referrals, ares->referral);
+ ac->num_refs++;
+ ac->referrals[ac->num_refs] = NULL;
+
+ break;
+
+ case LDB_REPLY_DONE:
+
+ ret = server_sort_results(ac);
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ret);
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
+
+static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_control *control;
+ struct ldb_server_sort_control **sort_ctrls;
+ struct ldb_control **saved_controls;
+ struct ldb_request *down_req;
+ struct sort_context *ac;
+ struct ldb_context *ldb;
+ int ret;
+ const char * const *attrs;
+ size_t n_attrs, i;
+ const char *sort_attr;
+
+ ldb = ldb_module_get_ctx(module);
+
+ /* check if there's a server sort control */
+ control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ ac = talloc_zero(req, struct sort_context);
+ if (ac == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
+ if (!sort_ctrls) {
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ /* FIXME: we do not support more than one attribute for sorting right now */
+ /* FIXME: we need to check if the attribute type exist or return an error */
+
+ if (sort_ctrls[1] != NULL) {
+ if (control->critical) {
+ struct ldb_control **controls = NULL;
+
+ /* callback immediately */
+ ret = build_response(req, &controls,
+ LDB_ERR_UNWILLING_TO_PERFORM,
+ "sort control is not complete yet");
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(req, controls, NULL, ret);
+ } else {
+ /* just pass the call down and don't do any sorting */
+ return ldb_next_request(module, req);
+ }
+ }
+
+ control->critical = 0;
+
+ /* We are asked to sort on an attribute, and if that attribute is not
+ already in the search attributes we need to add it (and later
+ remove it on the return journey).
+ */
+ sort_attr = sort_ctrls[0]->attributeName;
+ if (req->op.search.attrs == NULL) {
+ /* This means all non-operational attributes, which means
+ there's nothing to add. */
+ attrs = NULL;
+ } else {
+ n_attrs = 0;
+ while (req->op.search.attrs[n_attrs] != NULL) {
+ if (sort_attr &&
+ strcmp(req->op.search.attrs[n_attrs], sort_attr) == 0) {
+ sort_attr = NULL;
+ }
+ n_attrs++;
+ }
+
+ if (sort_attr == NULL) {
+ attrs = req->op.search.attrs;
+ } else {
+ const char **tmp = talloc_array(ac, const char *, n_attrs + 2);
+
+ for (i = 0; i < n_attrs; i++) {
+ tmp[i] = req->op.search.attrs[i];
+ }
+ ac->extra_sort_key = sort_attr;
+ tmp[n_attrs] = sort_attr;
+ tmp[n_attrs + 1] = NULL;
+ attrs = tmp;
+ }
+ }
+
+ ac->attributeName = sort_ctrls[0]->attributeName;
+ ac->orderingRule = sort_ctrls[0]->orderingRule;
+ ac->reverse = sort_ctrls[0]->reverse;
+
+ ret = ldb_build_search_req_ex(&down_req, ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ attrs,
+ req->controls,
+ ac,
+ server_sort_search_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* save it locally and remove it from the list */
+ /* we do not need to replace them later as we
+ * are keeping the original req intact */
+ if (!ldb_save_controls(control, down_req, &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(module, down_req);
+}
+
+static int server_sort_init(struct ldb_module *module)
+{
+ struct ldb_context *ldb;
+ int ret;
+
+ ldb = ldb_module_get_ctx(module);
+
+ ret = ldb_mod_register_control(module, LDB_CONTROL_SERVER_SORT_OID);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ "server_sort:"
+ "Unable to register control with rootdse!");
+ }
+
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_server_sort_module_ops = {
+ .name = "server_sort",
+ .search = server_sort_search,
+ .init_context = server_sort_init
+};
+
+int ldb_server_sort_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_module(&ldb_server_sort_module_ops);
+}
diff --git a/lib/ldb/nssldb/README.txt b/lib/ldb/nssldb/README.txt
new file mode 100644
index 0000000..7f5877c
--- /dev/null
+++ b/lib/ldb/nssldb/README.txt
@@ -0,0 +1,34 @@
+
+This test code requires a tdb that is configured for to use the asq module.
+You can do that adding the following record to a tdb:
+
+dn: @MODULES
+@LIST: asq
+
+Other modules can be used as well (like rdn_name for example)
+
+The uidNumber 0 and the gidNumber 0 are considered invalid.
+
+The user records should contain the following attributes:
+uid (required) the user name
+userPassword (optional) the user password (if not present "LDB" is
+ returned in the password field)
+uidNumber (required) the user uid
+gidNumber (required) the user primary gid
+gecos (optional) the GECOS
+homeDirectory (required) the home directory
+loginShell (required) the login shell
+memberOf (required) all the groups the user is member of should
+ be reported here using their DNs. The
+ primary group as well.
+
+The group accounts should contain the following attributes:
+cn (required) the group name
+uesrPassword (optional) the group password (if not present "LDB" is
+ returned in the password field)
+gidNumber (required) the group gid
+member (optional) the DNs of the member users, also the ones
+ that have this group as primary
+
+
+SSS
diff --git a/lib/ldb/nssldb/ldb-grp.c b/lib/ldb/nssldb/ldb-grp.c
new file mode 100644
index 0000000..5e7556d
--- /dev/null
+++ b/lib/ldb/nssldb/ldb-grp.c
@@ -0,0 +1,429 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb-nss.h"
+
+extern struct _ldb_nss_context *_ldb_nss_ctx;
+
+const char *_ldb_nss_gr_attrs[] = {
+ "cn",
+ "userPassword",
+ "gidNumber",
+ NULL
+};
+
+const char *_ldb_nss_mem_attrs[] = {
+ "uid",
+ NULL
+};
+
+#define _NSS_LDB_ENOMEM(amem) \
+ do { \
+ if ( ! amem) { \
+ errno = ENOMEM; \
+ talloc_free(memctx); \
+ return NSS_STATUS_UNAVAIL; \
+ } \
+ } while(0)
+
+/* This setgrent, getgrent, endgrent is not very efficient */
+
+NSS_STATUS _nss_ldb_setgrent(void)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->gr_cur = 0;
+ if (_ldb_nss_ctx->gr_res != NULL) {
+ talloc_free(_ldb_nss_ctx->gr_res);
+ _ldb_nss_ctx->gr_res = NULL;
+ }
+
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->ldb,
+ &_ldb_nss_ctx->gr_res,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _ldb_nss_gr_attrs,
+ _LDB_NSS_GRENT_FILTER);
+ if (ret != LDB_SUCCESS) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_endgrent(void)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->gr_cur = 0;
+ if (_ldb_nss_ctx->gr_res) {
+ talloc_free(_ldb_nss_ctx->gr_res);
+ _ldb_nss_ctx->gr_res = NULL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getgrent_r(struct group *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ struct ldb_result *res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ *errnop = 0;
+
+ if (_ldb_nss_ctx->gr_cur >= _ldb_nss_ctx->gr_res->count) {
+ /* already returned all entries */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ res = talloc_zero(_ldb_nss_ctx->gr_res, struct ldb_result);
+ if ( ! res) {
+ errno = *errnop = ENOMEM;
+ _ldb_nss_ctx->gr_cur++; /* skip this entry */
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ ret = _ldb_nss_group_request(&res,
+ _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur]->dn,
+ _ldb_nss_mem_attrs,
+ "member");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ talloc_free(res);
+ _ldb_nss_ctx->gr_cur++; /* skip this entry */
+ return ret;
+ }
+
+ ret = _ldb_nss_fill_group(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur],
+ res);
+
+ talloc_free(res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ if (ret != NSS_STATUS_TRYAGAIN) {
+ _ldb_nss_ctx->gr_cur++; /* skip this entry */
+ }
+ return ret;
+ }
+
+ /* this entry is ok, increment counter to nex entry */
+ _ldb_nss_ctx->gr_cur++;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getgrnam_r(const char *name, struct group *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ TALLOC_CTX *ctx;
+ struct ldb_result *gr_res;
+ struct ldb_result *mem_res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ ctx = talloc_new(_ldb_nss_ctx->ldb);
+ if ( ! ctx) {
+ *errnop = errno = ENOMEM;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* build the filter for this uid */
+ filter = talloc_asprintf(ctx, _LDB_NSS_GRNAM_FILTER, name);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->ldb,
+ &gr_res,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _ldb_nss_gr_attrs,
+ filter);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ talloc_steal(ctx, gr_res);
+
+ /* if none found return */
+ if (gr_res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (gr_res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ mem_res = talloc_zero(ctx, struct ldb_result);
+ if ( ! mem_res) {
+ errno = *errnop = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ ret = _ldb_nss_group_request(&mem_res,
+ gr_res->msgs[0]->dn,
+ _ldb_nss_mem_attrs,
+ "member");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ goto done;
+ }
+
+ ret = _ldb_nss_fill_group(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ gr_res->msgs[0],
+ mem_res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = NSS_STATUS_SUCCESS;
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+NSS_STATUS _nss_ldb_getgrgid_r(gid_t gid, struct group *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ TALLOC_CTX *ctx;
+ struct ldb_result *gr_res;
+ struct ldb_result *mem_res;
+
+ if (gid == 0) { /* we don't serve root gid by policy */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ ctx = talloc_new(_ldb_nss_ctx->ldb);
+ if ( ! ctx) {
+ *errnop = errno = ENOMEM;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* build the filter for this uid */
+ filter = talloc_asprintf(ctx, _LDB_NSS_GRGID_FILTER, gid);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->ldb,
+ &gr_res,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _ldb_nss_gr_attrs,
+ filter);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ talloc_steal(ctx, gr_res);
+
+ /* if none found return */
+ if (gr_res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (gr_res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ mem_res = talloc_zero(ctx, struct ldb_result);
+ if ( ! mem_res) {
+ errno = *errnop = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ ret = _ldb_nss_group_request(&mem_res,
+ gr_res->msgs[0]->dn,
+ _ldb_nss_mem_attrs,
+ "member");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ goto done;
+ }
+
+ ret = _ldb_nss_fill_group(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ gr_res->msgs[0],
+ mem_res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = NSS_STATUS_SUCCESS;
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+NSS_STATUS _nss_ldb_initgroups_dyn(const char *user, gid_t group, long int *start, long int *size, gid_t **groups, long int limit, int *errnop)
+{
+ int ret;
+ char *filter;
+ const char * attrs[] = { "uidNumber", "gidNumber", NULL };
+ struct ldb_result *uid_res;
+ struct ldb_result *mem_res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ mem_res = talloc_zero(_ldb_nss_ctx, struct ldb_result);
+ if ( ! mem_res) {
+ errno = *errnop = ENOMEM;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* build the filter for this name */
+ filter = talloc_asprintf(mem_res, _LDB_NSS_PWNAM_FILTER, user);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->ldb,
+ &uid_res,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ attrs,
+ filter);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ talloc_steal(mem_res, uid_res);
+
+ /* if none found return */
+ if (uid_res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (uid_res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ ret = _ldb_nss_group_request(&mem_res,
+ uid_res->msgs[0]->dn,
+ attrs,
+ "memberOf");
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ *errnop = errno;
+ goto done;
+ }
+
+ ret = _ldb_nss_fill_initgr(group,
+ limit,
+ start,
+ size,
+ groups,
+ errnop,
+ mem_res);
+
+ if (ret != NSS_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = NSS_STATUS_SUCCESS;
+
+done:
+ talloc_free(mem_res);
+ return ret;
+}
diff --git a/lib/ldb/nssldb/ldb-nss.c b/lib/ldb/nssldb/ldb-nss.c
new file mode 100644
index 0000000..92b0635
--- /dev/null
+++ b/lib/ldb/nssldb/ldb-nss.c
@@ -0,0 +1,395 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb-nss.h"
+
+struct _ldb_nss_context *_ldb_nss_ctx = NULL;
+
+NSS_STATUS _ldb_nss_init(void)
+{
+ int ret;
+
+ pid_t mypid = getpid();
+
+ if (_ldb_nss_ctx != NULL) {
+ if (_ldb_nss_ctx->pid == mypid) {
+ /* already initialized */
+ return NSS_STATUS_SUCCESS;
+ } else {
+ /* we are in a forked child now, reinitialize */
+ talloc_free(_ldb_nss_ctx);
+ _ldb_nss_ctx = NULL;
+ }
+ }
+
+ _ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid);
+ if (_ldb_nss_ctx == NULL) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ _ldb_nss_ctx->pid = mypid;
+
+ _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx, NULL);
+ if (_ldb_nss_ctx->ldb == NULL) {
+ goto failed;
+ }
+
+ ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+
+ _ldb_nss_ctx->base = ldb_dn_new(_ldb_nss_ctx, _ldb_nss_ctx->ldb, _LDB_NSS_BASEDN);
+ if ( ! ldb_dn_validate(_ldb_nss_ctx->base)) {
+ goto failed;
+ }
+
+ _ldb_nss_ctx->pw_cur = 0;
+ _ldb_nss_ctx->pw_res = NULL;
+ _ldb_nss_ctx->gr_cur = 0;
+ _ldb_nss_ctx->gr_res = NULL;
+
+ return NSS_STATUS_SUCCESS;
+
+failed:
+ /* talloc_free(_ldb_nss_ctx); */
+ _ldb_nss_ctx = NULL;
+ return NSS_STATUS_UNAVAIL;
+}
+
+NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *msg)
+{
+ int len;
+ int bufpos;
+ const char *tmp;
+
+ bufpos = 0;
+
+ /* get username */
+ tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL);
+ if (tmp == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_name = &buffer[bufpos];
+ bufpos += len;
+
+ /* get userPassword */
+ tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL);
+ if (tmp == NULL) {
+ tmp = "LDB";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_passwd = &buffer[bufpos];
+ bufpos += len;
+
+ /* this backend never serves an uid 0 user */
+ result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0);
+ if (result->pw_uid == 0) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0);
+ if (result->pw_gid == 0) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* get gecos */
+ tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL);
+ if (tmp == NULL) {
+ tmp = "";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_gecos = &buffer[bufpos];
+ bufpos += len;
+
+ /* get homeDirectory */
+ tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL);
+ if (tmp == NULL) {
+ tmp = "";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_dir = &buffer[bufpos];
+ bufpos += len;
+
+ /* get shell */
+ tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL);
+ if (tmp == NULL) {
+ tmp = "";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->pw_shell = &buffer[bufpos];
+ bufpos += len;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _ldb_nss_fill_group(struct group *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *group,
+ struct ldb_result *members)
+{
+ const char *tmp;
+ size_t len;
+ size_t bufpos;
+ size_t lsize;
+ unsigned int i;
+
+ bufpos = 0;
+
+ /* get group name */
+ tmp = ldb_msg_find_attr_as_string(group, "cn", NULL);
+ if (tmp == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->gr_name = &buffer[bufpos];
+ bufpos += len;
+
+ /* get userPassword */
+ tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL);
+ if (tmp == NULL) {
+ tmp = "LDB";
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->gr_passwd = &buffer[bufpos];
+ bufpos += len;
+
+ result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0);
+ if (result->gr_gid == 0) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* check if there is enough memory for the list of pointers */
+ lsize = (members->count + 1) * sizeof(char *);
+
+ /* align buffer on pointer boundary */
+ bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*)));
+ if ((buflen - bufpos) < lsize) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ result->gr_mem = (char **)&buffer[bufpos];
+ bufpos += lsize;
+
+ for (i = 0; i < members->count; i++) {
+ tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL);
+ if (tmp == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+ len = strlen(tmp)+1;
+ if (bufpos + len > buflen) {
+ /* buffer too small */
+ *errnop = errno = EAGAIN;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy(&buffer[bufpos], tmp, len);
+ result->gr_mem[i] = &buffer[bufpos];
+ bufpos += len;
+ }
+
+ result->gr_mem[i] = NULL;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
+ long int limit,
+ long int *start,
+ long int *size,
+ gid_t **groups,
+ int *errnop,
+ struct ldb_result *grlist)
+{
+ NSS_STATUS ret;
+ unsigned int i;
+
+ for (i = 0; i < grlist->count; i++) {
+
+ if (limit && (*start > limit)) {
+ /* TODO: warn no all groups were reported */
+ *errnop = 0;
+ ret = NSS_STATUS_SUCCESS;
+ goto done;
+ }
+
+ if (*start == *size) {
+ /* buffer full, enlarge it */
+ long int gs;
+ gid_t *gm;
+
+ gs = (*size) + 32;
+ if (limit && (gs > limit)) {
+ gs = limit;
+ }
+
+ gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t));
+ if ( ! gm) {
+ *errnop = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ *groups = gm;
+ *size = gs;
+ }
+
+ (*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0);
+ if ((*groups)[*start] == 0 || (*groups)[*start] == group) {
+ /* skip root group or primary group */
+ continue;
+ }
+ (*start)++;
+
+ }
+
+ *errnop = 0;
+ ret = NSS_STATUS_SUCCESS;
+done:
+ return ret;
+}
+
+#define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0)
+
+NSS_STATUS _ldb_nss_group_request(struct ldb_result **_res,
+ struct ldb_dn *group_dn,
+ const char * const *attrs,
+ const char *mattr)
+{
+ struct ldb_control **ctrls;
+ struct ldb_control *ctrl;
+ struct ldb_asq_control *asqc;
+ struct ldb_request *req;
+ int ret;
+ struct ldb_result *res = *_res;
+
+ ctrls = talloc_array(res, struct ldb_control *, 2);
+ _LDB_NSS_ALLOC_CHECK(ctrls);
+
+ ctrl = talloc(ctrls, struct ldb_control);
+ _LDB_NSS_ALLOC_CHECK(ctrl);
+
+ asqc = talloc(ctrl, struct ldb_asq_control);
+ _LDB_NSS_ALLOC_CHECK(asqc);
+
+ asqc->source_attribute = talloc_strdup(asqc, mattr);
+ _LDB_NSS_ALLOC_CHECK(asqc->source_attribute);
+
+ asqc->request = 1;
+ asqc->src_attr_len = strlen(asqc->source_attribute);
+ ctrl->oid = LDB_CONTROL_ASQ_OID;
+ ctrl->critical = 1;
+ ctrl->data = asqc;
+ ctrls[0] = ctrl;
+ ctrls[1] = NULL;
+
+ ret = ldb_build_search_req(
+ &req,
+ _ldb_nss_ctx->ldb,
+ res,
+ group_dn,
+ LDB_SCOPE_BASE,
+ "(objectClass=*)",
+ attrs,
+ ctrls,
+ res,
+ ldb_search_default_callback);
+
+ if (ret != LDB_SUCCESS) {
+ errno = ENOENT;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0);
+
+ ret = ldb_request(_ldb_nss_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ } else {
+ talloc_free(req);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ talloc_free(req);
+ return NSS_STATUS_SUCCESS;
+}
+
diff --git a/lib/ldb/nssldb/ldb-nss.h b/lib/ldb/nssldb/ldb-nss.h
new file mode 100644
index 0000000..583876f
--- /dev/null
+++ b/lib/ldb/nssldb/ldb-nss.h
@@ -0,0 +1,84 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LDB_NSS
+#define _LDB_NSS
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+#include <nss.h>
+#include <pwd.h>
+#include <grp.h>
+
+#define _LDB_NSS_URL "etc/users.ldb"
+#define _LDB_NSS_BASEDN "CN=Users,CN=System"
+#define _LDB_NSS_PWENT_FILTER "(&(objectClass=posixAccount)(!(uidNumber=0))(!(gidNumber=0)))"
+#define _LDB_NSS_PWUID_FILTER "(&(objectClass=posixAccount)(uidNumber=%d)(!(gidNumber=0)))"
+#define _LDB_NSS_PWNAM_FILTER "(&(objectClass=posixAccount)(uid=%s)(!(uidNumber=0))(!(gidNumber=0)))"
+
+#define _LDB_NSS_GRENT_FILTER "(&(objectClass=posixGroup)(!(gidNumber=0)))"
+#define _LDB_NSS_GRGID_FILTER "(&(objectClass=posixGroup)(gidNumber=%d)))"
+#define _LDB_NSS_GRNAM_FILTER "(&(objectClass=posixGroup)(cn=%s)(!(gidNumber=0)))"
+
+typedef enum nss_status NSS_STATUS;
+
+struct _ldb_nss_context {
+
+ pid_t pid;
+
+ struct ldb_context *ldb;
+ struct ldb_dn *base;
+
+ int pw_cur;
+ struct ldb_result *pw_res;
+
+ int gr_cur;
+ struct ldb_result *gr_res;
+};
+
+NSS_STATUS _ldb_nss_init(void);
+
+NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *msg);
+
+NSS_STATUS _ldb_nss_fill_group(struct group *result,
+ char *buffer,
+ int buflen,
+ int *errnop,
+ struct ldb_message *group,
+ struct ldb_result *members);
+
+NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
+ long int limit,
+ long int *start,
+ long int *size,
+ gid_t **groups,
+ int *errnop,
+ struct ldb_result *grlist);
+
+NSS_STATUS _ldb_nss_group_request(struct ldb_result **res,
+ struct ldb_dn *group_dn,
+ const char * const *attrs,
+ const char *mattr);
+
+#endif /* _LDB_NSS */
diff --git a/lib/ldb/nssldb/ldb-pwd.c b/lib/ldb/nssldb/ldb-pwd.c
new file mode 100644
index 0000000..6ab103a
--- /dev/null
+++ b/lib/ldb/nssldb/ldb-pwd.c
@@ -0,0 +1,242 @@
+/*
+ LDB nsswitch module
+
+ Copyright (C) Simo Sorce 2006
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ldb-nss.h"
+
+extern struct _ldb_nss_context *_ldb_nss_ctx;
+
+const char *_ldb_nss_pw_attrs[] = {
+ "uid",
+ "userPassword",
+ "uidNumber",
+ "gidNumber",
+ "gecos",
+ "homeDirectory",
+ "loginShell",
+ NULL
+};
+
+NSS_STATUS _nss_ldb_setpwent(void)
+{
+ int ret;
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->pw_cur = 0;
+ if (_ldb_nss_ctx->pw_res != NULL) {
+ talloc_free(_ldb_nss_ctx->pw_res);
+ _ldb_nss_ctx->pw_res = NULL;
+ }
+
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->ldb,
+ &_ldb_nss_ctx->pw_res,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _ldb_nss_pw_attrs,
+ _LDB_NSS_PWENT_FILTER);
+ if (ret != LDB_SUCCESS) {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_endpwent(void)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->pw_cur = 0;
+ if (_ldb_nss_ctx->pw_res) {
+ talloc_free(_ldb_nss_ctx->pw_res);
+ _ldb_nss_ctx->pw_res = NULL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getpwent_r(struct passwd *result_buf,
+ char *buffer,
+ int buflen,
+ int *errnop)
+{
+ int ret;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ *errnop = 0;
+
+ if (_ldb_nss_ctx->pw_cur >= _ldb_nss_ctx->pw_res->count) {
+ /* already returned all entries */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = _ldb_nss_fill_passwd(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ _ldb_nss_ctx->pw_res->msgs[_ldb_nss_ctx->pw_cur]);
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ _ldb_nss_ctx->pw_cur++;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+NSS_STATUS _nss_ldb_getpwuid_r(uid_t uid, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ struct ldb_result *res;
+
+ if (uid == 0) { /* we don't serve root uid by policy */
+ *errnop = errno = ENOENT;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ /* build the filter for this uid */
+ filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWUID_FILTER, uid);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOMEM;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->ldb,
+ &res,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _ldb_nss_pw_attrs,
+ filter);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* if none found return */
+ if (res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* fill in the passwd struct */
+ ret = _ldb_nss_fill_passwd(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ res->msgs[0]);
+
+done:
+ talloc_free(filter);
+ talloc_free(res);
+ return ret;
+}
+
+NSS_STATUS _nss_ldb_getpwnam_r(const char *name, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop)
+{
+ int ret;
+ char *filter;
+ struct ldb_result *res;
+
+ ret = _ldb_nss_init();
+ if (ret != NSS_STATUS_SUCCESS) {
+ return ret;
+ }
+
+ /* build the filter for this name */
+ filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWNAM_FILTER, name);
+ if (filter == NULL) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* search the entry */
+ ret = ldb_search(_ldb_nss_ctx->ldb,
+ _ldb_nss_ctx->ldb,
+ &res,
+ _ldb_nss_ctx->base,
+ LDB_SCOPE_SUBTREE,
+ _ldb_nss_pw_attrs,
+ filter);
+ if (ret != LDB_SUCCESS) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* if none found return */
+ if (res->count == 0) {
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_NOTFOUND;
+ goto done;
+ }
+
+ if (res->count != 1) {
+ /* this is a fatal error */
+ *errnop = errno = ENOENT;
+ ret = NSS_STATUS_UNAVAIL;
+ goto done;
+ }
+
+ /* fill in the passwd struct */
+ ret = _ldb_nss_fill_passwd(result_buf,
+ buffer,
+ buflen,
+ errnop,
+ res->msgs[0]);
+
+done:
+ talloc_free(filter);
+ talloc_free(res);
+ return ret;
+}
+
diff --git a/lib/ldb/pyldb-util.pc.in b/lib/ldb/pyldb-util.pc.in
new file mode 100644
index 0000000..60ec702
--- /dev/null
+++ b/lib/ldb/pyldb-util.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+modulesdir=@LDB_MODULESDIR@
+
+Name: pyldb-util@PYTHON_SO_ABI_FLAG@
+Description: Python bindings for LDB
+Version: @PACKAGE_VERSION@
+Requires: ldb
+Libs: @LIB_RPATH@ -L${libdir} -lpyldb-util@PYTHON_LIBNAME_SO_ABI_FLAG@
+Cflags: -I${includedir}
+URL: http://ldb.samba.org/
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
new file mode 100644
index 0000000..3177e20
--- /dev/null
+++ b/lib/ldb/pyldb.c
@@ -0,0 +1,5015 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python interface to ldb.
+
+ Copyright (C) 2005,2006 Tim Potter <tpot@samba.org>
+ Copyright (C) 2006 Simo Sorce <idra@samba.org>
+ Copyright (C) 2007-2010 Jelmer Vernooij <jelmer@samba.org>
+ Copyright (C) 2009-2010 Matthias Dieter Wallnöfer
+ Copyright (C) 2009-2011 Andrew Tridgell
+ Copyright (C) 2009-2011 Andrew Bartlett
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include "ldb_private.h"
+#include "ldb_handlers.h"
+#include "pyldb.h"
+#include "dlinklist.h"
+
+/* discard signature of 'func' in favour of 'target_sig' */
+#define PY_DISCARD_FUNC_SIG(target_sig, func) (target_sig)(void(*)(void))func
+
+struct py_ldb_search_iterator_reply;
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ PyLdbObject *ldb;
+ struct {
+ struct ldb_request *req;
+ struct py_ldb_search_iterator_reply *next;
+ struct py_ldb_search_iterator_reply *result;
+ PyObject *exception;
+ } state;
+} PyLdbSearchIteratorObject;
+
+struct py_ldb_search_iterator_reply {
+ struct py_ldb_search_iterator_reply *prev, *next;
+ PyLdbSearchIteratorObject *py_iter;
+ PyObject *obj;
+};
+
+void initldb(void);
+static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg);
+static PyObject *PyExc_LdbError;
+
+static PyTypeObject PyLdbControl;
+static PyTypeObject PyLdbResult;
+static PyTypeObject PyLdbSearchIterator;
+static PyTypeObject PyLdbMessage;
+#define PyLdbMessage_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessage)
+static PyTypeObject PyLdbModule;
+static PyTypeObject PyLdbDn;
+#define pyldb_Dn_Check(ob) PyObject_TypeCheck(ob, &PyLdbDn)
+static PyTypeObject PyLdb;
+#define PyLdb_Check(ob) PyObject_TypeCheck(ob, &PyLdb)
+static PyTypeObject PyLdbMessageElement;
+#define pyldb_MessageElement_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessageElement)
+
+static PyTypeObject PyLdbTree;
+static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx);
+static PyObject *PyLdbModule_FromModule(struct ldb_module *mod);
+static struct ldb_message_element *PyObject_AsMessageElement(
+ TALLOC_CTX *mem_ctx,
+ PyObject *set_obj,
+ unsigned int flags,
+ const char *attr_name);
+static PyTypeObject PyLdbBytesType;
+
+#define PYARG_STR_UNI "es"
+
+static PyObject *PyLdbBytes_FromStringAndSize(const char *msg, int size)
+{
+ PyObject* result = NULL;
+ PyObject* args = NULL;
+ args = Py_BuildValue("(y#)", msg, size);
+ if (args == NULL) {
+ return NULL;
+ }
+ result = PyLdbBytesType.tp_new(&PyLdbBytesType, args, NULL);
+ Py_DECREF(args);
+ return result;
+}
+
+static PyObject *richcmp(int cmp_val, int op)
+{
+ int ret;
+ switch (op) {
+ case Py_LT: ret = cmp_val < 0; break;
+ case Py_LE: ret = cmp_val <= 0; break;
+ case Py_EQ: ret = cmp_val == 0; break;
+ case Py_NE: ret = cmp_val != 0; break;
+ case Py_GT: ret = cmp_val > 0; break;
+ case Py_GE: ret = cmp_val >= 0; break;
+ default:
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return PyBool_FromLong(ret);
+}
+
+
+static PyObject *py_ldb_control_str(PyLdbControlObject *self)
+{
+ if (self->data != NULL) {
+ char* control = ldb_control_to_string(self->mem_ctx, self->data);
+ if (control == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ return PyUnicode_FromString(control);
+ } else {
+ return PyUnicode_FromString("ldb control");
+ }
+}
+
+static void py_ldb_control_dealloc(PyLdbControlObject *self)
+{
+ if (self->mem_ctx != NULL) {
+ talloc_free(self->mem_ctx);
+ }
+ self->data = NULL;
+ Py_TYPE(self)->tp_free(self);
+}
+
+/* Create a text (rather than bytes) interface for a LDB result object */
+static PyObject *wrap_text(const char *type, PyObject *wrapped)
+{
+ PyObject *mod, *cls, *constructor, *inst;
+ mod = PyImport_ImportModule("_ldb_text");
+ if (mod == NULL)
+ return NULL;
+ cls = PyObject_GetAttrString(mod, type);
+ Py_DECREF(mod);
+ if (cls == NULL) {
+ Py_DECREF(mod);
+ return NULL;
+ }
+ constructor = PyObject_GetAttrString(cls, "_wrap");
+ Py_DECREF(cls);
+ if (constructor == NULL) {
+ return NULL;
+ }
+ inst = PyObject_CallFunction(constructor, discard_const_p(char, "O"), wrapped);
+ Py_DECREF(constructor);
+ return inst;
+}
+
+static PyObject *py_ldb_control_get_oid(PyLdbControlObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyUnicode_FromString(self->data->oid);
+}
+
+static PyObject *py_ldb_control_get_critical(PyLdbControlObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyBool_FromLong(self->data->critical);
+}
+
+static int py_ldb_control_set_critical(PyLdbControlObject *self, PyObject *value, void *closure)
+{
+ if (value == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "cannot delete critical flag");
+ return -1;
+ }
+ if (PyObject_IsTrue(value)) {
+ self->data->critical = true;
+ } else {
+ self->data->critical = false;
+ }
+ return 0;
+}
+
+static PyObject *py_ldb_control_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ char *data = NULL;
+ const char * const kwnames[] = { "ldb", "data", NULL };
+ struct ldb_control *parsed_controls;
+ PyLdbControlObject *ret;
+ PyObject *py_ldb;
+ TALLOC_CTX *mem_ctx;
+ struct ldb_context *ldb_ctx;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!s",
+ discard_const_p(char *, kwnames),
+ &PyLdb, &py_ldb, &data))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
+ parsed_controls = ldb_parse_control_from_string(ldb_ctx, mem_ctx, data);
+
+ if (!parsed_controls) {
+ talloc_free(mem_ctx);
+ PyErr_SetString(PyExc_ValueError, "unable to parse control string");
+ return NULL;
+ }
+
+ ret = PyObject_New(PyLdbControlObject, type);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret->mem_ctx = mem_ctx;
+
+ ret->data = talloc_move(mem_ctx, &parsed_controls);
+ if (ret->data == NULL) {
+ Py_DECREF(ret);
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ return (PyObject *)ret;
+}
+
+static PyGetSetDef py_ldb_control_getset[] = {
+ {
+ .name = discard_const_p(char, "oid"),
+ .get = (getter)py_ldb_control_get_oid,
+ },
+ {
+ .name = discard_const_p(char, "critical"),
+ .get = (getter)py_ldb_control_get_critical,
+ .set = (setter)py_ldb_control_set_critical,
+ },
+ { .name = NULL },
+};
+
+static PyTypeObject PyLdbControl = {
+ .tp_name = "ldb.control",
+ .tp_dealloc = (destructor)py_ldb_control_dealloc,
+ .tp_getattro = PyObject_GenericGetAttr,
+ .tp_basicsize = sizeof(PyLdbControlObject),
+ .tp_getset = py_ldb_control_getset,
+ .tp_doc = "LDB control.",
+ .tp_str = (reprfunc)py_ldb_control_str,
+ .tp_new = py_ldb_control_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
+static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_ctx)
+{
+ PyObject *exc = NULL;
+ if (ret == LDB_ERR_PYTHON_EXCEPTION) {
+ return; /* Python exception should already be set, just keep that */
+ }
+ exc = Py_BuildValue("(i,s)", ret,
+ ldb_ctx == NULL?ldb_strerror(ret):ldb_errstring(ldb_ctx));
+ if (exc == NULL) {
+ /*
+ * Py_BuildValue failed, and will have set its own exception.
+ * It isn't the one we wanted, but it will have to do.
+ * This is all very unexpected.
+ */
+ fprintf(stderr, "could not make LdbError %d!\n", ret);
+ return;
+ }
+ PyErr_SetObject(error, exc);
+ Py_DECREF(exc);
+}
+
+static PyObject *py_ldb_bytes_str(PyBytesObject *self)
+{
+ char *msg = NULL;
+ Py_ssize_t size;
+ int result = 0;
+ if (!PyBytes_Check(self)) {
+ PyErr_Format(PyExc_TypeError,"Unexpected type");
+ return NULL;
+ }
+ result = PyBytes_AsStringAndSize((PyObject *)self, &msg, &size);
+ if (result != 0) {
+ PyErr_Format(PyExc_TypeError, "Failed to extract bytes");
+ return NULL;
+ }
+ return PyUnicode_FromStringAndSize(msg, size);
+}
+
+static PyTypeObject PyLdbBytesType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "ldb.bytes",
+ .tp_doc = "str/bytes (with custom str)",
+ .tp_str = (reprfunc)py_ldb_bytes_str,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
+static PyObject *PyObject_FromLdbValue(const struct ldb_val *val)
+{
+ return PyLdbBytes_FromStringAndSize((const char *)val->data, val->length);
+}
+
+static PyObject *PyStr_FromLdbValue(const struct ldb_val *val)
+{
+ return PyUnicode_FromStringAndSize((const char *)val->data, val->length);
+}
+
+/**
+ * Create a Python object from a ldb_result.
+ *
+ * @param result LDB result to convert
+ * @return Python object with converted result (a list object)
+ */
+static PyObject *PyLdbControl_FromControl(struct ldb_control *control)
+{
+ TALLOC_CTX *ctl_ctx = talloc_new(NULL);
+ PyLdbControlObject *ctrl;
+ if (ctl_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ctrl = (PyLdbControlObject *)PyLdbControl.tp_alloc(&PyLdbControl, 0);
+ if (ctrl == NULL) {
+ talloc_free(ctl_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ctrl->mem_ctx = ctl_ctx;
+ ctrl->data = talloc_steal(ctrl->mem_ctx, control);
+ if (ctrl->data == NULL) {
+ Py_DECREF(ctrl);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ return (PyObject*) ctrl;
+}
+
+/**
+ * Create a Python object from a ldb_result.
+ *
+ * @param result LDB result to convert
+ * @return Python object with converted result (a list object)
+ */
+static PyObject *PyLdbResult_FromResult(struct ldb_result *result)
+{
+ PyLdbResultObject *ret;
+ PyObject *list, *controls, *referals;
+ Py_ssize_t i;
+
+ if (result == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ ret = (PyLdbResultObject *)PyLdbResult.tp_alloc(&PyLdbResult, 0);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ list = PyList_New(result->count);
+ if (list == NULL) {
+ PyErr_NoMemory();
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ for (i = 0; i < result->count; i++) {
+ PyList_SetItem(list, i, PyLdbMessage_FromMessage(result->msgs[i]));
+ }
+
+ ret->mem_ctx = talloc_new(NULL);
+ if (ret->mem_ctx == NULL) {
+ Py_DECREF(list);
+ Py_DECREF(ret);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ret->msgs = list;
+
+ if (result->controls) {
+ i = 0;
+ while (result->controls[i]) {
+ i++;
+ }
+ controls = PyList_New(i);
+ if (controls == NULL) {
+ Py_DECREF(ret);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (i=0; result->controls[i]; i++) {
+ PyObject *ctrl = (PyObject*) PyLdbControl_FromControl(result->controls[i]);
+ if (ctrl == NULL) {
+ Py_DECREF(ret);
+ Py_DECREF(controls);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ PyList_SetItem(controls, i, ctrl);
+ }
+ } else {
+ /*
+ * No controls so we keep an empty list
+ */
+ controls = PyList_New(0);
+ if (controls == NULL) {
+ Py_DECREF(ret);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ }
+
+ ret->controls = controls;
+
+ i = 0;
+
+ while (result->refs && result->refs[i]) {
+ i++;
+ }
+
+ referals = PyList_New(i);
+ if (referals == NULL) {
+ Py_DECREF(ret);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ for (i = 0;result->refs && result->refs[i]; i++) {
+ PyList_SetItem(referals, i, PyUnicode_FromString(result->refs[i]));
+ }
+ ret->referals = referals;
+ return (PyObject *)ret;
+}
+
+/**
+ * Create a LDB Result from a Python object.
+ * If conversion fails, NULL will be returned and a Python exception set.
+ *
+ * Note: the result object only includes the messages at the moment; extended
+ * result, controls and referrals are ignored.
+ *
+ * @param mem_ctx Memory context in which to allocate the LDB Result
+ * @param obj Python object to convert
+ * @return a ldb_result, or NULL if the conversion failed
+ */
+static struct ldb_result *PyLdbResult_AsResult(TALLOC_CTX *mem_ctx,
+ PyObject *obj)
+{
+ struct ldb_result *res;
+ Py_ssize_t i;
+
+ if (obj == Py_None)
+ return NULL;
+
+ if (!PyList_Check(obj)) {
+ PyErr_SetString(PyExc_ValueError, "Expected list of LDB results");
+ return NULL;
+ }
+
+ res = talloc_zero(mem_ctx, struct ldb_result);
+ if (res == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ res->count = PyList_Size(obj);
+ res->msgs = talloc_array(res, struct ldb_message *, res->count);
+ if (res->msgs == NULL) {
+ talloc_free(res);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (i = 0; i < res->count; i++) {
+ PyObject *item = PyList_GetItem(obj, i);
+ if (item == NULL) {
+ talloc_free(res);
+ return NULL;
+ }
+ res->msgs[i] = pyldb_Message_AsMessage(item);
+ }
+ return res;
+}
+
+static PyObject *py_ldb_dn_validate(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyBool_FromLong(ldb_dn_validate(self->dn));
+}
+
+static PyObject *py_ldb_dn_is_valid(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyBool_FromLong(ldb_dn_is_valid(self->dn));
+}
+
+static PyObject *py_ldb_dn_is_special(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyBool_FromLong(ldb_dn_is_special(self->dn));
+}
+
+static PyObject *py_ldb_dn_is_null(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyBool_FromLong(ldb_dn_is_null(self->dn));
+}
+
+static PyObject *py_ldb_dn_get_casefold(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyUnicode_FromString(ldb_dn_get_casefold(self->dn));
+}
+
+static PyObject *py_ldb_dn_get_linearized(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyUnicode_FromString(ldb_dn_get_linearized(self->dn));
+}
+
+static PyObject *py_ldb_dn_canonical_str(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyUnicode_FromString(ldb_dn_canonical_string(self->dn, self->dn));
+}
+
+static PyObject *py_ldb_dn_canonical_ex_str(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyUnicode_FromString(ldb_dn_canonical_ex_string(self->dn, self->dn));
+}
+
+static PyObject *py_ldb_dn_extended_str(PyLdbDnObject *self, PyObject *args, PyObject *kwargs)
+{
+ const char * const kwnames[] = { "mode", NULL };
+ int mode = 1;
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i",
+ discard_const_p(char *, kwnames),
+ &mode))
+ return NULL;
+ return PyUnicode_FromString(ldb_dn_get_extended_linearized(self->dn, self->dn, mode));
+}
+
+static PyObject *py_ldb_dn_get_extended_component(PyLdbDnObject *self, PyObject *args)
+{
+ char *name;
+ const struct ldb_val *val;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+ val = ldb_dn_get_extended_component(self->dn, name);
+ if (val == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ return PyBytes_FromStringAndSize((const char *)val->data, val->length);
+}
+
+static PyObject *py_ldb_dn_set_extended_component(PyLdbDnObject *self, PyObject *args)
+{
+ char *name;
+ int err;
+ uint8_t *value = NULL;
+ Py_ssize_t size = 0;
+
+ if (!PyArg_ParseTuple(args, "sz#", &name, (char **)&value, &size))
+ return NULL;
+
+ if (value == NULL) {
+ err = ldb_dn_set_extended_component(self->dn, name, NULL);
+ } else {
+ struct ldb_val val;
+ val.data = (uint8_t *)value;
+ val.length = size;
+ err = ldb_dn_set_extended_component(self->dn, name, &val);
+ }
+
+ if (err != LDB_SUCCESS) {
+ PyErr_SetString(PyExc_TypeError, "Failed to set extended component");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_dn_repr(PyLdbDnObject *self)
+{
+ PyObject *str = PyUnicode_FromString(ldb_dn_get_linearized(self->dn));
+ PyObject *repr, *result;
+ if (str == NULL)
+ return NULL;
+ repr = PyObject_Repr(str);
+ if (repr == NULL) {
+ Py_DECREF(str);
+ return NULL;
+ }
+ result = PyUnicode_FromFormat("Dn(%s)", PyUnicode_AsUTF8(repr));
+ Py_DECREF(str);
+ Py_DECREF(repr);
+ return result;
+}
+
+static PyObject *py_ldb_dn_check_special(PyLdbDnObject *self, PyObject *args)
+{
+ char *name;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+
+ return PyBool_FromLong(ldb_dn_check_special(self->dn, name));
+}
+
+static PyObject *py_ldb_dn_richcmp(PyObject *dn1, PyObject *dn2, int op)
+{
+ int ret;
+ if (!pyldb_Dn_Check(dn2)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ ret = ldb_dn_compare(pyldb_Dn_AS_DN(dn1), pyldb_Dn_AS_DN(dn2));
+ return richcmp(ret, op);
+}
+
+static PyObject *py_ldb_dn_get_parent(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_dn *dn = pyldb_Dn_AS_DN((PyObject *)self);
+ struct ldb_dn *parent;
+ PyLdbDnObject *py_ret;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (ldb_dn_get_comp_num(dn) < 1) {
+ Py_RETURN_NONE;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ parent = ldb_dn_get_parent(mem_ctx, dn);
+ if (parent == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ py_ret = (PyLdbDnObject *)PyLdbDn.tp_alloc(&PyLdbDn, 0);
+ if (py_ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->dn = parent;
+ return (PyObject *)py_ret;
+}
+
+static PyObject *py_ldb_dn_add_child(PyLdbDnObject *self, PyObject *args)
+{
+ PyObject *py_other;
+ struct ldb_dn *dn, *other;
+ bool ok;
+ if (!PyArg_ParseTuple(args, "O", &py_other))
+ return NULL;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), &other))
+ return NULL;
+
+ ok = ldb_dn_add_child(dn, other);
+ if (!ok) {
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, NULL);
+ return NULL;
+ }
+
+ Py_RETURN_TRUE;
+}
+
+static PyObject *py_ldb_dn_add_base(PyLdbDnObject *self, PyObject *args)
+{
+ PyObject *py_other;
+ struct ldb_dn *other, *dn;
+ bool ok;
+ if (!PyArg_ParseTuple(args, "O", &py_other))
+ return NULL;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), &other))
+ return NULL;
+
+ ok = ldb_dn_add_base(dn, other);
+ if (!ok) {
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, NULL);
+ return NULL;
+ }
+
+ Py_RETURN_TRUE;
+}
+
+static PyObject *py_ldb_dn_remove_base_components(PyLdbDnObject *self, PyObject *args)
+{
+ struct ldb_dn *dn;
+ int i;
+ bool ok;
+ if (!PyArg_ParseTuple(args, "i", &i))
+ return NULL;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ ok = ldb_dn_remove_base_components(dn, i);
+ if (!ok) {
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, NULL);
+ return NULL;
+ }
+
+ Py_RETURN_TRUE;
+}
+
+static PyObject *py_ldb_dn_is_child_of(PyLdbDnObject *self, PyObject *args)
+{
+ PyObject *py_base;
+ struct ldb_dn *dn, *base;
+ if (!PyArg_ParseTuple(args, "O", &py_base))
+ return NULL;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ if (!pyldb_Object_AsDn(NULL, py_base, ldb_dn_get_ldb_context(dn), &base))
+ return NULL;
+
+ return PyBool_FromLong(ldb_dn_compare_base(base, dn) == 0);
+}
+
+static PyObject *py_ldb_dn_get_component_name(PyLdbDnObject *self, PyObject *args)
+{
+ struct ldb_dn *dn;
+ const char *name;
+ unsigned int num = 0;
+
+ if (!PyArg_ParseTuple(args, "I", &num))
+ return NULL;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ name = ldb_dn_get_component_name(dn, num);
+ if (name == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ return PyUnicode_FromString(name);
+}
+
+static PyObject *py_ldb_dn_get_component_value(PyLdbDnObject *self, PyObject *args)
+{
+ struct ldb_dn *dn;
+ const struct ldb_val *val;
+ unsigned int num = 0;
+
+ if (!PyArg_ParseTuple(args, "I", &num))
+ return NULL;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ val = ldb_dn_get_component_val(dn, num);
+ if (val == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ return PyStr_FromLdbValue(val);
+}
+
+static PyObject *py_ldb_dn_set_component(PyLdbDnObject *self, PyObject *args)
+{
+ unsigned int num = 0;
+ char *name = NULL, *value = NULL;
+ struct ldb_val val = { 0 };
+ int err;
+ Py_ssize_t size = 0;
+
+ if (!PyArg_ParseTuple(args, "Iss#", &num, &name, &value, &size))
+ return NULL;
+
+ val.data = (unsigned char*) value;
+ val.length = size;
+
+ err = ldb_dn_set_component(self->dn, num, name, val);
+ if (err != LDB_SUCCESS) {
+ PyErr_SetString(PyExc_TypeError, "Failed to set component");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_dn_get_rdn_name(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_dn *dn;
+ const char *name;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ name = ldb_dn_get_rdn_name(dn);
+ if (name == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ return PyUnicode_FromString(name);
+}
+
+static PyObject *py_ldb_dn_get_rdn_value(PyLdbDnObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_dn *dn;
+ const struct ldb_val *val;
+
+ dn = pyldb_Dn_AS_DN((PyObject *)self);
+
+ val = ldb_dn_get_rdn_val(dn);
+ if (val == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ return PyStr_FromLdbValue(val);
+}
+
+static PyMethodDef py_ldb_dn_methods[] = {
+ { "validate", (PyCFunction)py_ldb_dn_validate, METH_NOARGS,
+ "S.validate() -> bool\n"
+ "Validate DN is correct." },
+ { "is_valid", (PyCFunction)py_ldb_dn_is_valid, METH_NOARGS,
+ "S.is_valid() -> bool\n" },
+ { "is_special", (PyCFunction)py_ldb_dn_is_special, METH_NOARGS,
+ "S.is_special() -> bool\n"
+ "Check whether this is a special LDB DN." },
+ { "is_null", (PyCFunction)py_ldb_dn_is_null, METH_NOARGS,
+ "Check whether this is a null DN." },
+ { "get_casefold", (PyCFunction)py_ldb_dn_get_casefold, METH_NOARGS,
+ NULL },
+ { "get_linearized", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_ldb_dn_get_linearized),
+ METH_NOARGS,
+ NULL },
+ { "canonical_str", (PyCFunction)py_ldb_dn_canonical_str, METH_NOARGS,
+ "S.canonical_str() -> string\n"
+ "Canonical version of this DN (like a posix path)." },
+ { "is_child_of", (PyCFunction)py_ldb_dn_is_child_of, METH_VARARGS,
+ "S.is_child_of(basedn) -> int\nReturns True if this DN is a child of basedn\n"},
+ { "canonical_ex_str", (PyCFunction)py_ldb_dn_canonical_ex_str, METH_NOARGS,
+ "S.canonical_ex_str() -> string\n"
+ "Canonical version of this DN (like a posix path, with terminating newline)." },
+ { "extended_str", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_ldb_dn_extended_str),
+ METH_VARARGS | METH_KEYWORDS,
+ "S.extended_str(mode=1) -> string\n"
+ "Extended version of this DN" },
+ { "parent", (PyCFunction)py_ldb_dn_get_parent, METH_NOARGS,
+ "S.parent() -> dn\n"
+ "Get the parent for this DN." },
+ { "add_child", (PyCFunction)py_ldb_dn_add_child, METH_VARARGS,
+ "S.add_child(dn) -> bool\n"
+ "Add a child DN to this DN." },
+ { "add_base", (PyCFunction)py_ldb_dn_add_base, METH_VARARGS,
+ "S.add_base(dn) -> bool\n"
+ "Add a base DN to this DN." },
+ { "remove_base_components", (PyCFunction)py_ldb_dn_remove_base_components, METH_VARARGS,
+ "S.remove_base_components(int) -> bool\n"
+ "Remove a number of DN components from the base of this DN." },
+ { "check_special", (PyCFunction)py_ldb_dn_check_special, METH_VARARGS,
+ "S.check_special(name) -> bool\n\n"
+ "Check if name is a special DN name"},
+ { "get_extended_component", (PyCFunction)py_ldb_dn_get_extended_component, METH_VARARGS,
+ "S.get_extended_component(name) -> string\n\n"
+ "returns a DN extended component as a binary string"},
+ { "set_extended_component", (PyCFunction)py_ldb_dn_set_extended_component, METH_VARARGS,
+ "S.set_extended_component(name, value) -> None\n\n"
+ "set a DN extended component as a binary string"},
+ { "get_component_name", (PyCFunction)py_ldb_dn_get_component_name, METH_VARARGS,
+ "S.get_component_name(num) -> string\n"
+ "get the attribute name of the specified component" },
+ { "get_component_value", (PyCFunction)py_ldb_dn_get_component_value, METH_VARARGS,
+ "S.get_component_value(num) -> string\n"
+ "get the attribute value of the specified component as a binary string" },
+ { "set_component", (PyCFunction)py_ldb_dn_set_component, METH_VARARGS,
+ "S.set_component(num, name, value) -> None\n"
+ "set the attribute name and value of the specified component" },
+ { "get_rdn_name", (PyCFunction)py_ldb_dn_get_rdn_name, METH_NOARGS,
+ "S.get_rdn_name() -> string\n"
+ "get the RDN attribute name" },
+ { "get_rdn_value", (PyCFunction)py_ldb_dn_get_rdn_value, METH_NOARGS,
+ "S.get_rdn_value() -> string\n"
+ "get the RDN attribute value as a binary string" },
+ {0}
+};
+
+static Py_ssize_t py_ldb_dn_len(PyLdbDnObject *self)
+{
+ return ldb_dn_get_comp_num(pyldb_Dn_AS_DN((PyObject *)self));
+}
+
+/*
+ copy a DN as a python object
+ */
+static PyObject *py_ldb_dn_copy(struct ldb_dn *dn)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldb_dn *new_dn = NULL;
+ PyLdbDnObject *py_ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ new_dn = ldb_dn_copy(mem_ctx, dn);
+ if (new_dn == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+
+ py_ret = (PyLdbDnObject *)PyLdbDn.tp_alloc(&PyLdbDn, 0);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->dn = new_dn;
+ return (PyObject *)py_ret;
+}
+
+static PyObject *py_ldb_dn_concat(PyLdbDnObject *self, PyObject *py_other)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldb_dn *dn = pyldb_Dn_AS_DN((PyObject *)self),
+ *other;
+ struct ldb_dn *new_dn = NULL;
+ PyLdbDnObject *py_ret;
+
+ if (!pyldb_Object_AsDn(NULL, py_other, NULL, &other))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ new_dn = ldb_dn_copy(mem_ctx, dn);
+ if (new_dn == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+
+ if (!ldb_dn_add_base(new_dn, other)) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to concatenate DNs");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ py_ret = (PyLdbDnObject *)PyLdbDn.tp_alloc(&PyLdbDn, 0);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->dn = new_dn;
+
+ return (PyObject *)py_ret;
+}
+
+static PySequenceMethods py_ldb_dn_seq = {
+ .sq_length = (lenfunc)py_ldb_dn_len,
+ .sq_concat = (binaryfunc)py_ldb_dn_concat,
+};
+
+static PyObject *py_ldb_dn_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ struct ldb_dn *ret = NULL;
+ char *str = NULL;
+ PyObject *py_ldb = NULL;
+ struct ldb_context *ldb_ctx = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ PyLdbDnObject *py_ret = NULL;
+ const char * const kwnames[] = { "ldb", "dn", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O"PYARG_STR_UNI,
+ discard_const_p(char *, kwnames),
+ &py_ldb, "utf8", &str))
+ goto out;
+
+ if (!PyLdb_Check(py_ldb)) {
+ PyErr_SetString(PyExc_TypeError, "Expected Ldb");
+ goto out;
+ }
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ goto out;
+ }
+
+ ret = ldb_dn_new(mem_ctx, ldb_ctx, str);
+ if (!ldb_dn_validate(ret)) {
+ talloc_free(mem_ctx);
+ PyErr_SetString(PyExc_ValueError, "unable to parse dn string");
+ goto out;
+ }
+
+ py_ret = (PyLdbDnObject *)type->tp_alloc(type, 0);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ goto out;
+ }
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->dn = ret;
+out:
+ if (str != NULL) {
+ PyMem_Free(discard_const_p(char, str));
+ }
+ return (PyObject *)py_ret;
+}
+
+static void py_ldb_dn_dealloc(PyLdbDnObject *self)
+{
+ talloc_free(self->mem_ctx);
+ PyObject_Del(self);
+}
+
+static PyTypeObject PyLdbDn = {
+ .tp_name = "ldb.Dn",
+ .tp_methods = py_ldb_dn_methods,
+ .tp_str = (reprfunc)py_ldb_dn_get_linearized,
+ .tp_repr = (reprfunc)py_ldb_dn_repr,
+ .tp_richcompare = (richcmpfunc)py_ldb_dn_richcmp,
+ .tp_as_sequence = &py_ldb_dn_seq,
+ .tp_doc = "A LDB distinguished name.",
+ .tp_new = py_ldb_dn_new,
+ .tp_dealloc = (destructor)py_ldb_dn_dealloc,
+ .tp_basicsize = sizeof(PyLdbDnObject),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
+/* Debug */
+static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3, 0);
+static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap)
+{
+ PyObject *fn = (PyObject *)context;
+ PyObject *result = NULL;
+ result = PyObject_CallFunction(fn, discard_const_p(char, "(i,O)"), level, PyUnicode_FromFormatV(fmt, ap));
+ Py_XDECREF(result);
+}
+
+static PyObject *py_ldb_debug_func;
+
+static PyObject *py_ldb_set_debug(PyObject *self, PyObject *args)
+{
+ PyObject *cb;
+ struct ldb_context *ldb_ctx;
+
+ if (!PyArg_ParseTuple(args, "O", &cb))
+ return NULL;
+
+ if (py_ldb_debug_func != NULL) {
+ Py_DECREF(py_ldb_debug_func);
+ }
+
+ Py_INCREF(cb);
+ /* FIXME: DECREF cb when exiting program */
+ py_ldb_debug_func = cb;
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError,
+ ldb_set_debug(ldb_ctx, py_ldb_debug, cb),
+ ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_create_perms(PyTypeObject *self, PyObject *args)
+{
+ unsigned int perms;
+ if (!PyArg_ParseTuple(args, "I", &perms))
+ return NULL;
+
+ ldb_set_create_perms(pyldb_Ldb_AS_LDBCONTEXT(self), perms);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_modules_dir(PyTypeObject *self, PyObject *args)
+{
+ char *modules_dir;
+ if (!PyArg_ParseTuple(args, "s", &modules_dir))
+ return NULL;
+
+ ldb_set_modules_dir(pyldb_Ldb_AS_LDBCONTEXT(self), modules_dir);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_transaction_start(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ int ldb_err;
+ ldb_err = ldb_transaction_start(ldb_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_transaction_commit(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ int ldb_err;
+ ldb_err = ldb_transaction_commit(ldb_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_transaction_prepare_commit(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ int ldb_err;
+ ldb_err = ldb_transaction_prepare_commit(ldb_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_transaction_cancel(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ int ldb_err;
+ ldb_err = ldb_transaction_cancel(ldb_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_setup_wellknown_attributes(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ int ldb_err;
+ ldb_err = ldb_setup_wellknown_attributes(ldb_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_repr(PyLdbObject *self)
+{
+ return PyUnicode_FromString("<ldb connection>");
+}
+
+static PyObject *py_ldb_get_root_basedn(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_dn *dn = ldb_get_root_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
+ if (dn == NULL)
+ Py_RETURN_NONE;
+ return py_ldb_dn_copy(dn);
+}
+
+
+static PyObject *py_ldb_get_schema_basedn(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_dn *dn = ldb_get_schema_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
+ if (dn == NULL)
+ Py_RETURN_NONE;
+ return py_ldb_dn_copy(dn);
+}
+
+static PyObject *py_ldb_get_config_basedn(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_dn *dn = ldb_get_config_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
+ if (dn == NULL)
+ Py_RETURN_NONE;
+ return py_ldb_dn_copy(dn);
+}
+
+static PyObject *py_ldb_get_default_basedn(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_dn *dn = ldb_get_default_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
+ if (dn == NULL)
+ Py_RETURN_NONE;
+ return py_ldb_dn_copy(dn);
+}
+
+static const char **PyList_AsStrList(TALLOC_CTX *mem_ctx, PyObject *list,
+ const char *paramname)
+{
+ const char **ret;
+ Py_ssize_t i;
+ if (!PyList_Check(list)) {
+ PyErr_Format(PyExc_TypeError, "%s is not a list", paramname);
+ return NULL;
+ }
+ ret = talloc_array(NULL, const char *, PyList_Size(list)+1);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ for (i = 0; i < PyList_Size(list); i++) {
+ const char *str = NULL;
+ Py_ssize_t size;
+ PyObject *item = PyList_GetItem(list, i);
+ if (!PyUnicode_Check(item)) {
+ PyErr_Format(PyExc_TypeError, "%s should be strings", paramname);
+ talloc_free(ret);
+ return NULL;
+ }
+ str = PyUnicode_AsUTF8AndSize(item, &size);
+ if (str == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret[i] = talloc_strndup(ret, str, size);
+ }
+ ret[i] = NULL;
+ return ret;
+}
+
+static int py_ldb_init(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ const char * const kwnames[] = { "url", "flags", "options", NULL };
+ char *url = NULL;
+ PyObject *py_options = Py_None;
+ const char **options;
+ unsigned int flags = 0;
+ int ret;
+ struct ldb_context *ldb;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|zIO:Ldb.__init__",
+ discard_const_p(char *, kwnames),
+ &url, &flags, &py_options))
+ return -1;
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ if (py_options == Py_None) {
+ options = NULL;
+ } else {
+ options = PyList_AsStrList(ldb, py_options, "options");
+ if (options == NULL)
+ return -1;
+ }
+
+ if (url != NULL) {
+ ret = ldb_connect(ldb, url, flags, options);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb);
+ talloc_free(options);
+ return -1;
+ }
+ } else {
+ ldb_set_flags(ldb, flags);
+ }
+
+ talloc_free(options);
+ return 0;
+}
+
+static PyObject *py_ldb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ PyLdbObject *ret;
+ struct ldb_context *ldb;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ret = (PyLdbObject *)type->tp_alloc(type, 0);
+ if (ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ret->mem_ctx = mem_ctx;
+
+ ret->ldb_ctx = ldb;
+ return (PyObject *)ret;
+}
+
+static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ char *url = NULL;
+ unsigned int flags = 0;
+ PyObject *py_options = Py_None;
+ int ret;
+ const char **options;
+ const char * const kwnames[] = { "url", "flags", "options", NULL };
+ struct ldb_context *ldb_ctx;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|IO",
+ discard_const_p(char *, kwnames),
+ &url, &flags, &py_options))
+ return NULL;
+
+ if (py_options == Py_None) {
+ options = NULL;
+ } else {
+ options = PyList_AsStrList(NULL, py_options, "options");
+ if (options == NULL)
+ return NULL;
+ }
+
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ ret = ldb_connect(ldb_ctx, url, flags, options);
+ talloc_free(options);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_modify(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_msg;
+ PyObject *py_controls = Py_None;
+ struct ldb_context *ldb_ctx;
+ struct ldb_request *req;
+ struct ldb_control **parsed_controls;
+ struct ldb_message *msg;
+ int ret;
+ TALLOC_CTX *mem_ctx;
+ bool validate=true;
+ const char * const kwnames[] = { "message", "controls", "validate", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Ob",
+ discard_const_p(char *, kwnames),
+ &py_msg, &py_controls, &validate))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ if (py_controls == Py_None) {
+ parsed_controls = NULL;
+ } else {
+ const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
+ if (controls == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
+ if (controls[0] != NULL && parsed_controls == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
+ return NULL;
+ }
+ talloc_free(controls);
+ }
+
+ if (!PyLdbMessage_Check(py_msg)) {
+ PyErr_SetString(PyExc_TypeError, "Expected Ldb Message");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ msg = pyldb_Message_AsMessage(py_msg);
+
+ if (validate) {
+ ret = ldb_msg_sanity_check(ldb_ctx, msg);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ }
+
+ ret = ldb_build_mod_req(&req, ldb_ctx, mem_ctx, msg, parsed_controls,
+ NULL, ldb_op_default_callback, NULL);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetString(PyExc_TypeError, "failed to build request");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ /* do request and autostart a transaction */
+ /* Then let's LDB handle the message error in case of pb as they are meaningful */
+
+ ret = ldb_transaction_start(ldb_ctx);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ ret = ldb_request(ldb_ctx, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_transaction_commit(ldb_ctx);
+ } else {
+ ldb_transaction_cancel(ldb_ctx);
+ }
+
+ talloc_free(mem_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+
+/**
+ * Obtain a ldb message from a Python Dictionary object.
+ *
+ * @param mem_ctx Memory context
+ * @param py_obj Python Dictionary object
+ * @param ldb_ctx LDB context
+ * @param mod_flags Flags to be set on every message element
+ * @return ldb_message on success or NULL on failure
+ */
+static struct ldb_message *PyDict_AsMessage(TALLOC_CTX *mem_ctx,
+ PyObject *py_obj,
+ struct ldb_context *ldb_ctx,
+ unsigned int mod_flags)
+{
+ struct ldb_message *msg;
+ unsigned int msg_pos = 0;
+ Py_ssize_t dict_pos = 0;
+ PyObject *key, *value;
+ struct ldb_message_element *msg_el;
+ PyObject *dn_value = PyDict_GetItemString(py_obj, "dn");
+
+ msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ msg->elements = talloc_zero_array(msg, struct ldb_message_element, PyDict_Size(py_obj));
+ if (msg->elements == NULL) {
+ PyErr_NoMemory();
+ TALLOC_FREE(msg);
+ return NULL;
+ }
+
+ if (dn_value) {
+ if (!pyldb_Object_AsDn(msg, dn_value, ldb_ctx, &msg->dn)) {
+ PyErr_SetString(PyExc_TypeError, "unable to import dn object");
+ TALLOC_FREE(msg);
+ return NULL;
+ }
+ if (msg->dn == NULL) {
+ PyErr_SetString(PyExc_TypeError, "dn set but not found");
+ TALLOC_FREE(msg);
+ return NULL;
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "no dn set");
+ TALLOC_FREE(msg);
+ return NULL;
+ }
+
+ while (PyDict_Next(py_obj, &dict_pos, &key, &value)) {
+ const char *key_str = PyUnicode_AsUTF8(key);
+ if (ldb_attr_cmp(key_str, "dn") != 0) {
+ msg_el = PyObject_AsMessageElement(msg->elements, value,
+ mod_flags, key_str);
+ if (msg_el == NULL) {
+ PyErr_Format(PyExc_TypeError, "unable to import element '%s'", key_str);
+ TALLOC_FREE(msg);
+ return NULL;
+ }
+ memcpy(&msg->elements[msg_pos], msg_el, sizeof(*msg_el));
+
+ /*
+ * PyObject_AsMessageElement might have returned a
+ * reference to an existing MessageElement, and so left
+ * the name and flags unchanged. Thus if those members
+ * aren’t set, we’ll assume that the user forgot to
+ * initialize them.
+ */
+ if (msg->elements[msg_pos].name == NULL) {
+ /* No name was set — set it now. */
+ msg->elements[msg_pos].name = talloc_strdup(msg->elements, key_str);
+ if (msg->elements[msg_pos].name == NULL) {
+ PyErr_NoMemory();
+ TALLOC_FREE(msg);
+ return NULL;
+ }
+ }
+ if (msg->elements[msg_pos].flags == 0) {
+ /* No flags were set — set them now. */
+ msg->elements[msg_pos].flags = mod_flags;
+ }
+
+ msg_pos++;
+ }
+ }
+
+ msg->num_elements = msg_pos;
+
+ return msg;
+}
+
+static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_obj;
+ int ret;
+ struct ldb_context *ldb_ctx;
+ struct ldb_request *req;
+ struct ldb_message *msg = NULL;
+ PyObject *py_controls = Py_None;
+ TALLOC_CTX *mem_ctx;
+ struct ldb_control **parsed_controls;
+ const char * const kwnames[] = { "message", "controls", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
+ discard_const_p(char *, kwnames),
+ &py_obj, &py_controls))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ if (py_controls == Py_None) {
+ parsed_controls = NULL;
+ } else {
+ const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
+ if (controls == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
+ if (controls[0] != NULL && parsed_controls == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
+ return NULL;
+ }
+ talloc_free(controls);
+ }
+
+ if (PyLdbMessage_Check(py_obj)) {
+ msg = pyldb_Message_AsMessage(py_obj);
+ } else if (PyDict_Check(py_obj)) {
+ msg = PyDict_AsMessage(mem_ctx, py_obj, ldb_ctx, LDB_FLAG_MOD_ADD);
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Dictionary or LdbMessage object expected!");
+ }
+
+ if (!msg) {
+ /* we should have a PyErr already set */
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret = ldb_msg_sanity_check(ldb_ctx, msg);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret = ldb_build_add_req(&req, ldb_ctx, mem_ctx, msg, parsed_controls,
+ NULL, ldb_op_default_callback, NULL);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetString(PyExc_TypeError, "failed to build request");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ /* do request and autostart a transaction */
+ /* Then let's LDB handle the message error in case of pb as they are meaningful */
+
+ ret = ldb_transaction_start(ldb_ctx);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ ret = ldb_request(ldb_ctx, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_transaction_commit(ldb_ctx);
+ } else {
+ ldb_transaction_cancel(ldb_ctx);
+ }
+
+ talloc_free(mem_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_delete(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_dn;
+ struct ldb_dn *dn;
+ int ret;
+ struct ldb_context *ldb_ctx;
+ struct ldb_request *req;
+ PyObject *py_controls = Py_None;
+ TALLOC_CTX *mem_ctx;
+ struct ldb_control **parsed_controls;
+ const char * const kwnames[] = { "dn", "controls", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
+ discard_const_p(char *, kwnames),
+ &py_dn, &py_controls))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ if (py_controls == Py_None) {
+ parsed_controls = NULL;
+ } else {
+ const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
+ if (controls == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
+ if (controls[0] != NULL && parsed_controls == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
+ return NULL;
+ }
+ talloc_free(controls);
+ }
+
+ if (!pyldb_Object_AsDn(mem_ctx, py_dn, ldb_ctx, &dn)) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret = ldb_build_del_req(&req, ldb_ctx, mem_ctx, dn, parsed_controls,
+ NULL, ldb_op_default_callback, NULL);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetString(PyExc_TypeError, "failed to build request");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ /* do request and autostart a transaction */
+ /* Then let's LDB handle the message error in case of pb as they are meaningful */
+
+ ret = ldb_transaction_start(ldb_ctx);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ ret = ldb_request(ldb_ctx, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_transaction_commit(ldb_ctx);
+ } else {
+ ldb_transaction_cancel(ldb_ctx);
+ }
+
+ talloc_free(mem_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_rename(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_dn1, *py_dn2;
+ struct ldb_dn *dn1, *dn2;
+ int ret;
+ TALLOC_CTX *mem_ctx;
+ PyObject *py_controls = Py_None;
+ struct ldb_control **parsed_controls;
+ struct ldb_context *ldb_ctx;
+ struct ldb_request *req;
+ const char * const kwnames[] = { "dn1", "dn2", "controls", NULL };
+
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|O",
+ discard_const_p(char *, kwnames),
+ &py_dn1, &py_dn2, &py_controls))
+ return NULL;
+
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (py_controls == Py_None) {
+ parsed_controls = NULL;
+ } else {
+ const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
+ if (controls == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
+ if (controls[0] != NULL && parsed_controls == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
+ return NULL;
+ }
+ talloc_free(controls);
+ }
+
+
+ if (!pyldb_Object_AsDn(mem_ctx, py_dn1, ldb_ctx, &dn1)) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ if (!pyldb_Object_AsDn(mem_ctx, py_dn2, ldb_ctx, &dn2)) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret = ldb_build_rename_req(&req, ldb_ctx, mem_ctx, dn1, dn2, parsed_controls,
+ NULL, ldb_op_default_callback, NULL);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetString(PyExc_TypeError, "failed to build request");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ /* do request and autostart a transaction */
+ /* Then let's LDB handle the message error in case of pb as they are meaningful */
+
+ ret = ldb_transaction_start(ldb_ctx);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ ret = ldb_request(ldb_ctx, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_transaction_commit(ldb_ctx);
+ } else {
+ ldb_transaction_cancel(ldb_ctx);
+ }
+
+ talloc_free(mem_ctx);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_schema_attribute_remove(PyLdbObject *self, PyObject *args)
+{
+ char *name;
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+
+ ldb_schema_attribute_remove(pyldb_Ldb_AS_LDBCONTEXT(self), name);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_schema_attribute_add(PyLdbObject *self, PyObject *args)
+{
+ char *attribute, *syntax;
+ unsigned int flags;
+ int ret;
+ struct ldb_context *ldb_ctx;
+
+ if (!PyArg_ParseTuple(args, "sIs", &attribute, &flags, &syntax))
+ return NULL;
+
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ ret = ldb_schema_attribute_add(ldb_ctx, attribute, flags, syntax);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *ldb_ldif_to_pyobject(struct ldb_context *ldb, struct ldb_ldif *ldif)
+{
+ PyObject *obj = NULL;
+ PyObject *result = NULL;
+
+ if (ldif == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ switch (ldif->changetype) {
+ case LDB_CHANGETYPE_NONE:
+ case LDB_CHANGETYPE_ADD:
+ obj = PyLdbMessage_FromMessage(ldif->msg);
+ break;
+ case LDB_CHANGETYPE_MODIFY:
+ obj = PyLdbMessage_FromMessage(ldif->msg);
+ break;
+ case LDB_CHANGETYPE_DELETE:
+ if (ldif->msg->num_elements != 0) {
+ PyErr_Format(PyExc_ValueError,
+ "CHANGETYPE(DELETE) with num_elements=%u",
+ ldif->msg->num_elements);
+ return NULL;
+ }
+ obj = pyldb_Dn_FromDn(ldif->msg->dn);
+ break;
+ case LDB_CHANGETYPE_MODRDN: {
+ struct ldb_dn *olddn = NULL;
+ PyObject *olddn_obj = NULL;
+ bool deleteoldrdn = false;
+ PyObject *deleteoldrdn_obj = NULL;
+ struct ldb_dn *newdn = NULL;
+ PyObject *newdn_obj = NULL;
+ int ret;
+
+ ret = ldb_ldif_parse_modrdn(ldb,
+ ldif,
+ ldif,
+ &olddn,
+ NULL,
+ &deleteoldrdn,
+ NULL,
+ &newdn);
+ if (ret != LDB_SUCCESS) {
+ PyErr_Format(PyExc_ValueError,
+ "ldb_ldif_parse_modrdn() failed");
+ return NULL;
+ }
+
+ olddn_obj = pyldb_Dn_FromDn(olddn);
+ if (olddn_obj == NULL) {
+ return NULL;
+ }
+ if (deleteoldrdn) {
+ deleteoldrdn_obj = Py_True;
+ } else {
+ deleteoldrdn_obj = Py_False;
+ }
+ newdn_obj = pyldb_Dn_FromDn(newdn);
+ if (newdn_obj == NULL) {
+ deleteoldrdn_obj = NULL;
+ Py_CLEAR(olddn_obj);
+ return NULL;
+ }
+
+ obj = Py_BuildValue(discard_const_p(char, "{s:O,s:O,s:O}"),
+ "olddn", olddn_obj,
+ "deleteoldrdn", deleteoldrdn_obj,
+ "newdn", newdn_obj);
+ Py_CLEAR(olddn_obj);
+ deleteoldrdn_obj = NULL;
+ Py_CLEAR(newdn_obj);
+ }
+ break;
+ default:
+ PyErr_Format(PyExc_NotImplementedError,
+ "Unsupported LDB_CHANGETYPE(%u)",
+ ldif->changetype);
+ return NULL;
+ }
+
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ /* We don't want this being attached * to the 'ldb' any more */
+ result = Py_BuildValue(discard_const_p(char, "(iO)"),
+ ldif->changetype,
+ obj);
+ Py_CLEAR(obj);
+ return result;
+}
+
+
+static PyObject *py_ldb_write_ldif(PyLdbObject *self, PyObject *args)
+{
+ int changetype;
+ PyObject *py_msg;
+ struct ldb_ldif ldif;
+ PyObject *ret;
+ char *string;
+ TALLOC_CTX *mem_ctx;
+
+ if (!PyArg_ParseTuple(args, "Oi", &py_msg, &changetype))
+ return NULL;
+
+ if (!PyLdbMessage_Check(py_msg)) {
+ PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for msg");
+ return NULL;
+ }
+
+ ldif.msg = pyldb_Message_AsMessage(py_msg);
+ ldif.changetype = changetype;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ string = ldb_ldif_write_string(pyldb_Ldb_AS_LDBCONTEXT(self), mem_ctx, &ldif);
+ if (!string) {
+ PyErr_SetString(PyExc_KeyError, "Failed to generate LDIF");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret = PyUnicode_FromString(string);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static PyObject *py_ldb_parse_ldif(PyLdbObject *self, PyObject *args)
+{
+ PyObject *list, *ret;
+ struct ldb_ldif *ldif;
+ const char *s;
+ struct ldb_dn *last_dn = NULL;
+
+ TALLOC_CTX *mem_ctx;
+
+ if (!PyArg_ParseTuple(args, "s", &s))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (!mem_ctx) {
+ Py_RETURN_NONE;
+ }
+
+ list = PyList_New(0);
+ if (list == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ while (s && *s != '\0') {
+ ldif = ldb_ldif_read_string(self->ldb_ctx, &s);
+ talloc_steal(mem_ctx, ldif);
+ if (ldif) {
+ int res = 0;
+ PyObject *py_ldif = ldb_ldif_to_pyobject(self->ldb_ctx, ldif);
+ if (py_ldif == NULL) {
+ Py_CLEAR(list);
+ if (PyErr_Occurred() == NULL) {
+ PyErr_BadArgument();
+ }
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ res = PyList_Append(list, py_ldif);
+ Py_CLEAR(py_ldif);
+ if (res == -1) {
+ Py_CLEAR(list);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ last_dn = ldif->msg->dn;
+ } else {
+ const char *last_dn_str = NULL;
+ const char *err_string = NULL;
+ if (last_dn == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "unable to parse LDIF "
+ "string at first chunk");
+ Py_CLEAR(list);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ last_dn_str
+ = ldb_dn_get_linearized(last_dn);
+
+ err_string
+ = talloc_asprintf(mem_ctx,
+ "unable to parse ldif "
+ "string AFTER %s",
+ last_dn_str);
+
+ PyErr_SetString(PyExc_ValueError,
+ err_string);
+ talloc_free(mem_ctx);
+ Py_CLEAR(list);
+ return NULL;
+ }
+ }
+ talloc_free(mem_ctx); /* The pyobject already has a reference to the things it needs */
+ ret = PyObject_GetIter(list);
+ Py_DECREF(list);
+ return ret;
+}
+
+static PyObject *py_ldb_msg_diff(PyLdbObject *self, PyObject *args)
+{
+ int ldb_ret;
+ PyObject *py_msg_old;
+ PyObject *py_msg_new;
+ struct ldb_message *diff;
+ struct ldb_context *ldb;
+ PyObject *py_ret;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (!PyArg_ParseTuple(args, "OO", &py_msg_old, &py_msg_new))
+ return NULL;
+
+ if (!PyLdbMessage_Check(py_msg_old)) {
+ PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for old message");
+ return NULL;
+ }
+
+ if (!PyLdbMessage_Check(py_msg_new)) {
+ PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for new message");
+ return NULL;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+ ldb_ret = ldb_msg_difference(ldb, mem_ctx,
+ pyldb_Message_AsMessage(py_msg_old),
+ pyldb_Message_AsMessage(py_msg_new),
+ &diff);
+ if (ldb_ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ PyErr_SetString(PyExc_RuntimeError, "Failed to generate the Ldb Message diff");
+ return NULL;
+ }
+
+ diff = ldb_msg_copy(mem_ctx, diff);
+ if (diff == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ py_ret = PyLdbMessage_FromMessage(diff);
+
+ talloc_free(mem_ctx);
+
+ return py_ret;
+}
+
+static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args)
+{
+ const struct ldb_schema_attribute *a;
+ struct ldb_val old_val;
+ struct ldb_val new_val;
+ TALLOC_CTX *mem_ctx;
+ PyObject *ret;
+ char *element_name;
+ PyObject *val;
+ Py_ssize_t size;
+ int result;
+
+ if (!PyArg_ParseTuple(args, "sO", &element_name, &val))
+ return NULL;
+
+ result = PyBytes_AsStringAndSize(val, (char **)&old_val.data, &size);
+ old_val.length = size;
+
+ if (result != 0) {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to convert passed value to String");
+ return NULL;
+ }
+
+ a = ldb_schema_attribute_by_name(pyldb_Ldb_AS_LDBCONTEXT(self), element_name);
+
+ if (a == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (a->syntax->ldif_write_fn(pyldb_Ldb_AS_LDBCONTEXT(self), mem_ctx, &old_val, &new_val) != 0) {
+ talloc_free(mem_ctx);
+ Py_RETURN_NONE;
+ }
+
+ ret = PyBytes_FromStringAndSize((const char *)new_val.data, new_val.length);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_base = Py_None;
+ int scope = LDB_SCOPE_DEFAULT;
+ char *expr = NULL;
+ PyObject *py_attrs = Py_None;
+ PyObject *py_controls = Py_None;
+ const char * const kwnames[] = { "base", "scope", "expression", "attrs", "controls", NULL };
+ int ret;
+ struct ldb_result *res;
+ struct ldb_request *req;
+ const char **attrs;
+ struct ldb_context *ldb_ctx;
+ struct ldb_control **parsed_controls;
+ struct ldb_dn *base;
+ PyObject *py_ret;
+ TALLOC_CTX *mem_ctx;
+
+ /* type "int" rather than "enum" for "scope" is intentional */
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOO",
+ discard_const_p(char *, kwnames),
+ &py_base, &scope, &expr, &py_attrs, &py_controls))
+ return NULL;
+
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ if (py_attrs == Py_None) {
+ attrs = NULL;
+ } else {
+ attrs = PyList_AsStrList(mem_ctx, py_attrs, "attrs");
+ if (attrs == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ }
+
+ if (py_base == Py_None) {
+ base = ldb_get_default_basedn(ldb_ctx);
+ } else {
+ if (!pyldb_Object_AsDn(mem_ctx, py_base, ldb_ctx, &base)) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ }
+
+ if (py_controls == Py_None) {
+ parsed_controls = NULL;
+ } else {
+ const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
+ if (controls == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
+ if (controls[0] != NULL && parsed_controls == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
+ return NULL;
+ }
+ talloc_free(controls);
+ }
+
+ res = talloc_zero(mem_ctx, struct ldb_result);
+ if (res == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret = ldb_build_search_req(&req, ldb_ctx, mem_ctx,
+ base,
+ scope,
+ expr,
+ attrs,
+ parsed_controls,
+ res,
+ ldb_search_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ talloc_steal(req, attrs);
+
+ ret = ldb_request(ldb_ctx, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ py_ret = PyLdbResult_FromResult(res);
+
+ talloc_free(mem_ctx);
+
+ return py_ret;
+}
+
+static int py_ldb_search_iterator_reply_destructor(struct py_ldb_search_iterator_reply *reply)
+{
+ if (reply->py_iter != NULL) {
+ DLIST_REMOVE(reply->py_iter->state.next, reply);
+ if (reply->py_iter->state.result == reply) {
+ reply->py_iter->state.result = NULL;
+ }
+ reply->py_iter = NULL;
+ }
+
+ Py_CLEAR(reply->obj);
+
+ return 0;
+}
+
+static int py_ldb_search_iterator_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ PyLdbSearchIteratorObject *py_iter = (PyLdbSearchIteratorObject *)req->context;
+ struct ldb_result result = { .msgs = NULL };
+ struct py_ldb_search_iterator_reply *reply = NULL;
+
+ if (ares == NULL) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ int ret = ares->error;
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, ret);
+ }
+
+ reply = talloc_zero(py_iter->mem_ctx,
+ struct py_ldb_search_iterator_reply);
+ if (reply == NULL) {
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ reply->py_iter = py_iter;
+ talloc_set_destructor(reply, py_ldb_search_iterator_reply_destructor);
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ reply->obj = PyLdbMessage_FromMessage(ares->message);
+ if (reply->obj == NULL) {
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ DLIST_ADD_END(py_iter->state.next, reply);
+ TALLOC_FREE(ares);
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_REFERRAL:
+ reply->obj = PyUnicode_FromString(ares->referral);
+ if (reply->obj == NULL) {
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ DLIST_ADD_END(py_iter->state.next, reply);
+ TALLOC_FREE(ares);
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ result = (struct ldb_result) { .controls = ares->controls };
+ reply->obj = PyLdbResult_FromResult(&result);
+ if (reply->obj == NULL) {
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ py_iter->state.result = reply;
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ TALLOC_FREE(ares);
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+}
+
+static PyObject *py_ldb_search_iterator(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_base = Py_None;
+ int scope = LDB_SCOPE_DEFAULT;
+ int timeout = 0;
+ char *expr = NULL;
+ PyObject *py_attrs = Py_None;
+ PyObject *py_controls = Py_None;
+ const char * const kwnames[] = { "base", "scope", "expression", "attrs", "controls", "timeout", NULL };
+ int ret;
+ const char **attrs;
+ struct ldb_context *ldb_ctx;
+ struct ldb_control **parsed_controls;
+ struct ldb_dn *base;
+ PyLdbSearchIteratorObject *py_iter;
+
+ /* type "int" rather than "enum" for "scope" is intentional */
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOOi",
+ discard_const_p(char *, kwnames),
+ &py_base, &scope, &expr, &py_attrs, &py_controls, &timeout))
+ return NULL;
+
+ py_iter = (PyLdbSearchIteratorObject *)PyLdbSearchIterator.tp_alloc(&PyLdbSearchIterator, 0);
+ if (py_iter == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_iter->ldb = self;
+ Py_INCREF(self);
+ ZERO_STRUCT(py_iter->state);
+ py_iter->mem_ctx = talloc_new(NULL);
+ if (py_iter->mem_ctx == NULL) {
+ Py_DECREF(py_iter);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+
+ if (py_attrs == Py_None) {
+ attrs = NULL;
+ } else {
+ attrs = PyList_AsStrList(py_iter->mem_ctx, py_attrs, "attrs");
+ if (attrs == NULL) {
+ Py_DECREF(py_iter);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ }
+
+ if (py_base == Py_None) {
+ base = ldb_get_default_basedn(ldb_ctx);
+ } else {
+ if (!pyldb_Object_AsDn(py_iter->mem_ctx, py_base, ldb_ctx, &base)) {
+ Py_DECREF(py_iter);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ }
+
+ if (py_controls == Py_None) {
+ parsed_controls = NULL;
+ } else {
+ const char **controls = NULL;
+
+ controls = PyList_AsStrList(py_iter->mem_ctx,
+ py_controls, "controls");
+ if (controls == NULL) {
+ Py_DECREF(py_iter);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ parsed_controls = ldb_parse_control_strings(ldb_ctx,
+ py_iter->mem_ctx,
+ controls);
+ if (controls[0] != NULL && parsed_controls == NULL) {
+ Py_DECREF(py_iter);
+ PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
+ return NULL;
+ }
+ talloc_free(controls);
+ }
+
+ ret = ldb_build_search_req(&py_iter->state.req,
+ ldb_ctx,
+ py_iter->mem_ctx,
+ base,
+ scope,
+ expr,
+ attrs,
+ parsed_controls,
+ py_iter,
+ py_ldb_search_iterator_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ Py_DECREF(py_iter);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ ldb_set_timeout(ldb_ctx, py_iter->state.req, timeout);
+
+ ret = ldb_request(ldb_ctx, py_iter->state.req);
+ if (ret != LDB_SUCCESS) {
+ Py_DECREF(py_iter);
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return NULL;
+ }
+
+ return (PyObject *)py_iter;
+}
+
+static PyObject *py_ldb_get_opaque(PyLdbObject *self, PyObject *args)
+{
+ char *name;
+ void *data;
+
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+
+ data = ldb_get_opaque(pyldb_Ldb_AS_LDBCONTEXT(self), name);
+
+ if (data == NULL)
+ Py_RETURN_NONE;
+
+ /* FIXME: More interpretation */
+
+ Py_RETURN_TRUE;
+}
+
+static PyObject *py_ldb_set_opaque(PyLdbObject *self, PyObject *args)
+{
+ char *name;
+ PyObject *data;
+
+ if (!PyArg_ParseTuple(args, "sO", &name, &data))
+ return NULL;
+
+ /* FIXME: More interpretation */
+
+ ldb_set_opaque(pyldb_Ldb_AS_LDBCONTEXT(self), name, data);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_modules(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+ PyObject *ret = PyList_New(0);
+ struct ldb_module *mod;
+
+ if (ret == NULL) {
+ return PyErr_NoMemory();
+ }
+ for (mod = ldb->modules; mod; mod = mod->next) {
+ PyObject *item = PyLdbModule_FromModule(mod);
+ int res = 0;
+ if (item == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Failed to load LdbModule");
+ Py_CLEAR(ret);
+ return NULL;
+ }
+ res = PyList_Append(ret, item);
+ Py_CLEAR(item);
+ if (res == -1) {
+ Py_CLEAR(ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+static PyObject *py_ldb_sequence_number(PyLdbObject *self, PyObject *args)
+{
+ struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+ int type, ret;
+ uint64_t value;
+
+ if (!PyArg_ParseTuple(args, "i", &type))
+ return NULL;
+
+ /* FIXME: More interpretation */
+
+ ret = ldb_sequence_number(ldb, type, &value);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
+
+ return PyLong_FromLongLong(value);
+}
+
+static PyObject *py_ldb_whoami(PyLdbObject *self, PyObject *args)
+{
+ struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+ struct ldb_result *res = NULL;
+ struct ldb_extended *ext_res = NULL;
+ size_t len = 0;
+ int ret;
+
+ ret = ldb_extended(ldb, LDB_EXTENDED_WHOAMI_OID, NULL, &res);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
+
+ ext_res = res->extended;
+ if (ext_res == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Got no exop reply");
+ return NULL;
+ }
+
+ if (strcmp(ext_res->oid, LDB_EXTENDED_WHOAMI_OID) != 0) {
+ PyErr_SetString(PyExc_TypeError, "Got wrong reply OID");
+ return NULL;
+ }
+
+ len = talloc_get_size(ext_res->data);
+ if (len == 0) {
+ Py_RETURN_NONE;
+ }
+
+ return PyUnicode_FromStringAndSize(ext_res->data, len);
+}
+
+
+static const struct ldb_dn_extended_syntax test_dn_syntax = {
+ .name = "TEST",
+ .read_fn = ldb_handler_copy,
+ .write_clear_fn = ldb_handler_copy,
+ .write_hex_fn = ldb_handler_copy,
+};
+
+static PyObject *py_ldb_register_test_extensions(PyLdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
+ int ret;
+
+ ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &test_dn_syntax);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
+
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef py_ldb_methods[] = {
+ { "set_debug", (PyCFunction)py_ldb_set_debug, METH_VARARGS,
+ "S.set_debug(callback) -> None\n"
+ "Set callback for LDB debug messages.\n"
+ "The callback should accept a debug level and debug text." },
+ { "set_create_perms", (PyCFunction)py_ldb_set_create_perms, METH_VARARGS,
+ "S.set_create_perms(mode) -> None\n"
+ "Set mode to use when creating new LDB files." },
+ { "set_modules_dir", (PyCFunction)py_ldb_set_modules_dir, METH_VARARGS,
+ "S.set_modules_dir(path) -> None\n"
+ "Set path LDB should search for modules" },
+ { "transaction_start", (PyCFunction)py_ldb_transaction_start, METH_NOARGS,
+ "S.transaction_start() -> None\n"
+ "Start a new transaction." },
+ { "transaction_prepare_commit", (PyCFunction)py_ldb_transaction_prepare_commit, METH_NOARGS,
+ "S.transaction_prepare_commit() -> None\n"
+ "prepare to commit a new transaction (2-stage commit)." },
+ { "transaction_commit", (PyCFunction)py_ldb_transaction_commit, METH_NOARGS,
+ "S.transaction_commit() -> None\n"
+ "commit a new transaction." },
+ { "transaction_cancel", (PyCFunction)py_ldb_transaction_cancel, METH_NOARGS,
+ "S.transaction_cancel() -> None\n"
+ "cancel a new transaction." },
+ { "setup_wellknown_attributes", (PyCFunction)py_ldb_setup_wellknown_attributes, METH_NOARGS,
+ NULL },
+ { "get_root_basedn", (PyCFunction)py_ldb_get_root_basedn, METH_NOARGS,
+ NULL },
+ { "get_schema_basedn", (PyCFunction)py_ldb_get_schema_basedn, METH_NOARGS,
+ NULL },
+ { "get_default_basedn", (PyCFunction)py_ldb_get_default_basedn, METH_NOARGS,
+ NULL },
+ { "get_config_basedn", (PyCFunction)py_ldb_get_config_basedn, METH_NOARGS,
+ NULL },
+ { "connect", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_connect),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.connect(url, flags=0, options=None) -> None\n"
+ "Connect to a LDB URL." },
+ { "modify", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_modify),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.modify(message, controls=None, validate=False) -> None\n"
+ "Modify an entry." },
+ { "add", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_add),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.add(message, controls=None) -> None\n"
+ "Add an entry." },
+ { "delete", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_delete),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.delete(dn, controls=None) -> None\n"
+ "Remove an entry." },
+ { "rename", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_rename),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.rename(old_dn, new_dn, controls=None) -> None\n"
+ "Rename an entry." },
+ { "search", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_search),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.search(base=None, scope=None, expression=None, attrs=None, controls=None) -> result\n"
+ "Search in a database.\n"
+ "\n"
+ ":param base: Optional base DN to search\n"
+ ":param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE)\n"
+ ":param expression: Optional search expression\n"
+ ":param attrs: Attributes to return (defaults to all)\n"
+ ":param controls: Optional list of controls\n"
+ ":return: ldb.Result object\n"
+ },
+ { "search_iterator", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_ldb_search_iterator),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.search_iterator(base=None, scope=None, expression=None, attrs=None, controls=None, timeout=None) -> iterator\n"
+ "Search in a database.\n"
+ "\n"
+ ":param base: Optional base DN to search\n"
+ ":param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE)\n"
+ ":param expression: Optional search expression\n"
+ ":param attrs: Attributes to return (defaults to all)\n"
+ ":param controls: Optional list of controls\n"
+ ":param timeout: Optional timeout in seconds (defaults to 300), 0 means the default, -1 no timeout\n"
+ ":return: ldb.SearchIterator object that provides results when they arrive\n"
+ },
+ { "schema_attribute_remove", (PyCFunction)py_ldb_schema_attribute_remove, METH_VARARGS,
+ NULL },
+ { "schema_attribute_add", (PyCFunction)py_ldb_schema_attribute_add, METH_VARARGS,
+ NULL },
+ { "schema_format_value", (PyCFunction)py_ldb_schema_format_value, METH_VARARGS,
+ NULL },
+ { "parse_ldif", (PyCFunction)py_ldb_parse_ldif, METH_VARARGS,
+ "S.parse_ldif(ldif) -> iter(messages)\n"
+ "Parse a string formatted using LDIF." },
+ { "write_ldif", (PyCFunction)py_ldb_write_ldif, METH_VARARGS,
+ "S.write_ldif(message, changetype) -> ldif\n"
+ "Print the message as a string formatted using LDIF." },
+ { "msg_diff", (PyCFunction)py_ldb_msg_diff, METH_VARARGS,
+ "S.msg_diff(Message) -> Message\n"
+ "Return an LDB Message of the difference between two Message objects." },
+ { "get_opaque", (PyCFunction)py_ldb_get_opaque, METH_VARARGS,
+ "S.get_opaque(name) -> value\n"
+ "Get an opaque value set on this LDB connection. \n"
+ ":note: The returned value may not be useful in Python."
+ },
+ { "set_opaque", (PyCFunction)py_ldb_set_opaque, METH_VARARGS,
+ "S.set_opaque(name, value) -> None\n"
+ "Set an opaque value on this LDB connection. \n"
+ ":note: Passing incorrect values may cause crashes." },
+ { "modules", (PyCFunction)py_ldb_modules, METH_NOARGS,
+ "S.modules() -> list\n"
+ "Return the list of modules on this LDB connection " },
+ { "sequence_number", (PyCFunction)py_ldb_sequence_number, METH_VARARGS,
+ "S.sequence_number(type) -> value\n"
+ "Return the value of the sequence according to the requested type" },
+ { "whoami",
+ (PyCFunction)py_ldb_whoami,
+ METH_NOARGS,
+ "S.whoami(type) -> value\n"
+ "Return the RFC4532 whoami string",
+ },
+ { "_register_test_extensions", (PyCFunction)py_ldb_register_test_extensions, METH_NOARGS,
+ "S._register_test_extensions() -> None\n"
+ "Register internal extensions used in testing" },
+ {0},
+};
+
+static PyObject *PyLdbModule_FromModule(struct ldb_module *mod)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldb_module *mod_ref = NULL;
+ PyLdbModuleObject *ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ mod_ref = talloc_reference(mem_ctx, mod);
+ if (mod_ref == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+
+ ret = (PyLdbModuleObject *)PyLdbModule.tp_alloc(&PyLdbModule, 0);
+ if (ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ret->mem_ctx = mem_ctx;
+ ret->mod = mod_ref;
+ return (PyObject *)ret;
+}
+
+static PyObject *py_ldb_get_firstmodule(PyLdbObject *self, void *closure)
+{
+ struct ldb_module *mod = pyldb_Ldb_AS_LDBCONTEXT(self)->modules;
+ if (mod == NULL) {
+ Py_RETURN_NONE;
+ }
+ return PyLdbModule_FromModule(mod);
+}
+
+static PyGetSetDef py_ldb_getset[] = {
+ {
+ .name = discard_const_p(char, "firstmodule"),
+ .get = (getter)py_ldb_get_firstmodule,
+ },
+ { .name = NULL },
+};
+
+static int py_ldb_contains(PyLdbObject *self, PyObject *obj)
+{
+ struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
+ struct ldb_dn *dn;
+ struct ldb_result *result;
+ unsigned int count;
+ int ret;
+
+ if (!pyldb_Object_AsDn(ldb_ctx, obj, ldb_ctx, &dn)) {
+ return -1;
+ }
+
+ ret = ldb_search(ldb_ctx, ldb_ctx, &result, dn, LDB_SCOPE_BASE, NULL,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+ return -1;
+ }
+
+ count = result->count;
+
+ talloc_free(result);
+
+ if (count > 1) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Searching for [%s] dn gave %u results!",
+ ldb_dn_get_linearized(dn),
+ count);
+ return -1;
+ }
+
+ return count;
+}
+
+static PySequenceMethods py_ldb_seq = {
+ .sq_contains = (objobjproc)py_ldb_contains,
+};
+
+static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldb_context *ldb_ctx_ref = NULL;
+ PyLdbObject *ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ ldb_ctx_ref = talloc_reference(mem_ctx, ldb_ctx);
+ if (ldb_ctx_ref == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+
+ ret = (PyLdbObject *)PyLdb.tp_alloc(&PyLdb, 0);
+ if (ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ret->mem_ctx = mem_ctx;
+ ret->ldb_ctx = ldb_ctx_ref;
+ return (PyObject *)ret;
+}
+
+static void py_ldb_dealloc(PyLdbObject *self)
+{
+ talloc_free(self->mem_ctx);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyTypeObject PyLdb = {
+ .tp_name = "ldb.Ldb",
+ .tp_methods = py_ldb_methods,
+ .tp_repr = (reprfunc)py_ldb_repr,
+ .tp_new = py_ldb_new,
+ .tp_init = (initproc)py_ldb_init,
+ .tp_dealloc = (destructor)py_ldb_dealloc,
+ .tp_getset = py_ldb_getset,
+ .tp_getattro = PyObject_GenericGetAttr,
+ .tp_basicsize = sizeof(PyLdbObject),
+ .tp_doc = "Connection to a LDB database.",
+ .tp_as_sequence = &py_ldb_seq,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
+static void py_ldb_result_dealloc(PyLdbResultObject *self)
+{
+ talloc_free(self->mem_ctx);
+ Py_CLEAR(self->msgs);
+ Py_CLEAR(self->referals);
+ Py_CLEAR(self->controls);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *py_ldb_result_get_msgs(PyLdbResultObject *self, void *closure)
+{
+ Py_INCREF(self->msgs);
+ return self->msgs;
+}
+
+static PyObject *py_ldb_result_get_controls(PyLdbResultObject *self, void *closure)
+{
+ Py_INCREF(self->controls);
+ return self->controls;
+}
+
+static PyObject *py_ldb_result_get_referals(PyLdbResultObject *self, void *closure)
+{
+ Py_INCREF(self->referals);
+ return self->referals;
+}
+
+static PyObject *py_ldb_result_get_count(PyLdbResultObject *self, void *closure)
+{
+ Py_ssize_t size;
+ if (self->msgs == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "Count attribute is meaningless in this context");
+ return NULL;
+ }
+ size = PyList_Size(self->msgs);
+ return PyLong_FromLong(size);
+}
+
+static PyGetSetDef py_ldb_result_getset[] = {
+ {
+ .name = discard_const_p(char, "controls"),
+ .get = (getter)py_ldb_result_get_controls,
+ },
+ {
+ .name = discard_const_p(char, "msgs"),
+ .get = (getter)py_ldb_result_get_msgs,
+ },
+ {
+ .name = discard_const_p(char, "referals"),
+ .get = (getter)py_ldb_result_get_referals,
+ },
+ {
+ .name = discard_const_p(char, "count"),
+ .get = (getter)py_ldb_result_get_count,
+ },
+ { .name = NULL },
+};
+
+static PyObject *py_ldb_result_iter(PyLdbResultObject *self)
+{
+ return PyObject_GetIter(self->msgs);
+}
+
+static Py_ssize_t py_ldb_result_len(PyLdbResultObject *self)
+{
+ return PySequence_Size(self->msgs);
+}
+
+static PyObject *py_ldb_result_find(PyLdbResultObject *self, Py_ssize_t idx)
+{
+ return PySequence_GetItem(self->msgs, idx);
+}
+
+static PySequenceMethods py_ldb_result_seq = {
+ .sq_length = (lenfunc)py_ldb_result_len,
+ .sq_item = (ssizeargfunc)py_ldb_result_find,
+};
+
+static PyObject *py_ldb_result_repr(PyLdbObject *self)
+{
+ return PyUnicode_FromString("<ldb result>");
+}
+
+
+static PyTypeObject PyLdbResult = {
+ .tp_name = "ldb.Result",
+ .tp_repr = (reprfunc)py_ldb_result_repr,
+ .tp_dealloc = (destructor)py_ldb_result_dealloc,
+ .tp_iter = (getiterfunc)py_ldb_result_iter,
+ .tp_getset = py_ldb_result_getset,
+ .tp_getattro = PyObject_GenericGetAttr,
+ .tp_basicsize = sizeof(PyLdbResultObject),
+ .tp_as_sequence = &py_ldb_result_seq,
+ .tp_doc = "LDB result.",
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
+static void py_ldb_search_iterator_dealloc(PyLdbSearchIteratorObject *self)
+{
+ Py_CLEAR(self->state.exception);
+ TALLOC_FREE(self->mem_ctx);
+ ZERO_STRUCT(self->state);
+ Py_CLEAR(self->ldb);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *py_ldb_search_iterator_next(PyLdbSearchIteratorObject *self)
+{
+ PyObject *py_ret = NULL;
+
+ if (self->state.req == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "ldb.SearchIterator request already finished");
+ return NULL;
+ }
+
+ /*
+ * TODO: do we want a non-blocking mode?
+ * In future we may add an optional 'nonblocking'
+ * argument to search_iterator().
+ *
+ * For now we keep it simple and wait for at
+ * least one reply.
+ */
+
+ while (self->state.next == NULL) {
+ int ret;
+
+ if (self->state.result != NULL) {
+ /*
+ * We (already) got a final result from the server.
+ *
+ * We stop the iteration and let
+ * py_ldb_search_iterator_result() will deliver
+ * the result details.
+ */
+ TALLOC_FREE(self->state.req);
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+
+ ret = ldb_wait(self->state.req->handle, LDB_WAIT_NONE);
+ if (ret != LDB_SUCCESS) {
+ struct ldb_context *ldb_ctx;
+ TALLOC_FREE(self->state.req);
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self->ldb);
+ /*
+ * We stop the iteration and let
+ * py_ldb_search_iterator_result() will deliver
+ * the exception.
+ */
+ self->state.exception = Py_BuildValue(discard_const_p(char, "(i,s)"),
+ ret, ldb_errstring(ldb_ctx));
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ }
+
+ py_ret = self->state.next->obj;
+ self->state.next->obj = NULL;
+ /* no TALLOC_FREE() as self->state.next is a list */
+ talloc_free(self->state.next);
+ return py_ret;
+}
+
+static PyObject *py_ldb_search_iterator_result(PyLdbSearchIteratorObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ PyObject *py_ret = NULL;
+
+ if (self->state.req != NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "ldb.SearchIterator request running");
+ return NULL;
+ }
+
+ if (self->state.next != NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "ldb.SearchIterator not fully consumed.");
+ return NULL;
+ }
+
+ if (self->state.exception != NULL) {
+ PyErr_SetObject(PyExc_LdbError, self->state.exception);
+ Py_DECREF(self->state.exception);
+ self->state.exception = NULL;
+ return NULL;
+ }
+
+ if (self->state.result == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "ldb.SearchIterator result already consumed");
+ return NULL;
+ }
+
+ py_ret = self->state.result->obj;
+ self->state.result->obj = NULL;
+ TALLOC_FREE(self->state.result);
+ return py_ret;
+}
+
+static PyObject *py_ldb_search_iterator_abandon(PyLdbSearchIteratorObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ if (self->state.req == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "ldb.SearchIterator request already finished");
+ return NULL;
+ }
+
+ Py_CLEAR(self->state.exception);
+ TALLOC_FREE(self->mem_ctx);
+ ZERO_STRUCT(self->state);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_ldb_search_iterator_methods[] = {
+ { "result", (PyCFunction)py_ldb_search_iterator_result, METH_NOARGS,
+ "S.result() -> ldb.Result (without msgs and referrals)\n" },
+ { "abandon", (PyCFunction)py_ldb_search_iterator_abandon, METH_NOARGS,
+ "S.abandon()\n" },
+ {0}
+};
+
+static PyObject *py_ldb_search_iterator_repr(PyLdbSearchIteratorObject *self)
+{
+ return PyUnicode_FromString("<ldb search iterator>");
+}
+
+static PyTypeObject PyLdbSearchIterator = {
+ .tp_name = "ldb.SearchIterator",
+ .tp_repr = (reprfunc)py_ldb_search_iterator_repr,
+ .tp_dealloc = (destructor)py_ldb_search_iterator_dealloc,
+ .tp_iter = PyObject_SelfIter,
+ .tp_iternext = (iternextfunc)py_ldb_search_iterator_next,
+ .tp_methods = py_ldb_search_iterator_methods,
+ .tp_basicsize = sizeof(PyLdbSearchIteratorObject),
+ .tp_doc = "LDB search_iterator.",
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
+static PyObject *py_ldb_module_repr(PyLdbModuleObject *self)
+{
+ return PyUnicode_FromFormat("<ldb module '%s'>",
+ pyldb_Module_AsModule(self)->ops->name);
+}
+
+static PyObject *py_ldb_module_str(PyLdbModuleObject *self)
+{
+ return PyUnicode_FromString(pyldb_Module_AsModule(self)->ops->name);
+}
+
+static PyObject *py_ldb_module_start_transaction(PyLdbModuleObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ pyldb_Module_AsModule(self)->ops->start_transaction(pyldb_Module_AsModule(self));
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_module_end_transaction(PyLdbModuleObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ pyldb_Module_AsModule(self)->ops->end_transaction(pyldb_Module_AsModule(self));
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_module_del_transaction(PyLdbModuleObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ pyldb_Module_AsModule(self)->ops->del_transaction(pyldb_Module_AsModule(self));
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_module_search(PyLdbModuleObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_base, *py_tree, *py_attrs, *py_ret;
+ int ret, scope;
+ struct ldb_request *req;
+ const char * const kwnames[] = { "base", "scope", "tree", "attrs", NULL };
+ struct ldb_module *mod;
+ const char * const*attrs;
+
+ /* type "int" rather than "enum" for "scope" is intentional */
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!iOO",
+ discard_const_p(char *, kwnames),
+ &PyLdbDn, &py_base, &scope, &py_tree, &py_attrs))
+ return NULL;
+
+ mod = self->mod;
+
+ if (py_attrs == Py_None) {
+ attrs = NULL;
+ } else {
+ attrs = PyList_AsStrList(NULL, py_attrs, "attrs");
+ if (attrs == NULL)
+ return NULL;
+ }
+
+ ret = ldb_build_search_req(&req, mod->ldb, NULL, pyldb_Dn_AS_DN(py_base),
+ scope, NULL /* expr */, attrs,
+ NULL /* controls */, NULL, NULL, NULL);
+
+ talloc_steal(req, attrs);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, mod->ldb);
+
+ req->op.search.res = NULL;
+
+ ret = mod->ops->search(mod, req);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, mod->ldb);
+
+ py_ret = PyLdbResult_FromResult(req->op.search.res);
+
+ talloc_free(req);
+
+ return py_ret;
+}
+
+
+static PyObject *py_ldb_module_add(PyLdbModuleObject *self, PyObject *args)
+{
+ struct ldb_request *req;
+ PyObject *py_message;
+ int ret;
+ struct ldb_module *mod;
+
+ if (!PyArg_ParseTuple(args, "O!", &PyLdbMessage, &py_message))
+ return NULL;
+
+ req = talloc_zero(NULL, struct ldb_request);
+ req->operation = LDB_ADD;
+ req->op.add.message = pyldb_Message_AsMessage(py_message);
+
+ mod = pyldb_Module_AsModule(self);
+ ret = mod->ops->add(mod, req);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, mod->ldb);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_module_modify(PyLdbModuleObject *self, PyObject *args)
+{
+ int ret;
+ struct ldb_request *req;
+ PyObject *py_message;
+ struct ldb_module *mod;
+
+ if (!PyArg_ParseTuple(args, "O!", &PyLdbMessage, &py_message))
+ return NULL;
+
+ req = talloc_zero(NULL, struct ldb_request);
+ req->operation = LDB_MODIFY;
+ req->op.mod.message = pyldb_Message_AsMessage(py_message);
+
+ mod = pyldb_Module_AsModule(self);
+ ret = mod->ops->modify(mod, req);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, mod->ldb);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_module_delete(PyLdbModuleObject *self, PyObject *args)
+{
+ int ret;
+ struct ldb_request *req;
+ PyObject *py_dn;
+
+ if (!PyArg_ParseTuple(args, "O!", &PyLdbDn, &py_dn))
+ return NULL;
+
+ req = talloc_zero(NULL, struct ldb_request);
+ req->operation = LDB_DELETE;
+ req->op.del.dn = pyldb_Dn_AS_DN(py_dn);
+
+ ret = pyldb_Module_AsModule(self)->ops->del(pyldb_Module_AsModule(self), req);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, NULL);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_module_rename(PyLdbModuleObject *self, PyObject *args)
+{
+ int ret;
+ struct ldb_request *req;
+ PyObject *py_dn1, *py_dn2;
+
+ if (!PyArg_ParseTuple(args, "O!O!", &PyLdbDn, &py_dn1, &PyLdbDn, &py_dn2))
+ return NULL;
+
+ req = talloc_zero(NULL, struct ldb_request);
+
+ req->operation = LDB_RENAME;
+ req->op.rename.olddn = pyldb_Dn_AS_DN(py_dn1);
+ req->op.rename.newdn = pyldb_Dn_AS_DN(py_dn2);
+
+ ret = pyldb_Module_AsModule(self)->ops->rename(pyldb_Module_AsModule(self), req);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, NULL);
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_ldb_module_methods[] = {
+ { "search", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_module_search),
+ METH_VARARGS|METH_KEYWORDS, NULL },
+ { "add", (PyCFunction)py_ldb_module_add, METH_VARARGS, NULL },
+ { "modify", (PyCFunction)py_ldb_module_modify, METH_VARARGS, NULL },
+ { "rename", (PyCFunction)py_ldb_module_rename, METH_VARARGS, NULL },
+ { "delete", (PyCFunction)py_ldb_module_delete, METH_VARARGS, NULL },
+ { "start_transaction", (PyCFunction)py_ldb_module_start_transaction, METH_NOARGS, NULL },
+ { "end_transaction", (PyCFunction)py_ldb_module_end_transaction, METH_NOARGS, NULL },
+ { "del_transaction", (PyCFunction)py_ldb_module_del_transaction, METH_NOARGS, NULL },
+ {0},
+};
+
+static void py_ldb_module_dealloc(PyLdbModuleObject *self)
+{
+ talloc_free(self->mem_ctx);
+ PyObject_Del(self);
+}
+
+static PyTypeObject PyLdbModule = {
+ .tp_name = "ldb.LdbModule",
+ .tp_methods = py_ldb_module_methods,
+ .tp_repr = (reprfunc)py_ldb_module_repr,
+ .tp_str = (reprfunc)py_ldb_module_str,
+ .tp_basicsize = sizeof(PyLdbModuleObject),
+ .tp_dealloc = (destructor)py_ldb_module_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "LDB module (extension)",
+};
+
+
+/**
+ * Create a ldb_message_element from a Python object.
+ *
+ * This will accept any sequence objects that contains strings, or
+ * a string object.
+ *
+ * A reference to set_obj might be borrowed.
+ *
+ * @param mem_ctx Memory context
+ * @param set_obj Python object to convert
+ * @param flags ldb_message_element flags to set, if a new element is returned
+ * @param attr_name Name of the attribute to set, if a new element is returned
+ * @return New ldb_message_element, allocated as child of mem_ctx
+ */
+static struct ldb_message_element *PyObject_AsMessageElement(
+ TALLOC_CTX *mem_ctx,
+ PyObject *set_obj,
+ unsigned int flags,
+ const char *attr_name)
+{
+ struct ldb_message_element *me;
+ const char *msg = NULL;
+ Py_ssize_t size;
+ int result;
+
+ if (pyldb_MessageElement_Check(set_obj)) {
+ PyLdbMessageElementObject *set_obj_as_me = (PyLdbMessageElementObject *)set_obj;
+ /* We have to talloc_reference() the memory context, not the pointer
+ * which may not actually be it's own context */
+ if (talloc_reference(mem_ctx, set_obj_as_me->mem_ctx)) {
+ return pyldb_MessageElement_AsMessageElement(set_obj);
+ }
+ return NULL;
+ }
+
+ me = talloc(mem_ctx, struct ldb_message_element);
+ if (me == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ me->name = talloc_strdup(me, attr_name);
+ if (me->name == NULL) {
+ PyErr_NoMemory();
+ talloc_free(me);
+ return NULL;
+ }
+ me->flags = flags;
+ if (PyBytes_Check(set_obj) || PyUnicode_Check(set_obj)) {
+ me->num_values = 1;
+ me->values = talloc_array(me, struct ldb_val, me->num_values);
+ if (PyBytes_Check(set_obj)) {
+ char *_msg = NULL;
+ result = PyBytes_AsStringAndSize(set_obj, &_msg, &size);
+ if (result != 0) {
+ talloc_free(me);
+ return NULL;
+ }
+ msg = _msg;
+ } else {
+ msg = PyUnicode_AsUTF8AndSize(set_obj, &size);
+ if (msg == NULL) {
+ talloc_free(me);
+ return NULL;
+ }
+ }
+ me->values[0].data = talloc_memdup(me,
+ (const uint8_t *)msg,
+ size+1);
+ me->values[0].length = size;
+ } else if (PySequence_Check(set_obj)) {
+ Py_ssize_t i;
+ me->num_values = PySequence_Size(set_obj);
+ me->values = talloc_array(me, struct ldb_val, me->num_values);
+ for (i = 0; i < me->num_values; i++) {
+ PyObject *obj = PySequence_GetItem(set_obj, i);
+ if (PyBytes_Check(obj)) {
+ char *_msg = NULL;
+ result = PyBytes_AsStringAndSize(obj, &_msg, &size);
+ if (result != 0) {
+ talloc_free(me);
+ return NULL;
+ }
+ msg = _msg;
+ } else if (PyUnicode_Check(obj)) {
+ msg = PyUnicode_AsUTF8AndSize(obj, &size);
+ if (msg == NULL) {
+ talloc_free(me);
+ return NULL;
+ }
+ } else {
+ PyErr_Format(PyExc_TypeError,
+ "Expected string as element %zd in list", i);
+ talloc_free(me);
+ return NULL;
+ }
+ me->values[i].data = talloc_memdup(me,
+ (const uint8_t *)msg,
+ size+1);
+ me->values[i].length = size;
+ }
+ } else {
+ PyErr_Format(PyExc_TypeError,
+ "String or List type expected for '%s' attribute", attr_name);
+ talloc_free(me);
+ me = NULL;
+ }
+
+ return me;
+}
+
+
+static PyObject *ldb_msg_element_to_set(struct ldb_context *ldb_ctx,
+ struct ldb_message_element *me)
+{
+ Py_ssize_t i;
+ PyObject *result;
+
+ /* Python << 2.5 doesn't have PySet_New and PySet_Add. */
+ result = PyList_New(me->num_values);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < me->num_values; i++) {
+ PyObject *obj = NULL;
+ int ret;
+
+ obj = PyObject_FromLdbValue(&me->values[i]);
+ if (obj == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ ret = PyList_SetItem(result, i, obj);
+ if (ret) {
+ Py_DECREF(obj);
+ Py_DECREF(result);
+ return NULL;
+ }
+ }
+
+ return result;
+}
+
+static PyObject *py_ldb_msg_element_get(PyLdbMessageElementObject *self, PyObject *args)
+{
+ unsigned int i;
+ if (!PyArg_ParseTuple(args, "I", &i))
+ return NULL;
+ if (i >= pyldb_MessageElement_AsMessageElement(self)->num_values)
+ Py_RETURN_NONE;
+
+ return PyObject_FromLdbValue(&(pyldb_MessageElement_AsMessageElement(self)->values[i]));
+}
+
+static PyObject *py_ldb_msg_element_flags(PyLdbMessageElementObject *self, PyObject *args)
+{
+ struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
+ return PyLong_FromLong(el->flags);
+}
+
+static PyObject *py_ldb_msg_element_set_flags(PyLdbMessageElementObject *self, PyObject *args)
+{
+ unsigned int flags;
+ struct ldb_message_element *el;
+ if (!PyArg_ParseTuple(args, "I", &flags))
+ return NULL;
+
+ el = pyldb_MessageElement_AsMessageElement(self);
+ el->flags = flags;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_ldb_msg_element_methods[] = {
+ { "get", (PyCFunction)py_ldb_msg_element_get, METH_VARARGS, NULL },
+ { "set_flags", (PyCFunction)py_ldb_msg_element_set_flags, METH_VARARGS, NULL },
+ { "flags", (PyCFunction)py_ldb_msg_element_flags, METH_NOARGS, NULL },
+ {0},
+};
+
+static Py_ssize_t py_ldb_msg_element_len(PyLdbMessageElementObject *self)
+{
+ return pyldb_MessageElement_AsMessageElement(self)->num_values;
+}
+
+static PyObject *py_ldb_msg_element_find(PyLdbMessageElementObject *self, Py_ssize_t idx)
+{
+ struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
+ if (idx < 0 || idx >= el->num_values) {
+ PyErr_SetString(PyExc_IndexError, "Out of range");
+ return NULL;
+ }
+ return PyLdbBytes_FromStringAndSize((char *)el->values[idx].data, el->values[idx].length);
+}
+
+static PySequenceMethods py_ldb_msg_element_seq = {
+ .sq_length = (lenfunc)py_ldb_msg_element_len,
+ .sq_item = (ssizeargfunc)py_ldb_msg_element_find,
+};
+
+static PyObject *py_ldb_msg_element_richcmp(PyObject *self, PyObject *other, int op)
+{
+ int ret;
+ if (!pyldb_MessageElement_Check(other)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ ret = ldb_msg_element_compare(pyldb_MessageElement_AsMessageElement(self),
+ pyldb_MessageElement_AsMessageElement(other));
+ return richcmp(ret, op);
+}
+
+static PyObject *py_ldb_msg_element_iter(PyLdbMessageElementObject *self)
+{
+ PyObject *el = ldb_msg_element_to_set(NULL,
+ pyldb_MessageElement_AsMessageElement(self));
+ PyObject *ret = PyObject_GetIter(el);
+ Py_DECREF(el);
+ return ret;
+}
+
+static PyObject *PyLdbMessageElement_FromMessageElement(struct ldb_message_element *el, TALLOC_CTX *mem_ctx)
+{
+ TALLOC_CTX *ret_mem_ctx = NULL;
+ PyLdbMessageElementObject *ret;
+
+ ret_mem_ctx = talloc_new(NULL);
+ if (ret_mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ if (talloc_reference(ret_mem_ctx, mem_ctx) == NULL) {
+ talloc_free(ret_mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ret = PyObject_New(PyLdbMessageElementObject, &PyLdbMessageElement);
+ if (ret == NULL) {
+ talloc_free(ret_mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ret->mem_ctx = ret_mem_ctx;
+ ret->el = el;
+ return (PyObject *)ret;
+}
+
+static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *py_elements = NULL;
+ struct ldb_message_element *el;
+ unsigned int flags = 0;
+ char *name = NULL;
+ const char * const kwnames[] = { "elements", "flags", "name", NULL };
+ PyLdbMessageElementObject *ret;
+ TALLOC_CTX *mem_ctx;
+ const char *msg = NULL;
+ Py_ssize_t size;
+ int result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OIs",
+ discard_const_p(char *, kwnames),
+ &py_elements, &flags, &name))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (el == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ if (py_elements != NULL) {
+ Py_ssize_t i;
+ if (PyBytes_Check(py_elements) || PyUnicode_Check(py_elements)) {
+ char *_msg = NULL;
+ el->num_values = 1;
+ el->values = talloc_array(el, struct ldb_val, 1);
+ if (el->values == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ if (PyBytes_Check(py_elements)) {
+ result = PyBytes_AsStringAndSize(py_elements, &_msg, &size);
+ msg = _msg;
+ } else {
+ msg = PyUnicode_AsUTF8AndSize(py_elements, &size);
+ result = (msg == NULL) ? -1 : 0;
+ }
+ if (result != 0) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ el->values[0].data = talloc_memdup(el->values,
+ (const uint8_t *)msg, size + 1);
+ el->values[0].length = size;
+ } else if (PySequence_Check(py_elements)) {
+ el->num_values = PySequence_Size(py_elements);
+ el->values = talloc_array(el, struct ldb_val, el->num_values);
+ if (el->values == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (i = 0; i < el->num_values; i++) {
+ PyObject *item = PySequence_GetItem(py_elements, i);
+ if (item == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ if (PyBytes_Check(item)) {
+ char *_msg = NULL;
+ result = PyBytes_AsStringAndSize(item, &_msg, &size);
+ msg = _msg;
+ } else if (PyUnicode_Check(item)) {
+ msg = PyUnicode_AsUTF8AndSize(item, &size);
+ result = (msg == NULL) ? -1 : 0;
+ } else {
+ PyErr_Format(PyExc_TypeError,
+ "Expected string as element %zd in list", i);
+ result = -1;
+ }
+ if (result != 0) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ el->values[i].data = talloc_memdup(el,
+ (const uint8_t *)msg, size+1);
+ el->values[i].length = size;
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Expected string or list");
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ }
+
+ el->flags = flags;
+ if (name != NULL) {
+ el->name = talloc_strdup(el, name);
+ if (el->name == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+ }
+
+ ret = PyObject_New(PyLdbMessageElementObject, type);
+ if (ret == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ ret->mem_ctx = mem_ctx;
+ ret->el = el;
+ return (PyObject *)ret;
+}
+
+static PyObject *py_ldb_msg_element_repr(PyLdbMessageElementObject *self)
+{
+ char *element_str = NULL;
+ Py_ssize_t i;
+ struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
+ PyObject *ret, *repr;
+
+ for (i = 0; i < el->num_values; i++) {
+ PyObject *o = py_ldb_msg_element_find(self, i);
+ repr = PyObject_Repr(o);
+ if (element_str == NULL)
+ element_str = talloc_strdup(NULL, PyUnicode_AsUTF8(repr));
+ else
+ element_str = talloc_asprintf_append(element_str, ",%s", PyUnicode_AsUTF8(repr));
+ Py_DECREF(repr);
+
+ if (element_str == NULL) {
+ return PyErr_NoMemory();
+ }
+ }
+
+ if (element_str != NULL) {
+ ret = PyUnicode_FromFormat("MessageElement([%s])", element_str);
+ talloc_free(element_str);
+ } else {
+ ret = PyUnicode_FromString("MessageElement([])");
+ }
+
+ return ret;
+}
+
+static PyObject *py_ldb_msg_element_str(PyLdbMessageElementObject *self)
+{
+ struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
+
+ if (el->num_values == 1)
+ return PyUnicode_FromStringAndSize((char *)el->values[0].data, el->values[0].length);
+ else
+ Py_RETURN_NONE;
+}
+
+static void py_ldb_msg_element_dealloc(PyLdbMessageElementObject *self)
+{
+ talloc_free(self->mem_ctx);
+ PyObject_Del(self);
+}
+
+static PyObject *py_ldb_msg_element_get_text(PyObject *self, void *closure)
+{
+ return wrap_text("MessageElementTextWrapper", self);
+}
+
+static PyGetSetDef py_ldb_msg_element_getset[] = {
+ {
+ .name = discard_const_p(char, "text"),
+ .get = (getter)py_ldb_msg_element_get_text,
+ },
+ { .name = NULL }
+};
+
+static PyTypeObject PyLdbMessageElement = {
+ .tp_name = "ldb.MessageElement",
+ .tp_basicsize = sizeof(PyLdbMessageElementObject),
+ .tp_dealloc = (destructor)py_ldb_msg_element_dealloc,
+ .tp_repr = (reprfunc)py_ldb_msg_element_repr,
+ .tp_str = (reprfunc)py_ldb_msg_element_str,
+ .tp_methods = py_ldb_msg_element_methods,
+ .tp_getset = py_ldb_msg_element_getset,
+ .tp_richcompare = (richcmpfunc)py_ldb_msg_element_richcmp,
+ .tp_iter = (getiterfunc)py_ldb_msg_element_iter,
+ .tp_as_sequence = &py_ldb_msg_element_seq,
+ .tp_new = py_ldb_msg_element_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "An element of a Message",
+};
+
+
+static PyObject *py_ldb_msg_from_dict(PyTypeObject *type, PyObject *args)
+{
+ PyObject *py_ldb;
+ PyObject *py_dict;
+ PyObject *py_ret;
+ struct ldb_message *msg;
+ struct ldb_context *ldb_ctx;
+ unsigned int mod_flags = LDB_FLAG_MOD_REPLACE;
+
+ if (!PyArg_ParseTuple(args, "O!O!|I",
+ &PyLdb, &py_ldb, &PyDict_Type, &py_dict,
+ &mod_flags)) {
+ return NULL;
+ }
+
+ if (!PyLdb_Check(py_ldb)) {
+ PyErr_SetString(PyExc_TypeError, "Expected Ldb");
+ return NULL;
+ }
+
+ /* mask only flags we are going to use */
+ mod_flags = LDB_FLAG_MOD_TYPE(mod_flags);
+ if (!mod_flags) {
+ PyErr_SetString(PyExc_ValueError,
+ "FLAG_MOD_ADD, FLAG_MOD_REPLACE or FLAG_MOD_DELETE"
+ " expected as mod_flag value");
+ return NULL;
+ }
+
+ ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
+
+ msg = PyDict_AsMessage(ldb_ctx, py_dict, ldb_ctx, mod_flags);
+ if (!msg) {
+ return NULL;
+ }
+
+ py_ret = PyLdbMessage_FromMessage(msg);
+
+ talloc_unlink(ldb_ctx, msg);
+
+ return py_ret;
+}
+
+static PyObject *py_ldb_msg_remove_attr(PyLdbMessageObject *self, PyObject *args)
+{
+ char *name;
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+
+ ldb_msg_remove_attr(self->msg, name);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_msg_keys(PyLdbMessageObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ Py_ssize_t i, j = 0;
+ PyObject *obj = PyList_New(msg->num_elements+(msg->dn != NULL?1:0));
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ if (msg->dn != NULL) {
+ PyObject *py_dn = NULL;
+ int ret;
+
+ py_dn = PyUnicode_FromString("dn");
+ if (py_dn == NULL) {
+ Py_DECREF(obj);
+ return NULL;
+ }
+
+ ret = PyList_SetItem(obj, j, py_dn);
+ if (ret) {
+ Py_DECREF(py_dn);
+ Py_DECREF(obj);
+ return NULL;
+ }
+
+ j++;
+ }
+ for (i = 0; i < msg->num_elements; i++) {
+ PyObject *py_name = NULL;
+ int ret;
+
+ py_name = PyUnicode_FromString(msg->elements[i].name);
+ if (py_name == NULL) {
+ Py_DECREF(obj);
+ return NULL;
+ }
+
+ ret = PyList_SetItem(obj, j, py_name);
+ if (ret) {
+ Py_DECREF(py_name);
+ Py_DECREF(obj);
+ return NULL;
+ }
+
+ j++;
+ }
+ return obj;
+}
+
+static int py_ldb_msg_contains(PyLdbMessageObject *self, PyObject *py_name)
+{
+ struct ldb_message_element *el = NULL;
+ const char *name = NULL;
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ name = PyUnicode_AsUTF8(py_name);
+ if (name == NULL) {
+ return -1;
+ }
+ if (!ldb_attr_cmp(name, "dn")) {
+ return 1;
+ }
+ el = ldb_msg_find_element(msg, name);
+ return el != NULL ? 1 : 0;
+}
+
+static PyObject *py_ldb_msg_getitem(PyLdbMessageObject *self, PyObject *py_name)
+{
+ struct ldb_message_element *el = NULL;
+ const char *name = NULL;
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ name = PyUnicode_AsUTF8(py_name);
+ if (name == NULL) {
+ return NULL;
+ }
+ if (!ldb_attr_cmp(name, "dn")) {
+ return pyldb_Dn_FromDn(msg->dn);
+ }
+ el = ldb_msg_find_element(msg, name);
+ if (el == NULL) {
+ PyErr_SetString(PyExc_KeyError, "No such element");
+ return NULL;
+ }
+
+ return PyLdbMessageElement_FromMessageElement(el, msg->elements);
+}
+
+static PyObject *py_ldb_msg_get(PyLdbMessageObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *def = NULL;
+ const char *kwnames[] = { "name", "default", "idx", NULL };
+ const char *name = NULL;
+ int idx = -1;
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ struct ldb_message_element *el;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Oi:msg",
+ discard_const_p(char *, kwnames), &name, &def, &idx)) {
+ return NULL;
+ }
+
+ if (strcasecmp(name, "dn") == 0) {
+ return pyldb_Dn_FromDn(msg->dn);
+ }
+
+ el = ldb_msg_find_element(msg, name);
+
+ if (el == NULL || (idx != -1 && el->num_values <= idx)) {
+ if (def != NULL) {
+ Py_INCREF(def);
+ return def;
+ }
+ Py_RETURN_NONE;
+ }
+
+ if (idx == -1) {
+ return (PyObject *)PyLdbMessageElement_FromMessageElement(el, msg->elements);
+ }
+
+ return PyObject_FromLdbValue(&el->values[idx]);
+}
+
+static PyObject *py_ldb_msg_items(PyLdbMessageObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ Py_ssize_t i, j = 0;
+ PyObject *l = PyList_New(msg->num_elements + (msg->dn == NULL?0:1));
+ if (l == NULL) {
+ return PyErr_NoMemory();
+ }
+ if (msg->dn != NULL) {
+ PyObject *value = NULL;
+ PyObject *obj = pyldb_Dn_FromDn(msg->dn);
+ int res = 0;
+ value = Py_BuildValue("(sO)", "dn", obj);
+ Py_CLEAR(obj);
+ if (value == NULL) {
+ Py_CLEAR(l);
+ return NULL;
+ }
+ res = PyList_SetItem(l, 0, value);
+ if (res == -1) {
+ Py_CLEAR(l);
+ return NULL;
+ }
+ j++;
+ }
+ for (i = 0; i < msg->num_elements; i++, j++) {
+ PyObject *value = NULL;
+ PyObject *py_el = PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements);
+ int res = 0;
+ value = Py_BuildValue("(sO)", msg->elements[i].name, py_el);
+ Py_CLEAR(py_el);
+ if (value == NULL ) {
+ Py_CLEAR(l);
+ return NULL;
+ }
+ res = PyList_SetItem(l, j, value);
+ if (res == -1) {
+ Py_CLEAR(l);
+ return NULL;
+ }
+ }
+ return l;
+}
+
+static PyObject *py_ldb_msg_elements(PyLdbMessageObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ Py_ssize_t i = 0;
+ PyObject *l = PyList_New(msg->num_elements);
+ if (l == NULL) {
+ return NULL;
+ }
+ for (i = 0; i < msg->num_elements; i++) {
+ PyObject *msg_el = NULL;
+ int ret;
+
+ msg_el = PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements);
+ if (msg_el == NULL) {
+ Py_DECREF(l);
+ return NULL;
+ }
+
+ ret = PyList_SetItem(l, i, msg_el);
+ if (ret) {
+ Py_DECREF(msg_el);
+ Py_DECREF(l);
+ return NULL;
+ }
+ }
+ return l;
+}
+
+static PyObject *py_ldb_msg_add(PyLdbMessageObject *self, PyObject *args)
+{
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ PyLdbMessageElementObject *py_element;
+ int i, ret;
+ struct ldb_message_element *el;
+ struct ldb_message_element *el_new;
+
+ if (!PyArg_ParseTuple(args, "O!", &PyLdbMessageElement, &py_element))
+ return NULL;
+
+ el = py_element->el;
+ if (el == NULL) {
+ PyErr_SetString(PyExc_ValueError, "Invalid MessageElement object");
+ return NULL;
+ }
+ if (el->name == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "The element has no name");
+ return NULL;
+ }
+ ret = ldb_msg_add_empty(msg, el->name, el->flags, &el_new);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, NULL);
+
+ /* now deep copy all attribute values */
+ el_new->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
+ if (el_new->values == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ el_new->num_values = el->num_values;
+
+ for (i = 0; i < el->num_values; i++) {
+ el_new->values[i] = ldb_val_dup(el_new->values, &el->values[i]);
+ if (el_new->values[i].data == NULL
+ && el->values[i].length != 0) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_ldb_msg_methods[] = {
+ { "from_dict", (PyCFunction)py_ldb_msg_from_dict, METH_CLASS | METH_VARARGS,
+ "Message.from_dict(ldb, dict, mod_flag=FLAG_MOD_REPLACE) -> ldb.Message\n"
+ "Class method to create ldb.Message object from Dictionary.\n"
+ "mod_flag is one of FLAG_MOD_ADD, FLAG_MOD_REPLACE or FLAG_MOD_DELETE."},
+ { "keys", (PyCFunction)py_ldb_msg_keys, METH_NOARGS,
+ "S.keys() -> list\n\n"
+ "Return sequence of all attribute names." },
+ { "remove", (PyCFunction)py_ldb_msg_remove_attr, METH_VARARGS,
+ "S.remove(name)\n\n"
+ "Remove all entries for attributes with the specified name."},
+ { "get", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_msg_get),
+ METH_VARARGS | METH_KEYWORDS,
+ "msg.get(name,default=None,idx=None) -> string\n"
+ "idx is the index into the values array\n"
+ "if idx is None, then a list is returned\n"
+ "if idx is not None, then the element with that index is returned\n"
+ "if you pass the special name 'dn' then the DN object is returned\n"},
+ { "items", (PyCFunction)py_ldb_msg_items, METH_NOARGS, NULL },
+ { "elements", (PyCFunction)py_ldb_msg_elements, METH_NOARGS, NULL },
+ { "add", (PyCFunction)py_ldb_msg_add, METH_VARARGS,
+ "S.add(element)\n\n"
+ "Add an element to this message." },
+ {0},
+};
+
+static PyObject *py_ldb_msg_iter(PyLdbMessageObject *self)
+{
+ PyObject *list, *iter;
+
+ list = py_ldb_msg_keys(self, NULL);
+ iter = PyObject_GetIter(list);
+ Py_DECREF(list);
+ return iter;
+}
+
+static int py_ldb_msg_setitem(PyLdbMessageObject *self, PyObject *name, PyObject *value)
+{
+ const char *attr_name;
+
+ attr_name = PyUnicode_AsUTF8(name);
+ if (attr_name == NULL) {
+ PyErr_SetNone(PyExc_TypeError);
+ return -1;
+ }
+
+ if (value == NULL) {
+ /* delitem */
+ ldb_msg_remove_attr(self->msg, attr_name);
+ } else {
+ int ret;
+ struct ldb_message_element *el = PyObject_AsMessageElement(self->msg,
+ value, 0, attr_name);
+ if (el == NULL) {
+ return -1;
+ }
+ if (el->name == NULL) {
+ /*
+ * If ‘value’ is a MessageElement,
+ * PyObject_AsMessageElement() will have returned a
+ * reference to it without setting the name. We don’t
+ * want to modify the original object to set the name
+ * ourselves, but making a copy would result in
+ * different behaviour for a caller relying on a
+ * reference being kept. Rather than continue with a
+ * NULL name (and probably fail later on), let’s catch
+ * this potential mistake early.
+ */
+ PyErr_SetString(PyExc_ValueError, "MessageElement has no name set");
+ talloc_unlink(self->msg, el);
+ return -1;
+ }
+ ldb_msg_remove_attr(pyldb_Message_AsMessage(self), attr_name);
+ ret = ldb_msg_add(pyldb_Message_AsMessage(self), el, el->flags);
+ if (ret != LDB_SUCCESS) {
+ PyErr_SetLdbError(PyExc_LdbError, ret, NULL);
+ talloc_unlink(self->msg, el);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static Py_ssize_t py_ldb_msg_length(PyLdbMessageObject *self)
+{
+ return pyldb_Message_AsMessage(self)->num_elements;
+}
+
+static PySequenceMethods py_ldb_msg_sequence = {
+ .sq_contains = (objobjproc)py_ldb_msg_contains,
+};
+
+static PyMappingMethods py_ldb_msg_mapping = {
+ .mp_length = (lenfunc)py_ldb_msg_length,
+ .mp_subscript = (binaryfunc)py_ldb_msg_getitem,
+ .mp_ass_subscript = (objobjargproc)py_ldb_msg_setitem,
+};
+
+static PyObject *py_ldb_msg_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ const char * const kwnames[] = { "dn", NULL };
+ struct ldb_message *ret;
+ TALLOC_CTX *mem_ctx;
+ PyObject *pydn = NULL;
+ PyLdbMessageObject *py_ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O",
+ discard_const_p(char *, kwnames),
+ &pydn))
+ return NULL;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ret = ldb_msg_new(mem_ctx);
+ if (ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (pydn != NULL) {
+ struct ldb_dn *dn;
+ if (!pyldb_Object_AsDn(NULL, pydn, NULL, &dn)) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ ret->dn = talloc_reference(ret, dn);
+ if (ret->dn == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+ }
+
+ py_ret = (PyLdbMessageObject *)type->tp_alloc(type, 0);
+ if (py_ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->msg = ret;
+ return (PyObject *)py_ret;
+}
+
+static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldb_message *msg_ref = NULL;
+ PyLdbMessageObject *ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ msg_ref = talloc_reference(mem_ctx, msg);
+ if (msg_ref == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+
+ ret = (PyLdbMessageObject *)PyLdbMessage.tp_alloc(&PyLdbMessage, 0);
+ if (ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ret->mem_ctx = mem_ctx;
+ ret->msg = msg_ref;
+ return (PyObject *)ret;
+}
+
+static PyObject *py_ldb_msg_get_dn(PyLdbMessageObject *self, void *closure)
+{
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ return pyldb_Dn_FromDn(msg->dn);
+}
+
+static int py_ldb_msg_set_dn(PyLdbMessageObject *self, PyObject *value, void *closure)
+{
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ struct ldb_dn *dn = NULL;
+ if (value == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "cannot delete dn");
+ return -1;
+ }
+ if (!pyldb_Dn_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "expected dn");
+ return -1;
+ }
+
+ dn = talloc_reference(msg, pyldb_Dn_AS_DN(value));
+ if (dn == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ msg->dn = dn;
+ return 0;
+}
+
+static PyObject *py_ldb_msg_get_text(PyObject *self, void *closure)
+{
+ return wrap_text("MessageTextWrapper", self);
+}
+
+static PyGetSetDef py_ldb_msg_getset[] = {
+ {
+ .name = discard_const_p(char, "dn"),
+ .get = (getter)py_ldb_msg_get_dn,
+ .set = (setter)py_ldb_msg_set_dn,
+ },
+ {
+ .name = discard_const_p(char, "text"),
+ .get = (getter)py_ldb_msg_get_text,
+ },
+ { .name = NULL },
+};
+
+static PyObject *py_ldb_msg_repr(PyLdbMessageObject *self)
+{
+ PyObject *dict = PyDict_New(), *ret, *repr;
+ const char *repr_str = NULL;
+ if (dict == NULL) {
+ return NULL;
+ }
+ if (PyDict_Update(dict, (PyObject *)self) != 0) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+ repr = PyObject_Repr(dict);
+ if (repr == NULL) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+ repr_str = PyUnicode_AsUTF8(repr);
+ if (repr_str == NULL) {
+ Py_DECREF(repr);
+ Py_DECREF(dict);
+ return NULL;
+ }
+ ret = PyUnicode_FromFormat("Message(%s)", repr_str);
+ Py_DECREF(repr);
+ Py_DECREF(dict);
+ return ret;
+}
+
+static void py_ldb_msg_dealloc(PyLdbMessageObject *self)
+{
+ talloc_free(self->mem_ctx);
+ PyObject_Del(self);
+}
+
+static PyObject *py_ldb_msg_richcmp(PyLdbMessageObject *py_msg1,
+ PyLdbMessageObject *py_msg2, int op)
+{
+ struct ldb_message *msg1, *msg2;
+ unsigned int i;
+ int ret;
+
+ if (!PyLdbMessage_Check(py_msg2)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ msg1 = pyldb_Message_AsMessage(py_msg1),
+ msg2 = pyldb_Message_AsMessage(py_msg2);
+
+ if ((msg1->dn != NULL) || (msg2->dn != NULL)) {
+ ret = ldb_dn_compare(msg1->dn, msg2->dn);
+ if (ret != 0) {
+ return richcmp(ret, op);
+ }
+ }
+
+ ret = msg1->num_elements - msg2->num_elements;
+ if (ret != 0) {
+ return richcmp(ret, op);
+ }
+
+ for (i = 0; i < msg1->num_elements; i++) {
+ ret = ldb_msg_element_compare_name(&msg1->elements[i],
+ &msg2->elements[i]);
+ if (ret != 0) {
+ return richcmp(ret, op);
+ }
+
+ ret = ldb_msg_element_compare(&msg1->elements[i],
+ &msg2->elements[i]);
+ if (ret != 0) {
+ return richcmp(ret, op);
+ }
+ }
+
+ return richcmp(0, op);
+}
+
+static PyTypeObject PyLdbMessage = {
+ .tp_name = "ldb.Message",
+ .tp_methods = py_ldb_msg_methods,
+ .tp_getset = py_ldb_msg_getset,
+ .tp_as_sequence = &py_ldb_msg_sequence,
+ .tp_as_mapping = &py_ldb_msg_mapping,
+ .tp_basicsize = sizeof(PyLdbMessageObject),
+ .tp_dealloc = (destructor)py_ldb_msg_dealloc,
+ .tp_new = py_ldb_msg_new,
+ .tp_repr = (reprfunc)py_ldb_msg_repr,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_iter = (getiterfunc)py_ldb_msg_iter,
+ .tp_richcompare = (richcmpfunc)py_ldb_msg_richcmp,
+ .tp_doc = "A LDB Message",
+};
+
+static PyObject *PyLdbTree_FromTree(struct ldb_parse_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldb_parse_tree *tree_ref = NULL;
+ PyLdbTreeObject *ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ tree_ref = talloc_reference(mem_ctx, tree);
+ if (tree_ref == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+
+ ret = (PyLdbTreeObject *)PyLdbTree.tp_alloc(&PyLdbTree, 0);
+ if (ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ret->mem_ctx = mem_ctx;
+ ret->tree = tree_ref;
+ return (PyObject *)ret;
+}
+
+static void py_ldb_tree_dealloc(PyLdbTreeObject *self)
+{
+ talloc_free(self->mem_ctx);
+ PyObject_Del(self);
+}
+
+static PyTypeObject PyLdbTree = {
+ .tp_name = "ldb.Tree",
+ .tp_basicsize = sizeof(PyLdbTreeObject),
+ .tp_dealloc = (destructor)py_ldb_tree_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "A search tree",
+};
+
+/* Ldb_module */
+static int py_module_search(struct ldb_module *mod, struct ldb_request *req)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result, *py_base, *py_attrs, *py_tree;
+
+ py_base = pyldb_Dn_FromDn(req->op.search.base);
+
+ if (py_base == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ py_tree = PyLdbTree_FromTree(req->op.search.tree);
+
+ if (py_tree == NULL) {
+ Py_DECREF(py_base);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (req->op.search.attrs == NULL) {
+ py_attrs = Py_None;
+ } else {
+ int i, len;
+ for (len = 0; req->op.search.attrs[len]; len++);
+ py_attrs = PyList_New(len);
+ if (py_attrs == NULL) {
+ Py_DECREF(py_tree);
+ Py_DECREF(py_base);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ for (i = 0; i < len; i++) {
+ PyObject *py_attr = NULL;
+ int ret;
+
+ py_attr = PyUnicode_FromString(req->op.search.attrs[i]);
+ if (py_attr == NULL) {
+ Py_DECREF(py_tree);
+ Py_DECREF(py_base);
+ Py_DECREF(py_attrs);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = PyList_SetItem(py_attrs, i, py_attr);
+ if (ret) {
+ Py_DECREF(py_attr);
+ Py_DECREF(py_tree);
+ Py_DECREF(py_base);
+ Py_DECREF(py_attrs);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ }
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "search"),
+ discard_const_p(char, "OiOO"),
+ py_base, req->op.search.scope, py_tree, py_attrs);
+
+ Py_DECREF(py_attrs);
+ Py_DECREF(py_tree);
+ Py_DECREF(py_base);
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ req->op.search.res = PyLdbResult_AsResult(NULL, py_result);
+ if (req->op.search.res == NULL) {
+ Py_DECREF(py_result);
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_add(struct ldb_module *mod, struct ldb_request *req)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result, *py_msg;
+
+ py_msg = PyLdbMessage_FromMessage(discard_const_p(struct ldb_message, req->op.add.message));
+
+ if (py_msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "add"),
+ discard_const_p(char, "O"),
+ py_msg);
+
+ Py_DECREF(py_msg);
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_modify(struct ldb_module *mod, struct ldb_request *req)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result, *py_msg;
+
+ py_msg = PyLdbMessage_FromMessage(discard_const_p(struct ldb_message, req->op.mod.message));
+
+ if (py_msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "modify"),
+ discard_const_p(char, "O"),
+ py_msg);
+
+ Py_DECREF(py_msg);
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_del(struct ldb_module *mod, struct ldb_request *req)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result, *py_dn;
+
+ py_dn = pyldb_Dn_FromDn(req->op.del.dn);
+
+ if (py_dn == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "delete"),
+ discard_const_p(char, "O"),
+ py_dn);
+ Py_DECREF(py_dn);
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_rename(struct ldb_module *mod, struct ldb_request *req)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result, *py_olddn, *py_newdn;
+
+ py_olddn = pyldb_Dn_FromDn(req->op.rename.olddn);
+
+ if (py_olddn == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ py_newdn = pyldb_Dn_FromDn(req->op.rename.newdn);
+
+ if (py_newdn == NULL) {
+ Py_DECREF(py_olddn);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "rename"),
+ discard_const_p(char, "OO"),
+ py_olddn, py_newdn);
+
+ Py_DECREF(py_olddn);
+ Py_DECREF(py_newdn);
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_request(struct ldb_module *mod, struct ldb_request *req)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result;
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "request"),
+ discard_const_p(char, ""));
+
+ Py_XDECREF(py_result);
+
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int py_module_extended(struct ldb_module *mod, struct ldb_request *req)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result;
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "extended"),
+ discard_const_p(char, ""));
+
+ Py_XDECREF(py_result);
+
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+static int py_module_start_transaction(struct ldb_module *mod)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result;
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "start_transaction"),
+ discard_const_p(char, ""));
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_end_transaction(struct ldb_module *mod)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result;
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "end_transaction"),
+ discard_const_p(char, ""));
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_del_transaction(struct ldb_module *mod)
+{
+ PyObject *py_ldb = (PyObject *)mod->private_data;
+ PyObject *py_result;
+
+ py_result = PyObject_CallMethod(py_ldb, discard_const_p(char, "del_transaction"),
+ discard_const_p(char, ""));
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ Py_DECREF(py_result);
+
+ return LDB_SUCCESS;
+}
+
+static int py_module_destructor(struct ldb_module *mod)
+{
+ Py_CLEAR(mod->private_data);
+ return 0;
+}
+
+static int py_module_init(struct ldb_module *mod)
+{
+ PyObject *py_class = (PyObject *)mod->ops->private_data;
+ PyObject *py_result, *py_next, *py_ldb;
+
+ py_ldb = PyLdb_FromLdbContext(mod->ldb);
+
+ if (py_ldb == NULL)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ py_next = PyLdbModule_FromModule(mod->next);
+
+ if (py_next == NULL) {
+ Py_DECREF(py_ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ py_result = PyObject_CallFunction(py_class, discard_const_p(char, "OO"),
+ py_ldb, py_next);
+
+ Py_DECREF(py_next);
+ Py_DECREF(py_ldb);
+
+ if (py_result == NULL) {
+ return LDB_ERR_PYTHON_EXCEPTION;
+ }
+
+ mod->private_data = py_result;
+
+ talloc_set_destructor(mod, py_module_destructor);
+
+ return ldb_next_init(mod);
+}
+
+static PyObject *py_register_module(PyObject *module, PyObject *args)
+{
+ int ret;
+ struct ldb_module_ops *ops;
+ PyObject *input;
+ PyObject *tmp = NULL;
+ const char *name = NULL;
+
+ if (!PyArg_ParseTuple(args, "O", &input))
+ return NULL;
+
+ ops = talloc_zero(NULL, struct ldb_module_ops);
+ if (ops == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ tmp = PyObject_GetAttrString(input, discard_const_p(char, "name"));
+ if (tmp == NULL) {
+ TALLOC_FREE(ops);
+ return NULL;
+ }
+ name = PyUnicode_AsUTF8(tmp);
+ if (name == NULL) {
+ Py_DECREF(tmp);
+ TALLOC_FREE(ops);
+ return NULL;
+ }
+
+ ops->name = talloc_strdup(ops, name);
+ Py_XDECREF(tmp);
+ if (ops->name == NULL) {
+ TALLOC_FREE(ops);
+ return PyErr_NoMemory();
+ }
+ Py_INCREF(input);
+ ops->private_data = input;
+ ops->init_context = py_module_init;
+ ops->search = py_module_search;
+ ops->add = py_module_add;
+ ops->modify = py_module_modify;
+ ops->del = py_module_del;
+ ops->rename = py_module_rename;
+ ops->request = py_module_request;
+ ops->extended = py_module_extended;
+ ops->start_transaction = py_module_start_transaction;
+ ops->end_transaction = py_module_end_transaction;
+ ops->del_transaction = py_module_del_transaction;
+
+ ret = ldb_register_module(ops);
+ if (ret != LDB_SUCCESS) {
+ Py_DECREF(input);
+ TALLOC_FREE(ops);
+ }
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, NULL);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_timestring(PyObject *module, PyObject *args)
+{
+ /* most times "time_t" is a signed integer type with 32 or 64 bit:
+ * http://stackoverflow.com/questions/471248/what-is-ultimately-a-time-t-typedef-to */
+ long int t_val;
+ char *tresult;
+ PyObject *ret;
+ if (!PyArg_ParseTuple(args, "l", &t_val))
+ return NULL;
+ tresult = ldb_timestring(NULL, (time_t) t_val);
+ if (tresult == NULL) {
+ /*
+ * Most likely EOVERFLOW from gmtime()
+ */
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+ ret = PyUnicode_FromString(tresult);
+ talloc_free(tresult);
+ return ret;
+}
+
+static PyObject *py_string_to_time(PyObject *module, PyObject *args)
+{
+ char *str;
+ if (!PyArg_ParseTuple(args, "s", &str))
+ return NULL;
+
+ return PyLong_FromLong(ldb_string_to_time(str));
+}
+
+static PyObject *py_valid_attr_name(PyObject *self, PyObject *args)
+{
+ char *name;
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+ return PyBool_FromLong(ldb_valid_attr_name(name));
+}
+
+/*
+ encode a string using RFC2254 rules
+ */
+static PyObject *py_binary_encode(PyObject *self, PyObject *args)
+{
+ char *str, *encoded;
+ Py_ssize_t size = 0;
+ struct ldb_val val;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, "s#", &str, &size))
+ return NULL;
+ val.data = (uint8_t *)str;
+ val.length = size;
+
+ encoded = ldb_binary_encode(NULL, val);
+ if (encoded == NULL) {
+ PyErr_SetString(PyExc_TypeError, "unable to encode binary string");
+ return NULL;
+ }
+ ret = PyUnicode_FromString(encoded);
+ talloc_free(encoded);
+ return ret;
+}
+
+/*
+ decode a string using RFC2254 rules
+ */
+static PyObject *py_binary_decode(PyObject *self, PyObject *args)
+{
+ char *str;
+ struct ldb_val val;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, "s", &str))
+ return NULL;
+
+ val = ldb_binary_decode(NULL, str);
+ if (val.data == NULL) {
+ PyErr_SetString(PyExc_TypeError, "unable to decode binary string");
+ return NULL;
+ }
+ ret = PyBytes_FromStringAndSize((const char*)val.data, val.length);
+ talloc_free(val.data);
+ return ret;
+}
+
+static PyMethodDef py_ldb_global_methods[] = {
+ { "register_module", py_register_module, METH_VARARGS,
+ "S.register_module(module) -> None\n\n"
+ "Register a LDB module."},
+ { "timestring", py_timestring, METH_VARARGS,
+ "S.timestring(int) -> string\n\n"
+ "Generate a LDAP time string from a UNIX timestamp" },
+ { "string_to_time", py_string_to_time, METH_VARARGS,
+ "S.string_to_time(string) -> int\n\n"
+ "Parse a LDAP time string into a UNIX timestamp." },
+ { "valid_attr_name", py_valid_attr_name, METH_VARARGS,
+ "S.valid_attr_name(name) -> bool\n\n"
+ "Check whether the supplied name is a valid attribute name." },
+ { "binary_encode", py_binary_encode, METH_VARARGS,
+ "S.binary_encode(string) -> string\n\n"
+ "Perform a RFC2254 binary encoding on a string" },
+ { "binary_decode", py_binary_decode, METH_VARARGS,
+ "S.binary_decode(string) -> string\n\n"
+ "Perform a RFC2254 binary decode on a string" },
+ {0}
+};
+
+#define MODULE_DOC "An interface to LDB, a LDAP-like API that can either to talk an embedded database (TDB-based) or a standards-compliant LDAP server."
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "ldb",
+ .m_doc = MODULE_DOC,
+ .m_size = -1,
+ .m_methods = py_ldb_global_methods,
+};
+
+static PyObject* module_init(void)
+{
+ PyObject *m;
+
+ PyLdbBytesType.tp_base = &PyBytes_Type;
+ if (PyType_Ready(&PyLdbBytesType) < 0) {
+ return NULL;
+ }
+
+ if (PyType_Ready(&PyLdbDn) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdbMessage) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdbMessageElement) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdb) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdbModule) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdbTree) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdbResult) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdbSearchIterator) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyLdbControl) < 0)
+ return NULL;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+#define ADD_LDB_INT(val) PyModule_AddIntConstant(m, #val, LDB_ ## val)
+
+ ADD_LDB_INT(SEQ_HIGHEST_SEQ);
+ ADD_LDB_INT(SEQ_HIGHEST_TIMESTAMP);
+ ADD_LDB_INT(SEQ_NEXT);
+ ADD_LDB_INT(SCOPE_DEFAULT);
+ ADD_LDB_INT(SCOPE_BASE);
+ ADD_LDB_INT(SCOPE_ONELEVEL);
+ ADD_LDB_INT(SCOPE_SUBTREE);
+
+ ADD_LDB_INT(CHANGETYPE_NONE);
+ ADD_LDB_INT(CHANGETYPE_ADD);
+ ADD_LDB_INT(CHANGETYPE_DELETE);
+ ADD_LDB_INT(CHANGETYPE_MODIFY);
+ ADD_LDB_INT(CHANGETYPE_MODRDN);
+
+ ADD_LDB_INT(FLAG_MOD_ADD);
+ ADD_LDB_INT(FLAG_MOD_REPLACE);
+ ADD_LDB_INT(FLAG_MOD_DELETE);
+ ADD_LDB_INT(FLAG_FORCE_NO_BASE64_LDIF);
+
+ ADD_LDB_INT(ATTR_FLAG_HIDDEN);
+ ADD_LDB_INT(ATTR_FLAG_UNIQUE_INDEX);
+ ADD_LDB_INT(ATTR_FLAG_SINGLE_VALUE);
+ ADD_LDB_INT(ATTR_FLAG_FORCE_BASE64_LDIF);
+
+ ADD_LDB_INT(SUCCESS);
+ ADD_LDB_INT(ERR_OPERATIONS_ERROR);
+ ADD_LDB_INT(ERR_PROTOCOL_ERROR);
+ ADD_LDB_INT(ERR_TIME_LIMIT_EXCEEDED);
+ ADD_LDB_INT(ERR_SIZE_LIMIT_EXCEEDED);
+ ADD_LDB_INT(ERR_COMPARE_FALSE);
+ ADD_LDB_INT(ERR_COMPARE_TRUE);
+ ADD_LDB_INT(ERR_AUTH_METHOD_NOT_SUPPORTED);
+ ADD_LDB_INT(ERR_STRONG_AUTH_REQUIRED);
+ ADD_LDB_INT(ERR_REFERRAL);
+ ADD_LDB_INT(ERR_ADMIN_LIMIT_EXCEEDED);
+ ADD_LDB_INT(ERR_UNSUPPORTED_CRITICAL_EXTENSION);
+ ADD_LDB_INT(ERR_CONFIDENTIALITY_REQUIRED);
+ ADD_LDB_INT(ERR_SASL_BIND_IN_PROGRESS);
+ ADD_LDB_INT(ERR_NO_SUCH_ATTRIBUTE);
+ ADD_LDB_INT(ERR_UNDEFINED_ATTRIBUTE_TYPE);
+ ADD_LDB_INT(ERR_INAPPROPRIATE_MATCHING);
+ ADD_LDB_INT(ERR_CONSTRAINT_VIOLATION);
+ ADD_LDB_INT(ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+ ADD_LDB_INT(ERR_INVALID_ATTRIBUTE_SYNTAX);
+ ADD_LDB_INT(ERR_NO_SUCH_OBJECT);
+ ADD_LDB_INT(ERR_ALIAS_PROBLEM);
+ ADD_LDB_INT(ERR_INVALID_DN_SYNTAX);
+ ADD_LDB_INT(ERR_ALIAS_DEREFERENCING_PROBLEM);
+ ADD_LDB_INT(ERR_INAPPROPRIATE_AUTHENTICATION);
+ ADD_LDB_INT(ERR_INVALID_CREDENTIALS);
+ ADD_LDB_INT(ERR_INSUFFICIENT_ACCESS_RIGHTS);
+ ADD_LDB_INT(ERR_BUSY);
+ ADD_LDB_INT(ERR_UNAVAILABLE);
+ ADD_LDB_INT(ERR_UNWILLING_TO_PERFORM);
+ ADD_LDB_INT(ERR_LOOP_DETECT);
+ ADD_LDB_INT(ERR_NAMING_VIOLATION);
+ ADD_LDB_INT(ERR_OBJECT_CLASS_VIOLATION);
+ ADD_LDB_INT(ERR_NOT_ALLOWED_ON_NON_LEAF);
+ ADD_LDB_INT(ERR_NOT_ALLOWED_ON_RDN);
+ ADD_LDB_INT(ERR_ENTRY_ALREADY_EXISTS);
+ ADD_LDB_INT(ERR_OBJECT_CLASS_MODS_PROHIBITED);
+ ADD_LDB_INT(ERR_AFFECTS_MULTIPLE_DSAS);
+ ADD_LDB_INT(ERR_OTHER);
+
+ ADD_LDB_INT(FLG_RDONLY);
+ ADD_LDB_INT(FLG_NOSYNC);
+ ADD_LDB_INT(FLG_RECONNECT);
+ ADD_LDB_INT(FLG_NOMMAP);
+ ADD_LDB_INT(FLG_SHOW_BINARY);
+ ADD_LDB_INT(FLG_ENABLE_TRACING);
+ ADD_LDB_INT(FLG_DONT_CREATE_DB);
+
+ ADD_LDB_INT(PACKING_FORMAT);
+ ADD_LDB_INT(PACKING_FORMAT_V2);
+
+ /* Historical misspelling */
+ PyModule_AddIntConstant(m, "ERR_ALIAS_DEREFERINCING_PROBLEM", LDB_ERR_ALIAS_DEREFERENCING_PROBLEM);
+
+ PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
+
+ PyExc_LdbError = PyErr_NewException(discard_const_p(char, "_ldb.LdbError"), NULL, NULL);
+ PyModule_AddObject(m, "LdbError", PyExc_LdbError);
+
+ Py_INCREF(&PyLdb);
+ Py_INCREF(&PyLdbDn);
+ Py_INCREF(&PyLdbModule);
+ Py_INCREF(&PyLdbMessage);
+ Py_INCREF(&PyLdbMessageElement);
+ Py_INCREF(&PyLdbTree);
+ Py_INCREF(&PyLdbResult);
+ Py_INCREF(&PyLdbControl);
+
+ PyModule_AddObject(m, "Ldb", (PyObject *)&PyLdb);
+ PyModule_AddObject(m, "Dn", (PyObject *)&PyLdbDn);
+ PyModule_AddObject(m, "Message", (PyObject *)&PyLdbMessage);
+ PyModule_AddObject(m, "MessageElement", (PyObject *)&PyLdbMessageElement);
+ PyModule_AddObject(m, "Module", (PyObject *)&PyLdbModule);
+ PyModule_AddObject(m, "Tree", (PyObject *)&PyLdbTree);
+ PyModule_AddObject(m, "Control", (PyObject *)&PyLdbControl);
+
+ PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
+
+#define ADD_LDB_STRING(val) PyModule_AddStringConstant(m, #val, LDB_## val)
+
+ ADD_LDB_STRING(SYNTAX_DN);
+ ADD_LDB_STRING(SYNTAX_DIRECTORY_STRING);
+ ADD_LDB_STRING(SYNTAX_INTEGER);
+ ADD_LDB_STRING(SYNTAX_ORDERED_INTEGER);
+ ADD_LDB_STRING(SYNTAX_BOOLEAN);
+ ADD_LDB_STRING(SYNTAX_OCTET_STRING);
+ ADD_LDB_STRING(SYNTAX_UTC_TIME);
+ ADD_LDB_STRING(OID_COMPARATOR_AND);
+ ADD_LDB_STRING(OID_COMPARATOR_OR);
+
+ return m;
+}
+
+PyMODINIT_FUNC PyInit_ldb(void);
+PyMODINIT_FUNC PyInit_ldb(void)
+{
+ return module_init();
+}
diff --git a/lib/ldb/pyldb.h b/lib/ldb/pyldb.h
new file mode 100644
index 0000000..2d35442
--- /dev/null
+++ b/lib/ldb/pyldb.h
@@ -0,0 +1,117 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python interface to ldb.
+
+ Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PYLDB_H_
+#define _PYLDB_H_
+
+#include <talloc.h>
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct ldb_context *ldb_ctx;
+} PyLdbObject;
+
+/* pyldb_Ldb_AS_LDBCONTEXT() does not check argument validity,
+ pyldb_Ldb_AsLdbContext() does */
+#define pyldb_Ldb_AS_LDBCONTEXT(pyobj) ((PyLdbObject *)pyobj)->ldb_ctx
+
+#define pyldb_Ldb_AsLdbContext(pyobj) \
+ (pyldb_check_type(pyobj, "Ldb") ? \
+ pyldb_Ldb_AS_LDBCONTEXT(pyobj) : NULL)
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct ldb_dn *dn;
+} PyLdbDnObject;
+
+PyObject *pyldb_Dn_FromDn(struct ldb_dn *);
+bool pyldb_Object_AsDn(TALLOC_CTX *mem_ctx, PyObject *object, struct ldb_context *ldb_ctx, struct ldb_dn **dn);
+#define pyldb_Dn_AS_DN(pyobj) ((PyLdbDnObject *)pyobj)->dn
+
+bool pyldb_check_type(PyObject *obj, const char *type_name);
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct ldb_message *msg;
+} PyLdbMessageObject;
+#define pyldb_Message_AsMessage(pyobj) ((PyLdbMessageObject *)pyobj)->msg
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct ldb_module *mod;
+} PyLdbModuleObject;
+#define pyldb_Module_AsModule(pyobj) ((PyLdbModuleObject *)pyobj)->mod
+
+/*
+ * NOTE: el (and so the return value of
+ * pyldb_MessageElement_AsMessageElement()) may not be a valid talloc
+ * context, it could be part of an array
+ */
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct ldb_message_element *el;
+} PyLdbMessageElementObject;
+
+#define pyldb_MessageElement_AsMessageElement(pyobj) ((PyLdbMessageElementObject *)pyobj)->el
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct ldb_parse_tree *tree;
+} PyLdbTreeObject;
+#define pyldb_Tree_AsTree(pyobj) ((PyLdbTreeObject *)pyobj)->tree
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ PyObject *msgs;
+ PyObject *referals;
+ PyObject *controls;
+} PyLdbResultObject;
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct ldb_control *data;
+} PyLdbControlObject;
+
+#define PyErr_LDB_ERROR_IS_ERR_RAISE(err,ret,ldb) do { \
+ if (ret != LDB_SUCCESS) { \
+ PyErr_SetLdbError(err, ret, ldb); \
+ return NULL; \
+ } \
+} while(0)
+
+/* Picked out of thin air. To do this properly, we should probably have some part of the
+ * errors in LDB be allocated to bindings ? */
+#define LDB_ERR_PYTHON_EXCEPTION 142
+
+#endif /* _PYLDB_H_ */
diff --git a/lib/ldb/pyldb_util.c b/lib/ldb/pyldb_util.c
new file mode 100644
index 0000000..d1c5fad
--- /dev/null
+++ b/lib/ldb/pyldb_util.c
@@ -0,0 +1,185 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python interface to ldb - utility functions.
+
+ Copyright (C) 2007-2010 Jelmer Vernooij <jelmer@samba.org>
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include "ldb.h"
+#include "pyldb.h"
+
+static PyObject *ldb_module = NULL;
+
+/**
+ * Find out PyTypeObject in ldb module for a given typename
+ */
+static PyTypeObject * PyLdb_GetPyType(const char *typename)
+{
+ PyTypeObject *type = NULL;
+ bool ok;
+
+ if (ldb_module == NULL) {
+ ldb_module = PyImport_ImportModule("ldb");
+ if (ldb_module == NULL) {
+ return NULL;
+ }
+ }
+
+ type = (PyTypeObject *)PyObject_GetAttrString(ldb_module, typename);
+
+
+ if (type == NULL) {
+ PyErr_Format(PyExc_NameError,
+ "Unable to find type %s in ldb module",
+ typename);
+ return NULL;
+ }
+
+ ok = PyType_Check(type);
+ if (! ok) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected type ldb.%s, not %s",
+ typename, Py_TYPE(type)->tp_name);
+ Py_DECREF(type);
+ return NULL;
+ }
+
+ return type;
+}
+
+bool pyldb_check_type(PyObject *obj, const char *typename)
+{
+ bool ok = false;
+ PyTypeObject *type = PyLdb_GetPyType(typename);
+ if (type != NULL) {
+ ok = PyObject_TypeCheck(obj, type);
+ Py_DECREF(type);
+ }
+ return ok;
+}
+
+/**
+ * Obtain a ldb DN from a Python object.
+ *
+ * @param mem_ctx Memory context
+ * @param object Python object
+ * @param ldb_ctx LDB context
+ * @return Whether or not the conversion succeeded
+ */
+bool pyldb_Object_AsDn(TALLOC_CTX *mem_ctx, PyObject *object,
+ struct ldb_context *ldb_ctx, struct ldb_dn **dn)
+{
+ struct ldb_dn *odn;
+ PyTypeObject *PyLdb_Dn_Type;
+ bool is_dn;
+
+ if (ldb_ctx != NULL && (PyUnicode_Check(object))) {
+ const char *odn_str = NULL;
+
+ odn_str = PyUnicode_AsUTF8(object);
+ if (odn_str == NULL) {
+ return false;
+ }
+
+ odn = ldb_dn_new(mem_ctx, ldb_ctx, odn_str);
+ if (odn == NULL) {
+ PyErr_NoMemory();
+ return false;
+ }
+
+ *dn = odn;
+ return true;
+ }
+
+ if (ldb_ctx != NULL && PyBytes_Check(object)) {
+ const char *odn_str = NULL;
+
+ odn_str = PyBytes_AsString(object);
+ if (odn_str == NULL) {
+ return false;
+ }
+
+ odn = ldb_dn_new(mem_ctx, ldb_ctx, odn_str);
+ if (odn == NULL) {
+ PyErr_NoMemory();
+ return false;
+ }
+
+ *dn = odn;
+ return true;
+ }
+
+ PyLdb_Dn_Type = PyLdb_GetPyType("Dn");
+ if (PyLdb_Dn_Type == NULL) {
+ return false;
+ }
+
+ is_dn = PyObject_TypeCheck(object, PyLdb_Dn_Type);
+ Py_DECREF(PyLdb_Dn_Type);
+ if (is_dn) {
+ *dn = pyldb_Dn_AS_DN(object);
+ return true;
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Expected DN");
+ return false;
+}
+
+PyObject *pyldb_Dn_FromDn(struct ldb_dn *dn)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldb_dn *dn_ref = NULL;
+ PyLdbDnObject *py_ret;
+ PyTypeObject *PyLdb_Dn_Type;
+
+ if (dn == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ dn_ref = talloc_reference(mem_ctx, dn);
+ if (dn_ref == NULL) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
+
+ PyLdb_Dn_Type = PyLdb_GetPyType("Dn");
+ if (PyLdb_Dn_Type == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ py_ret = (PyLdbDnObject *)PyLdb_Dn_Type->tp_alloc(PyLdb_Dn_Type, 0);
+ Py_DECREF(PyLdb_Dn_Type);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->dn = dn;
+ return (PyObject *)py_ret;
+}
diff --git a/lib/ldb/tests/guidindexpackv1.ldb b/lib/ldb/tests/guidindexpackv1.ldb
new file mode 100644
index 0000000..96d783c
--- /dev/null
+++ b/lib/ldb/tests/guidindexpackv1.ldb
Binary files differ
diff --git a/lib/ldb/tests/init.ldif b/lib/ldb/tests/init.ldif
new file mode 100644
index 0000000..97b4561
--- /dev/null
+++ b/lib/ldb/tests/init.ldif
@@ -0,0 +1,41 @@
+dn: o=University of Michigan,c=TEST
+objectclass: organization
+objectclass: domainRelatedObject
+l: Ann Arbor, Michigan
+st: Michigan
+o: University of Michigan
+o: UMICH
+o: UM
+o: U-M
+o: U of M
+description: The University of Michigan at Ann Arbor
+postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
+ 09 $ US
+telephonenumber: +1 313 764-1817
+associateddomain: example.com
+
+# there was an empty "seeAlso" here
+
+dn: ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: People
+uidNumber: 0
+gidNumber: 0
+
+dn: ou=Ldb Test,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: People
+ou: Ldb Test
+uidNumber: 0
+gidNumber: 0
+
+dn: ou=LdbTspace,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: People
+ou: LdbTspace
+description: test white space removal in comparisons
+uidNumber: 0
+gidNumber: 0
diff --git a/lib/ldb/tests/init_slapd.sh b/lib/ldb/tests/init_slapd.sh
new file mode 100755
index 0000000..4629cf1
--- /dev/null
+++ b/lib/ldb/tests/init_slapd.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=$(dirname $0)/..
+ export LDBDIR
+fi
+
+rm -rf tests/tmp/db
+mkdir -p tests/tmp/db
+
+if [ -f tests/tmp/slapd.pid ]; then
+ kill $(cat tests/tmp/slapd.pid)
+ sleep 1
+fi
+if [ -f tests/tmp/slapd.pid ]; then
+ kill -9 $(cat tests/tmp/slapd.pid)
+ rm -f tests/tmp/slapd.pid
+fi
+
+# we don't consider a slapadd failure as a test suite failure, as it
+# has nothing to do with ldb
+
+MODCONF=tests/tmp/modules.conf
+rm -f $MODCONF
+touch $MODCONF || exit 1
+
+slaptest -u -f $LDBDIR/tests/slapd.conf >/dev/null 2>&1 || {
+ echo "enabling sladp modules"
+ cat >$MODCONF <<EOF
+modulepath /usr/lib/ldap
+moduleload back_bdb
+EOF
+}
+
+slaptest -u -f $LDBDIR/tests/slapd.conf || {
+ echo "slaptest failed - skipping ldap tests"
+ exit 0
+}
+
+slapadd -f $LDBDIR/tests/slapd.conf <$LDBDIR/tests/init.ldif || exit 0
diff --git a/lib/ldb/tests/kill_slapd.sh b/lib/ldb/tests/kill_slapd.sh
new file mode 100755
index 0000000..c60ae33
--- /dev/null
+++ b/lib/ldb/tests/kill_slapd.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=$(dirname $0)/..
+ export LDBDIR
+fi
+
+if [ -f tests/tmp/slapd.pid ]; then
+ echo "killing slapd process $(cat tests/tmp/slapd.pid)"
+ kill -9 $(cat tests/tmp/slapd.pid)
+ rm -f tests/tmp/slapd.pid
+fi
diff --git a/lib/ldb/tests/ldapi_url.sh b/lib/ldb/tests/ldapi_url.sh
new file mode 100755
index 0000000..bcda917
--- /dev/null
+++ b/lib/ldb/tests/ldapi_url.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# aargh, did LDAP ever have to expose this crap to users ...
+
+BASE=$(pwd)
+
+TMPDIR=$BASE/tests/tmp
+
+LDAPI_ESCAPE=$(echo $TMPDIR/ldapi | sed 's|/|%2F|g')
+
+echo "ldapi://$LDAPI_ESCAPE"
diff --git a/lib/ldb/tests/ldb_filter_attrs_in_place_test.c b/lib/ldb/tests/ldb_filter_attrs_in_place_test.c
new file mode 100644
index 0000000..bf37016
--- /dev/null
+++ b/lib/ldb/tests/ldb_filter_attrs_in_place_test.c
@@ -0,0 +1,940 @@
+/*
+ * Tests exercising ldb_filter_attrs_in_place().
+ *
+ *
+ * Copyright (C) Catalyst.NET Ltd 2017
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "../include/ldb.h"
+#include "../include/ldb_module.h"
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+};
+
+/*
+ * NOTE WELL:
+ *
+ * This test checks the current behaviour of the function, however
+ * this is not in a public ABI and many of the tested behaviours are
+ * not ideal. If the behaviour is deliberately improved, this test
+ * should be updated without worry to the new better behaviour.
+ *
+ * In particular the test is particularly to ensure the current
+ * behaviour is memory-safe.
+ */
+
+static int setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ talloc_free(*state);
+ return 0;
+}
+
+static void msg_add_dn(struct ldb_message *msg)
+{
+ const char *dn_attr = "distinguishedName";
+ char *dn = NULL;
+ int ret;
+
+ assert_null(ldb_msg_find_element(msg, dn_attr));
+
+ assert_non_null(msg->dn);
+ dn = ldb_dn_alloc_linearized(msg, msg->dn);
+ assert_non_null(dn);
+
+ /*
+ * The message's elements must be talloc allocated to call
+ * ldb_msg_add_steal_string().
+ */
+ msg->elements = talloc_memdup(msg,
+ msg->elements,
+ msg->num_elements * sizeof(msg->elements[0]));
+ assert_non_null(msg->elements);
+
+ ret = ldb_msg_add_steal_string(msg, dn_attr, dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+}
+
+/*
+ * Test against a record with only one attribute, matching the one in
+ * the list
+ */
+static void test_filter_attrs_in_place_one_attr_matched(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"foo", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 1;
+ msg->elements = &element_1;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_non_null(msg->dn);
+ assert_int_equal(msg->num_elements, 1);
+ assert_string_equal(msg->elements[0].name, "foo");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value, strlen(value));
+}
+
+/*
+ * Test against a record with only one attribute, matching the one of
+ * the multiple attributes in the list
+ */
+static void test_filter_attrs_in_place_one_attr_matched_of_many(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"foo", "bar", "baz", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 1;
+ msg->elements = &element_1;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_non_null(msg->dn);
+ assert_int_equal(msg->num_elements, 1);
+ assert_string_equal(msg->elements[0].name, "foo");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value, strlen(value));
+}
+
+/*
+ * Test against a record with only one attribute, matching both
+ * attributes in the list
+ */
+static void test_filter_attrs_in_place_two_attr_matched_attrs(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ /* deliberately the other order */
+ const char *attrs[] = {"bar", "foo", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ /* foo and bar are the other order to in attrs */
+ struct ldb_message_element elements[] = {
+ {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 2;
+ msg->elements = elements;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 2);
+
+ assert_non_null(msg->dn);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(msg->elements[0].name, "foo");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(msg->elements[1].name, "bar");
+ assert_int_equal(msg->elements[1].num_values, 1);
+ assert_int_equal(msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(msg->elements[1].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes, only of which is in
+ * the list
+ */
+static void test_filter_attrs_in_place_two_attr_matched_one_attr(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"bar", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ struct ldb_message_element elements[] = {
+ {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 2;
+ msg->elements = elements;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 1);
+
+ assert_non_null(msg->dn);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(msg->elements[0].name, "bar");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value2));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes, both matching the one
+ * specified attribute in the list (a corrupt record)
+ */
+static void test_filter_attrs_in_place_two_dup_attr_matched_one_attr(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"bar", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 2;
+ msg->elements = elements;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+
+ /* Both elements match the filter */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 2);
+
+ assert_non_null(msg->dn);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(msg->elements[0].name, "bar");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value1, strlen(value1));
+
+ assert_string_equal(msg->elements[1].name, "bar");
+ assert_int_equal(msg->elements[1].num_values, 1);
+ assert_int_equal(msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(msg->elements[1].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes, both matching the one
+ * specified attribute in the list (a corrupt record)
+ */
+static void test_filter_attrs_in_place_two_dup_attr_matched_dup(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"bar", "bar", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 2;
+ msg->elements = elements;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+
+ /* This does not fail the pidgenhole test */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 2);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(msg->elements[0].name, "bar");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(msg->elements[1].name, "bar");
+ assert_int_equal(msg->elements[1].num_values, 1);
+ assert_int_equal(msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(msg->elements[1].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes, both matching one of the
+ * specified attributes in the list (a corrupt record)
+ */
+static void test_filter_attrs_in_place_two_dup_attr_matched_one_of_two(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"bar", "foo", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 2;
+ msg->elements = elements;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+
+ /* This does not fail the pidgenhole test */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 2);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(msg->elements[0].name, "bar");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(msg->elements[1].name, "bar");
+ assert_int_equal(msg->elements[1].num_values, 1);
+ assert_int_equal(msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(msg->elements[1].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes against * (but not the
+ * other named attribute) (a corrupt record)
+ */
+static void test_filter_attrs_in_place_two_dup_attr_matched_star(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", "foo", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 2;
+ msg->elements = elements;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+
+ /* This does not fail the pidgenhole test */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 3);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(msg->elements[0].name, "bar");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_int_equal(msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(msg->elements[1].name, "bar");
+ assert_int_equal(msg->elements[1].num_values, 1);
+ assert_int_equal(msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(msg->elements[1].values[0].data,
+ value2, strlen(value2));
+
+ assert_non_null(msg->dn);
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(msg->dn));
+}
+
+/*
+ * Test against a record with only one attribute, matching the * in
+ * the list
+ */
+static void test_filter_attrs_in_place_one_attr_matched_star(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 1;
+ msg->elements = &element_1;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 2);
+
+ assert_non_null(msg->dn);
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(msg->dn));
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "foo",
+ NULL),
+ value);
+}
+
+/*
+ * Test against a record with two attributes, matching the * in
+ * the list
+ */
+static void test_filter_attrs_in_place_two_attr_matched_star(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+ struct ldb_message_element elements[] = {
+ {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 2;
+ msg->elements = elements;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 3);
+
+ assert_non_null(msg->dn);
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(msg->dn));
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "foo",
+ NULL),
+ value1);
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "bar",
+ NULL),
+ value2);
+}
+
+/*
+ * Test against a record with only one attribute, matching the * in
+ * the list, but without the DN being pre-filled. Succeeds, but the
+ * distinguishedName is not added.
+ */
+static void test_filter_attrs_in_place_one_attr_matched_star_no_dn(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+
+ assert_non_null(msg);
+ msg->dn = NULL;
+ msg->num_elements = 1;
+ msg->elements = &element_1;
+
+ assert_null(msg->dn);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 1);
+}
+
+/*
+ * Test against a record with only one attribute, matching the * in
+ * the list plus requsesting distinguishedName
+ */
+static void test_filter_attrs_in_place_one_attr_matched_star_dn(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", "distinguishedName", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 1;
+ msg->elements = &element_1;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 2);
+
+ assert_non_null(msg->dn);
+
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(msg->dn));
+ assert_string_equal(ldb_msg_find_attr_as_string(msg,
+ "foo",
+ NULL),
+ value);
+}
+
+/*
+ * Test against a record with only one attribute, but returning
+ * distinguishedName from the list (only)
+ */
+static void test_filter_attrs_in_place_one_attr_matched_dn(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"distinguishedName", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 1;
+ msg->elements = &element_1;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 1);
+
+ assert_non_null(msg->dn);
+ assert_string_equal(msg->elements[0].name, "distinguishedName");
+ assert_int_equal(msg->elements[0].num_values, 1);
+ assert_string_equal((char *)msg->elements[0].values[0].data,
+ ldb_dn_get_linearized(msg->dn));
+}
+
+/*
+ * Test against a record with only one attribute, not matching the
+ * empty attribute list
+ */
+static void test_filter_attrs_in_place_one_attr_empty_list(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+
+ assert_non_null(msg);
+ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org");
+ msg->num_elements = 1;
+ msg->elements = &element_1;
+
+ assert_non_null(msg->dn);
+ msg_add_dn(msg);
+
+ ret = ldb_filter_attrs_in_place(msg, attrs);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, 0);
+ assert_non_null(msg->dn);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_one_attr_matched,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_one_attr_matched_of_many,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_two_attr_matched_attrs,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_two_attr_matched_one_attr,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_two_dup_attr_matched_one_attr,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_two_dup_attr_matched_dup,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_two_dup_attr_matched_one_of_two,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_two_dup_attr_matched_star,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_one_attr_matched_star,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_two_attr_matched_star,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_one_attr_matched_star_no_dn,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_one_attr_matched_star_dn,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_one_attr_matched_dn,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_in_place_one_attr_empty_list,
+ setup,
+ teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_filter_attrs_test.c b/lib/ldb/tests/ldb_filter_attrs_test.c
new file mode 100644
index 0000000..291350a
--- /dev/null
+++ b/lib/ldb/tests/ldb_filter_attrs_test.c
@@ -0,0 +1,989 @@
+/*
+ * Tests exercising the ldb_filter_attrs().
+ *
+ *
+ * Copyright (C) Catalyst.NET Ltd 2017
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "../include/ldb.h"
+#include "../include/ldb_module.h"
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+};
+
+/*
+ * NOTE WELL:
+ *
+ * This test checks the current behaviour of the function, however
+ * this is not in a public ABI and many of the tested behaviours are
+ * not ideal. If the behaviour is deliberately improved, this test
+ * should be updated without worry to the new better behaviour.
+ *
+ * In particular the test is particularly to ensure the current
+ * behaviour is memory-safe.
+ */
+
+static int setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ talloc_free(*state);
+ return 0;
+}
+
+
+/*
+ * Test against a record with only one attribute, matching the one in
+ * the list
+ */
+static void test_filter_attrs_one_attr_matched(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"foo", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 1,
+ .elements = &element_1,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+
+ /*
+ * assert the ldb_filter_attrs does not read or modify
+ * filtered_msg.dn in this case
+ */
+ assert_null(filtered_msg->dn);
+ assert_int_equal(filtered_msg->num_elements, 1);
+ assert_string_equal(filtered_msg->elements[0].name, "foo");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_int_equal(filtered_msg->elements[0].values[0].length,
+ strlen(value));
+ assert_memory_equal(filtered_msg->elements[0].values[0].data,
+ value, strlen(value));
+}
+
+/*
+ * Test against a record with only one attribute, matching the one of
+ * the multiple attributes in the list
+ */
+static void test_filter_attrs_one_attr_matched_of_many(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"foo", "bar", "baz", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 1,
+ .elements = &element_1,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+
+ /*
+ * assert the ldb_filter_attrs does not read or modify
+ * filtered_msg.dn in this case
+ */
+ assert_null(filtered_msg->dn);
+ assert_int_equal(filtered_msg->num_elements, 1);
+ assert_string_equal(filtered_msg->elements[0].name, "foo");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_int_equal(filtered_msg->elements[0].values[0].length,
+ strlen(value));
+ assert_memory_equal(filtered_msg->elements[0].values[0].data,
+ value, strlen(value));
+}
+
+/*
+ * Test against a record with only one attribute, matching both
+ * attributes in the list
+ */
+static void test_filter_attrs_two_attr_matched_attrs(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ /* deliberately the other order */
+ const char *attrs[] = {"bar", "foo", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ /* foo and bar are the other order to in attrs */
+ struct ldb_message_element elements[] = {
+ {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 2,
+ .elements = elements,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+ assert_int_equal(filtered_msg->num_elements, 2);
+
+ /*
+ * assert the ldb_filter_attrs does not read or modify
+ * filtered_msg.dn in this case
+ */
+ assert_null(filtered_msg->dn);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(filtered_msg->elements[0].name, "foo");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_int_equal(filtered_msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(filtered_msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(filtered_msg->elements[1].name, "bar");
+ assert_int_equal(filtered_msg->elements[1].num_values, 1);
+ assert_int_equal(filtered_msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(filtered_msg->elements[1].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes, only of which is in
+ * the list
+ */
+static void test_filter_attrs_two_attr_matched_one_attr(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ /* deliberately the other order */
+ const char *attrs[] = {"bar", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ /* foo and bar are the other order to in attrs */
+ struct ldb_message_element elements[] = {
+ {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 2,
+ .elements = elements,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+ assert_int_equal(filtered_msg->num_elements, 1);
+
+ /*
+ * assert the ldb_filter_attrs does not read or modify
+ * filtered_msg.dn in this case
+ */
+ assert_null(filtered_msg->dn);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(filtered_msg->elements[0].name, "bar");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_int_equal(filtered_msg->elements[0].values[0].length,
+ strlen(value2));
+ assert_memory_equal(filtered_msg->elements[0].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes, both matching the one
+ * specified attribute in the list (a corrupt record)
+ */
+static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ /* deliberately the other order */
+ const char *attrs[] = {"bar", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ /* foo and bar are the other order to in attrs */
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 2,
+ .elements = elements,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+
+ /* This should fail the pidgenhole test */
+ assert_int_equal(ret, -1);
+ assert_null(filtered_msg->elements);
+}
+
+/*
+ * Test against a record with two attributes, both matching the one
+ * specified attribute in the list (a corrupt record)
+ */
+static void test_filter_attrs_two_dup_attr_matched_dup(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"bar", "bar", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ /* foo and bar are the other order to in attrs */
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 2,
+ .elements = elements,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+
+ /* This does not fail the pidgenhole test */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(filtered_msg->num_elements, 2);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(filtered_msg->elements[0].name, "bar");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_int_equal(filtered_msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(filtered_msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(filtered_msg->elements[1].name, "bar");
+ assert_int_equal(filtered_msg->elements[1].num_values, 1);
+ assert_int_equal(filtered_msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(filtered_msg->elements[1].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes, both matching one of the
+ * specified attributes in the list (a corrupt record)
+ */
+static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"bar", "foo", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ /* foo and bar are the other order to in attrs */
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 2,
+ .elements = elements,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+
+ /* This does not fail the pidgenhole test */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(filtered_msg->num_elements, 2);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(filtered_msg->elements[0].name, "bar");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_int_equal(filtered_msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(filtered_msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(filtered_msg->elements[1].name, "bar");
+ assert_int_equal(filtered_msg->elements[1].num_values, 1);
+ assert_int_equal(filtered_msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(filtered_msg->elements[1].values[0].data,
+ value2, strlen(value2));
+}
+
+/*
+ * Test against a record with two attributes against * (but not the
+ * other named attribute) (a corrupt record)
+ */
+static void test_filter_attrs_two_dup_attr_matched_star(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", "foo", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+
+ /* foo and bar are the other order to in attrs */
+ struct ldb_message_element elements[] = {
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 2,
+ .elements = elements,
+ };
+
+ assert_non_null(in.dn);
+
+ /* Needed as * implies distinguishedName */
+ filtered_msg->dn = in.dn;
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+
+ /* This does not fail the pidgenhole test */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(filtered_msg->num_elements, 3);
+
+ /* Assert that DB order is preserved */
+ assert_string_equal(filtered_msg->elements[0].name, "bar");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_int_equal(filtered_msg->elements[0].values[0].length,
+ strlen(value1));
+ assert_memory_equal(filtered_msg->elements[0].values[0].data,
+ value1, strlen(value1));
+ assert_string_equal(filtered_msg->elements[1].name, "bar");
+ assert_int_equal(filtered_msg->elements[1].num_values, 1);
+ assert_int_equal(filtered_msg->elements[1].values[0].length,
+ strlen(value2));
+ assert_memory_equal(filtered_msg->elements[1].values[0].data,
+ value2, strlen(value2));
+ /*
+ * assert the ldb_filter_attrs does not modify filtered_msg.dn
+ * in this case
+ */
+ assert_ptr_equal(filtered_msg->dn, in.dn);
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(in.dn));
+}
+
+/*
+ * Test against a record with only one attribute, matching the * in
+ * the list
+ */
+static void test_filter_attrs_one_attr_matched_star(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 1,
+ .elements = &element_1,
+ };
+
+ assert_non_null(in.dn);
+
+ /* Needed as * implies distinguishedName */
+ filtered_msg->dn = in.dn;
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+ assert_int_equal(filtered_msg->num_elements, 2);
+
+ /*
+ * assert the ldb_filter_attrs does not modify filtered_msg.dn
+ * in this case
+ */
+ assert_ptr_equal(filtered_msg->dn, in.dn);
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(in.dn));
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "foo",
+ NULL),
+ (const char *)value);
+}
+
+/*
+ * Test against a record with two attributes, matching the * in
+ * the list
+ */
+static void test_filter_attrs_two_attr_matched_star(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", NULL};
+
+ char value1[] = "The value.......end";
+ char value2[] = "The value..MUST.end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value1,
+ .length = strlen(value1)
+ };
+ struct ldb_val value_2 = {
+ .data = (uint8_t *)value2,
+ .length = strlen(value2)
+ };
+ struct ldb_message_element elements[] = {
+ {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ },
+ {
+ .name = "bar",
+ .num_values = 1,
+ .values = &value_2
+ }
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 2,
+ .elements = elements,
+ };
+
+ assert_non_null(in.dn);
+
+ /* Needed as * implies distinguishedName */
+ filtered_msg->dn = in.dn;
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+ assert_int_equal(filtered_msg->num_elements, 3);
+
+ /*
+ * assert the ldb_filter_attrs does not modify filtered_msg.dn
+ * in this case
+ */
+ assert_ptr_equal(filtered_msg->dn, in.dn);
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(in.dn));
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "foo",
+ NULL),
+ (const char *)value1);
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "bar",
+ NULL),
+ (const char *)value2);
+}
+
+/*
+ * Test against a record with only one attribute, matching the * in
+ * the list, but without the DN being pre-filled. Fails due to need
+ * to construct the distinguishedName
+ */
+static void test_filter_attrs_one_attr_matched_star_no_dn(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 1,
+ .elements = &element_1,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, -1);
+ assert_null(filtered_msg->elements);
+}
+
+/*
+ * Test against a record with only one attribute, matching the * in
+ * the list plus requsesting distinguishedName
+ */
+static void test_filter_attrs_one_attr_matched_star_dn(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"*", "distinguishedName", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 1,
+ .elements = &element_1,
+ };
+
+ assert_non_null(in.dn);
+
+ /* Needed for distinguishedName */
+ filtered_msg->dn = in.dn;
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+ assert_int_equal(filtered_msg->num_elements, 2);
+
+ /* show that ldb_filter_attrs does not modify in.dn */
+ assert_ptr_equal(filtered_msg->dn, in.dn);
+
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "distinguishedName",
+ NULL),
+ ldb_dn_get_linearized(in.dn));
+ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg,
+ "foo",
+ NULL),
+ (const char *)value);
+}
+
+/*
+ * Test against a record with only one attribute, but returning
+ * distinguishedName from the list (only)
+ */
+static void test_filter_attrs_one_attr_matched_dn(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {"distinguishedName", NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 1,
+ .elements = &element_1,
+ };
+
+ assert_non_null(in.dn);
+
+ /* Needed for distinguishedName */
+ filtered_msg->dn = in.dn;
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+ assert_int_equal(filtered_msg->num_elements, 1);
+
+ /* show that ldb_filter_attrs does not modify in.dn */
+ assert_ptr_equal(filtered_msg->dn, in.dn);
+ assert_string_equal(filtered_msg->elements[0].name, "distinguishedName");
+ assert_int_equal(filtered_msg->elements[0].num_values, 1);
+ assert_string_equal((const char *)filtered_msg->elements[0].values[0].data,
+ ldb_dn_get_linearized(in.dn));
+}
+
+/*
+ * Test against a record with only one attribute, not matching the
+ * empty attribute list
+ */
+static void test_filter_attrs_one_attr_empty_list(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ int ret;
+
+ struct ldb_message *filtered_msg = ldb_msg_new(ctx);
+
+ const char *attrs[] = {NULL};
+
+ char value[] = "The value.......end";
+ struct ldb_val value_1 = {
+ .data = (uint8_t *)value,
+ .length = strlen(value)
+ };
+ struct ldb_message_element element_1 = {
+ .name = "foo",
+ .num_values = 1,
+ .values = &value_1
+ };
+ struct ldb_message in = {
+ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"),
+ .num_elements = 1,
+ .elements = &element_1,
+ };
+
+ assert_non_null(in.dn);
+
+ ret = ldb_filter_attrs(ctx->ldb,
+ &in,
+ attrs,
+ filtered_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(filtered_msg);
+ assert_int_equal(filtered_msg->num_elements, 0);
+ assert_null(filtered_msg->dn);
+ assert_null(filtered_msg->elements);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_one_attr_matched,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_one_attr_matched_of_many,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_two_attr_matched_attrs,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_two_attr_matched_one_attr,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_two_dup_attr_matched_one_attr,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_two_dup_attr_matched_dup,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_two_dup_attr_matched_one_of_two,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_two_dup_attr_matched_star,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_one_attr_matched_star,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_two_attr_matched_star,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_one_attr_matched_star_no_dn,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_one_attr_matched_star_dn,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_one_attr_matched_dn,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_filter_attrs_one_attr_empty_list,
+ setup,
+ teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_key_value_sub_txn_mdb_test.valgrind b/lib/ldb/tests/ldb_key_value_sub_txn_mdb_test.valgrind
new file mode 100644
index 0000000..1747076
--- /dev/null
+++ b/lib/ldb/tests/ldb_key_value_sub_txn_mdb_test.valgrind
@@ -0,0 +1,97 @@
+{
+ Memory allocated by setup
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:setup
+}
+{
+ Memory allocated by setup
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:realloc
+ ...
+ fun:setup
+}
+{
+ Memory allocated by ldb_init
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_init
+}
+{
+ Memory allocated by ldb_init
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:realloc
+ ...
+ fun:ldb_init
+}
+{
+ Memory allocated by noconn_setup
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:noconn_setup
+}
+{
+ Memory allocated by parse, which allocates on the NULL context
+ Memcheck:Leak
+ match-leak-kinds: all
+ fun:malloc
+ ...
+ fun:parse
+}
+{
+ Memory allocated by tdb_parse_data
+ Memcheck:Leak
+ match-leak-kinds: all
+ fun:malloc
+ ...
+ fun:tdb_parse_data
+}
+{
+ Memory allocated by ldb_connect
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_connect
+}
+{
+ Memory allocated by ldb_connect
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:calloc
+ ...
+ fun:ldb_connect
+}
+{
+ Memory allocated by ldb_kv_cache_load
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_kv_cache_load
+}
+{
+ Memory allocated by ldb_kv_index_load
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_kv_index_load
+}
+{
+ Memory allocated by ldb_asprintf_errstring
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_asprintf_errstring
+}
+
diff --git a/lib/ldb/tests/ldb_key_value_sub_txn_test.c b/lib/ldb/tests/ldb_key_value_sub_txn_test.c
new file mode 100644
index 0000000..1eafd2d
--- /dev/null
+++ b/lib/ldb/tests/ldb_key_value_sub_txn_test.c
@@ -0,0 +1,844 @@
+/*
+ * Tests exercising the ldb key value operations.
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+/*
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <limits.h>
+#define NO_FAILURE INT_MAX
+#define FAILURE_LDB_ERR LDB_ERR_OTHER
+
+/*
+ * To test failure in ldb_kv_add, ldb_kv_delete, ldb_kv_modify and ldb_kv_rename
+ * we use the following global variables and macros to trigger a failure in
+ * the ldb_kv_<op>_internal functions. This allows testing of the sub
+ * transaction commits and roll backs in those operations.
+ *
+ * NOTE: Not all back ends support nested/sub transactions
+ */
+int cmocka_unit_test_fail_add_internal_after = NO_FAILURE;
+#define CMOCKA_UNIT_TEST_ADD_INTERNAL_FAIL \
+ {\
+ cmocka_unit_test_fail_add_internal_after--;\
+ if (cmocka_unit_test_fail_add_internal_after <= 0) {\
+ assert_int_equal(LDB_SUCCESS, ret);\
+ ret = FAILURE_LDB_ERR;\
+ }\
+ }\
+
+int cmocka_unit_test_fail_delete_internal_after = NO_FAILURE;
+#define CMOCKA_UNIT_TEST_DELETE_INTERNAL_FAIL \
+ {\
+ cmocka_unit_test_fail_delete_internal_after--;\
+ if (cmocka_unit_test_fail_delete_internal_after <= 0) {\
+ assert_int_equal(LDB_SUCCESS, ret);\
+ ret = FAILURE_LDB_ERR;\
+ }\
+ }\
+
+int cmocka_unit_test_fail_rename_internal_after = NO_FAILURE;
+#define CMOCKA_UNIT_TEST_RENAME_INTERNAL_FAIL \
+ {\
+ cmocka_unit_test_fail_rename_internal_after--;\
+ if (cmocka_unit_test_fail_rename_internal_after <= 0) {\
+ assert_int_equal(LDB_SUCCESS, ret);\
+ ret = FAILURE_LDB_ERR;\
+ }\
+ }\
+
+int cmocka_unit_test_fail_modify_internal_after = NO_FAILURE;
+#define CMOCKA_UNIT_TEST_MODIFY_INTERNAL_FAIL \
+ {\
+ cmocka_unit_test_fail_modify_internal_after--;\
+ if (cmocka_unit_test_fail_modify_internal_after <= 0) {\
+ assert_int_equal(LDB_SUCCESS, ret);\
+ ret = FAILURE_LDB_ERR;\
+ }\
+ }\
+
+#include "ldb_key_value/ldb_kv.c"
+
+
+#define DEFAULT_BE "tdb"
+
+#ifndef TEST_BE
+#define TEST_BE DEFAULT_BE
+#endif /* TEST_BE */
+
+#define NUM_RECS 1024
+
+
+struct test_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+};
+
+/*
+ * Remove the database files
+ */
+static void unlink_old_db(struct test_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+/*
+ * Test setup
+ */
+static int noconn_setup(void **state)
+{
+ struct test_ctx *test_ctx;
+ cmocka_unit_test_fail_add_internal_after = NO_FAILURE;
+ cmocka_unit_test_fail_delete_internal_after = NO_FAILURE;
+ cmocka_unit_test_fail_rename_internal_after = NO_FAILURE;
+ cmocka_unit_test_fail_modify_internal_after = NO_FAILURE;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "kvopstest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+/*
+ * Test teardown
+ */
+static int noconn_teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+/*
+ * Test setup
+ */
+static int setup(void **state)
+{
+ struct test_ctx *test_ctx;
+ int ret;
+ struct ldb_ldif *ldif;
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+
+ noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ *state = test_ctx;
+ return 0;
+}
+
+/*
+ * Test teardown
+ */
+static int teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+/*
+ * Build an ldb_kv_context that can be passed to the ldb_kv operation under test
+ */
+static struct ldb_kv_context* build_ldb_kv_context(
+ TALLOC_CTX *ctx,
+ struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct ldb_kv_context *ldb_kv_ctx = NULL;
+
+ ldb_kv_ctx = talloc_zero(ctx, struct ldb_kv_context);
+ assert_non_null(ldb_kv_ctx);
+
+ ldb_kv_ctx->module = module;
+ ldb_kv_ctx->req = req;
+
+ return ldb_kv_ctx;
+}
+
+/*
+ * Build an add request
+ */
+static struct ldb_request *build_add_request(
+ TALLOC_CTX *ctx,
+ struct ldb_context *ldb,
+ const char* dc,
+ const char* uuid,
+ const char* cn)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldb_request *req;
+
+ msg = ldb_msg_new(ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, ldb, "dc=%s", dc);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", cn);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", uuid);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_sanity_check(ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_build_add_req(
+ &req, ldb, ldb, msg, NULL, NULL, ldb_op_default_callback, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ return req;
+}
+
+/*
+ * Build a delete request
+ */
+static struct ldb_request *build_delete_request(
+ TALLOC_CTX *ctx,
+ struct ldb_context *ldb,
+ const char* dc)
+{
+ int ret = LDB_SUCCESS;
+ struct ldb_dn *dn = NULL;
+ struct ldb_request *req = NULL;
+
+ dn = ldb_dn_new_fmt(ctx, ldb, "dc=%s", dc);
+ assert_non_null(dn);
+
+ ret = ldb_build_del_req(
+ &req, ldb, ctx, dn, NULL, NULL, ldb_op_default_callback, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ return req;
+}
+
+/*
+ * Build a rename request
+ */
+static struct ldb_request *build_rename_request(
+ TALLOC_CTX *ctx,
+ struct ldb_context *ldb,
+ const char* old_dc,
+ const char* new_dc)
+{
+ int ret = LDB_SUCCESS;
+ struct ldb_dn *old_dn = NULL;
+ struct ldb_dn *new_dn = NULL;
+ struct ldb_request *req = NULL;
+
+ old_dn = ldb_dn_new_fmt(ctx, ldb, "dc=%s", old_dc);
+ assert_non_null(old_dn);
+
+ new_dn = ldb_dn_new_fmt(ctx, ldb, "dc=%s", new_dc);
+ assert_non_null(new_dn);
+
+ ret = ldb_build_rename_req(
+ &req,
+ ldb,
+ ctx,
+ old_dn,
+ new_dn,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ return req;
+}
+
+/*
+ * Build a ldb modify request
+ */
+static struct ldb_request *build_modify_request(
+ TALLOC_CTX *ctx,
+ struct ldb_context *ldb,
+ const char* dc,
+ const char* cn)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldb_request *req;
+
+ msg = ldb_msg_new(ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, ldb, "dc=%s", dc);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_empty(msg, "cn", LDB_FLAG_MOD_REPLACE, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "cn", cn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_sanity_check(ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_build_mod_req(
+ &req, ldb, ldb, msg, NULL, NULL, ldb_op_default_callback, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ return req;
+}
+
+/*
+ * Delete a record from the database
+ */
+static void delete_record(
+ TALLOC_CTX *ctx,
+ struct ldb_context *ldb,
+ const char* dc)
+{
+ struct ldb_kv_context *ldb_kv_ctx = NULL;
+ struct ldb_dn *basedn = NULL;
+ struct ldb_result *result = NULL;
+ struct ldb_request *req = NULL;
+ int ret = LDB_SUCCESS;
+
+ req = build_delete_request(ctx, ldb, dc);
+ ldb_kv_ctx = build_ldb_kv_context(ctx, ldb->modules, req);
+
+ ret = ldb_transaction_start(ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ cmocka_unit_test_fail_delete_internal_after = NO_FAILURE;
+ cmocka_unit_test_fail_modify_internal_after = NO_FAILURE;
+ ret = ldb_kv_delete(ldb_kv_ctx);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(ldb_kv_ctx);
+ TALLOC_FREE(req);
+
+ ret = ldb_transaction_commit(ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Ensure that the record was actually deleted.
+ */
+ basedn = ldb_dn_new_fmt(ctx, ldb, "dc=%s", dc);
+ assert_non_null(basedn);
+
+ /*
+ * DN search, indexed
+ */
+ ret = ldb_search(ldb, ctx, &result, basedn, LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+ TALLOC_FREE(basedn);
+ TALLOC_FREE(result);
+}
+
+/*
+ * Add a record to the database
+ */
+static void add_record(
+ TALLOC_CTX *ctx,
+ struct ldb_context *ldb,
+ const char* dc,
+ const char* uuid,
+ const char* cn)
+{
+
+ struct ldb_request *req = NULL;
+ int ret = LDB_SUCCESS;
+ struct ldb_kv_context *ldb_kv_ctx = NULL;
+ struct ldb_dn *basedn = NULL;
+ struct ldb_result *result = NULL;
+
+ req = build_add_request(ctx, ldb, dc, uuid, cn);
+
+ ldb_req_set_location(req, "add_record");
+
+ assert_int_equal(ret, LDB_SUCCESS);
+
+
+ ldb_kv_ctx = build_ldb_kv_context(ctx, ldb->modules, req);
+ cmocka_unit_test_fail_add_internal_after = NO_FAILURE;
+ cmocka_unit_test_fail_modify_internal_after = NO_FAILURE;
+
+ ret = ldb_transaction_start(ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv_add(ldb_kv_ctx);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(ldb_kv_ctx);
+ TALLOC_FREE(req);
+
+ ret = ldb_transaction_commit(ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Ensure that the record was actually written.
+ */
+ basedn = ldb_dn_new_fmt(ctx, ldb, "dc=%s", dc);
+ assert_non_null(basedn);
+
+ /*
+ * DN search, indexed
+ */
+ ret = ldb_search(ldb, ctx, &result, basedn, LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ TALLOC_FREE(result);
+
+
+ /*
+ * CN search unindexed
+ */
+ ret = ldb_search(
+ ldb,
+ ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ NULL,
+ "(cn=%s)",
+ cn);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ TALLOC_FREE(result);
+ TALLOC_FREE(basedn);
+}
+
+/*
+ * Test that a failed add operation does not change the database.
+ */
+static void test_add_failure(void **state)
+{
+ int ret = LDB_SUCCESS;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_request *req = NULL;
+ struct ldb_dn *basedn = NULL;
+ struct ldb_result *result = NULL;
+ struct ldb_kv_context *ldb_kv_ctx = NULL;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ req = build_add_request(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_add_failure",
+ "0123456789abcdef",
+ "test_add_failure_value");
+
+ ldb_req_set_location(req, "test_add_failure");
+
+ ldb_kv_ctx = build_ldb_kv_context(tmp_ctx, test_ctx->ldb->modules, req);
+ cmocka_unit_test_fail_add_internal_after = 1;
+
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv_add(ldb_kv_ctx);
+
+ assert_int_equal(ret, FAILURE_LDB_ERR);
+ TALLOC_FREE(ldb_kv_ctx);
+ TALLOC_FREE(req);
+
+
+ /*
+ * a search for "cn=test_add_failure_value" should fail
+ * as the transaction containing the operation should have been
+ * rolled back leaving the database consistent
+ *
+ * This should be an un-indexed search so the index caches won't be
+ * used.
+ */
+ basedn = ldb_dn_new_fmt(
+ tmp_ctx,
+ test_ctx->ldb,
+ "dc=%s",
+ "test_add_failure");
+ assert_non_null(basedn);
+
+ ret = ldb_search(
+ test_ctx->ldb, tmp_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ NULL,
+ "(cn=%s)",
+ "test_add_failure_value");
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+ TALLOC_FREE(basedn);
+ TALLOC_FREE(result);
+
+ ldb_transaction_cancel(test_ctx->ldb);
+ TALLOC_FREE(tmp_ctx);
+}
+
+
+/*
+ * Test that a failed delete operation does not modify the database.
+ */
+static void test_delete_failure(void **state)
+{
+ int ret = LDB_SUCCESS;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_request *req = NULL;
+ struct ldb_dn *basedn = NULL;
+ struct ldb_result *result = NULL;
+ struct ldb_kv_context *ldb_kv_ctx = NULL;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ add_record(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_delete_failure",
+ "0123456789abcded",
+ "test_delete_failure_value");
+
+ req = build_delete_request(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_delete_failure");
+
+ ldb_kv_ctx = build_ldb_kv_context(tmp_ctx, test_ctx->ldb->modules, req);
+ cmocka_unit_test_fail_delete_internal_after = 1;
+
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv_delete(ldb_kv_ctx);
+ assert_int_equal(ret, FAILURE_LDB_ERR);
+ TALLOC_FREE(ldb_kv_ctx);
+ TALLOC_FREE(req);
+
+ /*
+ * a search for "cn=test_add_failure_value" should succeed
+ * as the transaction containing the operation should have been
+ * rolled back leaving the database consistent
+ *
+ * This should be an un-indexed search so the index caches won't be
+ * used.
+ */
+ basedn = ldb_dn_new_fmt(
+ tmp_ctx,
+ test_ctx->ldb,
+ "dc=%s",
+ "test_delete_failure");
+ assert_non_null(basedn);
+
+ ret = ldb_search(
+ test_ctx->ldb, tmp_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ NULL,
+ "(cn=%s)",
+ "test_delete_failure_value");
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ TALLOC_FREE(basedn);
+ TALLOC_FREE(result);
+
+
+ ldb_transaction_cancel(test_ctx->ldb);
+ delete_record(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_delete_failure");
+ TALLOC_FREE(tmp_ctx);
+}
+
+/*
+ * Test that a failed rename operation dies not change the database
+ */
+static void test_rename_failure(void **state)
+{
+ int ret = LDB_SUCCESS;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_request *req = NULL;
+ struct ldb_dn *basedn = NULL;
+ struct ldb_result *result = NULL;
+ struct ldb_kv_context *ldb_kv_ctx = NULL;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ add_record(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_rename_failure",
+ "0123456789abcdec",
+ "test_rename_failure_value");
+
+ req = build_rename_request(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_rename_failure",
+ "test_rename_failure_renamed");
+
+ ldb_kv_ctx = build_ldb_kv_context(tmp_ctx, test_ctx->ldb->modules, req);
+ cmocka_unit_test_fail_rename_internal_after = 1;
+
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv_rename(ldb_kv_ctx);
+ assert_int_equal(ret, FAILURE_LDB_ERR);
+ TALLOC_FREE(ldb_kv_ctx);
+ TALLOC_FREE(req);
+
+ /*
+ * The original record should be present
+ */
+ basedn = ldb_dn_new_fmt(
+ tmp_ctx,
+ test_ctx->ldb,
+ "dc=%s",
+ "test_rename_failure");
+ assert_non_null(basedn);
+
+ ret = ldb_search(
+ test_ctx->ldb, tmp_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ NULL,
+ "(cn=%s)",
+ "test_rename_failure_value");
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ TALLOC_FREE(basedn);
+ TALLOC_FREE(result);
+
+ /*
+ * And the renamed record should not be present
+ */
+ basedn = ldb_dn_new_fmt(
+ tmp_ctx,
+ test_ctx->ldb,
+ "dc=%s",
+ "test_rename_failure_renamed");
+ assert_non_null(basedn);
+
+ ret = ldb_search(
+ test_ctx->ldb, tmp_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ NULL,
+ "(cn=%s)",
+ "test_rename_failure_value");
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+ TALLOC_FREE(basedn);
+ TALLOC_FREE(result);
+
+ ldb_transaction_cancel(test_ctx->ldb);
+ delete_record(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_rename_failure");
+ TALLOC_FREE(tmp_ctx);
+}
+
+/*
+ * Test that a failed modification operation does not change the database
+ */
+static void test_modify_failure(void **state)
+{
+ int ret = LDB_SUCCESS;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_request *req = NULL;
+ struct ldb_dn *basedn = NULL;
+ struct ldb_result *result = NULL;
+ struct ldb_kv_context *ldb_kv_ctx = NULL;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ add_record(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_modify_failure",
+ "0123456789abcdeb",
+ "test_modify_failure_value");
+
+ req = build_modify_request(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_modify_failure",
+ "test_modify_failure_value_modified");
+
+ ldb_kv_ctx = build_ldb_kv_context(tmp_ctx, test_ctx->ldb->modules, req);
+ cmocka_unit_test_fail_modify_internal_after = 2;
+
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv_modify(ldb_kv_ctx);
+ assert_int_equal(ret, FAILURE_LDB_ERR);
+ TALLOC_FREE(ldb_kv_ctx);
+ TALLOC_FREE(req);
+
+
+ /*
+ * The original value should be present
+ */
+ basedn = ldb_dn_new_fmt(
+ tmp_ctx,
+ test_ctx->ldb,
+ "dc=%s",
+ "test_modify_failure");
+ assert_non_null(basedn);
+
+ ret = ldb_search(
+ test_ctx->ldb, tmp_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ NULL,
+ "(cn=%s)",
+ "test_modify_failure_value");
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ TALLOC_FREE(result);
+
+ /*
+ * And the modified record should not be present
+ */
+ ret = ldb_search(
+ test_ctx->ldb, tmp_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ NULL,
+ "(cn=%s)",
+ "test_modify_failure_value_modified");
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+ TALLOC_FREE(basedn);
+ TALLOC_FREE(result);
+
+ ldb_transaction_cancel(test_ctx->ldb);
+ delete_record(
+ tmp_ctx,
+ test_ctx->ldb,
+ "test_modify_failure");
+ TALLOC_FREE(tmp_ctx);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_add_failure,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_delete_failure,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_rename_failure,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_modify_failure,
+ setup,
+ teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_key_value_test.c b/lib/ldb/tests/ldb_key_value_test.c
new file mode 100644
index 0000000..97f717b
--- /dev/null
+++ b/lib/ldb/tests/ldb_key_value_test.c
@@ -0,0 +1,388 @@
+/*
+ * Tests exercising the ldb key value operations.
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+/*
+ *
+ * Tests for the ldb key value layer
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include "ldb_key_value/ldb_kv.c"
+#include "ldb_key_value/ldb_kv_index.c"
+#include "ldb_key_value/ldb_kv_search.c"
+
+#define DEFAULT_BE "tdb"
+
+#ifndef TEST_BE
+#define TEST_BE DEFAULT_BE
+#endif /* TEST_BE */
+
+#define NUM_RECS 1024
+int ldb_kv_cache_reload(struct ldb_module *module) {
+ return LDB_SUCCESS;
+}
+int ldb_kv_cache_load(struct ldb_module *module) {
+ return LDB_SUCCESS;
+}
+int ldb_kv_check_at_attributes_values(const struct ldb_val *value) {
+ return LDB_SUCCESS;
+}
+int ldb_kv_increase_sequence_number(struct ldb_module *module) {
+ return LDB_SUCCESS;
+}
+
+struct test_ctx { uint8_t dummy; };
+
+static int setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ talloc_free(test_ctx);
+ return 0;
+}
+
+/*
+ * Test that the index cache is opened by ldb_kv_index_transaction_start
+ * and correctly initialised with the passed index cache size.
+ */
+static void test_index_cache_init(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct ldb_module *module = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ int ret = LDB_SUCCESS;
+
+ module = talloc_zero(test_ctx, struct ldb_module);
+ ldb_kv = talloc_zero(test_ctx, struct ldb_kv_private);
+ ldb_module_set_private(module, ldb_kv);
+
+ ret = ldb_kv_index_transaction_start(module, 191);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_non_null(ldb_kv->idxptr);
+ assert_non_null(ldb_kv->idxptr->itdb);
+ assert_int_equal(191, tdb_hash_size(ldb_kv->idxptr->itdb));
+
+ TALLOC_FREE(ldb_kv);
+ TALLOC_FREE(module);
+}
+
+static int mock_begin_write(struct ldb_kv_private* ldb_kv) {
+ return LDB_SUCCESS;
+}
+static int mock_abort_write(struct ldb_kv_private* ldb_kv) {
+ return LDB_SUCCESS;
+}
+
+/*
+ * Test that the index cache is set to the default cache size at the start of
+ * a transaction.
+ */
+static void test_default_index_cache_size(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct ldb_module *module = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ int ret = LDB_SUCCESS;
+ const struct kv_db_ops ops = {
+ .begin_write = mock_begin_write,
+ .abort_write = mock_abort_write
+ };
+
+ module = talloc_zero(test_ctx, struct ldb_module);
+ ldb_kv = talloc_zero(test_ctx, struct ldb_kv_private);
+ ldb_kv->pid = getpid();
+ ldb_kv->kv_ops = &ops;
+ ldb_kv->index_transaction_cache_size = DEFAULT_INDEX_CACHE_SIZE;
+ ldb_module_set_private(module, ldb_kv);
+
+ ret = ldb_kv_start_trans(module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_int_equal(
+ DEFAULT_INDEX_CACHE_SIZE,
+ tdb_hash_size(ldb_kv->idxptr->itdb));
+
+ ret = ldb_kv_del_trans(module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ TALLOC_FREE(ldb_kv);
+ TALLOC_FREE(module);
+}
+
+static int db_size = 0;
+static size_t mock_get_size(struct ldb_kv_private *ldb_kv) {
+ return db_size;
+}
+
+static int mock_iterate(
+ struct ldb_kv_private *ldb_kv,
+ ldb_kv_traverse_fn fn,
+ void *ctx) {
+ return 1;
+}
+
+/*
+ * Test that the index cache is correctly sized by the re_index call
+ */
+static void test_reindex_cache_size(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct ldb_module *module = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ int ret = LDB_SUCCESS;
+ const struct kv_db_ops ops = {
+ .iterate = mock_iterate,
+ .get_size = mock_get_size,
+ };
+
+ module = talloc_zero(test_ctx, struct ldb_module);
+ ldb_kv = talloc_zero(test_ctx, struct ldb_kv_private);
+ ldb_kv->kv_ops = &ops;
+ ldb_module_set_private(module, ldb_kv);
+
+ /*
+ * Use a value less than the DEFAULT_INDEX_CACHE_SIZE
+ * Should get the DEFAULT_INDEX_CACHE_SIZE
+ */
+ db_size = DEFAULT_INDEX_CACHE_SIZE - 1;
+ ret = ldb_kv_reindex(module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_int_equal(
+ DEFAULT_INDEX_CACHE_SIZE,
+ tdb_hash_size(ldb_kv->idxptr->itdb));
+
+ /*
+ * Use a value greater than the DEFAULT_INDEX_CACHE_SIZE
+ * Should get the value specified.
+ */
+ db_size = DEFAULT_INDEX_CACHE_SIZE + 1;
+ ret = ldb_kv_reindex(module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_int_equal(db_size, tdb_hash_size(ldb_kv->idxptr->itdb));
+
+ TALLOC_FREE(ldb_kv);
+ TALLOC_FREE(module);
+}
+
+/*
+ * Test that ldb_kv_init_store sets the default index transaction cache size
+ * if the option is not supplied.
+ */
+static void test_init_store_default_index_cache_size(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct ldb_module *module = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ struct ldb_context *ldb = NULL;
+ int ret = LDB_SUCCESS;
+
+ module = talloc_zero(test_ctx, struct ldb_module);
+ ldb = talloc_zero(test_ctx, struct ldb_context);
+ ldb_kv = talloc_zero(test_ctx, struct ldb_kv_private);
+
+ ret = ldb_kv_init_store(ldb_kv, "test", ldb, NULL, &module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_int_equal(
+ DEFAULT_INDEX_CACHE_SIZE,
+ ldb_kv->index_transaction_cache_size);
+
+ TALLOC_FREE(ldb_kv);
+ TALLOC_FREE(module);
+ TALLOC_FREE(ldb);
+}
+
+/*
+ * Test that ldb_kv_init_store sets the index transaction cache size
+ * to the value specified in the option.
+ */
+static void test_init_store_set_index_cache_size(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct ldb_module *module = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ struct ldb_context *ldb = NULL;
+ const char *options[] = {"transaction_index_cache_size:1900", NULL};
+ int ret = LDB_SUCCESS;
+
+ module = talloc_zero(test_ctx, struct ldb_module);
+ ldb = talloc_zero(test_ctx, struct ldb_context);
+ ldb_kv = talloc_zero(test_ctx, struct ldb_kv_private);
+
+ ret = ldb_kv_init_store(ldb_kv, "test", ldb, options, &module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_int_equal( 1900, ldb_kv->index_transaction_cache_size);
+
+ TALLOC_FREE(ldb_kv);
+ TALLOC_FREE(module);
+ TALLOC_FREE(ldb);
+}
+
+/*
+ * Test that ldb_kv_init_store sets the default index transaction cache size
+ * if the value specified in the option is not a number.
+ */
+static void test_init_store_set_index_cache_size_non_numeric(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct ldb_module *module = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ struct ldb_context *ldb = NULL;
+ const char *options[] = {"transaction_index_cache_size:fred", NULL};
+ int ret = LDB_SUCCESS;
+
+ module = talloc_zero(test_ctx, struct ldb_module);
+ ldb = talloc_zero(test_ctx, struct ldb_context);
+ ldb_kv = talloc_zero(test_ctx, struct ldb_kv_private);
+
+ ret = ldb_kv_init_store(ldb_kv, "test", ldb, options, &module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_int_equal(
+ DEFAULT_INDEX_CACHE_SIZE,
+ ldb_kv->index_transaction_cache_size);
+
+ TALLOC_FREE(ldb_kv);
+ TALLOC_FREE(module);
+ TALLOC_FREE(ldb);
+}
+
+/*
+ * Test that ldb_kv_init_store sets the default index transaction cache size
+ * if the value specified is too large
+ */
+static void test_init_store_set_index_cache_size_range(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct ldb_module *module = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ struct ldb_context *ldb = NULL;
+ const char *options[] = {
+ "transaction_index_cache_size:0xfffffffffffffffffffffffffffff",
+ NULL};
+ int ret = LDB_SUCCESS;
+
+ module = talloc_zero(test_ctx, struct ldb_module);
+ ldb = talloc_zero(test_ctx, struct ldb_context);
+ ldb_kv = talloc_zero(test_ctx, struct ldb_kv_private);
+
+ ret = ldb_kv_init_store(ldb_kv, "test", ldb, options, &module);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ assert_int_equal(
+ DEFAULT_INDEX_CACHE_SIZE,
+ ldb_kv->index_transaction_cache_size);
+
+ TALLOC_FREE(ldb_kv);
+ TALLOC_FREE(module);
+ TALLOC_FREE(ldb);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_index_cache_init,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_default_index_cache_size,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_reindex_cache_size,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_init_store_default_index_cache_size,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_init_store_set_index_cache_size,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_init_store_set_index_cache_size_non_numeric,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_init_store_set_index_cache_size_range,
+ setup,
+ teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_kv_ops_test.c b/lib/ldb/tests/ldb_kv_ops_test.c
new file mode 100644
index 0000000..b84ed0c
--- /dev/null
+++ b/lib/ldb/tests/ldb_kv_ops_test.c
@@ -0,0 +1,1819 @@
+/*
+ * Tests exercising the ldb key value operations.
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+/*
+ * A KV module is expected to have the following behaviour
+ *
+ * - A transaction must be open to perform any read, write or delete operation
+ * - Writes and Deletes should not be visible until a transaction is committed
+ * - Nested transactions are not permitted
+ * - transactions can be rolled back and committed.
+ * - supports iteration over all records in the database
+ * - supports the update_in_iterate operation allowing entries to be
+ * re-keyed.
+ * - has a get_size implementation that returns an estimate of the number of
+ * records in the database. Note that this can be an estimate rather than
+ * an accurate size.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include "ldb_tdb/ldb_tdb.h"
+#include "ldb_key_value/ldb_kv.h"
+
+
+#define DEFAULT_BE "tdb"
+
+#ifndef TEST_BE
+#define TEST_BE DEFAULT_BE
+#endif /* TEST_BE */
+
+#define NUM_RECS 1024
+
+
+struct test_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+};
+
+static void unlink_old_db(struct test_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int noconn_setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "kvopstest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int noconn_teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static int setup(void **state)
+{
+ struct test_ctx *test_ctx;
+ int ret;
+ struct ldb_ldif *ldif;
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+
+ noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static struct ldb_kv_private *get_ldb_kv(struct ldb_context *ldb)
+{
+ void *data = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+
+ data = ldb_module_get_private(ldb->modules);
+ assert_non_null(data);
+
+ ldb_kv = talloc_get_type(data, struct ldb_kv_private);
+ assert_non_null(ldb_kv);
+
+ return ldb_kv;
+}
+
+static int parse(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data)
+{
+ struct ldb_val* read = private_data;
+
+ /* Yes, we leak this. That is OK */
+ read->data = talloc_size(NULL,
+ data.length);
+ assert_non_null(read->data);
+
+ memcpy(read->data, data.data, data.length);
+ read->length = data.length;
+ return LDB_SUCCESS;
+}
+
+/*
+ * Parse function that just returns the int we pass it.
+ */
+static int parse_return(struct ldb_val key,
+ struct ldb_val data,
+ void *private_data)
+{
+ int *rcode = private_data;
+ return *rcode;
+}
+
+/*
+ * Test that data can be written to the kv store and be read back.
+ */
+static void test_add_get(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+
+ struct ldb_val read;
+ int rcode;
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, 0);
+
+ assert_int_equal(sizeof(value), read.length);
+ assert_memory_equal(value, read.data, sizeof(value));
+
+ /*
+ * Now check that the error code we return in the
+ * parse function is returned by fetch_and_parse.
+ */
+ for (rcode=0; rcode<50; rcode++) {
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key,
+ parse_return,
+ &rcode);
+ assert_int_equal(ret, rcode);
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ talloc_free(tmp_ctx);
+}
+
+/*
+ * Test that attempts to read data without a read transaction fail.
+ */
+static void test_read_outside_transaction(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+
+ struct ldb_val read;
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back
+ * Note there is no read transaction active
+ */
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ * Test that data can be deleted from the kv store
+ */
+static void test_delete(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+
+ struct ldb_val read;
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, 0);
+ assert_int_equal(sizeof(value), read.length);
+ assert_memory_equal(value, read.data, sizeof(value));
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Now delete it.
+ */
+ ret = ldb_kv->kv_ops->delete (ldb_kv, key);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now try to read it back
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ * Check that writes are correctly rolled back when a transaction
+ * is rolled back.
+ */
+static void test_transaction_abort_write(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+
+ struct ldb_val read;
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back
+ */
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, 0);
+ assert_int_equal(sizeof(value), read.length);
+ assert_memory_equal(value, read.data, sizeof(value));
+
+
+ /*
+ * Now abort the transaction
+ */
+ ret = ldb_kv->kv_ops->abort_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back, should not be there
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ * Check that deletes are correctly rolled back when a transaction is
+ * aborted.
+ */
+static void test_transaction_abort_delete(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+
+ struct ldb_val read;
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, 0);
+ assert_int_equal(sizeof(value), read.length);
+ assert_memory_equal(value, read.data, sizeof(value));
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Now delete it.
+ */
+ ret = ldb_kv->kv_ops->delete (ldb_kv, key);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back
+ */
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+
+ /*
+ * Abort the transaction
+ */
+ ret = ldb_kv->kv_ops->abort_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now try to read it back
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, 0);
+ assert_int_equal(sizeof(value), read.length);
+ assert_memory_equal(value, read.data, sizeof(value));
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ * Test that writes outside a transaction fail
+ */
+static void test_write_outside_transaction(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Attempt to write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ * Test data can not be deleted outside a transaction
+ */
+static void test_delete_outside_transaction(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+
+ struct ldb_val read;
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * And now read it back
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, 0);
+ assert_int_equal(sizeof(value), read.length);
+ assert_memory_equal(value, read.data, sizeof(value));
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Now attempt to delete a record
+ */
+ ret = ldb_kv->kv_ops->delete (ldb_kv, key);
+ assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
+
+ /*
+ * And now read it back
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
+ assert_int_equal(ret, 0);
+ assert_int_equal(sizeof(value), read.length);
+ assert_memory_equal(value, read.data, sizeof(value));
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+static int traverse_fn(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val data,
+ void *ctx)
+{
+
+ int *visits = ctx;
+ int i;
+
+ if (strncmp("key ", (char *) key.data, 4) == 0) {
+ i = strtol((char *) &key.data[4], NULL, 10);
+ visits[i]++;
+ }
+ return LDB_SUCCESS;
+}
+
+/*
+ * Test that iterate visits all the records.
+ */
+static void test_iterate(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ int i;
+ int num_recs = 1024;
+ int visits[num_recs];
+
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the records
+ */
+ for (i = 0; i < num_recs; i++) {
+ struct ldb_val key;
+ struct ldb_val rec;
+ int flags = 0;
+
+ visits[i] = 0;
+ key.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", i);
+ key.length = strlen((char *)key.data) + 1;
+
+ rec.data = (uint8_t *) talloc_asprintf(tmp_ctx,
+ "data for record (%04d)",
+ i);
+ rec.length = strlen((char *)rec.data) + 1;
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
+ assert_int_equal(ret, 0);
+
+ TALLOC_FREE(key.data);
+ TALLOC_FREE(rec.data);
+ }
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Now iterate over the kv store and ensure that all the
+ * records are visited.
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->iterate(ldb_kv, traverse_fn, visits);
+ for (i = 0; i <num_recs; i++) {
+ assert_int_equal(1, visits[i]);
+ }
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ TALLOC_FREE(tmp_ctx);
+}
+
+static void do_iterate_range_test(void **state, int range_start,
+ int range_end, bool fail)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = NULL;
+ int i;
+ int num_recs = 1024;
+ int skip_recs = 10;
+ int visits[num_recs];
+ struct ldb_val sk, ek;
+
+ TALLOC_CTX *tmp_ctx;
+
+ ldb_kv = get_ldb_kv(test_ctx->ldb);
+ assert_non_null(ldb_kv);
+
+ for (i = 0; i < num_recs; i++){
+ visits[i] = 0;
+ }
+
+ /*
+ * No iterate_range on tdb
+ */
+ if (strcmp(TEST_BE, "tdb") == 0) {
+ return;
+ }
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the records
+ */
+ for (i = skip_recs; i <= num_recs - skip_recs; i++) {
+ struct ldb_val key;
+ struct ldb_val rec;
+ int flags = 0;
+
+ key.data = (uint8_t *)talloc_asprintf(tmp_ctx,
+ "key %04d",
+ i);
+ key.length = strlen((char *)key.data);
+
+ rec.data = (uint8_t *)talloc_asprintf(tmp_ctx,
+ "data for record (%04d)",
+ i);
+ rec.length = strlen((char *)rec.data) + 1;
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
+ assert_int_equal(ret, 0);
+
+ TALLOC_FREE(key.data);
+ TALLOC_FREE(rec.data);
+ }
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ sk.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", range_start);
+ sk.length = strlen((char *)sk.data);
+
+ ek.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", range_end);
+ ek.length = strlen((char *)ek.data) + 1;
+
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->iterate_range(ldb_kv, sk, ek,
+ traverse_fn, visits);
+ if (fail){
+ assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
+ TALLOC_FREE(tmp_ctx);
+ return;
+ } else{
+ assert_int_equal(ret, 0);
+ }
+ for (i = 0; i < num_recs; i++) {
+ if (i >= skip_recs && i <= num_recs - skip_recs &&
+ i >= range_start && i <= range_end){
+ assert_int_equal(1, visits[i]);
+ } else {
+ assert_int_equal(0, visits[i]);
+ }
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ TALLOC_FREE(tmp_ctx);
+}
+
+/*
+ * Test that iterate_range visits all the records between two keys.
+ */
+static void test_iterate_range(void **state)
+{
+ do_iterate_range_test(state, 300, 900, false);
+
+ /*
+ * test start_key = end_key
+ */
+ do_iterate_range_test(state, 20, 20, false);
+
+ /*
+ * test reverse range fails
+ */
+ do_iterate_range_test(state, 50, 40, true);
+
+ /*
+ * keys are between 10-1014 so test with keys outside that range
+ */
+ do_iterate_range_test(state, 0, 20, false);
+ do_iterate_range_test(state, 1010, 1030, false);
+ do_iterate_range_test(state, 0, 1030, false);
+}
+
+struct update_context {
+ struct ldb_context* ldb;
+ int visits[NUM_RECS];
+};
+
+static int update_fn(struct ldb_kv_private *ldb_kv,
+ struct ldb_val key,
+ struct ldb_val data,
+ void *ctx)
+{
+
+ struct ldb_val new_key;
+ struct ldb_module *module = NULL;
+ struct update_context *context =NULL;
+ int ret = LDB_SUCCESS;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(ldb_kv);
+ assert_non_null(tmp_ctx);
+
+ context = talloc_get_type_abort(ctx, struct update_context);
+
+ module = talloc_zero(tmp_ctx, struct ldb_module);
+ module->ldb = context->ldb;
+
+ if (strncmp("key ", (char *) key.data, 4) == 0) {
+ int i = strtol((char *) &key.data[4], NULL, 10);
+ context->visits[i]++;
+ new_key.data = talloc_memdup(tmp_ctx, key.data, key.length);
+ new_key.length = key.length;
+ new_key.data[0] = 'K';
+
+ ret = ldb_kv->kv_ops->update_in_iterate(
+ ldb_kv, key, new_key, data, &module);
+ }
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+/*
+ * Test that update_in_iterate behaves as expected.
+ */
+static void test_update_in_iterate(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ int i;
+ struct update_context *context = NULL;
+
+
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ context = talloc_zero(tmp_ctx, struct update_context);
+ assert_non_null(context);
+ context->ldb = test_ctx->ldb;
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the records
+ */
+ for (i = 0; i < NUM_RECS; i++) {
+ struct ldb_val key;
+ struct ldb_val rec;
+ int flags = 0;
+
+ key.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", i);
+ key.length = strlen((char *)key.data) + 1;
+
+ rec.data = (uint8_t *) talloc_asprintf(tmp_ctx,
+ "data for record (%04d)",
+ i);
+ rec.length = strlen((char *)rec.data) + 1;
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
+ assert_int_equal(ret, 0);
+
+ TALLOC_FREE(key.data);
+ TALLOC_FREE(rec.data);
+ }
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Now iterate over the kv store and ensure that all the
+ * records are visited.
+ */
+
+ /*
+ * Needs to be done inside a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_kv->kv_ops->iterate(ldb_kv, update_fn, context);
+ for (i = 0; i < NUM_RECS; i++) {
+ assert_int_equal(1, context->visits[i]);
+ }
+
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ TALLOC_FREE(tmp_ctx);
+}
+
+/*
+ * Ensure that writes are not visible until the transaction has been
+ * committed.
+ */
+static void test_write_transaction_isolation(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ struct ldb_val key;
+ struct ldb_val val;
+
+ const char *KEY1 = "KEY01";
+ const char *VAL1 = "VALUE01";
+
+ const char *KEY2 = "KEY02";
+ const char *VAL2 = "VALUE02";
+
+ /*
+ * Pipes etc to coordinate the processes
+ */
+ int to_child[2];
+ int to_parent[2];
+ char buf[2];
+ pid_t pid, w_pid;
+ int wstatus;
+
+ TALLOC_CTX *tmp_ctx;
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ /*
+ * Add a record to the database
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL1);
+ val.length = strlen(VAL1) + 1;
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+
+ ret = pipe(to_child);
+ assert_int_equal(ret, 0);
+ ret = pipe(to_parent);
+ assert_int_equal(ret, 0);
+ /*
+ * Now fork a new process
+ */
+
+ pid = fork();
+ if (pid == 0) {
+
+ struct ldb_context *ldb = NULL;
+ close(to_child[1]);
+ close(to_parent[0]);
+
+ /*
+ * Wait for the transaction to start
+ */
+ ret = read(to_child[0], buf, 2);
+ if (ret != 2) {
+ print_error(__location__": read returned (%d)\n",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": ldb_connect returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ ldb_kv = get_ldb_kv(ldb);
+
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": lock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ /*
+ * Check that KEY1 is there
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ if ((strlen(VAL1) + 1) != val.length) {
+ print_error(__location__": KEY1 value lengths different"
+ ", expected (%d) actual(%d)\n",
+ (int)(strlen(VAL1) + 1), (int)val.length);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
+ print_error(__location__": KEY1 values different, "
+ "expected (%s) actual(%s)\n",
+ VAL1,
+ val.data);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ /*
+ * Check that KEY2 is not there
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
+ key.length = strlen(KEY2 + 1);
+
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": lock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ /*
+ * Signal the other process to commit the transaction
+ */
+ ret = write(to_parent[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__": write returned (%d)\n",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /*
+ * Wait for the transaction to be committed
+ */
+ ret = read(to_child[0], buf, 2);
+ if (ret != 2) {
+ print_error(__location__": read returned (%d)\n",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /*
+ * Check that KEY1 is there
+ */
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ if ((strlen(VAL1) + 1) != val.length) {
+ print_error(__location__": KEY1 value lengths different"
+ ", expected (%d) actual(%d)\n",
+ (int)(strlen(VAL1) + 1), (int)val.length);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
+ print_error(__location__": KEY1 values different, "
+ "expected (%s) actual(%s)\n",
+ VAL1,
+ val.data);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+
+ /*
+ * Check that KEY2 is there
+ */
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
+ key.length = strlen(KEY2) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ if ((strlen(VAL2) + 1) != val.length) {
+ print_error(__location__": KEY2 value lengths different"
+ ", expected (%d) actual(%d)\n",
+ (int)(strlen(VAL2) + 1), (int)val.length);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (memcmp(VAL2, val.data, strlen(VAL2)) != 0) {
+ print_error(__location__": KEY2 values different, "
+ "expected (%s) actual(%s)\n",
+ VAL2,
+ val.data);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ exit(0);
+ }
+ close(to_child[0]);
+ close(to_parent[1]);
+
+ /*
+ * Begin a transaction and add a record to the database
+ * but leave the transaction open
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
+ key.length = strlen(KEY2) + 1;
+
+ val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL2);
+ val.length = strlen(VAL2) + 1;
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Signal the child process
+ */
+ ret = write(to_child[1], "GO", 2);
+ assert_int_equal(2, ret);
+
+ /*
+ * Wait for the child process to check the DB state while the
+ * transaction is active
+ */
+ ret = read(to_parent[0], buf, 2);
+ assert_int_equal(2, ret);
+
+ /*
+ * commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(0, ret);
+
+ /*
+ * Signal the child process
+ */
+ ret = write(to_child[1], "GO", 2);
+ assert_int_equal(2, ret);
+
+ w_pid = waitpid(pid, &wstatus, 0);
+ assert_int_equal(pid, w_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+
+ TALLOC_FREE(tmp_ctx);
+}
+
+/*
+ * Ensure that deletes are not visible until the transaction has been
+ * committed.
+ */
+static void test_delete_transaction_isolation(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ struct ldb_val key;
+ struct ldb_val val;
+
+ const char *KEY1 = "KEY01";
+ const char *VAL1 = "VALUE01";
+
+ const char *KEY2 = "KEY02";
+ const char *VAL2 = "VALUE02";
+
+ /*
+ * Pipes etc to coordinate the processes
+ */
+ int to_child[2];
+ int to_parent[2];
+ char buf[2];
+ pid_t pid, w_pid;
+ int wstatus;
+
+ TALLOC_CTX *tmp_ctx;
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ /*
+ * Add records to the database
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL1);
+ val.length = strlen(VAL1) + 1;
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
+ assert_int_equal(ret, 0);
+
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
+ key.length = strlen(KEY2) + 1;
+
+ val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL2);
+ val.length = strlen(VAL2) + 1;
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+
+ ret = pipe(to_child);
+ assert_int_equal(ret, 0);
+ ret = pipe(to_parent);
+ assert_int_equal(ret, 0);
+ /*
+ * Now fork a new process
+ */
+
+ pid = fork();
+ if (pid == 0) {
+
+ struct ldb_context *ldb = NULL;
+ close(to_child[1]);
+ close(to_parent[0]);
+
+ /*
+ * Wait for the transaction to be started
+ */
+ ret = read(to_child[0], buf, 2);
+ if (ret != 2) {
+ print_error(__location__": read returned (%d)\n",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": ldb_connect returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ ldb_kv = get_ldb_kv(ldb);
+
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": lock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ /*
+ * Check that KEY1 is there
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ if ((strlen(VAL1) + 1) != val.length) {
+ print_error(__location__": KEY1 value lengths different"
+ ", expected (%d) actual(%d)\n",
+ (int)(strlen(VAL1) + 1), (int)val.length);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
+ print_error(__location__": KEY1 values different, "
+ "expected (%s) actual(%s)\n",
+ VAL1,
+ val.data);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /*
+ * Check that KEY2 is there
+ */
+
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
+ key.length = strlen(KEY2) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ if ((strlen(VAL2) + 1) != val.length) {
+ print_error(__location__": KEY2 value lengths different"
+ ", expected (%d) actual(%d)\n",
+ (int)(strlen(VAL2) + 1), (int)val.length);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (memcmp(VAL2, val.data, strlen(VAL2)) != 0) {
+ print_error(__location__": KEY2 values different, "
+ "expected (%s) actual(%s)\n",
+ VAL2,
+ val.data);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ /*
+ * Signal the other process to commit the transaction
+ */
+ ret = write(to_parent[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__": write returned (%d)\n",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /*
+ * Wait for the transaction to be committed
+ */
+ ret = read(to_child[0], buf, 2);
+ if (ret != 2) {
+ print_error(__location__": read returned (%d)\n",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /*
+ * Check that KEY1 is there
+ */
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ if ((strlen(VAL1) + 1) != val.length) {
+ print_error(__location__": KEY1 value lengths different"
+ ", expected (%d) actual(%d)\n",
+ (int)(strlen(VAL1) + 1), (int)val.length);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
+ print_error(__location__": KEY1 values different, "
+ "expected (%s) actual(%s)\n",
+ VAL1,
+ val.data);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ /*
+ * Check that KEY2 is not there
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
+ key.length = strlen(KEY2 + 1);
+
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": lock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ print_error(__location__": fetch_and_parse returned "
+ "(%d)\n",
+ ret);
+ exit(ret);
+ }
+
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ if (ret != LDB_SUCCESS) {
+ print_error(__location__": unlock_read returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+ TALLOC_FREE(tmp_ctx);
+ exit(0);
+ }
+ close(to_child[0]);
+ close(to_parent[1]);
+
+ /*
+ * Begin a transaction and delete a record from the database
+ * but leave the transaction open
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
+ key.length = strlen(KEY2) + 1;
+
+ ret = ldb_kv->kv_ops->delete (ldb_kv, key);
+ assert_int_equal(ret, 0);
+ /*
+ * Signal the child process
+ */
+ ret = write(to_child[1], "GO", 2);
+ assert_int_equal(2, ret);
+
+ /*
+ * Wait for the child process to check the DB state while the
+ * transaction is active
+ */
+ ret = read(to_parent[0], buf, 2);
+ assert_int_equal(2, ret);
+
+ /*
+ * commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(0, ret);
+
+ /*
+ * Signal the child process
+ */
+ ret = write(to_child[1], "GO", 2);
+ assert_int_equal(2, ret);
+
+ w_pid = waitpid(pid, &wstatus, 0);
+ assert_int_equal(pid, w_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+
+ TALLOC_FREE(tmp_ctx);
+}
+
+
+/*
+ * Test that get_size returns a sensible estimate of the number of records
+ * in the database.
+ */
+static void test_get_size(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ uint8_t key_val[] = "TheKey";
+ struct ldb_val key = {
+ .data = key_val,
+ .length = sizeof(key_val)
+ };
+
+ uint8_t value[] = "The record contents";
+ struct ldb_val data = {
+ .data = value,
+ .length = sizeof(value)
+ };
+ size_t size = 0;
+
+ int flags = 0;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ size = ldb_kv->kv_ops->get_size(ldb_kv);
+#if defined(TEST_LMDB)
+ assert_int_equal(2, size);
+#else
+ /*
+ * The tdb implementation of get_size over estimates for sparse files
+ * which is perfectly acceptable for it's intended use.
+ * mipsel, ia64: 9994
+ * ppc64el, powerpc, ppc64: 13369
+ * sparc64: 5046
+ */
+ assert_in_range(size, 2500, 15000);
+#endif
+
+ /*
+ * Begin a transaction
+ */
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Write the record
+ */
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Commit the transaction
+ */
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, 0);
+
+ size = ldb_kv->kv_ops->get_size(ldb_kv);
+#ifdef TEST_LMDB
+ assert_int_equal(3, size);
+#else
+ /*
+ * The tdb implementation of get_size over estimates for sparse files
+ * which is perfectly acceptable for it's intended use.
+ * mipsel, ia64: 9994
+ * ppc64el, powerpc, ppc64: 13369
+ * sparc64: 5046
+ */
+ assert_in_range(size, 2500, 15000);
+#endif
+ talloc_free(tmp_ctx);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_add_get,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_delete,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_transaction_abort_write,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_transaction_abort_delete,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_read_outside_transaction,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_write_outside_transaction,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_delete_outside_transaction,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_iterate,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_iterate_range,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_update_in_iterate,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_write_transaction_isolation,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_delete_transaction_isolation,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_get_size,
+ setup,
+ teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_kv_ops_test.valgrind b/lib/ldb/tests/ldb_kv_ops_test.valgrind
new file mode 100644
index 0000000..1747076
--- /dev/null
+++ b/lib/ldb/tests/ldb_kv_ops_test.valgrind
@@ -0,0 +1,97 @@
+{
+ Memory allocated by setup
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:setup
+}
+{
+ Memory allocated by setup
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:realloc
+ ...
+ fun:setup
+}
+{
+ Memory allocated by ldb_init
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_init
+}
+{
+ Memory allocated by ldb_init
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:realloc
+ ...
+ fun:ldb_init
+}
+{
+ Memory allocated by noconn_setup
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:noconn_setup
+}
+{
+ Memory allocated by parse, which allocates on the NULL context
+ Memcheck:Leak
+ match-leak-kinds: all
+ fun:malloc
+ ...
+ fun:parse
+}
+{
+ Memory allocated by tdb_parse_data
+ Memcheck:Leak
+ match-leak-kinds: all
+ fun:malloc
+ ...
+ fun:tdb_parse_data
+}
+{
+ Memory allocated by ldb_connect
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_connect
+}
+{
+ Memory allocated by ldb_connect
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:calloc
+ ...
+ fun:ldb_connect
+}
+{
+ Memory allocated by ldb_kv_cache_load
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_kv_cache_load
+}
+{
+ Memory allocated by ldb_kv_index_load
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_kv_index_load
+}
+{
+ Memory allocated by ldb_asprintf_errstring
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_asprintf_errstring
+}
+
diff --git a/lib/ldb/tests/ldb_lmdb_free_list_test.c b/lib/ldb/tests/ldb_lmdb_free_list_test.c
new file mode 100644
index 0000000..246fdc7
--- /dev/null
+++ b/lib/ldb/tests/ldb_lmdb_free_list_test.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) Catalyst.Net Ltd 2020
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * Tests confirming lmdb's handling of the free space list in the presence
+ * of active and stale readers. A stale reader is a process that opens a
+ * read lock and then exits without releasing the lock.
+ *
+ * lmdb uses MVCC to maintain databased consistency, new copies of updated
+ * records are written to the database. The old entries are only
+ * reused when they are no longer referenced in a read transaction.
+ *
+ * The tests all update a single record multiple times
+ *
+ * If there is a read transaction or a stale reader lmdb will report
+ * out of space.
+ *
+ * If no read transaction and no stale reader, lmdb reclaims space from the
+ * free list.
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include "ldb_tdb/ldb_tdb.h"
+#include "ldb_key_value/ldb_kv.h"
+
+#define DEFAULT_BE "mdb"
+
+#ifndef TEST_BE
+#define TEST_BE DEFAULT_BE
+#endif /* TEST_BE */
+
+const int RECORD_SIZE = 6144;
+const int ITERATIONS = 192;
+
+struct test_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+};
+
+static void unlink_old_db(struct test_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int noconn_setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "lmdb_free_list_test.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile =
+ talloc_asprintf(test_ctx, "%s-lock", test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath =
+ talloc_asprintf(test_ctx, TEST_BE "://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int noconn_teardown(void **state)
+{
+ struct test_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static int setup(void **state)
+{
+ struct test_ctx *test_ctx;
+ int ret;
+ struct ldb_ldif *ldif;
+ const char *index_ldif = "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+ /*
+ * Use a 1MiB DB for this test
+ */
+ const char *options[] = {"lmdb_env_size:1048576", NULL};
+
+ noconn_setup((void **)&test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ struct test_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+ noconn_teardown((void **)&test_ctx);
+ return 0;
+}
+
+static struct ldb_kv_private *get_ldb_kv(struct ldb_context *ldb)
+{
+ void *data = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+
+ data = ldb_module_get_private(ldb->modules);
+ assert_non_null(data);
+
+ ldb_kv = talloc_get_type(data, struct ldb_kv_private);
+ assert_non_null(ldb_kv);
+
+ return ldb_kv;
+}
+
+static int parse(struct ldb_val key, struct ldb_val data, void *private_data)
+{
+ struct ldb_val *read = private_data;
+
+ /* Yes, we leak this. That is OK */
+ read->data = talloc_size(NULL, data.length);
+ assert_non_null(read->data);
+
+ memcpy(read->data, data.data, data.length);
+ read->length = data.length;
+ return LDB_SUCCESS;
+}
+
+/*
+ * This test has the same structure as the test_free_list_read_lock
+ * except the parent process does not keep the read lock open while the
+ * child process is performing an update.
+ */
+static void test_free_list_no_read_lock(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ struct ldb_val key;
+ struct ldb_val val;
+
+ const char *KEY1 = "KEY01";
+
+ /*
+ * Pipes etc to coordinate the processes
+ */
+ int to_child[2];
+ int to_parent[2];
+ char buf[2];
+ pid_t pid;
+ size_t i;
+
+ TALLOC_CTX *tmp_ctx;
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ ret = pipe(to_child);
+ assert_int_equal(ret, 0);
+ ret = pipe(to_parent);
+ assert_int_equal(ret, 0);
+ /*
+ * Now fork a new process
+ */
+
+ pid = fork();
+ if (pid == 0) {
+ /*
+ * Child process
+ */
+
+ struct ldb_context *ldb = NULL;
+ close(to_child[1]);
+ close(to_parent[0]);
+
+ /*
+ * Wait for the parent to get ready.
+ */
+ ret = read(to_child[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(ldb);
+
+ ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ldb_kv = get_ldb_kv(ldb);
+ assert_non_null(ldb_kv);
+ /*
+ * Add a record to the database
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+ val.data = talloc_zero_size(tmp_ctx, RECORD_SIZE);
+ assert_non_null(val.data);
+ memset(val.data, 'x', RECORD_SIZE);
+ val.length = RECORD_SIZE;
+ /*
+ * Do more iterations than when a read lock, stale reader
+ * active to confirm that the space is being re-used.
+ */
+ for (i = 0; i < ITERATIONS * 10; i++) {
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ /*
+ * Signal the parent that we've done the updates
+ */
+ ret = write(to_parent[1], "GO", 2);
+ assert_int_equal(ret, 2);
+ exit(0);
+ }
+
+ close(to_child[0]);
+ close(to_parent[1]);
+
+ /*
+ * Begin a read transaction
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Now close it
+ */
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Signal the child process
+ */
+ ret = write(to_child[1], "GO", 2);
+ assert_int_equal(2, ret);
+
+ /*
+ * Wait for the child process to update the record
+ */
+ ret = read(to_parent[0], buf, 2);
+ assert_int_equal(2, ret);
+
+ /*
+ * Begin a read transaction
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+ /*
+ * read the record
+ * and close the transaction
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ close(to_child[1]);
+ close(to_parent[0]);
+ TALLOC_FREE(tmp_ctx);
+}
+
+/*
+ * This test has the same structure as the test_free_list_read_lock
+ * except the parent process keeps the read lock open while the
+ * child process is performing an update.
+ */
+static void test_free_list_read_lock(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ struct ldb_val key;
+ struct ldb_val val;
+
+ const char *KEY1 = "KEY01";
+
+ /*
+ * Pipes etc to coordinate the processes
+ */
+ int to_child[2];
+ int to_parent[2];
+ char buf[2];
+ pid_t pid;
+ size_t i;
+
+ TALLOC_CTX *tmp_ctx;
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ ret = pipe(to_child);
+ assert_int_equal(ret, 0);
+ ret = pipe(to_parent);
+ assert_int_equal(ret, 0);
+ /*
+ * Now fork a new process
+ */
+
+ pid = fork();
+ if (pid == 0) {
+ /*
+ * Child process
+ */
+
+ struct ldb_context *ldb = NULL;
+ close(to_child[1]);
+ close(to_parent[0]);
+
+ /*
+ * Wait for the transaction to start
+ */
+ ret = read(to_child[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(ldb);
+
+ ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ldb_kv = get_ldb_kv(ldb);
+ assert_non_null(ldb_kv);
+ /*
+ * Add a record to the database
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+ val.data = talloc_zero_size(tmp_ctx, RECORD_SIZE);
+ assert_non_null(val.data);
+ memset(val.data, 'x', RECORD_SIZE);
+ val.length = RECORD_SIZE;
+ for (i = 0; i < ITERATIONS; i++) {
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, 0);
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
+ if (ret == LDB_ERR_BUSY && i > 0) {
+ int rc = ldb_kv->kv_ops->abort_write(ldb_kv);
+ assert_int_equal(rc, LDB_SUCCESS);
+ break;
+ }
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ assert_int_equal(ret, LDB_ERR_BUSY);
+ assert_int_not_equal(i, 0);
+
+ /*
+ * Begin a read transaction
+ */
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+ /*
+ * read the record
+ * and close the transaction
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Signal the the parent that we've done the update
+ */
+ ret = write(to_parent[1], "GO", 2);
+ assert_int_equal(ret, 2);
+ exit(0);
+ }
+
+ close(to_child[0]);
+ close(to_parent[1]);
+
+ /*
+ * Begin a read transaction
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Signal the child process
+ */
+ ret = write(to_child[1], "GO", 2);
+ assert_int_equal(ret, 2);
+
+ /*
+ * Wait for the child process to update the record
+ */
+ ret = read(to_parent[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ /*
+ * read the record
+ * and close the transaction
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, 0);
+
+ close(to_child[1]);
+ close(to_parent[0]);
+ TALLOC_FREE(tmp_ctx);
+}
+
+/*
+ * This tests forks a child process that opens a read lock and then
+ * exits. This results in a stale reader entry in the lmdb lock file.
+ */
+static void test_free_list_stale_reader(void **state)
+{
+ int ret;
+ struct test_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+ struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
+ struct ldb_val key;
+ struct ldb_val val;
+
+ const char *KEY1 = "KEY01";
+
+ /*
+ * Pipes etc to coordinate the processes
+ */
+ int to_child[2];
+ int to_parent[2];
+ char buf[2];
+ pid_t pid;
+ size_t i;
+
+ TALLOC_CTX *tmp_ctx;
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ ret = pipe(to_child);
+ assert_int_equal(ret, 0);
+ ret = pipe(to_parent);
+ assert_int_equal(ret, 0);
+ /*
+ * Now fork a new process
+ */
+
+ pid = fork();
+ if (pid == 0) {
+ /*
+ * Child process
+ */
+
+ struct ldb_context *ldb = NULL;
+ close(to_child[1]);
+ close(to_parent[0]);
+
+ /*
+ * Wait for the parent to get ready
+ */
+ ret = read(to_child[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(ldb);
+
+ ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ldb_kv = get_ldb_kv(ldb);
+ assert_non_null(ldb_kv);
+
+ /*
+ * Begin a read transaction
+ */
+ ret = ldb_kv->kv_ops->lock_read(ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Now exit with out releasing the read lock
+ * this will result in a stale entry in the
+ * read lock table.
+ */
+
+ exit(0);
+ }
+
+ close(to_child[0]);
+ close(to_parent[1]);
+
+ /*
+ * Tell the child to start
+ */
+ ret = write(to_child[1], "GO", 2);
+ assert_int_equal(ret, 2);
+
+ close(to_child[1]);
+ close(to_parent[0]);
+
+ /*
+ * Now wait for the child process to complete
+ */
+ waitpid(pid, NULL, 0);
+
+ /*
+ * Add a record to the database
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+ val.data = talloc_zero_size(tmp_ctx, RECORD_SIZE);
+ assert_non_null(val.data);
+ memset(val.data, 'x', RECORD_SIZE);
+ val.length = RECORD_SIZE;
+ for (i = 0; i < ITERATIONS; i++) {
+ ret = ldb_kv->kv_ops->begin_write(ldb_kv);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
+ if (ret == LDB_ERR_BUSY && i > 0) {
+ int rc = ldb_kv->kv_ops->abort_write(ldb_kv);
+ assert_int_equal(rc, LDB_SUCCESS);
+ break;
+ }
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv->kv_ops->finish_write(ldb_kv);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ /*
+ * We now do an explicit clear of stale readers at the start of a
+ * write transaction so should not get LDB_ERR_BUSY any more
+ * assert_int_equal(ret, LDB_ERR_BUSY);
+ */
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_not_equal(i, 0);
+
+ /*
+ * Begin a read transaction
+ */
+ ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+ /*
+ * read the record
+ * and close the transaction
+ */
+ key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
+ key.length = strlen(KEY1) + 1;
+
+ ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ TALLOC_FREE(tmp_ctx);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_free_list_no_read_lock, setup, teardown),
+ cmocka_unit_test_setup_teardown(
+ test_free_list_read_lock, setup, teardown),
+ cmocka_unit_test_setup_teardown(
+ test_free_list_stale_reader, setup, teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_lmdb_size_test.c b/lib/ldb/tests/ldb_lmdb_size_test.c
new file mode 100644
index 0000000..95eba87
--- /dev/null
+++ b/lib/ldb/tests/ldb_lmdb_size_test.c
@@ -0,0 +1,249 @@
+/*
+ * lmdb backend specific tests for ldb
+ * Tests for truncated index keys
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * These tests confirm that database sizes of > 4GB are supported
+ * Due to the disk space requirement they are not run as part of the normal
+ * self test runs.
+ *
+ * Setup and tear down code copied from ldb_mod_op_test.c
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include <lmdb.h>
+
+
+#define TEST_BE "mdb"
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+};
+
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int ldbtest_noconn_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_noconn_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static int ldbtest_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ int ret;
+ /*
+ * We need to to set GUID index mode as it's required now required
+ * by LDB
+ */
+ struct ldb_ldif *ldif;
+ const char *index_ldif =
+ "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+ /*
+ * Set the lmdb map size to 8Gb
+ */
+ const char *options[] = {"lmdb_env_size:8589934592", NULL};
+
+ ldbtest_noconn_setup((void **) &test_ctx);
+
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_db_size_gt_4GB(void **state)
+{
+ int ret, x;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ const int MB = 1024 * 1024;
+ char *blob = NULL;
+
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ blob = talloc_zero_size(tmp_ctx, (MB + 1));
+ assert_non_null(blob);
+ memset(blob, 'x', MB);
+
+
+ /*
+ * Write 6144 1Mb records to the database, this will require more than
+ * 4GiB of disk space
+ */
+ for (x = 0; x < 6144; x++) {
+ char uuid[24];
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /*
+ * Generate a unique dn for each record
+ */
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test%d", x);
+ assert_non_null(msg->dn);
+
+ /*
+ * Generate a unique uuid for each added record
+ */
+ sprintf(uuid, "000000000000%04d", x);
+ ret = ldb_msg_add_string(msg, "objectUUID", uuid);
+ assert_int_equal(ret, 0);
+
+ ldb_transaction_start(test_ctx->ldb);
+ ret = ldb_msg_add_string(msg, "blob", blob);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+ ldb_transaction_commit(test_ctx->ldb);
+
+ TALLOC_FREE(msg);
+ }
+ talloc_free(tmp_ctx);
+ {
+ struct stat s;
+ ret = stat(test_ctx->dbfile, &s);
+ assert_int_equal(ret, 0);
+ /*
+ * There should have been at least 6GiB written to disk
+ */
+ assert_true(s.st_size > (6144LL * MB));
+ }
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_db_size_gt_4GB,
+ ldbtest_setup,
+ ldbtest_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_lmdb_test.c b/lib/ldb/tests/ldb_lmdb_test.c
new file mode 100644
index 0000000..798a191
--- /dev/null
+++ b/lib/ldb/tests/ldb_lmdb_test.c
@@ -0,0 +1,590 @@
+/*
+ * lmdb backend specific tests for ldb
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * lmdb backend specific tests for ldb
+ *
+ * Setup and tear down code copied from ldb_mod_op_test.c
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include "../ldb_tdb/ldb_tdb.h"
+#include "../ldb_mdb/ldb_mdb.h"
+#include "../ldb_key_value/ldb_kv.h"
+
+#define TEST_BE "mdb"
+
+#define LMDB_MAX_KEY_SIZE 511
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+};
+
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int ldbtest_noconn_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_noconn_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static int ldbtest_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ int ret;
+ struct ldb_ldif *ldif;
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+
+ ldbtest_noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_ldb_add_key_len_gt_max(void **state)
+{
+ int ret;
+ int xs_size = 0;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *xs = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /*
+ * The zero terminator is part of the key if we were not in
+ * GUID mode
+ */
+
+ xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */
+ xs_size += 1; /* want key on char too long */
+ xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
+ memset(xs, 'x', xs_size);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_key_len_2x_gt_max(void **state)
+{
+ int ret;
+ int xs_size = 0;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *xs = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /*
+ * The zero terminator is part of the key if we were not in
+ * GUID mode
+ */
+
+ xs_size = 2 * LMDB_MAX_KEY_SIZE;
+ xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
+ memset(xs, 'x', xs_size);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_key_len_eq_max(void **state)
+{
+ int ret;
+ int xs_size = 0;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *xs = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /*
+ * The zero terminator is part of the key if we were not in
+ * GUID mode
+ */
+
+ xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */
+ xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
+ memset(xs, 'x', xs_size);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+static int ldbtest_setup_noguid(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ int ret;
+
+ ldbtest_noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static void test_ldb_add_special_key_len_gt_max(void **state)
+{
+ int ret;
+ int xs_size = 0;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *xs = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /*
+ * The zero terminator is part of the key if we were not in
+ * GUID mode
+ */
+
+ xs_size = LMDB_MAX_KEY_SIZE - 5; /* "dn=@" and the zero terminator */
+ xs_size += 1; /* want key on char too long */
+ xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
+ memset(xs, 'x', xs_size);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "@%s", xs);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_special_key_len_eq_max(void **state)
+{
+ int ret;
+ int xs_size = 0;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *xs = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /*
+ * The zero terminator is part of the key if we were not in
+ * GUID mode
+ */
+
+ xs_size = LMDB_MAX_KEY_SIZE - 5; /* "dn=@" and the zero terminator */
+ xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
+ memset(xs, 'x', xs_size);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "@%s", xs);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_dn_no_guid_mode(void **state)
+{
+ int ret;
+ int xs_size = 0;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *xs = NULL;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /*
+ * The zero terminator is part of the key if we were not in
+ * GUID mode
+ */
+
+ xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */
+ xs_size += 1; /* want key on char too long */
+ xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
+ memset(xs, 'x', xs_size);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
+
+ talloc_free(tmp_ctx);
+}
+
+static struct MDB_env *get_mdb_env(struct ldb_context *ldb)
+{
+ void *data = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ struct lmdb_private *lmdb = NULL;
+ struct MDB_env *env = NULL;
+
+ data = ldb_module_get_private(ldb->modules);
+ assert_non_null(data);
+
+ ldb_kv = talloc_get_type(data, struct ldb_kv_private);
+ assert_non_null(ldb_kv);
+
+ lmdb = ldb_kv->lmdb_private;
+ assert_non_null(lmdb);
+
+ env = lmdb->env;
+ assert_non_null(env);
+
+ return env;
+}
+
+static void test_multiple_opens(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ struct ldb_context *ldb2 = NULL;
+ struct ldb_context *ldb3 = NULL;
+ struct MDB_env *env1 = NULL;
+ struct MDB_env *env2 = NULL;
+ struct MDB_env *env3 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database again
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb2 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb2, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb3 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+ /*
+ * We now have 3 ldb's open pointing to the same on disk database
+ * they should all share the same MDB_env
+ */
+ env1 = get_mdb_env(ldb1);
+ env2 = get_mdb_env(ldb2);
+ env3 = get_mdb_env(ldb3);
+
+ assert_ptr_equal(env1, env2);
+ assert_ptr_equal(env1, env3);
+}
+
+static void test_multiple_opens_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ struct ldb_context *ldb2 = NULL;
+ struct MDB_env *env1 = NULL;
+ struct MDB_env *env2 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database again
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb2 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb2, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ env1 = get_mdb_env(ldb1);
+ env2 = get_mdb_env(ldb2);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct ldb_context *ldb3 = NULL;
+ struct MDB_env *env3 = NULL;
+
+ close(pipes[0]);
+ ldb3 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
+ if (ret != 0) {
+ print_error(__location__": ldb_connect returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+ env3 = get_mdb_env(ldb3);
+ if (env1 != env2) {
+ print_error(__location__": env1 != env2\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (env1 == env3) {
+ print_error(__location__": env1 == env3\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_key_len_eq_max,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_key_len_gt_max,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_key_len_2x_gt_max,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_special_key_len_eq_max,
+ ldbtest_setup_noguid,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_special_key_len_gt_max,
+ ldbtest_setup_noguid,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_dn_no_guid_mode,
+ ldbtest_setup_noguid,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_multiple_opens,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_multiple_opens_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_match_test.c b/lib/ldb/tests/ldb_match_test.c
new file mode 100644
index 0000000..1bb56d0
--- /dev/null
+++ b/lib/ldb/tests/ldb_match_test.c
@@ -0,0 +1,313 @@
+/*
+ * Tests exercising the ldb match operations.
+ *
+ *
+ * Copyright (C) Catalyst.NET Ltd 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "../common/ldb_match.c"
+
+#include "../include/ldb.h"
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+};
+
+static int ldb_test_canonicalise(
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ const struct ldb_val *in,
+ struct ldb_val *out)
+{
+ out->length = in->length;
+ out->data = in->data;
+ return 0;
+}
+
+static int setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ struct ldb_schema_syntax *syntax = NULL;
+ int ret;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ syntax = talloc_zero(test_ctx, struct ldb_schema_syntax);
+ assert_non_null(syntax);
+ syntax->canonicalise_fn = ldb_test_canonicalise;
+
+ ret = ldb_schema_attribute_add_with_syntax(
+ test_ctx->ldb, "a", LDB_ATTR_FLAG_FIXED, syntax);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ talloc_free(*state);
+ return 0;
+}
+
+static void escape_string(uint8_t *buf, size_t buflen,
+ const uint8_t *s, size_t len)
+{
+ size_t i;
+ size_t j = 0;
+ for (i = 0; i < len; i++) {
+ if (j == buflen - 1) {
+ goto fin;
+ }
+ if (s[i] >= 0x20) {
+ buf[j] = s[i];
+ j++;
+ } else {
+ if (j >= buflen - 4) {
+ goto fin;
+ }
+ /* utf-8 control char representation */
+ buf[j] = 0xE2;
+ buf[j + 1] = 0x90;
+ buf[j + 2] = 0x80 + s[i];
+ j+= 3;
+ }
+ }
+fin:
+ buf[j] = 0;
+}
+
+
+/*
+ * The wild card pattern "attribute=*" is parsed as an LDB_OP_PRESENT operation
+ * rather than a LDB_OP_????
+ *
+ * This test serves to document that behaviour, and to confirm that
+ * ldb_wildcard_compare handles this case appropriately.
+ */
+static void test_wildcard_match_star(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ bool matched = false;
+ int ret;
+
+ uint8_t value[] = "The value.......end";
+ struct ldb_val val = {
+ .data = value,
+ .length = (sizeof(value))
+ };
+ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, "a=*");
+ assert_non_null(tree);
+
+ ret = ldb_wildcard_compare(ctx->ldb, tree, val, &matched);
+ assert_false(matched);
+ assert_int_equal(LDB_ERR_INAPPROPRIATE_MATCHING, ret);
+}
+
+/*
+ * Test basic wild card matching
+ *
+ */
+struct wildcard_test {
+ uint8_t *val;
+ size_t val_size;
+ const char *search;
+ bool should_match;
+ bool fold;
+};
+
+/*
+ * Q: Why this macro rather than plain struct values?
+ * A: So we can get the size of the const char[] value while it is still a
+ * true array, not a pointer.
+ *
+ * Q: but why not just use strlen?
+ * A: so values can contain '\0', which we supposedly allow.
+ */
+
+#define TEST_ENTRY(val, search, should_match, fold) \
+ { \
+ (uint8_t*)discard_const(val), \
+ sizeof(val) - 1, \
+ search, \
+ should_match, \
+ fold \
+ }
+
+static void test_wildcard_match(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ size_t failed = 0;
+ size_t i;
+ struct wildcard_test tests[] = {
+ TEST_ENTRY(" 1 0", "1*0*", true, true),
+ TEST_ENTRY(" 1 0", "1 *0", true, true),
+ TEST_ENTRY(" 1 0", "*1 0", true, true),
+ TEST_ENTRY("1 0", "*1 0", true, true),
+ TEST_ENTRY("The value.......end", "*end", true, true),
+ TEST_ENTRY("The value.......end", "*fend", false, true),
+ TEST_ENTRY("The value.......end", "*eel", false, true),
+ TEST_ENTRY("The value.......end", "*d", true, true),
+ TEST_ENTRY("The value.......end", "*D*", true, true),
+ TEST_ENTRY("The value.......end", "*e*d*", true, true),
+ TEST_ENTRY("end", "*e*d*", true, true),
+ TEST_ENTRY("end", " *e*d*", true, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0aaaaaaaaaaaa", "*aaaaa", true, true),
+ TEST_ENTRY("1.0..0.0.0.0.0.0.0aAaaaAAAAAAA", "*a", true, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0.0.0aaaa", "*aaaaa", false, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0.0.0", "*0.0", true, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0.0.0", "*0.0.0", true, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0.0", "1*0*0*0*0*0*0*0*0*0", true,
+ true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0", "1*0*0*0*0*0*0*0*0*0", false,
+ true),
+ TEST_ENTRY("1.0.0.0.000.0.0.0.0", "1*0*0*0*0*0*0*0*0*0", true,
+ true),
+ TEST_ENTRY("1\n0\r0\t000.0.0.0.0", "1*0*0*0*0*0*0*0*0", true,
+ true),
+ /*
+ * We allow NUL bytes and redundant spaces in non-casefolding
+ * syntaxes.
+ */
+ TEST_ENTRY(" 1 0", "*1 0", true, false),
+ TEST_ENTRY(" 1 0", "*1 0", true, false),
+ TEST_ENTRY("1 0", "*1 0", false, false),
+ TEST_ENTRY("1\x00 x", "1*x", true, false),
+ TEST_ENTRY("1\x00 x", "*x", true, false),
+ TEST_ENTRY("1\x00 x", "*x*", true, false),
+ TEST_ENTRY("1\x00 x", "* *", true, false),
+ TEST_ENTRY("1\x00 x", "1*", true, false),
+ TEST_ENTRY("1\x00 b* x", "1*b*", true, false),
+ TEST_ENTRY("1.0..0.0.0.0.0.0.0aAaaaAAAAAAA", "*a", false, false),
+ };
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ bool matched;
+ int ret;
+ struct ldb_val val = {
+ .data = (uint8_t *)tests[i].val,
+ .length = tests[i].val_size
+ };
+ const char *attr = tests[i].fold ? "objectclass" : "birthLocation";
+ const char *s = talloc_asprintf(ctx, "%s=%s",
+ attr, tests[i].search);
+ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, s);
+ assert_non_null(tree);
+ ret = ldb_wildcard_compare(ctx->ldb, tree, val, &matched);
+ if (ret != LDB_SUCCESS) {
+ uint8_t buf[100];
+ escape_string(buf, sizeof(buf),
+ tests[i].val, tests[i].val_size);
+ print_error("%zu val: «%s», search «%s» FAILED with %d\n",
+ i, buf, tests[i].search, ret);
+ failed++;
+ }
+ if (matched != tests[i].should_match) {
+ uint8_t buf[100];
+ escape_string(buf, sizeof(buf),
+ tests[i].val, tests[i].val_size);
+ print_error("%zu val: «%s», search «%s» should %s\n",
+ i, buf, tests[i].search,
+ matched ? "not match" : "match");
+ failed++;
+ }
+ }
+ if (failed != 0) {
+ fail_msg("wrong results for %zu/%zu wildcard searches\n",
+ failed, ARRAY_SIZE(tests));
+ }
+}
+
+#undef TEST_ENTRY
+
+
+/*
+ * ldb_handler_copy and ldb_val_dup over allocate by one and add a trailing '\0'
+ * to the data, to make them safe to use the C string functions on.
+ *
+ * However testing for the trailing '\0' is not the correct way to test for
+ * the end of a value, the length should be checked instead.
+ */
+static void test_wildcard_match_end_condition(void **state)
+{
+ struct ldbtest_ctx *ctx = *state;
+ bool matched = false;
+
+ uint8_t value[] = "hellomynameisbobx";
+ struct ldb_val val = {
+ .data = talloc_memdup(NULL, value, sizeof(value)),
+ .length = (sizeof(value) - 2)
+ };
+ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, "a=*hello*mynameis*bob");
+ assert_non_null(tree);
+
+ ldb_wildcard_compare(ctx->ldb, tree, val, &matched);
+ assert_true(matched);
+}
+
+/*
+ * Note: to run under valgrind use:
+ * valgrind \
+ * --suppressions=lib/ldb/tests/ldb_match_test.valgrind \
+ * bin/ldb_match_test
+ */
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_wildcard_match_star,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_wildcard_match,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_wildcard_match_end_condition,
+ setup,
+ teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_match_test.valgrind b/lib/ldb/tests/ldb_match_test.valgrind
new file mode 100644
index 0000000..660bd5a
--- /dev/null
+++ b/lib/ldb/tests/ldb_match_test.valgrind
@@ -0,0 +1,16 @@
+{
+ Memory allocated in set-up
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:setup
+}
+{
+ Memory allocated by ldb_init
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ ...
+ fun:ldb_init
+}
diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
new file mode 100644
index 0000000..f620fc1
--- /dev/null
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -0,0 +1,4724 @@
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+
+#define TEVENT_DEPRECATED 1
+#include <tevent.h>
+
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+
+#define DEFAULT_BE "tdb"
+
+#ifndef TEST_BE
+#define TEST_BE DEFAULT_BE
+#endif /* TEST_BE */
+
+#ifdef TEST_LMDB
+#include "lmdb.h"
+#include "../ldb_tdb/ldb_tdb.h"
+#include "../ldb_mdb/ldb_mdb.h"
+#endif
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+ char *debug_string;
+};
+
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int ldbtest_noconn_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_noconn_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static void test_connect(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ int ret;
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+}
+
+static struct ldb_message *get_test_ldb_message(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb)
+{
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ int ret;
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new(msg, ldb, "dc=samba,dc=org");
+ assert_non_null(msg->dn);
+ ret = ldb_msg_add_string(msg, "public", "key");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "supersecret", "password");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "binary", "\xff\xff\0");
+ assert_int_equal(ret, LDB_SUCCESS);
+ return msg;
+}
+
+static void test_ldif_message(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *got_ldif;
+ const char *expected_ldif =
+ "dn: dc=samba,dc=org\n"
+ "changetype: add\n"
+ "public: key\n"
+ "supersecret: password\n"
+ "binary:: //8=\n"
+ "\n";
+
+ struct ldb_message *msg = get_test_ldb_message(test_ctx,
+ test_ctx->ldb);
+
+ got_ldif = ldb_ldif_message_string(test_ctx->ldb,
+ test_ctx,
+ LDB_CHANGETYPE_ADD,
+ msg);
+ assert_string_equal(got_ldif, expected_ldif);
+ TALLOC_FREE(got_ldif);
+}
+
+static void test_ldif_message_redacted(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ int ret;
+ char *got_ldif;
+ const char *expected_ldif =
+ "dn: dc=samba,dc=org\n"
+ "changetype: add\n"
+ "public: key\n"
+ "# supersecret::: REDACTED SECRET ATTRIBUTE\n"
+ "binary:: //8=\n"
+ "\n";
+
+ const char *secret_attrs[] = {
+ "supersecret",
+ NULL
+ };
+
+ struct ldb_message *msg = ldb_msg_new(test_ctx);
+
+ ldb_set_opaque(test_ctx->ldb,
+ LDB_SECRET_ATTRIBUTE_LIST_OPAQUE,
+ secret_attrs);
+
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new(msg, test_ctx->ldb, "dc=samba,dc=org");
+ ret = ldb_msg_add_string(msg, "public", "key");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "supersecret", "password");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "binary", "\xff\xff\0");
+ assert_int_equal(ret, LDB_SUCCESS);
+ got_ldif = ldb_ldif_message_redacted_string(test_ctx->ldb,
+ test_ctx,
+ LDB_CHANGETYPE_ADD,
+ msg);
+ assert_string_equal(got_ldif, expected_ldif);
+ TALLOC_FREE(got_ldif);
+ assert_int_equal(ret, 0);
+}
+
+static int ldbtest_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ struct ldb_ldif *ldif;
+#ifdef GUID_IDX
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+#else
+ const char *index_ldif = "\n";
+#endif
+ int ret;
+
+ ldbtest_noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_ldb_add(void **state)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_search(void **state)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_dn *basedn2;
+ struct ldb_result *result = NULL;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = basedn;
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val1");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcde1");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ basedn2 = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test2");
+ assert_non_null(basedn2);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = basedn2;
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val2");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcde2");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+ ldb_dn_get_linearized(basedn));
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn2,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+ ldb_dn_get_linearized(basedn2));
+
+ talloc_free(tmp_ctx);
+}
+
+static int base_search_count(struct ldbtest_ctx *test_ctx, const char *entry_dn)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ int ret;
+ int count;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", entry_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+
+ count = result->count;
+ talloc_free(tmp_ctx);
+ return count;
+}
+
+static int sub_search_count(struct ldbtest_ctx *test_ctx,
+ const char *base_dn,
+ const char *filter)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ int ret;
+ int count;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+ LDB_SCOPE_SUBTREE, NULL, "%s", filter);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+
+ count = result->count;
+ talloc_free(tmp_ctx);
+ return count;
+}
+
+/* In general it would be better if utility test functions didn't assert
+ * but only returned a value, then assert in the test shows correct
+ * line
+ */
+static void assert_dn_exists(struct ldbtest_ctx *test_ctx,
+ const char *entry_dn)
+{
+ int count;
+
+ count = base_search_count(test_ctx, entry_dn);
+ assert_int_equal(count, 1);
+}
+
+static void assert_dn_doesnt_exist(struct ldbtest_ctx *test_ctx,
+ const char *entry_dn)
+{
+ int count;
+
+ count = base_search_count(test_ctx, entry_dn);
+ assert_int_equal(count, 0);
+}
+
+static void add_dn_with_cn(struct ldbtest_ctx *test_ctx,
+ struct ldb_dn *dn,
+ const char *cn_value,
+ const char *uuid_value)
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ assert_dn_doesnt_exist(test_ctx,
+ ldb_dn_get_linearized(dn));
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+ msg->dn = dn;
+
+ ret = ldb_msg_add_string(msg, "cn", cn_value);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", uuid_value);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_exists(test_ctx,
+ ldb_dn_get_linearized(dn));
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_del(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ const char *basedn = "dc=ldb_del_test";
+ struct ldb_dn *dn;
+
+ dn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "%s", basedn);
+ assert_non_null(dn);
+
+ add_dn_with_cn(test_ctx, dn,
+ "test_del_cn_val",
+ "0123456789abcdef");
+
+ ret = ldb_delete(test_ctx->ldb, dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_doesnt_exist(test_ctx, basedn);
+}
+
+static void test_ldb_del_noexist(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *basedn;
+ int ret;
+
+ basedn = ldb_dn_new(test_ctx, test_ctx->ldb, "dc=nosuchplace");
+ assert_non_null(basedn);
+
+ ret = ldb_delete(test_ctx->ldb, basedn);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+}
+
+static void test_ldb_handle(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_request *request = NULL;
+ struct ldb_request *request2 = NULL;
+ struct ldb_result *res = NULL;
+ const char *attrs[] = { "cn", NULL };
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ assert_non_null(res);
+
+ ret = ldb_build_search_req(&request, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ NULL);
+ assert_int_equal(ret, 0);
+
+ /* We are against ldb_tdb, so expect private event contexts */
+ assert_ptr_not_equal(ldb_handle_get_event_context(request->handle),
+ ldb_get_event_context(test_ctx->ldb));
+
+ ret = ldb_build_search_req(&request2, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ request);
+ assert_int_equal(ret, 0);
+
+ /* Expect that same event context will be chained */
+ assert_ptr_equal(ldb_handle_get_event_context(request->handle),
+ ldb_handle_get_event_context(request2->handle));
+
+ /* Now force this to use the global context */
+ ldb_handle_use_global_event_context(request2->handle);
+ assert_ptr_equal(ldb_handle_get_event_context(request2->handle),
+ ldb_get_event_context(test_ctx->ldb));
+
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_build_search_req(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ struct ldb_request *request = NULL;
+ struct ldb_request *request2 = NULL;
+ struct ldb_result *res = NULL;
+ const char *attrs[] = { "cn", NULL };
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ assert_non_null(res);
+
+ ret = ldb_build_search_req(&request, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ NULL);
+ assert_int_equal(ret, 0);
+
+ assert_int_equal(request->operation, LDB_SEARCH);
+ assert_ptr_equal(request->op.search.base, basedn);
+ assert_int_equal(request->op.search.scope, LDB_SCOPE_BASE);
+ assert_non_null(request->op.search.tree);
+ assert_ptr_equal(request->op.search.attrs, attrs);
+ assert_ptr_equal(request->context, res);
+ assert_ptr_equal(request->callback, ldb_search_default_callback);
+
+ ret = ldb_build_search_req(&request2, test_ctx->ldb, tmp_ctx,
+ basedn, LDB_SCOPE_BASE,
+ NULL, attrs, NULL, res,
+ ldb_search_default_callback,
+ request);
+ assert_int_equal(ret, 0);
+ assert_ptr_equal(request, request2->handle->parent);
+ assert_int_equal(request->starttime, request2->starttime);
+ assert_int_equal(request->timeout, request2->timeout);
+
+ talloc_free(tmp_ctx);
+}
+
+static void add_keyval(struct ldbtest_ctx *test_ctx,
+ const char *key,
+ const char *val,
+ const char *uuid)
+{
+ int ret;
+ struct ldb_message *msg;
+
+ msg = ldb_msg_new(test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "%s=%s", key, val);
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, key, val);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID", uuid);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ talloc_free(msg);
+}
+
+static struct ldb_result *get_keyval(struct ldbtest_ctx *test_ctx,
+ const char *key,
+ const char *val)
+{
+ int ret;
+ struct ldb_result *result;
+ struct ldb_dn *basedn;
+
+ basedn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "%s=%s", key, val);
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb, test_ctx, &result, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, 0);
+
+ return result;
+}
+
+static void test_transactions(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_result *res;
+
+ /* start lev-0 transaction */
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ add_keyval(test_ctx, "vegetable", "carrot",
+ "0123456789abcde0");
+
+ /* commit lev-0 transaction */
+ ret = ldb_transaction_commit(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ /* start another lev-1 nested transaction */
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ add_keyval(test_ctx, "fruit", "apple",
+ "0123456789abcde1");
+
+ /* abort lev-1 nested transaction */
+ ret = ldb_transaction_cancel(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ res = get_keyval(test_ctx, "vegetable", "carrot");
+ assert_non_null(res);
+ assert_int_equal(res->count, 1);
+
+ res = get_keyval(test_ctx, "fruit", "apple");
+ assert_non_null(res);
+ assert_int_equal(res->count, 0);
+}
+
+static void test_nested_transactions(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_result *res;
+
+ /* start lev-0 transaction */
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ add_keyval(test_ctx, "vegetable", "carrot",
+ "0123456789abcde0");
+
+
+ /* start another lev-1 nested transaction */
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ add_keyval(test_ctx, "fruit", "apple",
+ "0123456789abcde1");
+
+ /* abort lev-1 nested transaction */
+ ret = ldb_transaction_cancel(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ /* commit lev-0 transaction */
+ ret = ldb_transaction_commit(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ res = get_keyval(test_ctx, "vegetable", "carrot");
+ assert_non_null(res);
+ assert_int_equal(res->count, 1);
+
+ /* This documents the current ldb behaviour, i.e. nested
+ * transactions are not supported. And the cancellation of the nested
+ * transaction has no effect.
+ */
+ res = get_keyval(test_ctx, "fruit", "apple");
+ assert_non_null(res);
+ assert_int_equal(res->count, 1);
+}
+struct ldb_mod_test_ctx {
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *entry_dn;
+};
+
+struct keyval {
+ const char *key;
+ const char *val;
+};
+
+static struct ldb_message *build_mod_msg(TALLOC_CTX *mem_ctx,
+ struct ldbtest_ctx *test_ctx,
+ const char *dn,
+ int modify_flags,
+ struct keyval *kvs)
+{
+ struct ldb_message *msg;
+ int ret;
+ int i;
+
+ msg = ldb_msg_new(mem_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "%s", dn);
+ assert_non_null(msg->dn);
+
+ for (i = 0; kvs[i].key != NULL; i++) {
+ if (modify_flags) {
+ ret = ldb_msg_add_empty(msg, kvs[i].key,
+ modify_flags, NULL);
+ assert_int_equal(ret, 0);
+ }
+
+ if (kvs[i].val) {
+ ret = ldb_msg_add_string(msg, kvs[i].key, kvs[i].val);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ }
+
+ return msg;
+}
+
+static void ldb_test_add_data(TALLOC_CTX *mem_ctx,
+ struct ldbtest_ctx *ldb_test_ctx,
+ const char *basedn,
+ struct keyval *kvs)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+ struct ldb_result *result = NULL;
+ int ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = build_mod_msg(tmp_ctx, ldb_test_ctx,
+ basedn, 0, kvs);
+ assert_non_null(msg);
+
+ ret = ldb_add(ldb_test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_search(ldb_test_ctx->ldb, tmp_ctx, &result, msg->dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+ ldb_dn_get_linearized(msg->dn));
+
+ talloc_free(tmp_ctx);
+}
+
+static void ldb_test_remove_data(TALLOC_CTX *mem_ctx,
+ struct ldbtest_ctx *ldb_test_ctx,
+ const char *strdn)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *basedn;
+ int ret;
+ size_t count;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ assert_non_null(tmp_ctx);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, ldb_test_ctx->ldb,
+ "%s", strdn);
+ assert_non_null(basedn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, basedn);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_NO_SUCH_OBJECT);
+
+ count = base_search_count(ldb_test_ctx, ldb_dn_get_linearized(basedn));
+ assert_int_equal(count, 0);
+
+ talloc_free(tmp_ctx);
+}
+
+static void mod_test_add_data(struct ldb_mod_test_ctx *mod_test_ctx,
+ struct keyval *kvs)
+{
+ ldb_test_add_data(mod_test_ctx,
+ mod_test_ctx->ldb_test_ctx,
+ mod_test_ctx->entry_dn,
+ kvs);
+}
+
+static void mod_test_remove_data(struct ldb_mod_test_ctx *mod_test_ctx)
+{
+ ldb_test_remove_data(mod_test_ctx,
+ mod_test_ctx->ldb_test_ctx,
+ mod_test_ctx->entry_dn);
+}
+
+static struct ldb_result *run_mod_test(struct ldb_mod_test_ctx *mod_test_ctx,
+ int modify_flags,
+ struct keyval *kvs)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ struct ldb_message *mod_msg;
+ struct ldb_dn *basedn;
+ struct ldbtest_ctx *ldb_test_ctx;
+ int ret;
+
+ ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+ tmp_ctx = talloc_new(mod_test_ctx);
+ assert_non_null(tmp_ctx);
+
+ mod_msg = build_mod_msg(tmp_ctx, ldb_test_ctx, mod_test_ctx->entry_dn,
+ modify_flags, kvs);
+ assert_non_null(mod_msg);
+
+ ret = ldb_modify(ldb_test_ctx->ldb, mod_msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, ldb_test_ctx->ldb,
+ "%s", mod_test_ctx->entry_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(ldb_test_ctx->ldb, mod_test_ctx, &res, basedn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(res);
+ assert_int_equal(res->count, 1);
+ assert_string_equal(ldb_dn_get_linearized(res->msgs[0]->dn),
+ ldb_dn_get_linearized(mod_msg->dn));
+
+ talloc_free(tmp_ctx);
+ return res;
+}
+
+static int ldb_modify_test_setup(void **state)
+{
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct ldb_mod_test_ctx *mod_test_ctx;
+ struct keyval kvs[] = {
+ { "cn", "test_mod_cn" },
+ { "objectUUID", "0123456789abcdef"},
+ { NULL, NULL },
+ };
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ mod_test_ctx = talloc(ldb_test_ctx, struct ldb_mod_test_ctx);
+ assert_non_null(mod_test_ctx);
+
+ mod_test_ctx->entry_dn = "dc=mod_test_entry";
+ mod_test_ctx->ldb_test_ctx = ldb_test_ctx;
+
+ mod_test_remove_data(mod_test_ctx);
+ mod_test_add_data(mod_test_ctx, kvs);
+ *state = mod_test_ctx;
+ return 0;
+}
+
+static int ldb_modify_test_teardown(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldbtest_ctx *ldb_test_ctx;
+
+ ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+ mod_test_remove_data(mod_test_ctx);
+ talloc_free(mod_test_ctx);
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_modify_add_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct keyval mod_kvs[] = {
+ { "name", "test_mod_name" },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_ADD, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn is intact and name was added */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal((const char *)el->values[0].data, "test_mod_cn");
+
+ el = ldb_msg_find_element(res->msgs[0], "name");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal((const char *)el->values[0].data, "test_mod_name");
+}
+
+static void test_ldb_modify_extend_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct keyval mod_kvs[] = {
+ { "cn", "test_mod_cn2" },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_ADD, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn was extended with another value */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 2);
+ assert_string_equal((const char *)el->values[0].data, "test_mod_cn");
+ assert_string_equal((const char *)el->values[1].data, "test_mod_cn2");
+}
+
+static void test_ldb_modify_add_key_noval(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message *mod_msg;
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct ldb_message_element *el;
+ int ret;
+
+ ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+ mod_msg = ldb_msg_new(mod_test_ctx);
+ assert_non_null(mod_msg);
+
+ mod_msg->dn = ldb_dn_new_fmt(mod_msg, ldb_test_ctx->ldb,
+ "%s", mod_test_ctx->entry_dn);
+ assert_non_null(mod_msg->dn);
+
+ el = talloc_zero(mod_msg, struct ldb_message_element);
+ el->flags = LDB_FLAG_MOD_ADD;
+ assert_non_null(el);
+ el->name = talloc_strdup(el, "cn");
+ assert_non_null(el->name);
+
+ mod_msg->elements = el;
+ mod_msg->num_elements = 1;
+
+ ret = ldb_modify(ldb_test_ctx->ldb, mod_msg);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+}
+
+static void test_ldb_modify_replace_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ const char *new_cn = "new_cn";
+ struct keyval mod_kvs[] = {
+ { "cn", new_cn },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn was replaced */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal((const char *)el->values[0].data, new_cn);
+}
+
+static void test_ldb_modify_replace_noexist_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct keyval mod_kvs[] = {
+ { "name", "name_val" },
+ { NULL, NULL },
+ };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, mod_kvs);
+ assert_non_null(res);
+
+ /* Check cn is intact and name was added */
+ assert_int_equal(res->count, 1);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal((const char *)el->values[0].data, "test_mod_cn");
+
+ el = ldb_msg_find_element(res->msgs[0], mod_kvs[0].key);
+ assert_non_null(el);
+ assert_int_equal(el->num_values, 1);
+ assert_string_equal((const char *)el->values[0].data, mod_kvs[0].val);
+}
+
+static void test_ldb_modify_replace_zero_vals(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "cn", NULL },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, kvs);
+ assert_non_null(res);
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_null(el);
+}
+
+static void test_ldb_modify_replace_noexist_key_zero_vals(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "noexist_key", NULL },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, kvs);
+ assert_non_null(res);
+
+ /* cn should be intact */
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_non_null(el);
+}
+
+static void test_ldb_modify_del_key(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "cn", NULL },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_DELETE, kvs);
+ assert_non_null(res);
+
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_null(el);
+}
+
+static void test_ldb_modify_del_keyval(void **state)
+{
+ struct ldb_mod_test_ctx *mod_test_ctx = \
+ talloc_get_type_abort(*state,
+ struct ldb_mod_test_ctx);
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct keyval kvs[] = {
+ { "cn", "test_mod_cn" },
+ { NULL, NULL },
+ };
+
+ /* cn must be gone */
+ res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_DELETE, kvs);
+ assert_non_null(res);
+
+ el = ldb_msg_find_element(res->msgs[0], "cn");
+ assert_null(el);
+}
+
+struct search_test_ctx {
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *base_dn;
+};
+
+static char *get_full_dn(TALLOC_CTX *mem_ctx,
+ struct search_test_ctx *search_test_ctx,
+ const char *rdn)
+{
+ char *full_dn;
+
+ full_dn = talloc_asprintf(mem_ctx,
+ "%s,%s", rdn, search_test_ctx->base_dn);
+ assert_non_null(full_dn);
+
+ return full_dn;
+}
+
+static void search_test_add_data(struct search_test_ctx *search_test_ctx,
+ const char *rdn,
+ struct keyval *kvs)
+{
+ char *full_dn;
+
+ full_dn = get_full_dn(search_test_ctx, search_test_ctx, rdn);
+
+ ldb_test_add_data(search_test_ctx,
+ search_test_ctx->ldb_test_ctx,
+ full_dn,
+ kvs);
+}
+
+static void search_test_remove_data(struct search_test_ctx *search_test_ctx,
+ const char *rdn)
+{
+ char *full_dn;
+
+ full_dn = talloc_asprintf(search_test_ctx,
+ "%s,%s", rdn, search_test_ctx->base_dn);
+ assert_non_null(full_dn);
+
+ ldb_test_remove_data(search_test_ctx,
+ search_test_ctx->ldb_test_ctx,
+ full_dn);
+}
+
+static int ldb_search_test_setup(void **state)
+{
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct search_test_ctx *search_test_ctx;
+ struct keyval kvs[] = {
+ { "cn", "test_search_cn" },
+ { "cn", "test_search_cn2" },
+ { "uid", "test_search_uid" },
+ { "uid", "test_search_uid2" },
+ { "objectUUID", "0123456789abcde0"},
+ { NULL, NULL },
+ };
+ struct keyval kvs2[] = {
+ { "cn", "test_search_2_cn" },
+ { "cn", "test_search_2_cn2" },
+ { "uid", "test_search_2_uid" },
+ { "uid", "test_search_2_uid2" },
+ { "objectUUID", "0123456789abcde1"},
+ { NULL, NULL },
+ };
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ search_test_ctx = talloc(ldb_test_ctx, struct search_test_ctx);
+ assert_non_null(search_test_ctx);
+
+ search_test_ctx->base_dn = "dc=search_test_entry";
+ search_test_ctx->ldb_test_ctx = ldb_test_ctx;
+
+ search_test_remove_data(search_test_ctx, "cn=test_search_cn");
+ search_test_add_data(search_test_ctx, "cn=test_search_cn", kvs);
+
+ search_test_remove_data(search_test_ctx, "cn=test_search_2_cn");
+ search_test_add_data(search_test_ctx, "cn=test_search_2_cn", kvs2);
+
+ *state = search_test_ctx;
+ return 0;
+}
+
+static int ldb_search_test_teardown(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct ldbtest_ctx *ldb_test_ctx;
+
+ ldb_test_ctx = search_test_ctx->ldb_test_ctx;
+
+ search_test_remove_data(search_test_ctx, "cn=test_search_cn");
+ search_test_remove_data(search_test_ctx, "cn=test_search_2_cn");
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void assert_attr_has_vals(struct ldb_message *msg,
+ const char *attr,
+ const char *vals[],
+ const size_t nvals)
+{
+ struct ldb_message_element *el;
+ size_t i;
+
+ el = ldb_msg_find_element(msg, attr);
+ assert_non_null(el);
+
+ assert_int_equal(el->num_values, nvals);
+ for (i = 0; i < nvals; i++) {
+ assert_string_equal((const char *)el->values[i].data,
+ vals[i]);
+ }
+}
+
+static void assert_has_no_attr(struct ldb_message *msg,
+ const char *attr)
+{
+ struct ldb_message_element *el;
+
+ el = ldb_msg_find_element(msg, attr);
+ assert_null(el);
+}
+
+static bool has_dn(struct ldb_message *msg, const char *dn)
+{
+ const char *msgdn;
+
+ msgdn = ldb_dn_get_linearized(msg->dn);
+ if (strcmp(dn, msgdn) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static void test_search_match_none(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ size_t count;
+
+ count = base_search_count(search_test_ctx->ldb_test_ctx,
+ "dc=no_such_entry");
+ assert_int_equal(count, 0);
+}
+
+static void test_search_match_one(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ const char *cn_vals[] = { "test_search_cn",
+ "test_search_cn2" };
+ const char *uid_vals[] = { "test_search_uid",
+ "test_search_uid2" };
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=test_search_cn");
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+
+ assert_attr_has_vals(result->msgs[0], "cn", cn_vals, 2);
+ assert_attr_has_vals(result->msgs[0], "uid", uid_vals, 2);
+}
+
+static void test_search_match_filter(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ const char *cn_vals[] = { "test_search_cn",
+ "test_search_cn2" };
+ const char *attrs[] = { "cn", NULL };
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ attrs,
+ "cn=test_search_cn");
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 1);
+
+ assert_attr_has_vals(result->msgs[0], "cn", cn_vals, 2);
+ assert_has_no_attr(result->msgs[0], "uid");
+}
+
+static void assert_expected(struct search_test_ctx *search_test_ctx,
+ struct ldb_message *msg)
+{
+ char *full_dn1;
+ char *full_dn2;
+ const char *cn_vals[] = { "test_search_cn",
+ "test_search_cn2" };
+ const char *uid_vals[] = { "test_search_uid",
+ "test_search_uid2" };
+ const char *cn2_vals[] = { "test_search_2_cn",
+ "test_search_2_cn2" };
+ const char *uid2_vals[] = { "test_search_2_uid",
+ "test_search_2_uid2" };
+
+ full_dn1 = get_full_dn(search_test_ctx,
+ search_test_ctx,
+ "cn=test_search_cn");
+
+ full_dn2 = get_full_dn(search_test_ctx,
+ search_test_ctx,
+ "cn=test_search_2_cn");
+
+ if (has_dn(msg, full_dn1) == true) {
+ assert_attr_has_vals(msg, "cn", cn_vals, 2);
+ assert_attr_has_vals(msg, "uid", uid_vals, 2);
+ } else if (has_dn(msg, full_dn2) == true) {
+ assert_attr_has_vals(msg, "cn", cn2_vals, 2);
+ assert_attr_has_vals(msg, "uid", uid2_vals, 2);
+ } else {
+ fail();
+ }
+}
+
+static void test_search_match_both(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=test_search_*");
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 2);
+
+ assert_expected(search_test_ctx, result->msgs[0]);
+ assert_expected(search_test_ctx, result->msgs[1]);
+}
+
+static void test_search_match_basedn(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ struct ldb_message *msg;
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "dc=nosuchdn");
+ assert_non_null(basedn);
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=*");
+ assert_int_equal(ret, 0);
+
+ /* Add 'checkBaseOnSearch' to @OPTIONS */
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "@OPTIONS");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "checkBaseOnSearch", "TRUE");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb, msg);
+ assert_int_equal(ret, 0);
+
+ /* Search again */
+ /* The search should return LDB_ERR_NO_SUCH_OBJECT */
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_SUBTREE, NULL,
+ "cn=*");
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+
+ ret = ldb_delete(search_test_ctx->ldb_test_ctx->ldb, msg->dn);
+ assert_int_equal(ret, 0);
+}
+
+
+/*
+ * This test is complex.
+ * The purpose is to test for a deadlock detected between ldb_search()
+ * and ldb_transaction_commit(). The deadlock happens if in process
+ * (1) and (2):
+ * - (1) the all-record lock is taken in ltdb_search()
+ * - (2) the ldb_transaction_start() call is made
+ * - (1) an un-indexed search starts (forced here by doing it in
+ * the callback
+ * - (2) the ldb_transaction_commit() is called.
+ * This returns LDB_ERR_BUSY if the deadlock is detected
+ *
+ * With ldb 1.1.31 and tdb 1.3.12 we avoid this only due to a missing
+ * lock call in ltdb_search() due to a refcounting bug in
+ * ltdb_lock_read()
+ */
+
+struct search_against_transaction_ctx {
+ struct ldbtest_ctx *test_ctx;
+ int res_count;
+ pid_t child_pid;
+ struct ldb_dn *basedn;
+};
+
+static int test_ldb_search_against_transaction_callback2(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct search_against_transaction_ctx *ctx = req->context;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ ctx->res_count++;
+ if (ctx->res_count != 1) {
+ return LDB_SUCCESS;
+ }
+
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ break;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ return 0;
+
+}
+
+/*
+ * This purpose of this callback is to trigger a transaction in
+ * the child process while the all-record lock is held, but before
+ * we take any locks in the tdb_traverse_read() handler.
+ *
+ * In tdb 1.3.12 tdb_traverse_read() take the read transaction lock
+ * however in ldb 1.1.31 ltdb_search() forgets to take the all-record
+ * lock (except the very first time) due to a ref-counting bug.
+ *
+ */
+
+static int test_ldb_search_against_transaction_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret, ret2;
+ int pipes[2];
+ char buf[2];
+ struct search_against_transaction_ctx *ctx = req->context;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ ctx->child_pid = fork();
+ if (ctx->child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "dc=test");
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "objectUUID",
+ "0123456789abcdef");
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_add(ctx->test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ /* This search must be unindexed (ie traverse in tdb) */
+ ret = ldb_build_search_req(&req,
+ ctx->test_ctx->ldb,
+ ctx->test_ctx,
+ ctx->basedn,
+ LDB_SCOPE_SUBTREE,
+ "cn=*", NULL,
+ NULL,
+ ctx,
+ test_ldb_search_against_transaction_callback2,
+ NULL);
+ /*
+ * we don't assert on these return codes until after the search is
+ * finished, or the clean up will fail because we hold locks.
+ */
+
+ ret2 = ldb_request(ctx->test_ctx->ldb, req);
+
+ if (ret2 == LDB_SUCCESS) {
+ ret2 = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+ assert_int_equal(ret2, 0);
+ assert_int_equal(ctx->res_count, 2);
+
+ return LDB_SUCCESS;
+}
+
+static void test_ldb_search_against_transaction(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct search_against_transaction_ctx
+ ctx =
+ { .res_count = 0,
+ .test_ctx = search_test_ctx->ldb_test_ctx
+ };
+
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+ struct ldb_dn *base_search_dn;
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ base_search_dn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,%s",
+ search_test_ctx->base_dn);
+ assert_non_null(base_search_dn);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /* This search must be indexed (ie no traverse in tdb) */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ base_search_dn,
+ LDB_SCOPE_BASE,
+ "cn=*", NULL,
+ NULL,
+ &ctx,
+ test_ldb_search_against_transaction_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+ assert_int_equal(ctx.res_count, 2);
+
+ pid = waitpid(ctx.child_pid, &wstatus, 0);
+ assert_int_equal(pid, ctx.child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+
+}
+
+/*
+ * This test is also complex.
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * This would be a failure if if in process
+ * (1) and (2):
+ * - (1) ltdb_search() starts and calls back for one entry
+ * - (2) one of the entries to be matched is modified
+ * - (1) the indexed search tries to return the modified entry, but
+ * it is no longer found, either:
+ * - despite it still matching (dn changed)
+ * - it no longer matching (attrs changed)
+ *
+ * We also try un-indexed to show that the behaviour differs on this
+ * point, which it should not (an index should only impact search
+ * speed).
+ */
+
+struct modify_during_search_test_ctx {
+ struct ldbtest_ctx *test_ctx;
+ int res_count;
+ pid_t child_pid;
+ struct ldb_dn *basedn;
+ bool got_cn;
+ bool got_2_cn;
+ bool rename;
+};
+
+/*
+ * This purpose of this callback is to trigger a write in
+ * the child process while a search is in progress.
+ *
+ * In tdb 1.3.12 tdb_traverse_read() take the read transaction lock
+ * however in ldb 1.1.31 ltdb_search() forgets to take the all-record
+ * lock (except the very first time) due to a ref-counting bug.
+ *
+ * We assume that if the write will proceed, it will proceed in a 3
+ * second window after the function is called.
+ */
+
+static int test_ldb_modify_during_search_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret;
+ int pipes[2];
+ char buf[2];
+ struct modify_during_search_test_ctx *ctx = req->context;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ {
+ const struct ldb_val *cn_val
+ = ldb_dn_get_component_val(ares->message->dn, 0);
+ const char *cn = (char *)cn_val->data;
+ ctx->res_count++;
+ if (strcmp(cn, "test_search_cn") == 0) {
+ ctx->got_cn = true;
+ } else if (strcmp(cn, "test_search_2_cn") == 0) {
+ ctx->got_2_cn = true;
+ }
+ if (ctx->res_count == 2) {
+ return LDB_SUCCESS;
+ }
+ break;
+ }
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ ctx->child_pid = fork();
+ if (ctx->child_pid == 0 && ctx->rename) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_dn *dn, *new_dn;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ctx->got_cn) {
+ /* Modify the other one */
+ dn = ldb_dn_new_fmt(tmp_ctx, ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,"
+ "dc=search_test_entry");
+ } else {
+ dn = ldb_dn_new_fmt(tmp_ctx, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ }
+ if (dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ new_dn = ldb_dn_new_fmt(tmp_ctx, ctx->test_ctx->ldb,
+ "cn=test_search_cn_renamed,"
+ "dc=search_test_entry");
+ if (new_dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_rename(ctx->test_ctx->ldb, dn, new_dn);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+
+ } else if (ctx->child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ctx->got_cn) {
+ /* Modify the other one */
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,"
+ "dc=search_test_entry");
+ } else {
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ }
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "filterAttr", "TRUE");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el = ldb_msg_find_element(msg, "filterAttr");
+ if (el == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_modify(ctx->test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+ }
+
+ /*
+ * With TDB 1.3.13 and before "tdb: Remove locking from tdb_traverse_read()"
+ * we will hang here because the child process can not proceed to
+ * sending the "GO" as it is blocked at ldb_transaction_start().
+ */
+
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ sleep(3);
+
+ return LDB_SUCCESS;
+}
+
+static void test_ldb_modify_during_search(void **state, bool add_index,
+ bool rename)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct modify_during_search_test_ctx
+ ctx =
+ { .res_count = 0,
+ .test_ctx = search_test_ctx->ldb_test_ctx,
+ .rename = rename
+ };
+
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+
+ if (add_index) {
+ struct ldb_message *msg;
+ struct ldb_dn *indexlist = ldb_dn_new(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(indexlist);
+
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = indexlist;
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "cn");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+ ret = ldb_modify(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ }
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /*
+ * This search must be over multiple items, and should include
+ * the new name after a rename, to show that it would match
+ * both before and after that modify
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ ctx.basedn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(|(cn=test_search_cn_renamed)"
+ "(cn=test_search_cn)"
+ "(cn=test_search_2_cn)"
+ "))",
+ NULL,
+ NULL,
+ &ctx,
+ test_ldb_modify_during_search_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+ assert_int_equal(ctx.res_count, 2);
+ assert_int_equal(ctx.got_cn, true);
+ assert_int_equal(ctx.got_2_cn, true);
+
+ pid = waitpid(ctx.child_pid, &wstatus, 0);
+ assert_int_equal(pid, ctx.child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+
+}
+
+static void test_ldb_modify_during_indexed_search(void **state)
+{
+ test_ldb_modify_during_search(state, true, false);
+}
+
+static void test_ldb_modify_during_unindexed_search(void **state)
+{
+ test_ldb_modify_during_search(state, false, false);
+}
+
+static void test_ldb_rename_during_indexed_search(void **state)
+{
+ test_ldb_modify_during_search(state, true, true);
+}
+
+static void test_ldb_rename_during_unindexed_search(void **state)
+{
+ test_ldb_modify_during_search(state, false, true);
+}
+
+/*
+ * This test is also complex.
+ *
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * before the end of the callback
+ *
+ * This would be a failure if if in process
+ * (1) and (2):
+ * - (1) ldb_search() starts and calls back for a number of entries
+ * - (2) an entry in the DB is allowed to change before the callback returns
+ * - (1) the callback can see the modification
+ *
+ */
+
+/*
+ * This purpose of this callback is to trigger a write in
+ * the child process while a search DONE callback is in progress.
+ *
+ * In ldb 1.1.31 ldb_search() omitted to take a all-record
+ * lock for the full duration of the search and callbacks
+ *
+ * We assume that if the write will proceed, it will proceed in a 3
+ * second window after the function is called.
+ */
+
+static int test_ldb_modify_during_whole_search_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret;
+ int pipes[2];
+ char buf[2];
+ struct modify_during_search_test_ctx *ctx = req->context;
+ struct ldb_dn *search_dn;
+ struct ldb_result *res2;
+ unsigned res_count;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ break;
+ }
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ ctx->child_pid = fork();
+ if (ctx->child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ TALLOC_FREE(ctx->test_ctx->ldb);
+ TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
+ ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
+ if (ctx->test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ctx->test_ctx->ldb = ldb_init(ctx->test_ctx,
+ ctx->test_ctx->ev);
+ if (ctx->test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(ctx->test_ctx->ldb,
+ ctx->test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(ctx->test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg->dn = ldb_dn_new_fmt(msg, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "filterAttr", "TRUE");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el = ldb_msg_find_element(msg, "filterAttr");
+ if (el == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_transaction_start(ctx->test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_modify(ctx->test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(ctx->test_ctx->ldb);
+ exit(ret);
+ }
+
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ sleep(3);
+
+ /*
+ * If writes are not blocked until after this function, we
+ * will be able to successfully search for this modification
+ * here
+ */
+
+ search_dn = ldb_dn_new_fmt(ares, ctx->test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ ret = ldb_search(ctx->test_ctx->ldb, ares,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+
+ /*
+ * We do this in an unusual order, because if we fail an assert before
+ * ldb_request_done(), we will also fail to clean up as we hold locks.
+ */
+
+ res_count = res2->count;
+ ldb_request_done(req, LDB_SUCCESS);
+ assert_int_equal(ret, 0);
+
+ /* We should not have got the result */
+ assert_int_equal(res_count, 0);
+
+ return ret;
+}
+
+static void test_ldb_modify_during_whole_search(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct modify_during_search_test_ctx
+ ctx =
+ {
+ .test_ctx = search_test_ctx->ldb_test_ctx,
+ };
+
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+ struct ldb_dn *search_dn;
+ struct ldb_result *res2;
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /*
+ * The search just needs to call DONE, we don't care about the
+ * contents of the search for this test
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ ctx.basedn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(cn=test_search_cn))",
+ NULL,
+ NULL,
+ &ctx,
+ test_ldb_modify_during_whole_search_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+
+ pid = waitpid(ctx.child_pid, &wstatus, 0);
+ assert_int_equal(pid, ctx.child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+ /*
+ * If writes are blocked until after the search function, we
+ * will be able to successfully search for this modification
+ * now
+ */
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+ assert_int_equal(ret, 0);
+
+ /* We got the result */
+ assert_int_equal(res2->count, 1);
+}
+
+/*
+ * This test is also complex.
+ *
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * before the request is destroyed with TALLOC_FREE()
+ *
+ * This would be a failure if in process
+ * (1) and (2):
+ * - (1) ldb_search() starts and waits
+ * - (2) an entry in the DB is allowed to change before the ldb_wait() is called
+ * - (1) the original process can see the modification before the TALLOC_FREE()
+ * also we check that
+ * - (1) the original process can see the modification after the TALLOC_FREE()
+ *
+ */
+
+/*
+ * This purpose of this callback is to trigger a write in
+ * the child process before the ldb_wait() is called
+ *
+ * In ldb 1.1.31 ldb_search() omitted to take a all-record
+ * lock for the full duration of the search and callbacks
+ *
+ * We assume that if the write will proceed, it will proceed in a 3
+ * second window after the function is called.
+ */
+
+static int test_ldb_modify_before_ldb_wait_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ break;
+ }
+
+ return ldb_request_done(req, LDB_SUCCESS);
+}
+
+static void test_ldb_modify_before_ldb_wait(void **state)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ int ret;
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+ struct ldb_dn *search_dn;
+ struct ldb_dn *basedn;
+ struct ldb_result *res2;
+ int pipes[2];
+ char buf[2];
+ pid_t child_pid;
+ unsigned res_count;
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ assert_non_null(search_dn);
+
+ basedn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(basedn);
+
+ /*
+ * The search just needs to call DONE, we don't care about the
+ * contents of the search for this test
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(cn=test_search_cn))",
+ NULL,
+ NULL,
+ NULL,
+ test_ldb_modify_before_ldb_wait_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ TALLOC_FREE(search_test_ctx->ldb_test_ctx->ldb);
+ TALLOC_FREE(search_test_ctx->ldb_test_ctx->ev);
+ close(pipes[0]);
+ search_test_ctx->ldb_test_ctx->ev = tevent_context_init(search_test_ctx->ldb_test_ctx);
+ if (search_test_ctx->ldb_test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ search_test_ctx->ldb_test_ctx->ldb = ldb_init(search_test_ctx->ldb_test_ctx,
+ search_test_ctx->ldb_test_ctx->ev);
+ if (search_test_ctx->ldb_test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_connect(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx->ldb_test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
+
+ tmp_ctx = talloc_new(search_test_ctx->ldb_test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /*
+ * We must re-create this DN from a string to ensure
+ * it does not reference the now-gone LDB context of
+ * the parent
+ */
+ msg->dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_msg_add_string(msg, "filterAttr", "TRUE");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el = ldb_msg_find_element(msg, "filterAttr");
+ if (el == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_transaction_start(search_test_ctx->ldb_test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_modify(search_test_ctx->ldb_test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(search_test_ctx->ldb_test_ctx->ldb);
+ exit(ret);
+ }
+ close(pipes[1]);
+
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ sleep(3);
+
+ /*
+ * If writes are not blocked until after the (never called) ldb_wait(), we
+ * will be able to successfully search for this modification
+ * here
+ */
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb, search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+
+ /*
+ * We avoid making assertions before TALLOC_FREE()ing the request,
+ * lest the assert fail and mess with the clean-up because we still
+ * have locks.
+ */
+ res_count = res2->count;
+ TALLOC_FREE(req);
+
+ /* We should not have got the result */
+ assert_int_equal(res_count, 0);
+ assert_int_equal(ret, 0);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+ /*
+ * If writes are blocked until after the search request was freed, we
+ * will be able to successfully search for this modification
+ * now
+ */
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+ assert_int_equal(ret, 0);
+
+ /* We got the result */
+ assert_int_equal(res2->count, 1);
+}
+
+/*
+ * This test is also complex.
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * This would be a failure if if in process
+ * (1) and (2):
+ * - (1) ltdb_search() starts and calls back for one entry
+ * - (2) one of the entries to be matched is modified
+ * - (1) the indexed search tries to return the modified entry, but
+ * it is no longer found, either:
+ * - despite it still matching (dn changed)
+ * - it no longer matching (attrs changed)
+ *
+ * We also try un-indexed to show that the behaviour differs on this
+ * point, which it should not (an index should only impact search
+ * speed).
+ */
+
+/*
+ * This purpose of this callback is to trigger a write in the callback
+ * so as to change in in-memory index code while looping over the
+ * index result.
+ */
+
+static int test_ldb_callback_modify_during_search_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret;
+ struct modify_during_search_test_ctx *ctx = req->context;
+ struct ldb_dn *dn = NULL, *new_dn = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctx->test_ctx);
+ struct ldb_message *msg = NULL;
+
+ assert_non_null(tmp_ctx);
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ {
+ const struct ldb_val *cn_val
+ = ldb_dn_get_component_val(ares->message->dn, 0);
+ const char *cn = (char *)cn_val->data;
+ ctx->res_count++;
+ if (strcmp(cn, "test_search_cn") == 0) {
+ ctx->got_cn = true;
+ } else if (strcmp(cn, "test_search_2_cn") == 0) {
+ ctx->got_2_cn = true;
+ }
+ if (ctx->res_count == 2) {
+ return LDB_SUCCESS;
+ }
+ break;
+ }
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ if (ctx->rename) {
+ if (ctx->got_2_cn) {
+ /* Modify this one */
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ } else {
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ }
+ assert_non_null(dn);
+
+ new_dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_cn_renamed,"
+ "dc=not_search_test_entry");
+ assert_non_null(new_dn);
+
+ ret = ldb_rename(ctx->test_ctx->ldb, dn, new_dn);
+ assert_int_equal(ret, 0);
+
+ } else {
+ if (ctx->got_2_cn) {
+ /* Delete this one */
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ } else {
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ }
+ assert_non_null(dn);
+
+ ret = ldb_delete(ctx->test_ctx->ldb, dn);
+ assert_int_equal(ret, 0);
+ }
+
+ /*
+ * Now fill in the position we just removed from the
+ * index to ensure we fail the test (otherwise we just read
+ * past the end of the array and find the value we wanted to
+ * skip)
+ */
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /* We deliberately use ou= not cn= here */
+ msg->dn = ldb_dn_new_fmt(msg,
+ ctx->test_ctx->ldb,
+ "ou=test_search_cn_extra,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+
+ ret = ldb_msg_add_string(msg,
+ "objectUUID",
+ "0123456789abcde3");
+
+ ret = ldb_add(ctx->test_ctx->ldb,
+ msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ TALLOC_FREE(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+static void test_ldb_callback_modify_during_search(void **state, bool add_index,
+ bool rename)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct modify_during_search_test_ctx
+ ctx =
+ { .res_count = 0,
+ .test_ctx = search_test_ctx->ldb_test_ctx,
+ .rename = rename
+ };
+
+ int ret;
+ struct ldb_request *req;
+
+ ret = ldb_transaction_start(search_test_ctx->ldb_test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ if (add_index) {
+ struct ldb_message *msg;
+ struct ldb_dn *indexlist = ldb_dn_new(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(indexlist);
+
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = indexlist;
+
+ ret = ldb_msg_add_string(msg, "@IDXONE", "1");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "cn");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+ msg->elements[1].flags = LDB_FLAG_MOD_ADD;
+ ret = ldb_modify(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ }
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Now bring the IDXONE index into memory by modifying
+ * it. This exposes an issue in ldb_tdb
+ */
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn_extra,%s",
+ search_test_ctx->base_dn);
+
+ ret = ldb_msg_add_string(msg,
+ "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_delete(search_test_ctx->ldb_test_ctx->ldb,
+ msg->dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /*
+ * This search must be over multiple items, and should include
+ * the new name after a rename, to show that it would match
+ * both before and after that modify
+ *
+ * This needs to be a search that isn't matched by an index so
+ * that we just use the one-level index.
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ ctx.basedn,
+ LDB_SCOPE_ONELEVEL,
+ "(cn=*)",
+ NULL,
+ NULL,
+ &ctx,
+ test_ldb_callback_modify_during_search_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+
+ ret = ldb_transaction_commit(search_test_ctx->ldb_test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ assert_int_equal(ctx.res_count, 2);
+ assert_int_equal(ctx.got_cn, true);
+ assert_int_equal(ctx.got_2_cn, true);
+}
+
+static void test_ldb_callback_delete_during_indexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, true, false);
+}
+
+static void test_ldb_callback_delete_during_unindexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, false, false);
+}
+
+static void test_ldb_callback_rename_during_indexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, true, true);
+}
+
+static void test_ldb_callback_rename_during_unindexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, false, true);
+}
+
+static int ldb_case_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: CASE_INSENSITIVE\n"
+ "\n";
+ struct keyval kvs[] = {
+ { "cn", "CaseInsensitiveValue" },
+ { "uid", "CaseSensitiveValue" },
+ { "objectUUID", "0123456789abcdef" },
+ { NULL, NULL },
+ };
+
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &attrs_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ ldb_test_add_data(ldb_test_ctx,
+ ldb_test_ctx,
+ "cn=CaseInsensitiveValue",
+ kvs);
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_case_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@ATTRIBUTES");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldb_test_remove_data(ldb_test_ctx, ldb_test_ctx,
+ "cn=CaseInsensitiveValue");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_attrs_case_insensitive(void **state)
+{
+ int cnt;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ /* cn matches exact case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=CaseInsensitiveValue");
+ assert_int_equal(cnt, 1);
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ /* uid matches exact case */
+ cnt = sub_search_count(ldb_test_ctx, "", "uid=CaseSensitiveValue");
+ assert_int_equal(cnt, 1);
+
+ /* uid does not match lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "uid=casesensitivevalue");
+ assert_int_equal(cnt, 0);
+}
+
+static struct ldb_schema_attribute cn_attr_1;
+static struct ldb_schema_attribute cn_attr_2;
+static struct ldb_schema_attribute default_attr;
+
+/*
+ override the name to attribute handler function
+ */
+static const struct ldb_schema_attribute *ldb_test_attribute_handler_override(struct ldb_context *ldb,
+ void *private_data,
+ const char *name)
+{
+ if (private_data != NULL && ldb_attr_cmp(name, "cn") == 0) {
+ return &cn_attr_1;
+ } else if (private_data == NULL && ldb_attr_cmp(name, "cn") == 0) {
+ return &cn_attr_2;
+ } else if (ldb_attr_cmp(name, "uid") == 0) {
+ return &cn_attr_2;
+ }
+ return &default_attr;
+}
+
+static void test_ldb_attrs_case_handler(void **state)
+{
+ int cnt;
+ int ret;
+ const struct ldb_schema_syntax *syntax;
+
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_context *ldb = ldb_test_ctx->ldb;
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "*", 0,
+ syntax, &default_attr);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", 0,
+ syntax, &cn_attr_1);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Set an attribute handler, which will fail to match as we
+ * force case sensitive
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ (void *)1);
+
+ /* cn does not matche lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 0);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_DIRECTORY_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", 0,
+ syntax, &cn_attr_2);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Set an attribute handler, which will match as we
+ * force case insensitive
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ NULL);
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+}
+
+
+static void test_ldb_attrs_index_handler(void **state)
+{
+ int cnt;
+ int ret;
+ const struct ldb_schema_syntax *syntax;
+ struct ldb_ldif *ldif;
+
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+ "\n";
+
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_context *ldb = ldb_test_ctx->ldb;
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", 0,
+ syntax, &cn_attr_1);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_DIRECTORY_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "cn", LDB_ATTR_FLAG_INDEXED,
+ syntax, &cn_attr_2);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "", 0,
+ syntax, &default_attr);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Set an attribute handler
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ NULL);
+
+ /* cn matches lower case */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ /* Add the index (actually any modify will do) */
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ ldif->msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+ ret = ldb_modify(ldb_test_ctx->ldb,
+ ldif->msg);
+ }
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ ldb_schema_set_override_indexlist(ldb, false);
+
+ /* cn does match as there is an index now */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 1);
+
+ /*
+ * Set an attribute handler, which will later fail to match as we
+ * didn't re-index the DB
+ */
+ ldb_schema_attribute_set_override_handler(ldb,
+ ldb_test_attribute_handler_override,
+ (void *)1);
+
+ /*
+ * cn does not match as we changed the case sensitivity, but
+ * didn't re-index
+ *
+ * This shows that the override is in control
+ */
+ cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+ assert_int_equal(cnt, 0);
+
+}
+
+static int ldb_case_attrs_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ ldb_case_test_teardown(state);
+ return 0;
+}
+
+
+struct rename_test_ctx {
+ struct ldbtest_ctx *ldb_test_ctx;
+
+ struct ldb_dn *basedn;
+ const char *str_basedn;
+
+ const char *teardown_dn;
+};
+
+static int ldb_rename_test_setup(void **state)
+{
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct rename_test_ctx *rename_test_ctx;
+ const char *strdn = "dc=rename_test_entry_from";
+
+ ldbtest_setup((void **) &ldb_test_ctx);
+
+ rename_test_ctx = talloc(ldb_test_ctx, struct rename_test_ctx);
+ assert_non_null(rename_test_ctx);
+ rename_test_ctx->ldb_test_ctx = ldb_test_ctx;
+ assert_non_null(rename_test_ctx->ldb_test_ctx);
+
+ rename_test_ctx->basedn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", strdn);
+ assert_non_null(rename_test_ctx->basedn);
+
+ rename_test_ctx->str_basedn = strdn;
+ rename_test_ctx->teardown_dn = strdn;
+
+ add_dn_with_cn(ldb_test_ctx,
+ rename_test_ctx->basedn,
+ "test_rename_cn_val",
+ "0123456789abcde0");
+
+ *state = rename_test_ctx;
+ return 0;
+}
+
+static int ldb_rename_test_teardown(void **state)
+{
+ int ret;
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(*state,
+ struct rename_test_ctx);
+ struct ldbtest_ctx *ldb_test_ctx;
+ struct ldb_dn *del_dn;
+
+ ldb_test_ctx = rename_test_ctx->ldb_test_ctx;
+
+ del_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", rename_test_ctx->teardown_dn);
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ rename_test_ctx->teardown_dn);
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_rename(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx =
+ talloc_get_type_abort(*state, struct rename_test_ctx);
+ int ret;
+ const char *str_new_dn = "dc=rename_test_entry_to";
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ new_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx, str_new_dn);
+ assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+ rename_test_ctx->teardown_dn = str_new_dn;
+
+ /* FIXME - test the values which didn't change */
+}
+
+static void test_ldb_rename_from_doesnt_exist(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+ const char *str_new_dn = "dc=rename_test_entry_to";
+ const char *str_bad_old_dn = "dc=rename_test_no_such_entry";
+ struct ldb_dn *new_dn;
+ struct ldb_dn *bad_old_dn;
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ bad_old_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_bad_old_dn);
+ assert_non_null(bad_old_dn);
+
+ assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+ str_bad_old_dn);
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ bad_old_dn, new_dn);
+ assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+
+ assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+ str_new_dn);
+}
+
+static void test_ldb_rename_to_exists(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+ const char *str_new_dn = "dc=rename_test_already_exists";
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ add_dn_with_cn(rename_test_ctx->ldb_test_ctx,
+ new_dn,
+ "test_rename_cn_val",
+ "0123456789abcde1");
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ new_dn);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ /* Old object must still exist */
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+
+ ret = ldb_delete(rename_test_ctx->ldb_test_ctx->ldb,
+ new_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->teardown_dn);
+}
+
+static void test_ldb_rename_self(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+
+ /* Oddly enough, this is a success in ldb.. */
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ rename_test_ctx->basedn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* Old object must still exist */
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+}
+
+static void test_ldb_rename_dn_case_change(void **state)
+{
+ struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+ *state,
+ struct rename_test_ctx);
+ int ret;
+ char *str_new_dn;
+ struct ldb_dn *new_dn;
+ unsigned i;
+
+ str_new_dn = talloc_strdup(rename_test_ctx, rename_test_ctx->str_basedn);
+ assert_non_null(str_new_dn);
+ for (i = 0; str_new_dn[i]; i++) {
+ str_new_dn[i] = toupper(str_new_dn[i]);
+ }
+
+ new_dn = ldb_dn_new_fmt(rename_test_ctx,
+ rename_test_ctx->ldb_test_ctx->ldb,
+ "%s", str_new_dn);
+ assert_non_null(new_dn);
+
+ ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+ rename_test_ctx->basedn,
+ new_dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* DNs are case insensitive, so both searches will match */
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx, str_new_dn);
+ assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+ rename_test_ctx->str_basedn);
+ /* FIXME - test the values didn't change */
+}
+
+static int ldb_read_only_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ ldbtest_setup((void **) &test_ctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldb_read_only_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_read_only(void **state)
+{
+ struct ldb_context *ro_ldb = NULL;
+ struct ldb_context *rw_ldb = NULL;
+ int ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ /*
+ * Close the ldb context freeing it this will ensure it exists on
+ * disk and can be opened in read only mode
+ */
+ TALLOC_FREE(test_ctx->ldb);
+
+ /*
+ * Open the database in read only and read write mode,
+ * ensure it's opened in read only mode first
+ */
+ ro_ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ro_ldb, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ rw_ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(rw_ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+
+ /*
+ * Set up a context for the temporary variables
+ */
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Ensure that we can search the read write database
+ */
+ {
+ struct ldb_result *result = NULL;
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, rw_ldb,
+ "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_search(rw_ldb, tmp_ctx, &result, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(result);
+ TALLOC_FREE(dn);
+ }
+
+ /*
+ * Ensure that we can search the read only database
+ */
+ {
+ struct ldb_result *result = NULL;
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, ro_ldb,
+ "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_search(ro_ldb, tmp_ctx, &result, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(result);
+ TALLOC_FREE(dn);
+ }
+ /*
+ * Ensure that a write to the read only database fails
+ */
+ {
+ struct ldb_message *msg = NULL;
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, ro_ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID",
+ "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(ro_ldb, msg);
+ assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
+ TALLOC_FREE(msg);
+ }
+
+ /*
+ * Ensure that a write to the read write database succeeds
+ */
+ {
+ struct ldb_message *msg = NULL;
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, rw_ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+ assert_int_equal(ret, 0);
+
+ ret = ldb_msg_add_string(msg, "objectUUID",
+ "0123456789abcde2");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(rw_ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(msg);
+ }
+
+ /*
+ * Ensure that a delete from a read only database fails
+ */
+ {
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, ro_ldb, "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_delete(ro_ldb, dn);
+ assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
+ TALLOC_FREE(dn);
+ }
+
+
+ /*
+ * Ensure that a delete from a read write succeeds
+ */
+ {
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, rw_ldb, "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_delete(rw_ldb, dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(dn);
+ }
+ TALLOC_FREE(tmp_ctx);
+}
+
+static bool unique_values = false;
+
+static int unique_index_test_module_add(
+ struct ldb_module *module,
+ struct ldb_request *req)
+{
+ if (unique_values) {
+ struct ldb_message *msg = discard_const(req->op.add.message);
+ struct ldb_message_element *el = NULL;
+ el = ldb_msg_find_element(msg, "cn");
+ if (el != NULL) {
+ el->flags |= LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX;
+ }
+ }
+
+ return ldb_next_request(module, req);
+}
+
+static int unique_index_test_module_init(struct ldb_module *module)
+{
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_unique_index_test_module_ops = {
+ .name = "unique_index_test",
+ .init_context = unique_index_test_module_init,
+ .add = unique_index_test_module_add,
+};
+
+static int ldb_unique_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: UNIQUE_INDEX\n"
+ "\n";
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+#ifdef GUID_IDX
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+#endif
+ "\n";
+ const char *options[] = {"modules:unique_index_test", NULL};
+
+
+ ret = ldb_register_module(&ldb_unique_index_test_module_ops);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_ENTRY_ALREADY_EXISTS);
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &attrs_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ unique_values = true;
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_unique_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(del_dn);
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@ATTRIBUTES");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+
+static void test_ldb_add_unique_value_to_unique_index(void **state)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test");
+ assert_non_null(msg->dn);
+
+ ret = ldb_msg_add_string(msg, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg, "objectUUID",
+ "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ talloc_free(tmp_ctx);
+}
+
+static int ldb_non_unique_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+#ifdef GUID_IDX
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+#endif
+ "\n";
+ const char *options[] = {"modules:unique_index_test", NULL};
+
+
+ ret = ldb_register_module(&ldb_unique_index_test_module_ops);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_ENTRY_ALREADY_EXISTS);
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ unique_values = true;
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_non_unique_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(del_dn);
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_add_duplicate_value_to_unique_index(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_to_index_duplicates_allowed(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ unique_values = false;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_SUCCESS);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_to_index_unique_values_required(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ unique_values = true;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+ talloc_free(tmp_ctx);
+}
+
+static void PRINTF_ATTRIBUTE(3, 0) ldb_debug_string(
+ void *context,
+ enum ldb_debug_level level,
+ const char *fmt, va_list ap)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(context, struct ldbtest_ctx);
+
+ if (level <= LDB_DEBUG_WARNING) {
+ test_ctx->debug_string = talloc_vasprintf(test_ctx, fmt, ap);
+ }
+}
+
+static void test_ldb_unique_index_duplicate_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *p = NULL;
+
+ /* The GUID mode is not compatible with this test */
+#ifdef GUID_IDX
+ return;
+#endif
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, test_ctx);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+
+ assert_non_null(test_ctx->debug_string);
+ p = strstr(
+ test_ctx->debug_string,
+ "unique index violation on cn "
+ "in dc=test02, conflicts with dc=test01 in "
+ "@INDEX:CN:test_unique_index");
+ assert_non_null(p);
+ TALLOC_FREE(test_ctx->debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_duplicate_dn_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ /* The GUID mode is not compatible with this test */
+#ifdef GUID_IDX
+ return;
+#endif
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, test_ctx);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index01");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index02");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ assert_null(test_ctx->debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static int ldb_guid_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: UNIQUE_INDEX\n"
+ "\n";
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &attrs_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_guid_index_test_teardown(void **state)
+{
+ int ret;
+ struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ struct ldb_dn *del_dn;
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(del_dn);
+
+ del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+ ldb_test_ctx->ldb,
+ "@ATTRIBUTES");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+
+static void test_ldb_unique_index_duplicate_with_guid(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *p = NULL;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, test_ctx);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID", "0123456789abcde0");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+
+ assert_non_null(test_ctx->debug_string);
+ p = strstr(
+ test_ctx->debug_string,
+ "unique index violation on cn in dc=test02, conflicts with "
+ "objectUUID 0123456789abcdef in @INDEX:CN:test_unique_index");
+ assert_non_null(p);
+ TALLOC_FREE(test_ctx->debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_guid_index_duplicate_dn_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, test_ctx);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index01");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index02");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID", "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ assert_null(test_ctx->debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_talloc_destructor_transaction_cleanup(void **state)
+{
+ struct ldbtest_ctx *test_ctx = NULL;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ ldb_transaction_start(test_ctx->ldb);
+
+ /*
+ * Trigger the destructor
+ */
+ TALLOC_FREE(test_ctx->ldb);
+
+ /*
+ * Now ensure that a new connection can be opened
+ */
+ {
+ TALLOC_CTX *tctx = talloc_new(test_ctx);
+ struct ldbtest_ctx *ctx = talloc_zero(tctx, struct ldbtest_ctx);
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ int ret;
+
+ ldbtest_setup((void *)&ctx);
+
+ basedn = ldb_dn_new_fmt(tctx, ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(ctx->ldb,
+ tctx,
+ &result,
+ basedn,
+ LDB_SCOPE_BASE,
+ NULL,
+ NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+
+ ldbtest_teardown((void *)&ctx);
+ }
+}
+
+#ifdef TEST_LMDB
+static int test_ldb_multiple_connections_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret;
+ int pipes[2];
+ char buf[2];
+ int pid, child_pid;
+ int wstatus;
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ {
+ /*
+ * We open a new ldb on an ldb that is already open and
+ * then close it.
+ *
+ * If the multiple connection wrapping is correct the
+ * underlying MDB_env will be left open and we should see
+ * an active reader in the child we fork next
+ */
+ struct ldb_context *ldb = NULL;
+ struct tevent_context *ev = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ ev = tevent_context_init(mem_ctx);
+ assert_non_null(ev);
+
+ ldb = ldb_init(mem_ctx, ev);
+ assert_non_null(ldb);
+
+ ret = ldb_connect(ldb, TEST_BE"://apitest.ldb" , 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ TALLOC_FREE(ldb);
+ TALLOC_FREE(mem_ctx);
+ }
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct MDB_env *env = NULL;
+ struct MDB_envinfo stat;
+ close(pipes[0]);
+
+ /*
+ * Check that there are exactly two readers on the MDB file
+ * backing the ldb.
+ *
+ */
+ ret = mdb_env_create(&env);
+ if (ret != 0) {
+ print_error(__location__
+ " mdb_env_create returned (%d)",
+ ret);
+ exit(ret);
+ }
+
+ ret = mdb_env_open(env,
+ "apitest.ldb",
+ MDB_NOSUBDIR | MDB_NOTLS,
+ 0644);
+ if (ret != 0) {
+ print_error(__location__
+ " mdb_env_open returned (%d)",
+ ret);
+ exit(ret);
+ }
+
+ ret = mdb_env_info(env, &stat);
+ if (ret != 0) {
+ print_error(__location__
+ " mdb_env_info returned (%d)",
+ ret);
+ exit(ret);
+ }
+ if (stat.me_numreaders != 2) {
+ print_error(__location__
+ " Incorrect number of readers (%d)",
+ stat.me_numreaders);
+ exit(LDB_ERR_CONSTRAINT_VIOLATION);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+ return LDB_SUCCESS;
+
+}
+
+static void test_ldb_close_with_multiple_connections(void **state)
+{
+ struct search_test_ctx *search_test_ctx = NULL;
+ struct ldb_dn *search_dn = NULL;
+ struct ldb_request *req = NULL;
+ int ret = 0;
+
+ search_test_ctx = talloc_get_type_abort(*state, struct search_test_ctx);
+ assert_non_null(search_test_ctx);
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ assert_non_null(search_dn);
+
+ /*
+ * The search just needs to call DONE, we don't care about the
+ * contents of the search for this test
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ search_dn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(cn=test_search_cn))",
+ NULL,
+ NULL,
+ NULL,
+ test_ldb_multiple_connections_callback,
+ NULL);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ assert_int_equal(ret, 0);
+}
+
+#endif
+
+static void test_transaction_start_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ close(pipes[0]);
+ ret = ldb_transaction_start(ldb1);
+ if (ret != LDB_ERR_PROTOCOL_ERROR) {
+ print_error(__location__": ldb_transaction_start "
+ "returned (%d) %s\n",
+ ret,
+ ldb1->err_string);
+ exit(LDB_ERR_OTHER);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+static void test_transaction_commit_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_transaction_start(ldb1);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ close(pipes[0]);
+ ret = ldb_transaction_commit(ldb1);
+
+ if (ret != LDB_ERR_PROTOCOL_ERROR) {
+ print_error(__location__": ldb_transaction_commit "
+ "returned (%d) %s\n",
+ ret,
+ ldb1->err_string);
+ exit(LDB_ERR_OTHER);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+static void test_lock_read_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+
+ close(pipes[0]);
+
+ basedn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb,
+ test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_BASE,
+ NULL,
+ NULL);
+ if (ret != LDB_ERR_PROTOCOL_ERROR) {
+ print_error(__location__": ldb_search "
+ "returned (%d) %s\n",
+ ret,
+ ldb1->err_string);
+ exit(LDB_ERR_OTHER);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+ {
+ /*
+ * Ensure that the search actually succeeds on the opening
+ * pid
+ */
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+
+ close(pipes[0]);
+
+ basedn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb,
+ test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_BASE,
+ NULL,
+ NULL);
+ assert_int_equal(0, ret);
+ }
+}
+
+static void test_multiple_opens_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ struct ldb_context *ldb2 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database again
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb2 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb2, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct ldb_context *ldb3 = NULL;
+
+ close(pipes[0]);
+ ldb3 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
+ if (ret != 0) {
+ print_error(__location__": ldb_connect returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_connect,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldif_message,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldif_message_redacted,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_add,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_search,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_del,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_del_noexist,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_handle,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_build_search_req,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_transactions,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_nested_transactions,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_add_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_extend_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_add_key_noval,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_noexist_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_zero_vals,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_replace_noexist_key_zero_vals,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_del_key,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_del_keyval,
+ ldb_modify_test_setup,
+ ldb_modify_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_none,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_one,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_filter,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_both,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_search_match_basedn,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_search_against_transaction,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_callback_rename_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_callback_rename_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_callback_delete_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_callback_delete_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_whole_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_before_ldb_wait,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_attrs_case_insensitive,
+ ldb_case_test_setup,
+ ldb_case_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_attrs_case_handler,
+ ldb_case_test_setup,
+ ldb_case_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_attrs_index_handler,
+ ldb_case_test_setup,
+ ldb_case_attrs_index_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_from_doesnt_exist,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_to_exists,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_self,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_dn_case_change,
+ ldb_rename_test_setup,
+ ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_read_only,
+ ldb_read_only_setup,
+ ldb_read_only_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_unique_value_to_unique_index,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_duplicate_value_to_unique_index,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_to_index_duplicates_allowed,
+ ldb_non_unique_index_test_setup,
+ ldb_non_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_to_index_unique_values_required,
+ ldb_non_unique_index_test_setup,
+ ldb_non_unique_index_test_teardown),
+ /* These tests are not compatible with mdb */
+ cmocka_unit_test_setup_teardown(
+ test_ldb_unique_index_duplicate_logging,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_duplicate_dn_logging,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_guid_index_duplicate_dn_logging,
+ ldb_guid_index_test_setup,
+ ldb_guid_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_unique_index_duplicate_with_guid,
+ ldb_guid_index_test_setup,
+ ldb_guid_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_talloc_destructor_transaction_cleanup,
+ ldbtest_setup,
+ ldbtest_teardown),
+#ifdef TEST_LMDB
+ cmocka_unit_test_setup_teardown(
+ test_ldb_close_with_multiple_connections,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+#endif
+ cmocka_unit_test_setup_teardown(
+ test_transaction_start_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_transaction_commit_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_lock_read_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_multiple_opens_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ };
+
+ if (argc > 1) {
+ cmocka_set_test_filter(argv[1]);
+ }
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_msg.c b/lib/ldb/tests/ldb_msg.c
new file mode 100644
index 0000000..31786a9
--- /dev/null
+++ b/lib/ldb/tests/ldb_msg.c
@@ -0,0 +1,380 @@
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+
+#include <ldb.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+struct test_ctx {
+ struct ldb_message *msg;
+};
+
+static int ldb_msg_setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->msg = ldb_msg_new(test_ctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldb_msg_teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ talloc_free(test_ctx);
+ return 0;
+}
+
+
+static void add_uint_value(struct test_ctx *test_ctx,
+ struct ldb_message *msg,
+ const char *attr,
+ unsigned int x)
+{
+ int ret;
+ struct ldb_val v, v_dup;
+ char s[5];
+ snprintf(s, sizeof(s), "%04x", x);
+ v.data = (uint8_t *)s;
+ v.length = 4;
+ v_dup = ldb_val_dup(test_ctx, &v);
+ assert_non_null(v_dup.data);
+ assert_ptr_not_equal(v_dup.data, v.data);
+ assert_int_equal(v_dup.length, 4);
+
+ ret = ldb_msg_add_value(msg, attr, &v_dup, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+}
+
+
+static void test_ldb_msg_find_duplicate_val(void **state)
+{
+ int ret;
+ unsigned int i;
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_message *msg = test_ctx->msg;
+ struct ldb_message_element *el;
+ struct ldb_val dummy;
+ struct ldb_val *dupe = &dummy; /* so we can tell it was modified to NULL, not left as NULL */
+
+ ret = ldb_msg_add_empty(msg, "el1", 0, &el);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* An empty message contains no duplicates */
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+
+ for (i = 0; i < 5; i++) {
+ add_uint_value(test_ctx, msg, "el1", i);
+ }
+ /* at this point there are no duplicates, and the check uses the naive
+ quadratic path */
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+
+ /* add a duplicate, still using quadratric path */
+ add_uint_value(test_ctx, msg, "el1", 3);
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(dupe);
+ assert_int_equal(dupe->length, 4);
+ assert_memory_equal(dupe->data, "0003", 4);
+
+ /* add some more, triggering algorithmic jump */
+ for (i = 2; i < 11; i++) {
+ add_uint_value(test_ctx, msg, "el1", i);
+ }
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_non_null(dupe);
+ assert_int_equal(dupe->length, 4);
+ /*XXX not really guaranteed by the API */
+ assert_memory_equal(dupe->data, "0002", 4);
+
+ /* start a new element without duplicates, for the clever algorithm */
+ ldb_msg_add_empty(msg, "el2", 0, &el);
+ for (i = 0; i < 12; i++) {
+ add_uint_value(test_ctx, msg, "el2", i);
+ }
+ ret = ldb_msg_find_duplicate_val(NULL, test_ctx, el, &dupe, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_null(dupe);
+}
+
+
+static struct ldb_message_element *new_msg_element(TALLOC_CTX *mem_ctx,
+ const char *name,
+ unsigned int value_offset,
+ unsigned int num_values)
+{
+ unsigned int i, x;
+ struct ldb_message_element *el = talloc_zero(mem_ctx,
+ struct ldb_message_element);
+
+ el->values = talloc_array(el, struct ldb_val, num_values);
+ for (i = 0; i < num_values; i++) {
+ struct ldb_val v;
+ char s[50];
+ v.data = (uint8_t *)s;
+ /* % 3 is to ensure the values list is unsorted */
+ x = i + value_offset;
+ v.length = snprintf(s, sizeof(s), "%u %u", x % 3, x);
+ el->values[i] = ldb_val_dup(mem_ctx, &v);
+ }
+ el->name = name;
+ el->num_values = num_values;
+ return el;
+}
+
+static void _assert_element_equal(struct ldb_message_element *a,
+ struct ldb_message_element *b,
+ const char * const file,
+ const int line)
+{
+ unsigned int i;
+ _assert_int_equal(a->num_values, b->num_values, file, line);
+ _assert_int_equal(a->flags, b->flags, file, line);
+ _assert_string_equal(a->name, b->name, file, line);
+ for (i = 0; i < a->num_values; i++) {
+ struct ldb_val *v1 = &a->values[i];
+ struct ldb_val *v2 = &b->values[i];
+ _assert_int_equal(v1->length, v2->length, file, line);
+ _assert_memory_equal(v1->data, v2->data, v1->length,
+ file, line);
+ }
+}
+
+#define assert_element_equal(a, b) \
+ _assert_element_equal((a), (b), \
+ __FILE__, __LINE__)
+
+
+static void test_ldb_msg_find_common_values(void **state)
+{
+ /* we only use the state as a talloc context */
+ struct ldb_message_element *el, *el2, *el3, *el4, *el2b, *empty;
+ struct ldb_message_element *orig, *orig2, *orig3, *orig4;
+ int ret;
+ const uint32_t remove_dupes = LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
+ el = new_msg_element(*state, "test", 0, 4);
+ el2 = new_msg_element(*state, "test", 4, 4);
+ el3 = new_msg_element(*state, "test", 6, 4);
+ empty = new_msg_element(*state, "test", 0, 0);
+ orig = new_msg_element(*state, "test", 0, 4);
+ orig2 = new_msg_element(*state, "test", 4, 4);
+ orig3 = new_msg_element(*state, "test", 6, 4);
+
+ /* first round is with short value arrays, using quadratic method */
+ /* we expect no collisions here */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*or here */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* the same elements in reverse order */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* 6, 7 collide */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ /* and again */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ /* make sure the arrays haven't changed */
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el3, orig3);
+
+ /* now with the control permisive flag, the first element should be
+ modified to remove the overlap.*/
+
+ /* 6, 7 collide, so el2 will only have 4 and 5 */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el3, orig3);
+ assert_int_not_equal(el2->num_values, orig2->num_values);
+ assert_int_equal(el2->num_values, 2);
+ el2b = new_msg_element(*state, "test", 4, 2);
+ assert_element_equal(el2, el2b);
+
+ /* now try the same things with a long and a short value list.
+ this should still trigger the quadratic path.
+ */
+ el2 = new_msg_element(*state, "test", 4, 10);
+ orig2 = new_msg_element(*state, "test", 4, 10);
+
+ /* no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el3, orig3);
+
+ /*collisions with permissive flag*/
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el2, orig2);
+ assert_int_equal(el3->num_values, 0);
+
+ /* permutations involving empty elements.
+ everything should succeed. */
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(el2->num_values, orig2->num_values);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(el2->num_values, orig2->num_values);
+ assert_int_equal(el3->num_values, 0); /* el3 is now empty */
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el3, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el3, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el3, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el, orig);
+ assert_int_equal(el3->num_values, 0);
+
+ /* now with two large value lists */
+ el = new_msg_element(*state, "test", 0, 12);
+ orig = new_msg_element(*state, "test", 0, 12);
+ el4 = new_msg_element(*state, "test", 12, 12);
+ orig4 = new_msg_element(*state, "test", 12, 12);
+
+ /* no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el4, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /* collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el2, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el4, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, 0);
+ assert_int_equal(ret, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el2, orig2);
+ assert_element_equal(el4, orig4);
+
+ /* with permissive control, but no collisions */
+ ret = ldb_msg_find_common_values(NULL, *state, el, el4, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ assert_element_equal(el, orig);
+ assert_element_equal(el4, orig4);
+
+ /* now with collisions, thus modifications.
+ At this stage:
+ el is 0-11 (inclusive)
+ e2 is 4-13
+ el3 is empty
+ el4 is 12-23
+ */
+ ret = ldb_msg_find_common_values(NULL, *state, el4, el2, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el2, orig2);
+ assert_int_not_equal(el4->num_values, orig4->num_values);
+ /* 4 should start at 14 */
+ orig4 = new_msg_element(*state, "test", 14, 10);
+ assert_element_equal(el4, orig4);
+
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el, orig);
+ assert_int_not_equal(el2->num_values, orig2->num_values);
+ orig2 = new_msg_element(*state, "test", 12, 2);
+ assert_element_equal(el2, orig2);
+
+ /* test the empty el against the full elements */
+ ret = ldb_msg_find_common_values(NULL, *state, el, empty, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el, 0);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, el, empty, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_find_common_values(NULL, *state, empty, el, remove_dupes);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_element_equal(el, orig);
+ assert_element_equal(empty, el3);
+
+ /* make sure an identical element with a different name is rejected */
+ el2 = new_msg_element(*state, "fish", 12, 2);
+ ret = ldb_msg_find_common_values(NULL, *state, el2, el, remove_dupes);
+ assert_int_equal(ret, LDB_ERR_INAPPROPRIATE_MATCHING);
+}
+
+
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_ldb_msg_find_duplicate_val,
+ ldb_msg_setup,
+ ldb_msg_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_msg_find_common_values,
+ ldb_msg_setup,
+ ldb_msg_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_no_lmdb_test.c b/lib/ldb/tests/ldb_no_lmdb_test.c
new file mode 100644
index 0000000..be23d74
--- /dev/null
+++ b/lib/ldb/tests/ldb_no_lmdb_test.c
@@ -0,0 +1,159 @@
+/*
+ * Ensure lmdb backend is disabled
+ *
+ * Copyright (C) Mathieu Parent <math.parent@gmail.com> 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * Ensure lmdb backend is disabled
+ *
+ * Setup and tear down code copied from ldb_lmdb_test.c
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+
+#define TEST_BE "mdb"
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+
+ const char *dbpath;
+};
+
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int ldbtest_noconn_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_noconn_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static int ldbtest_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ int ret;
+
+ ldbtest_noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, LDB_ERR_OTHER);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_ldb_lmdb_not_found(void **state)
+{
+ // Actual test in ldbtest_setup
+ assert_int_equal(0, 0);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_ldb_lmdb_not_found,
+ ldbtest_setup,
+ ldbtest_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_parse_test.c b/lib/ldb/tests/ldb_parse_test.c
new file mode 100644
index 0000000..b08c7b7
--- /dev/null
+++ b/lib/ldb/tests/ldb_parse_test.c
@@ -0,0 +1,172 @@
+/*
+ * Tests exercising the ldb parse operations.
+ *
+ * Copyright (C) Catalyst.NET Ltd 2017
+ * Copyright (C) Michael Hanselmann 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "../include/ldb.h"
+
+struct test_ctx { uint8_t dummy; };
+
+static int setup(void **state)
+{
+ struct test_ctx *ctx;
+
+ ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(ctx);
+
+ *state = ctx;
+
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ struct test_ctx *ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+
+ talloc_free(ctx);
+
+ return 0;
+}
+
+static void test_roundtrip(TALLOC_CTX *mem_ctx, const char *filter, const char *expected)
+{
+ struct ldb_parse_tree *tree;
+ char *serialized;
+
+ assert_non_null(filter);
+ assert_non_null(expected);
+
+ tree = ldb_parse_tree(mem_ctx, filter);
+ assert_non_null(tree);
+
+ serialized = ldb_filter_from_tree(mem_ctx, tree);
+ assert_non_null(serialized);
+
+ assert_string_equal(serialized, expected);
+}
+
+static void test_parse_filtertype(void **state)
+{
+ struct test_ctx *ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+
+ test_roundtrip(ctx, "", "(|(objectClass=*)(distinguishedName=*))");
+ test_roundtrip(ctx, "a=value", "(a=value)");
+ test_roundtrip(ctx, "(|(foo=bar)(baz=hello))", "(|(foo=bar)(baz=hello))");
+ test_roundtrip(ctx, " ", "(|(objectClass=*)(distinguishedName=*))");
+}
+
+/*
+ * Test that a nested query with 128 levels of nesting is accepted
+ */
+static void test_nested_filter_eq_limit(void **state)
+{
+ struct test_ctx *ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+
+ /*
+ * 128 nested clauses
+ */
+ const char *nested_query = ""
+ "(|(!(|(&(|(|(|(|(|(|(|(|(|(|(|(|"
+ "(|(!(|(&(|(|(|(|(|(|(!(|(!(|(|(|"
+ "(|(!(|(&(|(|(&(|(|(|(|(|(!(!(!(|"
+ "(|(!(|(&(|(|(|(|(|(|(|(|(|(|(|(|"
+ "(|(!(|(&(|(|(|(!(|(|(&(|(|(|(|(|"
+ "(|(!(|(&(|(|(&(|(|(|(|(|(&(&(|(|"
+ "(|(!(|(&(|(|(|(|(|(|(!(|(|(|(|(|"
+ "(|(!(|(&(|(|(!(|(|(|(|(|(|(|(|(|"
+ "(a=b)"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))";
+
+ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, nested_query);
+
+ assert_non_null(tree);
+ /*
+ * Check that we get the same query back
+ */
+ test_roundtrip(ctx, nested_query, nested_query);
+}
+
+/*
+ * Test that a nested query with 129 levels of nesting is rejected.
+ */
+static void test_nested_filter_gt_limit(void **state)
+{
+ struct test_ctx *ctx =
+ talloc_get_type_abort(*state, struct test_ctx);
+
+ /*
+ * 129 nested clauses
+ */
+ const char *nested_query = ""
+ "(|(!(|(|(&(|(|(|(|(&(|(|(|(|(|(|"
+ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|"
+ "(|(!(|(|(&(|(|(!(|(|(|(|(!(|(|(|"
+ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|"
+ "(|(!(|(|(&(|(|(|(!(&(|(|(|(|(|(|"
+ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|"
+ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|"
+ "(|(!(|(|(&(|(|(|(|(|(|(|(|(&(|(|"
+ "(|"
+ "(a=b)"
+ ")"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))"
+ "))))))))))))))))";
+
+ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, nested_query);
+
+ assert_null(tree);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_parse_filtertype, setup, teardown),
+ cmocka_unit_test_setup_teardown(
+ test_nested_filter_eq_limit, setup, teardown),
+ cmocka_unit_test_setup_teardown(
+ test_nested_filter_gt_limit, setup, teardown),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/ldb_tdb_test.c b/lib/ldb/tests/ldb_tdb_test.c
new file mode 100644
index 0000000..64e5983
--- /dev/null
+++ b/lib/ldb/tests/ldb_tdb_test.c
@@ -0,0 +1,389 @@
+/*
+ * tdb backend specific tests for ldb
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * tdb backend specific tests for ldb
+ *
+ * Setup and tear down code copied from ldb_mod_op_test.c
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include "../ldb_tdb/ldb_tdb.h"
+#include "../ldb_key_value/ldb_kv.h"
+
+#define TEST_BE "tdb"
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+
+ const char *dbfile;
+
+ const char *dbpath;
+};
+
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static int ldbtest_noconn_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_noconn_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static int ldbtest_setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx;
+ int ret;
+ struct ldb_ldif *ldif;
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+
+ ldbtest_noconn_setup((void **) &test_ctx);
+
+ ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldbtest_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_noconn_teardown((void **) &test_ctx);
+ return 0;
+}
+
+
+static TDB_CONTEXT *get_tdb_context(struct ldb_context *ldb)
+{
+ void *data = NULL;
+ struct ldb_kv_private *ldb_kv = NULL;
+ TDB_CONTEXT *tdb = NULL;
+
+ data = ldb_module_get_private(ldb->modules);
+ assert_non_null(data);
+
+ ldb_kv = talloc_get_type(data, struct ldb_kv_private);
+ assert_non_null(ldb_kv);
+
+ tdb = ldb_kv->tdb;
+ assert_non_null(tdb);
+
+ return tdb;
+}
+
+static void test_multiple_opens(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ struct ldb_context *ldb2 = NULL;
+ struct ldb_context *ldb3 = NULL;
+ TDB_CONTEXT *tdb1 = NULL;
+ TDB_CONTEXT *tdb2 = NULL;
+ TDB_CONTEXT *tdb3 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database again
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb2 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb2, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb3 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+ /*
+ * We now have 3 ldb's open pointing to the same on disk database
+ * they should all share the same MDB_env
+ */
+ tdb1 = get_tdb_context(ldb1);
+ tdb2 = get_tdb_context(ldb2);
+ tdb3 = get_tdb_context(ldb3);
+
+ assert_ptr_equal(tdb1, tdb2);
+ assert_ptr_equal(tdb1, tdb3);
+}
+
+static void test_multiple_opens_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ struct ldb_context *ldb2 = NULL;
+ TDB_CONTEXT *tdb1 = NULL;
+ TDB_CONTEXT *tdb2 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database again
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb2 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb2, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ tdb1 = get_tdb_context(ldb1);
+ tdb2 = get_tdb_context(ldb2);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct ldb_context *ldb3 = NULL;
+ TDB_CONTEXT *tdb3 = NULL;
+
+ close(pipes[0]);
+ ldb3 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
+ if (ret != 0) {
+ print_error(__location__": ldb_connect returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+ tdb3 = get_tdb_context(ldb3);
+ if (tdb1 != tdb2) {
+ print_error(__location__": tdb1 != tdb2\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (tdb1 != tdb3) {
+ print_error(__location__": tdb1 != tdb3\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+static void test_multiple_opens_across_fork_triggers_reopen(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ struct ldb_context *ldb2 = NULL;
+ TDB_CONTEXT *tdb1 = NULL;
+ TDB_CONTEXT *tdb2 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database again
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb2 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb2, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ tdb1 = get_tdb_context(ldb1);
+ tdb2 = get_tdb_context(ldb2);
+ assert_ptr_equal(tdb1, tdb2);
+
+ /*
+ * Break the internal tdb_reopen() by making a
+ * transaction
+ *
+ * This shows that the tdb_reopen() is called, which is
+ * essential if the host OS does not have pread()
+ */
+ ret = tdb_transaction_start(tdb1);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct ldb_context *ldb3 = NULL;
+
+ close(pipes[0]);
+ ldb3 = ldb_init(test_ctx, test_ctx->ev);
+
+ /*
+ * This should fail as we have taken out a lock
+ * against the raw TDB above, and tdb_reopen()
+ * will fail in that state.
+ *
+ * This check matters as tdb_reopen() is important
+ * if the host does not have pread()
+ */
+ ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
+ if (ret == 0) {
+ print_error(__location__": ldb_connect expected "
+ "LDB_ERR_OPERATIONS_ERROR "
+ "returned (%d)\n",
+ ret);
+ exit(5000);
+ }
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_multiple_opens,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_multiple_opens_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_multiple_opens_across_fork_triggers_reopen,
+ ldbtest_setup,
+ ldbtest_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/lldb_ldap.c b/lib/ldb/tests/lldb_ldap.c
new file mode 100644
index 0000000..eea9f22
--- /dev/null
+++ b/lib/ldb/tests/lldb_ldap.c
@@ -0,0 +1,105 @@
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+
+#include <ldb.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+int ldb_ldap_init(const char *version);
+
+#include "ldb_ldap/ldb_ldap.c"
+
+struct test_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+ struct ldb_message *msg;
+};
+
+static int lldb_msg_setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+ test_ctx->msg = ldb_msg_new(test_ctx);
+ assert_non_null(test_ctx->msg);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int lldb_msg_teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ talloc_free(test_ctx);
+ return 0;
+}
+
+static void test_lldb_add_msg_attr(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+ struct ldb_message *msg = test_ctx->msg;
+ int ret;
+ unsigned int num_elements = 0;
+ struct berval **v = NULL;
+
+ v = talloc_zero_array(test_ctx, struct berval *, 2);
+ assert_non_null(v);
+
+ v[0] = talloc_zero(v, struct berval);
+ assert_non_null(v[0]);
+
+ v[0]->bv_val = talloc_strdup(msg, "dc=example,dc=test");
+ assert_non_null(v[0]->bv_val);
+
+ v[0]->bv_len = strlen(v[0]->bv_val);
+
+ num_elements = msg->num_elements;
+
+ ret = lldb_add_msg_attr(test_ctx->ldb, msg, "defaultNamingContext", v);
+ assert_int_equal(ret, LDB_SUCCESS);
+ assert_int_equal(msg->num_elements, num_elements + 1);
+}
+
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_lldb_add_msg_attr,
+ lldb_msg_setup,
+ lldb_msg_teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/photo.ldif b/lib/ldb/tests/photo.ldif
new file mode 100644
index 0000000..95ab065
--- /dev/null
+++ b/lib/ldb/tests/photo.ldif
@@ -0,0 +1,5 @@
+dn: cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+changetype: modify
+add: jpegPhoto
+jpegPhoto:< file://tests/samba4.png
+
diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py
new file mode 100755
index 0000000..043b721
--- /dev/null
+++ b/lib/ldb/tests/python/api.py
@@ -0,0 +1,3858 @@
+#!/usr/bin/env python3
+# Simple tests for the ldb python bindings.
+# Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
+
+import os
+from unittest import TestCase
+import sys
+sys.path.insert(0, "bin/python")
+import gc
+import time
+import ldb
+import shutil
+import errno
+
+
+TDB_PREFIX = "tdb://"
+MDB_PREFIX = "mdb://"
+
+MDB_INDEX_OBJ = {
+ "dn": "@INDEXLIST",
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]
+}
+
+
+def tempdir():
+ import tempfile
+ try:
+ dir_prefix = os.path.join(os.environ["SELFTEST_PREFIX"], "tmp")
+ except KeyError:
+ dir_prefix = None
+ return tempfile.mkdtemp(dir=dir_prefix)
+
+
+class NoContextTests(TestCase):
+
+ def test_valid_attr_name(self):
+ self.assertTrue(ldb.valid_attr_name("foo"))
+ self.assertFalse(ldb.valid_attr_name("24foo"))
+
+ def test_timestring(self):
+ self.assertEqual("19700101000000.0Z", ldb.timestring(0))
+ self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412))
+
+ self.assertEqual("00000101000000.0Z", ldb.timestring(-62167219200))
+ self.assertEqual("99991231235959.0Z", ldb.timestring(253402300799))
+
+ # should result with OSError EOVERFLOW from gmtime()
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(-62167219201)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(253402300800)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(0x7fffffffffffffff)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+
+ def test_string_to_time(self):
+ self.assertEqual(0, ldb.string_to_time("19700101000000.0Z"))
+ self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z"))
+
+ self.assertEqual(-62167219200, ldb.string_to_time("00000101000000.0Z"))
+ self.assertEqual(253402300799, ldb.string_to_time("99991231235959.0Z"))
+
+ def test_binary_encode(self):
+ encoded = ldb.binary_encode(b'test\\x')
+ decoded = ldb.binary_decode(encoded)
+ self.assertEqual(decoded, b'test\\x')
+
+ encoded2 = ldb.binary_encode('test\\x')
+ self.assertEqual(encoded2, encoded)
+
+
+class LdbBaseTest(TestCase):
+ def setUp(self):
+ super(LdbBaseTest, self).setUp()
+ try:
+ if self.prefix is None:
+ self.prefix = TDB_PREFIX
+ except AttributeError:
+ self.prefix = TDB_PREFIX
+
+ def tearDown(self):
+ super(LdbBaseTest, self).tearDown()
+
+ def url(self):
+ return self.prefix + self.filename
+
+ def flags(self):
+ if self.prefix == MDB_PREFIX:
+ return ldb.FLG_NOSYNC
+ else:
+ return 0
+
+
+class SimpleLdb(LdbBaseTest):
+
+ def setUp(self):
+ super(SimpleLdb, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.url(), flags=self.flags())
+ try:
+ self.ldb.add(self.index)
+ except AttributeError:
+ pass
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(SimpleLdb, self).tearDown()
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.ldb)
+
+ def test_connect(self):
+ ldb.Ldb(self.url(), flags=self.flags())
+
+ def test_connect_none(self):
+ ldb.Ldb()
+
+ def test_connect_later(self):
+ x = ldb.Ldb()
+ x.connect(self.url(), flags=self.flags())
+
+ def test_repr(self):
+ x = ldb.Ldb()
+ self.assertTrue(repr(x).startswith("<ldb connection"))
+
+ def test_set_create_perms(self):
+ x = ldb.Ldb()
+ x.set_create_perms(0o600)
+
+ def test_modules_none(self):
+ x = ldb.Ldb()
+ self.assertEqual([], x.modules())
+
+ def test_modules_tdb(self):
+ x = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual("[<ldb module 'tdb'>]", repr(x.modules()))
+
+ def test_firstmodule_none(self):
+ x = ldb.Ldb()
+ self.assertEqual(x.firstmodule, None)
+
+ def test_firstmodule_tdb(self):
+ x = ldb.Ldb(self.url(), flags=self.flags())
+ mod = x.firstmodule
+ self.assertEqual(repr(mod), "<ldb module 'tdb'>")
+
+ def test_search(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(len(l.search()), 0)
+
+ def test_search_controls(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(len(l.search(controls=["paged_results:0:5"])), 0)
+
+ def test_utf8_ldb_Dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ dn = ldb.Dn(l, (b'a=' + b'\xc4\x85\xc4\x87\xc4\x99\xc5\x82\xc5\x84\xc3\xb3\xc5\x9b\xc5\xba\xc5\xbc').decode('utf8'))
+
+ def test_utf8_encoded_ldb_Dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ dn_encoded_utf8 = b'a=' + b'\xc4\x85\xc4\x87\xc4\x99\xc5\x82\xc5\x84\xc3\xb3\xc5\x9b\xc5\xba\xc5\xbc'
+ try:
+ dn = ldb.Dn(l, dn_encoded_utf8)
+ except UnicodeDecodeError as e:
+ raise
+ except TypeError as te:
+ p3errors = ["argument 2 must be str, not bytes",
+ "Can't convert 'bytes' object to str implicitly"]
+ self.assertIn(str(te), p3errors)
+
+ def test_search_attrs(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(len(l.search(ldb.Dn(l, ""), ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
+
+ def test_search_string_dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(len(l.search("", ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
+
+ def test_search_attr_string(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertRaises(TypeError, l.search, attrs="dc")
+ self.assertRaises(TypeError, l.search, attrs=b"dc")
+
+ def test_opaque(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ l.set_opaque("my_opaque", l)
+ self.assertTrue(l.get_opaque("my_opaque") is not None)
+ self.assertEqual(None, l.get_opaque("unknown"))
+
+ def test_search_scope_base_empty_db(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
+ ldb.SCOPE_BASE)), 0)
+
+ def test_search_scope_onelevel_empty_db(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
+ ldb.SCOPE_ONELEVEL)), 0)
+
+ def test_delete(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertRaises(ldb.LdbError, lambda: l.delete(ldb.Dn(l, "dc=foo2")))
+
+ def test_delete_w_unhandled_ctrl(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo1")
+ m["b"] = [b"a"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ self.assertRaises(ldb.LdbError, lambda: l.delete(m.dn, ["search_options:1:2"]))
+ l.delete(m.dn)
+
+ def test_contains(self):
+ name = self.url()
+ l = ldb.Ldb(name, flags=self.flags())
+ self.assertFalse(ldb.Dn(l, "dc=foo3") in l)
+ l = ldb.Ldb(name, flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo3")
+ m["b"] = ["a"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ try:
+ self.assertTrue(ldb.Dn(l, "dc=foo3") in l)
+ self.assertFalse(ldb.Dn(l, "dc=foo4") in l)
+ finally:
+ l.delete(m.dn)
+
+ def test_get_config_basedn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(None, l.get_config_basedn())
+
+ def test_get_root_basedn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(None, l.get_root_basedn())
+
+ def test_get_schema_basedn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(None, l.get_schema_basedn())
+
+ def test_get_default_basedn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(None, l.get_default_basedn())
+
+ def test_add(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo4")
+ m["bla"] = b"bla"
+ m["objectUUID"] = b"0123456789abcdef"
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ try:
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=foo4"))
+
+ def test_search_iterator(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ s = l.search_iterator()
+ s.abandon()
+ try:
+ for me in s:
+ self.fail()
+ self.fail()
+ except RuntimeError as re:
+ pass
+ try:
+ s.abandon()
+ self.fail()
+ except RuntimeError as re:
+ pass
+ try:
+ s.result()
+ self.fail()
+ except RuntimeError as re:
+ pass
+
+ s = l.search_iterator()
+ count = 0
+ for me in s:
+ self.assertTrue(isinstance(me, ldb.Message))
+ count += 1
+ r = s.result()
+ self.assertEqual(len(r), 0)
+ self.assertEqual(count, 0)
+
+ m1 = ldb.Message()
+ m1.dn = ldb.Dn(l, "dc=foo4")
+ m1["bla"] = b"bla"
+ m1["objectUUID"] = b"0123456789abcdef"
+ l.add(m1)
+ try:
+ s = l.search_iterator()
+ msgs = []
+ for me in s:
+ self.assertTrue(isinstance(me, ldb.Message))
+ count += 1
+ msgs.append(me)
+ r = s.result()
+ self.assertEqual(len(r), 0)
+ self.assertEqual(len(msgs), 1)
+ self.assertEqual(msgs[0].dn, m1.dn)
+
+ m2 = ldb.Message()
+ m2.dn = ldb.Dn(l, "dc=foo5")
+ m2["bla"] = b"bla"
+ m2["objectUUID"] = b"0123456789abcdee"
+ l.add(m2)
+
+ s = l.search_iterator()
+ msgs = []
+ for me in s:
+ self.assertTrue(isinstance(me, ldb.Message))
+ count += 1
+ msgs.append(me)
+ r = s.result()
+ self.assertEqual(len(r), 0)
+ self.assertEqual(len(msgs), 2)
+ if msgs[0].dn == m1.dn:
+ self.assertEqual(msgs[0].dn, m1.dn)
+ self.assertEqual(msgs[1].dn, m2.dn)
+ else:
+ self.assertEqual(msgs[0].dn, m2.dn)
+ self.assertEqual(msgs[1].dn, m1.dn)
+
+ s = l.search_iterator()
+ msgs = []
+ for me in s:
+ self.assertTrue(isinstance(me, ldb.Message))
+ count += 1
+ msgs.append(me)
+ break
+ try:
+ s.result()
+ self.fail()
+ except RuntimeError as re:
+ pass
+ for me in s:
+ self.assertTrue(isinstance(me, ldb.Message))
+ count += 1
+ msgs.append(me)
+ break
+ for me in s:
+ self.fail()
+
+ r = s.result()
+ self.assertEqual(len(r), 0)
+ self.assertEqual(len(msgs), 2)
+ if msgs[0].dn == m1.dn:
+ self.assertEqual(msgs[0].dn, m1.dn)
+ self.assertEqual(msgs[1].dn, m2.dn)
+ else:
+ self.assertEqual(msgs[0].dn, m2.dn)
+ self.assertEqual(msgs[1].dn, m1.dn)
+ finally:
+ l.delete(ldb.Dn(l, "dc=foo4"))
+ l.delete(ldb.Dn(l, "dc=foo5"))
+
+ def test_add_text(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo4")
+ m["bla"] = "bla"
+ m["objectUUID"] = b"0123456789abcdef"
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ try:
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=foo4"))
+
+ def test_add_w_unhandled_ctrl(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo4")
+ m["bla"] = b"bla"
+ self.assertEqual(len(l.search()), 0)
+ self.assertRaises(ldb.LdbError, lambda: l.add(m, ["search_options:1:2"]))
+
+ def test_add_dict(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = {"dn": ldb.Dn(l, "dc=foo5"),
+ "bla": b"bla",
+ "objectUUID": b"0123456789abcdef"}
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ try:
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=foo5"))
+
+ def test_add_dict_text(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = {"dn": ldb.Dn(l, "dc=foo5"),
+ "bla": "bla",
+ "objectUUID": b"0123456789abcdef"}
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ try:
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=foo5"))
+
+ def test_add_dict_string_dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = {"dn": "dc=foo6", "bla": b"bla",
+ "objectUUID": b"0123456789abcdef"}
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ try:
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=foo6"))
+
+ def test_add_dict_bytes_dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = {"dn": b"dc=foo6", "bla": b"bla",
+ "objectUUID": b"0123456789abcdef"}
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ try:
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=foo6"))
+
+ def test_rename(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo7")
+ m["bla"] = b"bla"
+ m["objectUUID"] = b"0123456789abcdef"
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ try:
+ l.rename(ldb.Dn(l, "dc=foo7"), ldb.Dn(l, "dc=bar"))
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=bar"))
+
+ def test_rename_string_dns(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo8")
+ m["bla"] = b"bla"
+ m["objectUUID"] = b"0123456789abcdef"
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ self.assertEqual(len(l.search()), 1)
+ try:
+ l.rename("dc=foo8", "dc=bar")
+ self.assertEqual(len(l.search()), 1)
+ finally:
+ l.delete(ldb.Dn(l, "dc=bar"))
+
+ def test_rename_bad_string_dns(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo8")
+ m["bla"] = b"bla"
+ m["objectUUID"] = b"0123456789abcdef"
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ self.assertEqual(len(l.search()), 1)
+ self.assertRaises(ldb.LdbError,lambda: l.rename("dcXfoo8", "dc=bar"))
+ self.assertRaises(ldb.LdbError,lambda: l.rename("dc=foo8", "dcXbar"))
+ l.delete(ldb.Dn(l, "dc=foo8"))
+
+ def test_empty_dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertEqual(0, len(l.search()))
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=empty")
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ rm = l.search()
+ self.assertEqual(1, len(rm))
+ self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
+ set(rm[0].keys()))
+
+ rm = l.search(m.dn)
+ self.assertEqual(1, len(rm))
+ self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
+ set(rm[0].keys()))
+ rm = l.search(m.dn, attrs=["blah"])
+ self.assertEqual(1, len(rm))
+ self.assertEqual(0, len(rm[0]))
+
+ def test_modify_delete(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modifydelete")
+ m["bla"] = [b"1234"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual([b"1234"], list(rm["bla"]))
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modifydelete")
+ m["bla"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "bla")
+ self.assertEqual(ldb.FLAG_MOD_DELETE, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)
+ self.assertEqual(1, len(rm))
+ self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
+ set(rm[0].keys()))
+ rm = l.search(m.dn, attrs=["bla"])
+ self.assertEqual(1, len(rm))
+ self.assertEqual(0, len(rm[0]))
+ finally:
+ l.delete(ldb.Dn(l, "dc=modifydelete"))
+
+ def test_modify_delete_text(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modifydelete")
+ m.text["bla"] = ["1234"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual(["1234"], list(rm.text["bla"]))
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modifydelete")
+ m["bla"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "bla")
+ self.assertEqual(ldb.FLAG_MOD_DELETE, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)
+ self.assertEqual(1, len(rm))
+ self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
+ set(rm[0].keys()))
+ rm = l.search(m.dn, attrs=["bla"])
+ self.assertEqual(1, len(rm))
+ self.assertEqual(0, len(rm[0]))
+ finally:
+ l.delete(ldb.Dn(l, "dc=modifydelete"))
+
+ def test_modify_add(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m["bla"] = [b"1234"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+ self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual(3, len(rm))
+ self.assertEqual([b"1234", b"456"], list(rm["bla"]))
+ finally:
+ l.delete(ldb.Dn(l, "dc=add"))
+
+ def test_modify_add_text(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m.text["bla"] = ["1234"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
+ self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual(3, len(rm))
+ self.assertEqual(["1234", "456"], list(rm.text["bla"]))
+ finally:
+ l.delete(ldb.Dn(l, "dc=add"))
+
+ def test_modify_replace(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modify2")
+ m["bla"] = [b"1234", b"456"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modify2")
+ m["bla"] = ldb.MessageElement([b"789"], ldb.FLAG_MOD_REPLACE, "bla")
+ self.assertEqual(ldb.FLAG_MOD_REPLACE, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual(3, len(rm))
+ self.assertEqual([b"789"], list(rm["bla"]))
+ rm = l.search(m.dn, attrs=["bla"])[0]
+ self.assertEqual(1, len(rm))
+ finally:
+ l.delete(ldb.Dn(l, "dc=modify2"))
+
+ def test_modify_replace_text(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modify2")
+ m.text["bla"] = ["1234", "456"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=modify2")
+ m["bla"] = ldb.MessageElement(["789"], ldb.FLAG_MOD_REPLACE, "bla")
+ self.assertEqual(ldb.FLAG_MOD_REPLACE, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual(3, len(rm))
+ self.assertEqual(["789"], list(rm.text["bla"]))
+ rm = l.search(m.dn, attrs=["bla"])[0]
+ self.assertEqual(1, len(rm))
+ finally:
+ l.delete(ldb.Dn(l, "dc=modify2"))
+
+ def test_modify_flags_change(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m["bla"] = [b"1234"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+ self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual(3, len(rm))
+ self.assertEqual([b"1234", b"456"], list(rm["bla"]))
+
+ # Now create another modify, but switch the flags before we do it
+ m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+ m["bla"].set_flags(ldb.FLAG_MOD_DELETE)
+ l.modify(m)
+ rm = l.search(m.dn, attrs=["bla"])[0]
+ self.assertEqual(1, len(rm))
+ self.assertEqual([b"1234"], list(rm["bla"]))
+ finally:
+ l.delete(ldb.Dn(l, "dc=add"))
+
+ def test_modify_flags_change_text(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m.text["bla"] = ["1234"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ try:
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=add")
+ m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
+ self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
+ l.modify(m)
+ rm = l.search(m.dn)[0]
+ self.assertEqual(3, len(rm))
+ self.assertEqual(["1234", "456"], list(rm.text["bla"]))
+
+ # Now create another modify, but switch the flags before we do it
+ m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
+ m["bla"].set_flags(ldb.FLAG_MOD_DELETE)
+ l.modify(m)
+ rm = l.search(m.dn, attrs=["bla"])[0]
+ self.assertEqual(1, len(rm))
+ self.assertEqual(["1234"], list(rm.text["bla"]))
+ finally:
+ l.delete(ldb.Dn(l, "dc=add"))
+
+ def test_transaction_commit(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ l.transaction_start()
+ m = ldb.Message(ldb.Dn(l, "dc=foo9"))
+ m["foo"] = [b"bar"]
+ m["objectUUID"] = b"0123456789abcdef"
+ l.add(m)
+ l.transaction_commit()
+ l.delete(m.dn)
+
+ def test_transaction_cancel(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ l.transaction_start()
+ m = ldb.Message(ldb.Dn(l, "dc=foo10"))
+ m["foo"] = [b"bar"]
+ m["objectUUID"] = b"0123456789abcdee"
+ l.add(m)
+ l.transaction_cancel()
+ self.assertEqual(0, len(l.search(ldb.Dn(l, "dc=foo10"))))
+
+ def test_set_debug(self):
+ def my_report_fn(level, text):
+ pass
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ l.set_debug(my_report_fn)
+
+ def test_zero_byte_string(self):
+ """Testing we do not get trapped in the \0 byte in a property string."""
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ l.add({
+ "dn": b"dc=somedn",
+ "objectclass": b"user",
+ "cN": b"LDAPtestUSER",
+ "givenname": b"ldap",
+ "displayname": b"foo\0bar",
+ "objectUUID": b"0123456789abcdef"
+ })
+ res = l.search(expression="(dn=dc=somedn)")
+ self.assertEqual(b"foo\0bar", res[0]["displayname"][0])
+
+ def test_no_crash_broken_expr(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ self.assertRaises(ldb.LdbError, lambda: l.search("", ldb.SCOPE_SUBTREE, "&(dc=*)(dn=*)", ["dc"]))
+
+# Run the SimpleLdb tests against an lmdb backend
+
+
+class SimpleLdbLmdb(SimpleLdb):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(SimpleLdbLmdb, self).setUp()
+
+ def tearDown(self):
+ super(SimpleLdbLmdb, self).tearDown()
+
+
+class SimpleLdbNoLmdb(LdbBaseTest):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') != '0':
+ self.skipTest("lmdb backend enabled")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(SimpleLdbNoLmdb, self).setUp()
+
+ def tearDown(self):
+ super(SimpleLdbNoLmdb, self).tearDown()
+
+ def test_lmdb_disabled(self):
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ try:
+ self.ldb = ldb.Ldb(self.url(), flags=self.flags())
+ self.fail("Should have failed on missing LMDB")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_OTHER)
+
+
+class SearchTests(LdbBaseTest):
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(SearchTests, self).tearDown()
+
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+ def setUp(self):
+ super(SearchTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "search_test.ldb")
+ options = ["modules:rdn_name"]
+ if hasattr(self, 'IDXCHECK'):
+ options.append("disable_full_db_scan_for_self_test:1")
+ self.l = ldb.Ldb(self.url(),
+ flags=self.flags(),
+ options=options)
+ try:
+ self.l.add(self.index)
+ except AttributeError:
+ pass
+
+ self.l.add({"dn": "@ATTRIBUTES",
+ "DC": "CASE_INSENSITIVE"})
+
+ # Note that we can't use the name objectGUID here, as we
+ # want to stay clear of the objectGUID handler in LDB and
+ # instead use just the 16 bytes raw, which we just keep
+ # to printable chars here for ease of handling.
+
+ self.l.add({"dn": "DC=ORG",
+ "name": b"org",
+ "objectUUID": b"0000000000abcdef"})
+ self.l.add({"dn": "DC=EXAMPLE,DC=ORG",
+ "name": b"org",
+ "objectUUID": b"0000000001abcdef"})
+ self.l.add({"dn": "OU=OU1,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #1",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde3"})
+ self.l.add({"dn": "OU=OU2,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #2",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde4"})
+ self.l.add({"dn": "OU=OU3,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #3",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde5"})
+ self.l.add({"dn": "OU=OU4,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #4",
+ "x": "z", "y": "b",
+ "objectUUID": b"0023456789abcde6"})
+ self.l.add({"dn": "OU=OU5,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #5",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde7"})
+ self.l.add({"dn": "OU=OU6,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #6",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde8"})
+ self.l.add({"dn": "OU=OU7,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #7",
+ "x": "y", "y": "c",
+ "objectUUID": b"0023456789abcde9"})
+ self.l.add({"dn": "OU=OU8,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #8",
+ "x": "y", "y": "b",
+ "objectUUID": b"0023456789abcde0"})
+ self.l.add({"dn": "OU=OU9,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #9",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcdea"})
+
+ self.l.add({"dn": "DC=EXAMPLE,DC=COM",
+ "name": b"org",
+ "objectUUID": b"0000000011abcdef"})
+
+ self.l.add({"dn": "DC=EXAMPLE,DC=NET",
+ "name": b"org",
+ "objectUUID": b"0000000021abcdef"})
+
+ self.l.add({"dn": "OU=UNIQUE,DC=EXAMPLE,DC=NET",
+ "objectUUID": b"0000000022abcdef"})
+
+ self.l.add({"dn": "DC=SAMBA,DC=ORG",
+ "name": b"samba.org",
+ "objectUUID": b"0123456789abcdef"})
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG",
+ "name": b"Users",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+ self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG",
+ "name": b"OU #1",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde3"})
+ self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG",
+ "name": b"OU #2",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde4"})
+ self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG",
+ "name": b"OU #3",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde5"})
+ self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG",
+ "name": b"OU #4",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde6"})
+ self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG",
+ "name": b"OU #5",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde7"})
+ self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG",
+ "name": b"OU #6",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde8"})
+ self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG",
+ "name": b"OU #7",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde9"})
+ self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG",
+ "name": b"OU #8",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcde0"})
+ self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG",
+ "name": b"OU #9",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcdea"})
+ self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcdeb"})
+ self.l.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "y", "y": "a",
+ "objectUUID": b"0123456789abcdec"})
+ self.l.add({"dn": "OU=OU12,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "y", "y": "b",
+ "objectUUID": b"0123456789abcded"})
+ self.l.add({"dn": "OU=OU13,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcdee"})
+ self.l.add({"dn": "OU=OU14,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd01"})
+ self.l.add({"dn": "OU=OU15,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd02"})
+ self.l.add({"dn": "OU=OU16,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd03"})
+ self.l.add({"dn": "OU=OU17,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd04"})
+ self.l.add({"dn": "OU=OU18,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd05"})
+ self.l.add({"dn": "OU=OU19,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd06"})
+ self.l.add({"dn": "OU=OU20,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "b",
+ "objectUUID": b"0123456789abcd07"})
+ self.l.add({"dn": "OU=OU21,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "c",
+ "objectUUID": b"0123456789abcd08"})
+ self.l.add({"dn": "OU=OU22,DC=SAMBA,DC=ORG",
+ "name": b"OU #10",
+ "x": "x", "y": "c",
+ "objectUUID": b"0123456789abcd09"})
+
+ def test_base(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
+ def test_base_lower(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=samba,DC=org",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
+ def test_base_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 1)
+
+ def test_base_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 1)
+
+ def test_base_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(&(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_base_and2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(&(x=y)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_base_false(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou13)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_check_base_false(self):
+ """Testing a search"""
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou13)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_check_base_error(self):
+ """Testing a search"""
+ checkbaseonsearch = {"dn": "@OPTIONS",
+ "checkBaseOnSearch": b"TRUE"}
+ try:
+ self.l.add(checkbaseonsearch)
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+ m = ldb.Message.from_dict(self.l,
+ checkbaseonsearch)
+ self.l.modify(m)
+
+ try:
+ res11 = self.l.search(base="OU=OU11x,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(|(ou=ou13)(ou=ou12))")
+ self.fail("Should have failed on missing base")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ def test_subtree(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE)
+ if hasattr(self, 'IDXCHECK'):
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 25)
+
+ def test_subtree2(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_SUBTREE)
+ if hasattr(self, 'IDXCHECK'):
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 36)
+
+ def test_subtree_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(x=y)(|(y=b)(y=c)))")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_and2_lower(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(x=y)(|(y=b)(y=c)))")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 2)
+
+ def test_subtree_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 20)
+
+ def test_subtree_or3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(x=y)(y=b)(y=c))")
+ self.assertEqual(len(res11), 22)
+
+ def test_one_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 0)
+
+ def test_one_and2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=y)(y=b))")
+ self.assertEqual(len(res11), 1)
+
+ def test_one_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(ou=ou11)(ou=ou12))")
+ self.assertEqual(len(res11), 2)
+
+ def test_one_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 20)
+
+ def test_one_or2_lower(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=y)(y=b))")
+ self.assertEqual(len(res11), 20)
+
+ def test_one_unindexable(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(y=b*)")
+ if hasattr(self, 'IDX') and \
+ not hasattr(self, 'IDXONE') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 9)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
+ def test_one_unindexable_presence(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(y=*)")
+ if hasattr(self, 'IDX') and \
+ not hasattr(self, 'IDXONE') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 24)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
+ def test_subtree_and_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and_or3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_subtree_and_or4(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_subtree_and_or5(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_or_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 10)
+
+ def test_subtree_large_and_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(ou=ou10)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_unique_elsewhere(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_unique_elsewhere3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere4(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere5(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere6(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere7(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_here(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=UNIQUE,DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_and_none(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and_idx_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(@IDXDN=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_and_idxone_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(@IDXONE=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL)
+ if hasattr(self, 'IDXCHECK') \
+ and not hasattr(self, 'IDXONE'):
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 24)
+
+ def test_onelevel2(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL)
+ if hasattr(self, 'IDXCHECK') \
+ and not hasattr(self, 'IDXONE'):
+ self.fail()
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 9)
+
+ def test_onelevel_and_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_or3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_and_or4(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_and_or5(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_or_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 10)
+
+ def test_onelevel_large_and_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou10)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_unique_elsewhere(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere2(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_unique_elsewhere3(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere4(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere5(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere6(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_here(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=UNIQUE,DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_none(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_idx_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(@IDXDN=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_idxone_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(@IDXONE=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unindexable(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(y=b*)")
+ if hasattr(self, 'IDX') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 9)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
+ def test_onelevel_only_and_or(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or2(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or3(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or4(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or5(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_or_and(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_large_and_unique(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou10)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_unique(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_unique2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_none(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_or(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_or2(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_or3(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(ou=ou1)(ou=ou2))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_small_and_or4(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou1)(ou=ou2)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_small_and_or5(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou1))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_small_or_and(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_small_large_and_unique(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou9)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_small_unique_elsewhere(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_none(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unindexable_presence(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(y=*)")
+ if hasattr(self, 'IDX') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 24)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
+ def test_dn_filter_one(self):
+ """Testing that a dn= filter succeeds
+ (or fails with disallowDNFilter
+ set and IDXGUID or (IDX and not IDXONE) mode)
+ when the scope is SCOPE_ONELEVEL.
+
+ This should be made more consistent, but for now lock in
+ the behaviour
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
+ if hasattr(self, 'disallowDNFilter') and \
+ hasattr(self, 'IDX') and \
+ (hasattr(self, 'IDXGUID') or
+ ((not hasattr(self, 'IDXONE') and hasattr(self, 'IDX')))):
+ self.assertEqual(len(res11), 0)
+ else:
+ self.assertEqual(len(res11), 1)
+
+ def test_dn_filter_subtree(self):
+ """Testing that a dn= filter succeeds
+ (or fails with disallowDNFilter set)
+ when the scope is SCOPE_SUBTREE"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
+ if hasattr(self, 'disallowDNFilter') \
+ and hasattr(self, 'IDX'):
+ self.assertEqual(len(res11), 0)
+ else:
+ self.assertEqual(len(res11), 1)
+
+ def test_dn_filter_base(self):
+ """Testing that (incorrectly) a dn= filter works
+ when the scope is SCOPE_BASE"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 1)
+
+ def test_distinguishedName_filter_one(self):
+ """Testing that a distinguishedName= filter succeeds
+ when the scope is SCOPE_ONELEVEL.
+
+ This should be made more consistent, but for now lock in
+ the behaviour
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 1)
+
+ def test_distinguishedName_filter_subtree(self):
+ """Testing that a distinguishedName= filter succeeds
+ when the scope is SCOPE_SUBTREE"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 1)
+
+ def test_distinguishedName_filter_base(self):
+ """Testing that (incorrectly) a distinguishedName= filter works
+ when the scope is SCOPE_BASE"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 1)
+
+ def test_bad_dn_filter_base(self):
+ """Testing that a dn= filter on an invalid DN works
+ when the scope is SCOPE_BASE but
+ returns zero results"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 0)
+
+
+ def test_bad_dn_filter_one(self):
+ """Testing that a dn= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_ONELEVEL search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_dn_filter_subtree(self):
+ """Testing that a dn= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_SUBTREE search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_distinguishedName_filter_base(self):
+ """Testing that a distinguishedName= filter on an invalid DN works
+ when the scope is SCOPE_BASE but
+ returns zero results"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 0)
+
+
+ def test_bad_distinguishedName_filter_one(self):
+ """Testing that a distinguishedName= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_ONELEVEL search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_distinguishedName_filter_subtree(self):
+ """Testing that a distinguishedName= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_SUBTREE search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_dn_search_base(self):
+ """Testing with a bad base DN (SCOPE_BASE)"""
+
+ try:
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DCXXX",
+ scope=ldb.SCOPE_BASE)
+ self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+
+ def test_bad_dn_search_one(self):
+ """Testing with a bad base DN (SCOPE_ONELEVEL)"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DCXXXX",
+ scope=ldb.SCOPE_ONELEVEL)
+ self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+ def test_bad_dn_search_subtree(self):
+ """Testing with a bad base DN (SCOPE_SUBTREE)"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DCXXXX",
+ scope=ldb.SCOPE_SUBTREE)
+ self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+
+
+# Run the search tests against an lmdb backend
+class SearchTestsLmdb(SearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(SearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(SearchTestsLmdb, self).tearDown()
+
+
+class IndexedSearchTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+
+ def setUp(self):
+ super(IndexedSearchTests, self).setUp()
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"]})
+ self.IDX = True
+
+
+class IndexedCheckSearchTests(IndexedSearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things (full scan disabled)"""
+
+ def setUp(self):
+ self.IDXCHECK = True
+ super(IndexedCheckSearchTests, self).setUp()
+
+
+class IndexedSearchDnFilterTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+
+ def setUp(self):
+ super(IndexedSearchDnFilterTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE"})
+ self.disallowDNFilter = True
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"]})
+ self.IDX = True
+
+
+class IndexedAndOneLevelSearchTests(SearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things"""
+
+ def setUp(self):
+ super(IndexedAndOneLevelSearchTests, self).setUp()
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"]})
+ self.IDX = True
+ self.IDXONE = True
+
+
+class IndexedCheckedAndOneLevelSearchTests(IndexedAndOneLevelSearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things (full scan disabled)"""
+
+ def setUp(self):
+ self.IDXCHECK = True
+ super(IndexedCheckedAndOneLevelSearchTests, self).setUp()
+
+
+class IndexedAndOneLevelDNFilterSearchTests(SearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things"""
+
+ def setUp(self):
+ super(IndexedAndOneLevelDNFilterSearchTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE",
+ "checkBaseOnSearch": "TRUE"})
+ self.disallowDNFilter = True
+ self.checkBaseOnSearch = True
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"]})
+ self.IDX = True
+ self.IDXONE = True
+
+
+class GUIDIndexedSearchTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+
+ def setUp(self):
+ self.index = {"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]}
+ super(GUIDIndexedSearchTests, self).setUp()
+
+ self.IDXGUID = True
+
+
+class GUIDIndexedDNFilterSearchTests(SearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+
+ def setUp(self):
+ self.index = {"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]}
+ super(GUIDIndexedDNFilterSearchTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE",
+ "checkBaseOnSearch": "TRUE"})
+ self.disallowDNFilter = True
+ self.checkBaseOnSearch = True
+ self.IDX = True
+ self.IDXGUID = True
+
+
+class GUIDAndOneLevelIndexedSearchTests(SearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things"""
+
+ def setUp(self):
+ self.index = {"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]}
+ super(GUIDAndOneLevelIndexedSearchTests, self).setUp()
+ self.l.add({"dn": "@OPTIONS",
+ "disallowDNFilter": "TRUE",
+ "checkBaseOnSearch": "TRUE"})
+ self.disallowDNFilter = True
+ self.checkBaseOnSearch = True
+ self.IDX = True
+ self.IDXGUID = True
+ self.IDXONE = True
+
+
+class GUIDIndexedSearchTestsLmdb(GUIDIndexedSearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GUIDIndexedSearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDIndexedSearchTestsLmdb, self).tearDown()
+
+
+class GUIDIndexedDNFilterSearchTestsLmdb(GUIDIndexedDNFilterSearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GUIDIndexedDNFilterSearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDIndexedDNFilterSearchTestsLmdb, self).tearDown()
+
+
+class GUIDAndOneLevelIndexedSearchTestsLmdb(GUIDAndOneLevelIndexedSearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GUIDAndOneLevelIndexedSearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDAndOneLevelIndexedSearchTestsLmdb, self).tearDown()
+
+
+class AddModifyTests(LdbBaseTest):
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(AddModifyTests, self).tearDown()
+
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+ def setUp(self):
+ super(AddModifyTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "add_test.ldb")
+ self.l = ldb.Ldb(self.url(),
+ flags=self.flags(),
+ options=["modules:rdn_name"])
+ try:
+ self.l.add(self.index)
+ except AttributeError:
+ pass
+
+ self.l.add({"dn": "DC=SAMBA,DC=ORG",
+ "name": b"samba.org",
+ "objectUUID": b"0123456789abcdef"})
+ self.l.add({"dn": "@ATTRIBUTES",
+ "objectUUID": "UNIQUE_INDEX"})
+
+ def test_add_dup(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ try:
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+ self.fail("Should have failed adding duplicate entry")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ def test_add_bad(self):
+ try:
+ self.l.add({"dn": "BAD,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.fail("Should have failed adding entry with invalid DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+ def test_add_del_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.delete("OU=DUP,DC=SAMBA,DC=ORG")
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ def test_add_move_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ def test_add_move_fail_move_move(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ res2 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(objectUUID=0123456789abcde1)")
+ self.assertEqual(len(res2), 1)
+ self.assertEqual(str(res2[0].dn), "OU=DUP,DC=SAMBA,DC=ORG")
+
+ res3 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(objectUUID=0123456789abcde2)")
+ self.assertEqual(len(res3), 1)
+ self.assertEqual(str(res3[0].dn), "OU=DUP2,DC=SAMBA,DC=ORG")
+
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on duplicate DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ self.l.rename("OU=DUP2,DC=SAMBA,DC=ORG",
+ "OU=DUP3,DC=SAMBA,DC=ORG")
+
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+
+ res2 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(objectUUID=0123456789abcde1)")
+ self.assertEqual(len(res2), 1)
+ self.assertEqual(str(res2[0].dn), "OU=DUP2,DC=SAMBA,DC=ORG")
+
+ res3 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(objectUUID=0123456789abcde2)")
+ self.assertEqual(len(res3), 1)
+ self.assertEqual(str(res3[0].dn), "OU=DUP3,DC=SAMBA,DC=ORG")
+
+ def test_move_missing(self):
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on missing")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ def test_move_missing2(self):
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on missing")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ def test_move_bad(self):
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ try:
+ self.l.rename("OUXDUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on invalid DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+ def test_move_bad2(self):
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OUXDUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on missing")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+ def test_move_fail_move_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on duplicate DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ self.l.rename("OU=DUP2,DC=SAMBA,DC=ORG",
+ "OU=DUP3,DC=SAMBA,DC=ORG")
+
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde3"})
+
+
+class AddModifyTestsLmdb(AddModifyTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(AddModifyTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(AddModifyTestsLmdb, self).tearDown()
+
+
+class IndexedAddModifyTests(AddModifyTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+
+ def setUp(self):
+ if not hasattr(self, 'index'):
+ self.index = {"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou", b"objectUUID", b"z"],
+ "@IDXONE": [b"1"]}
+ super(IndexedAddModifyTests, self).setUp()
+
+ def test_duplicate_GUID(self):
+ try:
+ self.l.add({"dn": "OU=DUPGUID,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcdef"})
+ self.fail("Should have failed adding duplicate GUID")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
+
+ def test_duplicate_name_dup_GUID(self):
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"a123456789abcdef"})
+ try:
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"a123456789abcdef"})
+ self.fail("Should have failed adding duplicate GUID")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ def test_duplicate_name_dup_GUID2(self):
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"abc3456789abcdef"})
+ try:
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"aaa3456789abcdef"})
+ self.fail("Should have failed adding duplicate DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ # Checking the GUID didn't stick in the index
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"aaa3456789abcdef"})
+
+ def test_add_dup_guid_add(self):
+ self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ try:
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.fail("Should have failed on duplicate GUID")
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
+
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ def test_duplicate_index_values(self):
+ self.l.add({"dn": "OU=DIV1,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "z": "1",
+ "objectUUID": b"0123456789abcdff"})
+ self.l.add({"dn": "OU=DIV2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "z": "1",
+ "objectUUID": b"0123456789abcdfd"})
+
+
+class GUIDIndexedAddModifyTests(IndexedAddModifyTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things"""
+
+ def setUp(self):
+ self.index = {"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]}
+ super(GUIDIndexedAddModifyTests, self).setUp()
+
+
+class GUIDTransIndexedAddModifyTests(GUIDIndexedAddModifyTests):
+ """Test GUID index behaviour insdie the transaction"""
+
+ def setUp(self):
+ super(GUIDTransIndexedAddModifyTests, self).setUp()
+ self.l.transaction_start()
+
+ def tearDown(self):
+ self.l.transaction_commit()
+ super(GUIDTransIndexedAddModifyTests, self).tearDown()
+
+
+class TransIndexedAddModifyTests(IndexedAddModifyTests):
+ """Test index behaviour insdie the transaction"""
+
+ def setUp(self):
+ super(TransIndexedAddModifyTests, self).setUp()
+ self.l.transaction_start()
+
+ def tearDown(self):
+ self.l.transaction_commit()
+ super(TransIndexedAddModifyTests, self).tearDown()
+
+
+class GuidIndexedAddModifyTestsLmdb(GUIDIndexedAddModifyTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GuidIndexedAddModifyTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GuidIndexedAddModifyTestsLmdb, self).tearDown()
+
+
+class GuidTransIndexedAddModifyTestsLmdb(GUIDTransIndexedAddModifyTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GuidTransIndexedAddModifyTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GuidTransIndexedAddModifyTestsLmdb, self).tearDown()
+
+
+class BadIndexTests(LdbBaseTest):
+ def setUp(self):
+ super(BadIndexTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.url(), flags=self.flags())
+ if hasattr(self, 'IDXGUID'):
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+ else:
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"]})
+
+ super(BadIndexTests, self).setUp()
+
+ def test_unique(self):
+ self.ldb.add({"dn": "x=x,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "1"})
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2",
+ "y": "1"})
+ self.ldb.add({"dn": "x=z,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde3",
+ "y": "1"})
+
+ res = self.ldb.search(expression="(y=1)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 3)
+
+ # Now set this to unique index, but forget to check the result
+ try:
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "UNIQUE_INDEX"})
+ self.fail()
+ except ldb.LdbError:
+ pass
+
+ # We must still have a working index
+ res = self.ldb.search(expression="(y=1)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 3)
+
+ def test_unique_transaction(self):
+ self.ldb.add({"dn": "x=x,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "1"})
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2",
+ "y": "1"})
+ self.ldb.add({"dn": "x=z,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde3",
+ "y": "1"})
+
+ res = self.ldb.search(expression="(y=1)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 3)
+
+ self.ldb.transaction_start()
+
+ # Now set this to unique index, but forget to check the result
+ try:
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "UNIQUE_INDEX"})
+ except ldb.LdbError:
+ pass
+
+ try:
+ self.ldb.transaction_commit()
+ self.fail()
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
+
+ # We must still have a working index
+ res = self.ldb.search(expression="(y=1)",
+ base="dc=samba,dc=org")
+
+ self.assertEqual(len(res), 3)
+
+ def test_casefold(self):
+ self.ldb.add({"dn": "x=x,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "a"})
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2",
+ "y": "A"})
+ self.ldb.add({"dn": "x=z,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde3",
+ "y": ["a", "A"]})
+
+ res = self.ldb.search(expression="(y=a)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 2)
+
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "CASE_INSENSITIVE"})
+
+ # We must still have a working index
+ res = self.ldb.search(expression="(y=a)",
+ base="dc=samba,dc=org")
+
+ if hasattr(self, 'IDXGUID'):
+ self.assertEqual(len(res), 3)
+ else:
+ # We should not return this entry twice, but sadly
+ # we have not yet fixed
+ # https://bugzilla.samba.org/show_bug.cgi?id=13361
+ self.assertEqual(len(res), 4)
+
+ def test_casefold_transaction(self):
+ self.ldb.add({"dn": "x=x,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "a"})
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2",
+ "y": "A"})
+ self.ldb.add({"dn": "x=z,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde3",
+ "y": ["a", "A"]})
+
+ res = self.ldb.search(expression="(y=a)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 2)
+
+ self.ldb.transaction_start()
+
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "CASE_INSENSITIVE"})
+
+ self.ldb.transaction_commit()
+
+ # We must still have a working index
+ res = self.ldb.search(expression="(y=a)",
+ base="dc=samba,dc=org")
+
+ if hasattr(self, 'IDXGUID'):
+ self.assertEqual(len(res), 3)
+ else:
+ # We should not return this entry twice, but sadly
+ # we have not yet fixed
+ # https://bugzilla.samba.org/show_bug.cgi?id=13361
+ self.assertEqual(len(res), 4)
+
+ def test_modify_transaction(self):
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "2",
+ "z": "2"})
+
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "UNIQUE_INDEX"})
+
+ self.ldb.transaction_start()
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb, "x=y,dc=samba,dc=org")
+ m["0"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "y")
+ m["1"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "not-here")
+
+ try:
+ self.ldb.modify(m)
+ self.fail()
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_ATTRIBUTE)
+
+ try:
+ self.ldb.transaction_commit()
+ # We should fail here, but we want to be sure
+ # we fail below
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
+
+ # The index should still be pointing to x=y
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ try:
+ self.ldb.add({"dn": "x=y2,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2",
+ "y": "2"})
+ self.fail("Added unique attribute twice")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
+
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ self.assertEqual(str(res[0].dn), "x=y,dc=samba,dc=org")
+
+ def tearDown(self):
+ super(BadIndexTests, self).tearDown()
+
+
+class GUIDBadIndexTests(BadIndexTests):
+ """Test Bad index things with GUID index mode"""
+
+ def setUp(self):
+ self.IDXGUID = True
+
+ super(GUIDBadIndexTests, self).setUp()
+
+
+class GUIDBadIndexTestsLmdb(BadIndexTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ self.IDXGUID = True
+ super(GUIDBadIndexTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDBadIndexTestsLmdb, self).tearDown()
+
+
+class BatchModeTests(LdbBaseTest):
+
+ def setUp(self):
+ super(BatchModeTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.url(),
+ flags=self.flags(),
+ options=["batch_mode:1"])
+ if hasattr(self, 'IDXGUID'):
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+ else:
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"]})
+
+ def test_modify_transaction(self):
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "2",
+ "z": "2"})
+
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "UNIQUE_INDEX"})
+
+ self.ldb.transaction_start()
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb, "x=y,dc=samba,dc=org")
+ m["0"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "y")
+ m["1"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "not-here")
+
+ try:
+ self.ldb.modify(m)
+ self.fail()
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_ATTRIBUTE)
+
+ try:
+ self.ldb.transaction_commit()
+ self.fail("Commit should have failed as we were in batch mode")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
+
+ def tearDown(self):
+ super(BatchModeTests, self).tearDown()
+
+
+class DnTests(TestCase):
+
+ def setUp(self):
+ super(DnTests, self).setUp()
+ self.ldb = ldb.Ldb()
+
+ def tearDown(self):
+ super(DnTests, self).tearDown()
+ del(self.ldb)
+
+ def test_set_dn_invalid(self):
+ x = ldb.Message()
+
+ def assign():
+ x.dn = "astring"
+ self.assertRaises(TypeError, assign)
+
+ def test_eq(self):
+ x = ldb.Dn(self.ldb, "dc=foo11,bar=bloe")
+ y = ldb.Dn(self.ldb, "dc=foo11,bar=bloe")
+ self.assertEqual(x, y)
+ y = ldb.Dn(self.ldb, "dc=foo11,bar=blie")
+ self.assertNotEqual(x, y)
+
+ def test_str(self):
+ x = ldb.Dn(self.ldb, "dc=foo12,bar=bloe")
+ self.assertEqual(x.__str__(), "dc=foo12,bar=bloe")
+
+ def test_repr(self):
+ x = ldb.Dn(self.ldb, "dc=foo13,bla=blie")
+ self.assertEqual(x.__repr__(), "Dn('dc=foo13,bla=blie')")
+
+ def test_get_casefold_2(self):
+ x = ldb.Dn(self.ldb, "dc=foo14,bar=bloe")
+ self.assertEqual(x.get_casefold(), "DC=FOO14,BAR=bloe")
+
+ def test_validate(self):
+ x = ldb.Dn(self.ldb, "dc=foo15,bar=bloe")
+ self.assertTrue(x.validate())
+
+ def test_parent(self):
+ x = ldb.Dn(self.ldb, "dc=foo16,bar=bloe")
+ self.assertEqual("bar=bloe", x.parent().__str__())
+
+ def test_parent_nonexistent(self):
+ x = ldb.Dn(self.ldb, "@BLA")
+ self.assertEqual(None, x.parent())
+
+ def test_is_valid(self):
+ x = ldb.Dn(self.ldb, "dc=foo18,dc=bloe")
+ self.assertTrue(x.is_valid())
+ x = ldb.Dn(self.ldb, "")
+ self.assertTrue(x.is_valid())
+
+ def test_is_special(self):
+ x = ldb.Dn(self.ldb, "dc=foo19,bar=bloe")
+ self.assertFalse(x.is_special())
+ x = ldb.Dn(self.ldb, "@FOOBAR")
+ self.assertTrue(x.is_special())
+
+ def test_check_special(self):
+ x = ldb.Dn(self.ldb, "dc=foo20,bar=bloe")
+ self.assertFalse(x.check_special("FOOBAR"))
+ x = ldb.Dn(self.ldb, "@FOOBAR")
+ self.assertTrue(x.check_special("@FOOBAR"))
+
+ def test_len(self):
+ x = ldb.Dn(self.ldb, "dc=foo21,bar=bloe")
+ self.assertEqual(2, len(x))
+ x = ldb.Dn(self.ldb, "dc=foo21")
+ self.assertEqual(1, len(x))
+
+ def test_add_child(self):
+ x = ldb.Dn(self.ldb, "dc=foo22,bar=bloe")
+ self.assertTrue(x.add_child(ldb.Dn(self.ldb, "bla=bloe")))
+ self.assertEqual("bla=bloe,dc=foo22,bar=bloe", x.__str__())
+
+ def test_add_base(self):
+ x = ldb.Dn(self.ldb, "dc=foo23,bar=bloe")
+ base = ldb.Dn(self.ldb, "bla=bloe")
+ self.assertTrue(x.add_base(base))
+ self.assertEqual("dc=foo23,bar=bloe,bla=bloe", x.__str__())
+
+ def test_add_child_str(self):
+ x = ldb.Dn(self.ldb, "dc=foo22,bar=bloe")
+ self.assertTrue(x.add_child("bla=bloe"))
+ self.assertEqual("bla=bloe,dc=foo22,bar=bloe", x.__str__())
+
+ def test_add_base_str(self):
+ x = ldb.Dn(self.ldb, "dc=foo23,bar=bloe")
+ base = "bla=bloe"
+ self.assertTrue(x.add_base(base))
+ self.assertEqual("dc=foo23,bar=bloe,bla=bloe", x.__str__())
+
+ def test_add(self):
+ x = ldb.Dn(self.ldb, "dc=foo24")
+ y = ldb.Dn(self.ldb, "bar=bla")
+ self.assertEqual("dc=foo24,bar=bla", str(x + y))
+
+ def test_remove_base_components(self):
+ x = ldb.Dn(self.ldb, "dc=foo24,dc=samba,dc=org")
+ x.remove_base_components(len(x) - 1)
+ self.assertEqual("dc=foo24", str(x))
+
+ def test_parse_ldif(self):
+ msgs = self.ldb.parse_ldif("dn: foo=bar\n")
+ msg = next(msgs)
+ self.assertEqual("foo=bar", str(msg[1].dn))
+ self.assertTrue(isinstance(msg[1], ldb.Message))
+ ldif = self.ldb.write_ldif(msg[1], ldb.CHANGETYPE_NONE)
+ self.assertEqual("dn: foo=bar\n\n", ldif)
+
+ def test_parse_ldif_more(self):
+ msgs = self.ldb.parse_ldif("dn: foo=bar\n\n\ndn: bar=bar")
+ msg = next(msgs)
+ self.assertEqual("foo=bar", str(msg[1].dn))
+ msg = next(msgs)
+ self.assertEqual("bar=bar", str(msg[1].dn))
+
+ def test_print_ldif(self):
+ ldif = '''dn: dc=foo27
+foo: foo
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = [b"foo"]
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
+ def test_print_ldif_binary(self):
+ # this also confirms that ldb flags are set even without a URL)
+ self.ldb = ldb.Ldb(flags=ldb.FLG_SHOW_BINARY)
+ ldif = '''dn: dc=foo27
+foo: f
+öö
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = ["f\nöö"]
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
+
+ def test_print_ldif_no_base64_bad(self):
+ ldif = '''dn: dc=foo27
+foo: f
+öö
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = ["f\nöö"]
+ self.msg["foo"].set_flags(ldb.FLAG_FORCE_NO_BASE64_LDIF)
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
+ def test_print_ldif_no_base64_good(self):
+ ldif = '''dn: dc=foo27
+foo: föö
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = ["föö"]
+ self.msg["foo"].set_flags(ldb.FLAG_FORCE_NO_BASE64_LDIF)
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
+ def test_canonical_string(self):
+ x = ldb.Dn(self.ldb, "dc=foo25,bar=bloe")
+ self.assertEqual("/bloe/foo25", x.canonical_str())
+
+ def test_canonical_ex_string(self):
+ x = ldb.Dn(self.ldb, "dc=foo26,bar=bloe")
+ self.assertEqual("/bloe\nfoo26", x.canonical_ex_str())
+
+ def test_ldb_is_child_of(self):
+ """Testing ldb_dn_compare_dn"""
+ dn1 = ldb.Dn(self.ldb, "dc=base")
+ dn2 = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ dn3 = ldb.Dn(self.ldb, "cn=bar,dc=base")
+ dn4 = ldb.Dn(self.ldb, "cn=baz,cn=bar,dc=base")
+
+ self.assertTrue(dn1.is_child_of(dn1))
+ self.assertTrue(dn2.is_child_of(dn1))
+ self.assertTrue(dn4.is_child_of(dn1))
+ self.assertTrue(dn4.is_child_of(dn3))
+ self.assertTrue(dn4.is_child_of(dn4))
+ self.assertFalse(dn3.is_child_of(dn2))
+ self.assertFalse(dn1.is_child_of(dn4))
+
+ def test_ldb_is_child_of_str(self):
+ """Testing ldb_dn_compare_dn"""
+ dn1_str = "dc=base"
+ dn2_str = "cn=foo,dc=base"
+ dn3_str = "cn=bar,dc=base"
+ dn4_str = "cn=baz,cn=bar,dc=base"
+
+ dn1 = ldb.Dn(self.ldb, dn1_str)
+ dn2 = ldb.Dn(self.ldb, dn2_str)
+ dn3 = ldb.Dn(self.ldb, dn3_str)
+ dn4 = ldb.Dn(self.ldb, dn4_str)
+
+ self.assertTrue(dn1.is_child_of(dn1_str))
+ self.assertTrue(dn2.is_child_of(dn1_str))
+ self.assertTrue(dn4.is_child_of(dn1_str))
+ self.assertTrue(dn4.is_child_of(dn3_str))
+ self.assertTrue(dn4.is_child_of(dn4_str))
+ self.assertFalse(dn3.is_child_of(dn2_str))
+ self.assertFalse(dn1.is_child_of(dn4_str))
+
+ def test_get_component_name(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ self.assertEqual(dn.get_component_name(0), 'cn')
+ self.assertEqual(dn.get_component_name(1), 'dc')
+ self.assertEqual(dn.get_component_name(2), None)
+ self.assertEqual(dn.get_component_name(-1), None)
+
+ def test_get_component_value(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ self.assertEqual(dn.get_component_value(0), 'foo')
+ self.assertEqual(dn.get_component_value(1), 'base')
+ self.assertEqual(dn.get_component_name(2), None)
+ self.assertEqual(dn.get_component_name(-1), None)
+
+ def test_set_component(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ dn.set_component(0, 'cn', 'bar')
+ self.assertEqual(str(dn), "cn=bar,dc=base")
+ dn.set_component(1, 'o', 'asep')
+ self.assertEqual(str(dn), "cn=bar,o=asep")
+ self.assertRaises(TypeError, dn.set_component, 2, 'dc', 'base')
+ self.assertEqual(str(dn), "cn=bar,o=asep")
+ dn.set_component(1, 'o', 'a,b+c')
+ self.assertEqual(str(dn), r"cn=bar,o=a\,b\+c")
+
+ def test_set_component_bytes(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ dn.set_component(0, 'cn', b'bar')
+ self.assertEqual(str(dn), "cn=bar,dc=base")
+ dn.set_component(1, 'o', b'asep')
+ self.assertEqual(str(dn), "cn=bar,o=asep")
+
+ def test_set_component_none(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,cn=bar,dc=base")
+ self.assertRaises(TypeError, dn.set_component, 1, 'cn', None)
+
+ def test_get_extended_component_null(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,cn=bar,dc=base")
+ self.assertEqual(dn.get_extended_component("TEST"), None)
+
+ def test_get_extended_component(self):
+ self.ldb._register_test_extensions()
+ dn = ldb.Dn(self.ldb, "<TEST=foo>;cn=bar,dc=base")
+ self.assertEqual(dn.get_extended_component("TEST"), b"foo")
+
+ def test_set_extended_component(self):
+ self.ldb._register_test_extensions()
+ dn = ldb.Dn(self.ldb, "dc=base")
+ dn.set_extended_component("TEST", "foo")
+ self.assertEqual(dn.get_extended_component("TEST"), b"foo")
+ dn.set_extended_component("TEST", b"bar")
+ self.assertEqual(dn.get_extended_component("TEST"), b"bar")
+
+ def test_extended_str(self):
+ self.ldb._register_test_extensions()
+ dn = ldb.Dn(self.ldb, "<TEST=foo>;cn=bar,dc=base")
+ self.assertEqual(dn.extended_str(), "<TEST=foo>;cn=bar,dc=base")
+
+ def test_get_rdn_name(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ self.assertEqual(dn.get_rdn_name(), 'cn')
+
+ def test_get_rdn_value(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ self.assertEqual(dn.get_rdn_value(), 'foo')
+
+ def test_get_casefold(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ self.assertEqual(dn.get_casefold(), 'CN=FOO,DC=BASE')
+
+ def test_get_linearized(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ self.assertEqual(dn.get_linearized(), 'cn=foo,dc=base')
+
+ def test_is_null(self):
+ dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
+ self.assertFalse(dn.is_null())
+
+ dn = ldb.Dn(self.ldb, '')
+ self.assertTrue(dn.is_null())
+
+
+class LdbMsgTests(TestCase):
+
+ def setUp(self):
+ super(LdbMsgTests, self).setUp()
+ self.msg = ldb.Message()
+
+ def test_init_dn(self):
+ self.msg = ldb.Message(ldb.Dn(ldb.Ldb(), "dc=foo27"))
+ self.assertEqual("dc=foo27", str(self.msg.dn))
+
+ def test_iter_items(self):
+ self.assertEqual(0, len(self.msg.items()))
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo28")
+ self.assertEqual(1, len(self.msg.items()))
+
+ def test_items(self):
+ self.msg["foo"] = ["foo"]
+ self.msg["bar"] = ["bar"]
+ try:
+ items = self.msg.items()
+ except:
+ self.fail()
+ self.assertEqual([("foo", ldb.MessageElement(["foo"])),
+ ("bar", ldb.MessageElement(["bar"]))],
+ items)
+
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=test")
+ try:
+ items = self.msg.items()
+ except:
+ self.fail()
+ self.assertEqual([("dn", ldb.Dn(ldb.Ldb(), "dc=test")),
+ ("foo", ldb.MessageElement(["foo"])),
+ ("bar", ldb.MessageElement(["bar"]))],
+ items)
+
+ def test_repr(self):
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo29")
+ self.msg["dc"] = b"foo"
+ self.assertIn(repr(self.msg), [
+ "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])})",
+ "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')})",
+ ])
+ self.assertIn(repr(self.msg.text), [
+ "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])}).text",
+ "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')}).text",
+ ])
+
+ def test_len(self):
+ self.assertEqual(0, len(self.msg))
+
+ def test_notpresent(self):
+ self.assertRaises(KeyError, lambda: self.msg["foo"])
+
+ def test_invalid(self):
+ try:
+ self.assertRaises(TypeError, lambda: self.msg[42])
+ except KeyError:
+ self.fail()
+
+ def test_del(self):
+ del self.msg["foo"]
+
+ def test_add(self):
+ self.msg.add(ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla"))
+
+ def test_add_text(self):
+ self.msg.add(ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla"))
+
+ def test_elements_empty(self):
+ self.assertEqual([], self.msg.elements())
+
+ def test_elements(self):
+ el = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+ self.msg.add(el)
+ self.assertEqual([el], self.msg.elements())
+ self.assertEqual([el.text], self.msg.text.elements())
+
+ def test_add_value(self):
+ self.assertEqual(0, len(self.msg))
+ self.msg["foo"] = [b"foo"]
+ self.assertEqual(1, len(self.msg))
+
+ def test_add_value_text(self):
+ self.assertEqual(0, len(self.msg))
+ self.msg["foo"] = ["foo"]
+ self.assertEqual(1, len(self.msg))
+
+ def test_add_value_multiple(self):
+ self.assertEqual(0, len(self.msg))
+ self.msg["foo"] = [b"foo", b"bla"]
+ self.assertEqual(1, len(self.msg))
+ self.assertEqual([b"foo", b"bla"], list(self.msg["foo"]))
+
+ def test_add_value_multiple_text(self):
+ self.assertEqual(0, len(self.msg))
+ self.msg["foo"] = ["foo", "bla"]
+ self.assertEqual(1, len(self.msg))
+ self.assertEqual(["foo", "bla"], list(self.msg.text["foo"]))
+
+ def test_set_value(self):
+ self.msg["foo"] = [b"fool"]
+ self.assertEqual([b"fool"], list(self.msg["foo"]))
+ self.msg["foo"] = [b"bar"]
+ self.assertEqual([b"bar"], list(self.msg["foo"]))
+
+ def test_set_value_text(self):
+ self.msg["foo"] = ["fool"]
+ self.assertEqual(["fool"], list(self.msg.text["foo"]))
+ self.msg["foo"] = ["bar"]
+ self.assertEqual(["bar"], list(self.msg.text["foo"]))
+
+ def test_keys(self):
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
+ self.msg["foo"] = [b"bla"]
+ self.msg["bar"] = [b"bla"]
+ self.assertEqual(["dn", "foo", "bar"], list(self.msg.keys()))
+
+ def test_keys_text(self):
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
+ self.msg["foo"] = ["bla"]
+ self.msg["bar"] = ["bla"]
+ self.assertEqual(["dn", "foo", "bar"], list(self.msg.text.keys()))
+
+ def test_dn(self):
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
+ self.assertEqual("@BASEINFO", self.msg.dn.__str__())
+
+ def test_get_dn(self):
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
+ self.assertEqual("@BASEINFO", self.msg.get("dn").__str__())
+
+ def test_dn_text(self):
+ self.msg.text.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
+ self.assertEqual("@BASEINFO", str(self.msg.dn))
+ self.assertEqual("@BASEINFO", str(self.msg.text.dn))
+
+ def test_get_dn_text(self):
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
+ self.assertEqual("@BASEINFO", str(self.msg.get("dn")))
+ self.assertEqual("@BASEINFO", str(self.msg.text.get("dn")))
+
+ def test_get_invalid(self):
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
+ self.assertRaises(TypeError, self.msg.get, 42)
+
+ def test_get_other(self):
+ self.msg["foo"] = [b"bar"]
+ self.assertEqual(b"bar", self.msg.get("foo")[0])
+ self.assertEqual(b"bar", self.msg.get("foo", idx=0))
+ self.assertEqual(None, self.msg.get("foo", idx=1))
+ self.assertEqual("", self.msg.get("foo", default='', idx=1))
+
+ def test_get_other_text(self):
+ self.msg["foo"] = ["bar"]
+ self.assertEqual(["bar"], list(self.msg.text.get("foo")))
+ self.assertEqual("bar", self.msg.text.get("foo")[0])
+ self.assertEqual("bar", self.msg.text.get("foo", idx=0))
+ self.assertEqual(None, self.msg.get("foo", idx=1))
+ self.assertEqual("", self.msg.get("foo", default='', idx=1))
+
+ def test_get_default(self):
+ self.assertEqual(None, self.msg.get("tatayoyo", idx=0))
+ self.assertEqual("anniecordie", self.msg.get("tatayoyo", "anniecordie"))
+
+ def test_get_default_text(self):
+ self.assertEqual(None, self.msg.text.get("tatayoyo", idx=0))
+ self.assertEqual("anniecordie", self.msg.text.get("tatayoyo", "anniecordie"))
+
+ def test_get_unknown(self):
+ self.assertEqual(None, self.msg.get("lalalala"))
+
+ def test_get_unknown_text(self):
+ self.assertEqual(None, self.msg.text.get("lalalala"))
+
+ def test_contains(self):
+ self.msg['foo'] = ['bar']
+ self.assertIn('foo', self.msg)
+
+ self.msg['Foo'] = ['bar']
+ self.assertIn('Foo', self.msg)
+
+ def test_contains_case(self):
+ self.msg['foo'] = ['bar']
+ self.assertIn('Foo', self.msg)
+
+ self.msg['Foo'] = ['bar']
+ self.assertIn('foo', self.msg)
+
+ def test_contains_dn(self):
+ self.assertIn('dn', self.msg)
+
+ def test_contains_dn_case(self):
+ self.assertIn('DN', self.msg)
+
+ def test_contains_invalid(self):
+ self.assertRaises(TypeError, lambda: None in self.msg)
+
+ def test_msg_diff(self):
+ l = ldb.Ldb()
+ msgs = l.parse_ldif("dn: foo=bar\nfoo: bar\nbaz: do\n\ndn: foo=bar\nfoo: bar\nbaz: dont\n")
+ msg1 = next(msgs)[1]
+ msg2 = next(msgs)[1]
+ msgdiff = l.msg_diff(msg1, msg2)
+ self.assertEqual("foo=bar", msgdiff.get("dn").__str__())
+ self.assertRaises(KeyError, lambda: msgdiff["foo"])
+ self.assertEqual(1, len(msgdiff))
+
+ def test_equal_empty(self):
+ msg1 = ldb.Message()
+ msg2 = ldb.Message()
+ self.assertEqual(msg1, msg2)
+
+ def test_equal_simplel(self):
+ db = ldb.Ldb()
+ msg1 = ldb.Message()
+ msg1.dn = ldb.Dn(db, "foo=bar")
+ msg2 = ldb.Message()
+ msg2.dn = ldb.Dn(db, "foo=bar")
+ self.assertEqual(msg1, msg2)
+ msg1['foo'] = b'bar'
+ msg2['foo'] = b'bar'
+ self.assertEqual(msg1, msg2)
+ msg2['foo'] = b'blie'
+ self.assertNotEqual(msg1, msg2)
+ msg2['foo'] = b'blie'
+
+ def test_from_dict(self):
+ rec = {"dn": "dc=fromdict",
+ "a1": [b"a1-val1", b"a1-val1"]}
+ l = ldb.Ldb()
+ # check different types of input Flags
+ for flags in [ldb.FLAG_MOD_ADD, ldb.FLAG_MOD_REPLACE, ldb.FLAG_MOD_DELETE]:
+ m = ldb.Message.from_dict(l, rec, flags)
+ self.assertEqual(rec["a1"], list(m["a1"]))
+ self.assertEqual(flags, m["a1"].flags())
+ # check input params
+ self.assertRaises(TypeError, ldb.Message.from_dict, dict(), rec, ldb.FLAG_MOD_REPLACE)
+ self.assertRaises(TypeError, ldb.Message.from_dict, l, list(), ldb.FLAG_MOD_REPLACE)
+ self.assertRaises(ValueError, ldb.Message.from_dict, l, rec, 0)
+ # Message.from_dict expects dictionary with 'dn'
+ err_rec = {"a1": [b"a1-val1", b"a1-val1"]}
+ self.assertRaises(TypeError, ldb.Message.from_dict, l, err_rec, ldb.FLAG_MOD_REPLACE)
+
+ def test_from_dict_text(self):
+ rec = {"dn": "dc=fromdict",
+ "a1": ["a1-val1", "a1-val1"]}
+ l = ldb.Ldb()
+ # check different types of input Flags
+ for flags in [ldb.FLAG_MOD_ADD, ldb.FLAG_MOD_REPLACE, ldb.FLAG_MOD_DELETE]:
+ m = ldb.Message.from_dict(l, rec, flags)
+ self.assertEqual(rec["a1"], list(m.text["a1"]))
+ self.assertEqual(flags, m.text["a1"].flags())
+ # check input params
+ self.assertRaises(TypeError, ldb.Message.from_dict, dict(), rec, ldb.FLAG_MOD_REPLACE)
+ self.assertRaises(TypeError, ldb.Message.from_dict, l, list(), ldb.FLAG_MOD_REPLACE)
+ self.assertRaises(ValueError, ldb.Message.from_dict, l, rec, 0)
+ # Message.from_dict expects dictionary with 'dn'
+ err_rec = {"a1": ["a1-val1", "a1-val1"]}
+ self.assertRaises(TypeError, ldb.Message.from_dict, l, err_rec, ldb.FLAG_MOD_REPLACE)
+
+ def test_copy_add_message_element(self):
+ m = ldb.Message()
+ m["1"] = ldb.MessageElement([b"val 111"], ldb.FLAG_MOD_ADD, "1")
+ m["2"] = ldb.MessageElement([b"val 222"], ldb.FLAG_MOD_ADD, "2")
+ mto = ldb.Message()
+ mto["1"] = m["1"]
+ mto["2"] = m["2"]
+ self.assertEqual(mto["1"], m["1"])
+ self.assertEqual(mto["2"], m["2"])
+ mto = ldb.Message()
+ mto.add(m["1"])
+ mto.add(m["2"])
+ self.assertEqual(mto["1"], m["1"])
+ self.assertEqual(mto["2"], m["2"])
+
+ def test_copy_add_message_element_text(self):
+ m = ldb.Message()
+ m["1"] = ldb.MessageElement(["val 111"], ldb.FLAG_MOD_ADD, "1")
+ m["2"] = ldb.MessageElement(["val 222"], ldb.FLAG_MOD_ADD, "2")
+ mto = ldb.Message()
+ mto["1"] = m["1"]
+ mto["2"] = m["2"]
+ self.assertEqual(mto["1"], m.text["1"])
+ self.assertEqual(mto["2"], m.text["2"])
+ mto = ldb.Message()
+ mto.add(m["1"])
+ mto.add(m["2"])
+ self.assertEqual(mto.text["1"], m.text["1"])
+ self.assertEqual(mto.text["2"], m.text["2"])
+ self.assertEqual(mto["1"], m["1"])
+ self.assertEqual(mto["2"], m["2"])
+
+
+class MessageElementTests(TestCase):
+
+ def test_cmp_element(self):
+ x = ldb.MessageElement([b"foo"])
+ y = ldb.MessageElement([b"foo"])
+ z = ldb.MessageElement([b"bzr"])
+ self.assertEqual(x, y)
+ self.assertNotEqual(x, z)
+
+ def test_cmp_element_text(self):
+ x = ldb.MessageElement([b"foo"])
+ y = ldb.MessageElement(["foo"])
+ self.assertEqual(x, y)
+
+ def test_create_iterable(self):
+ x = ldb.MessageElement([b"foo"])
+ self.assertEqual([b"foo"], list(x))
+ self.assertEqual(["foo"], list(x.text))
+
+ def test_repr(self):
+ x = ldb.MessageElement([b"foo"])
+ self.assertEqual("MessageElement([b'foo'])", repr(x))
+ self.assertEqual("MessageElement([b'foo']).text", repr(x.text))
+ x = ldb.MessageElement([b"foo", b"bla"])
+ self.assertEqual(2, len(x))
+ self.assertEqual("MessageElement([b'foo',b'bla'])", repr(x))
+ self.assertEqual("MessageElement([b'foo',b'bla']).text", repr(x.text))
+
+ def test_get_item(self):
+ x = ldb.MessageElement([b"foo", b"bar"])
+ self.assertEqual(b"foo", x[0])
+ self.assertEqual(b"bar", x[1])
+ self.assertEqual(b"bar", x[-1])
+ self.assertRaises(IndexError, lambda: x[45])
+
+ def test_get_item_text(self):
+ x = ldb.MessageElement(["foo", "bar"])
+ self.assertEqual("foo", x.text[0])
+ self.assertEqual("bar", x.text[1])
+ self.assertEqual("bar", x.text[-1])
+ self.assertRaises(IndexError, lambda: x[45])
+
+ def test_len(self):
+ x = ldb.MessageElement([b"foo", b"bar"])
+ self.assertEqual(2, len(x))
+
+ def test_eq(self):
+ x = ldb.MessageElement([b"foo", b"bar"])
+ y = ldb.MessageElement([b"foo", b"bar"])
+ self.assertEqual(y, x)
+ x = ldb.MessageElement([b"foo"])
+ self.assertNotEqual(y, x)
+ y = ldb.MessageElement([b"foo"])
+ self.assertEqual(y, x)
+
+ def test_extended(self):
+ el = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
+ self.assertEqual("MessageElement([b'456'])", repr(el))
+ self.assertEqual("MessageElement([b'456']).text", repr(el.text))
+
+ def test_bad_text(self):
+ el = ldb.MessageElement(b'\xba\xdd')
+ self.assertRaises(UnicodeDecodeError, el.text.__getitem__, 0)
+
+
+class ModuleTests(TestCase):
+
+ def setUp(self):
+ super(ModuleTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.filename)
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(ModuleTests, self).setUp()
+
+ def test_register_module(self):
+ class ExampleModule:
+ name = "example"
+ ldb.register_module(ExampleModule)
+
+ def test_use_module(self):
+ ops = []
+
+ class ExampleModule:
+ name = "bla"
+
+ def __init__(self, ldb, next):
+ ops.append("init")
+ self.next = next
+
+ def search(self, *args, **kwargs):
+ return self.next.search(*args, **kwargs)
+
+ def request(self, *args, **kwargs):
+ pass
+
+ ldb.register_module(ExampleModule)
+ l = ldb.Ldb(self.filename)
+ l.add({"dn": "@MODULES", "@LIST": "bla"})
+ self.assertEqual([], ops)
+ l = ldb.Ldb(self.filename)
+ self.assertEqual(["init"], ops)
+
+
+class LdbResultTests(LdbBaseTest):
+
+ def setUp(self):
+ super(LdbResultTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.l = ldb.Ldb(self.url(), flags=self.flags())
+ try:
+ self.l.add(self.index)
+ except AttributeError:
+ pass
+ self.l.add({"dn": "DC=SAMBA,DC=ORG", "name": b"samba.org",
+ "objectUUID": b"0123456789abcde0"})
+ self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG", "name": b"Admins",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG", "name": b"Users",
+ "objectUUID": b"0123456789abcde2"})
+ self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG", "name": b"OU #1",
+ "objectUUID": b"0123456789abcde3"})
+ self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG", "name": b"OU #2",
+ "objectUUID": b"0123456789abcde4"})
+ self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG", "name": b"OU #3",
+ "objectUUID": b"0123456789abcde5"})
+ self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG", "name": b"OU #4",
+ "objectUUID": b"0123456789abcde6"})
+ self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG", "name": b"OU #5",
+ "objectUUID": b"0123456789abcde7"})
+ self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG", "name": b"OU #6",
+ "objectUUID": b"0123456789abcde8"})
+ self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG", "name": b"OU #7",
+ "objectUUID": b"0123456789abcde9"})
+ self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG", "name": b"OU #8",
+ "objectUUID": b"0123456789abcdea"})
+ self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG", "name": b"OU #9",
+ "objectUUID": b"0123456789abcdeb"})
+ self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG", "name": b"OU #10",
+ "objectUUID": b"0123456789abcdec"})
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(LdbResultTests, self).tearDown()
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+ def test_return_type(self):
+ res = self.l.search()
+ self.assertEqual(str(res), "<ldb result>")
+
+ def test_get_msgs(self):
+ res = self.l.search()
+ list = res.msgs
+
+ def test_get_controls(self):
+ res = self.l.search()
+ list = res.controls
+
+ def test_get_referals(self):
+ res = self.l.search()
+ list = res.referals
+
+ def test_iter_msgs(self):
+ found = False
+ for l in self.l.search().msgs:
+ if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
+ found = True
+ self.assertTrue(found)
+
+ def test_iter_msgs_count(self):
+ self.assertTrue(self.l.search().count > 0)
+ # 13 objects has been added to the DC=SAMBA, DC=ORG
+ self.assertEqual(self.l.search(base="DC=SAMBA,DC=ORG").count, 13)
+
+ def test_iter_controls(self):
+ res = self.l.search().controls
+ it = iter(res)
+
+ def test_create_control(self):
+ self.assertRaises(ValueError, ldb.Control, self.l, "tatayoyo:0")
+ c = ldb.Control(self.l, "relax:1")
+ self.assertEqual(c.critical, True)
+ self.assertEqual(c.oid, "1.3.6.1.4.1.4203.666.5.12")
+
+ def test_iter_refs(self):
+ res = self.l.search().referals
+ it = iter(res)
+
+ def test_search_sequence_msgs(self):
+ found = False
+ res = self.l.search().msgs
+
+ for i in range(0, len(res)):
+ l = res[i]
+ if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
+ found = True
+ self.assertTrue(found)
+
+ def test_search_as_iter(self):
+ found = False
+ res = self.l.search()
+
+ for l in res:
+ if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
+ found = True
+ self.assertTrue(found)
+
+ def test_search_iter(self):
+ found = False
+ res = self.l.search_iterator()
+
+ for l in res:
+ if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
+ found = True
+ self.assertTrue(found)
+
+ # Show that search results can't see into a transaction
+
+ def test_search_against_trans(self):
+ found11 = False
+
+ (r1, w1) = os.pipe()
+
+ (r2, w2) = os.pipe()
+
+ # For the first element, fork a child that will
+ # write to the DB
+ pid = os.fork()
+ if pid == 0:
+ # In the child, re-open
+ del(self.l)
+ gc.collect()
+
+ child_ldb = ldb.Ldb(self.url(), flags=self.flags())
+ # start a transaction
+ child_ldb.transaction_start()
+
+ # write to it
+ child_ldb.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
+ "name": b"samba.org",
+ "objectUUID": b"o123456789acbdef"})
+
+ os.write(w1, b"added")
+
+ # Now wait for the search to be done
+ os.read(r2, 6)
+
+ # and commit
+ try:
+ child_ldb.transaction_commit()
+ except ldb.LdbError as err:
+ # We print this here to see what went wrong in the child
+ print(err)
+ os._exit(1)
+
+ os.write(w1, b"transaction")
+ os._exit(0)
+
+ self.assertEqual(os.read(r1, 5), b"added")
+
+ # This should not turn up until the transaction is concluded
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 0)
+
+ os.write(w2, b"search")
+
+ # Now wait for the transaction to be done. This should
+ # deadlock, but the search doesn't hold a read lock for the
+ # iterator lifetime currently.
+ self.assertEqual(os.read(r1, 11), b"transaction")
+
+ # This should now turn up, as the transaction is over
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
+ self.assertFalse(found11)
+
+ (got_pid, status) = os.waitpid(pid, 0)
+ self.assertEqual(got_pid, pid)
+
+ def test_search_iter_against_trans(self):
+ found = False
+ found11 = False
+
+ # We need to hold this iterator open to hold the all-record
+ # lock
+ res = self.l.search_iterator()
+
+ (r1, w1) = os.pipe()
+
+ (r2, w2) = os.pipe()
+
+ # For the first element, with the sequence open (which
+ # means with ldb locks held), fork a child that will
+ # write to the DB
+ pid = os.fork()
+ if pid == 0:
+ # In the child, re-open
+ del(res)
+ del(self.l)
+ gc.collect()
+
+ child_ldb = ldb.Ldb(self.url(), flags=self.flags())
+ # start a transaction
+ child_ldb.transaction_start()
+
+ # write to it
+ child_ldb.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
+ "name": b"samba.org",
+ "objectUUID": b"o123456789acbdef"})
+
+ os.write(w1, b"added")
+
+ # Now wait for the search to be done
+ os.read(r2, 6)
+
+ # and commit
+ try:
+ child_ldb.transaction_commit()
+ except ldb.LdbError as err:
+ # We print this here to see what went wrong in the child
+ print(err)
+ os._exit(1)
+
+ os.write(w1, b"transaction")
+ os._exit(0)
+
+ self.assertEqual(os.read(r1, 5), b"added")
+
+ # This should not turn up until the transaction is concluded
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 0)
+
+ os.write(w2, b"search")
+
+ # allow the transaction to start
+ time.sleep(1)
+
+ # This should not turn up until the search finishes and
+ # removed the read lock, but for ldb_tdb that happened as soon
+ # as we called the first res.next()
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 0)
+
+ # These results are all collected at the first next(res) call
+ for l in res:
+ if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
+ found = True
+ if str(l.dn) == "OU=OU11,DC=SAMBA,DC=ORG":
+ found11 = True
+
+ # Now wait for the transaction to be done.
+ self.assertEqual(os.read(r1, 11), b"transaction")
+
+ # This should now turn up, as the transaction is over and all
+ # read locks are gone
+ res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res11), 1)
+
+ self.assertTrue(found)
+ self.assertFalse(found11)
+
+ (got_pid, status) = os.waitpid(pid, 0)
+ self.assertEqual(got_pid, pid)
+
+
+class LdbResultTestsLmdb(LdbResultTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(LdbResultTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(LdbResultTestsLmdb, self).tearDown()
+
+
+class BadTypeTests(TestCase):
+ def test_control(self):
+ l = ldb.Ldb()
+ self.assertRaises(TypeError, ldb.Control, '<bad type>', 'relax:1')
+ self.assertRaises(TypeError, ldb.Control, ldb, 1234)
+
+ def test_modify(self):
+ l = ldb.Ldb()
+ dn = ldb.Dn(l, 'a=b')
+ m = ldb.Message(dn)
+ self.assertRaises(TypeError, l.modify, '<bad type>')
+ self.assertRaises(TypeError, l.modify, m, '<bad type>')
+
+ def test_add(self):
+ l = ldb.Ldb()
+ dn = ldb.Dn(l, 'a=b')
+ m = ldb.Message(dn)
+ self.assertRaises(TypeError, l.add, '<bad type>')
+ self.assertRaises(TypeError, l.add, m, '<bad type>')
+
+ def test_delete(self):
+ l = ldb.Ldb()
+ dn = ldb.Dn(l, 'a=b')
+ self.assertRaises(TypeError, l.add, '<bad type>')
+ self.assertRaises(TypeError, l.add, dn, '<bad type>')
+
+ def test_rename(self):
+ l = ldb.Ldb()
+ dn = ldb.Dn(l, 'a=b')
+ self.assertRaises(TypeError, l.add, '<bad type>', dn)
+ self.assertRaises(TypeError, l.add, dn, '<bad type>')
+ self.assertRaises(TypeError, l.add, dn, dn, '<bad type>')
+
+ def test_search(self):
+ l = ldb.Ldb()
+ self.assertRaises(TypeError, l.search, base=1234)
+ self.assertRaises(TypeError, l.search, scope='<bad type>')
+ self.assertRaises(TypeError, l.search, expression=1234)
+ self.assertRaises(TypeError, l.search, attrs='<bad type>')
+ self.assertRaises(TypeError, l.search, controls='<bad type>')
+
+
+class VersionTests(TestCase):
+
+ def test_version(self):
+ self.assertTrue(isinstance(ldb.__version__, str))
+
+class NestedTransactionTests(LdbBaseTest):
+ def setUp(self):
+ super(NestedTransactionTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.url(), flags=self.flags())
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+
+ super(NestedTransactionTests, self).setUp()
+
+ #
+ # This test documents that currently ldb does not support true nested
+ # transactions.
+ #
+ # Note: The test is written so that it treats failure as pass.
+ # It is done this way as standalone ldb builds do not use the samba
+ # known fail mechanism
+ #
+ def test_nested_transactions(self):
+
+ self.ldb.transaction_start()
+
+ self.ldb.add({"dn": "x=x1,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1"})
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde1)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.add({"dn": "x=x2,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2"})
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.transaction_start()
+ self.ldb.add({"dn": "x=x3,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde3"})
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ self.ldb.transaction_cancel()
+ #
+ # Check that we can not see the record added by the cancelled
+ # transaction.
+ # Currently this fails as ldb does not support true nested
+ # transactions, and only the outer commits and cancels have an effect
+ #
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
+ base="dc=samba,dc=org")
+ #
+ # FIXME this test currently passes on a failure, i.e. if nested
+ # transaction support worked correctly the correct test would
+ # be.
+ # self.assertEqual(len(res), 0)
+ # as the add of objectUUID=0123456789abcde3 would reverted when
+ # the sub transaction it was nested in was rolled back.
+ #
+ # Currently this is not the case so the record is still present.
+ self.assertEqual(len(res), 1)
+
+
+ # Commit the outer transaction
+ #
+ self.ldb.transaction_commit()
+ #
+ # Now check we can still see the records added in the outer
+ # transaction.
+ #
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde1)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ #
+ # And that we can't see the records added by the nested transaction.
+ #
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
+ base="dc=samba,dc=org")
+ # FIXME again if nested transactions worked correctly we would not
+ # see this record. The test should be.
+ # self.assertEqual(len(res), 0)
+ self.assertEqual(len(res), 1)
+
+ def tearDown(self):
+ super(NestedTransactionTests, self).tearDown()
+
+
+class LmdbNestedTransactionTests(NestedTransactionTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(LmdbNestedTransactionTests, self).setUp()
+
+ def tearDown(self):
+ super(LmdbNestedTransactionTests, self).tearDown()
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.TestProgram()
diff --git a/lib/ldb/tests/python/crash.py b/lib/ldb/tests/python/crash.py
new file mode 100644
index 0000000..3283981
--- /dev/null
+++ b/lib/ldb/tests/python/crash.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+#
+# Tests for crashing functions
+
+import os
+from unittest import TestCase
+import os
+import sys
+import traceback
+
+import ldb
+
+
+def segfault_detector(f):
+ def wrapper(*args, **kwargs):
+ pid = os.fork()
+ if pid == 0:
+ # child, crashing?
+ try:
+ f(*args, **kwargs)
+ except Exception as e:
+ traceback.print_exc()
+ sys.stderr.flush()
+ sys.stdout.flush()
+ os._exit(0)
+
+ # parent, waiting
+ pid2, status = os.waitpid(pid, 0)
+ if os.WIFSIGNALED(status):
+ signal = os.WTERMSIG(status)
+ raise AssertionError("Failed with signal %d" % signal)
+
+ return wrapper
+
+
+class LdbDnCrashTests(TestCase):
+ @segfault_detector
+ def test_ldb_dn_explode_crash(self):
+ for i in range(106, 150):
+ dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i))
+ dn.validate()
+
+if __name__ == '__main__':
+ import unittest
+ unittest.TestProgram()
diff --git a/lib/ldb/tests/python/index.py b/lib/ldb/tests/python/index.py
new file mode 100755
index 0000000..c1da76d
--- /dev/null
+++ b/lib/ldb/tests/python/index.py
@@ -0,0 +1,1454 @@
+#!/usr/bin/env python3
+#
+# Tests for truncated index keys
+#
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+"""Tests for truncated index keys
+
+Databases such as lmdb have a maximum key length, these tests ensure that
+ldb behaves correctly in those circumstances.
+
+"""
+
+import os
+from unittest import TestCase
+import sys
+import ldb
+import shutil
+
+
+TDB_PREFIX = "tdb://"
+MDB_PREFIX = "mdb://"
+
+
+def tempdir():
+ import tempfile
+ try:
+ dir_prefix = os.path.join(os.environ["SELFTEST_PREFIX"], "tmp")
+ except KeyError:
+ dir_prefix = None
+ return tempfile.mkdtemp(dir=dir_prefix)
+
+
+def contains(result, dn):
+ if result is None:
+ return False
+
+ for r in result:
+ if str(r["dn"]) == dn:
+ return True
+ return False
+
+
+class LdbBaseTest(TestCase):
+ def setUp(self):
+ super(LdbBaseTest, self).setUp()
+ try:
+ if self.prefix is None:
+ self.prefix = TDB_PREFIX
+ except AttributeError:
+ self.prefix = TDB_PREFIX
+
+ def tearDown(self):
+ super(LdbBaseTest, self).tearDown()
+
+ def url(self):
+ return self.prefix + self.filename
+
+ def flags(self):
+ if self.prefix == MDB_PREFIX:
+ return ldb.FLG_NOSYNC
+ else:
+ return 0
+
+
+class MaxIndexKeyLengthTests(LdbBaseTest):
+ def checkGuids(self, key, guids):
+ #
+ # This check relies on the current implementation where the indexes
+ # are in the same database as the data.
+ #
+ # It checks that the index record exists, unless guids is None then
+ # the record must not exist. And the it contains the expected guid
+ # entries.
+ #
+ # The caller needs to provide the GUID's in the expected order
+ #
+ res = self.l.search(
+ base=key,
+ scope=ldb.SCOPE_BASE)
+ if guids is None:
+ self.assertEqual(len(res), 0)
+ return
+ self.assertEqual(len(res), 1)
+
+ # The GUID index format has only one value
+ index = res[0]["@IDX"][0]
+ self.assertEqual(len(guids), len(index))
+ self.assertEqual(guids, index)
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(MaxIndexKeyLengthTests, self).tearDown()
+
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+ def setUp(self):
+ super(MaxIndexKeyLengthTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "key_len_test.ldb")
+ # Note that the maximum key length is set to 54
+ # This accounts for the 4 bytes added by the dn formatting
+ # a leading dn=, and a trailing zero terminator
+ #
+ self.l = ldb.Ldb(self.url(),
+ options=[
+ "modules:rdn_name",
+ "max_key_len_for_self_test:54"])
+ self.l.add({"dn": "@ATTRIBUTES",
+ "uniqueThing": "UNIQUE_INDEX"})
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [
+ b"uniqueThing",
+ b"notUnique",
+ b"base64____lt",
+ b"base64_____eq",
+ b"base64______gt"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+
+ # Add a value to a unique index that exceeds the maximum key length
+ # This should be rejected.
+ def test_add_long_unique_add(self):
+ try:
+ self.l.add({"dn": "OU=UNIQUE_MAX_LEN,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcdef",
+ "uniqueThing": "01234567890123456789012345678901"})
+ # index key will be
+ # "@INDEX:UNIQUETHING:01234567890123456789012345678901"
+ self.fail("Should have failed on long index key")
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
+
+ # Test that DN's longer the maximum key length can be added
+ # and that duplicate DN's are rejected correctly
+ def test_add_long_dn_add(self):
+ #
+ # For all entries the DN index key gets truncated to
+ # @INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA
+ #
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcdef"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM",
+ "objectUUID": b"0123456789abcde0"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde0" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde0" + b"0123456789abcde1" + b"0123456789abcdef")
+
+ # Key is equal to max length does not get inserted into the truncated
+ # key namespace
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde5"})
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ # This key should not get truncated, as it's one character less than
+ # max, and will not be in the truncate name space
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde7"})
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde7")
+
+ try:
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcde2"})
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ try:
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM",
+ "objectUUID": b"0123456789abcde3"})
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ try:
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ "objectUUID": b"0123456789abcde4"})
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ try:
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde6"})
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ try:
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde8"})
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ def test_rename_truncated_dn_keys(self):
+ # For all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcdef"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM",
+ "objectUUID": b"0123456789abcde0"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde0" + b"0123456789abcdef")
+
+ # Non conflicting rename, should succeed
+ self.l.rename("OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ # Index should be unchanged.
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde0" + b"0123456789abcdef")
+
+ # Conflicting rename should fail
+ try:
+ self.l.rename("OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM",
+ "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+
+ def test_delete_truncated_dn_keys(self):
+ #
+ # For all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA
+ #
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcdef"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde1" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde5"})
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ # Try to delete a non existent DN with a truncated key
+ try:
+ self.l.delete("OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+ # Ensure that non of the other truncated DN's got deleted
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG")
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ self.assertEqual(len(res), 1)
+
+ # Ensure that the non truncated DN did not get deleted
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA")
+ self.assertEqual(len(res), 1)
+
+ # Check the indexes are correct
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde1" + b"0123456789abcdef")
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ # delete an existing entry
+ self.l.delete("OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG")
+
+ # Ensure it got deleted
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG")
+ self.assertEqual(len(res), 0)
+
+ # Ensure that non of the other truncated DN's got deleted
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ self.assertEqual(len(res), 1)
+
+ # Ensure the non truncated entry did not get deleted.
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA")
+ self.assertEqual(len(res), 1)
+
+ # Check the indexes are correct
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde1")
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ # delete an existing entry
+ self.l.delete("OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+
+ # Ensure it got deleted
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ self.assertEqual(len(res), 0)
+
+ # Ensure that non of the non truncated DN's got deleted
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA")
+ self.assertEqual(len(res), 1)
+ # Check the indexes are correct
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ None)
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ # delete an existing entry
+ self.l.delete("OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA")
+
+ # Ensure it got deleted
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBAxxx")
+ self.assertEqual(len(res), 0)
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ None)
+
+ def test_search_truncated_dn_keys(self):
+ #
+ # For all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA
+ #
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcdef"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde1" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde5"})
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG")
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA")
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM")
+ self.assertEqual(len(res), 0)
+
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ self.assertEqual(len(res), 0)
+
+ # Non existent, key one less than truncation limit
+ res = self.l.search(base="OU=A_LONG_DNXXXXXXXXXXXXXX,DC=SAMBA")
+ self.assertEqual(len(res), 0)
+
+ def test_search_dn_filter_truncated_dn_keys(self):
+ #
+ # For all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA
+ #
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcdef"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde1" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde5"})
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ res = self.l.search(
+ expression="dn=OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG")
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(
+ expression="dn=OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(
+ expression="dn=OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA")
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(
+ expression="dn=OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM")
+ self.assertEqual(len(res), 0)
+
+ res = self.l.search(
+ expression="dn=OU=A_LONG_DNXXXXXXXXXXXX,DC=SAMBA,DC=GOV")
+ self.assertEqual(len(res), 0)
+
+ # Non existent, key one less than truncation limit
+ res = self.l.search(
+ expression="dn=OU=A_LONG_DNXXXXXXXXXXXXXX,DC=SAMBA")
+ self.assertEqual(len(res), 0)
+
+ def test_search_one_level_truncated_dn_keys(self):
+ #
+ # Except for the base DN's
+ # all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=??,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA
+ # The base DN-s truncate to
+ # @INDEX:@IDXDN:OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR
+ #
+ self.l.add({"dn": "OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcdef"})
+ self.l.add({"dn": "OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcd1f"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR",
+ b"0123456789abcd1f" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcd11"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA",
+ b"0123456789abcd11" + b"0123456789abcde1")
+
+ self.l.add({"dn": "OU=02,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcde2"})
+ self.l.add({"dn": "OU=02,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcdf2"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=02,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA",
+ b"0123456789abcde2" + b"0123456789abcdf2")
+
+ self.l.add({"dn": "OU=03,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcde3"})
+ self.l.add({"dn": "OU=03,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcd13"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=03,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA",
+ b"0123456789abcd13" + b"0123456789abcde3")
+
+ # This key is not truncated as it's the max_key_len
+ self.l.add({"dn": "OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde7"})
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA",
+ b"0123456789abcde7")
+
+ res = self.l.search(base="OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1",
+ scope=ldb.SCOPE_ONELEVEL)
+ self.assertEqual(len(res), 3)
+ self.assertTrue(
+ contains(res, "OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1"))
+ self.assertTrue(
+ contains(res, "OU=03,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR1"))
+
+ res = self.l.search(base="OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2",
+ scope=ldb.SCOPE_ONELEVEL)
+ self.assertEqual(len(res), 3)
+ self.assertTrue(
+ contains(res, "OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2"))
+ self.assertTrue(
+ contains(res, "OU=03,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA,DC=OR2"))
+
+ res = self.l.search(base="OU=A_LONG_DN_ONE_LVLX,DC=SAMBA",
+ scope=ldb.SCOPE_ONELEVEL)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=01,OU=A_LONG_DN_ONE_LVLX,DC=SAMBA"))
+
+ def test_search_sub_tree_truncated_dn_keys(self):
+ #
+ # Except for the base DN's
+ # all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=??,OU=A_LONG_DN_SUB_TREE,DC=SAMBA
+ # The base DN-s truncate to
+ # @INDEX:@IDXDN:OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR
+ #
+ self.l.add({"dn": "OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcdef"})
+ self.l.add({"dn": "OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcde4"})
+ self.l.add({"dn": "OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR3",
+ "objectUUID": b"0123456789abcde8"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR",
+ b"0123456789abcde4" + b"0123456789abcde8" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=01,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=01,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcde5"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=01,OU=A_LONG_DN_SUB_TREE,DC=SAMBA",
+ b"0123456789abcde1" + b"0123456789abcde5")
+
+ self.l.add({"dn": "OU=02,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcde2"})
+ self.l.add({"dn": "OU=02,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcde6"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=02,OU=A_LONG_DN_SUB_TREE,DC=SAMBA",
+ b"0123456789abcde2" + b"0123456789abcde6")
+
+ self.l.add({"dn": "OU=03,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcde3"})
+
+ self.l.add({"dn": "OU=03,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcde7"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=03,OU=A_LONG_DN_SUB_TREE,DC=SAMBA",
+ b"0123456789abcde3" + b"0123456789abcde7")
+
+ self.l.add({"dn": "OU=04,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR4",
+ "objectUUID": b"0123456789abcde9"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=04,OU=A_LONG_DN_SUB_TREE,DC=SAMBA",
+ b"0123456789abcde9")
+
+ res = self.l.search(base="OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1",
+ scope=ldb.SCOPE_SUBTREE)
+ self.assertEqual(len(res), 4)
+ self.assertTrue(
+ contains(res, "OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1"))
+ self.assertTrue(
+ contains(res, "OU=01,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1"))
+ self.assertTrue(
+ contains(res, "OU=03,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR1"))
+
+ res = self.l.search(base="OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2",
+ scope=ldb.SCOPE_SUBTREE)
+ self.assertEqual(len(res), 4)
+ self.assertTrue(
+ contains(res, "OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2"))
+ self.assertTrue(
+ contains(res, "OU=01,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2"))
+ self.assertTrue(
+ contains(res, "OU=03,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR2"))
+
+ res = self.l.search(base="OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR3",
+ scope=ldb.SCOPE_SUBTREE)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR3"))
+
+ res = self.l.search(base="OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR4",
+ scope=ldb.SCOPE_SUBTREE)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=04,OU=A_LONG_DN_SUB_TREE,DC=SAMBA,DC=OR4"))
+
+ def test_search_base_truncated_dn_keys(self):
+ #
+ # For all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA
+ #
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ "objectUUID": b"0123456789abcdef"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde1" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ "objectUUID": b"0123456789abcde5"})
+ self.checkGuids(
+ "@INDEX:@IDXDN:OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ b"0123456789abcde5")
+
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXXX,DC=SAMBA,DC=COM",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 0)
+
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXX,DC=SAMBA,DC=GOV",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 0)
+
+ # Non existent, key one less than truncation limit
+ res = self.l.search(
+ base="OU=A_LONG_DNXXXXXXXXXXXXXX,DC=SAMBA",
+ scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 0)
+
+ #
+ # Test non unique index searched with truncated keys
+ #
+ def test_index_truncated_keys(self):
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+ eq_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ gt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ lt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ # > than max length and differs in values that will be truncated
+ gt_max_b = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
+
+ # Add two entries with the same value, key length = max so no
+ # truncation.
+ self.l.add({"dn": "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": eq_max,
+ "objectUUID": b"0123456789abcde0"})
+ self.checkGuids(
+ "@INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0")
+
+ self.l.add({"dn": "OU=02,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": eq_max,
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" + b"0123456789abcde1")
+
+ #
+ # An entry outside the tree
+ #
+ self.l.add({"dn": "OU=10,OU=SEARCH_NON_UNIQUE01,DC=SAMBA,DC=ORG",
+ "notUnique": eq_max,
+ "objectUUID": b"0123456789abcd11"})
+ self.checkGuids(
+ "@INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcd11" + b"0123456789abcde0" + b"0123456789abcde1")
+
+ # Key longer than max so should get truncated to same key as
+ # the previous two entries
+ self.l.add({"dn": "OU=03,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": gt_max,
+ "objectUUID": b"0123456789abcde2"})
+ # But in the truncated key space
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde2")
+
+ # Key longer than max so should get truncated to same key as
+ # the previous entries but differs in the chars after max length
+ self.l.add({"dn": "OU=23,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": gt_max_b,
+ "objectUUID": b"0123456789abcd22"})
+ # But in the truncated key space
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcd22" + b"0123456789abcde2")
+ #
+ # An entry outside the tree
+ #
+ self.l.add({"dn": "OU=11,OU=SEARCH_NON_UNIQUE01,DC=SAMBA,DC=ORG",
+ "notUnique": gt_max,
+ "objectUUID": b"0123456789abcd12"})
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcd12" + b"0123456789abcd22" + b"0123456789abcde2")
+
+ # Key shorter than max
+ #
+ self.l.add({"dn": "OU=04,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": lt_max,
+ "objectUUID": b"0123456789abcde3"})
+ self.checkGuids(
+ "@INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde3")
+ #
+ # An entry outside the tree
+ #
+ self.l.add({"dn": "OU=12,OU=SEARCH_NON_UNIQUE01,DC=SAMBA,DC=ORG",
+ "notUnique": lt_max,
+ "objectUUID": b"0123456789abcd13"})
+ self.checkGuids(
+ "@INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcd13" + b"0123456789abcde3")
+
+ #
+ # search for target is max value not truncated
+ # should return ou's 01, 02
+ #
+ expression = "(notUnique=" + eq_max.decode('ascii') + ")"
+ res = self.l.search(base="OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 2)
+ self.assertTrue(
+ contains(res, "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ #
+ # search for target is max value not truncated
+ # search one level up the tree, scope is ONE_LEVEL
+ # So should get no matches
+ #
+ expression = "(notUnique=" + eq_max.decode('ascii') + ")"
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 0)
+ #
+ # search for target is max value not truncated
+ # search one level up the tree, scope is SUBTREE
+ # So should get 3 matches
+ #
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression=expression)
+ self.assertEqual(len(res), 3)
+ self.assertTrue(
+ contains(res, "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ self.assertTrue(
+ contains(res, "OU=10,OU=SEARCH_NON_UNIQUE01,DC=SAMBA,DC=ORG"))
+ #
+ # search for target is max value + 1 so truncated
+ # should return ou 23 as it's gt_max_b being searched for
+ #
+ expression = "(notUnique=" + gt_max_b.decode('ascii') + ")"
+ res = self.l.search(base="OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=23,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ #
+ # search for target is max value + 1 so truncated
+ # should return ou 03 as it's gt_max being searched for
+ #
+ expression = "(notUnique=" + gt_max.decode('ascii') + ")"
+ res = self.l.search(base="OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=03,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ #
+ # scope one level and one level up one level up should get no matches
+ #
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 0)
+ #
+ # scope sub tree and one level up one level up should get 2 matches
+ #
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression=expression)
+ self.assertEqual(len(res), 2)
+ self.assertTrue(
+ contains(res, "OU=03,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ self.assertTrue(
+ contains(res, "OU=11,OU=SEARCH_NON_UNIQUE01,DC=SAMBA,DC=ORG"))
+
+ #
+ # search for target is max value - 1 so not truncated
+ # should return ou 04
+ #
+ expression = "(notUnique=" + lt_max.decode('ascii') + ")"
+ res = self.l.search(base="OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=04,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ #
+ # scope one level and one level up one level up should get no matches
+ #
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 0)
+
+ #
+ # scope sub tree and one level up one level up should get 2 matches
+ #
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression=expression)
+ self.assertEqual(len(res), 2)
+ self.assertTrue(
+ contains(res, "OU=04,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ self.assertTrue(
+ contains(res, "OU=12,OU=SEARCH_NON_UNIQUE01,DC=SAMBA,DC=ORG"))
+
+ #
+ # Test index key truncation for base64 encoded values
+ #
+ def test_index_truncated_base64_encoded_keys(self):
+ value = b"aaaaaaaaaaaaaaaaaaaa\x02"
+ # base64 encodes to "YWFhYWFhYWFhYWFhYWFhYWFhYWEC"
+
+ # One less than max key length
+ self.l.add({"dn": "OU=01,OU=BASE64,DC=SAMBA,DC=ORG",
+ "base64____lt": value,
+ "objectUUID": b"0123456789abcde0"})
+ self.checkGuids(
+ "@INDEX:BASE64____LT::YWFhYWFhYWFhYWFhYWFhYWFhYWEC",
+ b"0123456789abcde0")
+
+ # Equal max key length
+ self.l.add({"dn": "OU=02,OU=BASE64,DC=SAMBA,DC=ORG",
+ "base64_____eq": value,
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX:BASE64_____EQ::YWFhYWFhYWFhYWFhYWFhYWFhYWEC",
+ b"0123456789abcde1")
+
+ # One greater than max key length
+ self.l.add({"dn": "OU=03,OU=BASE64,DC=SAMBA,DC=ORG",
+ "base64______gt": value,
+ "objectUUID": b"0123456789abcde2"})
+ self.checkGuids(
+ "@INDEX#BASE64______GT##YWFhYWFhYWFhYWFhYWFhYWFhYWE",
+ b"0123456789abcde2")
+ #
+ # Test adding to non unique index with identical multivalued index
+ # attributes
+ #
+
+ def test_index_multi_valued_identical_keys(self):
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ as_eq_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ bs_eq_max = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+
+ try:
+ self.l.add({"dn": "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": [bs_eq_max, as_eq_max, as_eq_max],
+ "objectUUID": b"0123456789abcde0"})
+ self.fail("Exception not thrown")
+ except ldb.LdbError as e:
+ code = e.args[0]
+ self.assertEqual(ldb.ERR_ATTRIBUTE_OR_VALUE_EXISTS, code)
+
+ #
+ # Test non unique index with multivalued index attributes
+ # searched with non truncated keys
+ #
+ def test_search_index_multi_valued_truncated_keys(self):
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+ aa_gt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ ab_gt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
+ bb_gt_max = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+
+ self.l.add({"dn": "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": [aa_gt_max, ab_gt_max, bb_gt_max],
+ "objectUUID": b"0123456789abcde0"})
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" + b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+
+ expression = "(notUnique=" + aa_gt_max.decode('ascii') + ")"
+ res = self.l.search(base="OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ expression = "(notUnique=" + ab_gt_max.decode('ascii') + ")"
+ res = self.l.search(base="OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ expression = "(notUnique=" + bb_gt_max.decode('ascii') + ")"
+ res = self.l.search(base="OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=expression)
+ self.assertEqual(len(res), 1)
+ self.assertTrue(
+ contains(res, "OU=01,OU=SEARCH_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ #
+ # Test deletion of records with non unique index with multivalued index
+ # attributes
+ # replicate this to test modify with modify flags i.e. DELETE, REPLACE
+ #
+ def test_delete_index_multi_valued_truncated_keys(self):
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+ aa_gt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ ab_gt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
+ bb_gt_max = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ cc_gt_max = b"cccccccccccccccccccccccccccccccccc"
+
+ self.l.add({"dn": "OU=01,OU=DELETE_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": [aa_gt_max, ab_gt_max, bb_gt_max],
+ "objectUUID": b"0123456789abcde0"})
+ self.l.add({"dn": "OU=02,OU=DELETE_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": [aa_gt_max, ab_gt_max, cc_gt_max],
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" + b"0123456789abcde0" +
+ b"0123456789abcde1" + b"0123456789abcde1")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ b"0123456789abcde1")
+
+ res = self.l.search(
+ base="DC=SAMBA,DC=ORG",
+ expression="(notUnique=" + aa_gt_max.decode("ascii") + ")")
+ self.assertEqual(2, len(res))
+ self.assertTrue(
+ contains(res, "OU=01,OU=DELETE_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=DELETE_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ self.l.delete("OU=02,OU=DELETE_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" + b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ None)
+
+ self.l.delete("OU=01,OU=DELETE_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ None)
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ None)
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ None)
+
+ #
+ # Test modification of records with non unique index with multivalued index
+ # attributes
+ #
+ def test_modify_index_multi_valued_truncated_keys(self):
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:NOTUNIQUE:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+ aa_gt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ ab_gt_max = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
+ bb_gt_max = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ cc_gt_max = b"cccccccccccccccccccccccccccccccccc"
+
+ self.l.add({"dn": "OU=01,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": [aa_gt_max, ab_gt_max, bb_gt_max],
+ "objectUUID": b"0123456789abcde0"})
+ self.l.add({"dn": "OU=02,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG",
+ "notUnique": [aa_gt_max, ab_gt_max, cc_gt_max],
+ "objectUUID": b"0123456789abcde1"})
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" + b"0123456789abcde0" +
+ b"0123456789abcde1" + b"0123456789abcde1")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ b"0123456789abcde1")
+
+ res = self.l.search(
+ base="DC=SAMBA,DC=ORG",
+ expression="(notUnique=" + aa_gt_max.decode("ascii") + ")")
+ self.assertEqual(2, len(res))
+ self.assertTrue(
+ contains(res, "OU=01,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG"))
+
+ #
+ # Modify that does not change the indexed attribute
+ #
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(self.l, "OU=01,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ msg["notUnique"] = ldb.MessageElement(
+ [aa_gt_max, ab_gt_max, bb_gt_max],
+ ldb.FLAG_MOD_REPLACE,
+ "notUnique")
+ self.l.modify(msg)
+ #
+ # As the modify is replacing the attribute with the same contents
+ # there should be no changes to the indexes.
+ #
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" + b"0123456789abcde0" +
+ b"0123456789abcde1" + b"0123456789abcde1")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ b"0123456789abcde1")
+
+ #
+ # Modify that removes a value from the indexed attribute
+ #
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(self.l, "OU=01,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ msg["notUnique"] = ldb.MessageElement(
+ [aa_gt_max, bb_gt_max],
+ ldb.FLAG_MOD_REPLACE,
+ "notUnique")
+ self.l.modify(msg)
+
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" +
+ b"0123456789abcde1" + b"0123456789abcde1")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ b"0123456789abcde1")
+
+ #
+ # Modify that does a constrained delete the indexed attribute
+ #
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(self.l, "OU=02,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ msg["notUnique"] = ldb.MessageElement(
+ [ab_gt_max],
+ ldb.FLAG_MOD_DELETE,
+ "notUnique")
+ self.l.modify(msg)
+
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" + b"0123456789abcde1")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ b"0123456789abcde1")
+
+ #
+ # Modify that does an unconstrained delete the indexed attribute
+ #
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(self.l, "OU=02,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ msg["notUnique"] = ldb.MessageElement(
+ [],
+ ldb.FLAG_MOD_DELETE,
+ "notUnique")
+ self.l.modify(msg)
+
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ None)
+
+ #
+ # Modify that adds a value to the indexed attribute
+ #
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(self.l, "OU=02,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ msg["notUnique"] = ldb.MessageElement(
+ [cc_gt_max],
+ ldb.FLAG_MOD_ADD,
+ "notUnique")
+ self.l.modify(msg)
+
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ b"0123456789abcde1")
+
+ #
+ # Modify that adds a values to the indexed attribute
+ #
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(self.l, "OU=02,OU=MODIFY_NON_UNIQUE,DC=SAMBA,DC=ORG")
+ msg["notUnique"] = ldb.MessageElement(
+ [aa_gt_max, ab_gt_max],
+ ldb.FLAG_MOD_ADD,
+ "notUnique")
+ self.l.modify(msg)
+
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ b"0123456789abcde0" +
+ b"0123456789abcde1" + b"0123456789abcde1")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ b"0123456789abcde0")
+ self.checkGuids(
+ "@INDEX#NOTUNIQUE#ccccccccccccccccccccccccccccccccc",
+ b"0123456789abcde1")
+
+ #
+ # Test Sub tree searches when checkBaseOnSearch is enabled and the
+ # DN indexes are truncated and collide.
+ #
+ def test_check_base_on_search_truncated_dn_keys(self):
+ #
+ # Except for the base DN's
+ # all entries the DN index key gets truncated to
+ # 0 1 2 3 4 5
+ # 12345678901234567890123456789012345678901234567890
+ # @INDEX:@IDXDN:OU=??,OU=CHECK_BASE_DN_XXXX,DC=SAMBA
+ # The base DN-s truncate to
+ # @INDEX:@IDXDN:OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR
+ #
+ checkbaseonsearch = {"dn": "@OPTIONS",
+ "checkBaseOnSearch": b"TRUE"}
+ self.l.add(checkbaseonsearch)
+
+ self.l.add({"dn": "OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcdef"})
+ self.l.add({"dn": "OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcdee"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR",
+ b"0123456789abcdee" + b"0123456789abcdef")
+
+ self.l.add({"dn": "OU=01,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcdec"})
+ self.l.add({"dn": "OU=01,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcdeb"})
+ self.l.add({"dn": "OU=01,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR3",
+ "objectUUID": b"0123456789abcded"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=01,OU=CHECK_BASE_DN_XXXX,DC=SAMBA",
+ b"0123456789abcdeb" + b"0123456789abcdec" + b"0123456789abcded")
+
+ self.l.add({"dn": "OU=02,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR1",
+ "objectUUID": b"0123456789abcde0"})
+ self.l.add({"dn": "OU=02,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR2",
+ "objectUUID": b"0123456789abcde1"})
+ self.l.add({"dn": "OU=02,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR3",
+ "objectUUID": b"0123456789abcde2"})
+ self.checkGuids(
+ "@INDEX#@IDXDN#OU=02,OU=CHECK_BASE_DN_XXXX,DC=SAMBA",
+ b"0123456789abcde0" + b"0123456789abcde1" + b"0123456789abcde2")
+
+ res = self.l.search(base="OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR1",
+ scope=ldb.SCOPE_SUBTREE)
+ self.assertEqual(len(res), 3)
+ self.assertTrue(
+ contains(res, "OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR1"))
+ self.assertTrue(
+ contains(res, "OU=01,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR1"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR1"))
+
+ res = self.l.search(base="OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR2",
+ scope=ldb.SCOPE_SUBTREE)
+ self.assertEqual(len(res), 3)
+ self.assertTrue(
+ contains(res, "OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR2"))
+ self.assertTrue(
+ contains(res, "OU=01,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR2"))
+ self.assertTrue(
+ contains(res, "OU=02,OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR2"))
+
+ try:
+ res = self.l.search(base="OU=CHECK_BASE_DN_XXXX,DC=SAMBA,DC=OR3",
+ scope=ldb.SCOPE_SUBTREE)
+ self.fail("Expected exception no thrown")
+ except ldb.LdbError as e:
+ code = e.args[0]
+ self.assertEqual(ldb.ERR_NO_SUCH_OBJECT, code)
+
+
+# Run the index truncation tests against an lmdb backend
+class MaxIndexKeyLengthTestsLmdb(MaxIndexKeyLengthTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(MaxIndexKeyLengthTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(MaxIndexKeyLengthTestsLmdb, self).tearDown()
+
+
+class OrderedIntegerRangeTests(LdbBaseTest):
+
+ def tearDown(self):
+ shutil.rmtree(self.testdir)
+ super(OrderedIntegerRangeTests, self).tearDown()
+
+ # Ensure the LDB is closed now, so we close the FD
+ del(self.l)
+
+ def setUp(self):
+ super(OrderedIntegerRangeTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "ordered_integer_test.ldb")
+
+ self.l = ldb.Ldb(self.url(),
+ options=self.options())
+ self.l.add({"dn": "@ATTRIBUTES",
+ "int64attr": "ORDERED_INTEGER"})
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"int64attr"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+
+ def options(self):
+ if self.prefix == MDB_PREFIX:
+ return ['modules:rdn_name',
+ 'disable_full_db_scan_for_self_test:1']
+ else:
+ return ['modules:rdn_name']
+
+ def test_comparison_expression(self):
+ int64_max = 2**63-1
+ int64_min = -2**63
+ test_nums = list(range(-5, 5))
+ test_nums += list(range(int64_max-5, int64_max+1))
+ test_nums += list(range(int64_min, int64_min+5))
+ test_nums = sorted(test_nums)
+
+ for (i, num) in enumerate(test_nums):
+ ouuid = 0x0123456789abcdef + i
+ ouuid_s = bytes(('0' + hex(ouuid)[2:]).encode())
+ self.l.add({"dn": "OU=COMPTESTOU{},DC=SAMBA,DC=ORG".format(i),
+ "objectUUID": ouuid_s,
+ "int64attr": str(num)})
+
+ def assert_int64_expr(expr, py_expr=None):
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(int64attr%s)" % (expr))
+
+ if not py_expr:
+ py_expr = expr
+ expect = [n for n in test_nums if eval(str(n) + py_expr)]
+ vals = sorted([int(r.get("int64attr")[0]) for r in res])
+ self.assertEqual(len(res), len(expect))
+ self.assertEqual(set(vals), set(expect))
+ self.assertEqual(expect, vals)
+
+ assert_int64_expr(">=-2")
+ assert_int64_expr("<=2")
+ assert_int64_expr(">=" + str(int64_min))
+ assert_int64_expr("<=" + str(int64_min))
+ assert_int64_expr("<=" + str(int64_min+1))
+ assert_int64_expr("<=" + str(int64_max))
+ assert_int64_expr(">=" + str(int64_max))
+ assert_int64_expr(">=" + str(int64_max-1))
+ assert_int64_expr("=10", "==10")
+
+ def test_comparison_expression_duplicates(self):
+ int64_max = 2**63-1
+ int64_min = -2**63
+ test_nums = list(range(-5, 5)) * 3
+ test_nums += list(range(-20, 20, 5)) * 2
+ test_nums += list(range(-50, 50, 15))
+ test_nums = sorted(test_nums)
+
+ for (i, num) in enumerate(test_nums):
+ ouuid = 0x0123456789abcdef + i
+ ouuid_s = bytes(('0' + hex(ouuid)[2:]).encode())
+ self.l.add({"dn": "OU=COMPTESTOU{},DC=SAMBA,DC=ORG".format(i),
+ "objectUUID": ouuid_s,
+ "int64attr": str(num)})
+
+ def assert_int64_expr(expr, py_expr=None):
+ res = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(int64attr%s)" % (expr))
+
+ if not py_expr:
+ py_expr = expr
+ expect = [n for n in test_nums if eval(str(n) + py_expr)]
+ vals = sorted([int(r.get("int64attr")[0]) for r in res])
+ self.assertEqual(len(res), len(expect))
+ self.assertEqual(set(vals), set(expect))
+ self.assertEqual(expect, vals)
+
+ assert_int64_expr(">=-2")
+ assert_int64_expr("<=2")
+ assert_int64_expr(">=" + str(int64_min))
+ assert_int64_expr("<=" + str(int64_min))
+ assert_int64_expr("<=" + str(int64_min+1))
+ assert_int64_expr("<=" + str(int64_max))
+ assert_int64_expr(">=" + str(int64_max))
+ assert_int64_expr(">=" + str(int64_max-1))
+ assert_int64_expr("=-5", "==-5")
+ assert_int64_expr("=5", "==5")
+
+
+# Run the ordered integer range tests against an lmdb backend
+class OrderedIntegerRangeTestsLmdb(OrderedIntegerRangeTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(OrderedIntegerRangeTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(OrderedIntegerRangeTestsLmdb, self).tearDown()
+
+
+# Run the index truncation tests against an lmdb backend
+class RejectSubDBIndex(LdbBaseTest):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(RejectSubDBIndex, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir,
+ "reject_subidx_test.ldb")
+ self.l = ldb.Ldb(self.url(),
+ options=[
+ "modules:rdn_name"])
+
+ def tearDown(self):
+ super(RejectSubDBIndex, self).tearDown()
+
+ def test_try_subdb_index(self):
+ try:
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDX_LMDB_SUBDB": [b"1"],
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"],
+ })
+ except ldb.LdbError as e:
+ code = e.args[0]
+ string = e.args[1]
+ self.assertEqual(ldb.ERR_OPERATIONS_ERROR, code)
+ self.assertIn("sub-database index", string)
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.TestProgram()
diff --git a/lib/ldb/tests/python/repack.py b/lib/ldb/tests/python/repack.py
new file mode 100644
index 0000000..0844cd2
--- /dev/null
+++ b/lib/ldb/tests/python/repack.py
@@ -0,0 +1,204 @@
+import os
+from unittest import TestCase
+import shutil
+from subprocess import check_output
+import ldb
+
+TDB_PREFIX = "tdb://"
+MDB_PREFIX = "mdb://"
+
+def tempdir():
+ import tempfile
+ try:
+ dir_prefix = os.path.join(os.environ["SELFTEST_PREFIX"], "tmp")
+ except KeyError:
+ dir_prefix = None
+ return tempfile.mkdtemp(dir=dir_prefix)
+
+
+# Check enabling and disabling GUID indexing works and that the database is
+# repacked at version 2 if GUID indexing is enabled, or version 1 if disabled.
+class GUIDIndexAndPackFormatTests(TestCase):
+ prefix = TDB_PREFIX
+
+ def setup_newdb(self):
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir,
+ "guidpackformattest.ldb")
+ url = self.prefix + self.filename
+ self.l = ldb.Ldb(url, options=["modules:"])
+
+ self.num_recs_added = 0
+
+ #guidindexpackv1.ldb is a pre-made database packed with version 1 format
+ #but with GUID indexing enabled, which is not allowed, so Samba should
+ #repack the database on the first transaction.
+ def setup_premade_v1_db(self):
+ db_name = "guidindexpackv1.ldb"
+ this_file_dir = os.path.dirname(os.path.abspath(__file__))
+ db_path = os.path.join(this_file_dir, "../", db_name)
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, db_name)
+
+ shutil.copy(db_path, self.filename)
+
+ url = self.prefix + self.filename
+ self.l = ldb.Ldb(url, options=["modules:"])
+ self.num_recs_added = 10
+
+ def tearDown(self):
+ if hasattr(self, 'testdir'):
+ shutil.rmtree(self.testdir)
+
+ def add_one_rec(self):
+ ouuid = 0x0123456789abcdef + self.num_recs_added
+ ouuid_s = '0' + hex(ouuid)[2:]
+ dn = "OU=GUIDPFTEST{},DC=SAMBA,DC=ORG".format(self.num_recs_added)
+ rec = {"dn": dn, "objectUUID": ouuid_s, "distinguishedName": dn}
+ self.l.add(rec)
+ self.num_recs_added += 1
+
+ # Turn GUID back into a str for easier comparisons
+ return rec
+
+ def set_guid_indexing(self, enable=True):
+ modmsg = ldb.Message()
+ modmsg.dn = ldb.Dn(self.l, '@INDEXLIST')
+
+ attrs = {"@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]}
+ for attr, val in attrs.items():
+ replace = ldb.FLAG_MOD_REPLACE
+ el = val if enable else []
+ el = ldb.MessageElement(elements=el, flags=replace, name=attr)
+ modmsg.add(el)
+
+ self.l.modify(modmsg)
+
+ # Parse out the comments above each record that ldbdump produces
+ # containing pack format version and KV level key for each record.
+ # Return all GUID index keys and the set of all unique pack formats.
+ def ldbdump_guid_keys_pack_formats(self):
+ dump = check_output(["bin/ldbdump", "-i", self.filename])
+ dump = dump.decode("utf-8")
+ dump = dump.split("\n")
+
+ comments = [s for s in dump if s.startswith("#")]
+
+ guid_key_tag = "# key: GUID="
+ guid_keys = {c[len(guid_key_tag):] for c in comments
+ if c.startswith(guid_key_tag)}
+
+ pack_format_tag = "# pack format: "
+ pack_formats = {c[len(pack_format_tag):] for c in comments
+ if c.startswith(pack_format_tag)}
+ pack_formats = [int(s, 16) for s in pack_formats]
+
+ return guid_keys, pack_formats
+
+ # Put the whole database in a dict so we can easily check the database
+ # hasn't changed
+ def get_database(self):
+ recs = self.l.search(base="", scope=ldb.SCOPE_SUBTREE, expression="")
+ db = dict()
+ for r in recs:
+ dn = str(r.dn)
+ self.assertNotIn(dn, db)
+ db[dn] = dict()
+ for k in r.keys():
+ k = str(k)
+ db[dn][k] = str(r.get(k))
+ return db
+
+ # Toggle GUID indexing on and off a few times, and check that when GUID
+ # indexing is enabled, the database is repacked to pack format V2, and
+ # when GUID indexing is disabled again, the database is repacked with
+ # pack format V1.
+ def toggle_guidindex_check_pack(self):
+ expect_db = self.get_database()
+
+ for enable in [False, False, True, False, True, True, False]:
+ pf = ldb.PACKING_FORMAT_V2 if enable else ldb.PACKING_FORMAT
+
+ self.set_guid_indexing(enable=enable)
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ num_guid_keys = self.num_recs_added if enable else 0
+ self.assertEqual(len(guid_keys), num_guid_keys)
+ self.assertEqual(pack_formats, [pf])
+ self.assertEqual(self.get_database(), expect_db)
+
+ rec = self.add_one_rec()
+ expect_db[rec['dn']] = rec
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ num_guid_keys = self.num_recs_added if enable else 0
+ self.assertEqual(len(guid_keys), num_guid_keys)
+ self.assertEqual(pack_formats, [pf])
+ self.assertEqual(self.get_database(), expect_db)
+
+ # Check a newly created database is initially packed at V1, then is
+ # repacked at V2 when GUID indexing is enabled.
+ def test_repack(self):
+ self.setup_newdb()
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ self.assertEqual(len(guid_keys), 0)
+ self.assertEqual(pack_formats, [ldb.PACKING_FORMAT])
+ self.assertEqual(self.get_database(), {})
+
+ self.l.add({"dn": "@ATTRIBUTES"})
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ self.assertEqual(len(guid_keys), 0)
+ self.assertEqual(pack_formats, [ldb.PACKING_FORMAT])
+ self.assertEqual(self.get_database(), {})
+
+ self.l.add({"dn": "@INDEXLIST",
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ self.assertEqual(len(guid_keys), 0)
+ self.assertEqual(pack_formats, [ldb.PACKING_FORMAT_V2])
+ self.assertEqual(self.get_database(), {})
+
+ rec = self.add_one_rec()
+ expect_db = {rec["dn"]: rec}
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ self.assertEqual(len(guid_keys), 1)
+ self.assertEqual(pack_formats, [ldb.PACKING_FORMAT_V2])
+ self.assertEqual(self.get_database(), expect_db)
+
+ self.toggle_guidindex_check_pack()
+
+ # Check a database with V1 format with GUID indexing enabled is repacked
+ # with version 2 format.
+ def test_guid_indexed_v1_db(self):
+ self.setup_premade_v1_db()
+
+ expect_db = self.get_database()
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ self.assertEqual(len(guid_keys), self.num_recs_added)
+ self.assertEqual(pack_formats, [ldb.PACKING_FORMAT])
+ self.assertEqual(self.get_database(), expect_db)
+
+ rec = self.add_one_rec()
+ expect_db[rec['dn']] = rec
+
+ guid_keys, pack_formats = self.ldbdump_guid_keys_pack_formats()
+ self.assertEqual(len(guid_keys), self.num_recs_added)
+ self.assertEqual(pack_formats, [ldb.PACKING_FORMAT_V2])
+ self.assertEqual(self.get_database(), expect_db)
+
+ self.toggle_guidindex_check_pack()
+
+
+if __name__ == '__main__':
+ import unittest
+
+
+ unittest.TestProgram()
diff --git a/lib/ldb/tests/samba4.png b/lib/ldb/tests/samba4.png
new file mode 100644
index 0000000..c809688
--- /dev/null
+++ b/lib/ldb/tests/samba4.png
Binary files differ
diff --git a/lib/ldb/tests/sample_module.c b/lib/ldb/tests/sample_module.c
new file mode 100644
index 0000000..6ba9ed2
--- /dev/null
+++ b/lib/ldb/tests/sample_module.c
@@ -0,0 +1,122 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "ldb_module.h"
+
+static int sample_add_callback(struct ldb_request *down_req,
+ struct ldb_reply *ares)
+{
+ struct ldb_request *req =
+ talloc_get_type_abort(down_req->context,
+ struct ldb_request);
+
+ if (ares == NULL) {
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ return ldb_module_send_referral(req, ares->referral);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ return ldb_module_done(req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(req, ares->controls,
+ ares->response, LDB_SUCCESS);
+}
+
+static int sample_add(struct ldb_module *mod, struct ldb_request *req)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(mod);
+ struct ldb_control *control = NULL;
+ struct ldb_message *msg = NULL;
+ struct ldb_request *down_req = NULL;
+ int ret;
+
+ /* check if there's a relax control */
+ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
+ if (control != NULL) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ msg = ldb_msg_copy_shallow(req, req->op.add.message);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_msg_add_fmt(msg, "touchedBy", "sample");
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_add_req(&down_req, ldb, req,
+ msg,
+ req->controls,
+ req, sample_add_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ talloc_steal(down_req, msg);
+
+ /* go on with the call chain */
+ return ldb_next_request(mod, down_req);
+}
+
+static int sample_modify(struct ldb_module *mod, struct ldb_request *req)
+{
+ struct ldb_control *control;
+
+ /* check if there's a relax control */
+ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
+ if (control != NULL) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ /* not found go on */
+ return ldb_next_request(mod, req);
+}
+
+
+static struct ldb_module_ops ldb_sample_module_ops = {
+ .name = "sample",
+ .add = sample_add,
+ .del = sample_modify,
+ .modify = sample_modify,
+};
+
+int ldb_sample_init(const char *version)
+{
+ LDB_MODULE_CHECK_VERSION(version);
+ return ldb_register_module(&ldb_sample_module_ops);
+}
diff --git a/lib/ldb/tests/schema-tests/schema-add-test.ldif b/lib/ldb/tests/schema-tests/schema-add-test.ldif
new file mode 100644
index 0000000..472ab48
--- /dev/null
+++ b/lib/ldb/tests/schema-tests/schema-add-test.ldif
@@ -0,0 +1,66 @@
+dn: CN=Users,DC=schema,DC=test
+objectClass: top
+objectClass: container
+cn: Users
+description: Default container for upgraded user accounts
+instanceType: 4
+whenCreated: 20050116175504.0Z
+whenChanged: 20050116175504.0Z
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: FALSE
+name: Users
+objectGUID: b847056a-9934-d87b-8a1a-99fabe0863c8
+systemFlags: 0x8c000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,DC=schema,DC=test
+isCriticalSystemObject: TRUE
+nTSecurityDescriptor: foo
+
+dn: CN=Administrator,CN=Users,DC=schema,DC=test
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+cn: Administrator
+description: Built-in account for administering the computer/domain
+instanceType: 4
+whenCreated: 20050116175504.0Z
+whenChanged: 20050116175504.0Z
+uSNCreated: 1
+memberOf: CN=Group Policy Creator Owners,CN=Users,DC=schema,DC=test
+memberOf: CN=Domain Admins,CN=Users,DC=schema,DC=test
+memberOf: CN=Enterprise Admins,CN=Users,DC=schema,DC=test
+memberOf: CN=Schema Admins,CN=Users,DC=schema,DC=test
+memberOf: CN=Administrators,CN=Builtin,DC=schema,DC=test
+uSNChanged: 1
+name: Administrator
+objectGUID: 6c02f98c-46c6-aa38-5f13-a510cac04e6c
+userAccountControl: 0x10200
+badPwdCount: 0
+codePage: 0
+countryCode: 0
+badPasswordTime: 0
+lastLogoff: 0
+lastLogon: 0
+pwdLastSet: 0
+primaryGroupID: 513
+objectSid: S-1-5-21-43662522-77495566-38969261-500
+adminCount: 1
+accountExpires: 9223372036854775807
+logonCount: 0
+sAMAccountName: Administrator
+sAMAccountType: 0x30000000
+objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=schema,DC=test
+isCriticalSystemObject: TRUE
+unicodePwd: samba
+nTSecurityDescriptor: foo
+
+dn: CN=Test,CN=Users,DC=schema,DC=test
+objectClass: top
+objectClass: test
+cn: Test
+description: This is a test
+objectCategory: CN=Test,CN=Schema,CN=Configuration,DC=schema,DC=test
+nTSecurityDescriptor: foo
+instanceType: 4
+
diff --git a/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif b/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif
new file mode 100644
index 0000000..b976724
--- /dev/null
+++ b/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+replace: description
+description: this test must not fail
+
diff --git a/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif b/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif
new file mode 100644
index 0000000..fa193af
--- /dev/null
+++ b/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+delete: description
+# this test must not fail
+
diff --git a/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif b/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif
new file mode 100644
index 0000000..8ab7798
--- /dev/null
+++ b/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+add: description
+description: this test must not fail
+
diff --git a/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif b/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif
new file mode 100644
index 0000000..cbf0e60
--- /dev/null
+++ b/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+add: foo
+foo: this test must fail
+
diff --git a/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif b/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif
new file mode 100644
index 0000000..bc64e9e
--- /dev/null
+++ b/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif
@@ -0,0 +1,5 @@
+dn: CN=Test,CN=Users,DC=schema,DC=test
+changetype: modify
+delete: nTSecurityDescriptor
+# this test must fail
+
diff --git a/lib/ldb/tests/schema-tests/schema.ldif b/lib/ldb/tests/schema-tests/schema.ldif
new file mode 100644
index 0000000..4ab1932
--- /dev/null
+++ b/lib/ldb/tests/schema-tests/schema.ldif
@@ -0,0 +1,100 @@
+dn: @INDEXLIST
+@IDXATTR: name
+@IDXATTR: sAMAccountName
+@IDXATTR: objectSid
+@IDXATTR: objectClass
+@IDXATTR: member
+@IDXATTR: uidNumber
+@IDXATTR: gidNumber
+@IDXATTR: unixName
+@IDXATTR: privilege
+@IDXATTR: lDAPDisplayName
+
+dn: @ATTRIBUTES
+realm: CASE_INSENSITIVE
+userPrincipalName: CASE_INSENSITIVE
+servicePrincipalName: CASE_INSENSITIVE
+name: CASE_INSENSITIVE
+dn: CASE_INSENSITIVE
+sAMAccountName: CASE_INSENSITIVE
+objectClass: CASE_INSENSITIVE
+unicodePwd: HIDDEN
+ntPwdHash: HIDDEN
+ntPwdHistory: HIDDEN
+lmPwdHash: HIDDEN
+lmPwdHistory: HIDDEN
+createTimestamp: HIDDEN
+modifyTimestamp: HIDDEN
+
+dn: @MODULES
+@LIST: timestamps,schema
+
+dn: CN=Top,CN=Schema,CN=Configuration,DC=schema,DC=test
+objectClass: top
+objectClass: classSchema
+lDAPDisplayName: top
+cn: Top
+uSNCreated: 1
+uSNChanged: 1
+subClassOf: top
+systemMustContain: objectClass
+systemMayContain: structuralObjectClass
+systemMayContain: createTimeStamp
+systemMayContain: modifyTimeStamp
+systemMayContain: creatorsName
+systemMayContain: modifiersName
+systemMayContain: hasSubordinates
+systemMayContain: subschemaSubentry
+systemMayContain: collectiveSubentry
+systemMayContain: entryUUID
+systemMayContain: entryCSN
+systemMayContain: namingCSN
+systemMayContain: superiorUUID
+systemMayContain: contextCSN
+systemMayContain: whenCreated
+systemMayContain: whenChanged
+systemMayContain: uSNCreated
+systemMayContain: uSNChanged
+systemMayContain: distinguishedName
+systemMayContain: name
+systemMayContain: cn
+systemMayContain: userPassword
+systemMayContain: labeledURI
+
+dn: CN=Class-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test
+objectClass: top
+objectClass: classSchema
+lDAPDisplayName: classSchema
+cn: Class-Schema
+uSNCreated: 2
+uSNChanged: 2
+lDAPDisplayName: classSchema
+subClassOf: top
+systemMustContain: cn
+systemMustContain: subClassOf
+systemMayContain: systemPossSuperiors
+systemMayContain: systemOnly
+systemMayContain: systemMustContain
+systemMayContain: systemMayContain
+systemMayContain: systemAuxiliaryClass
+systemMayContain: possSuperiors
+systemMayContain: mustContain
+systemMayContain: mayContain
+systemMayContain: lDAPDisplayName
+systemMayContain: auxiliaryClass
+
+dn: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test
+objectClass: top
+objectClass: classSchema
+cn: Attribute-Schema
+uSNCreated: 3
+uSNChanged: 3
+lDAPDisplayName: attributeSchema
+subClassOf: top
+systemMustContain: oMSyntax
+systemMustContain: lDAPDisplayName
+systemMustContain: isSingleValued
+systemMustContain: cn
+systemMustContain: attributeSyntax
+systemMustContain: attributeID
+
diff --git a/lib/ldb/tests/slapd.conf b/lib/ldb/tests/slapd.conf
new file mode 100644
index 0000000..fa2789d
--- /dev/null
+++ b/lib/ldb/tests/slapd.conf
@@ -0,0 +1,26 @@
+loglevel 0
+
+include tests/schema/core.schema
+include tests/schema/cosine.schema
+include tests/schema/inetorgperson.schema
+include tests/schema/openldap.schema
+include tests/schema/nis.schema
+
+
+pidfile tests/tmp/slapd.pid
+argsfile tests/tmp/slapd.args
+
+access to * by * write
+
+allow update_anon bind_anon_dn
+
+include tests/tmp/modules.conf
+
+defaultsearchbase "o=University of Michigan,c=TEST"
+
+backend bdb
+database bdb
+suffix "o=University of Michigan,c=TEST"
+directory tests/tmp/db
+index objectClass eq
+index uid eq
diff --git a/lib/ldb/tests/start_slapd.sh b/lib/ldb/tests/start_slapd.sh
new file mode 100755
index 0000000..4a4a35e
--- /dev/null
+++ b/lib/ldb/tests/start_slapd.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=$(dirname $0)/..
+ export LDBDIR
+fi
+
+mkdir -p $LDBDIR/tests/tmp/db
+
+# running slapd in the background (with &) means it stays in the same process group, so it can be
+# killed by timelimit
+slapd -d0 -f $LDBDIR/tests/slapd.conf -h "$($LDBDIR/tests/ldapi_url.sh)" $* &
+
+sleep 2
diff --git a/lib/ldb/tests/test-attribs.ldif b/lib/ldb/tests/test-attribs.ldif
new file mode 100644
index 0000000..79508c4
--- /dev/null
+++ b/lib/ldb/tests/test-attribs.ldif
@@ -0,0 +1,6 @@
+dn: @ATTRIBUTES
+uid: CASE_INSENSITIVE
+cn: CASE_INSENSITIVE
+ou: CASE_INSENSITIVE
+dn: CASE_INSENSITIVE
+
diff --git a/lib/ldb/tests/test-config.ldif b/lib/ldb/tests/test-config.ldif
new file mode 100644
index 0000000..7926a9e
--- /dev/null
+++ b/lib/ldb/tests/test-config.ldif
@@ -0,0 +1,67 @@
+##############################
+# global configuration options
+dn: cn=Global,cn=Config,cn=Samba
+objectclass: globalconfig
+LocalConfigCn: cn=%U,cn=Config,cn=Samba
+LocalConfigCn;1: cn=%U,cn=Config,cn=Samba
+LocalConfigCn;2: cn=%I,cn=Config,cn=Samba
+LocalConfigCn;3: cn=%M,cn=Config,cn=Samba
+
+#############
+dn: cn=Protocol,cn=Global,cn=Config,cn=Samba
+maxXmit: 7000
+
+################################
+dn: cn=Volker,cn=Config,cn=Samba
+Workgroup: VNET3
+UnixCharset: UTF8
+Security: user
+Interfaces: vmnet* eth*
+NetbiosName: blu
+GuestAccount: tridge
+
+#################################
+dn: cn=Volker,cn=Config,cn=Samba
+Workgroup: VNET3
+UnixCharset: UTF8
+Security: user
+Interfaces: vmnet* eth*
+NetbiosName: blu
+GuestAccount: tridge
+Include: cn=%U,cn=MyConfig,cn=Config,cn=Samba
+
+#### ((objectClass=fileshare)(cn=test))
+##############################
+# [test] share
+dn: cn=test,cn=Shares,cn=Config,cn=Samba
+objectclass: fileshare
+cn: test
+Comment: a test share
+Path: /home/tridge/samba4/prefix/test
+ReadOnly: no
+
+#####################################
+# [msdn] a remote proxy share, stored
+# on \\msdn\test
+dn: cn=msdn,cn=Shares,cn=Config,cn=Samba
+objectclass: fileshare
+cn: msdn
+NtvfsHandler: cifs
+ReadOnly: no
+_CifsServer: msdn
+_CifsUser: administrator
+_CifsPassword: penguin
+_CifsDomain: winxp
+_CifsShare: test
+
+
+##############################
+# [VisualC] share
+dn: cn=visualc,cn=Shares,cn=Config,cn=Samba
+objectclass: fileshare
+cn: VisualC
+Comment: VisualC development
+Path: /home/tridge/VisualC
+ReadOnly: no
+NtvfsHandler: simple
+
diff --git a/lib/ldb/tests/test-controls.sh b/lib/ldb/tests/test-controls.sh
new file mode 100755
index 0000000..328ed29
--- /dev/null
+++ b/lib/ldb/tests/test-controls.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+if [ -n "$TEST_DATA_PREFIX" ]; then
+ LDB_URL="$TEST_DATA_PREFIX/tdbtest.ldb"
+else
+ LDB_URL="tdbtest.ldb"
+fi
+export LDB_URL
+
+PATH=bin:$PATH
+export PATH
+
+rm -f $LDB_URL*
+
+echo "LDB_URL: $LDB_URL"
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @MODULES
+@LIST: sample
+EOF
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: dc=bar
+dc: bar
+someThing: someThingElse
+EOF
+
+$VALGRIND ldbsearch "(touchedBy=sample)" | grep "touchedBy: sample" || exit 1
+# This action are expected to fails because the sample module return an error when presented the relax control
+
+cat <<EOF | $VALGRIND ldbadd --controls "relax:0" >/dev/null 2>&1 && exit 1
+dn: dc=foobar
+dc: foobar
+someThing: someThingElse
+EOF
+
+cat <<EOF | $VALGRIND ldbmodify --controls "relax:0" >/dev/null 2>&1 && exit 1
+dn: dc=bar
+changetype: modify
+replace someThing
+someThing: someThingElseBetter
+EOF
+
+$VALGRIND ldbsearch --controls "bypassoperational:0" >/dev/null 2>&1 || exit 1
diff --git a/lib/ldb/tests/test-default-config.ldif b/lib/ldb/tests/test-default-config.ldif
new file mode 100644
index 0000000..87b7bcd
--- /dev/null
+++ b/lib/ldb/tests/test-default-config.ldif
@@ -0,0 +1,17 @@
+##############################
+# global configuration options
+dn: cn=Global,cn=DefaultConfig,cn=Samba
+objectclass: globalconfig
+Workgroup: WORKGROUP
+UnixCharset: UTF8
+Security: user
+NetbiosName: blu
+GuestAccount: nobody
+
+##############################
+# [_default_] share
+dn: cn=_default_,cn=Shares,cn=DefaultConfig,cn=Samba
+objectclass: fileshare
+cn: _default_
+Path: /tmp
+ReadOnly: yes
diff --git a/lib/ldb/tests/test-dup-2.ldif b/lib/ldb/tests/test-dup-2.ldif
new file mode 100644
index 0000000..a426101
--- /dev/null
+++ b/lib/ldb/tests/test-dup-2.ldif
@@ -0,0 +1,6 @@
+dn: cn=Sentinel,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Sentinel
+sn: USER
+uid: USER, Sentinel
+
diff --git a/lib/ldb/tests/test-dup.ldif b/lib/ldb/tests/test-dup.ldif
new file mode 100644
index 0000000..b35420b
--- /dev/null
+++ b/lib/ldb/tests/test-dup.ldif
@@ -0,0 +1,13 @@
+dn: cn=Fred Bassett,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Fred Bassett
+sn: Bassett
+uid: Bassett, Fred
+
+dn: cn=Sentinel,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Sentinel
+sn: USER
+uid: USER, Sentinel
+
+
diff --git a/lib/ldb/tests/test-extended.sh b/lib/ldb/tests/test-extended.sh
new file mode 100755
index 0000000..f4dabd6
--- /dev/null
+++ b/lib/ldb/tests/test-extended.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+echo "Running extended search tests"
+
+mv $LDB_URL $LDB_URL.1
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: cn=testrec1,cn=TEST
+i1: 1
+i2: 0
+i3: 1234
+i4: 0x7003004
+
+dn: cn=testrec2,cn=TEST
+i1: 0x800000
+
+dn: cn=testrec3,cn=TEST
+i1: 0x101010101
+i1: 7
+
+dn: cn=auser1,cn=TEST
+groupType: 2147483648
+samAccountType: 805306368
+
+dn: cn=auser2,cn=TEST
+groupType: 2147483648
+samAccountType: 805306369
+
+dn: cn=auser3,cn=TEST
+groupType: 2147483649
+samAccountType: 805306370
+
+dn: cn=auser4,cn=TEST
+groupType: 2147483649
+samAccountType: 805306369
+EOF
+
+checkcount()
+{
+ count=$1
+ expression="$2"
+ n=$($VALGRIND ldbsearch "$expression" | grep '^dn' | wc -l)
+ if [ $n != $count ]; then
+ echo "Got $n but expected $count for $expression"
+ $VALGRIND ldbsearch "$expression"
+ exit 1
+ fi
+ echo "OK: $count $expression"
+}
+
+checkcount 1 '(i3=1234)'
+checkcount 0 '(i3=12345)'
+
+checkcount 2 '(i1:1.2.840.113556.1.4.803:=1)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=3)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=7)'
+checkcount 0 '(i1:1.2.840.113556.1.4.803:=15)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=0x800000)'
+checkcount 1 '(i1:1.2.840.113556.1.4.803:=8388608)'
+
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=1)'
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=3)'
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=7)'
+checkcount 2 '(i1:1.2.840.113556.1.4.804:=15)'
+checkcount 1 '(i1:1.2.840.113556.1.4.804:=0x800000)'
+checkcount 1 '(i1:1.2.840.113556.1.4.804:=8388608)'
+
+# this is one that w2k gives
+checkcount 3 '(|(|(&(!(groupType:1.2.840.113556.1.4.803:=1))(groupType:1.2.840.113556.1.4.803:=2147483648)(groupType:1.2.840.113556.1.4.804:=10))(samAccountType=805306368))(samAccountType=805306369))'
diff --git a/lib/ldb/tests/test-generic.sh b/lib/ldb/tests/test-generic.sh
new file mode 100755
index 0000000..03ac914
--- /dev/null
+++ b/lib/ldb/tests/test-generic.sh
@@ -0,0 +1,158 @@
+#!/bin/sh
+
+if [ -z "$LDB_SPECIALS" ]; then
+ LDB_SPECIALS=1
+ export LDB_SPECIALS
+fi
+
+echo "LDB_URL: $LDB_URL"
+
+echo "Adding base elements"
+$VALGRIND ldbadd $LDBDIR/tests/test.ldif || exit 1
+
+echo "Adding again - should fail"
+$VALGRIND ldbadd $LDBDIR/tests/test.ldif 2>/dev/null && {
+ echo "Should have failed to add again - gave $?"
+ exit 1
+}
+
+echo "Adding LDIF with one already-existing user again - should fail"
+$VALGRIND ldbadd $LDBDIR/tests/test-dup.ldif 2>/dev/null && {
+ echo "Should have failed to add again - gave $?"
+ exit 1
+}
+
+echo "Adding again - should succeed (as previous failed)"
+$VALGRIND ldbadd $LDBDIR/tests/test-dup-2.ldif || exit 1
+
+echo "Modifying elements"
+$VALGRIND ldbmodify $LDBDIR/tests/test-modify.ldif || exit 1
+
+echo "Modify LDIF with one un-met constraint - should fail"
+$VALGRIND ldbadd $LDBDIR/tests/test-modify-unmet.ldif 2>/dev/null && {
+ echo "Should have failed to modify - gave $?"
+ exit 1
+}
+
+echo "Modify LDIF with after failure of un-met constraint - should also fail"
+$VALGRIND ldbadd $LDBDIR/tests/test-modify-unmet-2.ldif 2>/dev/null && {
+ echo "Should have failed to modify - gave $?"
+ exit 1
+}
+
+echo "Showing modified record"
+$VALGRIND ldbsearch '(uid=uham)' || exit 1
+
+echo "Rename entry with ldbmodify - modrdn"
+$VALGRIND ldbmodify $LDBDIR/tests/test-modify-modrdn.ldif || exit 1
+
+echo "Rename entry with ldbrename"
+OLDDN="cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST"
+NEWDN="cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST"
+$VALGRIND ldbrename "$OLDDN" "$NEWDN" || exit 1
+
+echo "Showing renamed record"
+$VALGRIND ldbsearch '(uid=uham)' || exit 1
+
+echo "Starting ldbtest"
+$VALGRIND ldbtest --num-records 100 --num-searches 10 || exit 1
+
+if [ $LDB_SPECIALS = 1 ]; then
+ echo "Adding index"
+ $VALGRIND ldbadd $LDBDIR/tests/test-index.ldif || exit 1
+fi
+
+echo "Adding bad attributes - should fail"
+$VALGRIND ldbadd $LDBDIR/tests/test-wrong_attributes.ldif && {
+ echo "Should fhave failed - gave $?"
+ exit 1
+}
+
+echo "Testing indexed search"
+$VALGRIND ldbsearch '(uid=uham)' || exit 1
+$VALGRIND ldbsearch '(&(objectclass=person)(objectclass=person)(objectclass=top))' || exit 1
+$VALGRIND ldbsearch '(&(uid=uham)(uid=uham))' || exit 1
+$VALGRIND ldbsearch '(|(uid=uham)(uid=uham))' || exit 1
+$VALGRIND ldbsearch '(|(uid=uham)(uid=uham)(objectclass=OpenLDAPperson))' || exit 1
+$VALGRIND ldbsearch '(&(uid=uham)(uid=uham)(!(objectclass=xxx)))' || exit 1
+$VALGRIND ldbsearch '(&(objectclass=person)(uid=uham)(!(uid=uhamxx)))' uid \* \+ dn || exit 1
+$VALGRIND ldbsearch '(&(uid=uham)(uid=uha*)(title=*))' uid || exit 1
+
+echo "Testing invalid search expression"
+$VALGRIND ldbsearch '(&(uid=uham)(title=foo\blah))' uid && exit 1
+
+# note that the "((" is treated as an attribute not an expression
+# this matches the openldap ldapsearch behaviour of looking for a '='
+# to see if the first argument is an expression or not
+$VALGRIND ldbsearch '((' uid || exit 1
+$VALGRIND ldbsearch '(objectclass=)' uid || exit 1
+$VALGRIND ldbsearch -b 'cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' --scope=base "" sn || exit 1
+
+echo "Test wildcard match"
+$VALGRIND ldbadd $LDBDIR/tests/test-wildcard.ldif || exit 1
+$VALGRIND ldbsearch '(cn=test*multi)' || exit 1
+$VALGRIND ldbsearch '(cn=*test*multi*)' || exit 1
+$VALGRIND ldbsearch '(cn=*test_multi)' || exit 1
+$VALGRIND ldbsearch '(cn=test_multi*)' || exit 1
+$VALGRIND ldbsearch '(cn=test*multi*test*multi)' || exit 1
+$VALGRIND ldbsearch '(cn=test*multi*test*multi*multi_*)' || exit 1
+
+echo "Starting ldbtest indexed"
+$VALGRIND ldbtest --num-records 100 --num-searches 500 || exit 1
+
+echo "Testing one level search"
+count=$($VALGRIND ldbsearch -b 'ou=Groups,o=University of Michigan,c=TEST' --scope=one 'objectclass=*' none | grep '^dn' | wc -l)
+if [ $count != 3 ]; then
+ echo returned $count records - expected 3
+ exit 1
+fi
+
+echo "Testing binary file attribute value"
+$VALGRIND ldbmodify $LDBDIR/tests/photo.ldif || exit 1
+count=$($VALGRIND ldbsearch '(cn=Hampster Ursula)' jpegPhoto | grep '^dn' | wc -l)
+if [ $count != 1 ]; then
+ echo returned $count records - expected 1
+ exit 1
+fi
+
+echo "*TODO* Testing UTF8 upper lower case searches !!"
+
+echo "Testing compare"
+count=$($VALGRIND ldbsearch '(cn>=t)' cn | grep '^dn' | wc -l)
+if [ $count != 1 ]; then
+ # only "cn: test_multi_test_multi_test_multi" (comes after "t")
+ # upper-cased words come before "t" - hence excluded
+ echo returned $count records - expected 1
+ exit 1
+fi
+$VALGRIND ldbsearch '(cn>t)' cn && exit 1 # strictly greater should not work
+
+count=$($VALGRIND ldbsearch '(cn<=t)' cn | grep '^dn' | wc -l)
+if [ $count != 18 ]; then
+ # everything except "cn: test_multi_test_multi_test_multi" (comes after "t")
+ # upper-cased letters come before "t" - hence included
+ echo returned $count records - expected 18
+ exit 1
+fi
+$VALGRIND ldbsearch '(cn<t)' cn && exit 1 # strictly less should not work
+
+checkcount()
+{
+ count=$1
+ scope=$2
+ basedn=$3
+ expression="$4"
+ n=$($VALGRIND ldbsearch --scope="$scope" -b "$basedn" "$expression" | grep '^dn' | wc -l)
+ if [ $n != $count ]; then
+ echo "Got $n but expected $count for $expression"
+ exit 1
+ fi
+ echo "OK: $count $expression"
+}
+
+checkcount 0 'base' '' '(uid=uham)'
+checkcount 0 'one' '' '(uid=uham)'
+
+checkcount 1 'base' 'cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' '(uid=uham)'
+checkcount 1 'one' 'ou=Alumni Association,ou=People,o=University of Michigan,c=TEST' '(uid=uham)'
+checkcount 1 'one' 'ou=People,o=University of Michigan,c=TEST' '(ou=ldb test)'
diff --git a/lib/ldb/tests/test-index.ldif b/lib/ldb/tests/test-index.ldif
new file mode 100644
index 0000000..2681736
--- /dev/null
+++ b/lib/ldb/tests/test-index.ldif
@@ -0,0 +1,7 @@
+dn: @INDEXLIST
+@IDXATTR: uid
+@IDXATTR: objectclass
+
+dn: @ATTRIBUTES
+uid: CASE_INSENSITIVE
+
diff --git a/lib/ldb/tests/test-ldap.sh b/lib/ldb/tests/test-ldap.sh
new file mode 100755
index 0000000..6e0e4a4
--- /dev/null
+++ b/lib/ldb/tests/test-ldap.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH
+export PATH
+SCHEMA_NEEDED="core nis cosine inetorgperson openldap"
+
+# setup needed schema files
+for f in $SCHEMA_NEEDED; do
+ if [ ! -r tests/schema/$f.schema ]; then
+ mkdir -p tests/schema
+ if [ -r /etc/ldap/schema/$f.schema ]; then
+ ln -s /etc/ldap/schema/$f.schema tests/schema/$f.schema
+ continue
+ fi
+ if [ -r /etc/openldap/schema/$f.schema ]; then
+ ln -s /etc/openldap/schema/$f.schema tests/schema/$f.schema
+ continue
+ fi
+
+ echo "SKIPPING TESTS: you need the following OpenLDAP schema files"
+ for f in $SCHEMA_NEEDED; do
+ echo " $f.schema"
+ done
+ exit 0
+ fi
+done
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=$(dirname $0)/..
+ export LDBDIR
+fi
+
+LDB_URL=$($LDBDIR/tests/ldapi_url.sh)
+export LDB_URL
+
+PATH=bin:$PATH
+export PATH
+
+LDB_SPECIALS=0
+export LDB_SPECIALS
+
+if $LDBDIR/tests/init_slapd.sh &&
+ $LDBDIR/tests/start_slapd.sh &&
+ $LDBDIR/tests/test-generic.sh; then
+ echo "ldap tests passed"
+ ret=0
+else
+ echo "ldap tests failed"
+ ret=$?
+fi
+
+#$LDBDIR/tests/kill_slapd.sh
+
+exit $ret
diff --git a/lib/ldb/tests/test-modify-modrdn.ldif b/lib/ldb/tests/test-modify-modrdn.ldif
new file mode 100644
index 0000000..efa3149
--- /dev/null
+++ b/lib/ldb/tests/test-modify-modrdn.ldif
@@ -0,0 +1,12 @@
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+changetype: moddn
+newrdn: cn=Hampster Ursula
+deleteoldrdn: 1
+newsuperior: ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+
+dn: cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+changetype: modrdn
+newrdn: cn=Ursula Hampster
+deleteoldrdn: 1
diff --git a/lib/ldb/tests/test-modify-unmet-2.ldif b/lib/ldb/tests/test-modify-unmet-2.ldif
new file mode 100644
index 0000000..8760938
--- /dev/null
+++ b/lib/ldb/tests/test-modify-unmet-2.ldif
@@ -0,0 +1,7 @@
+dn: cn=Sentinel,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+changetype: modify
+delete: drink
+drink: water
+
+
diff --git a/lib/ldb/tests/test-modify-unmet.ldif b/lib/ldb/tests/test-modify-unmet.ldif
new file mode 100644
index 0000000..6a46cdf
--- /dev/null
+++ b/lib/ldb/tests/test-modify-unmet.ldif
@@ -0,0 +1,15 @@
+dn: cn=Sentinel,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+changetype: modify
+add: drink
+drink: water
+
+dn: cn=Sentinel,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+changetype: modify
+add: sn
+sn: TEST
+-
+delete: sn
+sn: USER2
+
diff --git a/lib/ldb/tests/test-modify.ldif b/lib/ldb/tests/test-modify.ldif
new file mode 100644
index 0000000..e5b9ca4
--- /dev/null
+++ b/lib/ldb/tests/test-modify.ldif
@@ -0,0 +1,23 @@
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+changetype: modify
+add: drink
+drink: mango lassi
+-
+add: drink
+drink: lemonade
+-
+delete: pager
+-
+replace: telephonenumber
+telephonenumber: +61 2 6260 6012
+telephonenumber: +61 412 666 929
+-
+delete: telephonenumber
+telephonenumber: +61 2 6260 6012
+-
+delete: telephonenumber
+telephonenumber: +61 412 666 929
+-
+add: telephonenumber
+telephonenumber: +61 412 666 929
diff --git a/lib/ldb/tests/test-schema.sh b/lib/ldb/tests/test-schema.sh
new file mode 100755
index 0000000..15582a2
--- /dev/null
+++ b/lib/ldb/tests/test-schema.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+LDB_URL="tdb://schema.ldb"
+export LDB_URL
+
+rm -f schema.ldb
+
+echo "LDB_URL: $LDB_URL"
+
+echo "Adding schema"
+$VALGRIND bin/ldbadd $LDBDIR/tests/schema-tests/schema.ldif || exit 1
+
+echo "Adding few test elements (no failure expected here)"
+$VALGRIND bin/ldbadd $LDBDIR/tests/schema-tests/schema-add-test.ldif || exit 1
+
+echo "Modifying elements (2 failures expected here)"
+
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-1.ldif || exit 1
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-2.ldif || exit 1
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-3.ldif || exit 1
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-4.ldif
+if [ "$?" = "0" ]; then
+ echo "test failed!"
+ exit 1
+fi
+$VALGRIND bin/ldbmodify $LDBDIR/tests/schema-tests/schema-mod-test-5.ldif
+if [ "$?" = "0" ]; then
+ echo "test failed!"
+ exit 1
+fi
+
+echo "Showing modified record"
+$VALGRIND bin/ldbsearch '(cn=Test)' || exit 1
diff --git a/lib/ldb/tests/test-soloading.sh b/lib/ldb/tests/test-soloading.sh
new file mode 100755
index 0000000..a783305
--- /dev/null
+++ b/lib/ldb/tests/test-soloading.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+if [ -n "$TEST_DATA_PREFIX" ]; then
+ LDB_URL="$TEST_DATA_PREFIX/tdbtest.ldb"
+else
+ LDB_URL="tdbtest.ldb"
+fi
+export LDB_URL
+
+PATH=bin:$PATH
+export PATH
+
+rm -f $LDB_URL*
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=$(dirname $0)/..
+ export LDBDIR
+fi
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @MODULES
+@LIST: sample
+EOF
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: dc=bar
+dc: bar
+someThing: someThingElse
+EOF
+
+$VALGRIND ldbsearch "(touchedBy=sample)" | grep "touchedBy: sample" || exit 1
diff --git a/lib/ldb/tests/test-sqlite3.sh b/lib/ldb/tests/test-sqlite3.sh
new file mode 100755
index 0000000..389132d
--- /dev/null
+++ b/lib/ldb/tests/test-sqlite3.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+LDB_URL="sqlite3://sqltest.ldb"
+export LDB_URL
+
+rm -f sqltest.ldb
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=$(dirname $0)/..
+ export LDBDIR
+fi
+
+PATH=bin:$PATH
+export PATH
+
+LDB_SPECIALS=0
+export LDB_SPECIALS
+
+$LDBDIR/tests/test-generic.sh
+
+#. $LDBDIR/tests/test-extended.sh
+
+#. $LDBDIR/tests/test-tdb-features.sh
diff --git a/lib/ldb/tests/test-tdb-features.sh b/lib/ldb/tests/test-tdb-features.sh
new file mode 100644
index 0000000..1007fa0
--- /dev/null
+++ b/lib/ldb/tests/test-tdb-features.sh
@@ -0,0 +1,179 @@
+#!/bin/sh
+
+echo "Running tdb feature tests"
+
+mv $LDB_URL $LDB_URL.2
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @MODULES
+@LIST: rdn_name
+EOF
+
+checkcount()
+{
+ count=$1
+ expression="$2"
+ n=$($VALGRIND ldbsearch "$expression" | grep '^dn' | wc -l)
+ if [ $n != $count ]; then
+ echo "Got $n but expected $count for $expression"
+ $VALGRIND ldbsearch "$expression"
+ exit 1
+ fi
+ echo "OK: $count $expression"
+}
+
+echo "Testing case sensitive search"
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: cn=t1,cn=TEST
+objectClass: testclass
+test: foo
+EOF
+checkcount 1 '(test=foo)'
+checkcount 0 '(test=FOO)'
+checkcount 0 '(test=FO*)'
+checkcount 1 '(cn=t1)'
+
+echo "Making case insensitive"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: add
+add: test
+test: CASE_INSENSITIVE
+EOF
+
+echo $ldif | $VALGRIND ldbmodify || exit 1
+checkcount 1 '(test=foo)'
+checkcount 1 '(test=FOO)'
+checkcount 1 '(test=fo*)'
+
+echo "adding i"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: cn=t1,cn=TEST
+changetype: modify
+add: i
+i: 0x100
+EOF
+checkcount 1 '(i=0x100)'
+checkcount 0 '(i=256)'
+
+echo "marking i as INTEGER"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: modify
+add: i
+i: INTEGER
+EOF
+checkcount 1 '(i=0x100)'
+checkcount 1 '(i=256)'
+
+echo "adding j"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: cn=t1,cn=TEST
+changetype: modify
+add: j
+j: 0x100
+EOF
+checkcount 1 '(j=0x100)'
+checkcount 0 '(j=256)'
+
+echo "Adding wildcard attribute"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: modify
+add: *
+*: INTEGER
+EOF
+checkcount 1 '(j=0x100)'
+checkcount 1 '(j=256)'
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: num=1
+EOF
+
+echo "Testing search for attribute after change to use wildcard"
+checkcount 1 '(num=1)'
+
+echo "Testing class search"
+checkcount 0 '(objectClass=otherclass)'
+checkcount 1 '(objectClass=testclass)'
+
+echo "Adding index"
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @INDEXLIST
+@IDXATTR: i
+@IDXATTR: test
+EOF
+checkcount 1 '(i=0x100)'
+checkcount 1 '(i=256)'
+checkcount 0 '(i=-256)'
+checkcount 1 '(test=foo)'
+checkcount 1 '(test=FOO)'
+checkcount 1 '(test=*f*o)'
+
+echo "making test case sensitive"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: modify
+replace: test
+test: NONE
+EOF
+checkcount 1 '(test=foo)'
+checkcount 0 '(test=FOO)'
+checkcount 1 '(test=f*o*)'
+
+checkone()
+{
+ count=$1
+ base="$2"
+ expression="$3"
+ n=$($VALGRIND ldbsearch --scope=one -b "$base" "$expression" | grep '^dn' | wc -l)
+ if [ $n != $count ]; then
+ echo "Got $n but expected $count for $expression"
+ $VALGRIND ldbsearch --scope=one -b "$base" "$expression"
+ exit 1
+ fi
+ echo "OK: $count $expression"
+}
+
+echo "Removing wildcard attribute"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: @ATTRIBUTES
+changetype: modify
+delete: *
+*: INTEGER
+EOF
+
+echo "Adding one level indexes"
+cat <<EOF | $VALGRIND ldbmodify || exit 1
+dn: @INDEXLIST
+changetype: modify
+add: @IDXONE
+@IDXONE: 1
+EOF
+
+echo "Testing one level indexed search"
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: cn=one,cn=t1,cn=TEST
+objectClass: oneclass
+cn: one
+test: one
+EOF
+checkone 1 "cn=t1,cn=TEST" '(test=one)'
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: cn=two,cn=t1,cn=TEST
+objectClass: oneclass
+cn: two
+test: one
+
+dn: cn=three,cn=t1,cn=TEST
+objectClass: oneclass
+cn: three
+test: one
+
+dn: cn=four,cn=three,cn=t1,cn=TEST
+objectClass: oneclass
+cn: four
+test: one
+EOF
+checkone 3 "cn=t1,cn=TEST" '(test=one)'
+checkone 1 "cn=t1,cn=TEST" '(cn=two)'
diff --git a/lib/ldb/tests/test-tdb-subunit.sh b/lib/ldb/tests/test-tdb-subunit.sh
new file mode 100755
index 0000000..a89c01c
--- /dev/null
+++ b/lib/ldb/tests/test-tdb-subunit.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+BINDIR=$1
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+
+testit "ldb" $(dirname $0)/test-tdb.sh $BINDIR
diff --git a/lib/ldb/tests/test-tdb.sh b/lib/ldb/tests/test-tdb.sh
new file mode 100755
index 0000000..0b5414d
--- /dev/null
+++ b/lib/ldb/tests/test-tdb.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+BINDIR=$1
+
+if [ -n "$TEST_DATA_PREFIX" ]; then
+ LDB_URL="$TEST_DATA_PREFIX/tdbtest.ldb"
+ PYDESTDIR="$TEST_DATA_PREFIX"
+else
+ LDB_URL="tdbtest.ldb"
+fi
+export LDB_URL
+
+PATH=$BINDIR:$PATH
+export PATH
+
+if [ -z "$LDBDIR" ]; then
+ LDBDIR=$(dirname $0)/..
+ export LDBDIR
+fi
+
+cd $LDBDIR
+
+rm -f $LDB_URL*
+
+cat <<EOF | $VALGRIND ldbadd || exit 1
+dn: @MODULES
+@LIST: rdn_name
+EOF
+
+$VALGRIND ldbadd $LDBDIR/tests/init.ldif || exit 1
+
+. $LDBDIR/tests/test-generic.sh
+
+. $LDBDIR/tests/test-extended.sh
+
+. $LDBDIR/tests/test-tdb-features.sh
+
+. $LDBDIR/tests/test-controls.sh
diff --git a/lib/ldb/tests/test-wildcard.ldif b/lib/ldb/tests/test-wildcard.ldif
new file mode 100644
index 0000000..222512e
--- /dev/null
+++ b/lib/ldb/tests/test-wildcard.ldif
@@ -0,0 +1,5 @@
+dn: cn=test_multi_test_multi_test_multi,o=University of Michigan,c=TEST
+objectclass: person
+cn: test_multi_test_multi_test_multi
+sn: multi_test
+description: test multi wildcards matching
diff --git a/lib/ldb/tests/test-wrong_attributes.ldif b/lib/ldb/tests/test-wrong_attributes.ldif
new file mode 100644
index 0000000..27f45f0
--- /dev/null
+++ b/lib/ldb/tests/test-wrong_attributes.ldif
@@ -0,0 +1,3 @@
+dn: @ATTRIBUTES
+uid: CASE_INTENSIVE
+
diff --git a/lib/ldb/tests/test.ldif b/lib/ldb/tests/test.ldif
new file mode 100644
index 0000000..b3f0eed
--- /dev/null
+++ b/lib/ldb/tests/test.ldif
@@ -0,0 +1,440 @@
+dn: ou=Groups,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+ou: Groups
+
+dn: ou=Information Technology Division,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+ou: Information Technology Division
+description:: aMODwoPDgsKCw4PCgsOCwotFVlZQw4PCg8OCwoPDg8KCw4LCv0zDg8KDw4LCgsOD
+ woLDgsKKT8ODwoPDgsKDw4PCgsOCwqs6w4PCg8OCwoLDg8KCw4LCjUQkw4PCg8OCwoLDg8KCw4LCi
+ 01QUcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4
+ LCgsODwoLDgsKLRCQoZitEJMODwoPDgsKCw4PCgsOCwrfDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoP
+ Dg8KCw4LCgcODwoPDgsKDw4PCgsOCwqHDg8KDw4LCgsODwoLDgsKLRCQkZitEJMODwoPDgsKCw4PC
+ gsOCwrfDg8KDw4LCg8ODwoLDgsKQw4PCg8OCwoPDg8KCw4LCisODwoPDgsKCw4PCgsOCwotFUVZqU
+ MODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKAw4PCg8OCwoLDg8KCw4LCik85dCTDg8KDw4
+ LCgsODwoLDgsKFQ8ODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4L
+ Cvzl0JMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPD
+ gsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKLRCTDg8KDw4LCgsODwoLDgsKDw4PCg8OCwoLDg8KCw
+ 4LCuMODwoPDgsKDw4PCgsOCwoR0Q8ODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LChMODwo
+ PDgsKDw4PCgsOCwoFOdTrDg8KDw4LCg8ODwoLDgsKHw4PCg8OCwoPDg8KCw4LChMODwoPDgsKDw4P
+ CgsOCwoFOw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwrtHw4PCg8OCwoLDg8KCw4LChcOD
+ woPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsK4dMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODw
+ oLDgsKtR8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwo
+ PDgsKDw4PCgsOCwr9SfGrDg8KDw4LCgsODwoLDgsKLQGgxw4PCg8OCwoPDg8KCw4LCoWhQw4PCg8O
+ CwoPDg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKT8ODwoPDgsKCw4PCgsOC
+ wotEJDDDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHTDg8KDw4LCgsODwoLDgsKDw4PCg
+ 8OCwoPDg8KCw4LCuHXDg8KDw4LCgsODwoLDgsKLRCRqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4
+ PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpPDg8K
+ Dw4LCg8ODwoLDgsKQXV9eW8ODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoPD
+ g8KCw4LCgsODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODw
+ oPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgs
+ OCwoxWV8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKxw4PCg8OCwoLDg8KCw4LCi3wkw4P
+ Cg8OCwoLDg8KCw4LCjcODwoPDgsKCw4PCgsOCwofDg8KDw4LCg8ODwoLDgsKof8ODwoPDgsKDw4PC
+ gsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCg8ODwoPDgsKDw4PCgsOCwrh5w4PCg
+ 8OCwoLDg8KCw4LChzQzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PCgsOCworDg8KDw4LCgsODwo
+ LDgsKIw4PCg8OCwoLDg8KCw4LCuDFBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNdDF
+ Bw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPD
+ gsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw
+ 4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgs
+ KCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKAdcODwoPDgsKDw4PCgsOCwqhtw4PCg8OCwoLDg8KCw4L
+ ChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCsMODwoPDgsKC
+ w4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCt
+ sODwoPDgsKDw4PCgsOCwq7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4
+ PCgsOCwoPDg8KDw4LCg8ODwoLDgsKoZsODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4w4P
+ Cg8OCwoLDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwpUzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PC
+ gsOCworDg8KDw4LCgsODwoLDgsKISDJBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNN
+ DJBw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwo
+ PDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8O
+ DwoPDgsKDw4PCgsOCwojDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCnEzDg8KDw4LCgsOD
+ woLDgsKLSEBmw4PCg8OCwoLDg8KCw4LCg3lwdSTDg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw
+ 4LCv8ODwoPDgsKCw4PCgsOCwobDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgs
+ KCw4PCgsOCwp/Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwoj
+ Dg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCwpPDg8KDw4LCgsOD
+ woLDgsKBw4PCg8OCwoPDg8KCw4LCv1rDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODw
+ oPDgsKCw4PCgsOCwodqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwoBqaMODwoPDgsKCw4
+ PCgsOCwpBQw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDIMODwoPDgsKCw4PCgsOCwopPw4PCg8OCwoL
+ Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKOacODwoPDgsKCw4PCgsOCwrhf
+ XsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCw
+ oLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKGw4PCg8OCwoLDg8KCw4LCgM
+ ODwoPDgsKCw4PCgsOCwoRJw4PCg8OCwoLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsO
+ DwoLDgsKIw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQ9w4PCg8OCwoLDg8KCw4LCgcOD
+ woPDgsKDw4PCgsOCwr9aw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQxw4PCg8OCwoLDg
+ 8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LCm0
+ 7Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsK
+ Cw4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
+ gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODw
+ oPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgs
+ OCwo7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCkMODwoPDgsKDw4PCgsOCwojDg8KDw4L
+ CgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsK+
+ S8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKww4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDw
+ 4PCgsOCwoTDg8KDw4LCgsODwoLDgsKKT1DDg8KDw4LCg8ODwoLDgsKoRsODwoPDgsKCw4PCgsOCwo
+ vDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwrZ0Y8ODwoPDgsK
+ Cw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/dF/Dg8KDw4LCgsODwoLDgsKhdHpPw4PCg8OCwoLDg8KC
+ w4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PCg8OCwoPDg8KCw4LCqC1Jw4PCg8OCwoLDg8KCw4LChcODw
+ oPDgsKDw4PCgsOCwoB1RMODwoPDgsKCw4PCgsOCwqFwek/Dg8KDw4LCgsODwoLDgsKLw4PCg8OCwo
+ PDg8KCw4LCj1DDg8KDw4LCg8ODwoLDgsKoScODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK
+ AdTPDg8KDw4LCgsODwoLDgsKhbHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PC
+ g8OCwoPDg8KCw4LCqEnDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHXDg8KDw4LCgsODw
+ oLDgsKhaHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo9Qw4PCg8OCwoPDg8KCw4LCqM
+ ODwoPDgsKDw4PCgsOCwrpIw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoB1M8ODwoPDgsK
+ Dw4PCgsOCwoBfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
+ gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgjPDg8KDw4LCg8ODwoLDgsKAX17Dg
+ 8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCg8ODwo
+ LDgsKoJ8ODwoPDgsKDw4PCgsOCwq3Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoP
+ DgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4aHU5w4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PC
+ gsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw
+ 4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgs
+ KIw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpLDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoL
+ Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoB0IcODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKA
+ w4PCg8OCwoPDg8KCw4LCtMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKAdGbDg8KDw4LCg
+ sODwoLDgsKLQGY9dGY9dTPDg8KDw4LCg8ODwoLDgsKAX17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwo
+ LDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPDgsKDw4PCgsO
+ CwoIzw4PCg8OCwoPDg8KCw4LCgF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwovDg8KD
+ w4LCg8ODwoLDgsK/Ri9BUC9BRi9BWi9BZC9BWzBBZC9BZTBBZC9BZC9BbzBBZC9BeTBBw4PCg8OCw
+ oLDg8KCw4LCgzBBMUFhMUFrMUE=
+description:: UF7Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOC
+ wozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg
+ 8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCqFDDg8KDw4LCg8ODwoLDgsKpRsODwoPDgsKDw4PCgsOCwo
+ zDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8O
+ DwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKCw4PCgsOCwotEJCDDg8KDw4LCgsODwoLDgsKD
+ w4PCg8OCwoPDg8KCw4LCrMODwoPDgsKCw4PCgsOCwotUJCRTw4PCg8OCwoLDg8KCw4LCi1wkJFbDg
+ 8KDw4LCgsODwoLDgsKJTCRXVVBSU8ODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsKdT8ODwo
+ PDgsKCw4PCgsOCwoN8JDB1w4PCg8OCwoPDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8O
+ DwoLDgsKBTsODwoPDgsKDw4PCgsOCwqktw4PCg8OCwoLDg8KCw4LCg3wkMHTDg8KDw4LCgsODwoLD
+ gsKDfCQww4PCg8OCwoLDg8KCw4LChTPDg8KDw4LCg8ODwoLDgsK2OTXDg8KDw4LCg8ODwoLDgsKAw
+ 4PCg8OCwoPDg8KCw4LCgU7Dg8KDw4LCgsODwoLDgsKEIMODwoPDgsKCw4PCgsOCwqFIw4PCg8OCwo
+ PDg8KCw4LChU7Dg8KDw4LCgsODwoLDgsKJNcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8ODwoLDgsK
+ BTsODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKD
+ w4PCgsOCwr9TXMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw
+ 4LChMODwoPDgsKCw4PCgsOCwpHDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLIEjDg8
+ KDw4LCg8ODwoLDgsKFTlDDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ngw4PCg8OCwoL
+ Dg8KCw4LCi8ODwoPDgsKDw4PCgsOCwpjDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCm3Rx
+ w4PCg8OCwoLDg8KCw4LCizvDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi8ODwoPDgsKDw
+ 4PCgsOCwr9XaMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGdGLDg8KDw4LCgsODwo
+ LDgsKLf2zDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi1D
+ Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8OD
+ woLDgsKow4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwq10SmgoT03Dg8KDw4LCgsODwoLDg
+ sKLw4PCg8OCwoPDg8KCw4LCjcODwoPDgsKDw4PCgsOCwqggTMODwoPDgsKCw4PCgsOCwoXDg8KDw4
+ LCg8ODwoLDgsKAdDrDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLTSBQUcODwoPDgsK
+ Dw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKL
+ RCQoZitEJCDDg8KDw4LCgsODwoLDgsK3w4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwoHDg
+ 8KDw4LCg8ODwoLDgsKhw4PCg8OCwoLDg8KCw4LCi0QkJGYrRCTDg8KDw4LCgsODwoLDgsK3w4PCg8
+ OCwoPDg8KCw4LCkMODwoPDgsKDw4PCgsOCworDg8KDw4LCgsODwoLDgsKLRSBRVmpQw4PCg8OCwoP
+ Dg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKTzl0JHXDg8KDw4LCgsODwoLD
+ gsKhOXQkw4PCg8OCwoLDg8KCw4LChW/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODw
+ oPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKhRMODwoPDgsKDw4PCgsOCwoVOw4PCg8OCwoLDg8
+ KCw4LCi8ODwoPDgsKDw4PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ncw4P
+ Cg8OCwoLDg8KCw4LCiUQkw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsOD
+ woLDgsKEw4PCg8OCwoPDg8KCw4LCtjPDg8KDw4LCg8ODwoLDgsK2w4PCg8OCwoLDg8KCw4LCjUQkw
+ 4PCg8OCwoLDg8KCw4LCiyBEw4PCg8OCwoPDg8KCw4LChU5Qw4PCg8OCwoLDg8KCw4LCi8ODwoPDgs
+ KDw4PCgsOCwr9TYMODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4L
+ ChcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCkMODwoPDgsKC
+ w4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCj8ODwoPDgsKDw4PCgsOCwr9Ta
+ MODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw4LChMODwoPDgs
+ KCw4PCgsOCwr3Dg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4L
+ Cj1DDg8KDw4LCg8ODwoLDgsK/U2zDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCqMODwoPD
+ gsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKtw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCw
+ p9oMMODwoPDgsKDw4PCgsOCwolMw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4
+ LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCq0vDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4L
+ CgMODwoPDgsKCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi0QkOcODwoPD
+ gsKCw4PCgsOCwrDDg8KDw4LCg8ODwoLDgsKEdEU5w4PCg8OCwoLDg8KCw4LCtTR0PcODwoPDgsKCw
+ 4PCgsOCwovDg8KDw4LCg8ODwoLDgsKNw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwo5Lw4
+ PCg8OCwoLDg8KCw4LCi0AgUMODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKsw4PCg8OCwoL
+ Dg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHUow4PCg8OCwoLDg8KCw4LC
+ i8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCgsODwoLDgsKJw4PCg8OCwoLDg8KCw4LCtTTDg8KDw4LCg
+ 8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKDw4PCgsOCwrtWw4PCg8OCwoLDg8KCw4LCi8
+ ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCnw==
+
+#LEAD COMMENT
+
+# another comment
+dn: CN=All Staff,ou=Groups,o=University of Michigan,c=TEST
+#EMBEDDED COMMENT
+member: cn=Manager,o=University of Michigan,c=TEST
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Unive
+ rsity of Michigan,c=TEST
+member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
+ =US
+member: cn=John Doe,ou=Information Technology Division,ou=People,o=University
+ of Michigan,c=TEST
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Univ
+ ersity of Michigan,c=TEST
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
+ igan,c=TEST
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=Univers
+ ity of Michigan,c=TEST
+owner: cn=Manager,o=University of Michigan,c=TEST
+cn: All Staff
+description: Everyone in the sample data
+objectclass: groupofnames
+
+dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=TEST
+member: cn=Manager,o=University of Michigan,c=TEST
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
+ =US
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
+ igan,c=TEST
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+owner: cn=Manager,o=University of Michigan,c=TEST
+description: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+objectclass: groupofnames
+
+dn: cn=Finance, cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=TEST
+member: cn=Manager,o=University of Michigan,c=TEST
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
+ higan,c=TEST
+owner: cn=Manager,o=University of Michigan,c=TEST
+description: Finance group
+cn: Finance
+objectclass: groupofnames
+
+dn: ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: organizationalUnit
+ou: Alumni Association
+
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Universit
+ y of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn:: IEplbnNlbiA=
+uid:: YmplCW5zZW4
+title: Mythical Manager, Research Systems
+postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann
+ Arbor, MI 48103-4943
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+userpassword:: YmplbnNlbg==
+mail: bjensen@mailgw.example.com
+homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
+description: Mythical manager of the rsdd unix project
+drink: water
+homephone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimiletelephonenumber: +1 313 555 2274
+telephonenumber: +1 313 555 9022
+
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=University
+ of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+uid: bjorn
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+userpassword:: Ympvcm4=
+homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+description: Hiker, biker
+title: Director, Embedded Systems
+postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
+mail: bjorn@mailgw.example.com
+homephone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimiletelephonenumber: +1 313 555 2177
+telephonenumber: +1 313 555 0355
+
+dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+objectclass: OpenLDAPperson
+cn: Dorothy Stevens
+cn: Dot Stevens
+sn: Stevens
+uid: dots
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+drink: Lemonade
+homepostaladdress: 377 White St. Apt. 3 $ Ann Arbor, MI 48104
+description: Very tall
+facsimiletelephonenumber: +1 313 555 3223
+telephonenumber: +1 313 555 3664
+mail: dots@mail.alumni.example.com
+homephone: +1 313 555 0454
+
+dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=TEST
+owner: cn=Manager,o=University of Michigan,c=TEST
+description: All ITD Staff
+cn: ITD Staff
+objectclass: groupofuniquenames
+uniquemember: cn=Manager,o=University of Michigan,c=TEST
+uniquemember: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=U
+ niversity of Michigan,c=TEST
+uniquemember: cn=James A Jones 2,ou=Information Technology Division,ou=People,
+ o=University of Michigan,c=TEST
+uniquemember: cn=John Doe,ou=Information Technology Division,ou=People,o=Unive
+ rsity of Michigan,c=TEST
+
+dn: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+objectclass: OpenLDAPperson
+cn: James A Jones 1
+cn: James Jones
+cn: Jim Jones
+sn: Jones
+uid: jaj
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+userpassword:: amFq
+homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
+homephone: +1 313 555 4772
+description: Outstanding
+title: Mad Cow Researcher, UM Alumni Association
+pager: +1 313 555 3923
+mail: jaj@mail.alumni.example.com
+facsimiletelephonenumber: +1 313 555 4332
+telephonenumber: +1 313 555 0895
+
+dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Universi
+ ty of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: James A Jones 2
+cn: James Jones
+cn: Jim Jones
+sn: Doe
+uid: jjones
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 933 Brooks $ Ann Arbor, MI 48104
+homephone: +1 313 555 8838
+title: Senior Manager, Information Technology Division
+description: Not around very much
+mail: jjones@mailgw.example.com
+postaladdress: Info Tech Division $ 535 W William $ Ann Arbor, MI 48103
+pager: +1 313 555 2833
+facsimiletelephonenumber: +1 313 555 8688
+telephonenumber: +1 313 555 7334
+
+dn: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Jane Doe
+cn: Jane Alverson
+sn: Doe
+uid: jdoe
+title: Programmer Analyst, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+drink: diet coke
+description: Enthusiastic
+mail: jdoe@woof.net
+homephone: +1 313 555 5445
+pager: +1 313 555 1220
+facsimiletelephonenumber: +1 313 555 2311
+telephonenumber: +1 313 555 4774
+
+dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Michigan
+ ,c=TEST
+objectclass: OpenLDAPperson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+uid: jen
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+drink: Sam Adams
+homepostaladdress: 1000 Maple #44 $ Ann Arbor, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.example.com
+homephone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimiletelephonenumber: +1 313 555 2756
+telephonenumber: +1 313 555 8232
+
+dn: cn=John Doe,ou=Information Technology Division,ou=People,o=University of M
+ ichigan,c=TEST
+objectclass: OpenLDAPperson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+uid: johnd
+postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
+title: System Administrator, Information Technology Division
+description: overworked!
+mail: johnd@mailgw.example.com
+homephone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimiletelephonenumber: +1 313 555 4544
+telephonenumber: +1 313 555 9394
+
+dn: cn=Manager,o=University of Michigan,c=TEST
+objectclass: person
+cn: Manager
+cn: Directory Manager
+cn: Dir Man
+sn: Manager
+description: Manager of the directory
+userpassword:: c2VjcmV0
+
+dn: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michigan,c=
+ TEST
+objectclass: OpenLDAPperson
+cn: Mark Elliot
+cn: Mark A Elliot
+sn: Elliot
+uid: melliot
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 199 Outer Drive $ Ypsilanti, MI 48198
+homephone: +1 313 555 0388
+drink: Gasoline
+title: Director, UM Alumni Association
+mail: melliot@mail.alumni.example.com
+pager: +1 313 555 7671
+facsimiletelephonenumber: +1 313 555 7762
+telephonenumber: +1 313 555 4177
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
+ n,c=TEST
+objectclass: OpenLDAPperson
+cn: Ursula Hampster
+sn: Hampster
+uid: uham
+title: Secretary, UM Alumni Association
+postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
+seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=TEST
+homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
+mail: uham@mail.alumni.example.com
+description: a long attribute name, longer than 128 bytes so that we
+ trigger sign extension problems in tdb_pack, no that's not long enough
+ yet, maybe this is. I'll just keep going till it triggers the error
+homephone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimiletelephonenumber: +1 313 555 9700
+telephonenumber: +1 313 555 5331
+
+dn: cn=Fred Bassett,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
+objectclass: OpenLDAPperson
+cn: Fred Bassett
+sn: Bassett
+uid: Bassett, Fred
+
+dn: o=ESCPI , o=CNAM,c=TEST
+objectclass: organizationalUnit
+o: ESCPI
+o: CNAM
+
+dn: o=ESCPI , uo=CNAM,c=TEST
+objectclass: organizationalUnit
+o: ESCPI
+uo: CNAM
+
+dn: cn=mat,o=ESCPI,o=CNAM,c=TEST
+objectclass: person
+cn: mat
diff --git a/lib/ldb/tests/test_ldb_dn.c b/lib/ldb/tests/test_ldb_dn.c
new file mode 100644
index 0000000..6bf621a
--- /dev/null
+++ b/lib/ldb/tests/test_ldb_dn.c
@@ -0,0 +1,232 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <ldb.h>
+#include "ldb_private.h"
+
+static void test_ldb_dn_add_child_fmt(void **state)
+{
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+
+ struct ldb_dn *dn = ldb_dn_new(ldb, ldb, "dc=samba,dc=org");
+
+ assert_true(ldb_dn_add_child_fmt(dn,
+ "DC=X"));
+
+ assert_string_equal("DC=X,dc=samba,dc=org",
+ ldb_dn_get_linearized(dn));
+
+ assert_string_equal("DC=X,DC=SAMBA,DC=ORG",
+ ldb_dn_get_casefold(dn));
+
+}
+
+static void test_ldb_dn_add_child_fmt2(void **state)
+{
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+
+ struct ldb_dn *dn = ldb_dn_new(ldb, ldb, "dc=samba,dc=org");
+
+ assert_true(ldb_dn_add_child_fmt(dn,
+ "DC=X,DC=Y"));
+
+ assert_string_equal("DC=X,DC=Y,dc=samba,dc=org",
+ ldb_dn_get_linearized(dn));
+
+ assert_string_equal("DC=X,DC=Y,DC=SAMBA,DC=ORG",
+ ldb_dn_get_casefold(dn));
+
+ assert_int_equal(4,
+ ldb_dn_get_comp_num(dn));
+
+}
+
+static void test_ldb_dn_add_child_val(void **state)
+{
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+
+ struct ldb_dn *dn = ldb_dn_new(ldb, ldb, "dc=samba,dc=org");
+ struct ldb_val name = {.data = discard_const("X"),
+ .length = 1
+ };
+
+ assert_true(ldb_dn_add_child_val(dn,
+ "DC", name));
+
+ assert_string_equal("DC=X,dc=samba,dc=org",
+ ldb_dn_get_linearized(dn));
+
+ assert_string_equal("DC=X,DC=SAMBA,DC=ORG",
+ ldb_dn_get_casefold(dn));
+
+}
+
+static void test_ldb_dn_add_child_val2(void **state)
+{
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+
+ struct ldb_dn *dn = ldb_dn_new(ldb, ldb, "dc=samba,dc=org");
+
+ struct ldb_val name = {.data = discard_const("X,DC=Y"),
+ .length = 6
+ };
+
+ assert_true(ldb_dn_add_child_val(dn,
+ "DC", name));
+
+ assert_string_equal("DC=X\\,DC\\3DY,dc=samba,dc=org",
+ ldb_dn_get_linearized(dn));
+
+ assert_string_equal("DC=X\\,DC\\3DY,DC=SAMBA,DC=ORG",
+ ldb_dn_get_casefold(dn));
+
+ assert_int_equal(3,
+ ldb_dn_get_comp_num(dn));
+
+}
+
+struct explode_test {
+ const char *strdn;
+ int comp_num;
+ int ext_comp_num;
+ bool special;
+ bool invalid;
+ const char *linearized;
+ const char *ext_linearized_1;
+ bool explode_result;
+};
+
+static int extended_dn_read_ID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+
+ /* Allow to check we can cope with validity checks */
+ if (in->length != 4) {
+ return -1;
+ }
+
+ *out = *in;
+ out->data = talloc_memdup(mem_ctx, in->data, in->length);
+ if (out->data == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* write out (reused for both HEX and clear for now) */
+static int extended_dn_write_ID(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ *out = *in;
+
+ out->data = talloc_memdup(mem_ctx, in->data, in->length);
+ if (out->data == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+
+static void test_ldb_dn_explode(void **state)
+{
+ size_t i;
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+ struct explode_test tests[] = {
+ {"A=B", 1, 0, false, false, "A=B", "A=B", true},
+ {"", 0, 0, false, false, "", "", true},
+ {" ", -1, -1, false, false, " ", " ", false},
+ {"<>", 0, 0, false, false, "", NULL, true},
+ {"<", 0, 0, false, false, "", NULL, true},
+ {"<><", 0, 0, false, false, "", NULL, true},
+ {"<><>", 0, 0, false, false, "", NULL, true},
+ {"A=B,C=D", 2, 0, false, false, "A=B,C=D", "A=B,C=D", true},
+ {"<X=Y>A=B,C=D", -1, -1, false, false, "", NULL, false},
+ {"<X=Y>;A=B,C=D", -1, -1, false, false, "A=B,C=D", NULL, false},
+ {"<ID=ABC>;A=B,C=D", -1, -1, false, true, "A=B,C=D", NULL, false},
+ {"<ID=ABCD>;A=B,C=D", 2, 1, false, false, "A=B,C=D", "<ID=ABCD>;A=B,C=D", true},
+ {"x=🔥", 1, 0, false, false, "x=🔥", "x=🔥", true},
+ {"@FOO", 0, 0, true, false, "@FOO", "@FOO", true},
+ };
+
+ struct ldb_dn_extended_syntax syntax = {
+ .name = "ID",
+ .read_fn = extended_dn_read_ID,
+ .write_clear_fn = extended_dn_write_ID,
+ .write_hex_fn = extended_dn_write_ID
+ };
+
+ ldb_dn_extended_add_syntax(ldb, 0, &syntax);
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ bool result;
+ const char *linear;
+ const char *ext_linear;
+ struct ldb_dn *dn = ldb_dn_new(ldb, ldb, tests[i].strdn);
+
+ /*
+ * special, invalid, linear, and ext_linear are set before
+ * explode
+ */
+ linear = ldb_dn_get_linearized(dn);
+ assert_true((linear == NULL) == (tests[i].linearized == NULL));
+ assert_string_equal(linear,
+ tests[i].linearized);
+
+ ext_linear = ldb_dn_get_extended_linearized(ldb, dn, 1);
+ assert_true((ext_linear == NULL) ==
+ (tests[i].ext_linearized_1 == NULL));
+
+ if (tests[i].ext_linearized_1 != NULL) {
+ assert_string_equal(ext_linear,
+ tests[i].ext_linearized_1);
+ }
+ assert_true(ldb_dn_is_special(dn) == tests[i].special);
+ assert_true(ldb_dn_is_valid(dn) != tests[i].invalid);
+
+ /* comp nums are set by explode */
+ result = ldb_dn_validate(dn);
+ print_error("test %zu «%s»: res %i lin «%s» ext «%s»\n",
+ i, tests[i].strdn, result, linear, ext_linear);
+
+ assert_true(result == tests[i].explode_result);
+ assert_int_equal(ldb_dn_get_comp_num(dn),
+ tests[i].comp_num);
+ assert_int_equal(ldb_dn_get_extended_comp_num(dn),
+ tests[i].ext_comp_num);
+ }
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_ldb_dn_add_child_fmt),
+ cmocka_unit_test(test_ldb_dn_add_child_fmt2),
+ cmocka_unit_test(test_ldb_dn_add_child_val),
+ cmocka_unit_test(test_ldb_dn_add_child_val2),
+ cmocka_unit_test(test_ldb_dn_explode),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/test_ldb_qsort.c b/lib/ldb/tests/test_ldb_qsort.c
new file mode 100644
index 0000000..663cf0e
--- /dev/null
+++ b/lib/ldb/tests/test_ldb_qsort.c
@@ -0,0 +1,65 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <ldb.h>
+
+static int cmp_integer(int *a, int *b, void *opaque)
+{
+ if (a == NULL || b == NULL) {
+ return 0;
+ }
+
+ if (*a > *b) {
+ return 1;
+ }
+
+ if (*a < *b) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void test_ldb_qsort(void **state)
+{
+ int a[6] = { 6, 3, 2, 7, 9, 4 };
+
+ ldb_qsort(a, 6, sizeof(int), NULL, (ldb_qsort_cmp_fn_t)cmp_integer);
+
+ assert_int_equal(a[0], 2);
+ assert_int_equal(a[1], 3);
+ assert_int_equal(a[2], 4);
+ assert_int_equal(a[3], 6);
+ assert_int_equal(a[4], 7);
+ assert_int_equal(a[5], 9);
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_ldb_qsort),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/ldb/tests/testdata.txt b/lib/ldb/tests/testdata.txt
new file mode 100644
index 0000000..dadb9f0
--- /dev/null
+++ b/lib/ldb/tests/testdata.txt
@@ -0,0 +1,8 @@
+foo=bar5
+(&(|(a=b)(c=d))(e=f))
+(&(|(a=b)(c=d)(g=h))(e=f))
+name=firstname lastname
+(&(sid=S-1-2-3)(name = fred bloggs))
+(&(|(a=b)(c=d))(g=f))
+(&(sid=S-1-2-3)(!(name = fred bloggs)))
+(&(!(|(a=b)(c=d))(g=f)))
diff --git a/lib/ldb/tests/testsearch.txt b/lib/ldb/tests/testsearch.txt
new file mode 100644
index 0000000..c573863
--- /dev/null
+++ b/lib/ldb/tests/testsearch.txt
@@ -0,0 +1,5 @@
+(blah=foo)
+(objectclass=person)
+(dn=*)
+(&(objectclass=person)(objectclass=person))
+(&(objectclass=person)(objectclass=personx))
diff --git a/lib/ldb/tools/cmdline.c b/lib/ldb/tools/cmdline.c
new file mode 100644
index 0000000..ff25fe0
--- /dev/null
+++ b/lib/ldb/tools/cmdline.c
@@ -0,0 +1,766 @@
+/*
+ ldb database library - command line handling for ldb tools
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb.h"
+#include "ldb_module.h"
+#include "tools/cmdline.h"
+
+static struct ldb_cmdline options; /* needs to be static for older compilers */
+
+enum ldb_cmdline_options { CMDLINE_RELAX=1 };
+
+static struct poptOption builtin_popt_options[] = {
+ POPT_AUTOHELP
+ {
+ .longName = "url",
+ .shortName = 'H',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.url,
+ .val = 0,
+ .descrip = "database URL",
+ .argDescrip = "URL"
+ },
+ {
+ .longName = "basedn",
+ .shortName = 'b',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.basedn,
+ .val = 0,
+ .descrip = "base DN",
+ .argDescrip = "DN"
+ },
+ {
+ .longName = "editor",
+ .shortName = 'e',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.editor,
+ .val = 0,
+ .descrip = "external editor",
+ .argDescrip = "PROGRAM"
+ },
+ {
+ .longName = "scope",
+ .shortName = 's',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 's',
+ .descrip = "search scope",
+ .argDescrip = "SCOPE"
+ },
+ {
+ .longName = "verbose",
+ .shortName = 'v',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'v',
+ .descrip = "increase verbosity",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "trace",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.tracing,
+ .val = 0,
+ .descrip = "enable tracing",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "interactive",
+ .shortName = 'i',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.interactive,
+ .val = 0,
+ .descrip = "input from stdin",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "recursive",
+ .shortName = 'r',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.recursive,
+ .val = 0,
+ .descrip = "recursive delete",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "modules-path",
+ .shortName = 0,
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.modules_path,
+ .val = 0,
+ .descrip = "modules path",
+ .argDescrip = "PATH"
+ },
+ {
+ .longName = "num-searches",
+ .shortName = 0,
+ .argInfo = POPT_ARG_INT,
+ .arg = &options.num_searches,
+ .val = 0,
+ .descrip = "number of test searches",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "num-records",
+ .shortName = 0,
+ .argInfo = POPT_ARG_INT,
+ .arg = &options.num_records,
+ .val = 0,
+ .descrip = "number of test records",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "all",
+ .shortName = 'a',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.all_records,
+ .val = 0,
+ .descrip = "(|(objectClass=*)(distinguishedName=*))",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "nosync",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.nosync,
+ .val = 0,
+ .descrip = "non-synchronous transactions",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "sorted",
+ .shortName = 'S',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.sorted,
+ .val = 0,
+ .descrip = "sort attributes",
+ .argDescrip = NULL
+ },
+ {
+ .longName = NULL,
+ .shortName = 'o',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'o',
+ .descrip = "ldb_connect option",
+ .argDescrip = "OPTION"
+ },
+ {
+ .longName = "controls",
+ .shortName = 0,
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'c',
+ .descrip = "controls",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-binary",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.show_binary,
+ .val = 0,
+ .descrip = "display binary LDIF",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "paged",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'P',
+ .descrip = "use a paged search",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-deleted",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'D',
+ .descrip = "show deleted objects",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-recycled",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'R',
+ .descrip = "show recycled objects",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-deactivated-link",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'd',
+ .descrip = "show deactivated links",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "reveal",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'r',
+ .descrip = "reveal ldb internals",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "relax",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = CMDLINE_RELAX,
+ .descrip = "pass relax control",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "cross-ncs",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'N',
+ .descrip = "search across NC boundaries",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "extended-dn",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'E',
+ .descrip = "show extended DNs",
+ .argDescrip = NULL
+ },
+ POPT_TABLEEND
+};
+
+void ldb_cmdline_help(struct ldb_context *ldb, const char *cmdname, FILE *f)
+{
+ poptContext pc;
+ struct poptOption **popt_options = ldb_module_popt_options(ldb);
+ pc = poptGetContext(cmdname, 0, NULL, *popt_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ poptPrintHelp(pc, f, 0);
+}
+
+/*
+ add a control to the options structure
+ */
+static bool add_control(TALLOC_CTX *mem_ctx, const char *control)
+{
+ unsigned int i;
+
+ /* count how many controls we already have */
+ for (i=0; options.controls && options.controls[i]; i++) ;
+
+ options.controls = talloc_realloc(mem_ctx, options.controls, const char *, i + 2);
+ if (options.controls == NULL) {
+ return false;
+ }
+ options.controls[i] = control;
+ options.controls[i+1] = NULL;
+ return true;
+}
+
+/**
+ process command line options
+*/
+static struct ldb_cmdline *ldb_cmdline_process_internal(struct ldb_context *ldb,
+ int argc, const char **argv,
+ void (*usage)(struct ldb_context *),
+ bool dont_create,
+ bool search)
+{
+ struct ldb_cmdline *ret=NULL;
+ poptContext pc;
+ int num_options = 0;
+ int opt;
+ unsigned int flags = 0;
+ int rc;
+ struct poptOption **popt_options;
+
+ /* make the ldb utilities line buffered */
+ setlinebuf(stdout);
+
+ ret = talloc_zero(ldb, struct ldb_cmdline);
+ if (ret == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ goto failed;
+ }
+
+ options = *ret;
+
+ /* pull in URL */
+ options.url = getenv("LDB_URL");
+
+ /* and editor (used by ldbedit) */
+ options.editor = getenv("VISUAL");
+ if (!options.editor) {
+ options.editor = getenv("EDITOR");
+ }
+ if (!options.editor) {
+ options.editor = "vi";
+ }
+
+ options.scope = LDB_SCOPE_DEFAULT;
+
+ popt_options = ldb_module_popt_options(ldb);
+ (*popt_options) = builtin_popt_options;
+
+ rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_OPTIONS);
+ if (rc != LDB_SUCCESS) {
+ fprintf(stderr, "ldb: failed to run command line hooks : %s\n", ldb_strerror(rc));
+ goto failed;
+ }
+
+ pc = poptGetContext(argv[0], argc, argv, *popt_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 's': {
+ const char *arg = poptGetOptArg(pc);
+ if (strcmp(arg, "base") == 0) {
+ options.scope = LDB_SCOPE_BASE;
+ } else if (strcmp(arg, "sub") == 0) {
+ options.scope = LDB_SCOPE_SUBTREE;
+ } else if (strcmp(arg, "one") == 0) {
+ options.scope = LDB_SCOPE_ONELEVEL;
+ } else {
+ fprintf(stderr, "Invalid scope '%s'\n", arg);
+ goto failed;
+ }
+ break;
+ }
+
+ case 'v':
+ options.verbose++;
+ break;
+
+ case 'o':
+ options.options = talloc_realloc(ret, options.options,
+ const char *, num_options+3);
+ if (options.options == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ goto failed;
+ }
+ options.options[num_options] = poptGetOptArg(pc);
+ options.options[num_options+1] = NULL;
+ num_options++;
+ break;
+
+ case 'c': {
+ const char *cs = poptGetOptArg(pc);
+ const char *p;
+
+ for (p = cs; p != NULL; ) {
+ const char *t, *c;
+
+ t = strchr(p, ',');
+ if (t == NULL) {
+ c = talloc_strdup(options.controls, p);
+ p = NULL;
+ } else {
+ c = talloc_strndup(options.controls, p, t-p);
+ p = t + 1;
+ }
+ if (c == NULL || !add_control(ret, c)) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ }
+
+ break;
+ }
+ case 'P':
+ if (!add_control(ret, "paged_results:1:1024")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ case 'D':
+ if (!add_control(ret, "show_deleted:1")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ case 'R':
+ if (!add_control(ret, "show_recycled:0")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ case 'd':
+ if (!add_control(ret, "show_deactivated_link:0")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ case 'r':
+ if (!add_control(ret, "reveal_internals:0")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ case CMDLINE_RELAX:
+ if (!add_control(ret, "relax:0")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ case 'N':
+ if (!add_control(ret, "search_options:1:2")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ case 'E':
+ if (!add_control(ret, "extended_dn:1:1")) {
+ fprintf(stderr, __location__ ": out of memory\n");
+ goto failed;
+ }
+ break;
+ default:
+ fprintf(stderr, "Invalid option %s: %s\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ if (usage) usage(ldb);
+ goto failed;
+ }
+ }
+
+ /* setup the remaining options for the main program to use */
+ options.argv = poptGetArgs(pc);
+ if (options.argv) {
+ options.argv++;
+ while (options.argv[options.argc]) options.argc++;
+ }
+
+ *ret = options;
+
+ /* all utils need some option */
+ if (ret->url == NULL) {
+ fprintf(stderr, "You must supply a url with -H or with $LDB_URL\n");
+ if (usage) usage(ldb);
+ goto failed;
+ }
+
+ if (strcmp(ret->url, "NONE") == 0) {
+ return ret;
+ }
+
+ if (options.nosync) {
+ flags |= LDB_FLG_NOSYNC;
+ }
+
+ if (search) {
+ flags |= LDB_FLG_DONT_CREATE_DB;
+
+ if (options.show_binary) {
+ flags |= LDB_FLG_SHOW_BINARY;
+ }
+ }
+
+ if (options.tracing) {
+ flags |= LDB_FLG_ENABLE_TRACING;
+ }
+
+ if (options.modules_path != NULL) {
+ ldb_set_modules_dir(ldb, options.modules_path);
+ }
+
+ rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_PRECONNECT);
+ if (rc != LDB_SUCCESS) {
+ fprintf(stderr, "ldb: failed to run preconnect hooks : %s\n", ldb_strerror(rc));
+ goto failed;
+ }
+
+ /* now connect to the ldb */
+ if (ldb_connect(ldb, ret->url, flags, ret->options) != LDB_SUCCESS) {
+ fprintf(stderr, "Failed to connect to %s - %s\n",
+ ret->url, ldb_errstring(ldb));
+ goto failed;
+ }
+
+ rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_POSTCONNECT);
+ if (rc != LDB_SUCCESS) {
+ fprintf(stderr, "ldb: failed to run post connect hooks : %s\n", ldb_strerror(rc));
+ goto failed;
+ }
+
+ return ret;
+
+failed:
+ talloc_free(ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ return NULL;
+}
+
+struct ldb_cmdline *ldb_cmdline_process_search(struct ldb_context *ldb,
+ int argc, const char **argv,
+ void (*usage)(struct ldb_context *))
+{
+ return ldb_cmdline_process_internal(ldb, argc, argv, usage, true, true);
+}
+
+struct ldb_cmdline *ldb_cmdline_process_edit(struct ldb_context *ldb,
+ int argc, const char **argv,
+ void (*usage)(struct ldb_context *))
+{
+ return ldb_cmdline_process_internal(ldb, argc, argv, usage, false, true);
+}
+
+struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb,
+ int argc, const char **argv,
+ void (*usage)(struct ldb_context *))
+{
+ return ldb_cmdline_process_internal(ldb, argc, argv, usage, false, false);
+}
+
+/* this function check controls reply and determines if more
+ * processing is needed setting up the request controls correctly
+ *
+ * returns:
+ * -1 error
+ * 0 all ok
+ * 1 all ok, more processing required
+ */
+int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request)
+{
+ unsigned int i, j;
+ int ret = 0;
+
+ if (reply == NULL || request == NULL) return -1;
+
+ for (i = 0; reply[i]; i++) {
+ if (strcmp(LDB_CONTROL_VLV_RESP_OID, reply[i]->oid) == 0) {
+ struct ldb_vlv_resp_control *rep_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_vlv_resp_control);
+ if (rep_control == NULL) {
+ fprintf(stderr,
+ "Warning VLV reply OID received "
+ "with no VLV data\n");
+ continue;
+ }
+
+ /* check we have a matching control in the request */
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_VLV_REQ_OID, request[j]->oid) == 0)
+ break;
+ }
+ if (! request[j]) {
+ fprintf(stderr, "Warning VLV reply received but no request have been made\n");
+ continue;
+ }
+
+ /* check the result */
+ if (rep_control->vlv_result != 0) {
+ fprintf(stderr, "Warning: VLV not performed with error: %d\n", rep_control->vlv_result);
+ } else {
+ fprintf(stderr, "VLV Info: target position = %d, content count = %d\n", rep_control->targetPosition, rep_control->contentCount);
+ }
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_ASQ_OID, reply[i]->oid) == 0) {
+ struct ldb_asq_control *rep_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_asq_control);
+ if (rep_control == NULL) {
+ fprintf(stderr,
+ "Warning ASQ reply OID received "
+ "with no ASQ data\n");
+ continue;
+ }
+
+ /* check the result */
+ if (rep_control->result != 0) {
+ fprintf(stderr, "Warning: ASQ not performed with error: %d\n", rep_control->result);
+ }
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, reply[i]->oid) == 0) {
+ struct ldb_paged_control *rep_control, *req_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_paged_control);
+ if (rep_control == NULL) {
+ fprintf(stderr,
+ "Warning PAGED_RESULTS reply OID "
+ "received with no data\n");
+ continue;
+ }
+
+ if (rep_control->cookie_len == 0) { /* we are done */
+ break;
+ }
+
+ /* more processing required */
+ /* let's fill in the request control with the new cookie */
+
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, request[j]->oid) == 0)
+ break;
+ }
+ /* if there's a reply control we must find a request
+ * control matching it */
+ if (! request[j]) return -1;
+
+ req_control = talloc_get_type(request[j]->data, struct ldb_paged_control);
+
+ if (req_control->cookie)
+ talloc_free(req_control->cookie);
+ req_control->cookie = (char *)talloc_memdup(
+ req_control, rep_control->cookie,
+ rep_control->cookie_len);
+ req_control->cookie_len = rep_control->cookie_len;
+
+ ret = 1;
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_SORT_RESP_OID, reply[i]->oid) == 0) {
+ struct ldb_sort_resp_control *rep_control;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_sort_resp_control);
+ if (rep_control == NULL) {
+ fprintf(stderr,
+ "Warning SORT reply OID "
+ "received with no data\n");
+ continue;
+ }
+
+ /* check we have a matching control in the request */
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_SERVER_SORT_OID, request[j]->oid) == 0)
+ break;
+ }
+ if (! request[j]) {
+ fprintf(stderr, "Warning Server Sort reply received but no request found\n");
+ continue;
+ }
+
+ /* check the result */
+ if (rep_control->result != 0) {
+ fprintf(stderr, "Warning: Sorting not performed with error: %d\n", rep_control->result);
+ }
+
+ continue;
+ }
+
+ if (strcmp(LDB_CONTROL_DIRSYNC_OID, reply[i]->oid) == 0) {
+ struct ldb_dirsync_control *rep_control, *req_control;
+ char *cookie;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control);
+ if (rep_control == NULL) {
+ fprintf(stderr,
+ "Warning DIRSYNC reply OID "
+ "received with no data\n");
+ continue;
+ }
+ if (rep_control->cookie_len == 0) /* we are done */
+ break;
+
+ /* more processing required */
+ /* let's fill in the request control with the new cookie */
+
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_DIRSYNC_OID, request[j]->oid) == 0)
+ break;
+ }
+ /* if there's a reply control we must find a request
+ * control matching it */
+ if (! request[j]) return -1;
+
+ req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control);
+
+ if (req_control->cookie)
+ talloc_free(req_control->cookie);
+ req_control->cookie = (char *)talloc_memdup(
+ req_control, rep_control->cookie,
+ rep_control->cookie_len);
+ req_control->cookie_len = rep_control->cookie_len;
+
+ cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len);
+ printf("# DIRSYNC cookie returned was:\n# %s\n", cookie);
+
+ continue;
+ }
+ if (strcmp(LDB_CONTROL_DIRSYNC_EX_OID, reply[i]->oid) == 0) {
+ struct ldb_dirsync_control *rep_control, *req_control;
+ char *cookie;
+
+ rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control);
+ if (rep_control == NULL) {
+ fprintf(stderr,
+ "Warning DIRSYNC_EX reply OID "
+ "received with no data\n");
+ continue;
+ }
+ if (rep_control->cookie_len == 0) /* we are done */
+ break;
+
+ /* more processing required */
+ /* let's fill in the request control with the new cookie */
+
+ for (j = 0; request[j]; j++) {
+ if (strcmp(LDB_CONTROL_DIRSYNC_EX_OID, request[j]->oid) == 0)
+ break;
+ }
+ /* if there's a reply control we must find a request
+ * control matching it */
+ if (! request[j]) return -1;
+
+ req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control);
+
+ if (req_control->cookie)
+ talloc_free(req_control->cookie);
+ req_control->cookie = (char *)talloc_memdup(
+ req_control, rep_control->cookie,
+ rep_control->cookie_len);
+ req_control->cookie_len = rep_control->cookie_len;
+
+ cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len);
+ printf("# DIRSYNC_EX cookie returned was:\n# %s\n", cookie);
+
+ continue;
+ }
+
+ /* no controls matched, throw a warning */
+ fprintf(stderr, "Unknown reply control oid: %s\n", reply[i]->oid);
+ }
+
+ return ret;
+}
diff --git a/lib/ldb/tools/cmdline.h b/lib/ldb/tools/cmdline.h
new file mode 100644
index 0000000..dbc216a
--- /dev/null
+++ b/lib/ldb/tools/cmdline.h
@@ -0,0 +1,62 @@
+/*
+ ldb database library - command line handling for ldb tools
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <popt.h>
+
+struct ldb_cmdline {
+ const char *url;
+ enum ldb_scope scope;
+ const char *basedn;
+ const char *modules_path;
+ int interactive;
+ int sorted;
+ const char *editor;
+ int verbose;
+ int recursive;
+ int all_records;
+ int nosync;
+ const char **options;
+ int argc;
+ const char **argv;
+ int num_records;
+ int num_searches;
+ const char *sasl_mechanism;
+ const char **controls;
+ int show_binary;
+ int tracing;
+};
+
+struct ldb_cmdline *ldb_cmdline_process_search(struct ldb_context *ldb,
+ int argc, const char **argv,
+ void (*usage)(struct ldb_context *));
+struct ldb_cmdline *ldb_cmdline_process_edit(struct ldb_context *ldb,
+ int argc, const char **argv,
+ void (*usage)(struct ldb_context *));
+struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, int argc,
+ const char **argv,
+ void (*usage)(struct ldb_context *));
+
+
+int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request);
+void ldb_cmdline_help(struct ldb_context *ldb, const char *cmdname, FILE *f);
+
diff --git a/lib/ldb/tools/ldbadd.c b/lib/ldb/tools/ldbadd.c
new file mode 100644
index 0000000..e6cea29
--- /dev/null
+++ b/lib/ldb/tools/ldbadd.c
@@ -0,0 +1,186 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbadd
+ *
+ * Description: utility to add records - modelled on ldapadd
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "replace.h"
+#include "ldb.h"
+#include "tools/cmdline.h"
+#include "ldbutil.h"
+#include "include/ldb_private.h"
+
+static struct ldb_cmdline *options;
+
+static void usage(struct ldb_context *ldb)
+{
+ printf("Usage: ldbadd <options> <ldif...>\n");
+ printf("Adds records to a ldb, reading ldif the specified list of files\n\n");
+ ldb_cmdline_help(ldb, "ldbadd", stdout);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+}
+
+
+/*
+ add records from an opened file
+*/
+static int process_file(struct ldb_context *ldb, FILE *f, unsigned int *count)
+{
+ struct ldb_ldif *ldif;
+ int fun_ret = LDB_SUCCESS, ret;
+ struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ struct ldif_read_file_state state = {
+ .f = f
+ };
+
+ if (options->controls != NULL && req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ fun_ret = ldb_transaction_start(ldb);
+ if (fun_ret != LDB_SUCCESS) {
+ fprintf(stderr, "ERR: (%s) on transaction start\n",
+ ldb_errstring(ldb));
+ return fun_ret;
+ }
+
+ while ((ldif = ldb_ldif_read_file_state(ldb, &state))) {
+ if (ldif->changetype != LDB_CHANGETYPE_ADD &&
+ ldif->changetype != LDB_CHANGETYPE_NONE) {
+ fprintf(stderr, "Only CHANGETYPE_ADD records allowed\n");
+ break;
+ }
+
+ ret = ldb_msg_normalize(ldb, ldif, ldif->msg, &ldif->msg);
+ if (ret != LDB_SUCCESS) {
+ fprintf(stderr,
+ "ERR: Message canonicalize failed - %s\n",
+ ldb_strerror(ret));
+ fun_ret = ret;
+ ldb_ldif_read_free(ldb, ldif);
+ continue;
+ }
+
+ ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls);
+ if (ret != LDB_SUCCESS) {
+ fprintf(stderr, "ERR: %s : \"%s\" on DN %s at block before line %llu\n",
+ ldb_strerror(ret), ldb_errstring(ldb),
+ ldb_dn_get_linearized(ldif->msg->dn),
+ (unsigned long long)state.line_no);
+ fun_ret = ret;
+ } else {
+ (*count)++;
+ if (options->verbose) {
+ printf("Added %s\n", ldb_dn_get_linearized(ldif->msg->dn));
+ }
+ }
+ ldb_ldif_read_free(ldb, ldif);
+ if (ret) {
+ break;
+ }
+ }
+
+ if (fun_ret == LDB_SUCCESS && !feof(f)) {
+ fprintf(stderr, "Failed to parse ldif\n");
+ fun_ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (fun_ret == LDB_SUCCESS) {
+ fun_ret = ldb_transaction_commit(ldb);
+ if (fun_ret != LDB_SUCCESS) {
+ fprintf(stderr, "ERR: (%s) on transaction commit\n",
+ ldb_errstring(ldb));
+ }
+ } else {
+ ldb_transaction_cancel(ldb);
+ }
+
+ return fun_ret;
+}
+
+
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ unsigned int i, count = 0;
+ int ret = LDB_SUCCESS;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ printf("Failed to start transaction: %s\n", ldb_errstring(ldb));
+ return ret;
+ }
+
+ if (options->argc == 0) {
+ ret = process_file(ldb, stdin, &count);
+ } else {
+ for (i=0;i<options->argc;i++) {
+ const char *fname = options->argv[i];
+ FILE *f;
+ f = fopen(fname, "r");
+ if (!f) {
+ perror(fname);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = process_file(ldb, f, &count);
+ fclose(f);
+ }
+ }
+
+ if (count != 0) {
+ ret = ldb_transaction_commit(ldb);
+ if (ret != LDB_SUCCESS) {
+ printf("Failed to commit transaction: %s\n", ldb_errstring(ldb));
+ return ret;
+ }
+ } else {
+ ldb_transaction_cancel(ldb);
+ }
+
+ talloc_free(mem_ctx);
+
+ if (ret) {
+ printf("Add failed after processing %u records\n", count);
+ } else {
+ printf("Added %u records successfully\n", count);
+ }
+
+ return ret;
+}
diff --git a/lib/ldb/tools/ldbdel.c b/lib/ldb/tools/ldbdel.c
new file mode 100644
index 0000000..8036d09
--- /dev/null
+++ b/lib/ldb/tools/ldbdel.c
@@ -0,0 +1,135 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbdel
+ *
+ * Description: utility to delete records - modelled on ldapdelete
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "replace.h"
+#include "ldb.h"
+#include "tools/cmdline.h"
+#include "ldbutil.h"
+
+static int dn_cmp(struct ldb_message **msg1, struct ldb_message **msg2)
+{
+ return ldb_dn_compare((*msg1)->dn, (*msg2)->dn);
+}
+
+static int ldb_delete_recursive(struct ldb_context *ldb, struct ldb_dn *dn,struct ldb_control **req_ctrls)
+{
+ int ret;
+ unsigned int i, total=0;
+ const char *attrs[] = { NULL };
+ struct ldb_result *res;
+
+ ret = ldb_search(ldb, ldb, &res, dn, LDB_SCOPE_SUBTREE, attrs, "distinguishedName=*");
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* sort the DNs, deepest first */
+ TYPESAFE_QSORT(res->msgs, res->count, dn_cmp);
+
+ for (i = 0; i < res->count; i++) {
+ if (ldb_delete_ctrl(ldb, res->msgs[i]->dn,req_ctrls) == LDB_SUCCESS) {
+ total++;
+ } else {
+ printf("Failed to delete '%s' - %s\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn),
+ ldb_errstring(ldb));
+ }
+ }
+
+ talloc_free(res);
+
+ if (total == 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ printf("Deleted %u records\n", total);
+ return LDB_SUCCESS;
+}
+
+static void usage(struct ldb_context *ldb)
+{
+ printf("Usage: ldbdel <options> <DN...>\n");
+ printf("Deletes records from a ldb\n\n");
+ ldb_cmdline_help(ldb, "ldbdel", stdout);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_control **req_ctrls;
+ struct ldb_cmdline *options;
+ struct ldb_context *ldb;
+ int ret = 0, i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->argc < 1) {
+ usage(ldb);
+ }
+
+ req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ if (options->controls != NULL && req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i=0;i<options->argc;i++) {
+ struct ldb_dn *dn;
+
+ dn = ldb_dn_new(ldb, ldb, options->argv[i]);
+ if (dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (options->recursive) {
+ ret = ldb_delete_recursive(ldb, dn,req_ctrls);
+ } else {
+ ret = ldb_delete_ctrl(ldb, dn,req_ctrls);
+ if (ret == LDB_SUCCESS) {
+ printf("Deleted 1 record\n");
+ }
+ }
+ if (ret != LDB_SUCCESS) {
+ printf("delete of '%s' failed - (%s) %s\n",
+ ldb_dn_get_linearized(dn),
+ ldb_strerror(ret),
+ ldb_errstring(ldb));
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/lib/ldb/tools/ldbdump.c b/lib/ldb/tools/ldbdump.c
new file mode 100644
index 0000000..5cdb7d8
--- /dev/null
+++ b/lib/ldb/tools/ldbdump.c
@@ -0,0 +1,383 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple ldb tdb dump util
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include <tdb.h>
+#include <ldb.h>
+#include <ldb_private.h>
+
+#ifdef HAVE_LMDB
+#include <lmdb.h>
+#endif /* ifdef HAVE_LMDB */
+
+
+static struct ldb_context *ldb;
+bool show_index = false;
+bool validate_contents = false;
+
+static void print_data(TDB_DATA d)
+{
+ unsigned char *p = (unsigned char *)d.dptr;
+ int len = d.dsize;
+ while (len--) {
+ if (isprint(*p) && !strchr("\"\\", *p)) {
+ fputc(*p, stdout);
+ } else {
+ printf("\\%02X", *p);
+ }
+ p++;
+ }
+}
+
+static unsigned int pull_uint32(uint8_t *p)
+{
+ return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+}
+
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA _dbuf, void *state)
+{
+ int ret, i, j;
+ struct ldb_dn *dn = state;
+ struct ldb_message *msg = ldb_msg_new(NULL);
+ struct ldb_val dbuf = {
+ .data = _dbuf.dptr,
+ .length = _dbuf.dsize,
+ };
+ struct ldb_ldif ldif = {
+ .msg = msg,
+ .changetype = LDB_CHANGETYPE_NONE
+ };
+ if (!msg) {
+ return -1;
+ }
+
+ ret = ldb_unpack_data(ldb, &dbuf, msg);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to parse record %*.*s as an LDB record\n", (int)key.dsize, (int)key.dsize, (char *)key.dptr);
+ TALLOC_FREE(msg);
+ return 0;
+ }
+
+ if (dn && ldb_dn_compare(msg->dn, dn) != 0) {
+ TALLOC_FREE(msg);
+ return 0;
+ }
+
+ if (!show_index && ldb_dn_is_special(msg->dn)) {
+ const char *dn_lin = ldb_dn_get_linearized(msg->dn);
+ if ((strcmp(dn_lin, "@BASEINFO") == 0) || (strncmp(dn_lin, "@INDEX:", strlen("@INDEX:")) == 0)) {
+ /*
+ the user has asked not to show index
+ records. Also exclude BASEINFO as it
+ contains meta-data which will be re-created
+ if this database is restored
+ */
+ TALLOC_FREE(msg);
+ return 0;
+ }
+ }
+
+ printf("# key: ");
+ print_data(key);
+ printf("\n# pack format: %#010x\n", pull_uint32(_dbuf.dptr));
+
+ if (!validate_contents || ldb_dn_is_special(msg->dn)) {
+ ldb_ldif_write_file(ldb, stdout, &ldif);
+ TALLOC_FREE(msg);
+ return 0;
+ }
+
+ for (i=0;i<msg->num_elements;i++) {
+ const struct ldb_schema_attribute *a;
+
+ a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
+ for (j=0;j<msg->elements[i].num_values;j++) {
+ struct ldb_val v;
+ ret = a->syntax->ldif_write_fn(ldb, msg, &msg->elements[i].values[j], &v);
+ if (ret != 0) {
+ v = msg->elements[i].values[j];
+ if (ldb_should_b64_encode(ldb, &v)) {
+ v.data = (uint8_t *)ldb_base64_encode(ldb, (char *)v.data, v.length);
+ v.length = strlen((char *)v.data);
+ }
+ fprintf(stderr, "On %s element %s value %d (%*.*s) failed to convert to LDIF correctly, skipping possibly corrupt record\n",
+ ldb_dn_get_linearized(msg->dn),
+ msg->elements[i].name,
+ j, (int)v.length, (int)v.length,
+ v.data);
+ TALLOC_FREE(msg);
+ return 0;
+ }
+ }
+ }
+ ldb_ldif_write_file(ldb, stdout, &ldif);
+ TALLOC_FREE(msg);
+
+ return 0;
+}
+
+static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ const char *name = tdb_name(tdb);
+ const char *prefix = "";
+
+ if (!name)
+ name = "unnamed";
+
+ switch (level) {
+ case TDB_DEBUG_ERROR:
+ prefix = "ERROR: ";
+ break;
+ case TDB_DEBUG_WARNING:
+ prefix = "WARNING: ";
+ break;
+ case TDB_DEBUG_TRACE:
+ return;
+
+ default:
+ case TDB_DEBUG_FATAL:
+ prefix = "FATAL: ";
+ break;
+ }
+
+ va_start(ap, fmt);
+ fprintf(stderr, "tdb(%s): %s", name, prefix);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname)
+{
+ traverse_fn(NULL, key, dbuf, keyname);
+}
+
+static int dump_tdb(const char *fname, struct ldb_dn *dn, bool emergency)
+{
+ TDB_CONTEXT *tdb;
+ struct tdb_logging_context logfn = {
+ .log_fn = log_stderr,
+ };
+
+ tdb = tdb_open_ex(fname, 0, 0, O_RDONLY, 0, &logfn, NULL);
+ if (!tdb) {
+ fprintf(stderr, "Failed to open %s\n", fname);
+ return 1;
+ }
+
+ if (emergency) {
+ return tdb_rescue(tdb, emergency_walk, dn) == 0;
+ }
+ return tdb_traverse(tdb, traverse_fn, dn) == -1 ? 1 : 0;
+}
+
+#ifdef HAVE_LMDB
+static int dump_lmdb(const char *fname, struct ldb_dn *dn, bool emergency)
+{
+ int ret;
+ struct MDB_env *env = NULL;
+ struct MDB_txn *txn = NULL;
+ MDB_dbi dbi;
+ struct MDB_cursor *cursor = NULL;
+ struct MDB_val key;
+ struct MDB_val data;
+
+ ret = mdb_env_create(&env);
+ if (ret != 0) {
+ fprintf(stderr,
+ "Could not create MDB environment: (%d) %s\n",
+ ret,
+ mdb_strerror(ret));
+ goto close_env;
+ }
+
+ ret = mdb_env_open(env,
+ fname,
+ MDB_NOSUBDIR|MDB_NOTLS|MDB_RDONLY,
+ 0600);
+ if (ret != 0) {
+ fprintf(stderr,
+ "Could not open environment for %s: (%d) %s\n",
+ fname,
+ ret,
+ mdb_strerror(ret));
+ goto close_env;
+ }
+
+ ret = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
+ if (ret != 0) {
+ fprintf(stderr,
+ "Could not start transaction: (%d) %s\n",
+ ret,
+ mdb_strerror(ret));
+ goto close_env;
+ }
+
+ ret = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (ret != 0) {
+ fprintf(stderr,
+ "Could not open database: (%d) %s\n",
+ ret,
+ mdb_strerror(ret));
+ goto close_txn;
+ }
+
+ ret = mdb_cursor_open(txn, dbi, &cursor);
+ if (ret != 0) {
+ fprintf(stderr,
+ "Could not open cursor: (%d) %s\n",
+ ret,
+ mdb_strerror(ret));
+ goto close_txn;
+ }
+
+ ret = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
+ if (ret != 0 && ret != MDB_NOTFOUND) {
+ fprintf(stderr,
+ "Could not find first record: (%d) %s\n",
+ ret,
+ mdb_strerror(ret));
+ goto close_cursor;
+ }
+ while (ret != MDB_NOTFOUND) {
+ struct TDB_DATA tkey = {
+ .dptr = key.mv_data,
+ .dsize = key.mv_size
+ };
+ struct TDB_DATA tdata = {
+ .dptr = data.mv_data,
+ .dsize = data.mv_size
+ };
+ traverse_fn(NULL, tkey, tdata, dn);
+ ret = mdb_cursor_get(cursor, &key, &data, MDB_NEXT);
+ if (ret != 0 && ret != MDB_NOTFOUND) {
+ fprintf(stderr,
+ "Could not read next record: (%d) %s\n",
+ ret,
+ mdb_strerror(ret));
+ goto close_cursor;
+ }
+ }
+ ret = 0;
+
+close_cursor:
+ mdb_cursor_close(cursor);
+close_txn:
+ mdb_txn_commit(txn);
+close_env:
+ mdb_env_close(env);
+
+ if (ret != 0) {
+ return 1;
+ }
+ return 0;
+
+}
+#else
+static int dump_lmdb(const char *fname, struct ldb_dn *dn, bool emergency)
+{
+ /* not built with lmdb support */
+ return 1;
+}
+#endif /* #ifdef HAVE_LMDB */
+
+static void usage( void)
+{
+ printf( "Usage: ldbdump [options] <filename>\n\n");
+ printf( " -h this help message\n");
+ printf( " -d DN dumps DN only\n");
+ printf( " -e emergency dump, for corrupt databases\n");
+ printf( " -i include index and @BASEINFO records in dump\n");
+ printf( " -c validate contents of the records\n");
+}
+
+ int main(int argc, char *argv[])
+{
+ bool emergency = false;
+ int c, rc;
+ char *fname;
+ struct ldb_dn *dn = NULL;
+
+ ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ fprintf(stderr, "ldb: ldb_init failed()");
+ exit(1);
+ }
+
+ rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_PRECONNECT);
+ if (rc != LDB_SUCCESS) {
+ fprintf(stderr, "ldb: failed to run preconnect hooks (needed to get Samba LDIF handlers): %s\n", ldb_strerror(rc));
+ exit(1);
+ }
+
+ if (argc < 2) {
+ printf("Usage: ldbdump <fname>\n");
+ exit(1);
+ }
+
+ while ((c = getopt( argc, argv, "hd:eic")) != -1) {
+ switch (c) {
+ case 'h':
+ usage();
+ exit( 0);
+ case 'd':
+ dn = ldb_dn_new(ldb, ldb, optarg);
+ if (!dn) {
+ fprintf(stderr, "ldb failed to parse %s as a DN\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'e':
+ emergency = true;
+ break;
+ case 'i':
+ show_index = true;
+ break;
+ case 'c':
+ validate_contents = true;
+ break;
+ default:
+ usage();
+ exit( 1);
+ }
+ }
+
+ fname = argv[optind];
+
+ rc = dump_lmdb(fname, dn, emergency);
+ if (rc != 0) {
+ rc = dump_tdb(fname, dn, emergency);
+ if (rc != 0) {
+ fprintf(stderr, "Failed to open %s\n", fname);
+ return 1;
+ }
+ }
+ return 0;
+
+}
diff --git a/lib/ldb/tools/ldbedit.c b/lib/ldb/tools/ldbedit.c
new file mode 100644
index 0000000..497ef97
--- /dev/null
+++ b/lib/ldb/tools/ldbedit.c
@@ -0,0 +1,383 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbedit
+ *
+ * Description: utility for ldb database editing
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "ldb.h"
+#include "tools/cmdline.h"
+#include "tools/ldbutil.h"
+
+static struct ldb_cmdline *options;
+
+/*
+ debug routine
+*/
+static void ldif_write_msg(struct ldb_context *ldb,
+ FILE *f,
+ enum ldb_changetype changetype,
+ struct ldb_message *msg)
+{
+ struct ldb_ldif ldif;
+ ldif.changetype = changetype;
+ ldif.msg = msg;
+ ldb_ldif_write_file(ldb, f, &ldif);
+}
+
+/*
+ modify a database record so msg1 becomes msg2
+ returns the number of modified elements
+*/
+static int modify_record(struct ldb_context *ldb,
+ struct ldb_message *msg1,
+ struct ldb_message *msg2,
+ struct ldb_control **req_ctrls)
+{
+ int ret;
+ struct ldb_message *mod;
+
+ if (ldb_msg_difference(ldb, ldb, msg1, msg2, &mod) != LDB_SUCCESS) {
+ fprintf(stderr, "Failed to calculate message differences\n");
+ return -1;
+ }
+
+ ret = mod->num_elements;
+ if (ret == 0) {
+ goto done;
+ }
+
+ if (options->verbose > 0) {
+ ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod);
+ }
+
+ if (ldb_modify_ctrl(ldb, mod, req_ctrls) != LDB_SUCCESS) {
+ fprintf(stderr, "failed to modify %s - %s\n",
+ ldb_dn_get_linearized(msg1->dn), ldb_errstring(ldb));
+ ret = -1;
+ goto done;
+ }
+
+done:
+ talloc_free(mod);
+ return ret;
+}
+
+/*
+ find dn in msgs[]
+*/
+static struct ldb_message *msg_find(struct ldb_context *ldb,
+ struct ldb_message **msgs,
+ unsigned int count,
+ struct ldb_dn *dn)
+{
+ unsigned int i;
+ for (i=0;i<count;i++) {
+ if (ldb_dn_compare(dn, msgs[i]->dn) == 0) {
+ return msgs[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ merge the changes in msgs2 into the messages from msgs1
+*/
+static int merge_edits(struct ldb_context *ldb,
+ struct ldb_message **msgs1, unsigned int count1,
+ struct ldb_message **msgs2, unsigned int count2)
+{
+ unsigned int i;
+ struct ldb_message *msg;
+ int ret;
+ unsigned int adds=0, modifies=0, deletes=0;
+ struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ if (options->controls != NULL && req_ctrls == NULL) {
+ fprintf(stderr, "parsing controls failed: %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
+ if (ldb_transaction_start(ldb) != LDB_SUCCESS) {
+ fprintf(stderr, "Failed to start transaction: %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
+ /* do the adds and modifies */
+ for (i=0;i<count2;i++) {
+ msg = msg_find(ldb, msgs1, count1, msgs2[i]->dn);
+ if (!msg) {
+ if (options->verbose > 0) {
+ ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_ADD, msgs2[i]);
+ }
+ if (ldb_add_ctrl(ldb, msgs2[i], req_ctrls) != LDB_SUCCESS) {
+ fprintf(stderr, "failed to add %s - %s\n",
+ ldb_dn_get_linearized(msgs2[i]->dn),
+ ldb_errstring(ldb));
+ ldb_transaction_cancel(ldb);
+ return -1;
+ }
+ adds++;
+ } else {
+ ret = modify_record(ldb, msg, msgs2[i], req_ctrls);
+ if (ret != -1) {
+ modifies += (unsigned int) ret;
+ } else {
+ ldb_transaction_cancel(ldb);
+ return -1;
+ }
+ }
+ }
+
+ /* do the deletes */
+ for (i=0;i<count1;i++) {
+ msg = msg_find(ldb, msgs2, count2, msgs1[i]->dn);
+ if (!msg) {
+ if (options->verbose > 0) {
+ ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_DELETE, msgs1[i]);
+ }
+ if (ldb_delete_ctrl(ldb, msgs1[i]->dn, req_ctrls) != LDB_SUCCESS) {
+ fprintf(stderr, "failed to delete %s - %s\n",
+ ldb_dn_get_linearized(msgs1[i]->dn),
+ ldb_errstring(ldb));
+ ldb_transaction_cancel(ldb);
+ return -1;
+ }
+ deletes++;
+ }
+ }
+
+ if (ldb_transaction_commit(ldb) != LDB_SUCCESS) {
+ fprintf(stderr, "Failed to commit transaction: %s\n", ldb_errstring(ldb));
+ return -1;
+ }
+
+ printf("# %u adds %u modifies %u deletes\n", adds, modifies, deletes);
+
+ return 0;
+}
+
+/*
+ save a set of messages as ldif to a file
+*/
+static int save_ldif(struct ldb_context *ldb,
+ FILE *f, struct ldb_message **msgs, unsigned int count)
+{
+ unsigned int i;
+
+ fprintf(f, "# editing %u records\n", count);
+
+ for (i=0;i<count;i++) {
+ struct ldb_ldif ldif;
+ fprintf(f, "# record %u\n", i+1);
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = msgs[i];
+
+ ldb_ldif_write_file(ldb, f, &ldif);
+ }
+
+ return 0;
+}
+
+
+/*
+ edit the ldb search results in msgs using the user selected editor
+*/
+static int do_edit(struct ldb_context *ldb, struct ldb_message **msgs1,
+ unsigned int count1, const char *editor)
+{
+ int fd, ret;
+ FILE *f;
+ char file_template[] = "/tmp/ldbedit.XXXXXX";
+ char *cmd;
+ struct ldb_ldif *ldif;
+ struct ldb_message **msgs2 = NULL;
+ unsigned int count2 = 0;
+
+ /* write out the original set of messages to a temporary
+ file */
+ fd = mkstemp(file_template);
+
+ if (fd == -1) {
+ perror(file_template);
+ return -1;
+ }
+
+ f = fdopen(fd, "r+");
+
+ if (!f) {
+ perror("fopen");
+ close(fd);
+ unlink(file_template);
+ return -1;
+ }
+
+ if (save_ldif(ldb, f, msgs1, count1) != 0) {
+ return -1;
+ }
+
+ fclose(f);
+
+ cmd = talloc_asprintf(ldb, "%s %s", editor, file_template);
+
+ if (!cmd) {
+ unlink(file_template);
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+
+ /* run the editor */
+ ret = system(cmd);
+ talloc_free(cmd);
+
+ if (ret != 0) {
+ unlink(file_template);
+ fprintf(stderr, "edit with %s failed\n", editor);
+ return -1;
+ }
+
+ /* read the resulting ldif into msgs2 */
+ f = fopen(file_template, "r");
+ if (!f) {
+ perror(file_template);
+ return -1;
+ }
+
+ while ((ldif = ldb_ldif_read_file(ldb, f))) {
+ msgs2 = talloc_realloc(ldb, msgs2, struct ldb_message *, count2+1);
+ if (!msgs2) {
+ fprintf(stderr, "out of memory");
+ return -1;
+ }
+ msgs2[count2++] = ldif->msg;
+ }
+
+ /* the feof() test works here, even for the last line of the
+ * file, as we parse ldif files character by character, and
+ * feof() is only true if we have failed to read a character
+ * from the file. So if the last line is bad, we don't get
+ * feof() set, so we know the record was bad. Only if we
+ * attempt to go to the next record will we get feof() and
+ * thus consider that the ldif has ended without errors
+ */
+ if (!feof(f)) {
+ fprintf(stderr, "Error parsing ldif - aborting\n");
+ fclose(f);
+ unlink(file_template);
+ return -1;
+ }
+
+ fclose(f);
+ unlink(file_template);
+
+ return merge_edits(ldb, msgs1, count1, msgs2, count2);
+}
+
+static void usage(struct ldb_context *ldb)
+{
+ printf("Usage: ldbedit <options> <expression> <attributes ...>\n");
+ ldb_cmdline_help(ldb, "ldbedit", stdout);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ struct ldb_result *result = NULL;
+ struct ldb_dn *basedn = NULL;
+ int ret;
+ const char *expression = "(|(objectClass=*)(distinguishedName=*))";
+ const char * const * attrs = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct ldb_control **req_ctrls;
+ unsigned int i;
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ options = ldb_cmdline_process_edit(ldb, argc, argv, usage);
+
+ /* the check for '=' is for compatibility with ldapsearch */
+ if (options->argc > 0 &&
+ strchr(options->argv[0], '=')) {
+ expression = options->argv[0];
+ options->argv++;
+ options->argc--;
+ }
+
+ if (options->argc > 0) {
+ attrs = (const char * const *)(options->argv);
+ }
+
+ if (options->basedn != NULL) {
+ basedn = ldb_dn_new(ldb, ldb, options->basedn);
+ if (basedn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ for (i = 0; options->controls != NULL && options->controls[i] != NULL; i++) {
+ if (strncmp(options->controls[i], "reveal_internals:", 17) == 0) {
+ printf("Using reveal internals has unintended consequences.\n");
+ printf("If this is your intent, manually perform the search,"
+ " and use ldbmodify directly.\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ if (options->controls != NULL && req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_search_ctrl(ldb, ldb, &result, basedn, options->scope, attrs, req_ctrls, "%s", expression);
+ if (ret != LDB_SUCCESS) {
+ printf("search failed - %s\n", ldb_errstring(ldb));
+ return ret;
+ }
+
+ if (result->count == 0) {
+ printf("no matching records - cannot edit\n");
+ talloc_free(mem_ctx);
+ return LDB_SUCCESS;
+ }
+
+ ret = do_edit(ldb, result->msgs, result->count, options->editor);
+
+ talloc_free(mem_ctx);
+
+ return ret == 0 ? LDB_SUCCESS : LDB_ERR_OPERATIONS_ERROR;
+}
diff --git a/lib/ldb/tools/ldbmodify.c b/lib/ldb/tools/ldbmodify.c
new file mode 100644
index 0000000..2eb8bcc
--- /dev/null
+++ b/lib/ldb/tools/ldbmodify.c
@@ -0,0 +1,190 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbmodify
+ *
+ * Description: utility to modify records - modelled on ldapmodify
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "replace.h"
+#include "ldb.h"
+#include "tools/cmdline.h"
+#include "ldbutil.h"
+#include "include/ldb_private.h"
+
+static struct ldb_cmdline *options;
+
+static void usage(struct ldb_context *ldb)
+{
+ printf("Usage: ldbmodify <options> <ldif...>\n");
+ printf("Modifies a ldb based upon ldif change records\n\n");
+ ldb_cmdline_help(ldb, "ldbmodify", stdout);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+}
+
+/*
+ process modifies for one file
+*/
+static int process_file(struct ldb_context *ldb, FILE *f, unsigned int *count)
+{
+ struct ldb_ldif *ldif;
+ int fun_ret = LDB_SUCCESS, ret;
+ struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
+ struct ldif_read_file_state state = {
+ .f = f
+ };
+
+ if (options->controls != NULL && req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ fun_ret = ldb_transaction_start(ldb);
+ if (fun_ret != LDB_SUCCESS) {
+ fprintf(stderr, "ERR: (%s) on transaction start\n",
+ ldb_errstring(ldb));
+ return fun_ret;
+ }
+
+ while ((ldif = ldb_ldif_read_file_state(ldb, &state))) {
+ struct ldb_dn *olddn;
+ bool deleteoldrdn = false;
+ struct ldb_dn *newdn;
+ const char *errstr = NULL;
+
+ switch (ldif->changetype) {
+ case LDB_CHANGETYPE_NONE:
+ case LDB_CHANGETYPE_ADD:
+ ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls);
+ break;
+ case LDB_CHANGETYPE_DELETE:
+ ret = ldb_delete_ctrl(ldb, ldif->msg->dn,req_ctrls);
+ break;
+ case LDB_CHANGETYPE_MODIFY:
+ ret = ldb_modify_ctrl(ldb, ldif->msg,req_ctrls);
+ break;
+ case LDB_CHANGETYPE_MODRDN:
+ ret = ldb_ldif_parse_modrdn(ldb, ldif, ldif, &olddn,
+ NULL, &deleteoldrdn,
+ NULL, &newdn);
+ if (ret == LDB_SUCCESS) {
+ if (deleteoldrdn) {
+ ret = ldb_rename(ldb, olddn, newdn);
+ } else {
+ errstr = "modrdn: deleteoldrdn=0 "
+ "not supported.";
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ }
+ break;
+ default:
+ ret = LDB_ERR_PROTOCOL_ERROR;
+ break;
+ }
+ if (ret != LDB_SUCCESS) {
+ if (errstr == NULL) {
+ errstr = ldb_errstring(ldb);
+ }
+ fprintf(stderr,
+ "ERR: (%s) \"%s\" on DN %s at block before "
+ "line %zu\n",
+ ldb_strerror(ret),
+ errstr,
+ ldb_dn_get_linearized(ldif->msg->dn),
+ state.line_no);
+ fun_ret = ret;
+ } else {
+ (*count)++;
+ if (options->verbose) {
+ printf("Modified %s\n", ldb_dn_get_linearized(ldif->msg->dn));
+ }
+ }
+ ldb_ldif_read_free(ldb, ldif);
+ if (ret) {
+ break;
+ }
+ }
+
+ if (fun_ret == LDB_SUCCESS && !feof(f)) {
+ fprintf(stderr, "Failed to parse ldif\n");
+ fun_ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (fun_ret == LDB_SUCCESS) {
+ fun_ret = ldb_transaction_commit(ldb);
+ if (fun_ret != LDB_SUCCESS) {
+ fprintf(stderr, "ERR: (%s) on transaction commit\n",
+ ldb_errstring(ldb));
+ }
+ } else {
+ ldb_transaction_cancel(ldb);
+ }
+
+ return fun_ret;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ unsigned int i, count = 0;
+ int ret = LDB_SUCCESS;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->argc == 0) {
+ ret = process_file(ldb, stdin, &count);
+ } else {
+ for (i=0;i<options->argc;i++) {
+ const char *fname = options->argv[i];
+ FILE *f;
+ f = fopen(fname, "r");
+ if (!f) {
+ perror(fname);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = process_file(ldb, f, &count);
+ fclose(f);
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ if (ret) {
+ printf("Modify failed after processing %u records\n", count);
+ } else {
+ printf("Modified %u records successfully\n", count);
+ }
+
+ return ret;
+}
diff --git a/lib/ldb/tools/ldbrename.c b/lib/ldb/tools/ldbrename.c
new file mode 100644
index 0000000..ab2be4d
--- /dev/null
+++ b/lib/ldb/tools/ldbrename.c
@@ -0,0 +1,85 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbrename
+ *
+ * Description: utility to rename records - modelled on ldapmodrdn
+ *
+ * Author: Andrew Tridgell
+ * Author: Stefan Metzmacher
+ */
+
+#include "replace.h"
+#include "ldb.h"
+#include "tools/cmdline.h"
+
+static void usage(struct ldb_context *ldb)
+{
+ printf("Usage: ldbrename [<options>] <olddn> <newdn>\n");
+ printf("Renames records in a ldb\n\n");
+ ldb_cmdline_help(ldb, "ldbmodify", stdout);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+}
+
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ int ret;
+ struct ldb_cmdline *options;
+ struct ldb_dn *dn1, *dn2;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ if (options->argc < 2) {
+ usage(ldb);
+ }
+
+ dn1 = ldb_dn_new(ldb, ldb, options->argv[0]);
+ dn2 = ldb_dn_new(ldb, ldb, options->argv[1]);
+ if ((dn1 == NULL) || (dn2 == NULL)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_rename(ldb, dn1, dn2);
+ if (ret == LDB_SUCCESS) {
+ printf("Renamed 1 record\n");
+ } else {
+ printf("rename of '%s' to '%s' failed - %s\n",
+ options->argv[0], options->argv[1], ldb_errstring(ldb));
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/lib/ldb/tools/ldbsearch.c b/lib/ldb/tools/ldbsearch.c
new file mode 100644
index 0000000..374f240
--- /dev/null
+++ b/lib/ldb/tools/ldbsearch.c
@@ -0,0 +1,342 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbsearch
+ *
+ * Description: utility for ldb search - modelled on ldapsearch
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb.h"
+#include "tools/cmdline.h"
+
+static void usage(struct ldb_context *ldb)
+{
+ printf("Usage: ldbsearch <options> <expression> <attrs...>\n");
+ ldb_cmdline_help(ldb, "ldbsearch", stdout);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+}
+
+static int do_compare_msg(struct ldb_message **el1,
+ struct ldb_message **el2,
+ void *opaque)
+{
+ return ldb_dn_compare((*el1)->dn, (*el2)->dn);
+}
+
+struct search_context {
+ struct ldb_context *ldb;
+ struct ldb_control **req_ctrls;
+
+ int sort;
+ unsigned int num_stored;
+ struct ldb_message **store;
+ unsigned int refs_stored;
+ char **refs_store;
+
+ unsigned int entries;
+ unsigned int refs;
+
+ unsigned int pending;
+ int status;
+};
+
+static int store_message(struct ldb_message *msg, struct search_context *sctx) {
+
+ sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2);
+ if (!sctx->store) {
+ fprintf(stderr, "talloc_realloc failed while storing messages\n");
+ return -1;
+ }
+
+ sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg);
+ sctx->num_stored++;
+ sctx->store[sctx->num_stored] = NULL;
+
+ return 0;
+}
+
+static int store_referral(char *referral, struct search_context *sctx) {
+
+ sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2);
+ if (!sctx->refs_store) {
+ fprintf(stderr, "talloc_realloc failed while storing referrals\n");
+ return -1;
+ }
+
+ sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral);
+ sctx->refs_stored++;
+ sctx->refs_store[sctx->refs_stored] = NULL;
+
+ return 0;
+}
+
+static int display_message(struct ldb_message *msg, struct search_context *sctx) {
+ struct ldb_ldif ldif;
+
+ sctx->entries++;
+ printf("# record %d\n", sctx->entries);
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = msg;
+
+ if (sctx->sort) {
+ /*
+ * Ensure attributes are always returned in the same
+ * order. For testing, this makes comparison of old
+ * vs. new much easier.
+ */
+ ldb_msg_sort_elements(ldif.msg);
+ }
+
+ ldb_ldif_write_file(sctx->ldb, stdout, &ldif);
+
+ return 0;
+}
+
+static int display_referral(char *referral, struct search_context *sctx)
+{
+
+ sctx->refs++;
+ printf("# Referral\nref: %s\n\n", referral);
+
+ return 0;
+}
+
+static int search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct search_context *sctx;
+ int ret = LDB_SUCCESS;
+
+ sctx = talloc_get_type(req->context, struct search_context);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (sctx->sort) {
+ ret = store_message(ares->message, sctx);
+ } else {
+ ret = display_message(ares->message, sctx);
+ }
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ if (sctx->sort) {
+ ret = store_referral(ares->referral, sctx);
+ } else {
+ ret = display_referral(ares->referral, sctx);
+ }
+ if (ret) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ break;
+
+ case LDB_REPLY_DONE:
+ if (ares->controls) {
+ if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1)
+ sctx->pending = 1;
+ }
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ talloc_free(ares);
+ if (ret != LDB_SUCCESS) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int do_search(struct ldb_context *ldb,
+ struct ldb_dn *basedn,
+ struct ldb_cmdline *options,
+ const char *expression,
+ const char * const *attrs)
+{
+ struct ldb_request *req;
+ struct search_context *sctx;
+ int ret;
+
+ req = NULL;
+
+ sctx = talloc_zero(ldb, struct search_context);
+ if (!sctx) return LDB_ERR_OPERATIONS_ERROR;
+
+ sctx->ldb = ldb;
+ sctx->sort = options->sorted;
+ sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls);
+ if (options->controls != NULL && sctx->req_ctrls== NULL) {
+ printf("parsing controls failed: %s\n", ldb_errstring(ldb));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+again:
+ /* free any previous requests */
+ if (req) talloc_free(req);
+
+ ret = ldb_build_search_req(&req, ldb, ldb,
+ basedn, options->scope,
+ expression, attrs,
+ sctx->req_ctrls,
+ sctx, search_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(sctx);
+ printf("allocating request failed: %s\n", ldb_errstring(ldb));
+ return ret;
+ }
+
+ if (basedn == NULL) {
+ /*
+ we need to use a NULL base DN when doing a cross-ncs
+ search so we find results on all partitions in a
+ forest. When doing a domain-local search, default to
+ the default basedn
+ */
+ struct ldb_control *ctrl;
+ struct ldb_search_options_control *search_options = NULL;
+
+ ctrl = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
+ if (ctrl) {
+ search_options = talloc_get_type(ctrl->data, struct ldb_search_options_control);
+ }
+
+ if (ctrl == NULL || search_options == NULL ||
+ !(search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {
+ struct ldb_dn *base = ldb_get_default_basedn(ldb);
+ if (base != NULL) {
+ req->op.search.base = base;
+ }
+ }
+ }
+
+ sctx->pending = 0;
+
+ ret = ldb_request(ldb, req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(sctx);
+ talloc_free(req);
+ printf("search failed - %s\n", ldb_errstring(ldb));
+ return ret;
+ }
+
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(sctx);
+ talloc_free(req);
+ printf("search error - %s\n", ldb_errstring(ldb));
+ return ret;
+ }
+
+ if (sctx->pending)
+ goto again;
+
+ if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) {
+ unsigned int i;
+
+ if (sctx->num_stored) {
+ LDB_TYPESAFE_QSORT(sctx->store, sctx->num_stored, ldb, do_compare_msg);
+ }
+ for (i = 0; i < sctx->num_stored; i++) {
+ display_message(sctx->store[i], sctx);
+ }
+
+ for (i = 0; i < sctx->refs_stored; i++) {
+ display_referral(sctx->refs_store[i], sctx);
+ }
+ }
+
+ printf("# returned %u records\n# %u entries\n# %u referrals\n",
+ sctx->entries + sctx->refs, sctx->entries, sctx->refs);
+
+ talloc_free(sctx);
+ talloc_free(req);
+
+ return LDB_SUCCESS;
+}
+
+int main(int argc, const char **argv)
+{
+ struct ldb_context *ldb;
+ struct ldb_dn *basedn = NULL;
+ const char * const * attrs = NULL;
+ struct ldb_cmdline *options;
+ int ret = -1;
+ const char *expression = "(|(objectClass=*)(distinguishedName=*))";
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ options = ldb_cmdline_process_search(ldb, argc, argv, usage);
+
+ /* the check for '=' is for compatibility with ldapsearch */
+ if (!options->interactive &&
+ options->argc > 0 &&
+ strpbrk(options->argv[0], "=<>~:")) {
+ expression = options->argv[0];
+ options->argv++;
+ options->argc--;
+ }
+
+ if (options->argc > 0) {
+ attrs = (const char * const *)(options->argv);
+ }
+
+ if (options->basedn != NULL) {
+ basedn = ldb_dn_new(ldb, ldb, options->basedn);
+ if (basedn == NULL) {
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ if (options->interactive) {
+ char line[1024];
+ while (fgets(line, sizeof(line), stdin)) {
+ ret = do_search(ldb, basedn, options, line, attrs);
+ }
+ } else {
+ ret = do_search(ldb, basedn, options, expression, attrs);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/lib/ldb/tools/ldbtest.c b/lib/ldb/tools/ldbtest.c
new file mode 100644
index 0000000..64b6baa
--- /dev/null
+++ b/lib/ldb/tools/ldbtest.c
@@ -0,0 +1,438 @@
+/*
+ ldb database library
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldbtest
+ *
+ * Description: utility to test ldb
+ *
+ * Author: Andrew Tridgell
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "ldb.h"
+#include "tools/cmdline.h"
+
+static struct timespec tp1,tp2;
+static struct ldb_cmdline *options;
+
+static void _start_timer(void)
+{
+ if (clock_gettime(CUSTOM_CLOCK_MONOTONIC, &tp1) != 0) {
+ clock_gettime(CLOCK_REALTIME, &tp1);
+ }
+}
+
+static double _end_timer(void)
+{
+ if (clock_gettime(CUSTOM_CLOCK_MONOTONIC, &tp2) != 0) {
+ clock_gettime(CLOCK_REALTIME, &tp2);
+ }
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_nsec - tp1.tv_nsec)*1.0e-9);
+}
+
+static void add_records(struct ldb_context *ldb,
+ struct ldb_dn *basedn,
+ unsigned int count)
+{
+ struct ldb_message msg = {0};
+ unsigned int i;
+
+#if 0
+ if (ldb_lock(ldb, "transaction") != 0) {
+ printf("transaction lock failed\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+#endif
+ for (i=0;i<count;i++) {
+ struct ldb_message_element el[6];
+ struct ldb_val vals[6][1];
+ char *name;
+ TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+
+ name = talloc_asprintf(tmp_ctx, "Test%d", i);
+
+ msg.dn = ldb_dn_copy(tmp_ctx, basedn);
+ ldb_dn_add_child_fmt(msg.dn, "cn=%s", name);
+ msg.num_elements = 6;
+ msg.elements = el;
+
+ el[0].flags = 0;
+ el[0].name = talloc_strdup(tmp_ctx, "cn");
+ el[0].num_values = 1;
+ el[0].values = vals[0];
+ vals[0][0].data = (uint8_t *)name;
+ vals[0][0].length = strlen(name);
+
+ el[1].flags = 0;
+ el[1].name = "title";
+ el[1].num_values = 1;
+ el[1].values = vals[1];
+ vals[1][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "The title of %s", name);
+ vals[1][0].length = strlen((char *)vals[1][0].data);
+
+ el[2].flags = 0;
+ el[2].name = talloc_strdup(tmp_ctx, "uid");
+ el[2].num_values = 1;
+ el[2].values = vals[2];
+ vals[2][0].data = (uint8_t *)ldb_casefold(ldb, tmp_ctx, name, strlen(name));
+ vals[2][0].length = strlen((char *)vals[2][0].data);
+
+ el[3].flags = 0;
+ el[3].name = talloc_strdup(tmp_ctx, "mail");
+ el[3].num_values = 1;
+ el[3].values = vals[3];
+ vals[3][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@example.com", name);
+ vals[3][0].length = strlen((char *)vals[3][0].data);
+
+ el[4].flags = 0;
+ el[4].name = talloc_strdup(tmp_ctx, "objectClass");
+ el[4].num_values = 1;
+ el[4].values = vals[4];
+ vals[4][0].data = (uint8_t *)talloc_strdup(tmp_ctx, "OpenLDAPperson");
+ vals[4][0].length = strlen((char *)vals[4][0].data);
+
+ el[5].flags = 0;
+ el[5].name = talloc_strdup(tmp_ctx, "sn");
+ el[5].num_values = 1;
+ el[5].values = vals[5];
+ vals[5][0].data = (uint8_t *)name;
+ vals[5][0].length = strlen((char *)vals[5][0].data);
+
+ ldb_delete(ldb, msg.dn);
+
+ if (ldb_add(ldb, &msg) != LDB_SUCCESS) {
+ printf("Add of %s failed - %s\n", name, ldb_errstring(ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ printf("adding uid %s\r", name);
+ fflush(stdout);
+
+ talloc_free(tmp_ctx);
+ }
+#if 0
+ if (ldb_unlock(ldb, "transaction") != 0) {
+ printf("transaction unlock failed\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+#endif
+ printf("\n");
+}
+
+static void modify_records(struct ldb_context *ldb,
+ struct ldb_dn *basedn,
+ unsigned int count)
+{
+ struct ldb_message msg = {0};
+ unsigned int i;
+
+ for (i=0;i<count;i++) {
+ struct ldb_message_element el[3];
+ struct ldb_val vals[3];
+ char *name;
+ TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+
+ name = talloc_asprintf(tmp_ctx, "Test%d", i);
+ msg.dn = ldb_dn_copy(tmp_ctx, basedn);
+ ldb_dn_add_child_fmt(msg.dn, "cn=%s", name);
+
+ msg.num_elements = 3;
+ msg.elements = el;
+
+ el[0].flags = LDB_FLAG_MOD_DELETE;
+ el[0].name = talloc_strdup(tmp_ctx, "mail");
+ el[0].num_values = 0;
+
+ el[1].flags = LDB_FLAG_MOD_ADD;
+ el[1].name = talloc_strdup(tmp_ctx, "mail");
+ el[1].num_values = 1;
+ el[1].values = &vals[1];
+ vals[1].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other.example.com", name);
+ vals[1].length = strlen((char *)vals[1].data);
+
+ el[2].flags = LDB_FLAG_MOD_REPLACE;
+ el[2].name = talloc_strdup(tmp_ctx, "mail");
+ el[2].num_values = 1;
+ el[2].values = &vals[2];
+ vals[2].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other2.example.com", name);
+ vals[2].length = strlen((char *)vals[2].data);
+
+ if (ldb_modify(ldb, &msg) != LDB_SUCCESS) {
+ printf("Modify of %s failed - %s\n", name, ldb_errstring(ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ printf("Modifying uid %s\r", name);
+ fflush(stdout);
+
+ talloc_free(tmp_ctx);
+ }
+
+ printf("\n");
+}
+
+
+static void delete_records(struct ldb_context *ldb,
+ struct ldb_dn *basedn,
+ unsigned int count)
+{
+ unsigned int i;
+
+ for (i=0;i<count;i++) {
+ struct ldb_dn *dn;
+ char *name = talloc_asprintf(ldb, "Test%d", i);
+ dn = ldb_dn_copy(name, basedn);
+ ldb_dn_add_child_fmt(dn, "cn=%s", name);
+
+ printf("Deleting uid Test%d\r", i);
+ fflush(stdout);
+
+ if (ldb_delete(ldb, dn) != LDB_SUCCESS) {
+ printf("Delete of %s failed - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ talloc_free(name);
+ }
+
+ printf("\n");
+}
+
+static void search_uid(struct ldb_context *ldb, struct ldb_dn *basedn,
+ unsigned int nrecords, unsigned int nsearches)
+{
+ unsigned int i;
+
+ for (i=0;i<nsearches;i++) {
+ int uid = (i * 700 + 17) % (nrecords * 2);
+ char *expr;
+ struct ldb_result *res = NULL;
+ int ret;
+
+ expr = talloc_asprintf(ldb, "(uid=TEST%d)", uid);
+ ret = ldb_search(ldb, ldb, &res, basedn, LDB_SCOPE_SUBTREE, NULL, "%s", expr);
+
+ if (ret != LDB_SUCCESS || (uid < nrecords && res->count != 1)) {
+ printf("Failed to find %s - %s\n", expr, ldb_errstring(ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (uid >= nrecords && res->count > 0) {
+ printf("Found %s !? - %d\n", expr, ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ printf("Testing uid %d/%d - %d \r", i, uid, res->count);
+ fflush(stdout);
+
+ talloc_free(res);
+ talloc_free(expr);
+ }
+
+ printf("\n");
+}
+
+static void start_test(struct ldb_context *ldb, unsigned int nrecords,
+ unsigned int nsearches)
+{
+ struct ldb_dn *basedn;
+
+ basedn = ldb_dn_new(ldb, ldb, options->basedn);
+ if ( ! ldb_dn_validate(basedn)) {
+ printf("Invalid base DN format\n");
+ exit(LDB_ERR_INVALID_DN_SYNTAX);
+ }
+
+ printf("Adding %d records\n", nrecords);
+ add_records(ldb, basedn, nrecords);
+
+ printf("Starting search on uid\n");
+ _start_timer();
+ search_uid(ldb, basedn, nrecords, nsearches);
+ printf("uid search took %.2f seconds\n", _end_timer());
+
+ printf("Modifying records\n");
+ modify_records(ldb, basedn, nrecords);
+
+ printf("Deleting records\n");
+ delete_records(ldb, basedn, nrecords);
+}
+
+
+/*
+ 2) Store an @indexlist record
+
+ 3) Store a record that contains fields that should be index according
+to @index
+
+ 4) disconnection from database
+
+ 5) connect to same database
+
+ 6) search for record added in step 3 using a search key that should
+be indexed
+*/
+static void start_test_index(struct ldb_context **ldb)
+{
+ struct ldb_message *msg;
+ struct ldb_result *res = NULL;
+ struct ldb_dn *indexlist;
+ struct ldb_dn *basedn;
+ int ret;
+ unsigned int flags = 0;
+ const char *specials;
+
+ specials = getenv("LDB_SPECIALS");
+ if (specials && atoi(specials) == 0) {
+ printf("LDB_SPECIALS disabled - skipping index test\n");
+ return;
+ }
+
+ if (options->nosync) {
+ flags |= LDB_FLG_NOSYNC;
+ }
+
+ printf("Starting index test\n");
+
+ indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST");
+
+ ldb_delete(*ldb, indexlist);
+
+ msg = ldb_msg_new(NULL);
+ if (msg == NULL) {
+ printf("ldb_msg_new failed\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ msg->dn = indexlist;
+ ldb_msg_add_string(msg, "@IDXATTR", strdup("uid"));
+
+ if (ldb_add(*ldb, msg) != 0) {
+ printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ basedn = ldb_dn_new(*ldb, *ldb, options->basedn);
+
+ memset(msg, 0, sizeof(*msg));
+ msg->dn = ldb_dn_copy(msg, basedn);
+ ldb_dn_add_child_fmt(msg->dn, "cn=test");
+ ldb_msg_add_string(msg, "cn", strdup("test"));
+ ldb_msg_add_string(msg, "sn", strdup("test"));
+ ldb_msg_add_string(msg, "uid", strdup("test"));
+ ldb_msg_add_string(msg, "objectClass", strdup("OpenLDAPperson"));
+
+ if (ldb_add(*ldb, msg) != LDB_SUCCESS) {
+ printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (talloc_free(*ldb) != 0) {
+ printf("failed to free/close ldb database");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ (*ldb) = ldb_init(options, NULL);
+
+ ret = ldb_connect(*ldb, options->url, flags, NULL);
+ if (ret != LDB_SUCCESS) {
+ printf("failed to connect to %s\n", options->url);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ basedn = ldb_dn_new(*ldb, *ldb, options->basedn);
+ msg->dn = basedn;
+ ldb_dn_add_child_fmt(msg->dn, "cn=test");
+
+ ret = ldb_search(*ldb, *ldb, &res, basedn, LDB_SCOPE_SUBTREE, NULL, "uid=test");
+ if (ret != LDB_SUCCESS) {
+ printf("Search with (uid=test) filter failed!\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ if(res->count != 1) {
+ printf("Should have found 1 record - found %d\n", res->count);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST");
+
+ if (ldb_delete(*ldb, msg->dn) != 0 ||
+ ldb_delete(*ldb, indexlist) != 0) {
+ printf("cleanup failed - %s\n", ldb_errstring(*ldb));
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ printf("Finished index test\n");
+}
+
+
+static void usage(struct ldb_context *ldb)
+{
+ printf("Usage: ldbtest <options>\n");
+ printf("Options:\n");
+ printf(" -H ldb_url choose the database (or $LDB_URL)\n");
+ printf(" --num-records nrecords database size to use\n");
+ printf(" --num-searches nsearches number of searches to do\n");
+ printf("\n");
+ printf("tests ldb API\n\n");
+ exit(LDB_ERR_OPERATIONS_ERROR);
+}
+
+int main(int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct ldb_context *ldb;
+
+ ldb = ldb_init(mem_ctx, NULL);
+ if (ldb == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ options = ldb_cmdline_process(ldb, argc, argv, usage);
+
+ talloc_steal(mem_ctx, options);
+
+ if (options->basedn == NULL) {
+ options->basedn = "ou=Ldb Test,ou=People,o=University of Michigan,c=TEST";
+ }
+
+ srandom(1);
+
+ printf("Testing with num-records=%d and num-searches=%d\n",
+ options->num_records, options->num_searches);
+
+ start_test(ldb,
+ (unsigned int) options->num_records,
+ (unsigned int) options->num_searches);
+
+ start_test_index(&ldb);
+
+ talloc_free(mem_ctx);
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/ldb/tools/ldbutil.c b/lib/ldb/tools/ldbutil.c
new file mode 100644
index 0000000..52a9b27
--- /dev/null
+++ b/lib/ldb/tools/ldbutil.c
@@ -0,0 +1,220 @@
+/*
+ ldb database library utility
+
+ Copyright (C) Matthieu Patou 2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Description: Common function used by ldb_add/ldb_modify/ldb_delete
+ *
+ * Author: Matthieu Patou
+ */
+
+#include "replace.h"
+#include "ldb.h"
+#include "ldb_module.h"
+#include "ldbutil.h"
+
+
+/* autostarts a transaction if none active */
+static int ldb_do_autotransaction(struct ldb_context *ldb,
+ struct ldb_request *req)
+{
+ int ret;
+
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_request(ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret == LDB_SUCCESS) {
+ return ldb_transaction_commit(ldb);
+ }
+ ldb_transaction_cancel(ldb);
+
+ if (ldb_errstring(ldb) == NULL) {
+ /* no error string was setup by the backend */
+ ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret);
+ }
+
+ return ret;
+}
+/*
+ Same as ldb_add but accept control
+*/
+int ldb_add_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_add_req(&req, ldb, ldb,
+ message,
+ controls,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_do_autotransaction(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+/*
+ same as ldb_delete but accept control
+*/
+int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn,
+ struct ldb_control **controls)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_del_req(&req, ldb, ldb,
+ dn,
+ controls,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_do_autotransaction(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+
+/*
+ same as ldb_modify, but accepts controls
+*/
+int ldb_modify_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_msg_sanity_check(ldb, message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_build_mod_req(&req, ldb, ldb,
+ message,
+ controls,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* do request and autostart a transaction */
+ ret = ldb_do_autotransaction(ldb, req);
+
+ talloc_free(req);
+ return ret;
+}
+
+
+/*
+ ldb_search with controls
+*/
+int ldb_search_ctrl(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_result **result, struct ldb_dn *base,
+ enum ldb_scope scope, const char * const *attrs,
+ struct ldb_control **controls,
+ const char *exp_fmt, ...)
+{
+ struct ldb_request *req;
+ struct ldb_result *res;
+ char *expression;
+ va_list ap;
+ int ret;
+
+ expression = NULL;
+ *result = NULL;
+ req = NULL;
+
+ res = talloc_zero(mem_ctx, struct ldb_result);
+ if (!res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (exp_fmt) {
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
+ va_end(ap);
+
+ if (!expression) {
+ talloc_free(res);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ ret = ldb_build_search_req(&req, ldb, mem_ctx,
+ base?base:ldb_get_default_basedn(ldb),
+ scope,
+ expression,
+ attrs,
+ controls,
+ res,
+ ldb_search_default_callback,
+ NULL);
+ ldb_req_set_location(req, "ldb_search_ctrl");
+
+ if (ret != LDB_SUCCESS) goto done;
+
+ ret = ldb_request(ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ res = NULL;
+ }
+
+ talloc_free(expression);
+ talloc_free(req);
+
+ *result = res;
+ return ret;
+}
diff --git a/lib/ldb/tools/ldbutil.h b/lib/ldb/tools/ldbutil.h
new file mode 100644
index 0000000..6723863
--- /dev/null
+++ b/lib/ldb/tools/ldbutil.h
@@ -0,0 +1,46 @@
+/*
+ ldb database library utility header file
+
+ Copyright (C) Matthieu Patou 2009
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Name: ldb
+ *
+ * Description: Common function used by ldb_add/ldb_modify/ldb_delete
+ *
+ * Author: Matthieu Patou
+ */
+
+#include "ldb.h"
+
+int ldb_add_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls);
+int ldb_delete_ctrl(struct ldb_context *ldb, struct ldb_dn *dn,
+ struct ldb_control **controls);
+int ldb_modify_ctrl(struct ldb_context *ldb,
+ const struct ldb_message *message,
+ struct ldb_control **controls);
+int ldb_search_ctrl(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_result **result, struct ldb_dn *base,
+ enum ldb_scope scope, const char * const *attrs,
+ struct ldb_control **controls,
+ const char *exp_fmt, ...) PRINTF_ATTRIBUTE(8,9);
diff --git a/lib/ldb/web/index.html b/lib/ldb/web/index.html
new file mode 100644
index 0000000..7f50cdc
--- /dev/null
+++ b/lib/ldb/web/index.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>ldb</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>ldb</h1>
+
+ldb is a LDAP-like embedded database. It is not at all
+<a href="http://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol">LDAP</a>
+standards compliant, so if you want a standards compliant database then please
+see the excellent <a href="http://www.openldap.org/">OpenLDAP</a>
+project.<p>
+
+What ldb does is provide a fast database with an LDAP-like API
+designed to be used within an application. In some ways it can be seen
+as a intermediate solution between key-value pair databases and a real
+LDAP database.<p>
+
+ldb is the database engine used in Samba4.
+
+<h2>Features</h2>
+
+The main features that separate ldb from other solutions are:
+
+<ul>
+<li>Safe multi-reader, multi-writer, using byte range locking
+<li><a href="http://en.wikipedia.org/wiki/LDAP_Application_Program_Interface">LDAP-like API</a>
+<li>fast operation
+<li>choice of local tdb or remote LDAP backends
+<li>integration with <a href="http://talloc.samba.org">talloc</a>
+<li>schema-less operation, for trivial setup
+<li>modules for extensions (such as schema support)
+<li>easy setup of indexes and attribute properties
+<li><a href="http://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format">LDIF</a> for import/export
+<li>ldbedit tool for database (via LDIF) editing (reminiscent of 'vipw')
+</ul>
+
+<h2>Documentation</h2>
+
+Currently ldb is completely lacking in programmer or user
+documentation. This is your opportunity to make a contribution! Start
+with the public functions declared in <a
+href="http://samba.org/ftp/unpacked/ldb/include/ldb.h">ldb.h</a>
+and the example code in the <a
+href="http://samba.org/ftp/unpacked/ldb/tools/">tools
+directory</a>. Documentation in the same docbook format used by Samba
+would be preferred.
+
+<h2>Discussion and bug reports</h2>
+
+ldb does not have its own mailing list or bug tracking system. Please
+use
+the <a href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+<h2>Download</h2>
+
+You can download the latest release here:<br>
+ <a href="http://samba.org/ftp/pub/ldb">http://samba.org/ftp/pub/ldb</a>
+
+Alternatively, you can fetch via git. See the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+
+<hr>
+<tiny>
+<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br>
+ldb AT tridgell.net
+</tiny>
+
+</BODY>
+</HTML>
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
new file mode 100644
index 0000000..c249a82
--- /dev/null
+++ b/lib/ldb/wscript
@@ -0,0 +1,685 @@
+#!/usr/bin/env python
+
+APPNAME = 'ldb'
+# For Samba 4.20.x !
+VERSION = '2.9.0'
+
+import sys, os
+
+# find the buildtools directory
+top = '.'
+while not os.path.exists(top+'/buildtools') and len(top.split('/')) < 5:
+ top = top + '/..'
+sys.path.insert(0, top + '/buildtools/wafsamba')
+
+out = 'bin'
+
+from wafsamba import samba_dist, samba_utils
+from waflib import Errors, Options, Logs, Context
+import shutil
+
+samba_dist.DIST_DIRS('''lib/ldb:. lib/replace:lib/replace lib/talloc:lib/talloc
+ lib/tdb:lib/tdb lib/tdb:lib/tdb lib/tevent:lib/tevent
+ third_party/popt:third_party/popt
+ third_party/cmocka:third_party/cmocka
+ buildtools:buildtools third_party/waf:third_party/waf''')
+
+samba_dist.DIST_FILES('''lib/util/binsearch.h:lib/util/binsearch.h
+ lib/util/attr.h:lib/util/attr.h''')
+
+def options(opt):
+ opt.BUILTIN_DEFAULT('replace')
+ opt.PRIVATE_EXTENSION_DEFAULT('ldb', noextension='ldb')
+ opt.RECURSE('lib/tdb')
+ opt.RECURSE('lib/tevent')
+ opt.RECURSE('lib/replace')
+ opt.load('python') # options for disabling pyc or pyo compilation
+
+ opt.add_option('--without-ldb-lmdb',
+ help='disable new LMDB backend for LDB',
+ action='store_true', dest='without_ldb_lmdb', default=False)
+
+
+def configure(conf):
+ conf.RECURSE('lib/tdb')
+ conf.RECURSE('lib/tevent')
+
+ if conf.CHECK_FOR_THIRD_PARTY():
+ conf.RECURSE('third_party/popt')
+ conf.RECURSE('third_party/cmocka')
+ else:
+ if not conf.CHECK_POPT():
+ raise Errors.WafError('popt development packages have not been found.\nIf third_party is installed, check that it is in the proper place.')
+ else:
+ conf.define('USING_SYSTEM_POPT', 1)
+
+ if not conf.CHECK_CMOCKA():
+ raise Errors.WafError('cmocka development package have not been found.\nIf third_party is installed, check that it is in the proper place.')
+ else:
+ conf.define('USING_SYSTEM_CMOCKA', 1)
+
+ conf.RECURSE('lib/replace')
+ conf.find_program('xsltproc', var='XSLTPROC')
+ conf.SAMBA_CHECK_PYTHON()
+ conf.SAMBA_CHECK_PYTHON_HEADERS()
+
+ # where does the default LIBDIR end up? in conf.env somewhere?
+ #
+ conf.CONFIG_PATH('LDB_MODULESDIR', conf.SUBST_ENV_VAR('MODULESDIR') + '/ldb')
+
+ conf.env.standalone_ldb = conf.IN_LAUNCH_DIR()
+
+ if not conf.env.standalone_ldb:
+ max_ldb_version = [int(x) for x in VERSION.split(".")]
+ max_ldb_version[2] = 999
+ max_ldb_version_dots = "%d.%d.%d" % tuple(max_ldb_version)
+
+ if conf.env.disable_python:
+ if conf.CHECK_BUNDLED_SYSTEM_PKG('ldb',
+ minversion=VERSION,
+ maxversion=max_ldb_version_dots,
+ onlyif='talloc tdb tevent',
+ implied_deps='replace talloc tdb tevent'):
+ conf.define('USING_SYSTEM_LDB', 1)
+ else:
+ using_system_pyldb_util = True
+ dflt_name = 'pyldb-util' + conf.all_envs['default']['PYTHON_SO_ABI_FLAG']
+ if not conf.CHECK_BUNDLED_SYSTEM_PKG(dflt_name,
+ minversion=VERSION,
+ maxversion=max_ldb_version_dots,
+ onlyif='talloc tdb tevent',
+ implied_deps='replace talloc tdb tevent ldb'):
+ using_system_pyldb_util = False
+
+ if using_system_pyldb_util:
+ conf.define('USING_SYSTEM_PYLDB_UTIL', 1)
+
+ if conf.CHECK_BUNDLED_SYSTEM_PKG('ldb',
+ minversion=VERSION,
+ maxversion=max_ldb_version_dots,
+ onlyif='talloc tdb tevent %s' % dflt_name,
+ implied_deps='replace talloc tdb tevent'):
+ conf.define('USING_SYSTEM_LDB', 1)
+
+ if not conf.CHECK_CODE('return !(sizeof(size_t) >= 8)',
+ "HAVE_64_BIT_SIZE_T_FOR_LMDB",
+ execute=True,
+ msg='Checking for a 64-bit host to '
+ 'support lmdb'):
+ Logs.warn("--without-ldb-lmdb implied as this "
+ "host is not 64-bit")
+
+ if not conf.env.standalone_ldb and \
+ not Options.options.without_ad_dc and \
+ conf.CONFIG_GET('ENABLE_SELFTEST'):
+ Logs.warn("NOTE: Some AD DC parts of selftest will fail")
+
+ conf.env.REQUIRE_LMDB = False
+ else:
+ if conf.env.standalone_ldb:
+ if Options.options.without_ldb_lmdb:
+ conf.env.REQUIRE_LMDB = False
+ else:
+ conf.env.REQUIRE_LMDB = True
+ elif Options.options.without_ad_dc:
+ conf.env.REQUIRE_LMDB = False
+ else:
+ if Options.options.without_ldb_lmdb:
+ if not Options.options.without_ad_dc and \
+ conf.CONFIG_GET('ENABLE_SELFTEST'):
+ raise Errors.WafError('--without-ldb-lmdb conflicts '
+ 'with --enable-selftest while '
+ 'building the AD DC')
+
+ conf.env.REQUIRE_LMDB = False
+ else:
+ conf.env.REQUIRE_LMDB = True
+
+
+ if conf.CONFIG_SET('USING_SYSTEM_LDB'):
+ v = VERSION.split('.')
+ conf.DEFINE('EXPECTED_SYSTEM_LDB_VERSION_MAJOR', int(v[0]))
+ conf.DEFINE('EXPECTED_SYSTEM_LDB_VERSION_MINOR', int(v[1]))
+ conf.DEFINE('EXPECTED_SYSTEM_LDB_VERSION_RELEASE', int(v[2]))
+
+ if conf.env.standalone_ldb:
+ conf.CHECK_XSLTPROC_MANPAGES()
+
+ # we need this for the ldap backend
+ if conf.CHECK_FUNCS_IN('ber_flush ldap_open ldap_initialize', 'lber ldap', headers='lber.h ldap.h'):
+ conf.env.ENABLE_LDAP_BACKEND = True
+
+ # we don't want any libraries or modules to rely on runtime
+ # resolution of symbols
+ if not sys.platform.startswith("openbsd"):
+ conf.ADD_LDFLAGS('-Wl,-no-undefined', testflags=True)
+
+ # if lmdb support is enabled then we require lmdb
+ # is present, build the mdb back end and enable lmdb support in
+ # the tools.
+ if conf.env.REQUIRE_LMDB and \
+ not conf.CONFIG_SET('USING_SYSTEM_LDB'):
+ if not conf.CHECK_CFG(package='lmdb',
+ args='"lmdb >= 0.9.16" --cflags --libs',
+ msg='Checking for lmdb >= 0.9.16',
+ mandatory=False):
+ if not conf.CHECK_CODE('''
+ #if MDB_VERSION_MAJOR == 0 \
+ && MDB_VERSION_MINOR <= 9 \
+ && MDB_VERSION_PATCH < 16
+ #error LMDB too old
+ #endif
+ ''',
+ 'HAVE_GOOD_LMDB_VERSION',
+ headers='lmdb.h',
+ msg='Checking for lmdb >= 0.9.16 via header check'):
+
+ if conf.env.standalone_ldb:
+ raise Errors.WafError('ldb build (unless --without-ldb-lmdb) '
+ 'requires '
+ 'lmdb 0.9.16 or later')
+ elif not Options.options.without_ad_dc:
+ raise Errors.WafError('Samba AD DC and --enable-selftest '
+ 'requires '
+ 'lmdb 0.9.16 or later')
+
+ if conf.CHECK_FUNCS_IN('mdb_env_create', 'lmdb', headers='lmdb.h'):
+ conf.DEFINE('HAVE_LMDB', '1')
+ conf.env.HAVE_LMDB = True
+
+
+ conf.DEFINE('HAVE_CONFIG_H', 1, add_to_cflags=True)
+
+ conf.SAMBA_CONFIG_H()
+
+ conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
+
+def build(bld):
+ bld.RECURSE('lib/tevent')
+
+ if bld.CHECK_FOR_THIRD_PARTY():
+ bld.RECURSE('third_party/popt')
+ bld.RECURSE('third_party/cmocka')
+
+ bld.RECURSE('lib/replace')
+ bld.RECURSE('lib/tdb')
+
+ if bld.env.standalone_ldb:
+ if not 'PACKAGE_VERSION' in bld.env:
+ bld.env.PACKAGE_VERSION = VERSION
+ bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+ private_library = False
+ else:
+ private_library = True
+ # we're not currently linking against the ldap libs, but ldb.pc.in
+ # has @LDAP_LIBS@
+ bld.env.LDAP_LIBS = ''
+
+ LDB_MAP_SRC = bld.SUBDIR('ldb_map',
+ 'ldb_map.c ldb_map_inbound.c ldb_map_outbound.c')
+
+ COMMON_SRC = bld.SUBDIR('common',
+ '''ldb_modules.c ldb_ldif.c ldb_parse.c ldb_msg.c ldb_utf8.c
+ ldb_debug.c ldb_dn.c ldb_match.c ldb_options.c ldb_pack.c
+ ldb_attributes.c attrib_handlers.c ldb_controls.c qsort.c''')
+
+ bld.SAMBA_MODULE('ldb_ldap', 'ldb_ldap/ldb_ldap.c',
+ init_function='ldb_ldap_init',
+ module_init_name='ldb_init_module',
+ deps='talloc lber ldap ldb',
+ enabled=bld.env.ENABLE_LDAP_BACKEND,
+ internal_module=False,
+ subsystem='ldb')
+
+ if bld.PYTHON_BUILD_IS_ENABLED():
+ if not bld.CONFIG_SET('USING_SYSTEM_PYLDB_UTIL'):
+ name = bld.pyembed_libname('pyldb-util')
+ bld.SAMBA_LIBRARY(name,
+ deps='replace ldb',
+ source='pyldb_util.c',
+ public_headers=('' if private_library else 'pyldb.h'),
+ public_headers_install=not private_library,
+ vnum=VERSION,
+ private_library=private_library,
+ pc_files='pyldb-util.pc',
+ pyembed=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED(),
+ abi_directory='ABI',
+ abi_match='pyldb_*')
+
+ if not bld.CONFIG_SET('USING_SYSTEM_LDB'):
+ bld.SAMBA_PYTHON('pyldb', 'pyldb.c',
+ deps='replace ldb ' + name,
+ realname='ldb.so',
+ cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+
+ # Do only install this file as part of the Samba build if we do not
+ # use the system libldb!
+ if not bld.CONFIG_SET('USING_SYSTEM_PYLDB_UTIL'):
+ bld.SAMBA_SCRIPT('_ldb_text.py',
+ pattern='_ldb_text.py',
+ installdir='python')
+
+ bld.INSTALL_FILES('${PYTHONARCHDIR}', '_ldb_text.py')
+
+ if not bld.CONFIG_SET('USING_SYSTEM_LDB'):
+ if bld.is_install:
+ modules_dir = bld.EXPAND_VARIABLES('${LDB_MODULESDIR}')
+ else:
+ # when we run from the source directory, we want to use
+ # the current modules, not the installed ones
+ modules_dir = os.path.join(os.getcwd(), 'bin/modules/ldb')
+
+ abi_match = '!ldb_*module_ops !ldb_*backend_ops ldb_*'
+
+ ldb_headers = ('include/ldb.h include/ldb_errors.h '
+ 'include/ldb_module.h include/ldb_handlers.h')
+
+ bld.SAMBA_LIBRARY('ldb',
+ COMMON_SRC + ' ' + LDB_MAP_SRC,
+ deps='tevent LIBLDB_MAIN replace',
+ includes='include',
+ public_headers=('' if private_library else ldb_headers),
+ public_headers_install=not private_library,
+ pc_files='ldb.pc',
+ vnum=VERSION,
+ private_library=private_library,
+ manpages='man/ldb.3',
+ abi_directory='ABI',
+ abi_match = abi_match)
+
+ # generate a include/ldb_version.h
+ def generate_ldb_version_h(t):
+ '''generate a vscript file for our public libraries'''
+
+ tgt = t.outputs[0].bldpath(t.env)
+
+ v = t.env.LDB_VERSION.split('.')
+
+ f = open(tgt, mode='w')
+ try:
+ f.write('#define LDB_VERSION "%s"\n' % t.env.LDB_VERSION)
+ f.write('#define LDB_VERSION_MAJOR %d\n' % int(v[0]))
+ f.write('#define LDB_VERSION_MINOR %d\n' % int(v[1]))
+ f.write('#define LDB_VERSION_RELEASE %d\n' % int(v[2]))
+ finally:
+ f.close()
+ return
+ t = bld.SAMBA_GENERATOR('ldb_version.h',
+ rule=generate_ldb_version_h,
+ dep_vars=['LDB_VERSION'],
+ target='include/ldb_version.h',
+ public_headers='include/ldb_version.h',
+ public_headers_install=not private_library)
+ t.env.LDB_VERSION = VERSION
+
+ bld.SAMBA_MODULE('ldb_asq',
+ 'modules/asq.c',
+ init_function='ldb_asq_init',
+ module_init_name='ldb_init_module',
+ internal_module=False,
+ deps='ldb',
+ subsystem='ldb')
+
+ bld.SAMBA_MODULE('ldb_server_sort',
+ 'modules/sort.c',
+ init_function='ldb_server_sort_init',
+ internal_module=False,
+ module_init_name='ldb_init_module',
+ deps='ldb',
+ subsystem='ldb')
+
+ bld.SAMBA_MODULE('ldb_paged_searches',
+ 'modules/paged_searches.c',
+ init_function='ldb_paged_searches_init',
+ internal_module=False,
+ module_init_name='ldb_init_module',
+ deps='ldb',
+ subsystem='ldb')
+
+ bld.SAMBA_MODULE('ldb_rdn_name',
+ 'modules/rdn_name.c',
+ init_function='ldb_rdn_name_init',
+ internal_module=False,
+ module_init_name='ldb_init_module',
+ deps='ldb',
+ subsystem='ldb')
+
+ bld.SAMBA_MODULE('ldb_sample',
+ 'tests/sample_module.c',
+ init_function='ldb_sample_init',
+ internal_module=False,
+ module_init_name='ldb_init_module',
+ deps='ldb',
+ subsystem='ldb')
+
+ bld.SAMBA_MODULE('ldb_skel',
+ 'modules/skel.c',
+ init_function='ldb_skel_init',
+ internal_module=False,
+ module_init_name='ldb_init_module',
+ deps='ldb',
+ subsystem='ldb')
+
+ bld.SAMBA_MODULE('ldb_sqlite3',
+ 'sqlite3/ldb_sqlite3.c',
+ init_function='ldb_sqlite3_init',
+ internal_module=False,
+ module_init_name='ldb_init_module',
+ enabled=False,
+ deps='ldb',
+ subsystem='ldb')
+
+ bld.SAMBA_MODULE('ldb_tdb',
+ bld.SUBDIR('ldb_tdb',
+ '''ldb_tdb_init.c'''),
+ init_function='ldb_tdb_init',
+ module_init_name='ldb_init_module',
+ internal_module=False,
+ deps='ldb ldb_tdb_int ldb_key_value',
+ subsystem='ldb')
+
+ bld.SAMBA_LIBRARY('ldb_tdb_int',
+ bld.SUBDIR('ldb_tdb',
+ '''ldb_tdb_wrap.c ldb_tdb.c'''),
+ private_library=True,
+ deps='ldb tdb ldb_key_value ldb_tdb_err_map')
+
+ bld.SAMBA_LIBRARY('ldb_tdb_err_map',
+ bld.SUBDIR('ldb_tdb',
+ '''ldb_tdb_err_map.c '''),
+ private_library=True,
+ deps='ldb tdb')
+
+ bld.SAMBA_LIBRARY('ldb_key_value',
+ bld.SUBDIR('ldb_key_value',
+ '''ldb_kv.c ldb_kv_search.c ldb_kv_index.c
+ ldb_kv_cache.c'''),
+ private_library=True,
+ deps='tdb ldb ldb_tdb_err_map')
+
+ if bld.CONFIG_SET('HAVE_LMDB'):
+ bld.SAMBA_MODULE('ldb_mdb',
+ bld.SUBDIR('ldb_mdb',
+ '''ldb_mdb_init.c'''),
+ init_function='ldb_mdb_init',
+ module_init_name='ldb_init_module',
+ internal_module=False,
+ deps='ldb ldb_key_value ldb_mdb_int',
+ subsystem='ldb')
+
+ bld.SAMBA_LIBRARY('ldb_mdb_int',
+ bld.SUBDIR('ldb_mdb',
+ '''ldb_mdb.c '''),
+ private_library=True,
+ deps='ldb lmdb ldb_key_value')
+ lmdb_deps = ' ldb_mdb_int'
+ else:
+ lmdb_deps = ''
+
+
+ bld.SAMBA_MODULE('ldb_ldb',
+ bld.SUBDIR('ldb_ldb',
+ '''ldb_ldb.c'''),
+ init_function='ldb_ldb_init',
+ module_init_name='ldb_init_module',
+ internal_module=False,
+ deps='ldb ldb_tdb_int ldb_key_value' + lmdb_deps,
+ subsystem='ldb')
+
+ # have a separate subsystem for common/ldb.c, so it can rebuild
+ # for install with a different -DLDB_MODULESDIR=
+ bld.SAMBA_SUBSYSTEM('LIBLDB_MAIN',
+ 'common/ldb.c',
+ deps='tevent tdb',
+ includes='include',
+ cflags=['-DLDB_MODULESDIR=\"%s\"' % modules_dir])
+
+ LDB_TOOLS='ldbadd ldbsearch ldbdel ldbmodify ldbedit ldbrename'
+ for t in LDB_TOOLS.split():
+ bld.SAMBA_BINARY(t, 'tools/%s.c' % t, deps='ldb-cmdline ldb',
+ manpages='man/%s.1' % t)
+
+ # ldbtest doesn't get installed
+ bld.SAMBA_BINARY('ldbtest', 'tools/ldbtest.c', deps='ldb-cmdline ldb',
+ install=False)
+
+ if bld.CONFIG_SET('HAVE_LMDB'):
+ lmdb_deps = ' lmdb'
+ else:
+ lmdb_deps = ''
+ # ldbdump doesn't get installed
+ bld.SAMBA_BINARY('ldbdump',
+ 'tools/ldbdump.c',
+ deps='ldb-cmdline ldb' + lmdb_deps,
+ install=False)
+
+ bld.SAMBA_LIBRARY('ldb-cmdline',
+ source='tools/ldbutil.c tools/cmdline.c',
+ deps='ldb dl popt',
+ private_library=True)
+
+ bld.SAMBA_BINARY('ldb_tdb_mod_op_test',
+ source='tests/ldb_mod_op_test.c',
+ cflags='-DTEST_BE=\"tdb\"',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_tdb_guid_mod_op_test',
+ source='tests/ldb_mod_op_test.c',
+ cflags='-DTEST_BE=\"tdb\" -DGUID_IDX=1',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_tdb_kv_ops_test',
+ source='tests/ldb_kv_ops_test.c',
+ cflags='-DTEST_BE=\"tdb\"',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_tdb_test',
+ source='tests/ldb_tdb_test.c',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_msg_test',
+ source='tests/ldb_msg.c',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('test_ldb_qsort',
+ source='tests/test_ldb_qsort.c',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('test_ldb_dn',
+ source='tests/test_ldb_dn.c',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_match_test',
+ source='tests/ldb_match_test.c',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_key_value_test',
+ source='tests/ldb_key_value_test.c',
+ deps='cmocka ldb ldb_tdb_err_map',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_parse_test',
+ source='tests/ldb_parse_test.c',
+ deps='cmocka ldb ldb_tdb_err_map',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_filter_attrs_test',
+ source='tests/ldb_filter_attrs_test.c',
+ deps='cmocka ldb ldb_tdb_err_map',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_filter_attrs_in_place_test',
+ source='tests/ldb_filter_attrs_in_place_test.c',
+ deps='cmocka ldb ldb_tdb_err_map',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_key_value_sub_txn_tdb_test',
+ bld.SUBDIR('ldb_key_value',
+ '''ldb_kv_search.c
+ ldb_kv_index.c
+ ldb_kv_cache.c''') +
+ 'tests/ldb_key_value_sub_txn_test.c',
+ cflags='-DTEST_BE=\"tdb\"',
+ deps='cmocka ldb ldb_tdb_err_map',
+ install=False)
+
+ # If both libldap and liblber are available, test ldb_ldap
+ # code for a regression of bz#14413 -- even if we don't build
+ # it ourselves and simply using the system version
+ if bld.env.LIB_LDAP and bld.env.LIB_LBER:
+ bld.SAMBA_BINARY('lldb_ldap_test',
+ source='tests/lldb_ldap.c',
+ deps='cmocka talloc lber ldap ldb',
+ install=False)
+
+ if bld.CONFIG_SET('HAVE_LMDB'):
+ bld.SAMBA_BINARY('ldb_mdb_mod_op_test',
+ source='tests/ldb_mod_op_test.c',
+ cflags='-DTEST_BE=\"mdb\" -DGUID_IDX=1 '
+ + '-DTEST_LMDB=1',
+ deps='cmocka ldb lmdb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_lmdb_test',
+ source='tests/ldb_lmdb_test.c',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_lmdb_size_test',
+ source='tests/ldb_lmdb_size_test.c',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_mdb_kv_ops_test',
+ source='tests/ldb_kv_ops_test.c',
+ cflags='-DTEST_BE=\"mdb\" -DTEST_LMDB=1',
+ deps='cmocka ldb',
+ install=False)
+
+ bld.SAMBA_BINARY('ldb_lmdb_free_list_test',
+ source='tests/ldb_lmdb_free_list_test.c',
+ cflags='-DTEST_BE=\"mdb\" -DTEST_LMDB=1',
+ deps='cmocka ldb',
+ install=False)
+ #
+ # We rely on the versions of the ldb_key_value functions included
+ # in ldb_key_value_sub_txn_test.c taking priority over the versions
+ # in the ldb_key_value shared library.
+ # If this turns out to not be the case, the dependencies will
+ # need to be unrolled, and all the source files included and the
+ # ldb_tdb module initialization code will need to be called
+ # manually.
+ bld.SAMBA_BINARY('ldb_key_value_sub_txn_mdb_test',
+ bld.SUBDIR('ldb_key_value',
+ '''ldb_kv_search.c
+ ldb_kv_index.c
+ ldb_kv_cache.c''') +
+ 'tests/ldb_key_value_sub_txn_test.c',
+ cflags='-DTEST_BE=\"mdb\"',
+ deps='cmocka ldb ldb_tdb_err_map',
+ install=False)
+ else:
+ bld.SAMBA_BINARY('ldb_no_lmdb_test',
+ source='tests/ldb_no_lmdb_test.c',
+ deps='cmocka ldb',
+ install=False)
+
+def test(ctx):
+ '''run ldb testsuite'''
+ env = samba_utils.LOAD_ENVIRONMENT()
+ ctx.env = env
+
+ test_prefix = "%s/st" % (Context.g_module.out)
+ shutil.rmtree(test_prefix, ignore_errors=True)
+ os.makedirs(test_prefix)
+ os.environ['TEST_DATA_PREFIX'] = test_prefix
+ os.environ['LDB_MODULES_PATH'] = Context.g_module.out + "/modules/ldb"
+ if env.HAVE_LMDB:
+ os.environ['HAVE_LMDB'] = '1'
+ else:
+ os.environ['HAVE_LMDB'] = '0'
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared')
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private')
+
+ cmd = 'tests/test-tdb.sh %s' % Context.g_module.out
+ ret = samba_utils.RUN_COMMAND(cmd)
+ print("testsuite returned %d" % ret)
+
+ tmp_dir = os.path.join(test_prefix, 'tmp')
+ if not os.path.exists(tmp_dir):
+ os.mkdir(tmp_dir)
+ pyret = samba_utils.RUN_PYTHON_TESTS(
+ ['tests/python/api.py',
+ 'tests/python/crash.py',
+ 'tests/python/index.py',
+ 'tests/python/repack.py'],
+ extra_env={'SELFTEST_PREFIX': test_prefix})
+ pyret = samba_utils.RUN_PYTHON_TESTS(
+ ['tests/python/api.py',
+ 'tests/python/crash.py',
+ 'tests/python/index.py',
+ 'tests/python/repack.py'],
+ extra_env={'SELFTEST_PREFIX': test_prefix,
+ 'LC_ALL': 'tr_TR.UTF-8'}) or pyret
+ print("Python testsuite returned %d" % pyret)
+
+ cmocka_ret = 0
+ test_exes = ['test_ldb_qsort',
+ 'test_ldb_dn',
+ 'ldb_msg_test',
+ 'ldb_tdb_mod_op_test',
+ 'ldb_tdb_guid_mod_op_test',
+ 'ldb_tdb_kv_ops_test',
+ 'ldb_tdb_test',
+ 'ldb_match_test',
+ 'ldb_key_value_test',
+ # we currently don't run ldb_key_value_sub_txn_tdb_test as it
+ # tests the nested/sub transaction handling
+ # on operations which the TDB backend does not currently
+ # support
+ # 'ldb_key_value_sub_txn_tdb_test'
+ 'ldb_parse_test',
+ 'ldb_filter_attrs_test',
+ 'ldb_filter_attrs_in_place_test',
+ ]
+
+ # if LIB_LDAP and LIB_LBER defined, then we can test ldb_ldap backend
+ # behavior regression for bz#14413
+ if env.LIB_LDAP and env.LIB_LBER:
+ test_exes += ["lldb_ldap_test"]
+
+ if env.HAVE_LMDB:
+ test_exes += ['ldb_mdb_mod_op_test',
+ 'ldb_lmdb_test',
+ # we don't want to run ldb_lmdb_size_test (which proves
+ # we can fit > 4G of data into the DB), it would fill up
+ # the disk on many of our test instances
+ 'ldb_mdb_kv_ops_test',
+ 'ldb_key_value_sub_txn_mdb_test',
+ 'ldb_lmdb_free_list_test']
+ else:
+ test_exes += ['ldb_no_lmdb_test']
+
+ for test_exe in test_exes:
+ cmd = os.path.join(Context.g_module.out, test_exe)
+ cmocka_ret = cmocka_ret or samba_utils.RUN_COMMAND(cmd)
+
+ sys.exit(ret or pyret or cmocka_ret)
+
+def dist():
+ '''makes a tarball for distribution'''
+ samba_dist.dist()
+
+def reconfigure(ctx):
+ '''reconfigure if config scripts have changed'''
+ import samba_utils
+ samba_utils.reconfigure(ctx)
diff --git a/lib/messaging/messages_dgm.c b/lib/messaging/messages_dgm.c
new file mode 100644
index 0000000..1c96b2f
--- /dev/null
+++ b/lib/messaging/messages_dgm.c
@@ -0,0 +1,1790 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba internal messaging functions
+ * Copyright (C) 2013 by Volker Lendecke
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "util/util.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include "system/select.h"
+#include "lib/util/debug.h"
+#include "messages_dgm.h"
+#include "lib/util/genrand.h"
+#include "lib/util/dlinklist.h"
+#include "lib/pthreadpool/pthreadpool_tevent.h"
+#include "lib/util/msghdr.h"
+#include "lib/util/iov_buf.h"
+#include "lib/util/blocking.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/smb_strtox.h"
+
+#define MESSAGING_DGM_FRAGMENT_LENGTH 1024
+
+struct sun_path_buf {
+ /*
+ * This will carry enough for a socket path
+ */
+ char buf[sizeof(struct sockaddr_un)];
+};
+
+/*
+ * We can only have one tevent_fd per dgm_context and per
+ * tevent_context. Maintain a list of registered tevent_contexts per
+ * dgm_context.
+ */
+struct messaging_dgm_fde_ev {
+ struct messaging_dgm_fde_ev *prev, *next;
+
+ /*
+ * Backreference to enable DLIST_REMOVE from our
+ * destructor. Also, set to NULL when the dgm_context dies
+ * before the messaging_dgm_fde_ev.
+ */
+ struct messaging_dgm_context *ctx;
+
+ struct tevent_context *ev;
+ struct tevent_fd *fde;
+};
+
+struct messaging_dgm_out {
+ struct messaging_dgm_out *prev, *next;
+ struct messaging_dgm_context *ctx;
+
+ pid_t pid;
+ int sock;
+ bool is_blocking;
+ uint64_t cookie;
+
+ struct tevent_queue *queue;
+ struct tevent_timer *idle_timer;
+};
+
+struct messaging_dgm_in_msg {
+ struct messaging_dgm_in_msg *prev, *next;
+ struct messaging_dgm_context *ctx;
+ size_t msglen;
+ size_t received;
+ pid_t sender_pid;
+ int sender_sock;
+ uint64_t cookie;
+ uint8_t buf[];
+};
+
+struct messaging_dgm_context {
+ struct tevent_context *ev;
+ pid_t pid;
+ struct sun_path_buf socket_dir;
+ struct sun_path_buf lockfile_dir;
+ int lockfile_fd;
+
+ int sock;
+ struct messaging_dgm_in_msg *in_msgs;
+
+ struct messaging_dgm_fde_ev *fde_evs;
+ void (*recv_cb)(struct tevent_context *ev,
+ const uint8_t *msg,
+ size_t msg_len,
+ int *fds,
+ size_t num_fds,
+ void *private_data);
+ void *recv_cb_private_data;
+
+ bool *have_dgm_context;
+
+ struct pthreadpool_tevent *pool;
+ struct messaging_dgm_out *outsocks;
+};
+
+/* Set socket close on exec. */
+static int prepare_socket_cloexec(int sock)
+{
+#ifdef FD_CLOEXEC
+ int flags;
+
+ flags = fcntl(sock, F_GETFD, 0);
+ if (flags == -1) {
+ return errno;
+ }
+ flags |= FD_CLOEXEC;
+ if (fcntl(sock, F_SETFD, flags) == -1) {
+ return errno;
+ }
+#endif
+ return 0;
+}
+
+static void close_fd_array(int *fds, size_t num_fds)
+{
+ size_t i;
+
+ for (i = 0; i < num_fds; i++) {
+ if (fds[i] == -1) {
+ continue;
+ }
+
+ close(fds[i]);
+ fds[i] = -1;
+ }
+}
+
+/*
+ * The idle handler can free the struct messaging_dgm_out *,
+ * if it's unused (qlen of zero) which closes the socket.
+ */
+
+static void messaging_dgm_out_idle_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct messaging_dgm_out *out = talloc_get_type_abort(
+ private_data, struct messaging_dgm_out);
+ size_t qlen;
+
+ out->idle_timer = NULL;
+
+ qlen = tevent_queue_length(out->queue);
+ if (qlen == 0) {
+ TALLOC_FREE(out);
+ }
+}
+
+/*
+ * Setup the idle handler to fire after 1 second if the
+ * queue is zero.
+ */
+
+static void messaging_dgm_out_rearm_idle_timer(struct messaging_dgm_out *out)
+{
+ size_t qlen;
+
+ qlen = tevent_queue_length(out->queue);
+ if (qlen != 0) {
+ TALLOC_FREE(out->idle_timer);
+ return;
+ }
+
+ if (out->idle_timer != NULL) {
+ tevent_update_timer(out->idle_timer,
+ tevent_timeval_current_ofs(1, 0));
+ return;
+ }
+
+ out->idle_timer = tevent_add_timer(
+ out->ctx->ev, out, tevent_timeval_current_ofs(1, 0),
+ messaging_dgm_out_idle_handler, out);
+ /*
+ * No NULL check, we'll come back here. Worst case we're
+ * leaking a bit.
+ */
+}
+
+static int messaging_dgm_out_destructor(struct messaging_dgm_out *dst);
+static void messaging_dgm_out_idle_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data);
+
+/*
+ * Connect to an existing rendezvous point for another
+ * pid - wrapped inside a struct messaging_dgm_out *.
+ */
+
+static int messaging_dgm_out_create(TALLOC_CTX *mem_ctx,
+ struct messaging_dgm_context *ctx,
+ pid_t pid, struct messaging_dgm_out **pout)
+{
+ struct messaging_dgm_out *out;
+ struct sockaddr_un addr = { .sun_family = AF_UNIX };
+ int ret = ENOMEM;
+ int out_pathlen;
+ char addr_buf[sizeof(addr.sun_path) + (3 * sizeof(unsigned) + 2)];
+
+ out = talloc(mem_ctx, struct messaging_dgm_out);
+ if (out == NULL) {
+ goto fail;
+ }
+
+ *out = (struct messaging_dgm_out) {
+ .pid = pid,
+ .ctx = ctx,
+ .cookie = 1
+ };
+
+ out_pathlen = snprintf(addr_buf, sizeof(addr_buf),
+ "%s/%u", ctx->socket_dir.buf, (unsigned)pid);
+ if (out_pathlen < 0) {
+ goto errno_fail;
+ }
+ if ((size_t)out_pathlen >= sizeof(addr.sun_path)) {
+ ret = ENAMETOOLONG;
+ goto fail;
+ }
+
+ memcpy(addr.sun_path, addr_buf, out_pathlen + 1);
+
+ out->queue = tevent_queue_create(out, addr.sun_path);
+ if (out->queue == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ out->sock = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (out->sock == -1) {
+ goto errno_fail;
+ }
+
+ DLIST_ADD(ctx->outsocks, out);
+ talloc_set_destructor(out, messaging_dgm_out_destructor);
+
+ do {
+ ret = connect(out->sock,
+ (const struct sockaddr *)(const void *)&addr,
+ sizeof(addr));
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret == -1) {
+ goto errno_fail;
+ }
+
+ ret = set_blocking(out->sock, false);
+ if (ret == -1) {
+ goto errno_fail;
+ }
+ out->is_blocking = false;
+
+ *pout = out;
+ return 0;
+errno_fail:
+ ret = errno;
+fail:
+ TALLOC_FREE(out);
+ return ret;
+}
+
+static int messaging_dgm_out_destructor(struct messaging_dgm_out *out)
+{
+ DLIST_REMOVE(out->ctx->outsocks, out);
+
+ if ((tevent_queue_length(out->queue) != 0) &&
+ (tevent_cached_getpid() == out->ctx->pid)) {
+ /*
+ * We have pending jobs. We can't close the socket,
+ * this has been handed over to messaging_dgm_out_queue_state.
+ */
+ return 0;
+ }
+
+ if (out->sock != -1) {
+ close(out->sock);
+ out->sock = -1;
+ }
+ return 0;
+}
+
+/*
+ * Find the struct messaging_dgm_out * to talk to pid.
+ * If we don't have one, create it. Set the timer to
+ * delete after 1 sec.
+ */
+
+static int messaging_dgm_out_get(struct messaging_dgm_context *ctx, pid_t pid,
+ struct messaging_dgm_out **pout)
+{
+ struct messaging_dgm_out *out;
+ int ret;
+
+ for (out = ctx->outsocks; out != NULL; out = out->next) {
+ if (out->pid == pid) {
+ break;
+ }
+ }
+
+ if (out == NULL) {
+ ret = messaging_dgm_out_create(ctx, ctx, pid, &out);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /*
+ * shouldn't be possible, should be set if messaging_dgm_out_create
+ * succeeded. This check is to satisfy static checker
+ */
+ if (out == NULL) {
+ return EINVAL;
+ }
+ messaging_dgm_out_rearm_idle_timer(out);
+
+ *pout = out;
+ return 0;
+}
+
+/*
+ * This function is called directly to send a message fragment
+ * when the outgoing queue is zero, and from a pthreadpool
+ * job thread when messages are being queued (qlen != 0).
+ * Make sure *ONLY* thread-safe functions are called within.
+ */
+
+static ssize_t messaging_dgm_sendmsg(int sock,
+ const struct iovec *iov, int iovlen,
+ const int *fds, size_t num_fds,
+ int *perrno)
+{
+ struct msghdr msg;
+ ssize_t fdlen, ret;
+
+ /*
+ * Do the actual sendmsg syscall. This will be called from a
+ * pthreadpool helper thread, so be careful what you do here.
+ */
+
+ msg = (struct msghdr) {
+ .msg_iov = discard_const_p(struct iovec, iov),
+ .msg_iovlen = iovlen
+ };
+
+ fdlen = msghdr_prep_fds(&msg, NULL, 0, fds, num_fds);
+ if (fdlen == -1) {
+ *perrno = EINVAL;
+ return -1;
+ }
+
+ {
+ uint8_t buf[fdlen];
+
+ msghdr_prep_fds(&msg, buf, fdlen, fds, num_fds);
+
+ do {
+ ret = sendmsg(sock, &msg, 0);
+ } while ((ret == -1) && (errno == EINTR));
+ }
+
+ if (ret == -1) {
+ *perrno = errno;
+ }
+ return ret;
+}
+
+struct messaging_dgm_out_queue_state {
+ struct tevent_context *ev;
+ struct pthreadpool_tevent *pool;
+
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+
+ int sock;
+
+ int *fds;
+ uint8_t *buf;
+
+ ssize_t sent;
+ int err;
+};
+
+static int messaging_dgm_out_queue_state_destructor(
+ struct messaging_dgm_out_queue_state *state);
+static void messaging_dgm_out_queue_trigger(struct tevent_req *req,
+ void *private_data);
+static void messaging_dgm_out_threaded_job(void *private_data);
+static void messaging_dgm_out_queue_done(struct tevent_req *subreq);
+
+/*
+ * Push a message fragment onto a queue to be sent by a
+ * threadpool job. Makes copies of data/fd's to be sent.
+ * The running tevent_queue internally creates an immediate
+ * event to schedule the write.
+ */
+
+static struct tevent_req *messaging_dgm_out_queue_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct messaging_dgm_out *out,
+ const struct iovec *iov, int iovlen, const int *fds, size_t num_fds)
+{
+ struct tevent_req *req;
+ struct messaging_dgm_out_queue_state *state;
+ struct tevent_queue_entry *e;
+ size_t i;
+ ssize_t buflen;
+
+ req = tevent_req_create(out, &state,
+ struct messaging_dgm_out_queue_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->pool = out->ctx->pool;
+ state->sock = out->sock;
+ state->req = req;
+
+ /*
+ * Go blocking in a thread
+ */
+ if (!out->is_blocking) {
+ int ret = set_blocking(out->sock, true);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ out->is_blocking = true;
+ }
+
+ buflen = iov_buflen(iov, iovlen);
+ if (buflen == -1) {
+ tevent_req_error(req, EMSGSIZE);
+ return tevent_req_post(req, ev);
+ }
+
+ state->buf = talloc_array(state, uint8_t, buflen);
+ if (tevent_req_nomem(state->buf, req)) {
+ return tevent_req_post(req, ev);
+ }
+ iov_buf(iov, iovlen, state->buf, buflen);
+
+ state->fds = talloc_array(state, int, num_fds);
+ if (tevent_req_nomem(state->fds, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ for (i=0; i<num_fds; i++) {
+ state->fds[i] = -1;
+ }
+
+ for (i=0; i<num_fds; i++) {
+
+ state->fds[i] = dup(fds[i]);
+
+ if (state->fds[i] == -1) {
+ int ret = errno;
+
+ close_fd_array(state->fds, num_fds);
+
+ tevent_req_error(req, ret);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ talloc_set_destructor(state, messaging_dgm_out_queue_state_destructor);
+
+ e = tevent_queue_add_entry(out->queue, ev, req,
+ messaging_dgm_out_queue_trigger, req);
+ if (tevent_req_nomem(e, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static int messaging_dgm_out_queue_state_destructor(
+ struct messaging_dgm_out_queue_state *state)
+{
+ int *fds;
+ size_t num_fds;
+
+ if (state->subreq != NULL) {
+ /*
+ * We're scheduled, but we're destroyed. This happens
+ * if the messaging_dgm_context is destroyed while
+ * we're stuck in a blocking send. There's nothing we
+ * can do but to leak memory.
+ */
+ TALLOC_FREE(state->subreq);
+ (void)talloc_reparent(state->req, NULL, state);
+ return -1;
+ }
+
+ fds = state->fds;
+ num_fds = talloc_array_length(fds);
+ close_fd_array(fds, num_fds);
+ return 0;
+}
+
+/*
+ * tevent_queue callback that schedules the pthreadpool to actually
+ * send the queued message fragment.
+ */
+
+static void messaging_dgm_out_queue_trigger(struct tevent_req *req,
+ void *private_data)
+{
+ struct messaging_dgm_out_queue_state *state = tevent_req_data(
+ req, struct messaging_dgm_out_queue_state);
+
+ tevent_req_reset_endtime(req);
+
+ state->subreq = pthreadpool_tevent_job_send(
+ state, state->ev, state->pool,
+ messaging_dgm_out_threaded_job, state);
+ if (tevent_req_nomem(state->subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(state->subreq, messaging_dgm_out_queue_done,
+ req);
+}
+
+/*
+ * Wrapper function run by the pthread that calls
+ * messaging_dgm_sendmsg() to actually do the sendmsg().
+ */
+
+static void messaging_dgm_out_threaded_job(void *private_data)
+{
+ struct messaging_dgm_out_queue_state *state = talloc_get_type_abort(
+ private_data, struct messaging_dgm_out_queue_state);
+
+ struct iovec iov = { .iov_base = state->buf,
+ .iov_len = talloc_get_size(state->buf) };
+ size_t num_fds = talloc_array_length(state->fds);
+ int msec = 1;
+
+ while (true) {
+ int ret;
+
+ state->sent = messaging_dgm_sendmsg(state->sock, &iov, 1,
+ state->fds, num_fds, &state->err);
+
+ if (state->sent != -1) {
+ return;
+ }
+ if (state->err != ENOBUFS) {
+ return;
+ }
+
+ /*
+ * ENOBUFS is the FreeBSD way of saying "Try
+ * again". We have to do polling.
+ */
+ do {
+ ret = poll(NULL, 0, msec);
+ } while ((ret == -1) && (errno == EINTR));
+
+ /*
+ * Exponential backoff up to once a second
+ */
+ msec *= 2;
+ msec = MIN(msec, 1000);
+ }
+}
+
+/*
+ * Pickup the results of the pthread sendmsg().
+ */
+
+static void messaging_dgm_out_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct messaging_dgm_out_queue_state *state = tevent_req_data(
+ req, struct messaging_dgm_out_queue_state);
+ int ret;
+
+ if (subreq != state->subreq) {
+ abort();
+ }
+
+ ret = pthreadpool_tevent_job_recv(subreq);
+
+ TALLOC_FREE(subreq);
+ state->subreq = NULL;
+
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+ if (state->sent == -1) {
+ tevent_req_error(req, state->err);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static int messaging_dgm_out_queue_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
+
+static void messaging_dgm_out_sent_fragment(struct tevent_req *req);
+
+/*
+ * Core function to send a message fragment given a
+ * connected struct messaging_dgm_out * destination.
+ * If no current queue tries to send nonblocking
+ * directly. If not, queues the fragment (which makes
+ * a copy of it) and adds a 60-second timeout on the send.
+ */
+
+static int messaging_dgm_out_send_fragment(
+ struct tevent_context *ev, struct messaging_dgm_out *out,
+ const struct iovec *iov, int iovlen, const int *fds, size_t num_fds)
+{
+ struct tevent_req *req;
+ size_t qlen;
+ bool ok;
+
+ qlen = tevent_queue_length(out->queue);
+ if (qlen == 0) {
+ ssize_t nsent;
+ int err = 0;
+
+ if (out->is_blocking) {
+ int ret = set_blocking(out->sock, false);
+ if (ret == -1) {
+ return errno;
+ }
+ out->is_blocking = false;
+ }
+
+ nsent = messaging_dgm_sendmsg(out->sock, iov, iovlen, fds,
+ num_fds, &err);
+ if (nsent >= 0) {
+ return 0;
+ }
+
+ if (err == ENOBUFS) {
+ /*
+ * FreeBSD's way of telling us the dst socket
+ * is full. EWOULDBLOCK makes us spawn a
+ * polling helper thread.
+ */
+ err = EWOULDBLOCK;
+ }
+
+ if (err != EWOULDBLOCK) {
+ return err;
+ }
+ }
+
+ req = messaging_dgm_out_queue_send(out, ev, out, iov, iovlen,
+ fds, num_fds);
+ if (req == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(req, messaging_dgm_out_sent_fragment, out);
+
+ ok = tevent_req_set_endtime(req, ev,
+ tevent_timeval_current_ofs(60, 0));
+ if (!ok) {
+ TALLOC_FREE(req);
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Pickup the result of the fragment send. Reset idle timer
+ * if queue empty.
+ */
+
+static void messaging_dgm_out_sent_fragment(struct tevent_req *req)
+{
+ struct messaging_dgm_out *out = tevent_req_callback_data(
+ req, struct messaging_dgm_out);
+ int ret;
+
+ ret = messaging_dgm_out_queue_recv(req);
+ TALLOC_FREE(req);
+
+ if (ret != 0) {
+ DBG_WARNING("messaging_out_queue_recv returned %s\n",
+ strerror(ret));
+ }
+
+ messaging_dgm_out_rearm_idle_timer(out);
+}
+
+
+struct messaging_dgm_fragment_hdr {
+ size_t msglen;
+ pid_t pid;
+ int sock;
+};
+
+/*
+ * Fragment a message into MESSAGING_DGM_FRAGMENT_LENGTH - 64-bit cookie
+ * size chunks and send it.
+ *
+ * Message fragments are prefixed by a 64-bit cookie that
+ * stays the same for all fragments. This allows the receiver
+ * to recognise fragments of the same message and re-assemble
+ * them on the other end.
+ *
+ * Note that this allows other message fragments from other
+ * senders to be interleaved in the receive read processing,
+ * the combination of the cookie and header info allows unique
+ * identification of the message from a specific sender in
+ * re-assembly.
+ *
+ * If the message is smaller than MESSAGING_DGM_FRAGMENT_LENGTH - cookie
+ * then send a single message with cookie set to zero.
+ *
+ * Otherwise the message is fragmented into chunks and added
+ * to the sending queue. Any file descriptors are passed only
+ * in the last fragment.
+ *
+ * Finally the cookie is incremented (wrap over zero) to
+ * prepare for the next message sent to this channel.
+ *
+ */
+
+static int messaging_dgm_out_send_fragmented(struct tevent_context *ev,
+ struct messaging_dgm_out *out,
+ const struct iovec *iov,
+ int iovlen,
+ const int *fds, size_t num_fds)
+{
+ ssize_t msglen, sent;
+ int ret = 0;
+ struct iovec iov_copy[iovlen+2];
+ struct messaging_dgm_fragment_hdr hdr;
+ struct iovec src_iov;
+
+ if (iovlen < 0) {
+ return EINVAL;
+ }
+
+ msglen = iov_buflen(iov, iovlen);
+ if (msglen == -1) {
+ return EMSGSIZE;
+ }
+ if (num_fds > INT8_MAX) {
+ return EINVAL;
+ }
+
+ if ((size_t) msglen <=
+ (MESSAGING_DGM_FRAGMENT_LENGTH - sizeof(uint64_t))) {
+ uint64_t cookie = 0;
+
+ iov_copy[0].iov_base = &cookie;
+ iov_copy[0].iov_len = sizeof(cookie);
+ if (iovlen > 0) {
+ memcpy(&iov_copy[1], iov,
+ sizeof(struct iovec) * iovlen);
+ }
+
+ return messaging_dgm_out_send_fragment(
+ ev, out, iov_copy, iovlen+1, fds, num_fds);
+
+ }
+
+ hdr = (struct messaging_dgm_fragment_hdr) {
+ .msglen = msglen,
+ .pid = tevent_cached_getpid(),
+ .sock = out->sock
+ };
+
+ iov_copy[0].iov_base = &out->cookie;
+ iov_copy[0].iov_len = sizeof(out->cookie);
+ iov_copy[1].iov_base = &hdr;
+ iov_copy[1].iov_len = sizeof(hdr);
+
+ sent = 0;
+ src_iov = iov[0];
+
+ /*
+ * The following write loop sends the user message in pieces. We have
+ * filled the first two iovecs above with "cookie" and "hdr". In the
+ * following loops we pull message chunks from the user iov array and
+ * fill iov_copy piece by piece, possibly truncating chunks from the
+ * caller's iov array. Ugly, but hopefully efficient.
+ */
+
+ while (sent < msglen) {
+ size_t fragment_len;
+ size_t iov_index = 2;
+
+ fragment_len = sizeof(out->cookie) + sizeof(hdr);
+
+ while (fragment_len < MESSAGING_DGM_FRAGMENT_LENGTH) {
+ size_t space, chunk;
+
+ space = MESSAGING_DGM_FRAGMENT_LENGTH - fragment_len;
+ chunk = MIN(space, src_iov.iov_len);
+
+ iov_copy[iov_index].iov_base = src_iov.iov_base;
+ iov_copy[iov_index].iov_len = chunk;
+ iov_index += 1;
+
+ src_iov.iov_base = (char *)src_iov.iov_base + chunk;
+ src_iov.iov_len -= chunk;
+ fragment_len += chunk;
+
+ if (src_iov.iov_len == 0) {
+ iov += 1;
+ iovlen -= 1;
+ if (iovlen == 0) {
+ break;
+ }
+ src_iov = iov[0];
+ }
+ }
+ sent += (fragment_len - sizeof(out->cookie) - sizeof(hdr));
+
+ /*
+ * only the last fragment should pass the fd array.
+ * That simplifies the receiver a lot.
+ */
+ if (sent < msglen) {
+ ret = messaging_dgm_out_send_fragment(
+ ev, out, iov_copy, iov_index, NULL, 0);
+ } else {
+ ret = messaging_dgm_out_send_fragment(
+ ev, out, iov_copy, iov_index, fds, num_fds);
+ }
+ if (ret != 0) {
+ break;
+ }
+ }
+
+ out->cookie += 1;
+ if (out->cookie == 0) {
+ out->cookie += 1;
+ }
+
+ return ret;
+}
+
+static struct messaging_dgm_context *global_dgm_context;
+
+static int messaging_dgm_context_destructor(struct messaging_dgm_context *c);
+
+static int messaging_dgm_lockfile_create(struct messaging_dgm_context *ctx,
+ pid_t pid, int *plockfile_fd,
+ uint64_t *punique)
+{
+ char buf[64];
+ int lockfile_fd;
+ struct sun_path_buf lockfile_name;
+ struct flock lck;
+ uint64_t unique;
+ int unique_len, ret;
+ ssize_t written;
+
+ ret = snprintf(lockfile_name.buf, sizeof(lockfile_name.buf),
+ "%s/%u", ctx->lockfile_dir.buf, (unsigned)pid);
+ if (ret < 0) {
+ return errno;
+ }
+ if ((unsigned)ret >= sizeof(lockfile_name.buf)) {
+ return ENAMETOOLONG;
+ }
+
+ /* no O_EXCL, existence check is via the fcntl lock */
+
+ lockfile_fd = open(lockfile_name.buf, O_NONBLOCK|O_CREAT|O_RDWR,
+ 0644);
+
+ if ((lockfile_fd == -1) &&
+ ((errno == ENXIO) /* Linux */ ||
+ (errno == ENODEV) /* Linux kernel bug */ ||
+ (errno == EOPNOTSUPP) /* FreeBSD */)) {
+ /*
+ * Huh -- a socket? This might be a stale socket from
+ * an upgrade of Samba. Just unlink and retry, nobody
+ * else is supposed to be here at this time.
+ *
+ * Yes, this is racy, but I don't see a way to deal
+ * with this properly.
+ */
+ unlink(lockfile_name.buf);
+
+ lockfile_fd = open(lockfile_name.buf,
+ O_NONBLOCK|O_CREAT|O_WRONLY,
+ 0644);
+ }
+
+ if (lockfile_fd == -1) {
+ ret = errno;
+ DEBUG(1, ("%s: open failed: %s\n", __func__, strerror(errno)));
+ return ret;
+ }
+
+ lck = (struct flock) {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET
+ };
+
+ ret = fcntl(lockfile_fd, F_SETLK, &lck);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(1, ("%s: fcntl failed: %s\n", __func__, strerror(ret)));
+ goto fail_close;
+ }
+
+ /*
+ * Directly using the binary value for
+ * SERVERID_UNIQUE_ID_NOT_TO_VERIFY is a layering
+ * violation. But including all of ndr here just for this
+ * seems to be a bit overkill to me. Also, messages_dgm might
+ * be replaced sooner or later by something streams-based,
+ * where unique_id generation will be handled differently.
+ */
+
+ do {
+ generate_random_buffer((uint8_t *)&unique, sizeof(unique));
+ } while (unique == UINT64_C(0xFFFFFFFFFFFFFFFF));
+
+ unique_len = snprintf(buf, sizeof(buf), "%"PRIu64"\n", unique);
+
+ /* shorten a potentially preexisting file */
+
+ ret = ftruncate(lockfile_fd, unique_len);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(1, ("%s: ftruncate failed: %s\n", __func__,
+ strerror(ret)));
+ goto fail_unlink;
+ }
+
+ written = write(lockfile_fd, buf, unique_len);
+ if (written != unique_len) {
+ ret = errno;
+ DEBUG(1, ("%s: write failed: %s\n", __func__, strerror(ret)));
+ goto fail_unlink;
+ }
+
+ *plockfile_fd = lockfile_fd;
+ *punique = unique;
+ return 0;
+
+fail_unlink:
+ unlink(lockfile_name.buf);
+fail_close:
+ close(lockfile_fd);
+ return ret;
+}
+
+static void messaging_dgm_read_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+/*
+ * Create the rendezvous point in the file system
+ * that other processes can use to send messages to
+ * this pid.
+ */
+
+int messaging_dgm_init(struct tevent_context *ev,
+ uint64_t *punique,
+ const char *socket_dir,
+ const char *lockfile_dir,
+ void (*recv_cb)(struct tevent_context *ev,
+ const uint8_t *msg,
+ size_t msg_len,
+ int *fds,
+ size_t num_fds,
+ void *private_data),
+ void *recv_cb_private_data)
+{
+ struct messaging_dgm_context *ctx;
+ int ret;
+ struct sockaddr_un socket_address;
+ size_t len;
+ static bool have_dgm_context = false;
+
+ if (have_dgm_context) {
+ return EEXIST;
+ }
+
+ if ((socket_dir == NULL) || (lockfile_dir == NULL)) {
+ return EINVAL;
+ }
+
+ ctx = talloc_zero(NULL, struct messaging_dgm_context);
+ if (ctx == NULL) {
+ goto fail_nomem;
+ }
+ ctx->ev = ev;
+ ctx->pid = tevent_cached_getpid();
+ ctx->recv_cb = recv_cb;
+ ctx->recv_cb_private_data = recv_cb_private_data;
+
+ len = strlcpy(ctx->lockfile_dir.buf, lockfile_dir,
+ sizeof(ctx->lockfile_dir.buf));
+ if (len >= sizeof(ctx->lockfile_dir.buf)) {
+ TALLOC_FREE(ctx);
+ return ENAMETOOLONG;
+ }
+
+ len = strlcpy(ctx->socket_dir.buf, socket_dir,
+ sizeof(ctx->socket_dir.buf));
+ if (len >= sizeof(ctx->socket_dir.buf)) {
+ TALLOC_FREE(ctx);
+ return ENAMETOOLONG;
+ }
+
+ socket_address = (struct sockaddr_un) { .sun_family = AF_UNIX };
+ len = snprintf(socket_address.sun_path,
+ sizeof(socket_address.sun_path),
+ "%s/%u", socket_dir, (unsigned)ctx->pid);
+ if (len >= sizeof(socket_address.sun_path)) {
+ TALLOC_FREE(ctx);
+ return ENAMETOOLONG;
+ }
+
+ ret = messaging_dgm_lockfile_create(ctx, ctx->pid, &ctx->lockfile_fd,
+ punique);
+ if (ret != 0) {
+ DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
+ __func__, strerror(ret)));
+ TALLOC_FREE(ctx);
+ return ret;
+ }
+
+ unlink(socket_address.sun_path);
+
+ ctx->sock = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (ctx->sock == -1) {
+ ret = errno;
+ DBG_WARNING("socket failed: %s\n", strerror(ret));
+ TALLOC_FREE(ctx);
+ return ret;
+ }
+
+ ret = prepare_socket_cloexec(ctx->sock);
+ if (ret == -1) {
+ ret = errno;
+ DBG_WARNING("prepare_socket_cloexec failed: %s\n",
+ strerror(ret));
+ TALLOC_FREE(ctx);
+ return ret;
+ }
+
+ ret = bind(ctx->sock, (struct sockaddr *)(void *)&socket_address,
+ sizeof(socket_address));
+ if (ret == -1) {
+ ret = errno;
+ DBG_WARNING("bind failed: %s\n", strerror(ret));
+ TALLOC_FREE(ctx);
+ return ret;
+ }
+
+ talloc_set_destructor(ctx, messaging_dgm_context_destructor);
+
+ ctx->have_dgm_context = &have_dgm_context;
+
+ ret = pthreadpool_tevent_init(ctx, UINT_MAX, &ctx->pool);
+ if (ret != 0) {
+ DBG_WARNING("pthreadpool_tevent_init failed: %s\n",
+ strerror(ret));
+ TALLOC_FREE(ctx);
+ return ret;
+ }
+
+ global_dgm_context = ctx;
+ return 0;
+
+fail_nomem:
+ TALLOC_FREE(ctx);
+ return ENOMEM;
+}
+
+/*
+ * Remove the rendezvous point in the filesystem
+ * if we're the owner.
+ */
+
+static int messaging_dgm_context_destructor(struct messaging_dgm_context *c)
+{
+ while (c->outsocks != NULL) {
+ TALLOC_FREE(c->outsocks);
+ }
+ while (c->in_msgs != NULL) {
+ TALLOC_FREE(c->in_msgs);
+ }
+ while (c->fde_evs != NULL) {
+ tevent_fd_set_flags(c->fde_evs->fde, 0);
+ c->fde_evs->ctx = NULL;
+ DLIST_REMOVE(c->fde_evs, c->fde_evs);
+ }
+
+ close(c->sock);
+
+ if (tevent_cached_getpid() == c->pid) {
+ struct sun_path_buf name;
+ int ret;
+
+ ret = snprintf(name.buf, sizeof(name.buf), "%s/%u",
+ c->socket_dir.buf, (unsigned)c->pid);
+ if ((ret < 0) || ((size_t)ret >= sizeof(name.buf))) {
+ /*
+ * We've checked the length when creating, so this
+ * should never happen
+ */
+ abort();
+ }
+ unlink(name.buf);
+
+ ret = snprintf(name.buf, sizeof(name.buf), "%s/%u",
+ c->lockfile_dir.buf, (unsigned)c->pid);
+ if ((ret < 0) || ((size_t)ret >= sizeof(name.buf))) {
+ /*
+ * We've checked the length when creating, so this
+ * should never happen
+ */
+ abort();
+ }
+ unlink(name.buf);
+ }
+ close(c->lockfile_fd);
+
+ if (c->have_dgm_context != NULL) {
+ *c->have_dgm_context = false;
+ }
+
+ return 0;
+}
+
+static void messaging_dgm_validate(struct messaging_dgm_context *ctx)
+{
+#ifdef DEVELOPER
+ pid_t pid = tevent_cached_getpid();
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ struct sockaddr_un *un_addr;
+ struct sun_path_buf pathbuf;
+ struct stat st1, st2;
+ int ret;
+
+ /*
+ * Protect against using the wrong messaging context after a
+ * fork without reinit_after_fork.
+ */
+
+ ret = getsockname(ctx->sock, (struct sockaddr *)&addr, &addrlen);
+ if (ret == -1) {
+ DBG_ERR("getsockname failed: %s\n", strerror(errno));
+ goto fail;
+ }
+ if (addr.ss_family != AF_UNIX) {
+ DBG_ERR("getsockname returned family %d\n",
+ (int)addr.ss_family);
+ goto fail;
+ }
+ un_addr = (struct sockaddr_un *)&addr;
+
+ ret = snprintf(pathbuf.buf, sizeof(pathbuf.buf),
+ "%s/%u", ctx->socket_dir.buf, (unsigned)pid);
+ if (ret < 0) {
+ DBG_ERR("snprintf failed: %s\n", strerror(errno));
+ goto fail;
+ }
+ if ((size_t)ret >= sizeof(pathbuf.buf)) {
+ DBG_ERR("snprintf returned %d chars\n", (int)ret);
+ goto fail;
+ }
+
+ if (strcmp(pathbuf.buf, un_addr->sun_path) != 0) {
+ DBG_ERR("sockname wrong: Expected %s, got %s\n",
+ pathbuf.buf, un_addr->sun_path);
+ goto fail;
+ }
+
+ ret = snprintf(pathbuf.buf, sizeof(pathbuf.buf),
+ "%s/%u", ctx->lockfile_dir.buf, (unsigned)pid);
+ if (ret < 0) {
+ DBG_ERR("snprintf failed: %s\n", strerror(errno));
+ goto fail;
+ }
+ if ((size_t)ret >= sizeof(pathbuf.buf)) {
+ DBG_ERR("snprintf returned %d chars\n", (int)ret);
+ goto fail;
+ }
+
+ ret = stat(pathbuf.buf, &st1);
+ if (ret == -1) {
+ DBG_ERR("stat failed: %s\n", strerror(errno));
+ goto fail;
+ }
+ ret = fstat(ctx->lockfile_fd, &st2);
+ if (ret == -1) {
+ DBG_ERR("fstat failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ if ((st1.st_dev != st2.st_dev) || (st1.st_ino != st2.st_ino)) {
+ DBG_ERR("lockfile differs, expected (%d/%d), got (%d/%d)\n",
+ (int)st2.st_dev, (int)st2.st_ino,
+ (int)st1.st_dev, (int)st1.st_ino);
+ goto fail;
+ }
+
+ return;
+fail:
+ abort();
+#else
+ return;
+#endif
+}
+
+static void messaging_dgm_recv(struct messaging_dgm_context *ctx,
+ struct tevent_context *ev,
+ uint8_t *msg, size_t msg_len,
+ int *fds, size_t num_fds);
+
+/*
+ * Raw read callback handler - passes to messaging_dgm_recv()
+ * for fragment reassembly processing.
+ */
+
+static void messaging_dgm_read_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct messaging_dgm_context *ctx = talloc_get_type_abort(
+ private_data, struct messaging_dgm_context);
+ ssize_t received;
+ struct msghdr msg;
+ struct iovec iov;
+ size_t msgbufsize = msghdr_prep_recv_fds(NULL, NULL, 0, INT8_MAX);
+ uint8_t msgbuf[msgbufsize];
+ uint8_t buf[MESSAGING_DGM_FRAGMENT_LENGTH];
+ size_t num_fds;
+
+ messaging_dgm_validate(ctx);
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ return;
+ }
+
+ iov = (struct iovec) { .iov_base = buf, .iov_len = sizeof(buf) };
+ msg = (struct msghdr) { .msg_iov = &iov, .msg_iovlen = 1 };
+
+ msghdr_prep_recv_fds(&msg, msgbuf, msgbufsize, INT8_MAX);
+
+#ifdef MSG_CMSG_CLOEXEC
+ msg.msg_flags |= MSG_CMSG_CLOEXEC;
+#endif
+
+ received = recvmsg(ctx->sock, &msg, 0);
+ if (received == -1) {
+ if ((errno == EAGAIN) ||
+ (errno == EWOULDBLOCK) ||
+ (errno == EINTR) ||
+ (errno == ENOMEM)) {
+ /* Not really an error - just try again. */
+ return;
+ }
+ /* Problem with the socket. Set it unreadable. */
+ tevent_fd_set_flags(fde, 0);
+ return;
+ }
+
+ if ((size_t)received > sizeof(buf)) {
+ /* More than we expected, not for us */
+ return;
+ }
+
+ num_fds = msghdr_extract_fds(&msg, NULL, 0);
+ if (num_fds == 0) {
+ int fds[1];
+
+ messaging_dgm_recv(ctx, ev, buf, received, fds, 0);
+ } else {
+ size_t i;
+ int fds[num_fds];
+
+ msghdr_extract_fds(&msg, fds, num_fds);
+
+ for (i = 0; i < num_fds; i++) {
+ int err;
+
+ err = prepare_socket_cloexec(fds[i]);
+ if (err != 0) {
+ close_fd_array(fds, num_fds);
+ num_fds = 0;
+ }
+ }
+
+ messaging_dgm_recv(ctx, ev, buf, received, fds, num_fds);
+ }
+}
+
+static int messaging_dgm_in_msg_destructor(struct messaging_dgm_in_msg *m)
+{
+ DLIST_REMOVE(m->ctx->in_msgs, m);
+ return 0;
+}
+
+static void messaging_dgm_close_unconsumed(int *fds, size_t num_fds)
+{
+ size_t i;
+
+ for (i=0; i<num_fds; i++) {
+ if (fds[i] != -1) {
+ close(fds[i]);
+ fds[i] = -1;
+ }
+ }
+}
+
+/*
+ * Deal with identification of fragmented messages and
+ * re-assembly into full messages sent, then calls the
+ * callback.
+ */
+
+static void messaging_dgm_recv(struct messaging_dgm_context *ctx,
+ struct tevent_context *ev,
+ uint8_t *buf, size_t buflen,
+ int *fds, size_t num_fds)
+{
+ struct messaging_dgm_fragment_hdr hdr;
+ struct messaging_dgm_in_msg *msg;
+ size_t space;
+ uint64_t cookie;
+
+ if (buflen < sizeof(cookie)) {
+ goto close_fds;
+ }
+ memcpy(&cookie, buf, sizeof(cookie));
+ buf += sizeof(cookie);
+ buflen -= sizeof(cookie);
+
+ if (cookie == 0) {
+ ctx->recv_cb(ev, buf, buflen, fds, num_fds,
+ ctx->recv_cb_private_data);
+ messaging_dgm_close_unconsumed(fds, num_fds);
+ return;
+ }
+
+ if (buflen < sizeof(hdr)) {
+ goto close_fds;
+ }
+ memcpy(&hdr, buf, sizeof(hdr));
+ buf += sizeof(hdr);
+ buflen -= sizeof(hdr);
+
+ for (msg = ctx->in_msgs; msg != NULL; msg = msg->next) {
+ if ((msg->sender_pid == hdr.pid) &&
+ (msg->sender_sock == hdr.sock)) {
+ break;
+ }
+ }
+
+ if ((msg != NULL) && (msg->cookie != cookie)) {
+ TALLOC_FREE(msg);
+ }
+
+ if (msg == NULL) {
+ size_t msglen;
+ msglen = offsetof(struct messaging_dgm_in_msg, buf) +
+ hdr.msglen;
+
+ msg = talloc_size(ctx, msglen);
+ if (msg == NULL) {
+ goto close_fds;
+ }
+ talloc_set_name_const(msg, "struct messaging_dgm_in_msg");
+
+ *msg = (struct messaging_dgm_in_msg) {
+ .ctx = ctx, .msglen = hdr.msglen,
+ .sender_pid = hdr.pid, .sender_sock = hdr.sock,
+ .cookie = cookie
+ };
+ DLIST_ADD(ctx->in_msgs, msg);
+ talloc_set_destructor(msg, messaging_dgm_in_msg_destructor);
+ }
+
+ space = msg->msglen - msg->received;
+ if (buflen > space) {
+ goto close_fds;
+ }
+
+ memcpy(msg->buf + msg->received, buf, buflen);
+ msg->received += buflen;
+
+ if (msg->received < msg->msglen) {
+ /*
+ * Any valid sender will send the fds in the last
+ * block. Invalid senders might have sent fd's that we
+ * need to close here.
+ */
+ goto close_fds;
+ }
+
+ DLIST_REMOVE(ctx->in_msgs, msg);
+ talloc_set_destructor(msg, NULL);
+
+ ctx->recv_cb(ev, msg->buf, msg->msglen, fds, num_fds,
+ ctx->recv_cb_private_data);
+ messaging_dgm_close_unconsumed(fds, num_fds);
+
+ TALLOC_FREE(msg);
+ return;
+
+close_fds:
+ close_fd_array(fds, num_fds);
+}
+
+void messaging_dgm_destroy(void)
+{
+ TALLOC_FREE(global_dgm_context);
+}
+
+int messaging_dgm_send(pid_t pid,
+ const struct iovec *iov, int iovlen,
+ const int *fds, size_t num_fds)
+{
+ struct messaging_dgm_context *ctx = global_dgm_context;
+ struct messaging_dgm_out *out;
+ int ret;
+ unsigned retries = 0;
+
+ if (ctx == NULL) {
+ return ENOTCONN;
+ }
+
+ messaging_dgm_validate(ctx);
+
+again:
+ ret = messaging_dgm_out_get(ctx, pid, &out);
+ if (ret != 0) {
+ return ret;
+ }
+
+ DEBUG(10, ("%s: Sending message to %u\n", __func__, (unsigned)pid));
+
+ ret = messaging_dgm_out_send_fragmented(ctx->ev, out, iov, iovlen,
+ fds, num_fds);
+ if (ret == ECONNREFUSED) {
+ /*
+ * We cache outgoing sockets. If the receiver has
+ * closed and re-opened the socket since our last
+ * message, we get connection refused. Retry.
+ */
+
+ TALLOC_FREE(out);
+
+ if (retries < 5) {
+ retries += 1;
+ goto again;
+ }
+ }
+ return ret;
+}
+
+static int messaging_dgm_read_unique(int fd, uint64_t *punique)
+{
+ char buf[25];
+ ssize_t rw_ret;
+ int error = 0;
+ unsigned long long unique;
+ char *endptr;
+
+ rw_ret = pread(fd, buf, sizeof(buf)-1, 0);
+ if (rw_ret == -1) {
+ return errno;
+ }
+ buf[rw_ret] = '\0';
+
+ unique = smb_strtoull(buf, &endptr, 10, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ return error;
+ }
+
+ if (endptr[0] != '\n') {
+ return EINVAL;
+ }
+ *punique = unique;
+ return 0;
+}
+
+int messaging_dgm_get_unique(pid_t pid, uint64_t *unique)
+{
+ struct messaging_dgm_context *ctx = global_dgm_context;
+ struct sun_path_buf lockfile_name;
+ int ret, fd;
+
+ if (ctx == NULL) {
+ return EBADF;
+ }
+
+ messaging_dgm_validate(ctx);
+
+ if (pid == tevent_cached_getpid()) {
+ /*
+ * Protect against losing our own lock
+ */
+ return messaging_dgm_read_unique(ctx->lockfile_fd, unique);
+ }
+
+ ret = snprintf(lockfile_name.buf, sizeof(lockfile_name.buf),
+ "%s/%u", ctx->lockfile_dir.buf, (int)pid);
+ if (ret < 0) {
+ return errno;
+ }
+ if ((size_t)ret >= sizeof(lockfile_name.buf)) {
+ return ENAMETOOLONG;
+ }
+
+ fd = open(lockfile_name.buf, O_NONBLOCK|O_RDONLY, 0);
+ if (fd == -1) {
+ return errno;
+ }
+
+ ret = messaging_dgm_read_unique(fd, unique);
+ close(fd);
+ return ret;
+}
+
+int messaging_dgm_cleanup(pid_t pid)
+{
+ struct messaging_dgm_context *ctx = global_dgm_context;
+ struct sun_path_buf lockfile_name, socket_name;
+ int fd, len, ret;
+ struct flock lck = {
+ .l_pid = 0,
+ };
+
+ if (ctx == NULL) {
+ return ENOTCONN;
+ }
+
+ len = snprintf(socket_name.buf, sizeof(socket_name.buf), "%s/%u",
+ ctx->socket_dir.buf, (unsigned)pid);
+ if (len < 0) {
+ return errno;
+ }
+ if ((size_t)len >= sizeof(socket_name.buf)) {
+ return ENAMETOOLONG;
+ }
+
+ len = snprintf(lockfile_name.buf, sizeof(lockfile_name.buf), "%s/%u",
+ ctx->lockfile_dir.buf, (unsigned)pid);
+ if (len < 0) {
+ return errno;
+ }
+ if ((size_t)len >= sizeof(lockfile_name.buf)) {
+ return ENAMETOOLONG;
+ }
+
+ fd = open(lockfile_name.buf, O_NONBLOCK|O_WRONLY, 0);
+ if (fd == -1) {
+ ret = errno;
+ if (ret != ENOENT) {
+ DEBUG(10, ("%s: open(%s) failed: %s\n", __func__,
+ lockfile_name.buf, strerror(ret)));
+ }
+ return ret;
+ }
+
+ lck.l_type = F_WRLCK;
+ lck.l_whence = SEEK_SET;
+ lck.l_start = 0;
+ lck.l_len = 0;
+
+ ret = fcntl(fd, F_SETLK, &lck);
+ if (ret != 0) {
+ ret = errno;
+ if ((ret != EACCES) && (ret != EAGAIN)) {
+ DEBUG(10, ("%s: Could not get lock: %s\n", __func__,
+ strerror(ret)));
+ }
+ close(fd);
+ return ret;
+ }
+
+ DEBUG(10, ("%s: Cleaning up : %s\n", __func__, strerror(ret)));
+
+ (void)unlink(socket_name.buf);
+ (void)unlink(lockfile_name.buf);
+ (void)close(fd);
+ return 0;
+}
+
+static int messaging_dgm_wipe_fn(pid_t pid, void *private_data)
+{
+ pid_t *our_pid = (pid_t *)private_data;
+ int ret;
+
+ if (pid == *our_pid) {
+ /*
+ * fcntl(F_GETLK) will succeed for ourselves, we hold
+ * that lock ourselves.
+ */
+ return 0;
+ }
+
+ ret = messaging_dgm_cleanup(pid);
+ DEBUG(10, ("messaging_dgm_cleanup(%lu) returned %s\n",
+ (unsigned long)pid, ret ? strerror(ret) : "ok"));
+
+ return 0;
+}
+
+int messaging_dgm_wipe(void)
+{
+ pid_t pid = tevent_cached_getpid();
+ messaging_dgm_forall(messaging_dgm_wipe_fn, &pid);
+ return 0;
+}
+
+int messaging_dgm_forall(int (*fn)(pid_t pid, void *private_data),
+ void *private_data)
+{
+ struct messaging_dgm_context *ctx = global_dgm_context;
+ DIR *msgdir;
+ struct dirent *dp;
+ int error = 0;
+
+ if (ctx == NULL) {
+ return ENOTCONN;
+ }
+
+ messaging_dgm_validate(ctx);
+
+ /*
+ * We scan the socket directory and not the lock directory. Otherwise
+ * we would race against messaging_dgm_lockfile_create's open(O_CREAT)
+ * and fcntl(SETLK).
+ */
+
+ msgdir = opendir(ctx->socket_dir.buf);
+ if (msgdir == NULL) {
+ return errno;
+ }
+
+ while ((dp = readdir(msgdir)) != NULL) {
+ unsigned long pid;
+ int ret;
+
+ pid = smb_strtoul(dp->d_name, NULL, 10, &error, SMB_STR_STANDARD);
+ if ((pid == 0) || (error != 0)) {
+ /*
+ * . and .. and other malformed entries
+ */
+ continue;
+ }
+
+ ret = fn(pid, private_data);
+ if (ret != 0) {
+ break;
+ }
+ }
+ closedir(msgdir);
+
+ return 0;
+}
+
+struct messaging_dgm_fde {
+ struct tevent_fd *fde;
+};
+
+static int messaging_dgm_fde_ev_destructor(struct messaging_dgm_fde_ev *fde_ev)
+{
+ if (fde_ev->ctx != NULL) {
+ DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
+ fde_ev->ctx = NULL;
+ }
+ return 0;
+}
+
+/*
+ * Reference counter for a struct tevent_fd messaging read event
+ * (with callback function) on a struct tevent_context registered
+ * on a messaging context.
+ *
+ * If we've already registered this struct tevent_context before
+ * (so already have a read event), just increase the reference count.
+ *
+ * Otherwise create a new struct tevent_fd messaging read event on the
+ * previously unseen struct tevent_context - this is what drives
+ * the message receive processing.
+ *
+ */
+
+struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev)
+{
+ struct messaging_dgm_context *ctx = global_dgm_context;
+ struct messaging_dgm_fde_ev *fde_ev;
+ struct messaging_dgm_fde *fde;
+
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ fde = talloc(mem_ctx, struct messaging_dgm_fde);
+ if (fde == NULL) {
+ return NULL;
+ }
+
+ for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
+ if (tevent_fd_get_flags(fde_ev->fde) == 0) {
+ /*
+ * If the event context got deleted,
+ * tevent_fd_get_flags() will return 0
+ * for the stale fde.
+ *
+ * In that case we should not
+ * use fde_ev->ev anymore.
+ */
+ continue;
+ }
+ if (fde_ev->ev == ev) {
+ break;
+ }
+ }
+
+ if (fde_ev == NULL) {
+ fde_ev = talloc(fde, struct messaging_dgm_fde_ev);
+ if (fde_ev == NULL) {
+ return NULL;
+ }
+ fde_ev->fde = tevent_add_fd(
+ ev, fde_ev, ctx->sock, TEVENT_FD_READ,
+ messaging_dgm_read_handler, ctx);
+ if (fde_ev->fde == NULL) {
+ TALLOC_FREE(fde);
+ return NULL;
+ }
+ fde_ev->ev = ev;
+ fde_ev->ctx = ctx;
+ DLIST_ADD(ctx->fde_evs, fde_ev);
+ talloc_set_destructor(
+ fde_ev, messaging_dgm_fde_ev_destructor);
+ } else {
+ /*
+ * Same trick as with tdb_wrap: The caller will never
+ * see the talloc_referenced object, the
+ * messaging_dgm_fde_ev, so problems with
+ * talloc_unlink will not happen.
+ */
+ if (talloc_reference(fde, fde_ev) == NULL) {
+ TALLOC_FREE(fde);
+ return NULL;
+ }
+ }
+
+ fde->fde = fde_ev->fde;
+ return fde;
+}
+
+bool messaging_dgm_fde_active(struct messaging_dgm_fde *fde)
+{
+ uint16_t flags;
+
+ if (fde == NULL) {
+ return false;
+ }
+ flags = tevent_fd_get_flags(fde->fde);
+ return (flags != 0);
+}
diff --git a/lib/messaging/messages_dgm.h b/lib/messaging/messages_dgm.h
new file mode 100644
index 0000000..7221c72
--- /dev/null
+++ b/lib/messaging/messages_dgm.h
@@ -0,0 +1,53 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * messages_dgm.c header
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MESSAGES_DGM_H_
+#define _MESSAGES_DGM_H_
+
+#include "replace.h"
+#include "system/filesys.h"
+#include <tevent.h>
+
+int messaging_dgm_init(struct tevent_context *ev,
+ uint64_t *unique,
+ const char *socket_dir,
+ const char *lockfile_dir,
+ void (*recv_cb)(struct tevent_context *ev,
+ const uint8_t *msg,
+ size_t msg_len,
+ int *fds,
+ size_t num_fds,
+ void *private_data),
+ void *recv_cb_private_data);
+void messaging_dgm_destroy(void);
+int messaging_dgm_get_unique(pid_t pid, uint64_t *unique);
+int messaging_dgm_send(pid_t pid,
+ const struct iovec *iov, int iovlen,
+ const int *fds, size_t num_fds);
+int messaging_dgm_cleanup(pid_t pid);
+int messaging_dgm_wipe(void);
+int messaging_dgm_forall(int (*fn)(pid_t pid, void *private_data),
+ void *private_data);
+
+struct messaging_dgm_fde;
+struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev);
+bool messaging_dgm_fde_active(struct messaging_dgm_fde *fde);
+
+#endif
diff --git a/lib/messaging/messages_dgm_ref.c b/lib/messaging/messages_dgm_ref.c
new file mode 100644
index 0000000..4e38c2d
--- /dev/null
+++ b/lib/messaging/messages_dgm_ref.c
@@ -0,0 +1,169 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba internal messaging functions
+ * Copyright (C) 2014 by Volker Lendecke
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "messages_dgm.h"
+#include "messages_dgm_ref.h"
+#include "lib/util/debug.h"
+#include "lib/util/dlinklist.h"
+
+struct msg_dgm_ref {
+ struct msg_dgm_ref *prev, *next;
+ struct messaging_dgm_fde *fde;
+ void (*recv_cb)(struct tevent_context *ev,
+ const uint8_t *msg, size_t msg_len,
+ int *fds, size_t num_fds, void *private_data);
+ void *recv_cb_private_data;
+};
+
+static pid_t dgm_pid = 0;
+static struct msg_dgm_ref *refs = NULL;
+static struct msg_dgm_ref *next_ref = NULL;
+
+static int msg_dgm_ref_destructor(struct msg_dgm_ref *r);
+static void msg_dgm_ref_recv(struct tevent_context *ev,
+ const uint8_t *msg, size_t msg_len,
+ int *fds, size_t num_fds, void *private_data);
+
+void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ uint64_t *unique,
+ const char *socket_dir,
+ const char *lockfile_dir,
+ void (*recv_cb)(struct tevent_context *ev,
+ const uint8_t *msg, size_t msg_len,
+ int *fds, size_t num_fds,
+ void *private_data),
+ void *recv_cb_private_data,
+ int *err)
+{
+ struct msg_dgm_ref *result, *tmp_refs;
+
+ result = talloc(mem_ctx, struct msg_dgm_ref);
+ if (result == NULL) {
+ *err = ENOMEM;
+ return NULL;
+ }
+ result->fde = NULL;
+
+ tmp_refs = refs;
+
+ if ((refs != NULL) && (dgm_pid != tevent_cached_getpid())) {
+ /*
+ * Have to reinit after fork
+ */
+ messaging_dgm_destroy();
+ refs = NULL;
+ }
+
+ if (refs == NULL) {
+ int ret;
+
+ ret = messaging_dgm_init(ev, unique, socket_dir, lockfile_dir,
+ msg_dgm_ref_recv, NULL);
+ DBG_DEBUG("messaging_dgm_init returned %s\n", strerror(ret));
+ if (ret != 0) {
+ DEBUG(10, ("messaging_dgm_init failed: %s\n",
+ strerror(ret)));
+ TALLOC_FREE(result);
+ *err = ret;
+ return NULL;
+ }
+ dgm_pid = tevent_cached_getpid();
+ } else {
+ int ret;
+ ret = messaging_dgm_get_unique(tevent_cached_getpid(), unique);
+ DBG_DEBUG("messaging_dgm_get_unique returned %s\n",
+ strerror(ret));
+ if (ret != 0) {
+ TALLOC_FREE(result);
+ *err = ret;
+ return NULL;
+ }
+
+ }
+
+ result->fde = messaging_dgm_register_tevent_context(result, ev);
+ if (result->fde == NULL) {
+ TALLOC_FREE(result);
+ *err = ENOMEM;
+ return NULL;
+ }
+
+ DBG_DEBUG("unique = %"PRIu64"\n", *unique);
+
+ refs = tmp_refs;
+
+ result->recv_cb = recv_cb;
+ result->recv_cb_private_data = recv_cb_private_data;
+ DLIST_ADD(refs, result);
+ talloc_set_destructor(result, msg_dgm_ref_destructor);
+
+ return result;
+}
+
+static void msg_dgm_ref_recv(struct tevent_context *ev,
+ const uint8_t *msg, size_t msg_len,
+ int *fds, size_t num_fds, void *private_data)
+{
+ struct msg_dgm_ref *r;
+
+ /*
+ * We have to broadcast incoming messages to all refs. The first ref
+ * that grabs the fd's will get them.
+ */
+ for (r = refs; r != NULL; r = next_ref) {
+ bool active;
+
+ next_ref = r->next;
+
+ active = messaging_dgm_fde_active(r->fde);
+ if (!active) {
+ /*
+ * r's tevent_context has died.
+ */
+ continue;
+ }
+
+ r->recv_cb(ev, msg, msg_len, fds, num_fds,
+ r->recv_cb_private_data);
+ }
+}
+
+static int msg_dgm_ref_destructor(struct msg_dgm_ref *r)
+{
+ if (refs == NULL) {
+ abort();
+ }
+
+ if (r == next_ref) {
+ next_ref = r->next;
+ }
+
+ DLIST_REMOVE(refs, r);
+
+ TALLOC_FREE(r->fde);
+
+ DBG_DEBUG("refs=%p\n", refs);
+
+ if (refs == NULL) {
+ messaging_dgm_destroy();
+ }
+ return 0;
+}
diff --git a/lib/messaging/messages_dgm_ref.h b/lib/messaging/messages_dgm_ref.h
new file mode 100644
index 0000000..cd77101
--- /dev/null
+++ b/lib/messaging/messages_dgm_ref.h
@@ -0,0 +1,38 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba internal messaging functions
+ * Copyright (C) 2014 by Volker Lendecke
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MESSAGES_DGM_REF_H_
+#define _MESSAGES_DGM_REF_H_
+
+#include <talloc.h>
+#include <tevent.h>
+#include "replace.h"
+
+void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ uint64_t *unique,
+ const char *socket_dir,
+ const char *lockfile_dir,
+ void (*recv_cb)(struct tevent_context *ev,
+ const uint8_t *msg, size_t msg_len,
+ int *fds, size_t num_fds,
+ void *private_data),
+ void *recv_cb_private_data,
+ int *err);
+
+#endif
diff --git a/lib/messaging/wscript_build b/lib/messaging/wscript_build
new file mode 100644
index 0000000..e22a60d
--- /dev/null
+++ b/lib/messaging/wscript_build
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('messages_dgm',
+ source='''
+ messages_dgm.c
+ messages_dgm_ref.c
+ ''',
+ deps='''
+ talloc
+ samba-debug
+ PTHREADPOOL
+ msghdr
+ genrand
+ samba-util
+ ''',
+ private_library=True)
diff --git a/lib/mscat/dumpmscat.c b/lib/mscat/dumpmscat.c
new file mode 100644
index 0000000..5364610
--- /dev/null
+++ b/lib/mscat/dumpmscat.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2016 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <talloc.h>
+
+#include <libtasn1.h>
+#include <gnutls/pkcs7.h>
+
+#include "mscat.h"
+
+static const char *mac_to_string(enum mscat_mac_algorithm algo) {
+ switch(algo) {
+ case MSCAT_MAC_NULL:
+ return "NULL";
+ case MSCAT_MAC_MD5:
+ return "MD5";
+ case MSCAT_MAC_SHA1:
+ return "SHA1";
+ case MSCAT_MAC_SHA256:
+ return "SHA256";
+ case MSCAT_MAC_SHA512:
+ return "SHA512";
+ case MSCAT_MAC_UNKNOWN:
+ return "UNKNOWN";
+ }
+
+ return "UNKNOWN";
+}
+
+int main(int argc, char *argv[]) {
+ TALLOC_CTX *mem_ctx;
+ const char *filename = NULL;
+ const char *ca_file = NULL;
+ struct mscat_pkcs7 *cat_pkcs7;
+ struct mscat_ctl *msctl;
+ unsigned int member_count = 0;
+ unsigned int attribute_count = 0;
+ unsigned int i;
+ int rc;
+
+ if (argc < 1) {
+ return -1;
+ }
+ filename = argv[1];
+
+ if (filename == NULL || filename[0] == '\0') {
+ return -1;
+ }
+
+ mem_ctx = talloc_init("dumpmscat");
+ if (mem_ctx == NULL) {
+ fprintf(stderr, "Failed to initialize talloc\n");
+ exit(1);
+ }
+
+ /* READ MS ROOT CERTIFICATE */
+
+ cat_pkcs7 = mscat_pkcs7_init(mem_ctx);
+ if (cat_pkcs7 == NULL) {
+ exit(1);
+ }
+
+ rc = mscat_pkcs7_import_catfile(cat_pkcs7,
+ filename);
+ if (rc != 0) {
+ exit(1);
+ }
+
+ if (argc >= 2) {
+ ca_file = argv[2];
+ }
+
+ rc = mscat_pkcs7_verify(cat_pkcs7, ca_file);
+ if (rc != 0) {
+ printf("FAILED TO VERIFY CATALOG FILE!\n");
+ exit(1);
+ }
+ printf("CATALOG FILE VERIFIED!\n\n");
+
+ msctl = mscat_ctl_init(mem_ctx);
+ if (msctl == NULL) {
+ exit(1);
+ }
+
+ rc = mscat_ctl_import(msctl, cat_pkcs7);
+ if (rc < 0) {
+ exit(1);
+ }
+
+ rc = mscat_ctl_get_member_count(msctl);
+ if (rc < 0) {
+ exit(1);
+ }
+
+ member_count = rc;
+ printf("CATALOG MEMBER COUNT=%d\n", member_count);
+
+ for (i = 0; i < member_count; i++) {
+ struct mscat_ctl_member *m;
+ size_t j;
+
+ rc = mscat_ctl_get_member(msctl,
+ mem_ctx,
+ i + 1,
+ &m);
+ if (rc != 0) {
+ exit(1);
+ }
+
+ printf("CATALOG MEMBER\n");
+ if (m->checksum.type == MSCAT_CHECKSUM_STRING) {
+ printf(" CHECKSUM: %s\n", m->checksum.string);
+ } else if (m->checksum.type == MSCAT_CHECKSUM_BLOB) {
+ printf(" CHECKSUM: ");
+ for (j = 0; j < m->checksum.size; j++) {
+ printf("%X", m->checksum.blob[j]);
+ }
+ printf("\n");
+ }
+ printf("\n");
+
+ if (m->file.name != NULL) {
+ printf(" FILE: %s, FLAGS=0x%08x\n",
+ m->file.name,
+ m->file.flags);
+ }
+
+ if (m->info.guid != NULL) {
+ printf(" GUID: %s, ID=0x%08x\n",
+ m->info.guid,
+ m->info.id);
+ }
+
+ if (m->osattr.value != NULL) {
+ printf(" OSATTR: %s, FLAGS=0x%08x\n",
+ m->osattr.value,
+ m->osattr.flags);
+ }
+
+ if (m->mac.type != MSCAT_MAC_UNKNOWN) {
+ printf(" MAC: %s, DIGEST: ",
+ mac_to_string(m->mac.type));
+ for (j = 0; j < m->mac.digest_size; j++) {
+ printf("%X", m->mac.digest[j]);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+ printf("\n");
+
+ rc = mscat_ctl_get_attribute_count(msctl);
+ if (rc < 0) {
+ exit(1);
+ }
+ attribute_count = rc;
+ printf("CATALOG ATTRIBUTE COUNT=%d\n", attribute_count);
+
+ for (i = 0; i < attribute_count; i++) {
+ struct mscat_ctl_attribute *a;
+
+ rc = mscat_ctl_get_attribute(msctl,
+ mem_ctx,
+ i + 1,
+ &a);
+ if (rc != 0) {
+ exit(1);
+ }
+
+ printf(" NAME=%s, FLAGS=0x%08x, VALUE=%s\n",
+ a->name,
+ a->flags,
+ a->value);
+ }
+ talloc_free(mem_ctx);
+ return 0;
+}
diff --git a/lib/mscat/mscat.asn b/lib/mscat/mscat.asn
new file mode 100644
index 0000000..a4bdd05
--- /dev/null
+++ b/lib/mscat/mscat.asn
@@ -0,0 +1,136 @@
+--
+-- ASN.1 Description for Microsoft Catalog Files
+--
+-- Copyright 2016 Andreas Schneider <asn@samba.org>
+-- Copyright 2016 Nikos Mavrogiannopoulos <nmav@redhat.com>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published
+-- by the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+--
+CATALOG {}
+DEFINITIONS IMPLICIT TAGS ::= -- assuming implicit tags, should try explicit too
+
+BEGIN
+
+-- CATALOG_NAME_VALUE
+CatalogNameValue ::= SEQUENCE { -- 180
+ name BMPString,
+ flags INTEGER, -- 10010001
+ value OCTET STRING -- UTF-16-LE
+}
+
+-- CATALOG_MEMBER_INFO
+CatalogMemberInfo ::= SEQUENCE {
+ name BMPString,
+ id INTEGER -- 0200
+}
+
+CatalogMemberInfo2 ::= SEQUENCE {
+ memId OBJECT IDENTIFIER,
+ unknown SET OF SpcLink
+}
+
+-- SPC_INDIRECT_DATA
+SpcIndirectData ::= SEQUENCE {
+ data SpcAttributeTypeAndOptionalValue,
+ messageDigest DigestInfo
+}
+
+SpcAttributeTypeAndOptionalValue ::= SEQUENCE {
+ type OBJECT IDENTIFIER,
+ value ANY DEFINED BY type OPTIONAL
+}
+
+DigestInfo ::= SEQUENCE {
+ digestAlgorithm AlgorithmIdentifier,
+ digest OCTET STRING
+}
+
+AlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY DEFINED BY algorithm OPTIONAL
+ -- contains a value of the type
+}
+
+-- SPC_PE_IMAGE_DATA
+SpcPEImageData ::= SEQUENCE {
+ flags SpcPeImageFlags DEFAULT includeResources,
+ link [0] EXPLICIT SpcLink OPTIONAL
+}
+
+SpcPeImageFlags ::= BIT STRING {
+ includeResources (0),
+ includeDebugInfo (1),
+ includeImportAddressTable (2)
+}
+
+SpcLink ::= CHOICE {
+ url [0] IMPLICIT IA5String,
+ moniker [1] IMPLICIT SpcSerializedObject,
+ file [2] EXPLICIT SpcString
+}
+
+SpcSerializedObject ::= SEQUENCE {
+ classId OCTET STRING, -- GUID
+ data OCTET STRING -- Binary structure
+}
+
+SpcString ::= CHOICE {
+ unicode [0] IMPLICIT BMPString,
+ ascii [1] IMPLICIT IA5String
+}
+
+-- SPC_IMAGE_DATA_FILE
+SpcImageDataFile ::= SEQUENCE {
+ flags BIT STRING,
+ file SpcLink
+}
+
+-----------------------------------------------------------
+-- CERT_TRUST_LIST STRUCTURE
+-----------------------------------------------------------
+
+CatalogListId ::= SEQUENCE {
+ oid OBJECT IDENTIFIER
+}
+
+CatalogListMemberId ::= SEQUENCE {
+ oid OBJECT IDENTIFIER,
+ optional NULL
+}
+
+MemberAttribute ::= SEQUENCE {
+ contentType OBJECT IDENTIFIER,
+ content SET OF ANY DEFINED BY contentType
+}
+
+CatalogListMember ::= SEQUENCE {
+ checksum OCTET STRING, -- The member checksum (e.g. SHA1)
+ attributes SET OF MemberAttribute OPTIONAL
+}
+
+CatalogAttribute ::= SEQUENCE {
+ dataId OBJECT IDENTIFIER,
+ encapsulated_data OCTET STRING -- encapsulates CatNameValue or SpcPeImageData
+}
+
+CertTrustList ::= SEQUENCE {
+ catalogListId CatalogListId,
+ unknownString OCTET STRING, -- 16 bytes MD5 hash?
+ trustUtcTime UTCTime,
+ catalogListMemberId CatalogListMemberId,
+ members SEQUENCE OF CatalogListMember,
+ attributes [0] EXPLICIT SEQUENCE OF CatalogAttribute OPTIONAL
+}
+
+END
diff --git a/lib/mscat/mscat.h b/lib/mscat/mscat.h
new file mode 100644
index 0000000..fbf60ff
--- /dev/null
+++ b/lib/mscat/mscat.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MSCAT_H
+#define _MSCAT_H
+
+#include <stdbool.h>
+#include <talloc.h>
+#include <gnutls/pkcs7.h>
+#include <libtasn1.h>
+
+enum mscat_mac_algorithm {
+ MSCAT_MAC_UNKNOWN,
+ MSCAT_MAC_NULL,
+ MSCAT_MAC_MD5,
+ MSCAT_MAC_SHA1,
+ MSCAT_MAC_SHA256,
+ MSCAT_MAC_SHA512
+};
+
+struct mscat_pkcs7;
+
+struct mscat_pkcs7 *mscat_pkcs7_init(TALLOC_CTX *mem_ctx);
+
+int mscat_pkcs7_import_catfile(struct mscat_pkcs7 *mp7,
+ const char *catfile);
+
+int mscat_pkcs7_verify(struct mscat_pkcs7 *mp7,
+ const char *ca_file);
+
+struct mscat_ctl;
+
+struct mscat_ctl *mscat_ctl_init(TALLOC_CTX *mem_ctx);
+
+int mscat_ctl_import(struct mscat_ctl *ctl,
+ struct mscat_pkcs7 *pkcs7);
+
+int mscat_ctl_get_member_count(struct mscat_ctl *ctl);
+
+enum mscat_checksum_type {
+ MSCAT_CHECKSUM_STRING = 1,
+ MSCAT_CHECKSUM_BLOB
+};
+
+struct mscat_ctl_member {
+ struct {
+ enum mscat_checksum_type type;
+ union {
+ const char *string;
+ uint8_t *blob;
+ };
+ size_t size;
+ } checksum;
+ struct {
+ const char *name;
+ uint32_t flags;
+ } file;
+ struct {
+ const char *value;
+ uint32_t flags;
+ } osattr;
+ struct {
+ const char *guid;
+ uint32_t id;
+ } info;
+ struct {
+ enum mscat_mac_algorithm type;
+ uint8_t *digest;
+ size_t digest_size;
+ } mac;
+};
+
+int mscat_ctl_get_member(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ unsigned int idx,
+ struct mscat_ctl_member **member);
+
+int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl);
+
+struct mscat_ctl_attribute {
+ const char *name;
+ uint32_t flags;
+ const char *value;
+};
+
+int mscat_ctl_get_attribute(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ unsigned int idx,
+ struct mscat_ctl_attribute **pattribute);
+
+#endif /* _MSCAT_H */
diff --git a/lib/mscat/mscat_ctl.c b/lib/mscat/mscat_ctl.c
new file mode 100644
index 0000000..292aa9a
--- /dev/null
+++ b/lib/mscat/mscat_ctl.c
@@ -0,0 +1,1197 @@
+/*
+ * Copyright (c) 2016 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <util/debug.h>
+#include <util/byteorder.h>
+#include <util/data_blob.h>
+#include <charset.h>
+
+#include "mscat.h"
+#include "mscat_private.h"
+
+#define ASN1_NULL_DATA "\x05\x00"
+#define ASN1_NULL_DATA_SIZE 2
+
+#define HASH_SHA1_OBJID "1.3.14.3.2.26"
+#define HASH_SHA256_OBJID "2.16.840.1.101.3.4.2.1"
+#define HASH_SHA512_OBJID "2.16.840.1.101.3.4.2.3"
+
+#define SPC_INDIRECT_DATA_OBJID "1.3.6.1.4.1.311.2.1.4"
+#define SPC_PE_IMAGE_DATA_OBJID "1.3.6.1.4.1.311.2.1.15"
+
+#define CATALOG_LIST_OBJOID "1.3.6.1.4.1.311.12.1.1"
+#define CATALOG_LIST_MEMBER_OBJOID "1.3.6.1.4.1.311.12.1.2"
+#define CATALOG_LIST_MEMBER_V2_OBJOID "1.3.6.1.4.1.311.12.1.3"
+
+#define CAT_NAME_VALUE_OBJID "1.3.6.1.4.1.311.12.2.1"
+#define CAT_MEMBERINFO_OBJID "1.3.6.1.4.1.311.12.2.2"
+
+extern const asn1_static_node mscat_asn1_tab[];
+
+struct mscat_ctl {
+ int version;
+ asn1_node asn1_desc;
+ asn1_node tree_ctl;
+ gnutls_datum_t raw_ctl;
+};
+
+static char *mscat_asn1_get_oid(TALLOC_CTX *mem_ctx,
+ asn1_node root,
+ const char *oid_name)
+{
+ char oid_str[32] = {0};
+ int oid_len = sizeof(oid_str);
+ int rc;
+
+ rc = asn1_read_value(root,
+ oid_name,
+ oid_str,
+ &oid_len);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to read value '%s': %s\n",
+ oid_name,
+ asn1_strerror(rc));
+ return NULL;
+ }
+
+ return talloc_strndup(mem_ctx, oid_str, oid_len);
+}
+
+static bool mscat_asn1_oid_equal(const char *o1, const char *o2)
+{
+ int cmp;
+
+ cmp = strcmp(o1, o2);
+ if (cmp != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+static int mscat_asn1_read_value(TALLOC_CTX *mem_ctx,
+ asn1_node root,
+ const char *name,
+ DATA_BLOB *blob)
+{
+ DATA_BLOB tmp = data_blob_null;
+ unsigned int etype = ASN1_ETYPE_INVALID;
+ int tmp_len = 0;
+ size_t len;
+ int rc;
+
+ rc = asn1_read_value_type(root, name, NULL, &tmp_len, &etype);
+ if (rc != ASN1_SUCCESS) {
+ return rc;
+ }
+ len = tmp_len;
+
+ if (etype == ASN1_ETYPE_BIT_STRING) {
+ if (len + 7 < len) {
+ return -1;
+ }
+ len = (len + 7) / 8;
+ }
+
+ if (len == 0) {
+ *blob = data_blob_null;
+ return 0;
+ }
+
+ if (len + 1 < len) {
+ return -1;
+ }
+ tmp = data_blob_talloc_zero(mem_ctx, len + 1);
+ if (tmp.data == NULL) {
+ return -1;
+ }
+
+ rc = asn1_read_value(root,
+ name,
+ tmp.data,
+ &tmp_len);
+ if (rc != ASN1_SUCCESS) {
+ data_blob_free(&tmp);
+ return rc;
+ }
+ len = tmp_len;
+
+ if (etype == ASN1_ETYPE_BIT_STRING) {
+ if (len + 7 < len) {
+ return -1;
+ }
+ len = (len + 7) / 8;
+ }
+ tmp.length = len;
+
+ *blob = tmp;
+
+ return 0;
+}
+
+static int mscat_ctl_cleanup(struct mscat_ctl *ctl)
+{
+ if (ctl->asn1_desc != NULL) {
+ asn1_delete_structure(&ctl->asn1_desc);
+ }
+
+ return 0;
+}
+
+struct mscat_ctl *mscat_ctl_init(TALLOC_CTX *mem_ctx)
+{
+ char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
+ struct mscat_ctl *cat_ctl = NULL;
+ int rc;
+
+ cat_ctl = talloc_zero(mem_ctx, struct mscat_ctl);
+ if (cat_ctl == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(cat_ctl, mscat_ctl_cleanup);
+
+ cat_ctl->asn1_desc = NULL;
+ cat_ctl->tree_ctl = NULL;
+
+ rc = asn1_array2tree(mscat_asn1_tab,
+ &cat_ctl->asn1_desc,
+ error_string);
+ if (rc != ASN1_SUCCESS) {
+ talloc_free(cat_ctl);
+ DBG_ERR("Failed to create parser tree: %s - %s\n",
+ asn1_strerror(rc),
+ error_string);
+ return NULL;
+ }
+
+ return cat_ctl;
+}
+
+int mscat_ctl_import(struct mscat_ctl *ctl,
+ struct mscat_pkcs7 *pkcs7)
+{
+ char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *oid;
+ bool ok;
+ int rc;
+
+ rc = gnutls_pkcs7_get_embedded_data(pkcs7->c,
+ GNUTLS_PKCS7_EDATA_GET_RAW,
+ &ctl->raw_ctl);
+ if (rc != GNUTLS_E_SUCCESS) {
+ DBG_ERR("Failed to get embedded data from pkcs7: %s\n",
+ gnutls_strerror(rc));
+ return -1;
+ }
+
+ rc = asn1_create_element(ctl->asn1_desc,
+ "CATALOG.CertTrustList",
+ &ctl->tree_ctl);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to create CertTrustList ASN.1 element - %s\n",
+ asn1_strerror(rc));
+ return -1;
+ }
+
+ rc = asn1_der_decoding(&ctl->tree_ctl,
+ ctl->raw_ctl.data,
+ ctl->raw_ctl.size,
+ error_string);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to parse ASN.1 CertTrustList: %s - %s\n",
+ asn1_strerror(rc),
+ error_string);
+ return -1;
+ }
+
+ tmp_ctx = talloc_new(ctl);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ oid = mscat_asn1_get_oid(tmp_ctx,
+ ctl->tree_ctl,
+ "catalogListId.oid");
+ if (oid == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_OBJOID);
+ if (!ok) {
+ DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID\n",
+ oid);
+ rc = -1;
+ goto done;
+ }
+ talloc_free(oid);
+
+ oid = mscat_asn1_get_oid(tmp_ctx,
+ ctl->tree_ctl,
+ "catalogListMemberId.oid");
+ if (oid == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_V2_OBJOID);
+ if (ok) {
+ ctl->version = 2;
+ } else {
+ ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_OBJOID);
+ if (ok) {
+ ctl->version = 1;
+ } else {
+ DBG_ERR("Invalid oid (%s), expected "
+ "CATALOG_LIST_MEMBER_OBJOID\n",
+ oid);
+ rc = -1;
+ goto done;
+ }
+ }
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int ctl_get_member_checksum_string(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ unsigned int idx,
+ const char **pchecksum,
+ size_t *pchecksum_size)
+{
+ TALLOC_CTX *tmp_ctx;
+ DATA_BLOB chksum_ucs2 = data_blob_null;
+ size_t converted_size = 0;
+ char *checksum = NULL;
+ char *element = NULL;
+ int rc = -1;
+ bool ok;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ element = talloc_asprintf(tmp_ctx,
+ "members.?%u.checksum",
+ idx);
+ if (element == NULL) {
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ ctl->tree_ctl,
+ element,
+ &chksum_ucs2);
+ talloc_free(element);
+ if (rc != 0) {
+ goto done;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16LE,
+ CH_UNIX,
+ chksum_ucs2.data,
+ chksum_ucs2.length,
+ &checksum,
+ &converted_size);
+ if (!ok) {
+ rc = -1;
+ goto done;
+ }
+
+ *pchecksum_size = strlen(checksum) + 1;
+ *pchecksum = talloc_move(mem_ctx, &checksum);
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int ctl_get_member_checksum_blob(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ unsigned int idx,
+ uint8_t **pchecksum,
+ size_t *pchecksum_size)
+{
+ TALLOC_CTX *tmp_ctx;
+ DATA_BLOB chksum = data_blob_null;
+ char *element = NULL;
+ int rc = -1;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ element = talloc_asprintf(tmp_ctx,
+ "members.?%u.checksum",
+ idx);
+ if (element == NULL) {
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ ctl->tree_ctl,
+ element,
+ &chksum);
+ talloc_free(element);
+ if (rc != 0) {
+ goto done;
+ }
+
+ *pchecksum = talloc_move(mem_ctx, &chksum.data);
+ *pchecksum_size = chksum.length;
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int ctl_parse_name_value(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *content,
+ char **pname,
+ uint32_t *pflags,
+ char **pvalue)
+{
+ char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
+ asn1_node name_value = NULL;
+ TALLOC_CTX *tmp_ctx;
+ DATA_BLOB name_blob = data_blob_null;
+ DATA_BLOB flags_blob = data_blob_null;
+ DATA_BLOB value_blob = data_blob_null;
+ size_t converted_size = 0;
+ bool ok;
+ int rc;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ rc = asn1_create_element(ctl->asn1_desc,
+ "CATALOG.CatalogNameValue",
+ &name_value);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to create element for "
+ "CATALOG.CatalogNameValue: %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = asn1_der_decoding(&name_value,
+ content->data,
+ content->length,
+ error_string);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to decode CATALOG.CatalogNameValue: %s - %s\n",
+ asn1_strerror(rc),
+ error_string);
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(mem_ctx,
+ name_value,
+ "name",
+ &name_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to read 'name': %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(mem_ctx,
+ name_value,
+ "flags",
+ &flags_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to read 'flags': %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(mem_ctx,
+ name_value,
+ "value",
+ &value_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to read 'value': %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16BE,
+ CH_UNIX,
+ name_blob.data,
+ name_blob.length,
+ pname,
+ &converted_size);
+ if (!ok) {
+ rc = ASN1_MEM_ERROR;
+ goto done;
+ }
+
+ *pflags = RIVAL(flags_blob.data, 0);
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16LE,
+ CH_UNIX,
+ value_blob.data,
+ value_blob.length,
+ pvalue,
+ &converted_size);
+ if (!ok) {
+ rc = ASN1_MEM_ERROR;
+ goto done;
+ }
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int ctl_parse_member_info(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *content,
+ char **pname,
+ uint32_t *pid)
+{
+ char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
+ asn1_node member_info = NULL;
+ TALLOC_CTX *tmp_ctx;
+ DATA_BLOB name_blob = data_blob_null;
+ DATA_BLOB id_blob = data_blob_null;
+ size_t converted_size = 0;
+ bool ok;
+ int rc;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ rc = asn1_create_element(ctl->asn1_desc,
+ "CATALOG.CatalogMemberInfo",
+ &member_info);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to create element for "
+ "CATALOG.CatalogMemberInfo: %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = asn1_der_decoding(&member_info,
+ content->data,
+ content->length,
+ error_string);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to decode CATALOG.CatalogMemberInfo: %s - %s\n",
+ asn1_strerror(rc),
+ error_string);
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(mem_ctx,
+ member_info,
+ "name",
+ &name_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to read 'name': %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(mem_ctx,
+ member_info,
+ "id",
+ &id_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to read 'id': %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16BE,
+ CH_UNIX,
+ name_blob.data,
+ name_blob.length,
+ pname,
+ &converted_size);
+ if (!ok) {
+ rc = ASN1_MEM_ERROR;
+ goto done;
+ }
+
+ *pid = RSVAL(id_blob.data, 0);
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+
+static int ctl_spc_pe_image_data(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *content,
+ char **pfile)
+{
+ char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
+ asn1_node spc_pe_image_data = NULL;
+ DATA_BLOB flags_blob = data_blob_null;
+ DATA_BLOB choice_blob = data_blob_null;
+ char *file = NULL;
+ TALLOC_CTX *tmp_ctx;
+ int cmp;
+ int rc;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ rc = asn1_create_element(ctl->asn1_desc,
+ "CATALOG.SpcPEImageData",
+ &spc_pe_image_data);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to create element for "
+ "CATALOG.SpcPEImageData: %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = asn1_der_decoding(&spc_pe_image_data,
+ content->data,
+ content->length,
+ error_string);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to decode CATALOG.SpcPEImageData: %s - %s\n",
+ asn1_strerror(rc),
+ error_string);
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ spc_pe_image_data,
+ "flags",
+ &flags_blob);
+ if (rc == ASN1_SUCCESS) {
+ uint32_t flags = RIVAL(flags_blob.data, 0);
+
+ DBG_ERR(">>> SPC_PE_IMAGE_DATA FLAGS=0x%08x\n",
+ flags);
+ } else {
+ DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ spc_pe_image_data,
+ "link",
+ &choice_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to parse 'link' in CATALOG.SpcPEImageData - %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ cmp = strncmp((char *)choice_blob.data, "url", choice_blob.length);
+ if (cmp == 0) {
+ /* Never seen in a printer catalog file yet */
+ DBG_INFO("Please report a Samba bug and attach the catalog "
+ "file\n");
+ }
+
+ cmp = strncmp((char *)choice_blob.data, "moniker", choice_blob.length);
+ if (cmp == 0) {
+ /* Never seen in a printer catalog file yet */
+ DBG_INFO("Please report a Samba bug and attach the catalog "
+ "file\n");
+ }
+
+ cmp = strncmp((char *)choice_blob.data, "file", choice_blob.length);
+ if (cmp == 0) {
+ DATA_BLOB file_blob;
+ char *link;
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ spc_pe_image_data,
+ "link.file",
+ &choice_blob);
+ if (rc != ASN1_SUCCESS) {
+ goto done;
+ }
+
+ link = talloc_asprintf(tmp_ctx, "link.file.%s", (char *)choice_blob.data);
+ if (link == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ spc_pe_image_data,
+ link,
+ &file_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to read '%s' - %s\n",
+ link,
+ asn1_strerror(rc));
+ rc = -1;
+ goto done;
+ }
+
+ cmp = strncmp((char *)choice_blob.data, "unicode", choice_blob.length);
+ if (cmp == 0) {
+ size_t converted_size = 0;
+ bool ok;
+
+ ok = convert_string_talloc(tmp_ctx,
+ CH_UTF16BE,
+ CH_UNIX,
+ file_blob.data,
+ file_blob.length,
+ &file,
+ &converted_size);
+ if (!ok) {
+ rc = -1;
+ goto done;
+ }
+ }
+
+ cmp = strncmp((char *)choice_blob.data, "ascii", choice_blob.length);
+ if (cmp == 0) {
+ file = talloc_strndup(tmp_ctx,
+ (char *)file_blob.data,
+ file_blob.length);
+ if (file == NULL) {
+ rc = -1;
+ goto done;
+ }
+ }
+ }
+
+ if (file != NULL) {
+ *pfile = talloc_move(mem_ctx, &file);
+ }
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int ctl_spc_indirect_data(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *content,
+ enum mscat_mac_algorithm *pmac_algorithm,
+ uint8_t **pdigest,
+ size_t *pdigest_size)
+{
+ char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0};
+ asn1_node spc_indirect_data = NULL;
+ TALLOC_CTX *tmp_ctx;
+ enum mscat_mac_algorithm mac_algorithm = MSCAT_MAC_UNKNOWN;
+ const char *oid = NULL;
+ DATA_BLOB data_value_blob = data_blob_null;
+ DATA_BLOB digest_parameters_blob = data_blob_null;
+ DATA_BLOB digest_blob = data_blob_null;
+ bool ok;
+ int rc;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ rc = asn1_create_element(ctl->asn1_desc,
+ "CATALOG.SpcIndirectData",
+ &spc_indirect_data);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to create element for "
+ "CATALOG.SpcIndirectData: %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ rc = asn1_der_decoding(&spc_indirect_data,
+ content->data,
+ content->length,
+ error_string);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to decode CATALOG.SpcIndirectData: %s - %s\n",
+ asn1_strerror(rc),
+ error_string);
+ goto done;
+ }
+
+ oid = mscat_asn1_get_oid(tmp_ctx,
+ spc_indirect_data,
+ "data.type");
+ if (oid == NULL) {
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ spc_indirect_data,
+ "data.value",
+ &data_value_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to find data.value in SpcIndirectData: %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ ok = mscat_asn1_oid_equal(oid, SPC_PE_IMAGE_DATA_OBJID);
+ if (ok) {
+ char *file = NULL;
+
+ rc = ctl_spc_pe_image_data(ctl,
+ tmp_ctx,
+ &data_value_blob,
+ &file);
+ if (rc != 0) {
+ goto done;
+ }
+
+ /* Just returns <<<Obsolete>>> as file */
+ DBG_NOTICE(">>> LINK: %s\n",
+ file);
+ }
+
+ oid = mscat_asn1_get_oid(tmp_ctx,
+ spc_indirect_data,
+ "messageDigest.digestAlgorithm.algorithm");
+ if (oid == NULL) {
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ spc_indirect_data,
+ "messageDigest.digestAlgorithm.parameters",
+ &digest_parameters_blob);
+ if (rc == ASN1_SUCCESS) {
+ /* Make sure we don't have garbage */
+ int cmp;
+
+ if (digest_parameters_blob.length != ASN1_NULL_DATA_SIZE) {
+ rc = -1;
+ goto done;
+ }
+ cmp = memcmp(digest_parameters_blob.data,
+ ASN1_NULL_DATA,
+ digest_parameters_blob.length);
+ if (cmp != 0) {
+ rc = -1;
+ goto done;
+ }
+ } else if (rc != ASN1_ELEMENT_NOT_FOUND) {
+ DBG_ERR("Failed to read 'messageDigest.digestAlgorithm.parameters': %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+
+ ok = mscat_asn1_oid_equal(oid, HASH_SHA1_OBJID);
+ if (ok) {
+ mac_algorithm = MSCAT_MAC_SHA1;
+ }
+
+ ok = mscat_asn1_oid_equal(oid, HASH_SHA256_OBJID);
+ if (ok) {
+ mac_algorithm = MSCAT_MAC_SHA256;
+ }
+
+ if (mac_algorithm != MSCAT_MAC_UNKNOWN &&
+ mac_algorithm != MSCAT_MAC_NULL) {
+ rc = mscat_asn1_read_value(tmp_ctx,
+ spc_indirect_data,
+ "messageDigest.digest",
+ &digest_blob);
+ if (rc != ASN1_SUCCESS) {
+ DBG_ERR("Failed to find messageDigest.digest in "
+ "SpcIndirectData: %s\n",
+ asn1_strerror(rc));
+ goto done;
+ }
+ }
+
+ *pmac_algorithm = mac_algorithm;
+ *pdigest = talloc_move(mem_ctx, &digest_blob.data);
+ *pdigest_size = digest_blob.length;
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int ctl_get_member_attributes(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ unsigned int idx,
+ struct mscat_ctl_member *m)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *el1 = NULL;
+ int count = 0;
+ int i;
+ int rc = -1;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ el1 = talloc_asprintf(tmp_ctx,
+ "members.?%u.attributes",
+ idx);
+ if (el1 == NULL) {
+ goto done;
+ }
+
+ rc = asn1_number_of_elements(ctl->tree_ctl,
+ el1,
+ &count);
+ if (rc != ASN1_SUCCESS) {
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ int content_start = 0;
+ int content_end = 0;
+ size_t content_len;
+ DATA_BLOB content;
+ char *el2;
+ char *oid;
+ bool ok;
+
+ el2 = talloc_asprintf(tmp_ctx,
+ "%s.?%d.contentType",
+ el1,
+ i + 1);
+ if (el2 == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ oid = mscat_asn1_get_oid(tmp_ctx,
+ ctl->tree_ctl,
+ el2);
+ talloc_free(el2);
+ if (oid == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ /* FIXME Looks like this is always 1 */
+ el2 = talloc_asprintf(tmp_ctx,
+ "%s.?%d.content.?1",
+ el1,
+ i + 1);
+ if (el2 == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ DBG_DEBUG("Decode element (startEnd) %s\n",
+ el2);
+
+ rc = asn1_der_decoding_startEnd(ctl->tree_ctl,
+ ctl->raw_ctl.data,
+ ctl->raw_ctl.size,
+ el2,
+ &content_start,
+ &content_end);
+ if (rc != ASN1_SUCCESS) {
+ goto done;
+ }
+ if (content_start < content_end) {
+ goto done;
+ }
+ content_len = content_end - content_start + 1;
+
+ DBG_DEBUG("Content data_blob length: %zu\n",
+ content_len);
+
+ content = data_blob_talloc_zero(tmp_ctx, content_len);
+ if (content.data == NULL) {
+ rc = -1;
+ goto done;
+ }
+ memcpy(content.data,
+ &ctl->raw_ctl.data[content_start],
+ content_len);
+
+ ok = mscat_asn1_oid_equal(oid, CAT_NAME_VALUE_OBJID);
+ if (ok) {
+ char *name;
+ uint32_t flags;
+ char *value;
+ int cmp;
+
+ rc = ctl_parse_name_value(ctl,
+ tmp_ctx,
+ &content,
+ &name,
+ &flags,
+ &value);
+ if (rc != 0) {
+ goto done;
+ }
+
+ DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s\n",
+ name,
+ flags,
+ value);
+
+ cmp = strcmp(name, "File");
+ if (cmp == 0) {
+ m->file.name = talloc_move(m, &value);
+ m->file.flags = flags;
+
+ continue;
+ }
+
+ cmp = strcmp(name, "OSAttr");
+ if (cmp == 0) {
+ m->osattr.value = talloc_move(m, &value);
+ m->osattr.flags = flags;
+
+ continue;
+ }
+ }
+
+ ok = mscat_asn1_oid_equal(oid, CAT_MEMBERINFO_OBJID);
+ if (ok) {
+ char *name = NULL;
+ uint32_t id = 0;
+
+ rc = ctl_parse_member_info(ctl,
+ tmp_ctx,
+ &content,
+ &name,
+ &id);
+ if (rc != 0) {
+ goto done;
+ }
+
+ m->info.guid = talloc_move(m, &name);
+ m->info.id = id;
+
+ continue;
+ }
+
+ ok = mscat_asn1_oid_equal(oid, SPC_INDIRECT_DATA_OBJID);
+ if (ok) {
+ rc = ctl_spc_indirect_data(ctl,
+ m,
+ &content,
+ &m->mac.type,
+ &m->mac.digest,
+ &m->mac.digest_size);
+ if (rc != 0) {
+ goto done;
+ }
+
+ continue;
+ }
+ }
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+int mscat_ctl_get_member(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ unsigned int idx,
+ struct mscat_ctl_member **pmember)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct mscat_ctl_member *m = NULL;
+ int rc = -1;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ m = talloc_zero(tmp_ctx, struct mscat_ctl_member);
+ if (m == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ if (ctl->version == 1) {
+ m->checksum.type = MSCAT_CHECKSUM_STRING;
+ rc = ctl_get_member_checksum_string(ctl,
+ m,
+ idx,
+ &m->checksum.string,
+ &m->checksum.size);
+ } else if (ctl->version == 2) {
+ m->checksum.type = MSCAT_CHECKSUM_BLOB;
+ rc = ctl_get_member_checksum_blob(ctl,
+ m,
+ idx,
+ &m->checksum.blob,
+ &m->checksum.size);
+ }
+ if (rc != 0) {
+ goto done;
+ }
+
+ rc = ctl_get_member_attributes(ctl,
+ mem_ctx,
+ idx,
+ m);
+ if (rc != 0) {
+ goto done;
+ }
+
+ *pmember = talloc_move(mem_ctx, &m);
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+int mscat_ctl_get_member_count(struct mscat_ctl *ctl)
+{
+ int count = 0;
+ int rc;
+
+ rc = asn1_number_of_elements(ctl->tree_ctl,
+ "members",
+ &count);
+ if (rc != ASN1_SUCCESS) {
+ return -1;
+ }
+
+ return count;
+}
+
+int mscat_ctl_get_attribute(struct mscat_ctl *ctl,
+ TALLOC_CTX *mem_ctx,
+ unsigned int idx,
+ struct mscat_ctl_attribute **pattribute)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *el1 = NULL;
+ const char *el2 = NULL;
+ const char *oid = NULL;
+ char *name = NULL;
+ uint32_t flags = 0;
+ char *value = NULL;
+ struct mscat_ctl_attribute *a = NULL;
+ DATA_BLOB encapsulated_data_blob = data_blob_null;
+ int rc;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ a = talloc_zero(tmp_ctx, struct mscat_ctl_attribute);
+ if (a == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ el1 = talloc_asprintf(tmp_ctx,
+ "attributes.?%u.dataId",
+ idx);
+ if (el1 == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ oid = mscat_asn1_get_oid(tmp_ctx,
+ ctl->tree_ctl,
+ el1);
+ if (oid == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ el2 = talloc_asprintf(tmp_ctx,
+ "attributes.?%u.encapsulated_data",
+ idx);
+ if (el2 == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ rc = mscat_asn1_read_value(tmp_ctx,
+ ctl->tree_ctl,
+ el2,
+ &encapsulated_data_blob);
+ if (rc != ASN1_SUCCESS) {
+ goto done;
+ }
+
+ rc = ctl_parse_name_value(ctl,
+ tmp_ctx,
+ &encapsulated_data_blob,
+ &name,
+ &flags,
+ &value);
+ if (rc != 0) {
+ goto done;
+ }
+
+ a->name = talloc_move(a, &name);
+ a->flags = flags;
+ a->value = talloc_move(a, &value);
+
+ *pattribute = talloc_move(mem_ctx, &a);
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl)
+{
+ int count = 0;
+ int rc;
+
+ rc = asn1_number_of_elements(ctl->tree_ctl,
+ "attributes",
+ &count);
+ if (rc != ASN1_SUCCESS) {
+ return -1;
+ }
+
+ return count;
+}
diff --git a/lib/mscat/mscat_pkcs7.c b/lib/mscat/mscat_pkcs7.c
new file mode 100644
index 0000000..07d8514
--- /dev/null
+++ b/lib/mscat/mscat_pkcs7.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2016 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <util/debug.h>
+#include <util/data_blob.h>
+
+#include "mscat.h"
+#include "mscat_private.h"
+
+#define PKCS7_CTL_OBJID "1.3.6.1.4.1.311.10.1"
+
+static int mscat_pkcs7_cleanup(struct mscat_pkcs7 *mp7)
+{
+ if (mp7->c != NULL) {
+ gnutls_pkcs7_deinit(mp7->c);
+ }
+
+ return 0;
+}
+
+struct mscat_pkcs7 *mscat_pkcs7_init(TALLOC_CTX *mem_ctx)
+{
+ struct mscat_pkcs7 *pkcs7;
+ int rc;
+
+ pkcs7 = talloc_zero(mem_ctx, struct mscat_pkcs7);
+ if (pkcs7 == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(pkcs7, mscat_pkcs7_cleanup);
+
+ rc = gnutls_pkcs7_init(&pkcs7->c);
+ if (rc != 0) {
+ talloc_free(pkcs7);
+ return NULL;
+ }
+
+ return pkcs7;
+}
+
+static int mscat_read_file(TALLOC_CTX *mem_ctx,
+ const char *filename,
+ DATA_BLOB *pblob)
+{
+ struct stat sb = {0};
+ size_t alloc_size;
+ size_t count;
+ DATA_BLOB blob = data_blob_null;
+ FILE *fp;
+ int rc;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ rc = fstat(fileno(fp), &sb);
+ if (rc != 0) {
+ goto error;
+ }
+
+ if (!S_ISREG(sb.st_mode)) {
+ errno = EINVAL;
+ rc = -1;
+ goto error;
+ }
+ if (SIZE_MAX - 1 < (unsigned long)sb.st_size) {
+ errno = ENOMEM;
+ rc = -1;
+ goto error;
+ }
+ alloc_size = sb.st_size + 1;
+
+ blob = data_blob_talloc_zero(mem_ctx, alloc_size);
+ if (blob.data == NULL) {
+ rc = -1;
+ goto error;
+ }
+
+ count = fread(blob.data, 1, blob.length, fp);
+ if (count != blob.length) {
+ if (ferror(fp)) {
+ rc = -1;
+ goto error;
+ }
+ }
+ blob.data[count] = '\0';
+ blob.length = count;
+ fclose(fp);
+
+ *pblob = blob;
+
+ return 0;
+error:
+ data_blob_free(&blob);
+ fclose(fp);
+ return rc;
+}
+
+int mscat_pkcs7_import_catfile(struct mscat_pkcs7 *mp7,
+ const char *catfile)
+{
+ TALLOC_CTX *tmp_ctx;
+ gnutls_datum_t mscat_data = {
+ .size = 0,
+ };
+ DATA_BLOB blob = {
+ .length = 0,
+ };
+ int rc;
+
+ tmp_ctx = talloc_new(mp7);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ rc = mscat_read_file(tmp_ctx,
+ catfile,
+ &blob);
+ if (rc == -1) {
+ DBG_ERR("Failed to read catalog file '%s' - %s\n",
+ catfile,
+ strerror(errno));
+ goto done;
+ }
+
+ mscat_data.data = blob.data;
+ mscat_data.size = blob.length;
+
+ rc = gnutls_pkcs7_import(mp7->c,
+ &mscat_data,
+ GNUTLS_X509_FMT_DER);
+ if (rc < 0) {
+ DBG_ERR("Failed to import PKCS7 from '%s' - %s\n",
+ catfile,
+ gnutls_strerror(rc));
+ goto done;
+ }
+
+ rc = 0;
+done:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+int mscat_pkcs7_verify(struct mscat_pkcs7 *mp7,
+ const char *ca_file)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ gnutls_x509_trust_list_t tl = NULL;
+ gnutls_datum_t ca_data;
+ DATA_BLOB blob = {
+ .length = 0,
+ };
+ uint32_t flags = 0;
+ const char *oid;
+ int count;
+ int cmp;
+ int rc;
+ int i;
+
+ oid = gnutls_pkcs7_get_embedded_data_oid(mp7->c);
+ if (oid == NULL) {
+ DBG_ERR("Failed to get oid - %s\n",
+ gnutls_strerror(errno));
+ return -1;
+ }
+
+ cmp = strcmp(oid, PKCS7_CTL_OBJID);
+ if (cmp != 0) {
+ DBG_ERR("Invalid oid in catalog file! oid: %s, expected: %s\n",
+ oid,
+ PKCS7_CTL_OBJID);
+ return -1;
+ }
+
+ tmp_ctx = talloc_new(mp7);
+ if (tmp_ctx == NULL) {
+ return -1;
+ }
+
+ rc = gnutls_x509_trust_list_init(&tl,
+ 0); /* default size */
+ if (rc != 0) {
+ DBG_ERR("Failed to create trust list - %s\n",
+ gnutls_strerror(rc));
+ goto done;
+ }
+
+
+ /* Load the system trust list */
+ rc = gnutls_x509_trust_list_add_system_trust(tl, 0, 0);
+ if (rc < 0) {
+ DBG_ERR("Failed to add system trust list - %s\n",
+ gnutls_strerror(rc));
+ goto done;
+ }
+ DBG_INFO("Loaded %d CAs\n", rc);
+
+ if (ca_file != NULL) {
+ rc = mscat_read_file(tmp_ctx,
+ ca_file,
+ &blob);
+ if (rc != 0) {
+ DBG_ERR("Failed to read CA file '%s' - %s\n",
+ ca_file,
+ strerror(errno));
+ goto done;
+ }
+
+ ca_data.data = blob.data;
+ ca_data.size = blob.length;
+
+ rc = gnutls_x509_trust_list_add_trust_mem(tl,
+ &ca_data,
+ NULL, /* crls */
+ GNUTLS_X509_FMT_DER,
+ 0, /* tl_flags */
+ 0); /* tl_vflags */
+ if (rc < 0) {
+ DBG_ERR("Failed to add '%s' to trust list - %s (%d)\n",
+ ca_file,
+ gnutls_strerror(rc),
+ rc);
+ goto done;
+ }
+ DBG_INFO("Loaded %d additional CAs\n", rc);
+ }
+
+ /*
+ * Drivers often exist for quite some time, so it is possible that one
+ * of the certificates in the trust list expired.
+ * This is not a big deal, but we need to disable the time checks
+ * or the verification will fail.
+ */
+ flags = GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS|
+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS;
+
+#if GNUTLS_VERSION_NUMBER >= 0x030600
+ /* The "Microsoft Root Authority" certificate uses SHA1 */
+ flags |= GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1;
+#endif
+
+ count = gnutls_pkcs7_get_signature_count(mp7->c);
+ if (count == 0) {
+ DBG_ERR("Failed to verify catalog file, no signatures found\n");
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ rc = gnutls_pkcs7_verify(mp7->c,
+ tl,
+ NULL, /* vdata */
+ 0, /* vdata_size */
+ i, /* index */
+ NULL, /* data */
+ flags); /* flags */
+ if (rc < 0) {
+ DBG_ERR("Failed to verify catalog file - %s (%d)\n",
+ gnutls_strerror(rc),
+ rc);
+ goto done;
+ }
+ }
+
+ rc = 0;
+done:
+ gnutls_x509_trust_list_deinit(tl, 1);
+ talloc_free(tmp_ctx);
+ return rc;
+}
diff --git a/lib/mscat/mscat_private.h b/lib/mscat/mscat_private.h
new file mode 100644
index 0000000..d79b364
--- /dev/null
+++ b/lib/mscat/mscat_private.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MSCAT_PRIVATE_H
+#define _MSCAT_PRIVATE_H
+
+#include <gnutls/pkcs7.h>
+
+struct mscat_pkcs7 {
+ gnutls_pkcs7_t c;
+};
+
+#endif /* _MSCAT_PRIVATE_H */
diff --git a/lib/mscat/wscript b/lib/mscat/wscript
new file mode 100644
index 0000000..00eb1d4
--- /dev/null
+++ b/lib/mscat/wscript
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+import os
+import sys
+from waflib import Logs
+
+def configure(conf):
+ pkg_name = 'libtasn1'
+ pkg_minversion = '3.8'
+
+ if conf.CHECK_BUNDLED_SYSTEM_PKG(pkg_name, minversion=pkg_minversion):
+ if not conf.find_program('asn1Parser', var='ASN1PARSER'):
+ Logs.warn('WARNING: ans1Parser hasn\'t been found! Please install it (e.g. libtasn1-bin)')
+
+def build(bld):
+ if (bld.CONFIG_SET('HAVE_LIBTASN1') and
+ bld.env.ASN1PARSER):
+
+ bld.SAMBA_GENERATOR('MSCAT_PARSER',
+ source='mscat.asn',
+ target='mscat_asn1_tab.c',
+ rule='${ASN1PARSER} --output ${TGT} ${SRC}',
+ group='build_source')
+
+ bld.SAMBA_LIBRARY('mscat',
+ source='''
+ mscat_asn1_tab.c
+ mscat_ctl.c
+ mscat_pkcs7.c
+ ''',
+ deps='''
+ talloc
+ gnutls
+ libtasn1
+ samba-util
+ ''',
+ private_library=True)
+
+ bld.SAMBA_BINARY('dumpmscat',
+ source='dumpmscat.c',
+ deps='mscat')
diff --git a/lib/param/README b/lib/param/README
new file mode 100644
index 0000000..11422f5
--- /dev/null
+++ b/lib/param/README
@@ -0,0 +1,86 @@
+libsamba-hostconfig
+-------------------
+
+This directory contains "libsamba-hostconfig".
+
+The libsamba-hostconfig library provides access to all host-wide configuration
+such as the configured shares, default parameter values and host secret keys.
+
+
+Adding a parameter
+------------------
+
+To add or change an smb.conf option, in general you only have to add
+the documentation to docs-xml/smbdotconf, or change it.
+In addition to that, if special defaults are needed, the functions
+loadparm_init() in lib/param/loadparm.c and/or init_globals() in
+source3/param/loadparm.c need to be adapted accordingly.
+The rest is generated for you.
+
+It is important to get the attributes right in the <samba:parameter ...>
+tag of the xml files. These determine the details of the generated code.
+
+- Supported attributes are name, context, type, constant, function,
+ generated_function, synonym, parm, enumlist, handler, and deprecated.
+- Supported contexts are 'G' (for global) and 'S' (for share).
+- Supported types are boolean, boolean-rev, boolean-auto, list,
+ cmdlist, string, ustring, char, integer, bytes, octal, and enum.
+
+
+
+Using smb.conf parameters in the code
+-------------------------------------
+
+Call the lpcfg_*() function. To get the lp_ctx, have the caller pass
+it to you. To get a lp_ctx for the source3/param loadparm system, use:
+
+struct loadparm_context *lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_helpers());
+
+Remember to talloc_unlink(tmp_ctx, lp_ctx) the result when you are done!
+
+To get a lp_ctx for the lib/param loadparm system, typically the
+pointer is already set up by popt at startup, and is passed down from
+cmdline_lp_ctx.
+
+In pure source3/ code, you may use lp_*() functions, but are
+encouraged to use the lpcfg_*() functions so that code can be made
+common.
+
+
+How does loadparm_init_s3() work?
+---------------------------------
+
+loadparm_s3_helpers() returns a initialised table of function
+pointers, pointing at all global lp_*() functions, except for those
+that return substituted strings (% macros). The lpcfg_*() function
+then calls this plugged in function, allowing the one function and
+pattern to use either loadparm system.
+
+
+There is a lot of generated code, here, what generates what?
+------------------------------------------------------------
+
+The regular format of the CPP macros in param_functions.c is used to
+generate up the prototypes (mkproto.pl, mks3param_proto.pl), the service
+and globals table (mkparamdefs.pl), the glue table (mmks3param.pl) and
+the initialisation of the glue table (mks3param_ctx_table.pl).
+
+I have tried combining some of these, but it just makes the scripts more
+complex.
+
+The CPP macros are defined in and expand in lib/param/loadparm.c and
+source3/param/loadparm.c to read the values from the generated
+structures. They are CPP #included into these files so that the same
+macro has two definitions, depending on the system it is loading into.
+
+
+Why was this done, rather than a 'proper' fix, or just using one system or the other?
+-------------------------------------------------------------------------------------
+
+This was done to allow merging from both ends - merging more parts of
+the loadparm handling, and merging code that needs to read the
+smb.conf, without having to do it all at once. Ideally
+param_functions.c would be generated from param_table.c or (even
+better) our XML manpage source, and the CPP macros would instead be
+generated expanded as generated C files, but this is a task nobody has
+taken on yet.
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
new file mode 100644
index 0000000..6ef29ed
--- /dev/null
+++ b/lib/param/loadparm.c
@@ -0,0 +1,3765 @@
+/*
+ Unix SMB/CIFS implementation.
+ Parameter loading functions
+ Copyright (C) Karl Auer 1993-1998
+
+ Largely re-written by Andrew Tridgell, September 1994
+
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Alexander Bokovoy 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James Myers 2003 <myersjj@samba.org>
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+ Copyright (C) Andrew Bartlett 2011-2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Load parameters.
+ *
+ * This module provides suitable callback functions for the params
+ * module. It builds the internal table of service details which is
+ * then used by the rest of the server.
+ *
+ * To add a parameter:
+ *
+ * 1) add it to the global or service structure definition
+ * 2) add it to the parm_table
+ * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
+ * 4) If it's a global then initialise it in init_globals. If a local
+ * (ie. service) parameter then initialise it in the sDefault structure
+ *
+ *
+ * Notes:
+ * The configuration file is processed sequentially for speed. It is NOT
+ * accessed randomly as happens in 'real' Windows. For this reason, there
+ * is a fair bit of sequence-dependent code here - ie., code which assumes
+ * that certain things happen before others. In particular, the code which
+ * happens at the boundary between sections is delicately poised, so be
+ * careful!
+ *
+ */
+
+#include "includes.h"
+#include "version.h"
+#include "dynconfig/dynconfig.h"
+#include "system/time.h"
+#include "system/locale.h"
+#include "system/network.h" /* needed for TCP_NODELAY */
+#include "../lib/util/dlinklist.h"
+#include "lib/param/param.h"
+#define LOADPARM_SUBSTITUTION_INTERNALS 1
+#include "lib/param/loadparm.h"
+#include "auth/gensec/gensec.h"
+#include "lib/param/s3_param.h"
+#include "lib/util/bitmap.h"
+#include "libcli/smb/smb_constants.h"
+#include "tdb.h"
+#include "librpc/gen_ndr/nbt.h"
+#include "librpc/gen_ndr/dns.h"
+#include "librpc/gen_ndr/security.h"
+#include "libds/common/roles.h"
+#include "lib/util/samba_util.h"
+#include "libcli/auth/ntlm_check.h"
+#include "lib/crypto/gnutls_helpers.h"
+#include "lib/util/smb_strtox.h"
+#include "auth/credentials/credentials.h"
+
+#ifdef HAVE_HTTPCONNECTENCRYPT
+#include <cups/http.h>
+#endif
+
+#define standard_sub_basic talloc_strdup
+
+#include "lib/param/param_global.h"
+
+struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx)
+{
+ return lp_ctx->sDefault;
+}
+
+int lpcfg_rpc_low_port(struct loadparm_context *lp_ctx)
+{
+ return lp_ctx->globals->rpc_low_port;
+}
+
+int lpcfg_rpc_high_port(struct loadparm_context *lp_ctx)
+{
+ return lp_ctx->globals->rpc_high_port;
+}
+
+enum samba_weak_crypto lpcfg_weak_crypto(struct loadparm_context *lp_ctx)
+{
+ if (lp_ctx->globals->weak_crypto == SAMBA_WEAK_CRYPTO_UNKNOWN) {
+ lp_ctx->globals->weak_crypto = SAMBA_WEAK_CRYPTO_DISALLOWED;
+
+ if (samba_gnutls_weak_crypto_allowed()) {
+ lp_ctx->globals->weak_crypto = SAMBA_WEAK_CRYPTO_ALLOWED;
+ }
+ }
+
+ return lp_ctx->globals->weak_crypto;
+}
+
+/**
+ * Convenience routine to grab string parameters into temporary memory
+ * and run standard_sub_basic on them.
+ *
+ * The buffers can be written to by
+ * callers without affecting the source string.
+ */
+
+static const char *lpcfg_string(const char *s)
+{
+#if 0 /* until REWRITE done to make thread-safe */
+ size_t len = s ? strlen(s) : 0;
+ char *ret;
+#endif
+
+ /* The follow debug is useful for tracking down memory problems
+ especially if you have an inner loop that is calling a lp_*()
+ function that returns a string. Perhaps this debug should be
+ present all the time? */
+
+#if 0
+ DEBUG(10, ("lpcfg_string(%s)\n", s));
+#endif
+
+#if 0 /* until REWRITE done to make thread-safe */
+ if (!lp_talloc)
+ lp_talloc = talloc_init("lp_talloc");
+
+ ret = talloc_array(lp_talloc, char, len + 100); /* leave room for substitution */
+
+ if (!ret)
+ return NULL;
+
+ if (!s)
+ *ret = 0;
+ else
+ strlcpy(ret, s, len);
+
+ if (trim_string(ret, "\"", "\"")) {
+ if (strchr(ret,'"') != NULL)
+ strlcpy(ret, s, len);
+ }
+
+ standard_sub_basic(ret,len+100);
+ return (ret);
+#endif
+ return s;
+}
+
+/*
+ In this section all the functions that are used to access the
+ parameters from the rest of the program are defined
+*/
+
+/*
+ * the creation of separate lpcfg_*() and lp_*() functions is to allow
+ * for code compatibility between existing Samba4 and Samba3 code.
+ */
+
+/* this global context supports the lp_*() function variants */
+static struct loadparm_context *global_loadparm_context;
+
+#define FN_GLOBAL_SUBSTITUTED_STRING(fn_name,var_name) \
+ _PUBLIC_ char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx, \
+ const struct loadparm_substitution *lp_sub, TALLOC_CTX *mem_ctx) \
+{ \
+ if (lp_ctx == NULL) return NULL; \
+ return lpcfg_substituted_string(mem_ctx, lp_sub, \
+ lp_ctx->globals->var_name ? lp_ctx->globals->var_name : ""); \
+}
+
+#define FN_GLOBAL_CONST_STRING(fn_name,var_name) \
+ _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
+ if (lp_ctx == NULL) return NULL; \
+ return lp_ctx->globals->var_name ? lpcfg_string(lp_ctx->globals->var_name) : ""; \
+}
+
+#define FN_GLOBAL_LIST(fn_name,var_name) \
+ _PUBLIC_ const char **lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
+ if (lp_ctx == NULL) return NULL; \
+ return lp_ctx->globals->var_name; \
+ }
+
+#define FN_GLOBAL_BOOL(fn_name,var_name) \
+ _PUBLIC_ bool lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) {\
+ if (lp_ctx == NULL) return false; \
+ return lp_ctx->globals->var_name; \
+}
+
+#define FN_GLOBAL_INTEGER(fn_name,var_name) \
+ _PUBLIC_ int lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
+ return lp_ctx->globals->var_name; \
+ }
+
+/* Local parameters don't need the ->s3_fns because the struct
+ * loadparm_service is shared and lpcfg_service() checks the ->s3_fns
+ * hook */
+#define FN_LOCAL_SUBSTITUTED_STRING(fn_name,val) \
+ _PUBLIC_ char *lpcfg_ ## fn_name(struct loadparm_service *service, \
+ struct loadparm_service *sDefault, TALLOC_CTX *ctx) { \
+ return(talloc_strdup(ctx, lpcfg_string((const char *)((service != NULL && service->val != NULL) ? service->val : sDefault->val)))); \
+ }
+
+#define FN_LOCAL_CONST_STRING(fn_name,val) \
+ _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_service *service, \
+ struct loadparm_service *sDefault) { \
+ return((const char *)((service != NULL && service->val != NULL) ? service->val : sDefault->val)); \
+ }
+
+#define FN_LOCAL_LIST(fn_name,val) \
+ _PUBLIC_ const char **lpcfg_ ## fn_name(struct loadparm_service *service, \
+ struct loadparm_service *sDefault) {\
+ return(const char **)(service != NULL && service->val != NULL? service->val : sDefault->val); \
+ }
+
+#define FN_LOCAL_PARM_BOOL(fn_name, val) FN_LOCAL_BOOL(fn_name, val)
+
+#define FN_LOCAL_BOOL(fn_name,val) \
+ _PUBLIC_ bool lpcfg_ ## fn_name(struct loadparm_service *service, \
+ struct loadparm_service *sDefault) { \
+ return((service != NULL)? service->val : sDefault->val); \
+ }
+
+#define FN_LOCAL_INTEGER(fn_name,val) \
+ _PUBLIC_ int lpcfg_ ## fn_name(struct loadparm_service *service, \
+ struct loadparm_service *sDefault) { \
+ return((service != NULL)? service->val : sDefault->val); \
+ }
+
+#define FN_LOCAL_PARM_INTEGER(fn_name, val) FN_LOCAL_INTEGER(fn_name, val)
+
+#define FN_LOCAL_CHAR(fn_name,val) \
+ _PUBLIC_ char lpcfg_ ## fn_name(struct loadparm_service *service, \
+ struct loadparm_service *sDefault) { \
+ return((service != NULL)? service->val : sDefault->val); \
+ }
+
+#define FN_LOCAL_PARM_CHAR(fn_name,val) FN_LOCAL_CHAR(fn_name, val)
+
+#include "lib/param/param_functions.c"
+
+/* These functions cannot be auto-generated */
+FN_LOCAL_BOOL(autoloaded, autoloaded)
+FN_GLOBAL_CONST_STRING(dnsdomain, dnsdomain)
+
+/* local prototypes */
+static struct loadparm_service *lpcfg_getservicebyname(struct loadparm_context *lp_ctx,
+ const char *pszServiceName);
+static bool do_section(const char *pszSectionName, void *);
+static bool set_variable_helper(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
+ const char *pszParmName, const char *pszParmValue);
+static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmName,
+ const char *pszParmValue, int flags);
+
+/* The following are helper functions for parametrical options support. */
+/* It returns a pointer to parametrical option value if it exists or NULL otherwise */
+/* Actual parametrical functions are quite simple */
+struct parmlist_entry *get_parametric_helper(struct loadparm_service *service,
+ const char *type, const char *option,
+ struct parmlist_entry *global_opts)
+{
+ size_t type_len = strlen(type);
+ size_t option_len = strlen(option);
+ char param_key[type_len + option_len + 2];
+ struct parmlist_entry *data = NULL;
+
+ snprintf(param_key, sizeof(param_key), "%s:%s", type, option);
+
+ /*
+ * Try to fetch the option from the data.
+ */
+ if (service != NULL) {
+ data = service->param_opt;
+ while (data != NULL) {
+ if (strwicmp(data->key, param_key) == 0) {
+ return data;
+ }
+ data = data->next;
+ }
+ }
+
+ /*
+ * Fall back to fetching from the globals.
+ */
+ data = global_opts;
+ while (data != NULL) {
+ if (strwicmp(data->key, param_key) == 0) {
+ return data;
+ }
+ data = data->next;
+ }
+
+ return NULL;
+}
+
+const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *type, const char *option)
+{
+ struct parmlist_entry *data;
+
+ if (lp_ctx == NULL)
+ return NULL;
+
+ data = get_parametric_helper(service,
+ type, option, lp_ctx->globals->param_opt);
+
+ if (data == NULL) {
+ return NULL;
+ } else {
+ return data->value;
+ }
+}
+
+
+/**
+ * convenience routine to return int parameters.
+ */
+int lp_int(const char *s)
+{
+
+ if (!s || !*s) {
+ DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
+ return -1;
+ }
+
+ return strtol(s, NULL, 0);
+}
+
+/**
+ * convenience routine to return unsigned long parameters.
+ */
+unsigned long lp_ulong(const char *s)
+{
+ int error = 0;
+ unsigned long int ret;
+
+ if (!s || !*s) {
+ DBG_DEBUG("lp_ulong(%s): is called with NULL!\n",s);
+ return -1;
+ }
+
+ ret = smb_strtoul(s, NULL, 0, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ DBG_DEBUG("lp_ulong(%s): conversion failed\n",s);
+ return -1;
+ }
+
+ return ret;
+}
+
+/**
+ * convenience routine to return unsigned long long parameters.
+ */
+unsigned long long lp_ulonglong(const char *s)
+{
+ int error = 0;
+ unsigned long long int ret;
+
+ if (!s || !*s) {
+ DBG_DEBUG("lp_ulonglong(%s): is called with NULL!\n", s);
+ return -1;
+ }
+
+ ret = smb_strtoull(s, NULL, 0, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ DBG_DEBUG("lp_ulonglong(%s): conversion failed\n",s);
+ return -1;
+ }
+
+ return ret;
+}
+
+/**
+ * convenience routine to return unsigned long parameters.
+ */
+static long lp_long(const char *s)
+{
+
+ if (!s) {
+ DEBUG(0,("lp_long(%s): is called with NULL!\n",s));
+ return -1;
+ }
+
+ return strtol(s, NULL, 0);
+}
+
+/**
+ * convenience routine to return unsigned long parameters.
+ */
+static double lp_double(const char *s)
+{
+
+ if (!s) {
+ DEBUG(0,("lp_double(%s): is called with NULL!\n",s));
+ return -1;
+ }
+
+ return strtod(s, NULL);
+}
+
+/**
+ * convenience routine to return boolean parameters.
+ */
+bool lp_bool(const char *s)
+{
+ bool ret = false;
+
+ if (!s || !*s) {
+ DEBUG(0,("lp_bool(%s): is called with NULL!\n",s));
+ return false;
+ }
+
+ if (!set_boolean(s, &ret)) {
+ DEBUG(0,("lp_bool(%s): value is not boolean!\n",s));
+ return false;
+ }
+
+ return ret;
+}
+
+/**
+ * Return parametric option from a given service. Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ * Returned value is allocated in 'lp_talloc' context
+ */
+
+const char *lpcfg_parm_string(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value)
+ return lpcfg_string(value);
+
+ return NULL;
+}
+
+/**
+ * Return parametric option from a given service. Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ * Returned value is allocated in 'lp_talloc' context
+ */
+
+const char **lpcfg_parm_string_list(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *type,
+ const char *option, const char *separator)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value != NULL) {
+ char **l = str_list_make(mem_ctx, value, separator);
+ return discard_const_p(const char *, l);
+ }
+
+ return NULL;
+}
+
+/**
+ * Return parametric option from a given service. Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ */
+
+int lpcfg_parm_int(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, int default_v)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value)
+ return lp_int(value);
+
+ return default_v;
+}
+
+/**
+ * Return parametric option from a given service. Type is a part of
+ * option before ':'.
+ * Parametric option has following syntax: 'Type: option = value'.
+ */
+
+int lpcfg_parm_bytes(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, int default_v)
+{
+ uint64_t bval;
+
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value && conv_str_size_error(value, &bval)) {
+ if (bval <= INT_MAX) {
+ return (int)bval;
+ }
+ }
+
+ return default_v;
+}
+
+/**
+ * Return parametric option from a given service.
+ * Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ */
+unsigned long lpcfg_parm_ulong(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, unsigned long default_v)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value)
+ return lp_ulong(value);
+
+ return default_v;
+}
+
+/**
+ * Return parametric option from a given service.
+ * Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ */
+unsigned long long lpcfg_parm_ulonglong(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *type, const char *option,
+ unsigned long long default_v)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value) {
+ return lp_ulonglong(value);
+ }
+
+ return default_v;
+}
+
+long lpcfg_parm_long(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, long default_v)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value)
+ return lp_long(value);
+
+ return default_v;
+}
+
+double lpcfg_parm_double(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, double default_v)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value != NULL)
+ return lp_double(value);
+
+ return default_v;
+}
+
+/**
+ * Return parametric option from a given service. Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ */
+
+bool lpcfg_parm_bool(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, bool default_v)
+{
+ const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+ if (value != NULL)
+ return lp_bool(value);
+
+ return default_v;
+}
+
+
+/* this is used to prevent lots of mallocs of size 1 */
+static const char lpcfg_string_empty[] = "";
+
+/**
+ Free a string value.
+**/
+void lpcfg_string_free(char **s)
+{
+ if (s == NULL) {
+ return;
+ }
+ if (*s == lpcfg_string_empty) {
+ *s = NULL;
+ return;
+ }
+ TALLOC_FREE(*s);
+}
+
+/**
+ * Set a string value, deallocating any existing space, and allocing the space
+ * for the string
+ */
+bool lpcfg_string_set(TALLOC_CTX *mem_ctx, char **dest, const char *src)
+{
+ lpcfg_string_free(dest);
+
+ if ((src == NULL) || (*src == '\0')) {
+ *dest = discard_const_p(char, lpcfg_string_empty);
+ return true;
+ }
+
+ *dest = talloc_strdup(mem_ctx, src);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_set\n"));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Set a string value, deallocating any existing space, and allocing the space
+ * for the string
+ */
+bool lpcfg_string_set_upper(TALLOC_CTX *mem_ctx, char **dest, const char *src)
+{
+ lpcfg_string_free(dest);
+
+ if ((src == NULL) || (*src == '\0')) {
+ *dest = discard_const_p(char, lpcfg_string_empty);
+ return true;
+ }
+
+ *dest = strupper_talloc(mem_ctx, src);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_set_upper\n"));
+ return false;
+ }
+
+ return true;
+}
+
+
+
+/**
+ * Add a new service to the services array initialising it with the given
+ * service.
+ */
+
+struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
+ const struct loadparm_service *pservice,
+ const char *name)
+{
+ int i;
+ int num_to_alloc = lp_ctx->iNumServices + 1;
+ struct parmlist_entry *data, *pdata;
+
+ if (lp_ctx->s3_fns != NULL) {
+ smb_panic("Add a service should not be called on an s3 loadparm ctx");
+ }
+
+ if (pservice == NULL) {
+ pservice = lp_ctx->sDefault;
+ }
+
+ /* it might already exist */
+ if (name) {
+ struct loadparm_service *service = lpcfg_getservicebyname(lp_ctx,
+ name);
+ if (service != NULL) {
+ /* Clean all parametric options for service */
+ /* They will be added during parsing again */
+ data = service->param_opt;
+ while (data) {
+ pdata = data->next;
+ talloc_free(data);
+ data = pdata;
+ }
+ service->param_opt = NULL;
+ return service;
+ }
+ }
+
+ /* find an invalid one */
+ for (i = 0; i < lp_ctx->iNumServices; i++)
+ if (lp_ctx->services[i] == NULL)
+ break;
+
+ /* if not, then create one */
+ if (i == lp_ctx->iNumServices) {
+ struct loadparm_service **tsp;
+
+ tsp = talloc_realloc(lp_ctx, lp_ctx->services, struct loadparm_service *, num_to_alloc);
+
+ if (!tsp) {
+ DEBUG(0,("lpcfg_add_service: failed to enlarge services!\n"));
+ return NULL;
+ } else {
+ lp_ctx->services = tsp;
+ lp_ctx->services[lp_ctx->iNumServices] = NULL;
+ }
+
+ lp_ctx->iNumServices++;
+ }
+
+ lp_ctx->services[i] = talloc_zero(lp_ctx->services, struct loadparm_service);
+ if (lp_ctx->services[i] == NULL) {
+ DEBUG(0,("lpcfg_add_service: out of memory!\n"));
+ return NULL;
+ }
+ copy_service(lp_ctx->services[i], pservice, NULL);
+ if (name != NULL)
+ lpcfg_string_set(lp_ctx->services[i], &lp_ctx->services[i]->szService, name);
+ return lp_ctx->services[i];
+}
+
+/**
+ * Map a parameter's string representation to something we can use.
+ * Returns False if the parameter string is not recognised, else TRUE.
+ */
+
+int lpcfg_map_parameter(const char *pszParmName)
+{
+ int iIndex;
+
+ for (iIndex = 0; parm_table[iIndex].label; iIndex++)
+ if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
+ return iIndex;
+
+ /* Warn only if it isn't parametric option */
+ if (strchr(pszParmName, ':') == NULL)
+ DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
+ /* We do return 'fail' for parametric options as well because they are
+ stored in different storage
+ */
+ return -1;
+}
+
+
+/**
+ return the parameter structure for a parameter
+*/
+struct parm_struct *lpcfg_parm_struct(struct loadparm_context *lp_ctx, const char *name)
+{
+ int num = lpcfg_map_parameter(name);
+
+ if (num < 0) {
+ return NULL;
+ }
+
+ return &parm_table[num];
+}
+
+/**
+ return the parameter pointer for a parameter
+*/
+void *lpcfg_parm_ptr(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, struct parm_struct *parm)
+{
+ if (lp_ctx->s3_fns) {
+ return lp_ctx->s3_fns->get_parm_ptr(service, parm);
+ }
+
+ if (service == NULL) {
+ if (parm->p_class == P_LOCAL)
+ return ((char *)lp_ctx->sDefault)+parm->offset;
+ else if (parm->p_class == P_GLOBAL)
+ return ((char *)lp_ctx->globals)+parm->offset;
+ else return NULL;
+ } else {
+ return ((char *)service) + parm->offset;
+ }
+}
+
+/**
+ return the parameter pointer for a parameter
+*/
+bool lpcfg_parm_is_cmdline(struct loadparm_context *lp_ctx, const char *name)
+{
+ int parmnum;
+
+ parmnum = lpcfg_map_parameter(name);
+ if (parmnum == -1) return false;
+
+ return lp_ctx->flags[parmnum] & FLAG_CMDLINE;
+}
+
+bool lpcfg_parm_is_unspecified(struct loadparm_context *lp_ctx, const char *name)
+{
+ int parmnum;
+
+ parmnum = lpcfg_map_parameter(name);
+ if (parmnum == -1) return false;
+
+ return lp_ctx->flags[parmnum] & FLAG_DEFAULT;
+}
+
+/**
+ * Find a service by name. Otherwise works like get_service.
+ */
+
+static struct loadparm_service *lpcfg_getservicebyname(struct loadparm_context *lp_ctx,
+ const char *pszServiceName)
+{
+ int iService;
+
+ if (lp_ctx->s3_fns) {
+ return lp_ctx->s3_fns->get_service(pszServiceName);
+ }
+
+ for (iService = lp_ctx->iNumServices - 1; iService >= 0; iService--)
+ if (lp_ctx->services[iService] != NULL &&
+ strwicmp(lp_ctx->services[iService]->szService, pszServiceName) == 0) {
+ return lp_ctx->services[iService];
+ }
+
+ return NULL;
+}
+
+/**
+ * Add a parametric option to a parmlist_entry,
+ * replacing old value, if already present.
+ */
+void set_param_opt(TALLOC_CTX *mem_ctx,
+ struct parmlist_entry **opt_list,
+ const char *opt_name,
+ const char *opt_value,
+ unsigned priority)
+{
+ struct parmlist_entry *new_opt, *opt;
+
+ opt = *opt_list;
+
+ /* Traverse destination */
+ while (opt) {
+ /* If we already have same option, override it */
+ if (strwicmp(opt->key, opt_name) == 0) {
+ if ((opt->priority & FLAG_CMDLINE) &&
+ !(priority & FLAG_CMDLINE)) {
+ /* it's been marked as not to be
+ overridden */
+ return;
+ }
+ TALLOC_FREE(opt->list);
+ lpcfg_string_set(opt, &opt->value, opt_value);
+ opt->priority = priority;
+ return;
+ }
+ opt = opt->next;
+ }
+
+ new_opt = talloc_pooled_object(
+ mem_ctx, struct parmlist_entry,
+ 2, strlen(opt_name) + 1 + strlen(opt_value) + 1);
+ if (new_opt == NULL) {
+ smb_panic("OOM");
+ }
+ new_opt->key = NULL;
+ lpcfg_string_set(new_opt, &new_opt->key, opt_name);
+ new_opt->value = NULL;
+ lpcfg_string_set(new_opt, &new_opt->value, opt_value);
+
+ new_opt->list = NULL;
+ new_opt->priority = priority;
+ DLIST_ADD(*opt_list, new_opt);
+}
+
+/**
+ * Copy a service structure to another.
+ * If pcopymapDest is NULL then copy all fields
+ */
+
+void copy_service(struct loadparm_service *pserviceDest,
+ const struct loadparm_service *pserviceSource,
+ struct bitmap *pcopymapDest)
+{
+ int i;
+ bool bcopyall = (pcopymapDest == NULL);
+ struct parmlist_entry *data;
+
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].p_class == P_LOCAL &&
+ (bcopyall || bitmap_query(pcopymapDest, i))) {
+ const void *src_ptr =
+ ((const char *)pserviceSource) + parm_table[i].offset;
+ void *dest_ptr =
+ ((char *)pserviceDest) + parm_table[i].offset;
+
+ switch (parm_table[i].type) {
+ case P_BOOL:
+ case P_BOOLREV:
+ *(bool *)dest_ptr = *(const bool *)src_ptr;
+ break;
+
+ case P_INTEGER:
+ case P_BYTES:
+ case P_OCTAL:
+ case P_ENUM:
+ *(int *)dest_ptr = *(const int *)src_ptr;
+ break;
+
+ case P_CHAR:
+ *(char *)dest_ptr = *(const char *)src_ptr;
+ break;
+
+ case P_STRING:
+ lpcfg_string_set(pserviceDest,
+ (char **)dest_ptr,
+ *(const char * const *)src_ptr);
+ break;
+
+ case P_USTRING:
+ lpcfg_string_set_upper(pserviceDest,
+ (char **)dest_ptr,
+ *(const char * const *)src_ptr);
+ break;
+ case P_CMDLIST:
+ case P_LIST:
+ TALLOC_FREE(*((char ***)dest_ptr));
+ *(char ***)dest_ptr = str_list_copy(pserviceDest,
+ *discard_const_p(const char **, src_ptr));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (bcopyall) {
+ init_copymap(pserviceDest);
+ if (pserviceSource->copymap)
+ bitmap_copy(pserviceDest->copymap,
+ pserviceSource->copymap);
+ }
+
+ for (data = pserviceSource->param_opt; data != NULL; data = data->next) {
+ set_param_opt(pserviceDest, &pserviceDest->param_opt,
+ data->key, data->value, data->priority);
+ }
+}
+
+/**
+ * Check a service for consistency. Return False if the service is in any way
+ * incomplete or faulty, else True.
+ */
+bool lpcfg_service_ok(struct loadparm_service *service)
+{
+ bool bRetval;
+
+ bRetval = true;
+ if (service->szService[0] == '\0') {
+ DEBUG(0, ("The following message indicates an internal error:\n"));
+ DEBUG(0, ("No service name in service entry.\n"));
+ bRetval = false;
+ }
+
+ /* The [printers] entry MUST be printable. I'm all for flexibility, but */
+ /* I can't see why you'd want a non-printable printer service... */
+ if (strwicmp(service->szService, PRINTERS_NAME) == 0) {
+ if (!service->printable) {
+ DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
+ service->szService));
+ service->printable = true;
+ }
+ /* [printers] service must also be non-browsable. */
+ if (service->browseable)
+ service->browseable = false;
+ }
+
+ if (service->path[0] == '\0' &&
+ strwicmp(service->szService, HOMES_NAME) != 0 &&
+ service->msdfs_proxy[0] == '\0')
+ {
+ DEBUG(0, ("WARNING: No path in service %s - making it unavailable!\n",
+ service->szService));
+ service->available = false;
+ }
+
+ if (!service->available)
+ DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
+ service->szService));
+
+ return bRetval;
+}
+
+
+/*******************************************************************
+ Keep a linked list of all config files so we know when one has changed
+ it's date and needs to be reloaded.
+********************************************************************/
+
+void add_to_file_list(TALLOC_CTX *mem_ctx, struct file_lists **list,
+ const char *fname, const char *subfname)
+{
+ struct file_lists *f = *list;
+
+ while (f) {
+ if (f->name && !strcmp(f->name, fname))
+ break;
+ f = f->next;
+ }
+
+ if (!f) {
+ f = talloc_zero(mem_ctx, struct file_lists);
+ if (!f)
+ goto fail;
+ f->next = *list;
+ f->name = talloc_strdup(f, fname);
+ if (!f->name) {
+ TALLOC_FREE(f);
+ goto fail;
+ }
+ f->subfname = talloc_strdup(f, subfname);
+ if (!f->subfname) {
+ TALLOC_FREE(f);
+ goto fail;
+ }
+ *list = f;
+ }
+
+ /* If file_modtime() fails it leaves f->modtime as zero. */
+ (void)file_modtime(subfname, &f->modtime);
+ return;
+
+fail:
+ DEBUG(0, ("Unable to add file to file list: %s\n", fname));
+
+}
+
+/*
+ * set the value for a P_ENUM
+ */
+bool lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue,
+ int *ptr )
+{
+ int i;
+
+ for (i = 0; parm->enum_list[i].name; i++) {
+ if (strwicmp(pszParmValue, parm->enum_list[i].name) == 0) {
+ *ptr = parm->enum_list[i].value;
+ return true;
+ }
+ }
+ DEBUG(0, ("WARNING: Ignoring invalid value '%s' for parameter '%s'\n",
+ pszParmValue, parm->label));
+ return false;
+}
+
+
+/***************************************************************************
+ Handle the "realm" parameter
+***************************************************************************/
+
+bool handle_realm(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ char *upper;
+ char *lower;
+
+ upper = strupper_talloc(lp_ctx, pszParmValue);
+ if (upper == NULL) {
+ return false;
+ }
+
+ lower = strlower_talloc(lp_ctx, pszParmValue);
+ if (lower == NULL) {
+ TALLOC_FREE(upper);
+ return false;
+ }
+
+ lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->realm, upper);
+ lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->dnsdomain, lower);
+
+ return true;
+}
+
+/***************************************************************************
+ Handle the include operation.
+***************************************************************************/
+
+bool handle_include(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ char *fname;
+ const char *substitution_variable_substring;
+ char next_char;
+
+ if (lp_ctx->s3_fns) {
+ return lp_ctx->s3_fns->lp_include(lp_ctx, service, pszParmValue, ptr);
+ }
+
+ fname = standard_sub_basic(lp_ctx, pszParmValue);
+
+ add_to_file_list(lp_ctx, &lp_ctx->file_lists, pszParmValue, fname);
+
+ lpcfg_string_set(lp_ctx, ptr, fname);
+
+ if (file_exist(fname))
+ return pm_process(fname, do_section, lpcfg_do_parameter, lp_ctx);
+
+ /*
+ * If the file doesn't exist, we check that it isn't due to variable
+ * substitution
+ */
+ substitution_variable_substring = strchr(fname, '%');
+
+ if (substitution_variable_substring != NULL) {
+ next_char = substitution_variable_substring[1];
+ if ((next_char >= 'a' && next_char <= 'z')
+ || (next_char >= 'A' && next_char <= 'Z')) {
+ DEBUG(2, ("Tried to load %s but variable substitution in "
+ "filename, ignoring file.\n", fname));
+ return true;
+ }
+ }
+
+ DEBUG(2, ("Can't find include file %s\n", fname));
+
+ return false;
+}
+
+/***************************************************************************
+ Handle the interpretation of the copy parameter.
+***************************************************************************/
+
+bool handle_copy(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ bool bRetval;
+ struct loadparm_service *serviceTemp = NULL;
+
+ bRetval = false;
+
+ DEBUG(3, ("Copying service from service %s\n", pszParmValue));
+
+ serviceTemp = lpcfg_getservicebyname(lp_ctx, pszParmValue);
+
+ if (service == NULL) {
+ DEBUG(0, ("Unable to copy service - invalid service destination.\n"));
+ return false;
+ }
+
+ if (serviceTemp != NULL) {
+ if (serviceTemp == service) {
+ DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
+ } else {
+ copy_service(service,
+ serviceTemp,
+ service->copymap);
+ lpcfg_string_set(service, ptr, pszParmValue);
+
+ bRetval = true;
+ }
+ } else {
+ DEBUG(0, ("Unable to copy service - source not found: %s\n",
+ pszParmValue));
+ bRetval = false;
+ }
+
+ return bRetval;
+}
+
+bool handle_debug_list(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+
+ return debug_parse_levels(pszParmValue);
+}
+
+bool handle_logfile(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ if (lp_ctx->s3_fns == NULL) {
+ debug_set_logfile(pszParmValue);
+ }
+
+ lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+
+ return true;
+}
+
+/*
+ * These special charset handling methods only run in the source3 code.
+ */
+
+bool handle_charset(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ if (lp_ctx->s3_fns) {
+ if (*ptr == NULL || strcmp(*ptr, pszParmValue) != 0) {
+ struct smb_iconv_handle *ret = NULL;
+
+ ret = reinit_iconv_handle(NULL,
+ lpcfg_dos_charset(lp_ctx),
+ lpcfg_unix_charset(lp_ctx));
+ if (ret == NULL) {
+ smb_panic("reinit_iconv_handle failed");
+ }
+ }
+
+ }
+ return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+
+}
+
+bool handle_dos_charset(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ bool is_utf8 = false;
+ size_t len = strlen(pszParmValue);
+
+ if (lp_ctx->s3_fns) {
+ if (len == 4 || len == 5) {
+ /* Don't use StrCaseCmp here as we don't want to
+ initialize iconv. */
+ if ((toupper_m(pszParmValue[0]) == 'U') &&
+ (toupper_m(pszParmValue[1]) == 'T') &&
+ (toupper_m(pszParmValue[2]) == 'F')) {
+ if (len == 4) {
+ if (pszParmValue[3] == '8') {
+ is_utf8 = true;
+ }
+ } else {
+ if (pszParmValue[3] == '-' &&
+ pszParmValue[4] == '8') {
+ is_utf8 = true;
+ }
+ }
+ }
+ }
+
+ if (*ptr == NULL || strcmp(*ptr, pszParmValue) != 0) {
+ struct smb_iconv_handle *ret = NULL;
+ if (is_utf8) {
+ DEBUG(0,("ERROR: invalid DOS charset: 'dos charset' must not "
+ "be UTF8, using (default value) %s instead.\n",
+ DEFAULT_DOS_CHARSET));
+ pszParmValue = DEFAULT_DOS_CHARSET;
+ }
+ ret = reinit_iconv_handle(NULL,
+ lpcfg_dos_charset(lp_ctx),
+ lpcfg_unix_charset(lp_ctx));
+ if (ret == NULL) {
+ smb_panic("reinit_iconv_handle failed");
+ }
+ }
+ }
+
+ return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+}
+
+bool handle_printing(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ static int parm_num = -1;
+
+ if (parm_num == -1) {
+ parm_num = lpcfg_map_parameter("printing");
+ }
+
+ if (!lp_set_enum_parm(&parm_table[parm_num], pszParmValue, (int*)ptr)) {
+ return false;
+ }
+
+ if (lp_ctx->s3_fns) {
+ if (service == NULL) {
+ init_printer_values(lp_ctx, lp_ctx->globals->ctx, lp_ctx->sDefault);
+ } else {
+ init_printer_values(lp_ctx, service, service);
+ }
+ }
+
+ return true;
+}
+
+bool handle_ldap_debug_level(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ lp_ctx->globals->ldap_debug_level = lp_int(pszParmValue);
+
+ if (lp_ctx->s3_fns) {
+ lp_ctx->s3_fns->init_ldap_debugging();
+ }
+ return true;
+}
+
+/*
+ * idmap related parameters
+ */
+
+bool handle_idmap_backend(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ if (lp_ctx->s3_fns) {
+ lp_do_parameter_parametric(lp_ctx, service, "idmap config * : backend",
+ pszParmValue, 0);
+ }
+
+ return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+}
+
+bool handle_idmap_uid(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ if (lp_ctx->s3_fns) {
+ lp_do_parameter_parametric(lp_ctx, service, "idmap config * : range",
+ pszParmValue, 0);
+ }
+
+ return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+}
+
+bool handle_idmap_gid(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ if (lp_ctx->s3_fns) {
+ lp_do_parameter_parametric(lp_ctx, service, "idmap config * : range",
+ pszParmValue, 0);
+ }
+
+ return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+}
+
+bool handle_smb_ports(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ static int parm_num = -1;
+ int i;
+ const char **list;
+
+ if (!pszParmValue || !*pszParmValue) {
+ return false;
+ }
+
+ if (parm_num == -1) {
+ parm_num = lpcfg_map_parameter("smb ports");
+ if (parm_num == -1) {
+ return false;
+ }
+ }
+
+ if (!set_variable_helper(lp_ctx->globals->ctx, parm_num, ptr, "smb ports",
+ pszParmValue)) {
+ return false;
+ }
+
+ list = lp_ctx->globals->smb_ports;
+ if (list == NULL) {
+ return false;
+ }
+
+ /* Check that each port is a valid integer and within range */
+ for (i = 0; list[i] != NULL; i++) {
+ char *end = NULL;
+ int port = 0;
+ port = strtol(list[i], &end, 10);
+ if (*end != '\0' || port <= 0 || port > 65535) {
+ TALLOC_FREE(list);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool handle_rpc_server_dynamic_port_range(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmValue,
+ char **ptr)
+{
+ static int parm_num = -1;
+ int low_port = -1, high_port = -1;
+ int rc;
+
+ if (parm_num == -1) {
+ parm_num = lpcfg_map_parameter("rpc server dynamic port range");
+ if (parm_num == -1) {
+ return false;
+ }
+ }
+
+ if (pszParmValue == NULL || pszParmValue[0] == '\0') {
+ return false;
+ }
+
+ rc = sscanf(pszParmValue, "%d - %d", &low_port, &high_port);
+ if (rc != 2) {
+ return false;
+ }
+
+ if (low_port > high_port) {
+ return false;
+ }
+
+ if (low_port < SERVER_TCP_PORT_MIN|| high_port > SERVER_TCP_PORT_MAX) {
+ return false;
+ }
+
+ if (!set_variable_helper(lp_ctx->globals->ctx, parm_num, ptr,
+ "rpc server dynamic port range",
+ pszParmValue)) {
+ return false;
+ }
+
+ lp_ctx->globals->rpc_low_port = low_port;
+ lp_ctx->globals->rpc_high_port = high_port;
+
+ return true;
+}
+
+bool handle_smb2_max_credits(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ int value = lp_int(pszParmValue);
+
+ if (value <= 0) {
+ value = DEFAULT_SMB2_MAX_CREDITS;
+ }
+
+ *(int *)ptr = value;
+
+ return true;
+}
+
+bool handle_cups_encrypt(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ int result = 0;
+#ifdef HAVE_HTTPCONNECTENCRYPT
+ int value = lp_int(pszParmValue);
+
+ switch (value) {
+ case Auto:
+ result = HTTP_ENCRYPT_REQUIRED;
+ break;
+ case true:
+ result = HTTP_ENCRYPT_ALWAYS;
+ break;
+ case false:
+ result = HTTP_ENCRYPT_NEVER;
+ break;
+ default:
+ result = 0;
+ break;
+ }
+#endif
+ *(int *)ptr = result;
+
+ return true;
+}
+
+/***************************************************************************
+ Initialise a copymap.
+***************************************************************************/
+
+/**
+ * Initializes service copymap
+ * Note: pservice *must* be valid TALLOC_CTX
+ */
+void init_copymap(struct loadparm_service *pservice)
+{
+ int i;
+
+ TALLOC_FREE(pservice->copymap);
+
+ pservice->copymap = bitmap_talloc(pservice, num_parameters());
+ if (!pservice->copymap) {
+ DEBUG(0,
+ ("Couldn't allocate copymap!! (size %d)\n",
+ (int)num_parameters()));
+ } else {
+ for (i = 0; i < num_parameters(); i++) {
+ bitmap_set(pservice->copymap, i);
+ }
+ }
+}
+
+/**
+ * Process a parametric option
+ */
+static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmName,
+ const char *pszParmValue, int flags)
+{
+ struct parmlist_entry **data;
+ char *name;
+ TALLOC_CTX *mem_ctx;
+
+ while (isspace((unsigned char)*pszParmName)) {
+ pszParmName++;
+ }
+
+ name = strlower_talloc(lp_ctx, pszParmName);
+ if (!name) return false;
+
+ if (service == NULL) {
+ data = &lp_ctx->globals->param_opt;
+ /**
+ * s3 code cannot deal with parametric options stored on the globals ctx.
+ */
+ if (lp_ctx->s3_fns != NULL) {
+ mem_ctx = NULL;
+ } else {
+ mem_ctx = lp_ctx->globals->ctx;
+ }
+ } else {
+ data = &service->param_opt;
+ mem_ctx = service;
+ }
+
+ set_param_opt(mem_ctx, data, name, pszParmValue, flags);
+
+ talloc_free(name);
+
+ return true;
+}
+
+static bool set_variable_helper(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
+ const char *pszParmName, const char *pszParmValue)
+{
+ size_t i;
+
+ /* switch on the type of variable it is */
+ switch (parm_table[parmnum].type)
+ {
+ case P_BOOL: {
+ bool b;
+ if (!set_boolean(pszParmValue, &b)) {
+ DEBUG(0, ("set_variable_helper(%s): value is not "
+ "boolean!\n", pszParmValue));
+ return false;
+ }
+ *(bool *)parm_ptr = b;
+ }
+ break;
+
+ case P_BOOLREV: {
+ bool b;
+ if (!set_boolean(pszParmValue, &b)) {
+ DEBUG(0, ("set_variable_helper(%s): value is not "
+ "boolean!\n", pszParmValue));
+ return false;
+ }
+ *(bool *)parm_ptr = !b;
+ }
+ break;
+
+ case P_INTEGER:
+ *(int *)parm_ptr = lp_int(pszParmValue);
+ break;
+
+ case P_CHAR:
+ *(char *)parm_ptr = *pszParmValue;
+ break;
+
+ case P_OCTAL:
+ i = sscanf(pszParmValue, "%o", (int *)parm_ptr);
+ if ( i != 1 ) {
+ DEBUG ( 0, ("Invalid octal number %s\n", pszParmName ));
+ return false;
+ }
+ break;
+
+ case P_BYTES:
+ {
+ uint64_t val;
+ if (conv_str_size_error(pszParmValue, &val)) {
+ if (val <= INT_MAX) {
+ *(int *)parm_ptr = (int)val;
+ break;
+ }
+ }
+
+ DEBUG(0, ("set_variable_helper(%s): value is not "
+ "a valid size specifier!\n", pszParmValue));
+ return false;
+ }
+
+ case P_CMDLIST:
+ TALLOC_FREE(*(char ***)parm_ptr);
+ *(char ***)parm_ptr = str_list_make_v3(mem_ctx,
+ pszParmValue, NULL);
+ break;
+
+ case P_LIST:
+ {
+ char **new_list = str_list_make_v3(mem_ctx,
+ pszParmValue, NULL);
+ if (new_list == NULL) {
+ break;
+ }
+
+ for (i=0; new_list[i]; i++) {
+ if (*(const char ***)parm_ptr != NULL &&
+ new_list[i][0] == '+' &&
+ new_list[i][1])
+ {
+ if (!str_list_check(*(const char ***)parm_ptr,
+ &new_list[i][1])) {
+ *(const char ***)parm_ptr = str_list_add(*(const char ***)parm_ptr,
+ &new_list[i][1]);
+ }
+ } else if (*(const char ***)parm_ptr != NULL &&
+ new_list[i][0] == '-' &&
+ new_list[i][1])
+ {
+ str_list_remove(*(const char ***)parm_ptr,
+ &new_list[i][1]);
+ } else {
+ if (i != 0) {
+ DEBUG(0, ("Unsupported list syntax for: %s = %s\n",
+ pszParmName, pszParmValue));
+ return false;
+ }
+ *(char ***)parm_ptr = new_list;
+ break;
+ }
+ }
+ break;
+ }
+
+ case P_STRING:
+ lpcfg_string_set(mem_ctx, (char **)parm_ptr, pszParmValue);
+ break;
+
+ case P_USTRING:
+ lpcfg_string_set_upper(mem_ctx, (char **)parm_ptr, pszParmValue);
+ break;
+
+ case P_ENUM:
+ if (!lp_set_enum_parm(&parm_table[parmnum], pszParmValue, (int*)parm_ptr)) {
+ return false;
+ }
+ break;
+
+ }
+
+ return true;
+
+}
+
+bool handle_name_resolve_order(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ const char **valid_values = NULL;
+ const char **values_to_set = NULL;
+ int i;
+ bool value_is_valid = false;
+ valid_values = str_list_make_v3_const(NULL,
+ DEFAULT_NAME_RESOLVE_ORDER,
+ NULL);
+ if (valid_values == NULL) {
+ DBG_ERR("OOM: failed to make string list from %s\n",
+ DEFAULT_NAME_RESOLVE_ORDER);
+ goto out;
+ }
+ values_to_set = str_list_make_v3_const(lp_ctx->globals->ctx,
+ pszParmValue,
+ NULL);
+ if (values_to_set == NULL) {
+ DBG_ERR("OOM: failed to make string list from %s\n",
+ pszParmValue);
+ goto out;
+ }
+ TALLOC_FREE(lp_ctx->globals->name_resolve_order);
+ for (i = 0; values_to_set[i] != NULL; i++) {
+ value_is_valid = str_list_check(valid_values, values_to_set[i]);
+ if (!value_is_valid) {
+ DBG_ERR("WARNING: Ignoring invalid list value '%s' "
+ "for parameter 'name resolve order'\n",
+ values_to_set[i]);
+ break;
+ }
+ }
+out:
+ if (value_is_valid) {
+ lp_ctx->globals->name_resolve_order = values_to_set;
+ } else {
+ TALLOC_FREE(values_to_set);
+ }
+ TALLOC_FREE(valid_values);
+ return value_is_valid;
+}
+
+bool handle_kdc_default_domain_supported_enctypes(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ char **enctype_list = NULL;
+ char **enctype = NULL;
+ uint32_t result = 0;
+ bool ok = true;
+
+ enctype_list = str_list_make(NULL, pszParmValue, NULL);
+ if (enctype_list == NULL) {
+ DBG_ERR("OOM: failed to make string list from %s\n",
+ pszParmValue);
+ ok = false;
+ goto out;
+ }
+
+ for (enctype = enctype_list; *enctype != NULL; ++enctype) {
+ if (strwicmp(*enctype, "arcfour-hmac-md5") == 0 ||
+ strwicmp(*enctype, "rc4-hmac") == 0)
+ {
+ result |= KERB_ENCTYPE_RC4_HMAC_MD5;
+ }
+ else if (strwicmp(*enctype, "aes128-cts-hmac-sha1-96") == 0 ||
+ strwicmp(*enctype, "aes128-cts") == 0)
+ {
+ result |= KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ }
+ else if (strwicmp(*enctype, "aes256-cts-hmac-sha1-96") == 0 ||
+ strwicmp(*enctype, "aes256-cts") == 0)
+ {
+ result |= KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ }
+ else if (strwicmp(*enctype, "aes256-cts-hmac-sha1-96-sk") == 0 ||
+ strwicmp(*enctype, "aes256-cts-sk") == 0)
+ {
+ result |= KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK;
+ }
+ else {
+ const char *bitstr = *enctype;
+ int base;
+ int error;
+ unsigned long bit;
+
+ /* See if the bit's specified in hexadecimal. */
+ if (bitstr[0] == '0' &&
+ (bitstr[1] == 'x' || bitstr[2] == 'X'))
+ {
+ base = 16;
+ bitstr += 2;
+ }
+ else {
+ base = 10;
+ }
+
+ bit = smb_strtoul(bitstr, NULL, base, &error, SMB_STR_FULL_STR_CONV);
+ if (error) {
+ DBG_ERR("WARNING: Ignoring invalid value '%s' "
+ "for parameter 'kdc default domain supported enctypes'\n",
+ *enctype);
+ ok = false;
+ } else {
+ result |= bit;
+ }
+ }
+ }
+
+ *(int *)ptr = result;
+out:
+ TALLOC_FREE(enctype_list);
+
+ return ok;
+}
+
+bool handle_kdc_supported_enctypes(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmValue, char **ptr)
+{
+ char **enctype_list = NULL;
+ char **enctype = NULL;
+ uint32_t result = 0;
+ bool ok = true;
+
+ enctype_list = str_list_make(NULL, pszParmValue, NULL);
+ if (enctype_list == NULL) {
+ DBG_ERR("OOM: failed to make string list from %s\n",
+ pszParmValue);
+ ok = false;
+ goto out;
+ }
+
+ for (enctype = enctype_list; *enctype != NULL; ++enctype) {
+ if (strwicmp(*enctype, "arcfour-hmac-md5") == 0 ||
+ strwicmp(*enctype, "rc4-hmac") == 0)
+ {
+ result |= KERB_ENCTYPE_RC4_HMAC_MD5;
+ }
+ else if (strwicmp(*enctype, "aes128-cts-hmac-sha1-96") == 0 ||
+ strwicmp(*enctype, "aes128-cts") == 0)
+ {
+ result |= KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ }
+ else if (strwicmp(*enctype, "aes256-cts-hmac-sha1-96") == 0 ||
+ strwicmp(*enctype, "aes256-cts") == 0)
+ {
+ result |= KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ }
+ else {
+ const char *bitstr = *enctype;
+ int base;
+ int error;
+ unsigned long bit;
+
+ /* See if the bit's specified in hexadecimal. */
+ if (bitstr[0] == '0' &&
+ (bitstr[1] == 'x' || bitstr[2] == 'X'))
+ {
+ base = 16;
+ bitstr += 2;
+ }
+ else {
+ base = 10;
+ }
+
+ bit = smb_strtoul(bitstr, NULL, base, &error, SMB_STR_FULL_STR_CONV);
+ if (error) {
+ DBG_ERR("WARNING: Ignoring invalid value '%s' "
+ "for parameter 'kdc default domain supported enctypes'\n",
+ *enctype);
+ ok = false;
+ } else {
+ result |= bit;
+ }
+ }
+ }
+
+ *(int *)ptr = result;
+out:
+ TALLOC_FREE(enctype_list);
+
+ return ok;
+}
+
+static bool set_variable(TALLOC_CTX *mem_ctx, struct loadparm_service *service,
+ int parmnum, void *parm_ptr,
+ const char *pszParmName, const char *pszParmValue,
+ struct loadparm_context *lp_ctx, bool on_globals)
+{
+ int i;
+ bool ok;
+
+ /* if it is a special case then go ahead */
+ if (parm_table[parmnum].special) {
+ ok = parm_table[parmnum].special(lp_ctx, service, pszParmValue,
+ (char **)parm_ptr);
+ } else {
+ ok = set_variable_helper(mem_ctx, parmnum, parm_ptr,
+ pszParmName, pszParmValue);
+ }
+
+ if (!ok) {
+ return false;
+ }
+
+ if (on_globals && (lp_ctx->flags[parmnum] & FLAG_DEFAULT)) {
+ lp_ctx->flags[parmnum] &= ~FLAG_DEFAULT;
+ /* we have to also unset FLAG_DEFAULT on aliases */
+ for (i=parmnum-1;i>=0 && parm_table[i].offset == parm_table[parmnum].offset;i--) {
+ lp_ctx->flags[i] &= ~FLAG_DEFAULT;
+ }
+ for (i=parmnum+1;i<num_parameters() && parm_table[i].offset == parm_table[parmnum].offset;i++) {
+ lp_ctx->flags[i] &= ~FLAG_DEFAULT;
+ }
+ }
+ return true;
+}
+
+
+bool lpcfg_do_global_parameter(struct loadparm_context *lp_ctx,
+ const char *pszParmName, const char *pszParmValue)
+{
+ int parmnum = lpcfg_map_parameter(pszParmName);
+ void *parm_ptr;
+
+ if (parmnum < 0) {
+ if (strchr(pszParmName, ':')) {
+ return lp_do_parameter_parametric(lp_ctx, NULL, pszParmName, pszParmValue, 0);
+ }
+ DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
+ return true;
+ }
+
+ /* if the flag has been set on the command line, then don't allow override,
+ but don't report an error */
+ if (lp_ctx->flags[parmnum] & FLAG_CMDLINE) {
+ return true;
+ }
+
+ if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
+ char *suppress_env = getenv("SAMBA_DEPRECATED_SUPPRESS");
+ bool print_warning = (suppress_env == NULL
+ || suppress_env[0] == '\0');
+ if (print_warning) {
+ DBG_WARNING("WARNING: The \"%s\" option "
+ "is deprecated\n",
+ pszParmName);
+
+ }
+ }
+
+ parm_ptr = lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[parmnum]);
+
+ return set_variable(lp_ctx->globals->ctx, NULL, parmnum, parm_ptr,
+ pszParmName, pszParmValue, lp_ctx, true);
+}
+
+bool lpcfg_do_service_parameter(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmName, const char *pszParmValue)
+{
+ void *parm_ptr;
+ int i;
+ int parmnum = lpcfg_map_parameter(pszParmName);
+
+ if (parmnum < 0) {
+ if (strchr(pszParmName, ':')) {
+ return lp_do_parameter_parametric(lp_ctx, service, pszParmName, pszParmValue, 0);
+ }
+ DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
+ return true;
+ }
+
+ /* if the flag has been set on the command line, then don't allow override,
+ but don't report an error */
+ if (lp_ctx->flags[parmnum] & FLAG_CMDLINE) {
+ return true;
+ }
+
+ if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
+ char *suppress_env = getenv("SAMBA_DEPRECATED_SUPPRESS");
+ bool print_warning = (suppress_env == NULL
+ || suppress_env[0] == '\0');
+ if (print_warning) {
+ DBG_WARNING("WARNING: The \"%s\" option "
+ "is deprecated\n",
+ pszParmName);
+
+ }
+ }
+
+ if (parm_table[parmnum].p_class == P_GLOBAL) {
+ DEBUG(0,
+ ("Global parameter %s found in service section!\n",
+ pszParmName));
+ return true;
+ }
+ parm_ptr = ((char *)service) + parm_table[parmnum].offset;
+
+ if (!service->copymap)
+ init_copymap(service);
+
+ /* this handles the aliases - set the copymap for other
+ * entries with the same data pointer */
+ for (i = 0; parm_table[i].label; i++)
+ if (parm_table[i].offset == parm_table[parmnum].offset &&
+ parm_table[i].p_class == parm_table[parmnum].p_class)
+ bitmap_clear(service->copymap, i);
+
+ return set_variable(service, service, parmnum, parm_ptr, pszParmName,
+ pszParmValue, lp_ctx, false);
+}
+
+/**
+ * Process a parameter.
+ */
+
+bool lpcfg_do_parameter(const char *pszParmName, const char *pszParmValue,
+ void *userdata)
+{
+ struct loadparm_context *lp_ctx = (struct loadparm_context *)userdata;
+
+ if (lp_ctx->bInGlobalSection)
+ return lpcfg_do_global_parameter(lp_ctx, pszParmName,
+ pszParmValue);
+ else
+ return lpcfg_do_service_parameter(lp_ctx, lp_ctx->currentService,
+ pszParmName, pszParmValue);
+}
+
+/*
+ variable argument do parameter
+*/
+bool lpcfg_do_global_parameter_var(struct loadparm_context *lp_ctx, const char *pszParmName, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+bool lpcfg_do_global_parameter_var(struct loadparm_context *lp_ctx,
+ const char *pszParmName, const char *fmt, ...)
+{
+ char *s;
+ bool ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf(NULL, fmt, ap);
+ va_end(ap);
+ ret = lpcfg_do_global_parameter(lp_ctx, pszParmName, s);
+ talloc_free(s);
+ return ret;
+}
+
+
+/*
+ set a parameter from the commandline - this is called from command line parameter
+ parsing code. It sets the parameter then marks the parameter as unable to be modified
+ by smb.conf processing
+*/
+bool lpcfg_set_cmdline(struct loadparm_context *lp_ctx, const char *pszParmName,
+ const char *pszParmValue)
+{
+ int parmnum;
+ int i;
+
+ while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
+
+ parmnum = lpcfg_map_parameter(pszParmName);
+
+ if (parmnum < 0 && strchr(pszParmName, ':')) {
+ /* set a parametric option */
+ bool ok;
+ ok = lp_do_parameter_parametric(lp_ctx, NULL, pszParmName,
+ pszParmValue, FLAG_CMDLINE);
+ if (lp_ctx->s3_fns != NULL) {
+ if (ok) {
+ lp_ctx->s3_fns->store_cmdline(pszParmName, pszParmValue);
+ }
+ }
+ return ok;
+ }
+
+ if (parmnum < 0) {
+ DEBUG(0,("Unknown option '%s'\n", pszParmName));
+ return false;
+ }
+
+ /* reset the CMDLINE flag in case this has been called before */
+ lp_ctx->flags[parmnum] &= ~FLAG_CMDLINE;
+
+ if (!lpcfg_do_global_parameter(lp_ctx, pszParmName, pszParmValue)) {
+ return false;
+ }
+
+ lp_ctx->flags[parmnum] |= FLAG_CMDLINE;
+
+ /* we have to also set FLAG_CMDLINE on aliases */
+ for (i=parmnum-1;
+ i>=0 && parm_table[i].p_class == parm_table[parmnum].p_class &&
+ parm_table[i].offset == parm_table[parmnum].offset;
+ i--) {
+ lp_ctx->flags[i] |= FLAG_CMDLINE;
+ }
+ for (i=parmnum+1;
+ i<num_parameters() &&
+ parm_table[i].p_class == parm_table[parmnum].p_class &&
+ parm_table[i].offset == parm_table[parmnum].offset;
+ i++) {
+ lp_ctx->flags[i] |= FLAG_CMDLINE;
+ }
+
+ if (lp_ctx->s3_fns != NULL) {
+ lp_ctx->s3_fns->store_cmdline(pszParmName, pszParmValue);
+ }
+
+ return true;
+}
+
+/*
+ set a option from the commandline in 'a=b' format. Use to support --option
+*/
+bool lpcfg_set_option(struct loadparm_context *lp_ctx, const char *option)
+{
+ char *p, *s;
+ bool ret;
+
+ s = talloc_strdup(NULL, option);
+ if (!s) {
+ return false;
+ }
+
+ p = strchr(s, '=');
+ if (!p) {
+ talloc_free(s);
+ return false;
+ }
+
+ *p = 0;
+
+ ret = lpcfg_set_cmdline(lp_ctx, s, p+1);
+ talloc_free(s);
+ return ret;
+}
+
+
+#define BOOLSTR(b) ((b) ? "Yes" : "No")
+
+/**
+ * Print a parameter of the specified type.
+ */
+
+void lpcfg_print_parameter(struct parm_struct *p, void *ptr, FILE * f)
+{
+ /* For the separation of lists values that we print below */
+ const char *list_sep = ", ";
+ int i;
+ switch (p->type)
+ {
+ case P_ENUM:
+ for (i = 0; p->enum_list[i].name; i++) {
+ if (*(int *)ptr == p->enum_list[i].value) {
+ fprintf(f, "%s",
+ p->enum_list[i].name);
+ break;
+ }
+ }
+ break;
+
+ case P_BOOL:
+ fprintf(f, "%s", BOOLSTR(*(bool *)ptr));
+ break;
+
+ case P_BOOLREV:
+ fprintf(f, "%s", BOOLSTR(!*(bool *)ptr));
+ break;
+
+ case P_INTEGER:
+ case P_BYTES:
+ fprintf(f, "%d", *(int *)ptr);
+ break;
+
+ case P_CHAR:
+ fprintf(f, "%c", *(char *)ptr);
+ break;
+
+ case P_OCTAL: {
+ int val = *(int *)ptr;
+ if (val == -1) {
+ fprintf(f, "-1");
+ } else {
+ fprintf(f, "0%03o", val);
+ }
+ break;
+ }
+
+ case P_CMDLIST:
+ list_sep = " ";
+
+ FALL_THROUGH;
+ case P_LIST:
+ if ((char ***)ptr && *(char ***)ptr) {
+ char **list = *(char ***)ptr;
+ for (; *list; list++) {
+ /* surround strings with whitespace in double quotes */
+ if (*(list+1) == NULL) {
+ /* last item, no extra separator */
+ list_sep = "";
+ }
+ if ( strchr_m( *list, ' ' ) ) {
+ fprintf(f, "\"%s\"%s", *list, list_sep);
+ } else {
+ fprintf(f, "%s%s", *list, list_sep);
+ }
+ }
+ }
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ if (*(char **)ptr) {
+ fprintf(f, "%s", *(char **)ptr);
+ }
+ break;
+ }
+}
+
+/**
+ * Check if two parameters are equal.
+ */
+
+static bool lpcfg_equal_parameter(parm_type type, void *ptr1, void *ptr2)
+{
+ switch (type) {
+ case P_BOOL:
+ case P_BOOLREV:
+ return (*((bool *)ptr1) == *((bool *)ptr2));
+
+ case P_INTEGER:
+ case P_ENUM:
+ case P_OCTAL:
+ case P_BYTES:
+ return (*((int *)ptr1) == *((int *)ptr2));
+
+ case P_CHAR:
+ return (*((char *)ptr1) == *((char *)ptr2));
+
+ case P_LIST:
+ case P_CMDLIST:
+ return str_list_equal(*(const char ***)ptr1, *(const char ***)ptr2);
+
+ case P_STRING:
+ case P_USTRING:
+ {
+ char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
+ if (p1 && !*p1)
+ p1 = NULL;
+ if (p2 && !*p2)
+ p2 = NULL;
+ return (p1 == p2 || strequal(p1, p2));
+ }
+ }
+ return false;
+}
+
+/**
+ * Process a new section (service).
+ *
+ * At this stage all sections are services.
+ * Later we'll have special sections that permit server parameters to be set.
+ * Returns True on success, False on failure.
+ */
+
+static bool do_section(const char *pszSectionName, void *userdata)
+{
+ struct loadparm_context *lp_ctx = (struct loadparm_context *)userdata;
+ bool bRetval;
+ bool isglobal;
+
+ if (lp_ctx->s3_fns != NULL) {
+ return lp_ctx->s3_fns->do_section(pszSectionName, lp_ctx);
+ }
+
+ isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
+ (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
+
+ /* if we've just struck a global section, note the fact. */
+ lp_ctx->bInGlobalSection = isglobal;
+
+ /* check for multiple global sections */
+ if (lp_ctx->bInGlobalSection) {
+ DEBUG(4, ("Processing section \"[%s]\"\n", pszSectionName));
+ bRetval = true;
+ goto out;
+ }
+
+ /* if we have a current service, tidy it up before moving on */
+ bRetval = true;
+
+ if (lp_ctx->currentService != NULL)
+ bRetval = lpcfg_service_ok(lp_ctx->currentService);
+
+ /* if all is still well, move to the next record in the services array */
+ if (bRetval) {
+ /* We put this here to avoid an odd message order if messages are */
+ /* issued by the post-processing of a previous section. */
+ DEBUG(4, ("Processing section \"[%s]\"\n", pszSectionName));
+
+ if ((lp_ctx->currentService = lpcfg_add_service(lp_ctx, lp_ctx->sDefault,
+ pszSectionName))
+ == NULL) {
+ DEBUG(0, ("Failed to add a new service\n"));
+ bRetval = false;
+ goto out;
+ }
+ }
+out:
+ return bRetval;
+}
+
+
+/**
+ * Determine if a particular base parameter is currently set to the default value.
+ */
+
+static bool is_default(void *base_structure, int i)
+{
+ void *def_ptr = ((char *)base_structure) + parm_table[i].offset;
+ switch (parm_table[i].type) {
+ case P_CMDLIST:
+ case P_LIST:
+ return str_list_equal((const char * const *)parm_table[i].def.lvalue,
+ *(const char * const **)def_ptr);
+ case P_STRING:
+ case P_USTRING:
+ return strequal(parm_table[i].def.svalue,
+ *(char **)def_ptr);
+ case P_BOOL:
+ case P_BOOLREV:
+ return parm_table[i].def.bvalue ==
+ *(bool *)def_ptr;
+ case P_INTEGER:
+ case P_CHAR:
+ case P_OCTAL:
+ case P_BYTES:
+ case P_ENUM:
+ return parm_table[i].def.ivalue ==
+ *(int *)def_ptr;
+ }
+ return false;
+}
+
+/**
+ *Display the contents of the global structure.
+ */
+
+void lpcfg_dump_globals(struct loadparm_context *lp_ctx, FILE *f,
+ bool show_defaults)
+{
+ int i;
+ struct parmlist_entry *data;
+
+ fprintf(f, "# Global parameters\n[global]\n");
+
+ for (i = 0; parm_table[i].label; i++) {
+ if (parm_table[i].p_class != P_GLOBAL) {
+ continue;
+ }
+
+ if (parm_table[i].flags & FLAG_SYNONYM) {
+ continue;
+ }
+
+ if (!show_defaults) {
+ if (lp_ctx->flags && (lp_ctx->flags[i] & FLAG_DEFAULT)) {
+ continue;
+ }
+
+ if (is_default(lp_ctx->globals, i)) {
+ continue;
+ }
+ }
+
+ fprintf(f, "\t%s = ", parm_table[i].label);
+ lpcfg_print_parameter(&parm_table[i], lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[i]), f);
+ fprintf(f, "\n");
+ }
+ if (lp_ctx->globals->param_opt != NULL) {
+ for (data = lp_ctx->globals->param_opt; data;
+ data = data->next) {
+ if (!show_defaults && (data->priority & FLAG_DEFAULT)) {
+ continue;
+ }
+ fprintf(f, "\t%s = %s\n", data->key, data->value);
+ }
+ }
+
+}
+
+/**
+ * Display the contents of a single services record.
+ */
+
+void lpcfg_dump_a_service(struct loadparm_service * pService, struct loadparm_service *sDefault, FILE * f,
+ unsigned int *flags, bool show_defaults)
+{
+ int i;
+ struct parmlist_entry *data;
+
+ if (pService != sDefault)
+ fprintf(f, "\n[%s]\n", pService->szService);
+
+ for (i = 0; parm_table[i].label; i++) {
+ if (parm_table[i].p_class != P_LOCAL) {
+ continue;
+ }
+
+ if (parm_table[i].flags & FLAG_SYNONYM) {
+ continue;
+ }
+
+ if (*parm_table[i].label == '-') {
+ continue;
+ }
+
+ if (pService == sDefault) {
+ if (!show_defaults) {
+ if (flags && (flags[i] & FLAG_DEFAULT)) {
+ continue;
+ }
+
+ if (is_default(sDefault, i)) {
+ continue;
+ }
+ }
+ } else {
+ bool equal;
+
+ equal = lpcfg_equal_parameter(parm_table[i].type,
+ ((char *)pService) +
+ parm_table[i].offset,
+ ((char *)sDefault) +
+ parm_table[i].offset);
+ if (equal) {
+ continue;
+ }
+ }
+
+ fprintf(f, "\t%s = ", parm_table[i].label);
+ lpcfg_print_parameter(&parm_table[i],
+ ((char *)pService) + parm_table[i].offset, f);
+ fprintf(f, "\n");
+ }
+ if (pService->param_opt != NULL) {
+ for (data = pService->param_opt; data; data = data->next) {
+ if (!show_defaults && (data->priority & FLAG_DEFAULT)) {
+ continue;
+ }
+ fprintf(f, "\t%s = %s\n", data->key, data->value);
+ }
+ }
+}
+
+bool lpcfg_dump_a_parameter(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *parm_name, FILE * f)
+{
+ struct parm_struct *parm;
+ void *ptr;
+ char *local_parm_name;
+ char *parm_opt;
+ const char *parm_opt_value;
+
+ /* check for parametrical option */
+ local_parm_name = talloc_strdup(lp_ctx, parm_name);
+ if (local_parm_name == NULL) {
+ return false;
+ }
+
+ parm_opt = strchr( local_parm_name, ':');
+
+ if (parm_opt) {
+ *parm_opt = '\0';
+ parm_opt++;
+ if (strlen(parm_opt)) {
+ parm_opt_value = lpcfg_parm_string(lp_ctx, service,
+ local_parm_name, parm_opt);
+ if (parm_opt_value) {
+ fprintf(f, "%s\n", parm_opt_value);
+ TALLOC_FREE(local_parm_name);
+ return true;
+ }
+ }
+ TALLOC_FREE(local_parm_name);
+ return false;
+ }
+ TALLOC_FREE(local_parm_name);
+
+ /* parameter is not parametric, search the table */
+ parm = lpcfg_parm_struct(lp_ctx, parm_name);
+ if (!parm) {
+ return false;
+ }
+
+ if (service != NULL && parm->p_class == P_GLOBAL) {
+ return false;
+ }
+
+ ptr = lpcfg_parm_ptr(lp_ctx, service,parm);
+
+ lpcfg_print_parameter(parm, ptr, f);
+ fprintf(f, "\n");
+ return true;
+}
+
+/**
+ * Auto-load some home services.
+ */
+static void lpcfg_add_auto_services(struct loadparm_context *lp_ctx,
+ const char *str)
+{
+ return;
+}
+
+/***************************************************************************
+ Initialise the sDefault parameter structure for the printer values.
+***************************************************************************/
+
+void init_printer_values(struct loadparm_context *lp_ctx, TALLOC_CTX *ctx,
+ struct loadparm_service *pService)
+{
+ /* choose defaults depending on the type of printing */
+ switch (pService->printing) {
+ case PRINT_BSD:
+ case PRINT_AIX:
+ case PRINT_LPRNT:
+ case PRINT_LPROS2:
+ lpcfg_string_set(ctx, &pService->lpq_command, "lpq -P'%p'");
+ lpcfg_string_set(ctx, &pService->lprm_command, "lprm -P'%p' %j");
+ lpcfg_string_set(ctx, &pService->print_command, "lpr -r -P'%p' %s");
+ break;
+
+ case PRINT_LPRNG:
+ case PRINT_PLP:
+ lpcfg_string_set(ctx, &pService->lpq_command, "lpq -P'%p'");
+ lpcfg_string_set(ctx, &pService->lprm_command, "lprm -P'%p' %j");
+ lpcfg_string_set(ctx, &pService->print_command, "lpr -r -P'%p' %s");
+ lpcfg_string_set(ctx, &pService->queuepause_command, "lpc stop '%p'");
+ lpcfg_string_set(ctx, &pService->queueresume_command, "lpc start '%p'");
+ lpcfg_string_set(ctx, &pService->lppause_command, "lpc hold '%p' %j");
+ lpcfg_string_set(ctx, &pService->lpresume_command, "lpc release '%p' %j");
+ break;
+
+ case PRINT_CUPS:
+ case PRINT_IPRINT:
+ /* set the lpq command to contain the destination printer
+ name only. This is used by cups_queue_get() */
+ lpcfg_string_set(ctx, &pService->lpq_command, "%p");
+ lpcfg_string_set(ctx, &pService->lprm_command, "");
+ lpcfg_string_set(ctx, &pService->print_command, "");
+ lpcfg_string_set(ctx, &pService->lppause_command, "");
+ lpcfg_string_set(ctx, &pService->lpresume_command, "");
+ lpcfg_string_set(ctx, &pService->queuepause_command, "");
+ lpcfg_string_set(ctx, &pService->queueresume_command, "");
+ break;
+
+ case PRINT_SYSV:
+ case PRINT_HPUX:
+ lpcfg_string_set(ctx, &pService->lpq_command, "lpstat -o%p");
+ lpcfg_string_set(ctx, &pService->lprm_command, "cancel %p-%j");
+ lpcfg_string_set(ctx, &pService->print_command, "lp -c -d%p %s; rm %s");
+ lpcfg_string_set(ctx, &pService->queuepause_command, "disable %p");
+ lpcfg_string_set(ctx, &pService->queueresume_command, "enable %p");
+#ifndef HPUX
+ lpcfg_string_set(ctx, &pService->lppause_command, "lp -i %p-%j -H hold");
+ lpcfg_string_set(ctx, &pService->lpresume_command, "lp -i %p-%j -H resume");
+#endif /* HPUX */
+ break;
+
+ case PRINT_QNX:
+ lpcfg_string_set(ctx, &pService->lpq_command, "lpq -P%p");
+ lpcfg_string_set(ctx, &pService->lprm_command, "lprm -P%p %j");
+ lpcfg_string_set(ctx, &pService->print_command, "lp -r -P%p %s");
+ break;
+
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+
+ case PRINT_TEST:
+ case PRINT_VLP: {
+ const char *tdbfile;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctx);
+ const char *tmp;
+
+ tmp = lpcfg_parm_string(lp_ctx, NULL, "vlp", "tdbfile");
+ if (tmp == NULL) {
+ tmp = "/tmp/vlp.tdb";
+ }
+
+ tdbfile = talloc_asprintf(tmp_ctx, "tdbfile=%s", tmp);
+ if (tdbfile == NULL) {
+ tdbfile="tdbfile=/tmp/vlp.tdb";
+ }
+
+ tmp = talloc_asprintf(tmp_ctx, "vlp %s print %%p %%s",
+ tdbfile);
+ lpcfg_string_set(ctx, &pService->print_command,
+ tmp ? tmp : "vlp print %p %s");
+
+ tmp = talloc_asprintf(tmp_ctx, "vlp %s lpq %%p",
+ tdbfile);
+ lpcfg_string_set(ctx, &pService->lpq_command,
+ tmp ? tmp : "vlp lpq %p");
+
+ tmp = talloc_asprintf(tmp_ctx, "vlp %s lprm %%p %%j",
+ tdbfile);
+ lpcfg_string_set(ctx, &pService->lprm_command,
+ tmp ? tmp : "vlp lprm %p %j");
+
+ tmp = talloc_asprintf(tmp_ctx, "vlp %s lppause %%p %%j",
+ tdbfile);
+ lpcfg_string_set(ctx, &pService->lppause_command,
+ tmp ? tmp : "vlp lppause %p %j");
+
+ tmp = talloc_asprintf(tmp_ctx, "vlp %s lpresume %%p %%j",
+ tdbfile);
+ lpcfg_string_set(ctx, &pService->lpresume_command,
+ tmp ? tmp : "vlp lpresume %p %j");
+
+ tmp = talloc_asprintf(tmp_ctx, "vlp %s queuepause %%p",
+ tdbfile);
+ lpcfg_string_set(ctx, &pService->queuepause_command,
+ tmp ? tmp : "vlp queuepause %p");
+
+ tmp = talloc_asprintf(tmp_ctx, "vlp %s queueresume %%p",
+ tdbfile);
+ lpcfg_string_set(ctx, &pService->queueresume_command,
+ tmp ? tmp : "vlp queueresume %p");
+ TALLOC_FREE(tmp_ctx);
+
+ break;
+ }
+#endif /* DEVELOPER */
+
+ }
+}
+
+
+static int lpcfg_destructor(struct loadparm_context *lp_ctx)
+{
+ struct parmlist_entry *data;
+
+ if (lp_ctx->refuse_free) {
+ /* someone is trying to free the
+ global_loadparm_context.
+ We can't allow that. */
+ return -1;
+ }
+
+ if (lp_ctx->globals->param_opt != NULL) {
+ struct parmlist_entry *next;
+ for (data = lp_ctx->globals->param_opt; data; data=next) {
+ next = data->next;
+ if (data->priority & FLAG_CMDLINE) continue;
+ DLIST_REMOVE(lp_ctx->globals->param_opt, data);
+ talloc_free(data);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Initialise the global parameter structure.
+ *
+ * Note that most callers should use loadparm_init_global() instead
+ */
+struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
+{
+ int i;
+ char *myname;
+ struct loadparm_context *lp_ctx;
+ struct parmlist_entry *parm;
+ char *logfile;
+
+ lp_ctx = talloc_zero(mem_ctx, struct loadparm_context);
+ if (lp_ctx == NULL)
+ return NULL;
+
+ talloc_set_destructor(lp_ctx, lpcfg_destructor);
+ lp_ctx->bInGlobalSection = true;
+ lp_ctx->globals = talloc_zero(lp_ctx, struct loadparm_global);
+ /* This appears odd, but globals in s3 isn't a pointer */
+ lp_ctx->globals->ctx = lp_ctx->globals;
+ lp_ctx->globals->rpc_low_port = SERVER_TCP_LOW_PORT;
+ lp_ctx->globals->rpc_high_port = SERVER_TCP_HIGH_PORT;
+ lp_ctx->globals->weak_crypto = SAMBA_WEAK_CRYPTO_UNKNOWN;
+ lp_ctx->sDefault = talloc_zero(lp_ctx, struct loadparm_service);
+ lp_ctx->flags = talloc_zero_array(lp_ctx, unsigned int, num_parameters());
+
+ lp_ctx->sDefault->max_print_jobs = 1000;
+ lp_ctx->sDefault->available = true;
+ lp_ctx->sDefault->browseable = true;
+ lp_ctx->sDefault->read_only = true;
+ lp_ctx->sDefault->map_archive = true;
+ lp_ctx->sDefault->strict_locking = true;
+ lp_ctx->sDefault->oplocks = true;
+ lp_ctx->sDefault->create_mask = 0744;
+ lp_ctx->sDefault->force_create_mode = 0000;
+ lp_ctx->sDefault->directory_mask = 0755;
+ lp_ctx->sDefault->force_directory_mode = 0000;
+ lp_ctx->sDefault->aio_read_size = 1;
+ lp_ctx->sDefault->aio_write_size = 1;
+ lp_ctx->sDefault->smbd_search_ask_sharemode = true;
+ lp_ctx->sDefault->smbd_getinfo_ask_sharemode = true;
+ lp_ctx->sDefault->volume_serial_number = -1;
+
+ DEBUG(3, ("Initialising global parameters\n"));
+
+ for (i = 0; parm_table[i].label; i++) {
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
+ !(lp_ctx->flags[i] & FLAG_CMDLINE)) {
+ TALLOC_CTX *parent_mem;
+ char **r;
+ if (parm_table[i].p_class == P_LOCAL) {
+ parent_mem = lp_ctx->sDefault;
+ r = (char **)(((char *)lp_ctx->sDefault) + parm_table[i].offset);
+ } else {
+ parent_mem = lp_ctx->globals;
+ r = (char **)(((char *)lp_ctx->globals) + parm_table[i].offset);
+ }
+ lpcfg_string_set(parent_mem, r, "");
+ }
+ }
+
+ logfile = talloc_asprintf(lp_ctx, "%s/log.samba", dyn_LOGFILEBASE);
+ lpcfg_do_global_parameter(lp_ctx, "log file", logfile);
+ talloc_free(logfile);
+
+ lpcfg_do_global_parameter(lp_ctx, "log level", "0");
+
+ lpcfg_do_global_parameter(lp_ctx, "syslog", "1");
+ lpcfg_do_global_parameter(lp_ctx, "syslog only", "No");
+ lpcfg_do_global_parameter(lp_ctx, "debug timestamp", "Yes");
+ lpcfg_do_global_parameter(lp_ctx, "debug prefix timestamp", "No");
+ lpcfg_do_global_parameter(lp_ctx, "debug hires timestamp", "Yes");
+ lpcfg_do_global_parameter(lp_ctx, "debug syslog format", "No");
+ lpcfg_do_global_parameter(lp_ctx, "debug pid", "No");
+ lpcfg_do_global_parameter(lp_ctx, "debug uid", "No");
+ lpcfg_do_global_parameter(lp_ctx, "debug class", "No");
+
+ lpcfg_do_global_parameter(lp_ctx, "server role", "auto");
+ lpcfg_do_global_parameter(lp_ctx, "domain logons", "No");
+ lpcfg_do_global_parameter(lp_ctx, "domain master", "Auto");
+
+ /* options that can be set on the command line must be initialised via
+ the slower lpcfg_do_global_parameter() to ensure that FLAG_CMDLINE is obeyed */
+#ifdef TCP_NODELAY
+ lpcfg_do_global_parameter(lp_ctx, "socket options", "TCP_NODELAY");
+#endif
+ lpcfg_do_global_parameter(lp_ctx, "workgroup", DEFAULT_WORKGROUP);
+ myname = get_myname(lp_ctx);
+ lpcfg_do_global_parameter(lp_ctx, "netbios name", myname);
+ talloc_free(myname);
+ lpcfg_do_global_parameter(lp_ctx,
+ "name resolve order",
+ DEFAULT_NAME_RESOLVE_ORDER);
+
+ lpcfg_do_global_parameter(lp_ctx, "fstype", "NTFS");
+
+ lpcfg_do_global_parameter(lp_ctx, "ntvfs handler", "unixuid default");
+ lpcfg_do_global_parameter(lp_ctx, "max connections", "0");
+
+ lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper wkssvc samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver");
+ lpcfg_do_global_parameter(lp_ctx, "server services", "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns");
+ lpcfg_do_global_parameter(lp_ctx, "kccsrv:samba_kcc", "true");
+ /* the winbind method for domain controllers is for both RODC
+ auth forwarding and for trusted domains */
+ lpcfg_do_global_parameter(lp_ctx, "private dir", dyn_PRIVATE_DIR);
+ lpcfg_do_global_parameter(lp_ctx, "binddns dir", dyn_BINDDNS_DIR);
+ lpcfg_do_global_parameter(lp_ctx, "registry:HKEY_LOCAL_MACHINE", "hklm.ldb");
+
+ /* This hive should be dynamically generated by Samba using
+ data from the sam, but for the moment leave it in a tdb to
+ keep regedt32 from popping up an annoying dialog. */
+ lpcfg_do_global_parameter(lp_ctx, "registry:HKEY_USERS", "hku.ldb");
+
+ /* using UTF8 by default allows us to support all chars */
+ lpcfg_do_global_parameter(lp_ctx, "unix charset", "UTF-8");
+
+ /* Use codepage 850 as a default for the dos character set */
+ lpcfg_do_global_parameter(lp_ctx, "dos charset", "CP850");
+
+ /*
+ * Allow the default PASSWD_CHAT to be overridden in local.h.
+ */
+ lpcfg_do_global_parameter(lp_ctx, "passwd chat", DEFAULT_PASSWD_CHAT);
+
+ lpcfg_do_global_parameter(lp_ctx, "pid directory", dyn_PIDDIR);
+ lpcfg_do_global_parameter(lp_ctx, "lock dir", dyn_LOCKDIR);
+ lpcfg_do_global_parameter(lp_ctx, "state directory", dyn_STATEDIR);
+ lpcfg_do_global_parameter(lp_ctx, "cache directory", dyn_CACHEDIR);
+ lpcfg_do_global_parameter(lp_ctx, "ncalrpc dir", dyn_NCALRPCDIR);
+
+ lpcfg_do_global_parameter(lp_ctx, "nbt client socket address", "0.0.0.0");
+ lpcfg_do_global_parameter_var(lp_ctx, "server string",
+ "Samba %s", SAMBA_VERSION_STRING);
+
+ lpcfg_do_global_parameter(lp_ctx, "password server", "*");
+
+ lpcfg_do_global_parameter(lp_ctx, "max mux", "50");
+ lpcfg_do_global_parameter(lp_ctx, "max xmit", "16644");
+ lpcfg_do_global_parameter(lp_ctx, "host msdfs", "true");
+
+ lpcfg_do_global_parameter(lp_ctx, "LargeReadwrite", "True");
+ lpcfg_do_global_parameter(lp_ctx, "server min protocol", "SMB2_02");
+ lpcfg_do_global_parameter(lp_ctx, "server max protocol", "SMB3");
+ lpcfg_do_global_parameter(lp_ctx, "client min protocol", "SMB2_02");
+ lpcfg_do_global_parameter(lp_ctx, "client max protocol", "default");
+ lpcfg_do_global_parameter(lp_ctx, "client ipc min protocol", "default");
+ lpcfg_do_global_parameter(lp_ctx, "client ipc max protocol", "default");
+ lpcfg_do_global_parameter(lp_ctx, "security", "AUTO");
+ lpcfg_do_global_parameter(lp_ctx, "EncryptPasswords", "True");
+ lpcfg_do_global_parameter(lp_ctx, "ReadRaw", "True");
+ lpcfg_do_global_parameter(lp_ctx, "WriteRaw", "True");
+ lpcfg_do_global_parameter(lp_ctx, "NullPasswords", "False");
+ lpcfg_do_global_parameter(lp_ctx, "old password allowed period", "60");
+ lpcfg_do_global_parameter(lp_ctx, "ObeyPamRestrictions", "False");
+
+ lpcfg_do_global_parameter(lp_ctx, "TimeServer", "False");
+ lpcfg_do_global_parameter(lp_ctx, "BindInterfacesOnly", "False");
+ lpcfg_do_global_parameter(lp_ctx, "Unicode", "True");
+ lpcfg_do_global_parameter(lp_ctx, "ClientLanManAuth", "False");
+ lpcfg_do_global_parameter(lp_ctx, "ClientNTLMv2Auth", "True");
+ lpcfg_do_global_parameter(lp_ctx, "LanmanAuth", "False");
+ lpcfg_do_global_parameter(lp_ctx, "NTLMAuth", "ntlmv2-only");
+ lpcfg_do_global_parameter(lp_ctx, "NT hash store", "always");
+ lpcfg_do_global_parameter(lp_ctx, "RawNTLMv2Auth", "False");
+ lpcfg_do_global_parameter(lp_ctx, "client use spnego principal", "False");
+
+ lpcfg_do_global_parameter(lp_ctx, "allow dcerpc auth level connect", "False");
+
+ lpcfg_do_global_parameter(lp_ctx, "UnixExtensions", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "PreferredMaster", "Auto");
+ lpcfg_do_global_parameter(lp_ctx, "LocalMaster", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "wins support", "False");
+ lpcfg_do_global_parameter(lp_ctx, "dns proxy", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind separator", "\\");
+ lpcfg_do_global_parameter(lp_ctx, "winbind sealed pipes", "True");
+ lpcfg_do_global_parameter(lp_ctx, "winbind scan trusted domains", "False");
+ lpcfg_do_global_parameter(lp_ctx, "require strong key", "True");
+ lpcfg_do_global_parameter(lp_ctx, "reject md5 servers", "True");
+ lpcfg_do_global_parameter(lp_ctx, "winbindd socket directory", dyn_WINBINDD_SOCKET_DIR);
+ lpcfg_do_global_parameter(lp_ctx, "ntp signd socket directory", dyn_NTP_SIGND_SOCKET_DIR);
+ lpcfg_do_global_parameter_var(lp_ctx, "gpo update command", "%s/samba-gpupdate", dyn_SCRIPTSBINDIR);
+ lpcfg_do_global_parameter_var(lp_ctx, "apply group policies", "False");
+ lpcfg_do_global_parameter_var(lp_ctx, "dns update command", "%s/samba_dnsupdate", dyn_SCRIPTSBINDIR);
+ lpcfg_do_global_parameter_var(lp_ctx, "spn update command", "%s/samba_spnupdate", dyn_SCRIPTSBINDIR);
+ lpcfg_do_global_parameter_var(lp_ctx, "samba kcc command",
+ "%s/samba_kcc", dyn_SCRIPTSBINDIR);
+#ifdef MIT_KDC_PATH
+ lpcfg_do_global_parameter_var(lp_ctx,
+ "mit kdc command",
+ MIT_KDC_PATH);
+#endif
+ lpcfg_do_global_parameter(lp_ctx, "template shell", "/bin/false");
+ lpcfg_do_global_parameter(lp_ctx, "template homedir", "/home/%D/%U");
+
+ lpcfg_do_global_parameter(lp_ctx, "client signing", "default");
+ lpcfg_do_global_parameter(lp_ctx, "client ipc signing", "default");
+ lpcfg_do_global_parameter(lp_ctx, "server signing", "default");
+
+ lpcfg_do_global_parameter(lp_ctx, "use mmap", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "smb ports", "445 139");
+ lpcfg_do_global_parameter_var(lp_ctx, "nbt port", "%d", NBT_NAME_SERVICE_PORT);
+ lpcfg_do_global_parameter_var(lp_ctx, "dgram port", "%d", NBT_DGRAM_SERVICE_PORT);
+ lpcfg_do_global_parameter(lp_ctx, "cldap port", "389");
+ lpcfg_do_global_parameter(lp_ctx, "krb5 port", "88");
+ lpcfg_do_global_parameter(lp_ctx, "kpasswd port", "464");
+ lpcfg_do_global_parameter_var(lp_ctx, "dns port", "%d", DNS_SERVICE_PORT);
+
+ lpcfg_do_global_parameter(lp_ctx, "kdc enable fast", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "nt status support", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "max wins ttl", "518400"); /* 6 days */
+ lpcfg_do_global_parameter(lp_ctx, "min wins ttl", "21600");
+
+ lpcfg_do_global_parameter(lp_ctx, "tls enabled", "True");
+ lpcfg_do_global_parameter(lp_ctx, "tls verify peer", "as_strict_as_possible");
+ lpcfg_do_global_parameter(lp_ctx, "tls keyfile", "tls/key.pem");
+ lpcfg_do_global_parameter(lp_ctx, "tls certfile", "tls/cert.pem");
+ lpcfg_do_global_parameter(lp_ctx, "tls cafile", "tls/ca.pem");
+ lpcfg_do_global_parameter(lp_ctx,
+ "tls priority",
+ "NORMAL:-VERS-SSL3.0");
+
+ lpcfg_do_global_parameter(lp_ctx, "nsupdate command", "/usr/bin/nsupdate -g");
+
+ lpcfg_do_global_parameter(lp_ctx, "allow dns updates", "secure only");
+ lpcfg_do_global_parameter(lp_ctx, "dns zone scavenging", "False");
+ lpcfg_do_global_parameter(lp_ctx, "dns forwarder", "");
+
+ lpcfg_do_global_parameter(lp_ctx, "algorithmic rid base", "1000");
+
+ lpcfg_do_global_parameter(lp_ctx, "enhanced browsing", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind nss info", "template");
+
+ lpcfg_do_global_parameter(lp_ctx, "server schannel", "True");
+ lpcfg_do_global_parameter(lp_ctx, "server schannel require seal", "True");
+ lpcfg_do_global_parameter(lp_ctx, "reject md5 clients", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "short preserve case", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "max open files", "16384");
+
+ lpcfg_do_global_parameter(lp_ctx, "cups connection timeout", "30");
+
+ lpcfg_do_global_parameter(lp_ctx, "locking", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "block size", "1024");
+
+ lpcfg_do_global_parameter(lp_ctx, "client use spnego", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "change notify", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "name cache timeout", "660");
+
+ lpcfg_do_global_parameter(lp_ctx, "defer sharing violations", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap replication sleep", "1000");
+
+ lpcfg_do_global_parameter(lp_ctx, "idmap backend", "tdb");
+
+ lpcfg_do_global_parameter(lp_ctx, "enable privileges", "True");
+
+ lpcfg_do_global_parameter_var(lp_ctx, "smb2 max write", "%u", DEFAULT_SMB2_MAX_WRITE);
+
+ lpcfg_do_global_parameter(lp_ctx, "passdb backend", "tdbsam");
+
+ lpcfg_do_global_parameter(lp_ctx, "deadtime", "10080");
+
+ lpcfg_do_global_parameter(lp_ctx, "getwd cache", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind nested groups", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "mangled names", "illegal");
+
+ lpcfg_do_global_parameter_var(lp_ctx, "smb2 max credits", "%u", DEFAULT_SMB2_MAX_CREDITS);
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap ssl", "start tls");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap deref", "auto");
+
+ lpcfg_do_global_parameter(lp_ctx, "lm interval", "60");
+
+ lpcfg_do_global_parameter(lp_ctx, "mangling method", "hash2");
+
+ lpcfg_do_global_parameter(lp_ctx, "hide dot files", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "browse list", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "passwd chat timeout", "2");
+
+ lpcfg_do_global_parameter(lp_ctx, "guest account", GUEST_ACCOUNT);
+
+ lpcfg_do_global_parameter(lp_ctx, "client schannel", "True");
+
+ lpcfg_do_global_parameter(lp_ctx, "smb encrypt", "default");
+
+ lpcfg_do_global_parameter(lp_ctx, "max log size", "5000");
+
+ lpcfg_do_global_parameter(lp_ctx, "idmap negative cache time", "120");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap follow referral", "auto");
+
+ lpcfg_do_global_parameter(lp_ctx, "multicast dns register", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind reconnect delay", "30");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind request timeout", "60");
+
+ lpcfg_do_global_parameter(lp_ctx, "nt acl support", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "acl check permissions", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "keepalive", "300");
+
+ lpcfg_do_global_parameter(lp_ctx, "smbd profiling level", "off");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind cache time", "300");
+
+ lpcfg_do_global_parameter(lp_ctx, "level2 oplocks", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "show add printer wizard", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap page size", "1000");
+
+ lpcfg_do_global_parameter(lp_ctx, "kernel share modes", "no");
+
+ lpcfg_do_global_parameter(lp_ctx, "strict locking", "Auto");
+
+ lpcfg_do_global_parameter(lp_ctx, "strict sync", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "map readonly", "no");
+
+ lpcfg_do_global_parameter(lp_ctx, "allow trusted domains", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "default devmode", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "os level", "20");
+
+ lpcfg_do_global_parameter(lp_ctx, "dos filetimes", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "mangling char", "~");
+
+ lpcfg_do_global_parameter(lp_ctx, "printcap cache time", "750");
+
+ lpcfg_do_global_parameter(lp_ctx, "create krb5 conf", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind max clients", "200");
+
+ lpcfg_do_global_parameter(lp_ctx, "acl map full control", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "nt pipe support", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap debug threshold", "10");
+
+ lpcfg_do_global_parameter(lp_ctx, "client ldap sasl wrapping", "seal");
+
+ lpcfg_do_global_parameter(lp_ctx, "mdns name", "netbios");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap server require strong auth", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "follow symlinks", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "machine password timeout", "604800");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap connection timeout", "2");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind expand groups", "0");
+
+ lpcfg_do_global_parameter(lp_ctx, "stat cache", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "lpq cache time", "30");
+
+ lpcfg_do_global_parameter_var(lp_ctx, "smb2 max trans", "%u", DEFAULT_SMB2_MAX_TRANSACT);
+
+ lpcfg_do_global_parameter_var(lp_ctx, "smb2 max read", "%u", DEFAULT_SMB2_MAX_READ);
+
+ lpcfg_do_global_parameter(lp_ctx, "durable handles", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "max stat cache size", "512");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap passwd sync", "no");
+
+ lpcfg_do_global_parameter(lp_ctx, "kernel change notify", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "max ttl", "259200");
+
+ lpcfg_do_global_parameter(lp_ctx, "blocking locks", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "load printers", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "idmap cache time", "604800");
+
+ lpcfg_do_global_parameter(lp_ctx, "preserve case", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "lm announce", "auto");
+
+ lpcfg_do_global_parameter(lp_ctx, "afs token lifetime", "604800");
+
+ lpcfg_do_global_parameter(lp_ctx, "enable core files", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "winbind max domain connections", "1");
+
+ lpcfg_do_global_parameter(lp_ctx, "case sensitive", "auto");
+
+ lpcfg_do_global_parameter(lp_ctx, "ldap timeout", "15");
+
+ lpcfg_do_global_parameter(lp_ctx, "mangle prefix", "1");
+
+ lpcfg_do_global_parameter(lp_ctx, "posix locking", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "lock spin time", "200");
+
+ lpcfg_do_global_parameter(lp_ctx, "nmbd bind explicit broadcast", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "init logon delay", "100");
+
+ lpcfg_do_global_parameter(lp_ctx, "usershare owner only", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "-valid", "yes");
+
+ lpcfg_do_global_parameter_var(lp_ctx, "usershare path", "%s/usershares", get_dyn_STATEDIR());
+
+#ifdef DEVELOPER
+ lpcfg_do_global_parameter_var(lp_ctx, "panic action", "/bin/sleep 999999999");
+#endif
+
+ lpcfg_do_global_parameter(lp_ctx, "smb passwd file", get_dyn_SMB_PASSWD_FILE());
+
+ lpcfg_do_global_parameter(lp_ctx, "logon home", "\\\\%N\\%U");
+
+ lpcfg_do_global_parameter(lp_ctx, "logon path", "\\\\%N\\%U\\profile");
+
+ lpcfg_do_global_parameter(lp_ctx, "printjob username", "%U");
+
+ lpcfg_do_global_parameter(lp_ctx, "aio max threads", "100");
+
+ lpcfg_do_global_parameter(lp_ctx, "smb2 leases", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "server multi channel support", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "kerberos encryption types", "all");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "rpc server dynamic port range",
+ "49152-65535");
+
+ lpcfg_do_global_parameter(lp_ctx, "prefork children", "4");
+ lpcfg_do_global_parameter(lp_ctx, "prefork backoff increment", "10");
+ lpcfg_do_global_parameter(lp_ctx, "prefork maximum backoff", "120");
+
+ lpcfg_do_global_parameter(lp_ctx, "check parent directory delete on close", "no");
+
+ lpcfg_do_global_parameter(lp_ctx, "ea support", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "store dos attributes", "yes");
+
+ lpcfg_do_global_parameter(lp_ctx, "debug encryption", "no");
+
+ lpcfg_do_global_parameter(lp_ctx, "spotlight backend", "noindex");
+
+ lpcfg_do_global_parameter(
+ lp_ctx, "ldap max anonymous request size", "256000");
+ lpcfg_do_global_parameter(
+ lp_ctx, "ldap max authenticated request size", "16777216");
+ lpcfg_do_global_parameter(
+ lp_ctx, "ldap max search request size", "256000");
+
+ /* Async DNS query timeout in seconds. */
+ lpcfg_do_global_parameter(lp_ctx, "async dns timeout", "10");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "client smb encrypt",
+ "default");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "client use kerberos",
+ "desired");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "client protection",
+ "default");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "smbd max xattr size",
+ "65536");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "acl flag inherited canonicalization",
+ "yes");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "winbind use krb5 enterprise principals",
+ "yes");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "client smb3 signing algorithms",
+ DEFAULT_SMB3_SIGNING_ALGORITHMS);
+ lpcfg_do_global_parameter(lp_ctx,
+ "server smb3 signing algorithms",
+ DEFAULT_SMB3_SIGNING_ALGORITHMS);
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "client smb3 encryption algorithms",
+ DEFAULT_SMB3_ENCRYPTION_ALGORITHMS);
+ lpcfg_do_global_parameter(lp_ctx,
+ "server smb3 encryption algorithms",
+ DEFAULT_SMB3_ENCRYPTION_ALGORITHMS);
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "min domain uid",
+ "1000");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "rpc start on demand helpers",
+ "yes");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "ad dc functional level",
+ "2008_R2");
+
+ lpcfg_do_global_parameter(lp_ctx,
+ "acl claims evaluation",
+ "AD DC only");
+
+ for (i = 0; parm_table[i].label; i++) {
+ if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
+ lp_ctx->flags[i] |= FLAG_DEFAULT;
+ }
+ }
+
+ for (parm=lp_ctx->globals->param_opt; parm; parm=parm->next) {
+ if (!(parm->priority & FLAG_CMDLINE)) {
+ parm->priority |= FLAG_DEFAULT;
+ }
+ }
+
+ for (parm=lp_ctx->sDefault->param_opt; parm; parm=parm->next) {
+ if (!(parm->priority & FLAG_CMDLINE)) {
+ parm->priority |= FLAG_DEFAULT;
+ }
+ }
+
+ return lp_ctx;
+}
+
+/**
+ * Initialise the global parameter structure.
+ */
+struct loadparm_context *loadparm_init_global(bool load_default)
+{
+ if (global_loadparm_context == NULL) {
+ global_loadparm_context = loadparm_init(NULL);
+ }
+ if (global_loadparm_context == NULL) {
+ return NULL;
+ }
+ global_loadparm_context->global = true;
+ if (load_default && !global_loadparm_context->loaded) {
+ lpcfg_load_default(global_loadparm_context);
+ }
+ global_loadparm_context->refuse_free = true;
+ return global_loadparm_context;
+}
+
+/**
+ * @brief Initialise the global parameter structure.
+ *
+ * This function initialized the globals if needed. Make sure that
+ * gfree_loadparm() is called before the application exits.
+ *
+ * @param mem_ctx The talloc memory context to allocate lp_ctx on.
+ *
+ * @param s3_fns The loadparm helper functions to use
+ *
+ * @return An initialized lp_ctx pointer or NULL on error.
+ */
+struct loadparm_context *loadparm_init_s3(TALLOC_CTX *mem_ctx,
+ const struct loadparm_s3_helpers *s3_fns)
+{
+ struct loadparm_context *loadparm_context = talloc_zero(mem_ctx, struct loadparm_context);
+ if (!loadparm_context) {
+ return NULL;
+ }
+ loadparm_context->s3_fns = s3_fns;
+ loadparm_context->globals = s3_fns->globals;
+ loadparm_context->flags = s3_fns->flags;
+
+ /* Make sure globals are correctly initialized */
+ loadparm_context->s3_fns->init_globals(loadparm_context, false);
+
+ return loadparm_context;
+}
+
+const char *lpcfg_configfile(struct loadparm_context *lp_ctx)
+{
+ return lp_ctx->szConfigFile;
+}
+
+const char *lp_default_path(void)
+{
+ if (getenv("SMB_CONF_PATH"))
+ return getenv("SMB_CONF_PATH");
+ else
+ return dyn_CONFIGFILE;
+}
+
+/**
+ * Update the internal state of a loadparm context after settings
+ * have changed.
+ */
+static bool lpcfg_update(struct loadparm_context *lp_ctx)
+{
+ struct debug_settings settings;
+ int max_protocol, min_protocol;
+ TALLOC_CTX *tmp_ctx;
+ const struct loadparm_substitution *lp_sub =
+ lpcfg_noop_substitution();
+
+ tmp_ctx = talloc_new(lp_ctx);
+ if (tmp_ctx == NULL) {
+ return false;
+ }
+
+ lpcfg_add_auto_services(lp_ctx, lpcfg_auto_services(lp_ctx, lp_sub, tmp_ctx));
+
+ if (!lp_ctx->globals->wins_server_list && lp_ctx->globals->we_are_a_wins_server) {
+ lpcfg_do_global_parameter(lp_ctx, "wins server", "127.0.0.1");
+ }
+
+ if (!lp_ctx->global) {
+ TALLOC_FREE(tmp_ctx);
+ return true;
+ }
+
+ panic_action = lp_ctx->globals->panic_action;
+
+ reload_charcnv(lp_ctx);
+
+ ZERO_STRUCT(settings);
+ /* Add any more debug-related smb.conf parameters created in
+ * future here */
+ settings.timestamp_logs = lp_ctx->globals->timestamp_logs;
+ settings.debug_prefix_timestamp = lp_ctx->globals->debug_prefix_timestamp;
+ settings.debug_hires_timestamp = lp_ctx->globals->debug_hires_timestamp;
+ settings.debug_syslog_format = lp_ctx->globals->debug_syslog_format;
+ settings.debug_pid = lp_ctx->globals->debug_pid;
+ settings.debug_uid = lp_ctx->globals->debug_uid;
+ settings.debug_class = lp_ctx->globals->debug_class;
+ settings.max_log_size = lp_ctx->globals->max_log_size;
+ debug_set_settings(&settings, lp_ctx->globals->logging,
+ lp_ctx->globals->syslog,
+ lp_ctx->globals->syslog_only);
+
+ /* FIXME: This is a bit of a hack, but we can't use a global, since
+ * not everything that uses lp also uses the socket library */
+ if (lpcfg_parm_bool(lp_ctx, NULL, "socket", "testnonblock", false)) {
+ setenv("SOCKET_TESTNONBLOCK", "1", 1);
+ } else {
+ unsetenv("SOCKET_TESTNONBLOCK");
+ }
+
+ /* Check if command line max protocol < min protocol, if so
+ * report a warning to the user.
+ */
+ max_protocol = lpcfg_client_max_protocol(lp_ctx);
+ min_protocol = lpcfg_client_min_protocol(lp_ctx);
+ if (lpcfg_client_max_protocol(lp_ctx) < lpcfg_client_min_protocol(lp_ctx)) {
+ const char *max_protocolp, *min_protocolp;
+ max_protocolp = lpcfg_get_smb_protocol(max_protocol);
+ min_protocolp = lpcfg_get_smb_protocol(min_protocol);
+ DBG_ERR("Max protocol %s is less than min protocol %s.\n",
+ max_protocolp, min_protocolp);
+ }
+
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+bool lpcfg_load_default(struct loadparm_context *lp_ctx)
+{
+ const char *path;
+
+ path = lp_default_path();
+
+ if (!file_exist(path)) {
+ /* We allow the default smb.conf file to not exist,
+ * basically the equivalent of an empty file. */
+ return lpcfg_update(lp_ctx);
+ }
+
+ return lpcfg_load(lp_ctx, path);
+}
+
+/**
+ * Load the services array from the services file.
+ *
+ * Return True on success, False on failure.
+ */
+static bool lpcfg_load_internal(struct loadparm_context *lp_ctx,
+ const char *filename, bool set_global)
+{
+ char *n2;
+ bool bRetval;
+
+ if (lp_ctx->szConfigFile != NULL) {
+ talloc_free(discard_const_p(char, lp_ctx->szConfigFile));
+ lp_ctx->szConfigFile = NULL;
+ }
+
+ lp_ctx->szConfigFile = talloc_strdup(lp_ctx, filename);
+
+ if (lp_ctx->s3_fns) {
+ return lp_ctx->s3_fns->load(filename);
+ }
+
+ lp_ctx->bInGlobalSection = true;
+ n2 = standard_sub_basic(lp_ctx, lp_ctx->szConfigFile);
+ DEBUG(2, ("lpcfg_load: refreshing parameters from %s\n", n2));
+
+ add_to_file_list(lp_ctx, &lp_ctx->file_lists, lp_ctx->szConfigFile, n2);
+
+ /* We get sections first, so have to start 'behind' to make up */
+ lp_ctx->currentService = NULL;
+ bRetval = pm_process(n2, do_section, lpcfg_do_parameter, lp_ctx);
+
+ /* finish up the last section */
+ DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
+ if (bRetval)
+ if (lp_ctx->currentService != NULL)
+ bRetval = lpcfg_service_ok(lp_ctx->currentService);
+
+ bRetval = bRetval && lpcfg_update(lp_ctx);
+
+ /* we do this unconditionally, so that it happens even
+ for a missing smb.conf */
+ reload_charcnv(lp_ctx);
+
+ if (bRetval == true && set_global) {
+ /* set this up so that any child python tasks will
+ find the right smb.conf */
+ setenv("SMB_CONF_PATH", filename, 1);
+
+ /* set the context used by the lp_*() function
+ variants */
+ global_loadparm_context = lp_ctx;
+ lp_ctx->loaded = true;
+ }
+
+ return bRetval;
+}
+
+bool lpcfg_load_no_global(struct loadparm_context *lp_ctx, const char *filename)
+{
+ return lpcfg_load_internal(lp_ctx, filename, false);
+}
+
+bool lpcfg_load(struct loadparm_context *lp_ctx, const char *filename)
+{
+ return lpcfg_load_internal(lp_ctx, filename, true);
+}
+
+/**
+ * Return the max number of services.
+ */
+
+int lpcfg_numservices(struct loadparm_context *lp_ctx)
+{
+ if (lp_ctx->s3_fns) {
+ return lp_ctx->s3_fns->get_numservices();
+ }
+
+ return lp_ctx->iNumServices;
+}
+
+/**
+ * Display the contents of the services array in human-readable form.
+ */
+
+void lpcfg_dump(struct loadparm_context *lp_ctx, FILE *f, bool show_defaults,
+ int maxtoprint)
+{
+ int iService;
+
+ if (lp_ctx->s3_fns) {
+ lp_ctx->s3_fns->dump(f, show_defaults, maxtoprint);
+ return;
+ }
+
+ lpcfg_dump_globals(lp_ctx, f, show_defaults);
+
+ lpcfg_dump_a_service(lp_ctx->sDefault, lp_ctx->sDefault, f, lp_ctx->flags, show_defaults);
+
+ for (iService = 0; iService < maxtoprint; iService++)
+ lpcfg_dump_one(f, show_defaults, lp_ctx->services[iService], lp_ctx->sDefault);
+}
+
+/**
+ * Display the contents of one service in human-readable form.
+ */
+void lpcfg_dump_one(FILE *f, bool show_defaults, struct loadparm_service *service, struct loadparm_service *sDefault)
+{
+ if (service != NULL) {
+ if (service->szService[0] == '\0')
+ return;
+ lpcfg_dump_a_service(service, sDefault, f, NULL, show_defaults);
+ }
+}
+
+struct loadparm_service *lpcfg_servicebynum(struct loadparm_context *lp_ctx,
+ int snum)
+{
+ if (lp_ctx->s3_fns) {
+ return lp_ctx->s3_fns->get_servicebynum(snum);
+ }
+
+ return lp_ctx->services[snum];
+}
+
+struct loadparm_service *lpcfg_service(struct loadparm_context *lp_ctx,
+ const char *service_name)
+{
+ int iService;
+ char *serviceName;
+
+ if (lp_ctx->s3_fns) {
+ return lp_ctx->s3_fns->get_service(service_name);
+ }
+
+ for (iService = lp_ctx->iNumServices - 1; iService >= 0; iService--) {
+ if (lp_ctx->services[iService] &&
+ lp_ctx->services[iService]->szService) {
+ /*
+ * The substitution here is used to support %U is
+ * service names
+ */
+ serviceName = standard_sub_basic(
+ lp_ctx->services[iService],
+ lp_ctx->services[iService]->szService);
+ if (strequal(serviceName, service_name)) {
+ talloc_free(serviceName);
+ return lp_ctx->services[iService];
+ }
+ talloc_free(serviceName);
+ }
+ }
+
+ DEBUG(7,("lpcfg_servicenumber: couldn't find %s\n", service_name));
+ return NULL;
+}
+
+const char *lpcfg_servicename(const struct loadparm_service *service)
+{
+ return service ? lpcfg_string((const char *)service->szService) : NULL;
+}
+
+struct smb_iconv_handle *lpcfg_iconv_handle(struct loadparm_context *lp_ctx)
+{
+ if (lp_ctx == NULL) {
+ return get_iconv_handle();
+ }
+ return lp_ctx->iconv_handle;
+}
+
+_PUBLIC_ void reload_charcnv(struct loadparm_context *lp_ctx)
+{
+ if (!lp_ctx->global) {
+ return;
+ }
+
+ lp_ctx->iconv_handle =
+ reinit_iconv_handle(lp_ctx,
+ lpcfg_dos_charset(lp_ctx),
+ lpcfg_unix_charset(lp_ctx));
+ if (lp_ctx->iconv_handle == NULL) {
+ smb_panic("reinit_iconv_handle failed");
+ }
+}
+
+_PUBLIC_ char *lpcfg_tls_keyfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
+{
+ return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_keyfile(lp_ctx));
+}
+
+_PUBLIC_ char *lpcfg_tls_certfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
+{
+ return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_certfile(lp_ctx));
+}
+
+_PUBLIC_ char *lpcfg_tls_cafile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
+{
+ return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_cafile(lp_ctx));
+}
+
+_PUBLIC_ char *lpcfg_tls_crlfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
+{
+ return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_crlfile(lp_ctx));
+}
+
+_PUBLIC_ char *lpcfg_tls_dhpfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
+{
+ return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_dhpfile(lp_ctx));
+}
+
+struct gensec_settings *lpcfg_gensec_settings(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
+{
+ struct gensec_settings *settings = talloc_zero(mem_ctx, struct gensec_settings);
+ if (settings == NULL)
+ return NULL;
+ SMB_ASSERT(lp_ctx != NULL);
+ settings->lp_ctx = talloc_reference(settings, lp_ctx);
+ settings->target_hostname = lpcfg_parm_string(lp_ctx, NULL, "gensec", "target_hostname");
+ return settings;
+}
+
+int lpcfg_server_role(struct loadparm_context *lp_ctx)
+{
+ int domain_master = lpcfg__domain_master(lp_ctx);
+
+ return lp_find_server_role(lpcfg__server_role(lp_ctx),
+ lpcfg__security(lp_ctx),
+ lpcfg__domain_logons(lp_ctx),
+ (domain_master == true) ||
+ (domain_master == Auto));
+}
+
+int lpcfg_security(struct loadparm_context *lp_ctx)
+{
+ return lp_find_security(lpcfg__server_role(lp_ctx),
+ lpcfg__security(lp_ctx));
+}
+
+int lpcfg_client_max_protocol(struct loadparm_context *lp_ctx)
+{
+ int client_max_protocol = lpcfg__client_max_protocol(lp_ctx);
+ if (client_max_protocol == PROTOCOL_DEFAULT) {
+ return PROTOCOL_LATEST;
+ }
+ return client_max_protocol;
+}
+
+int lpcfg_client_ipc_min_protocol(struct loadparm_context *lp_ctx)
+{
+ int client_ipc_min_protocol = lpcfg__client_ipc_min_protocol(lp_ctx);
+ if (client_ipc_min_protocol == PROTOCOL_DEFAULT) {
+ client_ipc_min_protocol = lpcfg_client_min_protocol(lp_ctx);
+ }
+ if (client_ipc_min_protocol < PROTOCOL_NT1) {
+ return PROTOCOL_NT1;
+ }
+ return client_ipc_min_protocol;
+}
+
+int lpcfg_client_ipc_max_protocol(struct loadparm_context *lp_ctx)
+{
+ int client_ipc_max_protocol = lpcfg__client_ipc_max_protocol(lp_ctx);
+ if (client_ipc_max_protocol == PROTOCOL_DEFAULT) {
+ return PROTOCOL_LATEST;
+ }
+ if (client_ipc_max_protocol < PROTOCOL_NT1) {
+ return PROTOCOL_NT1;
+ }
+ return client_ipc_max_protocol;
+}
+
+int lpcfg_client_ipc_signing(struct loadparm_context *lp_ctx)
+{
+ int client_ipc_signing = lpcfg__client_ipc_signing(lp_ctx);
+ if (client_ipc_signing == SMB_SIGNING_DEFAULT) {
+ return SMB_SIGNING_REQUIRED;
+ }
+ return client_ipc_signing;
+}
+
+enum credentials_use_kerberos lpcfg_client_use_kerberos(struct loadparm_context *lp_ctx)
+{
+ if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
+ return CRED_USE_KERBEROS_REQUIRED;
+ }
+
+ return lpcfg__client_use_kerberos(lp_ctx);
+}
+
+bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandatory)
+{
+ bool allowed = true;
+ enum smb_signing_setting signing_setting = lpcfg_server_signing(lp_ctx);
+
+ *mandatory = false;
+
+ if (signing_setting == SMB_SIGNING_DEFAULT) {
+ /*
+ * If we are a domain controller, SMB signing is
+ * really important, as it can prevent a number of
+ * attacks on communications between us and the
+ * clients
+ *
+ * However, it really sucks (no sendfile, CPU
+ * overhead) performance-wise when used on a
+ * file server, so disable it by default
+ * on non-DCs
+ */
+
+ if (lpcfg_server_role(lp_ctx) >= ROLE_ACTIVE_DIRECTORY_DC) {
+ signing_setting = SMB_SIGNING_REQUIRED;
+ } else {
+ signing_setting = SMB_SIGNING_OFF;
+ }
+ }
+
+ switch (signing_setting) {
+ case SMB_SIGNING_REQUIRED:
+ *mandatory = true;
+ break;
+ case SMB_SIGNING_DESIRED:
+ case SMB_SIGNING_IF_REQUIRED:
+ break;
+ case SMB_SIGNING_OFF:
+ allowed = false;
+ break;
+ case SMB_SIGNING_DEFAULT:
+ case SMB_SIGNING_IPC_DEFAULT:
+ smb_panic(__location__);
+ break;
+ }
+
+ return allowed;
+}
+
+int lpcfg_tdb_hash_size(struct loadparm_context *lp_ctx, const char *name)
+{
+ const char *base;
+
+ if (name == NULL) {
+ return 0;
+ }
+
+ base = strrchr_m(name, '/');
+ if (base != NULL) {
+ base += 1;
+ } else {
+ base = name;
+ }
+ return lpcfg_parm_int(lp_ctx, NULL, "tdb_hashsize", base, 0);
+
+}
+
+int lpcfg_tdb_flags(struct loadparm_context *lp_ctx, int tdb_flags)
+{
+ if (!lpcfg_use_mmap(lp_ctx)) {
+ tdb_flags |= TDB_NOMMAP;
+ }
+ return tdb_flags;
+}
+
+/*
+ * Do not allow LanMan auth if unless NTLMv1 is also allowed
+ *
+ * This also ensures it is disabled if NTLM is totally disabled
+ */
+bool lpcfg_lanman_auth(struct loadparm_context *lp_ctx)
+{
+ enum ntlm_auth_level ntlm_auth_level = lpcfg_ntlm_auth(lp_ctx);
+
+ if (ntlm_auth_level == NTLM_AUTH_ON) {
+ return lpcfg__lanman_auth(lp_ctx);
+ } else {
+ return false;
+ }
+}
+
+static char *lpcfg_noop_substitution_fn(
+ TALLOC_CTX *mem_ctx,
+ const struct loadparm_substitution *lp_sub,
+ const char *raw_value,
+ void *private_data)
+{
+ return talloc_strdup(mem_ctx, raw_value);
+}
+
+static const struct loadparm_substitution global_noop_substitution = {
+ .substituted_string_fn = lpcfg_noop_substitution_fn,
+};
+
+const struct loadparm_substitution *lpcfg_noop_substitution(void)
+{
+ return &global_noop_substitution;
+}
+
+char *lpcfg_substituted_string(TALLOC_CTX *mem_ctx,
+ const struct loadparm_substitution *lp_sub,
+ const char *raw_value)
+{
+ return lp_sub->substituted_string_fn(mem_ctx,
+ lp_sub,
+ raw_value,
+ lp_sub->private_data);
+}
+
+/**
+ * @brief Parse a string value of a given parameter to its integer enum value.
+ *
+ * @param[in] param_name The parameter name (e.g. 'client smb encrypt')
+ *
+ * @param[in] param_value The parameter value (e.g. 'required').
+ *
+ * @return The integer value of the enum the param_value matches or INT32_MIN
+ * on error.
+ */
+int32_t lpcfg_parse_enum_vals(const char *param_name,
+ const char *param_value)
+{
+ struct parm_struct *parm = NULL;
+ int32_t ret = INT32_MIN;
+ bool ok;
+
+ parm = lpcfg_parm_struct(NULL, param_name);
+ if (parm == NULL) {
+ return INT32_MIN;
+ }
+
+ ok = lp_set_enum_parm(parm, param_value, &ret);
+ if (!ok) {
+ return INT32_MIN;
+ }
+
+ return ret;
+}
diff --git a/lib/param/loadparm.h b/lib/param/loadparm.h
new file mode 100644
index 0000000..0bf4c17
--- /dev/null
+++ b/lib/param/loadparm.h
@@ -0,0 +1,344 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ type definitions for loadparm
+
+ Copyright (C) Karl Auer 1993-1998
+
+ Largely re-written by Andrew Tridgell, September 1994
+
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Alexander Bokovoy 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James Myers 2003 <myersjj@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LOADPARM_H
+#define _LOADPARM_H
+
+#include <talloc.h>
+
+struct parmlist_entry {
+ struct parmlist_entry *prev, *next;
+ char *key;
+ char *value;
+ char **list; /* For the source3 parametric options, to save the parsed list */
+ int priority;
+};
+
+struct parmlist {
+ struct parmlist_entry *entries;
+};
+
+/* the following are used by loadparm for option lists */
+typedef enum {
+ P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST,
+ P_STRING,P_USTRING,P_ENUM,P_BYTES,P_CMDLIST
+} parm_type;
+
+typedef enum {
+ P_LOCAL,P_GLOBAL,P_NONE
+} parm_class;
+
+struct enum_list {
+ int value;
+ const char *name;
+};
+
+struct loadparm_service;
+struct loadparm_context {
+ const char *szConfigFile;
+ struct loadparm_global *globals;
+ struct loadparm_service **services;
+ struct loadparm_service *sDefault;
+ struct smb_iconv_handle *iconv_handle;
+ int iNumServices;
+ struct loadparm_service *currentService;
+ bool bInGlobalSection;
+ struct file_lists *file_lists;
+ unsigned int *flags;
+ bool loaded;
+ bool refuse_free;
+ bool global; /* Is this the global context, which may set
+ * global variables such as debug level etc? */
+ const struct loadparm_s3_helpers *s3_fns;
+};
+
+struct parm_struct {
+ const char *label;
+ parm_type type;
+ parm_class p_class;
+ offset_t offset;
+ bool (*special)(struct loadparm_context *lpcfg_ctx,
+ struct loadparm_service *, const char *, char **);
+ const struct enum_list *enum_list;
+ unsigned flags;
+ union {
+ bool bvalue;
+ int ivalue;
+ char *svalue;
+ char cvalue;
+ char **lvalue;
+ } def;
+};
+
+extern struct parm_struct parm_table[];
+
+struct file_lists {
+ struct file_lists *next;
+ char *name;
+ char *subfname;
+ struct timespec modtime;
+};
+
+#define DEFAULT_NAME_RESOLVE_ORDER "lmhosts wins host bcast"
+#define FLAG_DEPRECATED 0x1000 /* options that should no longer be used */
+#define FLAG_SYNONYM 0x2000 /* options that is a synonym of another option */
+#define FLAG_CMDLINE 0x10000 /* option has been overridden */
+#define FLAG_DEFAULT 0x20000 /* this option was a default */
+
+/* This defines the section name in the configuration file that will
+ refer to the special "printers" service */
+#ifndef PRINTERS_NAME
+#define PRINTERS_NAME "printers"
+#endif
+
+/* This defines the section name in the configuration file that will
+ refer to the special "homes" service */
+#ifndef HOMES_NAME
+#define HOMES_NAME "homes"
+#endif
+
+/* This defines the section name in the configuration file that will contain */
+/* global parameters - that is, parameters relating to the whole server, not */
+/* just services. This name is then reserved, and may not be used as a */
+/* a service name. It will default to "global" if not defined here. */
+#ifndef GLOBAL_NAME
+#define GLOBAL_NAME "global"
+#define GLOBAL_NAME2 "globals"
+#endif
+
+/* The default workgroup - usually overridden in smb.conf */
+#ifndef DEFAULT_WORKGROUP
+#define DEFAULT_WORKGROUP "WORKGROUP"
+#endif
+
+/* types of configuration backends for loadparm */
+#define CONFIG_BACKEND_FILE 0
+#define CONFIG_BACKEND_REGISTRY 1
+
+/*
+ Do you want session setups at user level security with a invalid
+ password to be rejected or allowed in as guest? WinNT rejects them
+ but it can be a pain as it means "net view" needs to use a password
+
+ You have 3 choices in the setting of map_to_guest:
+
+ "NEVER_MAP_TO_GUEST" means session setups with an invalid password
+ are rejected. This is the default.
+
+ "MAP_TO_GUEST_ON_BAD_USER" means session setups with an invalid password
+ are rejected, unless the username does not exist, in which case it
+ is treated as a guest login
+
+ "MAP_TO_GUEST_ON_BAD_PASSWORD" means session setups with an invalid password
+ are treated as a guest login
+
+ Note that map_to_guest only has an effect in user or server
+ level security.
+*/
+
+#define NEVER_MAP_TO_GUEST 0
+#define MAP_TO_GUEST_ON_BAD_USER 1
+#define MAP_TO_GUEST_ON_BAD_PASSWORD 2
+#define MAP_TO_GUEST_ON_BAD_UID 3
+
+/*
+ * This should be under the HAVE_KRB5 flag but since they're used
+ * in lp_kerberos_method(), they need to be always available
+ * If you add any entries to KERBEROS_VERIFY defines, please modify USE.*KEYTAB macros
+ * so they remain accurate.
+ */
+
+#define KERBEROS_VERIFY_SECRETS 0
+#define KERBEROS_VERIFY_SYSTEM_KEYTAB 1
+#define KERBEROS_VERIFY_DEDICATED_KEYTAB 2
+#define KERBEROS_VERIFY_SECRETS_AND_KEYTAB 3
+
+#define KERBEROS_ETYPES_ALL 0
+#define KERBEROS_ETYPES_STRONG 1
+#define KERBEROS_ETYPES_LEGACY 2
+
+/* ACL compatibility */
+enum acl_compatibility {ACL_COMPAT_AUTO, ACL_COMPAT_WINNT, ACL_COMPAT_WIN2K};
+
+/* printing types */
+enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,
+ PRINT_QNX,PRINT_PLP,PRINT_LPRNG,PRINT_SOFTQ,
+ PRINT_CUPS,PRINT_LPRNT,PRINT_LPROS2,PRINT_IPRINT
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+,PRINT_TEST,PRINT_VLP
+#endif /* DEVELOPER */
+};
+
+#define SERVER_TCP_LOW_PORT 49152
+#define SERVER_TCP_HIGH_PORT 65535
+
+#define SERVER_TCP_PORT_MIN 1024
+#define SERVER_TCP_PORT_MAX 65535
+
+
+
+enum ldap_server_require_strong_auth {
+ LDAP_SERVER_REQUIRE_STRONG_AUTH_NO,
+ LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS,
+ LDAP_SERVER_REQUIRE_STRONG_AUTH_YES,
+};
+
+/* DNS update settings */
+enum dns_update_settings {DNS_UPDATE_OFF, DNS_UPDATE_ON, DNS_UPDATE_SIGNED};
+
+/* MDNS name sources */
+enum mdns_name_values {MDNS_NAME_NETBIOS, MDNS_NAME_MDNS};
+
+/* LDAP SSL options */
+enum ldap_ssl_types {LDAP_SSL_OFF, LDAP_SSL_START_TLS};
+
+/* LDAP PASSWD SYNC methods */
+enum ldap_passwd_sync_types {LDAP_PASSWD_SYNC_ON, LDAP_PASSWD_SYNC_OFF, LDAP_PASSWD_SYNC_ONLY};
+
+/* map readonly options */
+enum mapreadonly_options {MAP_READONLY_NO, MAP_READONLY_YES, MAP_READONLY_PERMISSIONS};
+
+/* case handling */
+enum case_handling {CASE_LOWER,CASE_UPPER};
+
+/* inherit owner options */
+enum inheritowner_options {
+ INHERIT_OWNER_NO,
+ INHERIT_OWNER_WINDOWS_AND_UNIX,
+ INHERIT_OWNER_UNIX_ONLY
+};
+
+/* mangled names options */
+enum mangled_names_options {MANGLED_NAMES_NO, MANGLED_NAMES_YES, MANGLED_NAMES_ILLEGAL};
+
+/* Spotlight backend options */
+enum spotlight_backend_options {
+ SPOTLIGHT_BACKEND_NOINDEX,
+ SPOTLIGHT_BACKEND_TRACKER,
+ SPOTLIGHT_BACKEND_ES,
+};
+
+/* FIPS values */
+enum samba_weak_crypto {
+ SAMBA_WEAK_CRYPTO_UNKNOWN,
+ SAMBA_WEAK_CRYPTO_ALLOWED,
+ SAMBA_WEAK_CRYPTO_DISALLOWED,
+};
+
+/* Controlling the storage of the NT password has on the AD DC */
+enum store_nt_hash {
+ NT_HASH_STORE_AUTO,
+ NT_HASH_STORE_NEVER,
+ NT_HASH_STORE_ALWAYS
+};
+
+/* Controlling the storage of the NT password has on the AD DC */
+enum acl_claims_evaluation {
+ ACL_CLAIMS_EVALUATION_AD_DC_ONLY,
+ ACL_CLAIMS_EVALUATION_NEVER
+};
+
+/*
+ * Default passwd chat script.
+ */
+#ifndef DEFAULT_PASSWD_CHAT
+#define DEFAULT_PASSWD_CHAT "*new*password* %n\\n *new*password* %n\\n *changed*"
+#endif
+
+/* Max number of jobs per print queue. */
+#ifndef PRINT_MAX_JOBID
+#define PRINT_MAX_JOBID 10000
+#endif
+
+/* the default guest account - allow override via CFLAGS */
+#ifndef GUEST_ACCOUNT
+#define GUEST_ACCOUNT "nobody"
+#endif
+
+/* SMB2 defaults */
+#define DEFAULT_SMB2_MAX_READ (8*1024*1024)
+#define DEFAULT_SMB2_MAX_WRITE (8*1024*1024)
+#define DEFAULT_SMB2_MAX_TRANSACT (8*1024*1024)
+#define DEFAULT_SMB2_MAX_CREDITS 8192
+
+#define DEFAULT_SMB3_SIGNING_ALGORITHMS "AES-128-GMAC AES-128-CMAC HMAC-SHA256"
+#define DEFAULT_SMB3_ENCRYPTION_ALGORITHMS "AES-128-GCM AES-128-CCM AES-256-GCM AES-256-CCM"
+
+#define LOADPARM_EXTRA_LOCALS \
+ int usershare; \
+ struct timespec usershare_last_mod; \
+ char *szService; \
+ struct parmlist_entry *param_opt; \
+ struct bitmap *copymap; \
+ char dummy[3]; /* for alignment */
+
+#include "lib/param/param_local.h"
+
+#define LOADPARM_EXTRA_GLOBALS \
+ struct parmlist_entry *param_opt; \
+ char *dnsdomain; \
+ int rpc_low_port; \
+ int rpc_high_port; \
+ enum samba_weak_crypto weak_crypto;
+
+const char* server_role_str(uint32_t role);
+int lp_find_server_role(int server_role, int security, int domain_logons, int domain_master);
+int lp_find_security(int server_role, int security);
+bool lp_is_security_and_server_role_valid(int server_role, int security);
+
+struct loadparm_global * get_globals(void);
+unsigned int * get_flags(void);
+int getservicebyname(const char *, struct loadparm_service *);
+bool lp_include(struct loadparm_context *, struct loadparm_service *,
+ const char *, char **);
+bool lp_do_section(const char *pszSectionName, void *userdata);
+bool store_lp_set_cmdline(const char *pszParmName, const char *pszParmValue);
+
+int num_parameters(void);
+int32_t lpcfg_parse_enum_vals(const char *param_name,
+ const char *param_value);
+
+struct loadparm_substitution;
+#ifdef LOADPARM_SUBSTITUTION_INTERNALS
+struct loadparm_substitution {
+ char *(*substituted_string_fn)(
+ TALLOC_CTX *mem_ctx,
+ const struct loadparm_substitution *lp_sub,
+ const char *raw_value,
+ void *private_data);
+ void *private_data;
+};
+#endif /* LOADPARM_SUBSTITUTION_INTERNALS */
+
+const struct loadparm_substitution *lpcfg_noop_substitution(void);
+char *lpcfg_substituted_string(TALLOC_CTX *mem_ctx,
+ const struct loadparm_substitution *lp_sub,
+ const char *raw_value);
+
+#endif /* _LOADPARM_H */
diff --git a/lib/param/loadparm_server_role.c b/lib/param/loadparm_server_role.c
new file mode 100644
index 0000000..a78d1ab
--- /dev/null
+++ b/lib/param/loadparm_server_role.c
@@ -0,0 +1,155 @@
+/*
+ Unix SMB/CIFS implementation.
+ Parameter loading functions
+ Copyright (C) Karl Auer 1993-1998
+
+ Largely re-written by Andrew Tridgell, September 1994
+
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Alexander Bokovoy 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Michael Adam 2008
+ Copyright (C) Andrew Bartlett 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "lib/param/loadparm.h"
+#include "libds/common/roles.h"
+
+/*******************************************************************
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+
+static const struct srv_role_tab {
+ uint32_t role;
+ const char *role_str;
+} srv_role_tab [] = {
+ { ROLE_STANDALONE, "ROLE_STANDALONE" },
+ { ROLE_DOMAIN_MEMBER, "ROLE_DOMAIN_MEMBER" },
+ { ROLE_DOMAIN_BDC, "ROLE_DOMAIN_BDC" },
+ { ROLE_DOMAIN_PDC, "ROLE_DOMAIN_PDC" },
+ { ROLE_ACTIVE_DIRECTORY_DC, "ROLE_ACTIVE_DIRECTORY_DC" },
+ { ROLE_IPA_DC, "ROLE_IPA_DC"},
+ { 0, NULL }
+};
+
+const char* server_role_str(uint32_t role)
+{
+ int i = 0;
+ for (i=0; srv_role_tab[i].role_str; i++) {
+ if (role == srv_role_tab[i].role) {
+ return srv_role_tab[i].role_str;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Set the server role based on security, domain logons and domain master
+ */
+int lp_find_server_role(int server_role, int security, int domain_logons, int domain_master)
+{
+ int role;
+
+ if (server_role != ROLE_AUTO) {
+ if (lp_is_security_and_server_role_valid(server_role, security)) {
+ return server_role;
+ }
+ }
+
+ /* If server_role is set to ROLE_AUTO, or conflicted with the
+ * chosen security setting, figure out the correct role */
+ role = ROLE_STANDALONE;
+
+ switch (security) {
+ case SEC_DOMAIN:
+ case SEC_ADS:
+ role = ROLE_DOMAIN_MEMBER;
+ break;
+ case SEC_AUTO:
+ case SEC_USER:
+ if (domain_logons) {
+
+ if (domain_master) {
+ role = ROLE_DOMAIN_PDC;
+ } else {
+ role = ROLE_DOMAIN_BDC;
+ }
+ }
+ break;
+ default:
+ DEBUG(0, ("Server's Role undefined due to unknown security mode\n"));
+ break;
+ }
+
+ return role;
+}
+
+/**
+ * Set the server role based on security, domain logons and domain master
+ */
+int lp_find_security(int server_role, int security)
+{
+ if (security != SEC_AUTO) {
+ return security;
+ }
+
+ switch (server_role) {
+ case ROLE_DOMAIN_MEMBER:
+ return SEC_ADS;
+ default:
+ return SEC_USER;
+ }
+}
+
+
+/**
+ * Check if server role and security parameters are contradictory
+ */
+bool lp_is_security_and_server_role_valid(int server_role, int security)
+{
+ bool valid = false;
+
+ if (security == SEC_AUTO) {
+ return true;
+ }
+
+ switch (server_role) {
+ case ROLE_AUTO:
+ valid = true;
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ if (security == SEC_ADS || security == SEC_DOMAIN) {
+ valid = true;
+ }
+ break;
+
+ case ROLE_STANDALONE:
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ case ROLE_ACTIVE_DIRECTORY_DC:
+ case ROLE_IPA_DC:
+ if (security == SEC_USER) {
+ valid = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return valid;
+}
diff --git a/lib/param/param.h b/lib/param/param.h
new file mode 100644
index 0000000..aed48c1
--- /dev/null
+++ b/lib/param/param.h
@@ -0,0 +1,282 @@
+/*
+ Unix SMB/CIFS implementation.
+ Generic parameter parsing interface
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PARAM_H /* _PARAM_H */
+#define _PARAM_H
+
+#include <talloc.h>
+
+struct loadparm_s3_helpers;
+struct loadparm_substitution;
+
+struct parmlist_entry;
+
+struct param_context {
+ struct param_section *sections;
+};
+
+struct param_section {
+ const char *name;
+ struct param_section *prev, *next;
+ struct parmlist *parameters;
+};
+
+struct param_context;
+struct smbsrv_connection;
+
+#define Auto (2)
+
+struct loadparm_context;
+struct loadparm_service;
+struct smbcli_options;
+struct smbcli_session_options;
+struct gensec_settings;
+struct bitmap;
+struct file_lists;
+
+#ifdef CONFIG_H_IS_FROM_SAMBA
+#include "lib/param/param_proto.h"
+#include "lib/param/param_functions.h"
+#endif
+
+const char **lpcfg_interfaces(struct loadparm_context *);
+const char *lpcfg_realm(struct loadparm_context *);
+const char *lpcfg_netbios_name(struct loadparm_context *);
+const char *lpcfg_private_dir(struct loadparm_context *);
+const char *lpcfg_binddns_dir(struct loadparm_context *);
+int lpcfg_server_role(struct loadparm_context *);
+int lpcfg_allow_dns_updates(struct loadparm_context *);
+
+void reload_charcnv(struct loadparm_context *lp_ctx);
+
+struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx);
+bool lpcfg_autoloaded(struct loadparm_service *, struct loadparm_service *);
+
+char *lpcfg_tls_keyfile(TALLOC_CTX *mem_ctx, struct loadparm_context *);
+char *lpcfg_tls_certfile(TALLOC_CTX *mem_ctx, struct loadparm_context *);
+char *lpcfg_tls_cafile(TALLOC_CTX *mem_ctx, struct loadparm_context *);
+char *lpcfg_tls_dhpfile(TALLOC_CTX *mem_ctx, struct loadparm_context *);
+char *lpcfg_tls_crlfile(TALLOC_CTX *mem_ctx, struct loadparm_context *);
+
+const char *lpcfg_dnsdomain(struct loadparm_context *);
+
+const char *lpcfg_servicename(const struct loadparm_service *service);
+
+
+const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *type, const char *option);
+
+const char *lpcfg_parm_string(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option);
+const char **lpcfg_parm_string_list(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *type,
+ const char *option, const char *separator);
+int lpcfg_parm_int(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, int default_v);
+int lpcfg_parm_bytes(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, int default_v);
+unsigned long lpcfg_parm_ulong(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, unsigned long default_v);
+unsigned long long lpcfg_parm_ulonglong(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *type, const char *option,
+ unsigned long long default_v);
+long lpcfg_parm_long(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, long default_v);
+double lpcfg_parm_double(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, double default_v);
+bool lpcfg_parm_bool(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, const char *type,
+ const char *option, bool default_v);
+struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
+ const struct loadparm_service *pservice,
+ const char *name);
+struct parm_struct *lpcfg_parm_struct(struct loadparm_context *lp_ctx, const char *name);
+void *lpcfg_parm_ptr(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service, struct parm_struct *parm);
+bool lpcfg_parm_is_cmdline(struct loadparm_context *lp_ctx, const char *name);
+bool lpcfg_parm_is_unspecified(struct loadparm_context *lp_ctx, const char *name);
+
+bool lpcfg_do_global_parameter(struct loadparm_context *lp_ctx,
+ const char *pszParmName, const char *pszParmValue);
+bool lpcfg_do_service_parameter(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *pszParmName, const char *pszParmValue);
+
+/**
+ * Process a parameter.
+ */
+bool lpcfg_do_global_parameter_var(struct loadparm_context *lp_ctx,
+ const char *pszParmName, const char *fmt, ...);
+bool lpcfg_set_cmdline(struct loadparm_context *lp_ctx, const char *pszParmName,
+ const char *pszParmValue);
+bool lpcfg_set_option(struct loadparm_context *lp_ctx, const char *option);
+
+/**
+ * Display the contents of a single services record.
+ */
+bool lpcfg_dump_a_parameter(struct loadparm_context *lp_ctx,
+ struct loadparm_service *service,
+ const char *parm_name, FILE * f);
+
+/**
+ * Initialise the global parameter structure.
+ */
+struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx);
+struct loadparm_context *loadparm_init_global(bool load_default);
+const char *lpcfg_configfile(struct loadparm_context *lp_ctx);
+bool lpcfg_load_default(struct loadparm_context *lp_ctx);
+const char *lp_default_path(void);
+
+/**
+ * Load the services array from the services file.
+ *
+ * Return True on success, False on failure.
+ */
+bool lpcfg_load(struct loadparm_context *lp_ctx, const char *filename);
+
+/**
+ * Return the max number of services.
+ */
+int lpcfg_numservices(struct loadparm_context *lp_ctx);
+
+/**
+ * Display the contents of the services array in human-readable form.
+ */
+void lpcfg_dump(struct loadparm_context *lp_ctx, FILE *f, bool show_defaults,
+ int maxtoprint);
+
+/**
+ * Display the contents of one service in human-readable form.
+ */
+void lpcfg_dump_one(FILE *f, bool show_defaults, struct loadparm_service *service, struct loadparm_service *sDefault);
+struct loadparm_service *lpcfg_servicebynum(struct loadparm_context *lp_ctx,
+ int snum);
+struct loadparm_service *lpcfg_service(struct loadparm_context *lp_ctx,
+ const char *service_name);
+
+struct smb_iconv_handle *lpcfg_iconv_handle(struct loadparm_context *lp_ctx);
+void lpcfg_smbcli_options(struct loadparm_context *lp_ctx,
+ struct smbcli_options *options);
+void lpcfg_smbcli_session_options(struct loadparm_context *lp_ctx,
+ struct smbcli_session_options *options);
+const char **lpcfg_smb_ports(struct loadparm_context *);
+const char *lpcfg_socket_options(struct loadparm_context *);
+struct dcerpc_server_info *lpcfg_dcerpc_server_info(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx);
+struct gensec_settings *lpcfg_gensec_settings(TALLOC_CTX *, struct loadparm_context *);
+
+/* The following definitions come from param/util.c */
+
+
+/**
+ * @file
+ * @brief Misc utility functions
+ */
+bool lpcfg_is_mydomain(struct loadparm_context *lp_ctx,
+ const char *domain);
+
+bool lpcfg_is_my_domain_or_realm(struct loadparm_context *lp_ctx,
+ const char *domain);
+
+/**
+ see if a string matches either our primary or one of our secondary
+ netbios aliases. do a case insensitive match
+*/
+bool lpcfg_is_myname(struct loadparm_context *lp_ctx, const char *name);
+
+/**
+ A useful function for returning a path in the Samba lock directory.
+**/
+char *lpcfg_lock_path(TALLOC_CTX* mem_ctx, struct loadparm_context *lp_ctx,
+ const char *name);
+
+/**
+ * @brief Returns an absolute path to a file in the directory containing the current config file
+ *
+ * @param name File to find, relative to the config file directory.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+char *lpcfg_config_path(TALLOC_CTX* mem_ctx, struct loadparm_context *lp_ctx,
+ const char *name);
+
+/**
+ * @brief Returns an absolute path to a file in the Samba private directory.
+ *
+ * @param name File to find, relative to PRIVATEDIR.
+ * if name is not relative, then use it as-is
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+char *lpcfg_private_path(TALLOC_CTX* mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *name);
+
+/**
+ * @brief Returns an absolute path to a NTDB or TDB file in the Samba
+ * private directory.
+ *
+ * @param name File to find, relative to PRIVATEDIR, without .tdb extension.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path, for
+ * use with dbwrap_local_open().
+ **/
+char *lpcfg_private_db_path(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *name);
+
+/**
+ return a path in the smbd.tmp directory, where all temporary file
+ for smbd go. If NULL is passed for name then return the directory
+ path itself
+*/
+char *smbd_tmp_path(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *name);
+
+const char *lpcfg_imessaging_path(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx);
+const char *lpcfg_sam_name(struct loadparm_context *lp_ctx);
+const char *lpcfg_sam_dnsname(struct loadparm_context *lp_ctx);
+
+void lpcfg_default_kdc_policy(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ time_t *svc_tkt_lifetime,
+ time_t *usr_tkt_lifetime,
+ time_t *renewal_lifetime);
+
+int lpcfg_rpc_port_low(struct loadparm_context *lp_ctx);
+int lpcfg_rpc_port_high(struct loadparm_context *lp_ctx);
+
+/* The following definitions come from lib/version.c */
+
+const char *samba_version_string(void);
+const char *samba_copyright_string(void);
+
+
+#endif /* _PARAM_H */
diff --git a/lib/param/param_table.c b/lib/param/param_table.c
new file mode 100644
index 0000000..ce59156
--- /dev/null
+++ b/lib/param/param_table.c
@@ -0,0 +1,463 @@
+/*
+ Unix SMB/CIFS implementation.
+ Parameter loading functions
+ Copyright (C) Karl Auer 1993-1998
+
+ Largely re-written by Andrew Tridgell, September 1994
+
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Alexander Bokovoy 2002
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Michael Adam 2008
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/param/param.h"
+#include "lib/param/loadparm.h"
+#include "lib/param/param_global.h"
+#include "libcli/auth/ntlm_check.h"
+#include "libcli/smb/smb_constants.h"
+#include "libds/common/roles.h"
+#include "libds/common/flags.h"
+#include "source4/lib/tls/tls.h"
+#include "auth/credentials/credentials.h"
+#include "source3/librpc/gen_ndr/ads.h"
+
+#ifndef N_
+#define N_(x) x
+#endif
+
+static const struct enum_list enum_protocol[] = {
+ {PROTOCOL_DEFAULT, "default"}, /* the caller decides what this means */
+ {PROTOCOL_SMB2_10, "SMB2"}, /* for now keep PROTOCOL_SMB2_10 */
+ {PROTOCOL_SMB3_11, "SMB3"}, /* for now keep PROTOCOL_SMB3_11 */
+ {PROTOCOL_SMB3_11, "SMB3_11"},
+ {PROTOCOL_SMB3_02, "SMB3_02"},
+ {PROTOCOL_SMB3_00, "SMB3_00"},
+ {PROTOCOL_SMB2_10, "SMB2_10"},
+ {PROTOCOL_SMB2_02, "SMB2_02"},
+ {PROTOCOL_NT1, "NT1"},
+ {PROTOCOL_LANMAN2, "LANMAN2"},
+ {PROTOCOL_LANMAN1, "LANMAN1"},
+ {PROTOCOL_CORE, "CORE"},
+ {PROTOCOL_COREPLUS, "COREPLUS"},
+ {PROTOCOL_COREPLUS, "CORE+"},
+ {-1, NULL}
+};
+
+const char* lpcfg_get_smb_protocol(int type)
+{
+ int i;
+ for (i = 1; enum_protocol[i].value != -1; i++) {
+ if (enum_protocol[i].value == type) {
+ return enum_protocol[i].name;
+ }
+ }
+ return NULL;
+}
+
+static const struct enum_list enum_security[] = {
+ {SEC_AUTO, "AUTO"},
+ {SEC_USER, "USER"},
+ {SEC_DOMAIN, "DOMAIN"},
+ {SEC_ADS, "ADS"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_bool_auto[] = {
+ {false, "No"},
+ {false, "False"},
+ {false, "0"},
+ {true, "Yes"},
+ {true, "True"},
+ {true, "1"},
+ {Auto, "Auto"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_csc_policy[] = {
+ {CSC_POLICY_MANUAL, "manual"},
+ {CSC_POLICY_DOCUMENTS, "documents"},
+ {CSC_POLICY_PROGRAMS, "programs"},
+ {CSC_POLICY_DISABLE, "disable"},
+ {-1, NULL}
+};
+
+/* Server role options */
+static const struct enum_list enum_server_role[] = {
+ {ROLE_AUTO, "auto"},
+ {ROLE_STANDALONE, "standalone server"},
+ {ROLE_STANDALONE, "standalone"},
+ {ROLE_DOMAIN_MEMBER, "member server"},
+ {ROLE_DOMAIN_MEMBER, "member"},
+ {ROLE_DOMAIN_PDC, "classic primary domain controller"},
+ {ROLE_DOMAIN_BDC, "classic backup domain controller"},
+ {ROLE_ACTIVE_DIRECTORY_DC, "active directory domain controller"},
+ {ROLE_ACTIVE_DIRECTORY_DC, "domain controller"},
+ {ROLE_ACTIVE_DIRECTORY_DC, "dc"},
+ {ROLE_IPA_DC, "IPA primary domain controller"},
+ {-1, NULL}
+};
+
+/* SMB signing types. */
+static const struct enum_list enum_smb_signing_vals[] = {
+ {SMB_SIGNING_DEFAULT, "default"},
+ {SMB_SIGNING_OFF, "No"},
+ {SMB_SIGNING_OFF, "False"},
+ {SMB_SIGNING_OFF, "0"},
+ {SMB_SIGNING_OFF, "Off"},
+ {SMB_SIGNING_OFF, "disabled"},
+ {SMB_SIGNING_IF_REQUIRED, "if_required"},
+ {SMB_SIGNING_IF_REQUIRED, "Yes"},
+ {SMB_SIGNING_IF_REQUIRED, "True"},
+ {SMB_SIGNING_IF_REQUIRED, "1"},
+ {SMB_SIGNING_IF_REQUIRED, "On"},
+ {SMB_SIGNING_IF_REQUIRED, "enabled"},
+ {SMB_SIGNING_IF_REQUIRED, "auto"},
+ {SMB_SIGNING_DESIRED, "desired"},
+ {SMB_SIGNING_REQUIRED, "required"},
+ {SMB_SIGNING_REQUIRED, "mandatory"},
+ {SMB_SIGNING_REQUIRED, "force"},
+ {SMB_SIGNING_REQUIRED, "forced"},
+ {SMB_SIGNING_REQUIRED, "enforced"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_smb_encryption_vals[] = {
+ {SMB_ENCRYPTION_DEFAULT, "default"},
+ {SMB_ENCRYPTION_OFF, "No"},
+ {SMB_ENCRYPTION_OFF, "False"},
+ {SMB_ENCRYPTION_OFF, "0"},
+ {SMB_ENCRYPTION_OFF, "Off"},
+ {SMB_ENCRYPTION_OFF, "disabled"},
+ {SMB_ENCRYPTION_IF_REQUIRED, "if_required"},
+ {SMB_ENCRYPTION_IF_REQUIRED, "Yes"},
+ {SMB_ENCRYPTION_IF_REQUIRED, "True"},
+ {SMB_ENCRYPTION_IF_REQUIRED, "1"},
+ {SMB_ENCRYPTION_IF_REQUIRED, "On"},
+ {SMB_ENCRYPTION_IF_REQUIRED, "enabled"},
+ {SMB_ENCRYPTION_IF_REQUIRED, "auto"},
+ {SMB_ENCRYPTION_DESIRED, "desired"},
+ {SMB_ENCRYPTION_REQUIRED, "required"},
+ {SMB_ENCRYPTION_REQUIRED, "mandatory"},
+ {SMB_ENCRYPTION_REQUIRED, "force"},
+ {SMB_ENCRYPTION_REQUIRED, "forced"},
+ {SMB_ENCRYPTION_REQUIRED, "enforced"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_use_kerberos_vals[] = {
+ {CRED_USE_KERBEROS_DESIRED, "desired"},
+ {CRED_USE_KERBEROS_DESIRED, "auto"},
+ {CRED_USE_KERBEROS_REQUIRED, "yes"},
+ {CRED_USE_KERBEROS_REQUIRED, "required"},
+ {CRED_USE_KERBEROS_DISABLED, "no"},
+ {CRED_USE_KERBEROS_DISABLED, "disabled"},
+ {CRED_USE_KERBEROS_DISABLED, "off"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_client_protection_vals[] = {
+ {CRED_CLIENT_PROTECTION_DEFAULT, "default"},
+ {CRED_CLIENT_PROTECTION_PLAIN, "plain"},
+ {CRED_CLIENT_PROTECTION_SIGN, "sign"},
+ {CRED_CLIENT_PROTECTION_ENCRYPT, "encrypt"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_mdns_name_values[] = {
+ {MDNS_NAME_NETBIOS, "netbios"},
+ {MDNS_NAME_MDNS, "mdns"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_tls_verify_peer_vals[] = {
+ {TLS_VERIFY_PEER_NO_CHECK,
+ TLS_VERIFY_PEER_NO_CHECK_STRING},
+ {TLS_VERIFY_PEER_CA_ONLY,
+ TLS_VERIFY_PEER_CA_ONLY_STRING},
+ {TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE,
+ TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING},
+ {TLS_VERIFY_PEER_CA_AND_NAME,
+ TLS_VERIFY_PEER_CA_AND_NAME_STRING},
+ {TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE,
+ TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING},
+ {-1, NULL}
+};
+
+/* DNS update options. */
+static const struct enum_list enum_dns_update_settings[] = {
+ {DNS_UPDATE_OFF, "disabled"},
+ {DNS_UPDATE_OFF, "No"},
+ {DNS_UPDATE_OFF, "False"},
+ {DNS_UPDATE_OFF, "0"},
+ {DNS_UPDATE_OFF, "Off"},
+ {DNS_UPDATE_ON, "nonsecure and secure"},
+ {DNS_UPDATE_ON, "nonsecure"},
+ {DNS_UPDATE_SIGNED, "secure only"},
+ {DNS_UPDATE_SIGNED, "secure"},
+ {DNS_UPDATE_SIGNED, "signed"},
+ {-1, NULL}
+};
+
+/*
+ Do you want session setups at user level security with a invalid
+ password to be rejected or allowed in as guest? WinNT rejects them
+ but it can be a pain as it means "net view" needs to use a password
+
+ You have 3 choices in the setting of map_to_guest:
+
+ "Never" means session setups with an invalid password
+ are rejected. This is the default.
+
+ "Bad User" means session setups with an invalid password
+ are rejected, unless the username does not exist, in which case it
+ is treated as a guest login
+
+ "Bad Password" means session setups with an invalid password
+ are treated as a guest login
+
+ Note that map_to_guest only has an effect in user or server
+ level security.
+*/
+
+static const struct enum_list enum_map_to_guest[] = {
+ {NEVER_MAP_TO_GUEST, "Never"},
+ {MAP_TO_GUEST_ON_BAD_USER, "Bad User"},
+ {MAP_TO_GUEST_ON_BAD_PASSWORD, "Bad Password"},
+ {MAP_TO_GUEST_ON_BAD_UID, "Bad Uid"},
+ {-1, NULL}
+};
+
+/* Config backend options */
+
+static const struct enum_list enum_config_backend[] = {
+ {CONFIG_BACKEND_FILE, "file"},
+ {CONFIG_BACKEND_REGISTRY, "registry"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_smbd_profiling_level[] = {
+ {0, "off"}, {1, "count"}, {2, "on"}, {-1, NULL}
+};
+
+
+/* ADS kerberos ticket verification options */
+
+static const struct enum_list enum_kerberos_method[] = {
+ {KERBEROS_VERIFY_SECRETS, "default"},
+ {KERBEROS_VERIFY_SECRETS, "secrets only"},
+ {KERBEROS_VERIFY_SECRETS, "secretsonly"},
+ {KERBEROS_VERIFY_SYSTEM_KEYTAB, "system keytab"},
+ {KERBEROS_VERIFY_SYSTEM_KEYTAB, "systemkeytab"},
+ {KERBEROS_VERIFY_DEDICATED_KEYTAB, "dedicated keytab"},
+ {KERBEROS_VERIFY_DEDICATED_KEYTAB, "dedicatedkeytab"},
+ {KERBEROS_VERIFY_SECRETS_AND_KEYTAB, "secrets and keytab"},
+ {KERBEROS_VERIFY_SECRETS_AND_KEYTAB, "secretsandkeytab"},
+ {-1, NULL}
+};
+
+/* Kerberos encryption types selection options */
+
+static const struct enum_list enum_kerberos_encryption_types_vals[] = {
+ {KERBEROS_ETYPES_ALL, "all"},
+ {KERBEROS_ETYPES_STRONG, "strong"},
+ {KERBEROS_ETYPES_LEGACY, "legacy"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_printing[] = {
+ {PRINT_SYSV, "sysv"},
+ {PRINT_AIX, "aix"},
+ {PRINT_HPUX, "hpux"},
+ {PRINT_BSD, "bsd"},
+ {PRINT_QNX, "qnx"},
+ {PRINT_PLP, "plp"},
+ {PRINT_LPRNG, "lprng"},
+#ifdef HAVE_CUPS
+ {PRINT_CUPS, "cups"},
+#endif
+#ifdef HAVE_IPRINT
+ {PRINT_IPRINT, "iprint"},
+#endif
+ {PRINT_LPRNT, "nt"},
+ {PRINT_LPROS2, "os2"},
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+ {PRINT_TEST, "test"},
+ {PRINT_VLP, "vlp"},
+#endif /* DEVELOPER */
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ldap_sasl_wrapping[] = {
+ {0, "plain"},
+ {ADS_AUTH_SASL_SIGN, "sign"},
+ {ADS_AUTH_SASL_SEAL, "seal"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ldap_server_require_strong_auth_vals[] = {
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "No" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "False" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_NO, "0" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS,
+ "allow_sasl_over_tls" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "Yes" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "True" },
+ { LDAP_SERVER_REQUIRE_STRONG_AUTH_YES, "1" },
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ldap_ssl[] = {
+ {LDAP_SSL_OFF, "no"},
+ {LDAP_SSL_OFF, "off"},
+ {LDAP_SSL_START_TLS, "start tls"},
+ {LDAP_SSL_START_TLS, "start_tls"},
+ {-1, NULL}
+};
+
+/* LDAP Dereferencing Alias types */
+#define SAMBA_LDAP_DEREF_NEVER 0
+#define SAMBA_LDAP_DEREF_SEARCHING 1
+#define SAMBA_LDAP_DEREF_FINDING 2
+#define SAMBA_LDAP_DEREF_ALWAYS 3
+
+static const struct enum_list enum_ldap_deref[] = {
+ {SAMBA_LDAP_DEREF_NEVER, "never"},
+ {SAMBA_LDAP_DEREF_SEARCHING, "searching"},
+ {SAMBA_LDAP_DEREF_FINDING, "finding"},
+ {SAMBA_LDAP_DEREF_ALWAYS, "always"},
+ {-1, "auto"}
+};
+
+static const struct enum_list enum_ldap_passwd_sync[] = {
+ {LDAP_PASSWD_SYNC_OFF, "no"},
+ {LDAP_PASSWD_SYNC_OFF, "off"},
+ {LDAP_PASSWD_SYNC_ON, "yes"},
+ {LDAP_PASSWD_SYNC_ON, "on"},
+ {LDAP_PASSWD_SYNC_ONLY, "only"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_map_readonly[] = {
+ {MAP_READONLY_NO, "no"},
+ {MAP_READONLY_NO, "false"},
+ {MAP_READONLY_NO, "0"},
+ {MAP_READONLY_YES, "yes"},
+ {MAP_READONLY_YES, "true"},
+ {MAP_READONLY_YES, "1"},
+ {MAP_READONLY_PERMISSIONS, "permissions"},
+ {MAP_READONLY_PERMISSIONS, "perms"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_case[] = {
+ {CASE_LOWER, "lower"},
+ {CASE_UPPER, "upper"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_inherit_owner_vals[] = {
+ {INHERIT_OWNER_NO, "no"},
+ {INHERIT_OWNER_WINDOWS_AND_UNIX, "windows and unix"},
+ {INHERIT_OWNER_WINDOWS_AND_UNIX, "yes"},
+ {INHERIT_OWNER_UNIX_ONLY, "unix only"},
+ {-1, NULL}};
+
+static const struct enum_list enum_mangled_names[] = {
+ {MANGLED_NAMES_NO, "no"},
+ {MANGLED_NAMES_NO, "false"},
+ {MANGLED_NAMES_NO, "0"},
+ {MANGLED_NAMES_ILLEGAL, "illegal"},
+ {MANGLED_NAMES_YES, "yes"},
+ {MANGLED_NAMES_YES, "true"},
+ {MANGLED_NAMES_YES, "1"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ntlm_auth[] = {
+ {NTLM_AUTH_DISABLED, "disabled"},
+ {NTLM_AUTH_NTLMV2_ONLY, "ntlmv2-only"},
+ {NTLM_AUTH_NTLMV2_ONLY, "no"},
+ {NTLM_AUTH_NTLMV2_ONLY, "false"},
+ {NTLM_AUTH_NTLMV2_ONLY, "0"},
+ {NTLM_AUTH_ON, "ntlmv1-permitted"},
+ {NTLM_AUTH_ON, "yes"},
+ {NTLM_AUTH_ON, "true"},
+ {NTLM_AUTH_ON, "1"},
+ {NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY, "mschapv2-and-ntlmv2-only"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_nt_hash_store[] = {
+ {NT_HASH_STORE_AUTO, "auto"},
+ {NT_HASH_STORE_NEVER, "never"},
+ {NT_HASH_STORE_ALWAYS, "always"},
+};
+
+
+static const struct enum_list enum_spotlight_backend[] = {
+ {SPOTLIGHT_BACKEND_NOINDEX, "noindex"},
+ {SPOTLIGHT_BACKEND_TRACKER, "tracker"},
+ {SPOTLIGHT_BACKEND_ES, "elasticsearch"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_debug_syslog_format[] = {
+ {DEBUG_SYSLOG_FORMAT_NO, "No"},
+ {DEBUG_SYSLOG_FORMAT_NO, "False"},
+ {DEBUG_SYSLOG_FORMAT_NO, "0"},
+ {DEBUG_SYSLOG_FORMAT_IN_LOGS, "in_logs"},
+ {DEBUG_SYSLOG_FORMAT_IN_LOGS, "Yes"},
+ {DEBUG_SYSLOG_FORMAT_IN_LOGS, "True"},
+ {DEBUG_SYSLOG_FORMAT_IN_LOGS, "1"},
+ {DEBUG_SYSLOG_FORMAT_ALWAYS, "always"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_ad_functional_level[] = {
+ {DS_DOMAIN_FUNCTION_2008_R2, "2008_R2"},
+ {DS_DOMAIN_FUNCTION_2012, "2012"},
+ {DS_DOMAIN_FUNCTION_2012_R2, "2012_R2"},
+ {DS_DOMAIN_FUNCTION_2016, "2016"},
+ {-1, NULL}
+};
+
+static const struct enum_list enum_acl_claims_evaluation[] = {
+ {ACL_CLAIMS_EVALUATION_AD_DC_ONLY, "AD DC only"},
+ {ACL_CLAIMS_EVALUATION_NEVER, "never"},
+ {-1, NULL}
+};
+
+/* Note: We do not initialise the defaults union - it is not allowed in ANSI C
+ *
+ * NOTE: Handling of duplicated (synonym) parameters:
+ * Parameters that are synonymous are stored in the same variable.
+ * All but the default spelling carry the flag FLAG_SYNONYM.
+ */
+
+#define GLOBAL_VAR(name) offsetof(struct loadparm_global, name)
+#define LOCAL_VAR(name) offsetof(struct loadparm_service, name)
+
+#include "lib/param/param_table_gen.c"
+
+int num_parameters(void)
+{
+ return (sizeof(parm_table) / sizeof(struct parm_struct));
+}
diff --git a/lib/param/s3_param.h b/lib/param/s3_param.h
new file mode 100644
index 0000000..60a2911
--- /dev/null
+++ b/lib/param/s3_param.h
@@ -0,0 +1,23 @@
+#ifndef __S3_PARAM_H__
+#define __S3_PARAM_H__
+
+struct loadparm_s3_helpers
+{
+ void * (*get_parm_ptr)(struct loadparm_service *service, struct parm_struct *parm);
+ struct loadparm_service * (*get_service)(const char *service_name);
+ struct loadparm_service * (*get_servicebynum)(int snum);
+ int (*getservicebyname)(const char *, struct loadparm_service *);
+ int (*get_numservices)(void);
+ bool (*load)(const char *filename);
+ bool (*store_cmdline)(const char *pszParmName, const char *pszParmValue);
+ void (*dump)(FILE *f, bool show_defaults, int maxtoprint);
+ bool (*lp_include)(struct loadparm_context*, struct loadparm_service *,
+ const char *, char **);
+ void (*init_ldap_debugging)(void);
+ bool (*do_section)(const char *pszSectionName, void *userdata);
+ void (*init_globals)(struct loadparm_context *lp_ctx, bool reinit_globals);
+ struct loadparm_global *globals;
+ unsigned int *flags;
+};
+
+#endif /* __S3_PARAM_H__ */
diff --git a/lib/param/samba-hostconfig.pc.in b/lib/param/samba-hostconfig.pc.in
new file mode 100644
index 0000000..307f27b
--- /dev/null
+++ b/lib/param/samba-hostconfig.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: samba-hostconfig
+Description: Host-wide Samba configuration
+Version: @PACKAGE_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -lsamba-hostconfig
+Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1
diff --git a/lib/param/util.c b/lib/param/util.c
new file mode 100644
index 0000000..8d862ad
--- /dev/null
+++ b/lib/param/util.c
@@ -0,0 +1,340 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+ Copyright (C) Jelmer Vernooij 2005-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "dynconfig/dynconfig.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include "param/param.h"
+#include "libds/common/roles.h"
+#include "tdb.h"
+
+/**
+ * @file
+ * @brief Misc utility functions
+ */
+
+
+bool lpcfg_is_mydomain(struct loadparm_context *lp_ctx,
+ const char *domain)
+{
+ return strequal(lpcfg_workgroup(lp_ctx), domain);
+}
+
+bool lpcfg_is_my_domain_or_realm(struct loadparm_context *lp_ctx,
+ const char *domain)
+{
+ return strequal(lpcfg_workgroup(lp_ctx), domain) ||
+ strequal(lpcfg_realm(lp_ctx), domain);
+}
+
+/**
+ see if a string matches either our primary or one of our secondary
+ netbios aliases. do a case insensitive match
+*/
+bool lpcfg_is_myname(struct loadparm_context *lp_ctx, const char *name)
+{
+ const char **aliases;
+ int i;
+
+ if (strcasecmp_m(name, lpcfg_netbios_name(lp_ctx)) == 0) {
+ return true;
+ }
+
+ aliases = lpcfg_netbios_aliases(lp_ctx);
+ for (i=0; aliases && aliases[i]; i++) {
+ if (strcasecmp_m(name, aliases[i]) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static char *lpcfg_common_path(TALLOC_CTX* mem_ctx,
+ const char *parent,
+ const char *name)
+{
+ char *fname, *dname;
+ bool ok;
+
+ if (name == NULL) {
+ return NULL;
+ }
+ if (name[0] == 0 || name[0] == '/' || strstr(name, ":/")) {
+ return talloc_strdup(mem_ctx, name);
+ }
+
+ dname = talloc_strdup(mem_ctx, parent);
+ if (dname == NULL) {
+ return NULL;
+ }
+ trim_string(dname,"","/");
+
+ ok = directory_create_or_exist(dname, 0755);
+ if (!ok) {
+ DEBUG(1, ("Unable to create directory %s for file %s. "
+ "Error was %s\n", dname, name, strerror(errno)));
+ return NULL;
+ }
+
+ fname = talloc_asprintf(mem_ctx, "%s/%s", dname, name);
+ if (fname == NULL) {
+ return dname;
+ }
+ talloc_free(dname);
+
+ return fname;
+}
+
+
+/**
+ A useful function for returning a path in the Samba lock directory.
+**/
+char *lpcfg_lock_path(TALLOC_CTX* mem_ctx, struct loadparm_context *lp_ctx,
+ const char *name)
+{
+ return lpcfg_common_path(mem_ctx, lpcfg_lock_directory(lp_ctx), name);
+}
+
+/**
+ A useful function for returning a path in the Samba state directory.
+**/
+char *lpcfg_state_path(TALLOC_CTX* mem_ctx, struct loadparm_context *lp_ctx,
+ const char *name)
+{
+ return lpcfg_common_path(mem_ctx, lpcfg_state_directory(lp_ctx), name);
+}
+
+/**
+ A useful function for returning a path in the Samba cache directory.
+**/
+char *lpcfg_cache_path(TALLOC_CTX* mem_ctx, struct loadparm_context *lp_ctx,
+ const char *name)
+{
+ return lpcfg_common_path(mem_ctx, lpcfg_cache_directory(lp_ctx), name);
+}
+
+/**
+ * @brief Returns an absolute path to a file in the directory containing the current config file
+ *
+ * @param name File to find, relative to the config file directory.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+
+char *lpcfg_config_path(TALLOC_CTX* mem_ctx, struct loadparm_context *lp_ctx,
+ const char *name)
+{
+ char *fname, *config_dir, *p;
+ config_dir = talloc_strdup(mem_ctx, lpcfg_configfile(lp_ctx));
+ if (config_dir == NULL) {
+ config_dir = talloc_strdup(mem_ctx, lp_default_path());
+ }
+ p = strrchr(config_dir, '/');
+ if (p == NULL) {
+ talloc_free(config_dir);
+ config_dir = talloc_strdup(mem_ctx, ".");
+ if (config_dir == NULL) {
+ return NULL;
+ }
+ } else {
+ p[0] = '\0';
+ }
+ fname = talloc_asprintf(mem_ctx, "%s/%s", config_dir, name);
+ talloc_free(config_dir);
+ return fname;
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba private directory.
+ *
+ * @param name File to find, relative to PRIVATEDIR.
+ * if name is not relative, then use it as-is
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+char *lpcfg_private_path(TALLOC_CTX* mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *name)
+{
+ char *fname;
+ if (name == NULL) {
+ return NULL;
+ }
+ if (name[0] == 0 || name[0] == '/' || strstr(name, ":/")) {
+ return talloc_strdup(mem_ctx, name);
+ }
+ fname = talloc_asprintf(mem_ctx, "%s/%s", lpcfg_private_dir(lp_ctx), name);
+ return fname;
+}
+
+/**
+ * @brief Returns an absolute path to a NTDB or TDB file in the Samba
+ * private directory.
+ *
+ * @param name File to find, relative to PRIVATEDIR, without .tdb extension.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path, for
+ * use with dbwrap_local_open().
+ **/
+char *lpcfg_private_db_path(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *name)
+{
+ return talloc_asprintf(mem_ctx, "%s/%s.tdb",
+ lpcfg_private_dir(lp_ctx), name);
+}
+
+/**
+ return a path in the smbd.tmp directory, where all temporary file
+ for smbd go. If NULL is passed for name then return the directory
+ path itself
+*/
+char *smbd_tmp_path(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *name)
+{
+ char *fname, *dname;
+ bool ok;
+
+ dname = lpcfg_private_path(mem_ctx, lp_ctx, "smbd.tmp");
+ if (dname == NULL) {
+ return NULL;
+ }
+
+ ok = directory_create_or_exist(dname, 0755);
+ if (!ok) {
+ return NULL;
+ }
+
+ if (name == NULL) {
+ return dname;
+ }
+
+ fname = talloc_asprintf(mem_ctx, "%s/%s", dname, name);
+ if (fname == NULL) {
+ return dname;
+ }
+ talloc_free(dname);
+
+ return fname;
+}
+
+const char *lpcfg_imessaging_path(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx)
+{
+ return smbd_tmp_path(mem_ctx, lp_ctx, "msg");
+}
+
+const char *lpcfg_sam_name(struct loadparm_context *lp_ctx)
+{
+ switch (lpcfg_server_role(lp_ctx)) {
+ case ROLE_DOMAIN_BDC:
+ case ROLE_DOMAIN_PDC:
+ case ROLE_ACTIVE_DIRECTORY_DC:
+ case ROLE_IPA_DC:
+ return lpcfg_workgroup(lp_ctx);
+ default:
+ return lpcfg_netbios_name(lp_ctx);
+ }
+}
+
+const char *lpcfg_sam_dnsname(struct loadparm_context *lp_ctx)
+{
+ switch (lpcfg_server_role(lp_ctx)) {
+ case ROLE_ACTIVE_DIRECTORY_DC:
+ case ROLE_IPA_DC:
+ return lpcfg_dnsdomain(lp_ctx);
+ default:
+ return NULL;
+ }
+}
+
+static int
+tdb_fetch_lifetime_fn(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ if (data.dsize < 256) {
+ long *result = private_data;
+ char tmp[data.dsize + 1];
+ memcpy(tmp, data.dptr, data.dsize);
+ tmp[data.dsize] = '\0';
+ *result = atol(tmp);
+ return 0;
+ }
+ return -1;
+}
+
+static long tdb_fetch_lifetime(struct tdb_context *tdb,
+ const char *keystr)
+{
+ long result = -1;
+ int ret;
+
+ ret = tdb_parse_record(
+ tdb,
+ (TDB_DATA){
+ .dptr = discard_const_p(uint8_t, keystr),
+ .dsize = strlen(keystr),
+ },
+ tdb_fetch_lifetime_fn,
+ &result);
+ if (ret == -1) {
+ return -1;
+ }
+ return result;
+}
+
+void lpcfg_default_kdc_policy(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ time_t *svc_tkt_lifetime,
+ time_t *usr_tkt_lifetime,
+ time_t *renewal_lifetime)
+{
+ long val;
+ TDB_CONTEXT *ctx = NULL;
+ const char *kdc_tdb = NULL;
+
+ kdc_tdb = lpcfg_cache_path(mem_ctx, lp_ctx, "gpo.tdb");
+ if (kdc_tdb)
+ ctx = tdb_open(kdc_tdb, 0, TDB_DEFAULT, O_RDWR, 0600);
+
+ if (!ctx || ( val = tdb_fetch_lifetime(ctx, "kdc:service_ticket_lifetime") ) == -1 )
+ val = lpcfg_parm_long(lp_ctx, NULL, "kdc", "service ticket lifetime", 10);
+ *svc_tkt_lifetime = val * 60 * 60;
+
+ if (!ctx || ( val = tdb_fetch_lifetime(ctx, "kdc:user_ticket_lifetime") ) == -1 )
+ val = lpcfg_parm_long(lp_ctx, NULL, "kdc", "user ticket lifetime", 10);
+ *usr_tkt_lifetime = val * 60 * 60;
+
+ if (!ctx || ( val = tdb_fetch_lifetime(ctx, "kdc:renewal_lifetime") ) == -1 )
+ val = lpcfg_parm_long(lp_ctx, NULL, "kdc", "renewal lifetime", 24 * 7);
+ *renewal_lifetime = val * 60 * 60;
+
+ if (ctx != NULL) {
+ tdb_close(ctx);
+ ctx = NULL;
+ }
+}
diff --git a/lib/param/wscript_build b/lib/param/wscript_build
new file mode 100644
index 0000000..864975a
--- /dev/null
+++ b/lib/param/wscript_build
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+bld.SAMBA_GENERATOR('param_functions.c',
+ source= '../../script/generate_param.py ../../docs-xml/smbdotconf/parameters.all.xml',
+ target='param_functions.c',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} --file ${SRC[1].abspath(env)} --output ${TGT} --mode=FUNCTIONS')
+
+bld.SAMBA_GENERATOR('param_functions.h',
+ source= '../../script/generate_param.py ../../docs-xml/smbdotconf/parameters.all.xml',
+ target='param_functions.h',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} --file ${SRC[1].abspath(env)} --output ${TGT} --mode=LIBPROTO')
+
+bld.SAMBA_GENERATOR('param_local.h',
+ source= '../../script/generate_param.py ../../docs-xml/smbdotconf/parameters.all.xml',
+ target='param_local.h',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} --file ${SRC[1].abspath(env)} --output ${TGT} --mode=PARAMDEFS --scope=LOCAL')
+
+bld.SAMBA_GENERATOR('param_global.h',
+ source= '../../script/generate_param.py ../../docs-xml/smbdotconf/parameters.all.xml',
+ target='param_global.h',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} --file ${SRC[1].abspath(env)} --output ${TGT} --mode=PARAMDEFS --scope=GLOBAL')
+
+bld.SAMBA_GENERATOR('param_table_gen.c',
+ source='../../script/generate_param.py ../../docs-xml/smbdotconf/parameters.all.xml',
+ target='param_table_gen.c',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} --file ${SRC[1].abspath(env)} --output ${TGT} --mode=PARAMTABLE')
+
+bld.SAMBA_LIBRARY('server-role',
+ source='loadparm_server_role.c',
+ deps='samba-util samba-debug',
+ private_library=True)
+
+bld.SAMBA_LIBRARY('samba-hostconfig',
+ source='loadparm.c util.c param_table.c',
+ pc_files='samba-hostconfig.pc',
+ vnum='0.0.1',
+ deps='DYNCONFIG server-role tdb',
+ public_deps='GNUTLS_HELPERS samba-util param_local.h',
+ public_headers='param.h',
+ autoproto='param_proto.h'
+ )
+
+
diff --git a/lib/printer_driver/printer_driver.c b/lib/printer_driver/printer_driver.c
new file mode 100644
index 0000000..2d07df3
--- /dev/null
+++ b/lib/printer_driver/printer_driver.c
@@ -0,0 +1,1255 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Guenther Deschner 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "rpc_client/init_spoolss.h"
+#include "libgpo/gpo_ini.h"
+#include "printer_driver.h"
+
+#define ADD_TO_ARRAY(mem_ctx, type, elem, array, num) \
+do { \
+ *(array) = talloc_realloc(mem_ctx, (*(array)), type, (*(num))+1); \
+ SMB_ASSERT((*(array)) != NULL); \
+ (*(array))[*(num)] = (elem); \
+ (*(num)) += 1; \
+} while (0)
+
+
+/* GetPrinterDriverDirectory -> drivers and dependent files */
+#define PRINTER_INF_DIRID_66000
+
+/* GetPrintProcessorDirectory -> print processors */
+#define PRINTER_INF_DIRID_66001
+
+/* GetColorDirectory -> color profiles */
+#define PRINTER_INF_DIRID_66003
+
+static const char *get_string_unquote(const char *s)
+{
+ bool ok;
+ size_t len;
+
+ if (s == NULL) {
+ return NULL;
+ }
+
+ len = strlen(s);
+ if (len < 2) {
+ return s;
+ }
+
+ if (s[0] == '"' && s[len-1] == '"') {
+ ok = trim_string(discard_const(s), "\"", "\"");
+ if (!ok) {
+ return NULL;
+ }
+ }
+
+ return s;
+}
+
+/*
+ * '%STRING%' indicates STRING is localized in the [Strings] section
+ */
+
+static const char *get_string_token(struct gp_inifile_context *ctx,
+ const char *s)
+{
+ NTSTATUS status;
+ bool ok;
+ char *key;
+ const char *s2;
+
+ if (s != NULL && s[0] != '%' && s[strlen(s)-1] != '%') {
+ return s;
+ }
+
+ ok = trim_string(discard_const(s), "%", "%");
+ if (!ok) {
+ return NULL;
+ }
+
+ key = talloc_asprintf(ctx, "Strings:%s", s);
+ if (key == NULL) {
+ return NULL;
+ }
+
+ status = gp_inifile_getstring(ctx, key, &s2);
+ talloc_free(key);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* what can you do... */
+ return s;
+ }
+
+ return s2;
+}
+
+static NTSTATUS gp_inifile_getstring_ext(struct gp_inifile_context *ctx,
+ const char *key,
+ const char **ret)
+{
+ NTSTATUS status;
+ const char *s;
+
+ status = gp_inifile_getstring(ctx, key, &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ s = get_string_unquote(s);
+ if (s == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (s[0] == '%' && s[strlen(s)-1] == '%') {
+ s = get_string_token(ctx, s);
+ }
+
+ s = get_string_unquote(s);
+ if (s == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ *ret = s;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS find_manufacturer_name(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *section_name,
+ const char **manufacturer_name)
+{
+ NTSTATUS status;
+ size_t num_keys = 0;
+ const char **keys = NULL;
+ const char **values = NULL;
+ const char *s;
+ char *p;
+
+ status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (num_keys < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ s = talloc_strdup(mem_ctx, keys[0]);
+ if (s == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p = strchr(s, ':');
+ if (p == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *p = '\0';
+ p++;
+
+ s = get_string_unquote(p);
+ if (s == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ s = get_string_token(ctx, s);
+
+ s = get_string_unquote(s);
+ if (s == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (s != NULL) {
+ *manufacturer_name = talloc_strdup(mem_ctx, s);
+ if (*manufacturer_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ talloc_free(keys);
+ talloc_free(values);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS find_manufacturer_url(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *section_name,
+ const char *manufacturer_name,
+ const char **manufacturer_url)
+{
+ NTSTATUS status;
+ size_t num_keys = 0;
+ const char **keys = NULL;
+ const char **values = NULL;
+ const char *s;
+ char *p;
+
+ status = gp_inifile_enum_section(ctx, section_name, &num_keys, &keys, &values);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (num_keys < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ p = strchr(keys[0], ':');
+ if (p == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *p = '\0';
+ p++;
+
+ s = get_string_unquote(p);
+ if (s == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ s = get_string_token(ctx, s);
+
+ s = get_string_unquote(s);
+ if (s == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (strequal(s, manufacturer_name)) {
+ s = get_string_unquote(values[0]);
+ if (s == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ if (s != NULL) {
+ *manufacturer_url = talloc_strdup(mem_ctx, s);
+ if (*manufacturer_url == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ talloc_free(keys);
+ talloc_free(values);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS add_string_to_spoolss_array(TALLOC_CTX *mem_ctx,
+ const char *s,
+ struct spoolss_StringArray **r)
+{
+ size_t count = 2;
+ struct spoolss_StringArray *a = *r;
+ bool ok;
+ int i;
+
+ if (a == NULL) {
+ a = talloc_zero(mem_ctx, struct spoolss_StringArray);
+ if (a == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (a->string == NULL) {
+ a->string = talloc_zero_array(a, const char *, count);
+ if (a->string == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ for (i = 0; a->string[i] != NULL; i++) { ;; }
+ count = i;
+
+ ok = add_string_to_array(mem_ctx, s, &a->string, &count);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ a->string = talloc_realloc(mem_ctx, a->string, const char *, count + 1);
+ if (a->string == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ a->string[count] = NULL;
+
+ *r = a;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS add_dependent_driver_file(TALLOC_CTX *mem_ctx,
+ const char *file,
+ struct spoolss_StringArray **r)
+{
+ char *p;
+
+ if (file == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (file[0] == '@') {
+ file++;
+ }
+
+ p = strchr(file, ',');
+ if (p != NULL) {
+ *p = '\0';
+ }
+
+ return add_string_to_spoolss_array(mem_ctx, file, r);
+}
+
+/*
+ * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-manufacturer-section
+ *
+ * [Manufacturer]
+ * "Kyocera"=Kyocera,NTx86.5.1,NTx86.6.0,NTamd64.5.1,NTamd64.6.0
+ */
+
+static NTSTATUS enum_devices_in_toc(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ size_t *pnum_devices,
+ const char ***pdevices,
+ const char ***pdevice_values)
+{
+ NTSTATUS status;
+ size_t i, num_manufacturers = 0;
+ const char **manufacturers = NULL;
+ const char **values = NULL;
+ char *p;
+ bool ok;
+
+ status = gp_inifile_enum_section(ctx, "Manufacturer", &num_manufacturers, &manufacturers, &values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (i = 0; i < num_manufacturers; i++) {
+
+ const char *models_section_name;
+ const char *s;
+ char **decorations;
+ int j;
+
+ DEBUG(11,("processing manufacturer: %s\n", manufacturers[i]));
+
+ status = gp_inifile_getstring(ctx, manufacturers[i], &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ decorations = str_list_make_v3(mem_ctx, s, ",");
+ if (decorations == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ models_section_name = decorations[0];
+
+ for (j = 1; decorations[j] != NULL; j++) {
+
+ /*
+ * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-models-section
+ */
+
+ const char *decorated_models_section_name;
+ size_t d, num_devices = 0;
+ const char **devices = NULL;
+ const char **device_values = NULL;
+ size_t c = 0;
+
+ decorated_models_section_name = talloc_asprintf(mem_ctx, "%s.%s",
+ models_section_name,
+ decorations[j]);
+ if (decorated_models_section_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(11,("processing decorated models_section_name: %s\n",
+ decorated_models_section_name));
+
+ status = gp_inifile_enum_section(ctx, decorated_models_section_name,
+ &num_devices, &devices,
+ &device_values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ for (d = 0; d < num_devices; d++) {
+
+ DEBUG(11,("processing device: %s\n",
+ devices[d]));
+
+ s = talloc_strdup(mem_ctx, devices[d]);
+ if (s == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p = strchr(s, ':');
+ if (p == NULL) {
+ return NT_STATUS_DRIVER_INTERNAL_ERROR;
+ }
+
+ *p = '\0';
+ p++;
+
+ s = get_string_unquote(p);
+
+ ok = add_string_to_array(mem_ctx, s, pdevices, pnum_devices);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ok = add_string_to_array(mem_ctx, device_values[d], pdevice_values, &c);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS find_device_in_toc(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *device_description,
+ const char **value)
+{
+ NTSTATUS status;
+ size_t d, num_devices = 0;
+ const char **devices = NULL;
+ const char **device_values = NULL;
+
+ if (device_description == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = enum_devices_in_toc(ctx, mem_ctx,
+ &num_devices,
+ &devices,
+ &device_values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (d = 0; d < num_devices; d++) {
+
+ if (strequal(device_description, devices[d])) {
+
+ DEBUG(10,("found device_description: %s\n",
+ device_description));
+
+ *value = talloc_strdup(mem_ctx, device_values[d]);
+ if (*value == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ DEBUGADD(10,("and returned: %s\n", *value));
+
+ return NT_STATUS_OK;
+ }
+ }
+
+ return NT_STATUS_DRIVER_INTERNAL_ERROR;
+}
+
+/*
+ * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-copyfiles-directive
+ */
+
+static NTSTATUS process_driver_section_copyfiles(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *driver_section,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ size_t i, num_keys = 0;
+ char *p, *key;
+ const char **keys = NULL;
+ const char **values = NULL;
+ char *str;
+ const char *s;
+
+ key = talloc_asprintf(mem_ctx, "%s:%s", driver_section, "CopyFiles");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(10,("Checking for CopyFiles entry in %s\n", driver_section));
+
+ status = gp_inifile_getstring(ctx, key, &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(10,("these are the files to copy: %s\n", s));
+
+ while (next_token_talloc(mem_ctx, &s, &str, ",")) {
+
+ DEBUG(10,("trying section: %s\n", str));
+
+ if (str[0] == '@') {
+ DEBUG(10,("adding dependent driver file: %s\n", str));
+ status = add_dependent_driver_file(mem_ctx, str, &r->dependent_files);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ continue;
+ }
+
+ status = gp_inifile_enum_section(ctx, str, &num_keys, &keys, &values);
+ if (NT_STATUS_IS_OK(status)) {
+ for (i = 0; i < num_keys; i++) {
+ p = strchr(keys[i], ':');
+ if (p == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ *p = '\0';
+ p++;
+
+ DEBUG(10,("adding dependent driver file: %s\n", p));
+
+ status = add_dependent_driver_file(mem_ctx, p, &r->dependent_files);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ TALLOC_FREE(keys);
+ TALLOC_FREE(values);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+#define process_driver_section_val(_ctx, _mem_ctx, _section, _r, _key, _element) \
+do { \
+ NTSTATUS _status; \
+ const char *__key, *_s; \
+ __key = talloc_asprintf(_mem_ctx, "%s:%s", _section, _key); \
+ NT_STATUS_HAVE_NO_MEMORY(__key); \
+ _status = gp_inifile_getstring(_ctx, __key, &_s); \
+ if (NT_STATUS_IS_OK(_status)) { \
+ (_r)->_element = talloc_strdup(mem_ctx, _s); \
+ NT_STATUS_HAVE_NO_MEMORY((_r)->_element); \
+ } \
+} while(0);
+
+static NTSTATUS process_driver_section_colorprofiles(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *section,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ const char *key, *s;
+
+ key = talloc_asprintf(mem_ctx, "%s:%s", section, "ColorProfiles");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_getstring_ext(ctx, key, &s);
+ if (NT_STATUS_IS_OK(status)) {
+
+ status = add_string_to_spoolss_array(mem_ctx, s, &r->color_profiles);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS process_driver_section_printprocessor(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *section,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ char *key, *p;
+ const char *s;
+
+ key = talloc_asprintf(mem_ctx, "%s:%s", section, "PrintProcessor");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_getstring_ext(ctx, key, &s);
+ if (NT_STATUS_IS_OK(status)) {
+ s = get_string_unquote(s);
+
+ p = strchr(s, ',');
+ if (p == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ *p = '\0';
+ r->print_processor = talloc_strdup(mem_ctx, s);
+ if (r->print_processor == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS process_driver_section_data_section(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *section,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ char *key;
+ const char *s;
+
+ key = talloc_asprintf(mem_ctx, "%s:%s", section, "DataSection");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_getstring(ctx, key, &s);
+ if (NT_STATUS_IS_OK(status)) {
+ process_driver_section_val(ctx, mem_ctx, s, r,
+ "DriverFile", driver_path);
+ process_driver_section_val(ctx, mem_ctx, s, r,
+ "HelpFile", help_file);
+ process_driver_section_val(ctx, mem_ctx, s, r,
+ "DataFile", data_file);
+ process_driver_section_val(ctx, mem_ctx, s, r,
+ "ConfigFile", config_file);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS process_one_core_driver_section(struct gp_inifile_context *core_ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *driver_section,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ size_t i, num_keys = 0;
+ const char **keys = NULL;
+ const char **values = NULL;
+
+ DEBUG(10,("CoreDriverSection is: %s\n", driver_section));
+
+ status = gp_inifile_enum_section(core_ctx, driver_section, &num_keys, &keys, &values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (i = 0; i < num_keys; i++) {
+
+ status = process_driver_section_copyfiles(core_ctx, mem_ctx, driver_section, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
+ "DriverFile", driver_path);
+ process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
+ "HelpFile", help_file);
+ process_driver_section_val(core_ctx, mem_ctx, driver_section, r,
+ "ConfigFile", config_file);
+
+ status = process_driver_section_colorprofiles(core_ctx, mem_ctx, driver_section, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ talloc_free(keys);
+ talloc_free(values);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * CoreDriverSections="{D20EA372-DD35-4950-9ED8-A6335AFE79F0},UNIDRV_BIDI.OEM,UNIDRV_BIDI_DATA","{D20EA372-DD35-4950-9ED8-A6335AFE79F2},PCLXL.OEM","{D20EA372-DD35-4950-9ED8-A6335AFE79F3},sRGBPROFILE.OEM"
+ */
+static NTSTATUS process_core_driver_sections(struct gp_inifile_context *core_ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *value,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ char *p;
+ char **list;
+ int i;
+
+ list = str_list_make_v3(mem_ctx, value, ",");
+ if (list == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; list[i] != NULL; i++) {
+ char **array;
+ int a;
+
+ /* FIXME: do we have to validate the core driver guid ? */
+
+ p = strchr(list[i], ',');
+ if (p != NULL) {
+ *p = '\0';
+ p++;
+ }
+
+ DEBUG(10,("CoreDriverSections we have to process: %s\n", p));
+
+ array = str_list_make_v3(mem_ctx, p, ",");
+ if (array == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (a = 0; array[a] != NULL; a++) {
+
+ if (core_ctx == NULL) {
+ DEBUG(0,("Need to process CoreDriverSections but "
+ "have no Core Driver Context!\n"));
+ return NT_STATUS_DRIVER_INTERNAL_ERROR;
+ }
+
+ status = process_one_core_driver_section(core_ctx, mem_ctx, array[a], r);
+ if (!NT_STATUS_IS_OK(status)) {
+ continue;
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-ddinstall-section
+ */
+static NTSTATUS find_driver_files(struct gp_inifile_context *ctx,
+ struct gp_inifile_context *core_ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *driver_name,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ char *key;
+ const char *s;
+ const char *value;
+ char *install_section_name;
+ bool ok;
+ char *hw_id;
+
+ status = find_device_in_toc(ctx, mem_ctx, driver_name, &value);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ r->driver_name = talloc_strdup(mem_ctx, driver_name);
+ if (r->driver_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = next_token_talloc(mem_ctx, &value, &install_section_name, ",");
+ if (!ok) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(10,("driver_name: %s, value: %s, install_section_name: %s\n",
+ driver_name, value, install_section_name));
+
+ /* Hardware Id is optional */
+ ok = next_token_talloc(mem_ctx, &value, &hw_id, ",");
+ if (ok) {
+ r->hardware_id = hw_id;
+ }
+
+ status = process_driver_section_copyfiles(ctx, mem_ctx, install_section_name, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ process_driver_section_val(ctx, mem_ctx, install_section_name, r,
+ "DriverFile", driver_path);
+ process_driver_section_val(ctx, mem_ctx, install_section_name, r,
+ "HelpFile", help_file);
+ process_driver_section_val(ctx, mem_ctx, install_section_name, r,
+ "DataFile", data_file);
+ process_driver_section_val(ctx, mem_ctx, install_section_name, r,
+ "ConfigFile", config_file);
+
+ status = process_driver_section_printprocessor(ctx, mem_ctx, install_section_name, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = process_driver_section_data_section(ctx, mem_ctx, install_section_name, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ key = talloc_asprintf(mem_ctx, "%s:%s", install_section_name, "CoreDriverSections");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_getstring(ctx, key, &s);
+ if (NT_STATUS_IS_OK(status)) {
+
+ DEBUG(10,("found CoreDriverSections: %s\n", s));
+
+ status = process_core_driver_sections(core_ctx, mem_ctx, s, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct inf_context {
+ struct gp_inifile_context *ctx;
+ struct gp_inifile_context *core_ctx;
+};
+
+static NTSTATUS init_inf_context(TALLOC_CTX *mem_ctx,
+ const char *inf_filename,
+ const char *core_filename,
+ struct inf_context **_inf_ctx)
+{
+ NTSTATUS status;
+ struct gp_inifile_context *ctx;
+ struct gp_inifile_context *core_ctx = NULL;
+ struct inf_context *inf_ctx;
+
+ inf_ctx = talloc_zero(mem_ctx, struct inf_context);
+ if (inf_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_init_context_direct(mem_ctx,
+ inf_filename,
+ &ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("init_inf_context: failed to load %s\n", inf_filename));
+ return status;
+ }
+
+ if (ctx->generated_filename != NULL) {
+ unlink(ctx->generated_filename);
+ }
+
+ if (core_filename != NULL) {
+ status = gp_inifile_init_context_direct(mem_ctx,
+ core_filename,
+ &core_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("init_inf_context: failed to load %s\n", core_filename));
+ return status;
+ }
+
+ if (core_ctx->generated_filename != NULL) {
+ unlink(core_ctx->generated_filename);
+ }
+ }
+
+ inf_ctx->ctx = ctx;
+ inf_ctx->core_ctx = core_ctx;
+
+ *_inf_ctx = inf_ctx;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS process_driver_driverver(struct gp_inifile_context *ctx,
+ struct spoolss_AddDriverInfo8 *r)
+{
+ NTSTATUS status;
+ const char *s;
+ char *p;
+ bool ok;
+ const char *str;
+
+ status = gp_inifile_getstring(ctx, "Version:DriverVer", &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ str = talloc_strdup(ctx, s);
+ if (str == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p = strchr(str, ',');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+
+ ok = spoolss_timestr_to_NTTIME(str, &r->driver_date);
+ if (!ok) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ok = spoolss_driver_version_to_qword(p, &r->driver_version);
+ if (!ok) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Parse a SourceDisksNames section,
+ * https://msdn.microsoft.com/de-de/windows/hardware/drivers/install/inf-sourcedisksnames-section?f=255&MSPPError=-2147217396
+ */
+static NTSTATUS process_source_disk_name(struct gp_inifile_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *short_environment,
+ const char **source_disk_name)
+{
+ NTSTATUS status;
+ bool ok;
+ const char *key;
+ size_t i, num_keys = 0;
+ const char **keys = NULL;
+ const char **values = NULL;
+
+ key = talloc_asprintf(mem_ctx, "SourceDisksNames.%s", short_environment);
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (keys == NULL && values == NULL) {
+ key = "SourceDisksNames";
+
+ status = gp_inifile_enum_section(ctx, key, &num_keys, &keys, &values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ for (i = 0; i < num_keys; i++) {
+
+ /*
+ * 1 = %Disk1%,,,"Amd64"
+ * diskid = disk-description[,[tag-or-cab-file],[unused],[path],[flags][,tag-file]]
+ */
+ char *disk_description, *tag_or_cab_file, *unused, *path;
+
+ ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &disk_description, ",");
+ if (!ok) {
+ continue;
+ }
+
+ ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &tag_or_cab_file, ",");
+ if (!ok) {
+ continue;
+ }
+
+ ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &unused, ",");
+ if (!ok) {
+ continue;
+ }
+
+ ok = next_token_no_ltrim_talloc(mem_ctx, &values[i], &path, ",");
+ if (!ok) {
+ continue;
+ }
+
+ *source_disk_name = path;
+
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_NOT_FOUND;
+}
+
+static NTSTATUS setup_driver_by_name(TALLOC_CTX *mem_ctx,
+ struct inf_context *inf_ctx,
+ const char *filename,
+ const char *environment,
+ const char *driver_name,
+ struct spoolss_AddDriverInfo8 *r,
+ const char **source_disk_name)
+{
+ NTSTATUS status;
+ struct gp_inifile_context *ctx = inf_ctx->ctx;
+ struct gp_inifile_context *core_ctx = inf_ctx->core_ctx;
+ char *key;
+ bool ok;
+ const char *short_environment;
+ const char *s;
+
+ short_environment = spoolss_get_short_filesys_environment(environment);
+ if (short_environment == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = find_driver_files(ctx, core_ctx, mem_ctx, driver_name, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = process_source_disk_name(ctx, mem_ctx,
+ short_environment,
+ source_disk_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ r->inf_path = talloc_strdup(mem_ctx, filename);
+ if (r->inf_path == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->architecture = talloc_strdup(mem_ctx, environment);
+ if (r->architecture == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (r->print_processor == NULL) {
+ r->print_processor = talloc_strdup(mem_ctx, "winprint");
+ if (r->print_processor == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ status = gp_inifile_getstring_ext(ctx, "Version:Class", &s);
+ if (NT_STATUS_IS_OK(status)) {
+ if (strequal(s, "Printer")) {
+ r->printer_driver_attributes |= PRINTER_DRIVER_CLASS;
+ }
+ }
+
+ status = gp_inifile_getstring(ctx, "Version:Signature", &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!strequal(s, "\"$Windows NT$\"")) {
+ return NT_STATUS_INVALID_SIGNATURE;
+ }
+
+ r->version = SPOOLSS_DRIVER_VERSION_200X;
+ status = gp_inifile_getstring(ctx, "Version:ClassVer", &s);
+ if (NT_STATUS_IS_OK(status)) {
+ int cmp = strncasecmp_m(s, "4.0", 3);
+ if (cmp == 0) {
+ r->version = SPOOLSS_DRIVER_VERSION_2012;
+ }
+ if (strequal(s, "3.0")) {
+ r->version = SPOOLSS_DRIVER_VERSION_200X;
+ }
+ }
+
+ status = gp_inifile_getstring_ext(ctx, "Version:Provider", &s);
+ if (NT_STATUS_IS_OK(status)) {
+ if (s != NULL) {
+ r->provider = talloc_strdup(mem_ctx, s);
+ if (r->provider == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ }
+
+ status = process_driver_driverver(ctx, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
+
+ status = gp_inifile_getstring(ctx, "Version:DriverIsolation", &s);
+ if (NT_STATUS_IS_OK(status)) {
+ int cmp = strncasecmp_m(s, "2", 1);
+ if (cmp == 0) {
+ r->printer_driver_attributes |= PRINTER_DRIVER_SANDBOX_ENABLED;
+ }
+ cmp = strncasecmp_m(s, "0", 1);
+ if (cmp == 0) {
+ r->printer_driver_attributes &= ~PRINTER_DRIVER_SANDBOX_ENABLED;
+ }
+ }
+
+ status = find_manufacturer_name(ctx, mem_ctx, "Manufacturer", &r->manufacturer_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = find_manufacturer_url(ctx, mem_ctx, "OEM URLS", r->manufacturer_name, &r->manufacturer_url);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* not critical */
+ }
+
+ status = gp_inifile_getbool(ctx, "PrinterPackageInstallation:PackageAware", &ok);
+ if (NT_STATUS_IS_OK(status)) {
+ if (ok) {
+ r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
+ }
+ }
+
+ key = talloc_asprintf(mem_ctx, "%s.%s:%s",
+ "PrinterPackageInstallation", short_environment, "PackageAware");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_getbool(ctx, key, &ok);
+ if (NT_STATUS_IS_OK(status)) {
+ if (ok) {
+ r->printer_driver_attributes |= PRINTER_DRIVER_PACKAGE_AWARE;
+ }
+ }
+
+ key = talloc_asprintf(mem_ctx, "%s.%s:%s",
+ "PrinterPackageInstallation", short_environment, "CoreDriverDependencies");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_getstring(ctx, key, &s);
+ if (NT_STATUS_IS_OK(status)) {
+ char **list;
+ r->core_driver_dependencies = talloc_zero(mem_ctx, struct spoolss_StringArray);
+ if (r->core_driver_dependencies == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ list = str_list_make_v3(r->core_driver_dependencies, s, ",");
+ if (list == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ r->core_driver_dependencies->string = const_str_list(list);
+ }
+
+ key = talloc_asprintf(mem_ctx, "%s.%s:%s",
+ "PrinterPackageInstallation", short_environment, "InboxVersionRequired");
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = gp_inifile_getstring(ctx, key, &s);
+ if (NT_STATUS_IS_OK(status)) {
+ if (strequal(s, "UseDriverVer")) {
+ r->min_inbox_driver_ver_date = r->driver_date;
+ r->min_inbox_driver_ver_version = r->driver_version;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ parse a printer inf file
+****************************************************************/
+
+NTSTATUS driver_inf_parse(TALLOC_CTX *mem_ctx,
+ const char *core_driver_inf,
+ const char *filename,
+ const char *environment,
+ const char *driver_name,
+ struct spoolss_AddDriverInfo8 *r,
+ const char **source_disk_name)
+{
+ NTSTATUS status;
+ struct inf_context *inf_ctx;
+
+ if (!filename || !environment) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = init_inf_context(mem_ctx,
+ filename,
+ core_driver_inf,
+ &inf_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = setup_driver_by_name(mem_ctx, inf_ctx,
+ filename,
+ environment,
+ driver_name,
+ r,
+ source_disk_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS driver_inf_list(TALLOC_CTX *mem_ctx,
+ const char *core_driver_inf,
+ const char *filename,
+ const char *environment,
+ uint32_t *count,
+ struct spoolss_AddDriverInfo8 **_r)
+{
+ NTSTATUS status;
+ const char *short_environment;
+ size_t d, num_devices = 0;
+ const char **devices = NULL;
+ const char **device_values = NULL;
+ struct inf_context *inf_ctx;
+
+ if (!filename || !environment) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ short_environment = spoolss_get_short_filesys_environment(environment);
+ if (short_environment == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = init_inf_context(mem_ctx,
+ filename,
+ core_driver_inf,
+ &inf_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = enum_devices_in_toc(inf_ctx->ctx, mem_ctx,
+ &num_devices,
+ &devices,
+ &device_values);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (d = 0; d < num_devices; d++) {
+
+ struct spoolss_AddDriverInfo8 r;
+ const char *source_disk_name;
+
+ ZERO_STRUCT(r);
+
+ status = setup_driver_by_name(mem_ctx, inf_ctx, filename,
+ environment, devices[d], &r,
+ &source_disk_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ADD_TO_ARRAY(mem_ctx, struct spoolss_AddDriverInfo8, r, _r, count);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/lib/printer_driver/printer_driver.h b/lib/printer_driver/printer_driver.h
new file mode 100644
index 0000000..e7f7b21
--- /dev/null
+++ b/lib/printer_driver/printer_driver.h
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Guenther Deschner 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+struct spoolss_AddDriverInfo8;
+NTSTATUS driver_inf_parse(TALLOC_CTX *mem_ctx,
+ const char *core_driver_inf,
+ const char *filename,
+ const char *environment,
+ const char *driver_name,
+ struct spoolss_AddDriverInfo8 *r,
+ const char **source_disk_name);
+NTSTATUS driver_inf_list(TALLOC_CTX *mem_ctx,
+ const char *core_driver_inf,
+ const char *filename,
+ const char *environment,
+ uint32_t *count,
+ struct spoolss_AddDriverInfo8 **r);
diff --git a/lib/printer_driver/wscript_build b/lib/printer_driver/wscript_build
new file mode 100644
index 0000000..f9c7153
--- /dev/null
+++ b/lib/printer_driver/wscript_build
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('printer_driver',
+ source='printer_driver.c',
+ deps='gpo cli_spoolss',
+ private_library=True)
diff --git a/lib/pthreadpool/Makefile b/lib/pthreadpool/Makefile
new file mode 100644
index 0000000..48626bd
--- /dev/null
+++ b/lib/pthreadpool/Makefile
@@ -0,0 +1,9 @@
+all: tests
+
+CFLAGS=-O3 -g -Wall
+
+pthreadpool.o: pthreadpool.c pthreadpool.h
+ gcc -c -O3 -o pthreadpool.o pthreadpool.c -I../../..
+
+tests: tests.o pthreadpool.o
+ gcc -o tests tests.o pthreadpool.o -lpthread \ No newline at end of file
diff --git a/lib/pthreadpool/pthreadpool.c b/lib/pthreadpool/pthreadpool.c
new file mode 100644
index 0000000..cbabec9
--- /dev/null
+++ b/lib/pthreadpool/pthreadpool.c
@@ -0,0 +1,863 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * thread pool implementation
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/threads.h"
+#include "system/filesys.h"
+#include "pthreadpool.h"
+#include "lib/util/dlinklist.h"
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+
+struct pthreadpool_job {
+ int id;
+ void (*fn)(void *private_data);
+ void *private_data;
+};
+
+struct pthreadpool {
+ /*
+ * List pthreadpools for fork safety
+ */
+ struct pthreadpool *prev, *next;
+
+ /*
+ * Control access to this struct
+ */
+ pthread_mutex_t mutex;
+
+ /*
+ * Threads waiting for work do so here
+ */
+ pthread_cond_t condvar;
+
+ /*
+ * Array of jobs
+ */
+ size_t jobs_array_len;
+ struct pthreadpool_job *jobs;
+
+ size_t head;
+ size_t num_jobs;
+
+ /*
+ * Indicate job completion
+ */
+ int (*signal_fn)(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_fn_private_data,
+ void *private_data);
+ void *signal_fn_private_data;
+
+ /*
+ * indicator to worker threads to stop processing further jobs
+ * and exit.
+ */
+ bool stopped;
+
+ /*
+ * indicator to the last worker thread to free the pool
+ * resources.
+ */
+ bool destroyed;
+
+ /*
+ * maximum number of threads
+ * 0 means no real thread, only strict sync processing.
+ */
+ unsigned max_threads;
+
+ /*
+ * Number of threads
+ */
+ unsigned num_threads;
+
+ /*
+ * Number of idle threads
+ */
+ unsigned num_idle;
+
+ /*
+ * Condition variable indicating that helper threads should
+ * quickly go away making way for fork() without anybody
+ * waiting on pool->condvar.
+ */
+ pthread_cond_t *prefork_cond;
+
+ /*
+ * Waiting position for helper threads while fork is
+ * running. The forking thread will have locked it, and all
+ * idle helper threads will sit here until after the fork,
+ * where the forking thread will unlock it again.
+ */
+ pthread_mutex_t fork_mutex;
+};
+
+static pthread_mutex_t pthreadpools_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct pthreadpool *pthreadpools = NULL;
+static pthread_once_t pthreadpool_atfork_initialized = PTHREAD_ONCE_INIT;
+
+static void pthreadpool_prep_atfork(void);
+
+/*
+ * Initialize a thread pool
+ */
+
+int pthreadpool_init(unsigned max_threads, struct pthreadpool **presult,
+ int (*signal_fn)(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_fn_private_data,
+ void *private_data),
+ void *signal_fn_private_data)
+{
+ struct pthreadpool *pool;
+ int ret;
+
+ pool = (struct pthreadpool *)malloc(sizeof(struct pthreadpool));
+ if (pool == NULL) {
+ return ENOMEM;
+ }
+ pool->signal_fn = signal_fn;
+ pool->signal_fn_private_data = signal_fn_private_data;
+
+ pool->jobs_array_len = 4;
+ pool->jobs = calloc(
+ pool->jobs_array_len, sizeof(struct pthreadpool_job));
+
+ if (pool->jobs == NULL) {
+ free(pool);
+ return ENOMEM;
+ }
+
+ pool->head = pool->num_jobs = 0;
+
+ ret = pthread_mutex_init(&pool->mutex, NULL);
+ if (ret != 0) {
+ free(pool->jobs);
+ free(pool);
+ return ret;
+ }
+
+ ret = pthread_cond_init(&pool->condvar, NULL);
+ if (ret != 0) {
+ pthread_mutex_destroy(&pool->mutex);
+ free(pool->jobs);
+ free(pool);
+ return ret;
+ }
+
+ ret = pthread_mutex_init(&pool->fork_mutex, NULL);
+ if (ret != 0) {
+ pthread_cond_destroy(&pool->condvar);
+ pthread_mutex_destroy(&pool->mutex);
+ free(pool->jobs);
+ free(pool);
+ return ret;
+ }
+
+ pool->stopped = false;
+ pool->destroyed = false;
+ pool->num_threads = 0;
+ pool->max_threads = max_threads;
+ pool->num_idle = 0;
+ pool->prefork_cond = NULL;
+
+ ret = pthread_mutex_lock(&pthreadpools_mutex);
+ if (ret != 0) {
+ pthread_mutex_destroy(&pool->fork_mutex);
+ pthread_cond_destroy(&pool->condvar);
+ pthread_mutex_destroy(&pool->mutex);
+ free(pool->jobs);
+ free(pool);
+ return ret;
+ }
+ DLIST_ADD(pthreadpools, pool);
+
+ ret = pthread_mutex_unlock(&pthreadpools_mutex);
+ assert(ret == 0);
+
+ pthread_once(&pthreadpool_atfork_initialized, pthreadpool_prep_atfork);
+
+ *presult = pool;
+
+ return 0;
+}
+
+size_t pthreadpool_max_threads(struct pthreadpool *pool)
+{
+ if (pool->stopped) {
+ return 0;
+ }
+
+ return pool->max_threads;
+}
+
+size_t pthreadpool_queued_jobs(struct pthreadpool *pool)
+{
+ int res;
+ int unlock_res;
+ size_t ret;
+
+ if (pool->stopped) {
+ return 0;
+ }
+
+ res = pthread_mutex_lock(&pool->mutex);
+ if (res != 0) {
+ return res;
+ }
+
+ if (pool->stopped) {
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return 0;
+ }
+
+ ret = pool->num_jobs;
+
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return ret;
+}
+
+static void pthreadpool_prepare_pool(struct pthreadpool *pool)
+{
+ int ret;
+
+ ret = pthread_mutex_lock(&pool->fork_mutex);
+ assert(ret == 0);
+
+ ret = pthread_mutex_lock(&pool->mutex);
+ assert(ret == 0);
+
+ while (pool->num_idle != 0) {
+ unsigned num_idle = pool->num_idle;
+ pthread_cond_t prefork_cond;
+
+ ret = pthread_cond_init(&prefork_cond, NULL);
+ assert(ret == 0);
+
+ /*
+ * Push all idle threads off pool->condvar. In the
+ * child we can destroy the pool, which would result
+ * in undefined behaviour in the
+ * pthread_cond_destroy(pool->condvar). glibc just
+ * blocks here.
+ */
+ pool->prefork_cond = &prefork_cond;
+
+ ret = pthread_cond_signal(&pool->condvar);
+ assert(ret == 0);
+
+ while (pool->num_idle == num_idle) {
+ ret = pthread_cond_wait(&prefork_cond, &pool->mutex);
+ assert(ret == 0);
+ }
+
+ pool->prefork_cond = NULL;
+
+ ret = pthread_cond_destroy(&prefork_cond);
+ assert(ret == 0);
+ }
+
+ /*
+ * Probably it's well-defined somewhere: What happens to
+ * condvars after a fork? The rationale of pthread_atfork only
+ * writes about mutexes. So better be safe than sorry and
+ * destroy/reinit pool->condvar across a fork.
+ */
+
+ ret = pthread_cond_destroy(&pool->condvar);
+ assert(ret == 0);
+}
+
+static void pthreadpool_prepare(void)
+{
+ int ret;
+ struct pthreadpool *pool;
+
+ ret = pthread_mutex_lock(&pthreadpools_mutex);
+ assert(ret == 0);
+
+ pool = pthreadpools;
+
+ while (pool != NULL) {
+ pthreadpool_prepare_pool(pool);
+ pool = pool->next;
+ }
+}
+
+static void pthreadpool_parent(void)
+{
+ int ret;
+ struct pthreadpool *pool;
+
+ for (pool = DLIST_TAIL(pthreadpools);
+ pool != NULL;
+ pool = DLIST_PREV(pool)) {
+ ret = pthread_cond_init(&pool->condvar, NULL);
+ assert(ret == 0);
+ ret = pthread_mutex_unlock(&pool->mutex);
+ assert(ret == 0);
+ ret = pthread_mutex_unlock(&pool->fork_mutex);
+ assert(ret == 0);
+ }
+
+ ret = pthread_mutex_unlock(&pthreadpools_mutex);
+ assert(ret == 0);
+}
+
+static void pthreadpool_child(void)
+{
+ int ret;
+ struct pthreadpool *pool;
+
+ for (pool = DLIST_TAIL(pthreadpools);
+ pool != NULL;
+ pool = DLIST_PREV(pool)) {
+
+ pool->num_threads = 0;
+ pool->num_idle = 0;
+ pool->head = 0;
+ pool->num_jobs = 0;
+ pool->stopped = true;
+
+ ret = pthread_cond_init(&pool->condvar, NULL);
+ assert(ret == 0);
+
+ ret = pthread_mutex_unlock(&pool->mutex);
+ assert(ret == 0);
+
+ ret = pthread_mutex_unlock(&pool->fork_mutex);
+ assert(ret == 0);
+ }
+
+ ret = pthread_mutex_unlock(&pthreadpools_mutex);
+ assert(ret == 0);
+}
+
+static void pthreadpool_prep_atfork(void)
+{
+ pthread_atfork(pthreadpool_prepare, pthreadpool_parent,
+ pthreadpool_child);
+}
+
+static int pthreadpool_free(struct pthreadpool *pool)
+{
+ int ret, ret1, ret2;
+
+ ret = pthread_mutex_lock(&pthreadpools_mutex);
+ if (ret != 0) {
+ return ret;
+ }
+ DLIST_REMOVE(pthreadpools, pool);
+ ret = pthread_mutex_unlock(&pthreadpools_mutex);
+ assert(ret == 0);
+
+ ret = pthread_mutex_lock(&pool->mutex);
+ assert(ret == 0);
+ ret = pthread_mutex_unlock(&pool->mutex);
+ assert(ret == 0);
+
+ ret = pthread_mutex_destroy(&pool->mutex);
+ ret1 = pthread_cond_destroy(&pool->condvar);
+ ret2 = pthread_mutex_destroy(&pool->fork_mutex);
+
+ if (ret != 0) {
+ return ret;
+ }
+ if (ret1 != 0) {
+ return ret1;
+ }
+ if (ret2 != 0) {
+ return ret2;
+ }
+
+ free(pool->jobs);
+ free(pool);
+
+ return 0;
+}
+
+/*
+ * Stop a thread pool. Wake up all idle threads for exit.
+ */
+
+static int pthreadpool_stop_locked(struct pthreadpool *pool)
+{
+ int ret;
+
+ pool->stopped = true;
+
+ if (pool->num_threads == 0) {
+ return 0;
+ }
+
+ /*
+ * We have active threads, tell them to finish.
+ */
+
+ ret = pthread_cond_broadcast(&pool->condvar);
+
+ return ret;
+}
+
+/*
+ * Stop a thread pool. Wake up all idle threads for exit.
+ */
+
+int pthreadpool_stop(struct pthreadpool *pool)
+{
+ int ret, ret1;
+
+ ret = pthread_mutex_lock(&pool->mutex);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (!pool->stopped) {
+ ret = pthreadpool_stop_locked(pool);
+ }
+
+ ret1 = pthread_mutex_unlock(&pool->mutex);
+ assert(ret1 == 0);
+
+ return ret;
+}
+
+/*
+ * Destroy a thread pool. Wake up all idle threads for exit. The last
+ * one will free the pool.
+ */
+
+int pthreadpool_destroy(struct pthreadpool *pool)
+{
+ int ret, ret1;
+ bool free_it;
+
+ assert(!pool->destroyed);
+
+ ret = pthread_mutex_lock(&pool->mutex);
+ if (ret != 0) {
+ return ret;
+ }
+
+ pool->destroyed = true;
+
+ if (!pool->stopped) {
+ ret = pthreadpool_stop_locked(pool);
+ }
+
+ free_it = (pool->num_threads == 0);
+
+ ret1 = pthread_mutex_unlock(&pool->mutex);
+ assert(ret1 == 0);
+
+ if (free_it) {
+ pthreadpool_free(pool);
+ }
+
+ return ret;
+}
+/*
+ * Prepare for pthread_exit(), pool->mutex must be locked and will be
+ * unlocked here. This is a bit of a layering violation, but here we
+ * also take care of removing the pool if we're the last thread.
+ */
+static void pthreadpool_server_exit(struct pthreadpool *pool)
+{
+ int ret;
+ bool free_it;
+
+ pool->num_threads -= 1;
+
+ free_it = (pool->destroyed && (pool->num_threads == 0));
+
+ ret = pthread_mutex_unlock(&pool->mutex);
+ assert(ret == 0);
+
+ if (free_it) {
+ pthreadpool_free(pool);
+ }
+}
+
+static bool pthreadpool_get_job(struct pthreadpool *p,
+ struct pthreadpool_job *job)
+{
+ if (p->stopped) {
+ return false;
+ }
+
+ if (p->num_jobs == 0) {
+ return false;
+ }
+ *job = p->jobs[p->head];
+ p->head = (p->head+1) % p->jobs_array_len;
+ p->num_jobs -= 1;
+ return true;
+}
+
+static bool pthreadpool_put_job(struct pthreadpool *p,
+ int id,
+ void (*fn)(void *private_data),
+ void *private_data)
+{
+ struct pthreadpool_job *job;
+
+ if (p->num_jobs == p->jobs_array_len) {
+ struct pthreadpool_job *tmp;
+ size_t new_len = p->jobs_array_len * 2;
+
+ tmp = realloc(
+ p->jobs, sizeof(struct pthreadpool_job) * new_len);
+ if (tmp == NULL) {
+ return false;
+ }
+ p->jobs = tmp;
+
+ /*
+ * We just doubled the jobs array. The array implements a FIFO
+ * queue with a modulo-based wraparound, so we have to memcpy
+ * the jobs that are logically at the queue end but physically
+ * before the queue head into the reallocated area. The new
+ * space starts at the current jobs_array_len, and we have to
+ * copy everything before the current head job into the new
+ * area.
+ */
+ memcpy(&p->jobs[p->jobs_array_len], p->jobs,
+ sizeof(struct pthreadpool_job) * p->head);
+
+ p->jobs_array_len = new_len;
+ }
+
+ job = &p->jobs[(p->head + p->num_jobs) % p->jobs_array_len];
+ job->id = id;
+ job->fn = fn;
+ job->private_data = private_data;
+
+ p->num_jobs += 1;
+
+ return true;
+}
+
+static void pthreadpool_undo_put_job(struct pthreadpool *p)
+{
+ p->num_jobs -= 1;
+}
+
+static void *pthreadpool_server(void *arg)
+{
+ struct pthreadpool *pool = (struct pthreadpool *)arg;
+ int res;
+
+ res = pthread_mutex_lock(&pool->mutex);
+ if (res != 0) {
+ return NULL;
+ }
+
+ while (1) {
+ struct timespec ts;
+ struct pthreadpool_job job;
+
+ /*
+ * idle-wait at most 1 second. If nothing happens in that
+ * time, exit this thread.
+ */
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 1;
+
+ while ((pool->num_jobs == 0) && !pool->stopped) {
+
+ pool->num_idle += 1;
+ res = pthread_cond_timedwait(
+ &pool->condvar, &pool->mutex, &ts);
+ pool->num_idle -= 1;
+
+ if (pool->prefork_cond != NULL) {
+ /*
+ * Me must allow fork() to continue
+ * without anybody waiting on
+ * &pool->condvar. Tell
+ * pthreadpool_prepare_pool that we
+ * got that message.
+ */
+
+ res = pthread_cond_signal(pool->prefork_cond);
+ assert(res == 0);
+
+ res = pthread_mutex_unlock(&pool->mutex);
+ assert(res == 0);
+
+ /*
+ * pthreadpool_prepare_pool has
+ * already locked this mutex across
+ * the fork. This makes us wait
+ * without sitting in a condvar.
+ */
+ res = pthread_mutex_lock(&pool->fork_mutex);
+ assert(res == 0);
+ res = pthread_mutex_unlock(&pool->fork_mutex);
+ assert(res == 0);
+
+ res = pthread_mutex_lock(&pool->mutex);
+ assert(res == 0);
+ }
+
+ if (res == ETIMEDOUT) {
+
+ if (pool->num_jobs == 0) {
+ /*
+ * we timed out and still no work for
+ * us. Exit.
+ */
+ pthreadpool_server_exit(pool);
+ return NULL;
+ }
+
+ break;
+ }
+ assert(res == 0);
+ }
+
+ if (pthreadpool_get_job(pool, &job)) {
+ int ret;
+
+ /*
+ * Do the work with the mutex unlocked
+ */
+
+ res = pthread_mutex_unlock(&pool->mutex);
+ assert(res == 0);
+
+ job.fn(job.private_data);
+
+ ret = pool->signal_fn(job.id,
+ job.fn, job.private_data,
+ pool->signal_fn_private_data);
+
+ res = pthread_mutex_lock(&pool->mutex);
+ assert(res == 0);
+
+ if (ret != 0) {
+ pthreadpool_server_exit(pool);
+ return NULL;
+ }
+ }
+
+ if (pool->stopped) {
+ /*
+ * we're asked to stop processing jobs, so exit
+ */
+ pthreadpool_server_exit(pool);
+ return NULL;
+ }
+ }
+}
+
+static int pthreadpool_create_thread(struct pthreadpool *pool)
+{
+ pthread_attr_t thread_attr;
+ pthread_t thread_id;
+ int res;
+ sigset_t mask, omask;
+
+ /*
+ * Create a new worker thread. It should not receive any signals.
+ */
+
+ sigfillset(&mask);
+
+ res = pthread_attr_init(&thread_attr);
+ if (res != 0) {
+ return res;
+ }
+
+ res = pthread_attr_setdetachstate(
+ &thread_attr, PTHREAD_CREATE_DETACHED);
+ if (res != 0) {
+ pthread_attr_destroy(&thread_attr);
+ return res;
+ }
+
+ res = pthread_sigmask(SIG_BLOCK, &mask, &omask);
+ if (res != 0) {
+ pthread_attr_destroy(&thread_attr);
+ return res;
+ }
+
+ res = pthread_create(&thread_id, &thread_attr, pthreadpool_server,
+ (void *)pool);
+
+ assert(pthread_sigmask(SIG_SETMASK, &omask, NULL) == 0);
+
+ pthread_attr_destroy(&thread_attr);
+
+ if (res == 0) {
+ pool->num_threads += 1;
+ }
+
+ return res;
+}
+
+int pthreadpool_add_job(struct pthreadpool *pool, int job_id,
+ void (*fn)(void *private_data), void *private_data)
+{
+ int res;
+ int unlock_res;
+
+ assert(!pool->destroyed);
+
+ res = pthread_mutex_lock(&pool->mutex);
+ if (res != 0) {
+ return res;
+ }
+
+ if (pool->stopped) {
+ /*
+ * Protect against the pool being shut down while
+ * trying to add a job
+ */
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return EINVAL;
+ }
+
+ if (pool->max_threads == 0) {
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+
+ /*
+ * If no thread are allowed we do strict sync processing.
+ */
+ fn(private_data);
+ res = pool->signal_fn(job_id, fn, private_data,
+ pool->signal_fn_private_data);
+ return res;
+ }
+
+ /*
+ * Add job to the end of the queue
+ */
+ if (!pthreadpool_put_job(pool, job_id, fn, private_data)) {
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return ENOMEM;
+ }
+
+ if (pool->num_idle > 0) {
+ /*
+ * We have idle threads, wake one.
+ */
+ res = pthread_cond_signal(&pool->condvar);
+ if (res != 0) {
+ pthreadpool_undo_put_job(pool);
+ }
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return res;
+ }
+
+ if (pool->num_threads >= pool->max_threads) {
+ /*
+ * No more new threads, we just queue the request
+ */
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return 0;
+ }
+
+ res = pthreadpool_create_thread(pool);
+ if (res == 0) {
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return 0;
+ }
+
+ if (pool->num_threads != 0) {
+ /*
+ * At least one thread is still available, let
+ * that one run the queued job.
+ */
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+ return 0;
+ }
+
+ pthreadpool_undo_put_job(pool);
+
+ unlock_res = pthread_mutex_unlock(&pool->mutex);
+ assert(unlock_res == 0);
+
+ return res;
+}
+
+size_t pthreadpool_cancel_job(struct pthreadpool *pool, int job_id,
+ void (*fn)(void *private_data), void *private_data)
+{
+ int res;
+ size_t i, j;
+ size_t num = 0;
+
+ assert(!pool->destroyed);
+
+ res = pthread_mutex_lock(&pool->mutex);
+ if (res != 0) {
+ return res;
+ }
+
+ for (i = 0, j = 0; i < pool->num_jobs; i++) {
+ size_t idx = (pool->head + i) % pool->jobs_array_len;
+ size_t new_idx = (pool->head + j) % pool->jobs_array_len;
+ struct pthreadpool_job *job = &pool->jobs[idx];
+
+ if ((job->private_data == private_data) &&
+ (job->id == job_id) &&
+ (job->fn == fn))
+ {
+ /*
+ * Just skip the entry.
+ */
+ num++;
+ continue;
+ }
+
+ /*
+ * If we already removed one or more jobs (so j will be smaller
+ * then i), we need to fill possible gaps in the logical list.
+ */
+ if (j < i) {
+ pool->jobs[new_idx] = *job;
+ }
+ j++;
+ }
+
+ pool->num_jobs -= num;
+
+ res = pthread_mutex_unlock(&pool->mutex);
+ assert(res == 0);
+
+ return num;
+}
diff --git a/lib/pthreadpool/pthreadpool.h b/lib/pthreadpool/pthreadpool.h
new file mode 100644
index 0000000..b473358
--- /dev/null
+++ b/lib/pthreadpool/pthreadpool.h
@@ -0,0 +1,158 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * threadpool implementation based on pthreads
+ * Copyright (C) Volker Lendecke 2009,2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PTHREADPOOL_H__
+#define __PTHREADPOOL_H__
+
+struct pthreadpool;
+
+/**
+ * @defgroup pthreadpool The pthreadpool API
+ *
+ * This API provides a way to run threadsafe functions in a helper
+ * thread. It is initially intended to run getaddrinfo asynchronously.
+ */
+
+
+/**
+ * @brief Create a pthreadpool
+ *
+ * A struct pthreadpool is the basis for for running threads in the
+ * background.
+ *
+ * @param[in] max_threads Maximum parallelism in this pool
+ * @param[out] presult Pointer to the threadpool returned
+ * @return success: 0, failure: errno
+ *
+ * max_threads=0 means unlimited parallelism. The caller has to take
+ * care to not overload the system.
+ */
+int pthreadpool_init(unsigned max_threads, struct pthreadpool **presult,
+ int (*signal_fn)(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_fn_private_data,
+ void *private_data),
+ void *signal_fn_private_data);
+
+/**
+ * @brief Get the max threads value of pthreadpool
+ *
+ * @note This can be 0 for strict sync processing.
+ *
+ * @param[in] pool The pool
+ * @return number of possible threads
+ */
+size_t pthreadpool_max_threads(struct pthreadpool *pool);
+
+/**
+ * @brief The number of queued jobs of pthreadpool
+ *
+ * This is the number of jobs added by pthreadpool_add_job(),
+ * which are not yet processed by a thread.
+ *
+ * @param[in] pool The pool
+ * @return The number of jobs
+ */
+size_t pthreadpool_queued_jobs(struct pthreadpool *pool);
+
+/**
+ * @brief Stop a pthreadpool
+ *
+ * Stop a pthreadpool. If jobs are submitted, but not yet active in
+ * a thread, they won't get executed. If a job has already been
+ * submitted to a thread, the job function will continue running, and
+ * the signal function might still be called.
+ *
+ * This allows a multi step shutdown using pthreadpool_stop(),
+ * pthreadpool_cancel_job() and pthreadpool_destroy().
+ *
+ * @param[in] pool The pool to stop
+ * @return success: 0, failure: errno
+ *
+ * @see pthreadpool_cancel_job()
+ * @see pthreadpool_destroy()
+ */
+int pthreadpool_stop(struct pthreadpool *pool);
+
+/**
+ * @brief Destroy a pthreadpool
+ *
+ * This basically implies pthreadpool_stop() if the pool
+ * isn't already stopped.
+ *
+ * Destroy a pthreadpool. If jobs are submitted, but not yet active in
+ * a thread, they won't get executed. If a job has already been
+ * submitted to a thread, the job function will continue running, and
+ * the signal function might still be called. The caller of
+ * pthreadpool_init must make sure the required resources are still
+ * around when the pool is destroyed with pending jobs. The last
+ * thread to exit will finally free() the pool memory.
+ *
+ * @param[in] pool The pool to destroy
+ * @return success: 0, failure: errno
+ *
+ * @see pthreadpool_stop()
+ */
+int pthreadpool_destroy(struct pthreadpool *pool);
+
+/**
+ * @brief Add a job to a pthreadpool
+ *
+ * This adds a job to a pthreadpool. The job can be identified by
+ * job_id. This integer will be passed to signal_fn() when the
+ * job is completed.
+ *
+ * @param[in] pool The pool to run the job on
+ * @param[in] job_id A custom identifier
+ * @param[in] fn The function to run asynchronously
+ * @param[in] private_data Pointer passed to fn
+ * @return success: 0, failure: errno
+ */
+int pthreadpool_add_job(struct pthreadpool *pool, int job_id,
+ void (*fn)(void *private_data), void *private_data);
+
+/**
+ * @brief Try to cancel a job in a pthreadpool
+ *
+ * This tries to cancel a job in a pthreadpool. The same
+ * arguments, which were given to pthreadpool_add_job()
+ * needs to be passed.
+ *
+ * The combination of id, fn, private_data might not be unique.
+ * So the function tries to cancel as much matching jobs as possible.
+ * Note once a job is scheduled in a thread it's to late to
+ * cancel it.
+ *
+ * Canceled jobs that weren't started yet won't be reported via a
+ * pool's signal_fn.
+ *
+ * @param[in] pool The pool to run the job on
+ * @param[in] job_id A custom identifier
+ * @param[in] fn The function to run asynchronously
+ * @param[in] private_data Pointer passed to fn
+ * @return The number of canceled jobs
+ *
+ * @see pthreadpool_add_job()
+ * @see pthreadpool_stop()
+ * @see pthreadpool_destroy()
+ */
+size_t pthreadpool_cancel_job(struct pthreadpool *pool, int job_id,
+ void (*fn)(void *private_data), void *private_data);
+
+#endif
diff --git a/lib/pthreadpool/pthreadpool_pipe.c b/lib/pthreadpool/pthreadpool_pipe.c
new file mode 100644
index 0000000..d6d519a
--- /dev/null
+++ b/lib/pthreadpool/pthreadpool_pipe.c
@@ -0,0 +1,202 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * threadpool implementation based on pthreads
+ * Copyright (C) Volker Lendecke 2009,2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "pthreadpool_pipe.h"
+#include "pthreadpool.h"
+
+struct pthreadpool_pipe {
+ struct pthreadpool *pool;
+ int num_jobs;
+ pid_t pid;
+ int pipe_fds[2];
+};
+
+static int pthreadpool_pipe_signal(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_private_data,
+ void *private_data);
+
+int pthreadpool_pipe_init(unsigned max_threads,
+ struct pthreadpool_pipe **presult)
+{
+ struct pthreadpool_pipe *pool;
+ int ret;
+
+ pool = calloc(1, sizeof(struct pthreadpool_pipe));
+ if (pool == NULL) {
+ return ENOMEM;
+ }
+ pool->pid = getpid();
+
+ ret = pipe(pool->pipe_fds);
+ if (ret == -1) {
+ int err = errno;
+ free(pool);
+ return err;
+ }
+
+ ret = pthreadpool_init(max_threads, &pool->pool,
+ pthreadpool_pipe_signal, pool);
+ if (ret != 0) {
+ close(pool->pipe_fds[0]);
+ close(pool->pipe_fds[1]);
+ free(pool);
+ return ret;
+ }
+
+ *presult = pool;
+ return 0;
+}
+
+static int pthreadpool_pipe_signal(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_private_data,
+ void *private_data)
+{
+ struct pthreadpool_pipe *pool = private_data;
+ ssize_t written;
+
+ do {
+ written = write(pool->pipe_fds[1], &jobid, sizeof(jobid));
+ } while ((written == -1) && (errno == EINTR));
+
+ if (written != sizeof(jobid)) {
+ return errno;
+ }
+
+ return 0;
+}
+
+int pthreadpool_pipe_destroy(struct pthreadpool_pipe *pool)
+{
+ int ret;
+
+ if (pool->num_jobs != 0) {
+ return EBUSY;
+ }
+
+ ret = pthreadpool_destroy(pool->pool);
+ if (ret != 0) {
+ return ret;
+ }
+
+ close(pool->pipe_fds[0]);
+ pool->pipe_fds[0] = -1;
+
+ close(pool->pipe_fds[1]);
+ pool->pipe_fds[1] = -1;
+
+ free(pool);
+ return 0;
+}
+
+static int pthreadpool_pipe_reinit(struct pthreadpool_pipe *pool)
+{
+ pid_t pid = getpid();
+ int signal_fd;
+ int ret;
+
+ if (pid == pool->pid) {
+ return 0;
+ }
+
+ signal_fd = pool->pipe_fds[0];
+
+ close(pool->pipe_fds[0]);
+ pool->pipe_fds[0] = -1;
+
+ close(pool->pipe_fds[1]);
+ pool->pipe_fds[1] = -1;
+
+ ret = pipe(pool->pipe_fds);
+ if (ret != 0) {
+ return errno;
+ }
+
+ ret = dup2(pool->pipe_fds[0], signal_fd);
+ if (ret != 0) {
+ return errno;
+ }
+
+ pool->pipe_fds[0] = signal_fd;
+ pool->num_jobs = 0;
+
+ return 0;
+}
+
+int pthreadpool_pipe_add_job(struct pthreadpool_pipe *pool, int job_id,
+ void (*fn)(void *private_data),
+ void *private_data)
+{
+ int ret;
+
+ ret = pthreadpool_pipe_reinit(pool);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = pthreadpool_add_job(pool->pool, job_id, fn, private_data);
+ if (ret != 0) {
+ return ret;
+ }
+
+ pool->num_jobs += 1;
+
+ return 0;
+}
+
+int pthreadpool_pipe_signal_fd(struct pthreadpool_pipe *pool)
+{
+ return pool->pipe_fds[0];
+}
+
+int pthreadpool_pipe_finished_jobs(struct pthreadpool_pipe *pool, int *jobids,
+ unsigned num_jobids)
+{
+ ssize_t to_read, nread, num_jobs;
+ pid_t pid = getpid();
+
+ if (pool->pid != pid) {
+ return EINVAL;
+ }
+
+ to_read = sizeof(int) * num_jobids;
+
+ do {
+ nread = read(pool->pipe_fds[0], jobids, to_read);
+ } while ((nread == -1) && (errno == EINTR));
+
+ if (nread == -1) {
+ return -errno;
+ }
+ if ((nread % sizeof(int)) != 0) {
+ return -EINVAL;
+ }
+
+ num_jobs = nread / sizeof(int);
+
+ if (num_jobs > pool->num_jobs) {
+ return -EINVAL;
+ }
+ pool->num_jobs -= num_jobs;
+
+ return num_jobs;
+}
diff --git a/lib/pthreadpool/pthreadpool_pipe.h b/lib/pthreadpool/pthreadpool_pipe.h
new file mode 100644
index 0000000..77516f7
--- /dev/null
+++ b/lib/pthreadpool/pthreadpool_pipe.h
@@ -0,0 +1,39 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * threadpool implementation based on pthreads
+ * Copyright (C) Volker Lendecke 2009,2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PTHREADPOOL_PIPE_H__
+#define __PTHREADPOOL_PIPE_H__
+
+struct pthreadpool_pipe;
+
+int pthreadpool_pipe_init(unsigned max_threads,
+ struct pthreadpool_pipe **presult);
+
+int pthreadpool_pipe_destroy(struct pthreadpool_pipe *pool);
+
+int pthreadpool_pipe_add_job(struct pthreadpool_pipe *pool, int job_id,
+ void (*fn)(void *private_data),
+ void *private_data);
+
+int pthreadpool_pipe_signal_fd(struct pthreadpool_pipe *pool);
+
+int pthreadpool_pipe_finished_jobs(struct pthreadpool_pipe *pool, int *jobids,
+ unsigned num_jobids);
+
+#endif
diff --git a/lib/pthreadpool/pthreadpool_sync.c b/lib/pthreadpool/pthreadpool_sync.c
new file mode 100644
index 0000000..48e6a0d
--- /dev/null
+++ b/lib/pthreadpool/pthreadpool_sync.c
@@ -0,0 +1,97 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * sync dummy implementation of the pthreadpool API
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "replace.h"
+#include "pthreadpool.h"
+
+struct pthreadpool {
+ bool stopped;
+
+ /*
+ * Indicate job completion
+ */
+ int (*signal_fn)(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_fn_private_data,
+ void *private_data);
+ void *signal_fn_private_data;
+};
+
+int pthreadpool_init(unsigned max_threads, struct pthreadpool **presult,
+ int (*signal_fn)(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_fn_private_data,
+ void *private_data),
+ void *signal_fn_private_data)
+{
+ struct pthreadpool *pool;
+
+ pool = (struct pthreadpool *)calloc(1, sizeof(struct pthreadpool));
+ if (pool == NULL) {
+ return ENOMEM;
+ }
+ pool->stopped = false;
+ pool->signal_fn = signal_fn;
+ pool->signal_fn_private_data = signal_fn_private_data;
+
+ *presult = pool;
+ return 0;
+}
+
+size_t pthreadpool_max_threads(struct pthreadpool *pool)
+{
+ return 0;
+}
+
+size_t pthreadpool_queued_jobs(struct pthreadpool *pool)
+{
+ return 0;
+}
+
+int pthreadpool_add_job(struct pthreadpool *pool, int job_id,
+ void (*fn)(void *private_data), void *private_data)
+{
+ if (pool->stopped) {
+ return EINVAL;
+ }
+
+ fn(private_data);
+
+ return pool->signal_fn(job_id, fn, private_data,
+ pool->signal_fn_private_data);
+}
+
+size_t pthreadpool_cancel_job(struct pthreadpool *pool, int job_id,
+ void (*fn)(void *private_data), void *private_data)
+{
+ return 0;
+}
+
+int pthreadpool_stop(struct pthreadpool *pool)
+{
+ pool->stopped = true;
+ return 0;
+}
+
+int pthreadpool_destroy(struct pthreadpool *pool)
+{
+ free(pool);
+ return 0;
+}
diff --git a/lib/pthreadpool/pthreadpool_tevent.c b/lib/pthreadpool/pthreadpool_tevent.c
new file mode 100644
index 0000000..a66f444
--- /dev/null
+++ b/lib/pthreadpool/pthreadpool_tevent.c
@@ -0,0 +1,428 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * threadpool implementation based on pthreads
+ * Copyright (C) Volker Lendecke 2009,2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "pthreadpool_tevent.h"
+#include "pthreadpool.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/dlinklist.h"
+
+struct pthreadpool_tevent_job_state;
+
+/*
+ * We need one pthreadpool_tevent_glue object per unique combination of tevent
+ * contexts and pthreadpool_tevent objects. Maintain a list of used tevent
+ * contexts in a pthreadpool_tevent.
+ */
+struct pthreadpool_tevent_glue {
+ struct pthreadpool_tevent_glue *prev, *next;
+ struct pthreadpool_tevent *pool; /* back-pointer to owning object. */
+ /* Tuple we are keeping track of in this list. */
+ struct tevent_context *ev;
+ struct tevent_threaded_context *tctx;
+ /* Pointer to link object owned by *ev. */
+ struct pthreadpool_tevent_glue_ev_link *ev_link;
+};
+
+/*
+ * The pthreadpool_tevent_glue_ev_link and its destructor ensure we remove the
+ * tevent context from our list of active event contexts if the event context
+ * is destroyed.
+ * This structure is talloc()'ed from the struct tevent_context *, and is a
+ * back-pointer allowing the related struct pthreadpool_tevent_glue object
+ * to be removed from the struct pthreadpool_tevent glue list if the owning
+ * tevent_context is talloc_free()'ed.
+ */
+struct pthreadpool_tevent_glue_ev_link {
+ struct pthreadpool_tevent_glue *glue;
+};
+
+struct pthreadpool_tevent {
+ struct pthreadpool *pool;
+ struct pthreadpool_tevent_glue *glue_list;
+
+ struct pthreadpool_tevent_job_state *jobs;
+};
+
+struct pthreadpool_tevent_job_state {
+ struct pthreadpool_tevent_job_state *prev, *next;
+ struct pthreadpool_tevent *pool;
+ struct tevent_context *ev;
+ struct tevent_immediate *im;
+ struct tevent_req *req;
+
+ void (*fn)(void *private_data);
+ void *private_data;
+};
+
+static int pthreadpool_tevent_destructor(struct pthreadpool_tevent *pool);
+
+static int pthreadpool_tevent_job_signal(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_private_data,
+ void *private_data);
+
+int pthreadpool_tevent_init(TALLOC_CTX *mem_ctx, unsigned max_threads,
+ struct pthreadpool_tevent **presult)
+{
+ struct pthreadpool_tevent *pool;
+ int ret;
+
+ pool = talloc_zero(mem_ctx, struct pthreadpool_tevent);
+ if (pool == NULL) {
+ return ENOMEM;
+ }
+
+ ret = pthreadpool_init(max_threads, &pool->pool,
+ pthreadpool_tevent_job_signal, pool);
+ if (ret != 0) {
+ TALLOC_FREE(pool);
+ return ret;
+ }
+
+ talloc_set_destructor(pool, pthreadpool_tevent_destructor);
+
+ *presult = pool;
+ return 0;
+}
+
+size_t pthreadpool_tevent_max_threads(struct pthreadpool_tevent *pool)
+{
+ if (pool->pool == NULL) {
+ return 0;
+ }
+
+ return pthreadpool_max_threads(pool->pool);
+}
+
+size_t pthreadpool_tevent_queued_jobs(struct pthreadpool_tevent *pool)
+{
+ if (pool->pool == NULL) {
+ return 0;
+ }
+
+ return pthreadpool_queued_jobs(pool->pool);
+}
+
+static int pthreadpool_tevent_destructor(struct pthreadpool_tevent *pool)
+{
+ struct pthreadpool_tevent_job_state *state, *next;
+ struct pthreadpool_tevent_glue *glue = NULL;
+ int ret;
+
+ ret = pthreadpool_stop(pool->pool);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (state = pool->jobs; state != NULL; state = next) {
+ next = state->next;
+ DLIST_REMOVE(pool->jobs, state);
+ state->pool = NULL;
+ }
+
+ /*
+ * Delete all the registered
+ * tevent_context/tevent_threaded_context
+ * pairs.
+ */
+ for (glue = pool->glue_list; glue != NULL; glue = pool->glue_list) {
+ /* The glue destructor removes it from the list */
+ TALLOC_FREE(glue);
+ }
+ pool->glue_list = NULL;
+
+ ret = pthreadpool_destroy(pool->pool);
+ if (ret != 0) {
+ return ret;
+ }
+ pool->pool = NULL;
+
+ return 0;
+}
+
+static int pthreadpool_tevent_glue_destructor(
+ struct pthreadpool_tevent_glue *glue)
+{
+ if (glue->pool->glue_list != NULL) {
+ DLIST_REMOVE(glue->pool->glue_list, glue);
+ }
+
+ /* Ensure the ev_link destructor knows we're gone */
+ glue->ev_link->glue = NULL;
+
+ TALLOC_FREE(glue->ev_link);
+ TALLOC_FREE(glue->tctx);
+
+ return 0;
+}
+
+/*
+ * Destructor called either explicitly from
+ * pthreadpool_tevent_glue_destructor(), or indirectly
+ * when owning tevent_context is destroyed.
+ *
+ * When called from pthreadpool_tevent_glue_destructor()
+ * ev_link->glue is already NULL, so this does nothing.
+ *
+ * When called from talloc_free() of the owning
+ * tevent_context we must ensure we also remove the
+ * linked glue object from the list inside
+ * struct pthreadpool_tevent.
+ */
+static int pthreadpool_tevent_glue_link_destructor(
+ struct pthreadpool_tevent_glue_ev_link *ev_link)
+{
+ TALLOC_FREE(ev_link->glue);
+ return 0;
+}
+
+static int pthreadpool_tevent_register_ev(struct pthreadpool_tevent *pool,
+ struct tevent_context *ev)
+{
+ struct pthreadpool_tevent_glue *glue = NULL;
+ struct pthreadpool_tevent_glue_ev_link *ev_link = NULL;
+
+ /*
+ * See if this tevent_context was already registered by
+ * searching the glue object list. If so we have nothing
+ * to do here - we already have a tevent_context/tevent_threaded_context
+ * pair.
+ */
+ for (glue = pool->glue_list; glue != NULL; glue = glue->next) {
+ if (glue->ev == ev) {
+ return 0;
+ }
+ }
+
+ /*
+ * Event context not yet registered - create a new glue
+ * object containing a tevent_context/tevent_threaded_context
+ * pair and put it on the list to remember this registration.
+ * We also need a link object to ensure the event context
+ * can't go away without us knowing about it.
+ */
+ glue = talloc_zero(pool, struct pthreadpool_tevent_glue);
+ if (glue == NULL) {
+ return ENOMEM;
+ }
+ *glue = (struct pthreadpool_tevent_glue) {
+ .pool = pool,
+ .ev = ev,
+ };
+ talloc_set_destructor(glue, pthreadpool_tevent_glue_destructor);
+
+ /*
+ * Now allocate the link object to the event context. Note this
+ * is allocated OFF THE EVENT CONTEXT ITSELF, so if the event
+ * context is freed we are able to cleanup the glue object
+ * in the link object destructor.
+ */
+
+ ev_link = talloc_zero(ev, struct pthreadpool_tevent_glue_ev_link);
+ if (ev_link == NULL) {
+ TALLOC_FREE(glue);
+ return ENOMEM;
+ }
+ ev_link->glue = glue;
+ talloc_set_destructor(ev_link, pthreadpool_tevent_glue_link_destructor);
+
+ glue->ev_link = ev_link;
+
+#ifdef HAVE_PTHREAD
+ glue->tctx = tevent_threaded_context_create(glue, ev);
+ if (glue->tctx == NULL) {
+ TALLOC_FREE(ev_link);
+ TALLOC_FREE(glue);
+ return ENOMEM;
+ }
+#endif
+
+ DLIST_ADD(pool->glue_list, glue);
+ return 0;
+}
+
+static void pthreadpool_tevent_job_fn(void *private_data);
+static void pthreadpool_tevent_job_done(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static int pthreadpool_tevent_job_state_destructor(
+ struct pthreadpool_tevent_job_state *state)
+{
+ if (state->pool == NULL) {
+ return 0;
+ }
+
+ /*
+ * We should never be called with state->req == NULL,
+ * state->pool must be cleared before the 2nd talloc_free().
+ */
+ if (state->req == NULL) {
+ abort();
+ }
+
+ /*
+ * We need to reparent to a long term context.
+ */
+ (void)talloc_reparent(state->req, NULL, state);
+ state->req = NULL;
+ return -1;
+}
+
+struct tevent_req *pthreadpool_tevent_job_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct pthreadpool_tevent *pool,
+ void (*fn)(void *private_data), void *private_data)
+{
+ struct tevent_req *req;
+ struct pthreadpool_tevent_job_state *state;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct pthreadpool_tevent_job_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->pool = pool;
+ state->ev = ev;
+ state->req = req;
+ state->fn = fn;
+ state->private_data = private_data;
+
+ if (pool == NULL) {
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
+ }
+ if (pool->pool == NULL) {
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
+ }
+
+ state->im = tevent_create_immediate(state);
+ if (tevent_req_nomem(state->im, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ret = pthreadpool_tevent_register_ev(pool, ev);
+ if (tevent_req_error(req, ret)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ret = pthreadpool_add_job(pool->pool, 0,
+ pthreadpool_tevent_job_fn,
+ state);
+ if (tevent_req_error(req, ret)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * Once the job is scheduled, we need to protect
+ * our memory.
+ */
+ talloc_set_destructor(state, pthreadpool_tevent_job_state_destructor);
+
+ DLIST_ADD_END(pool->jobs, state);
+
+ return req;
+}
+
+static void pthreadpool_tevent_job_fn(void *private_data)
+{
+ struct pthreadpool_tevent_job_state *state = talloc_get_type_abort(
+ private_data, struct pthreadpool_tevent_job_state);
+ state->fn(state->private_data);
+}
+
+static int pthreadpool_tevent_job_signal(int jobid,
+ void (*job_fn)(void *private_data),
+ void *job_private_data,
+ void *private_data)
+{
+ struct pthreadpool_tevent_job_state *state = talloc_get_type_abort(
+ job_private_data, struct pthreadpool_tevent_job_state);
+ struct tevent_threaded_context *tctx = NULL;
+ struct pthreadpool_tevent_glue *g = NULL;
+
+ if (state->pool == NULL) {
+ /* The pthreadpool_tevent is already gone */
+ return 0;
+ }
+
+#ifdef HAVE_PTHREAD
+ for (g = state->pool->glue_list; g != NULL; g = g->next) {
+ if (g->ev == state->ev) {
+ tctx = g->tctx;
+ break;
+ }
+ }
+
+ if (tctx == NULL) {
+ abort();
+ }
+#endif
+
+ if (tctx != NULL) {
+ /* with HAVE_PTHREAD */
+ tevent_threaded_schedule_immediate(tctx, state->im,
+ pthreadpool_tevent_job_done,
+ state);
+ } else {
+ /* without HAVE_PTHREAD */
+ tevent_schedule_immediate(state->im, state->ev,
+ pthreadpool_tevent_job_done,
+ state);
+ }
+
+ return 0;
+}
+
+static void pthreadpool_tevent_job_done(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct pthreadpool_tevent_job_state *state = talloc_get_type_abort(
+ private_data, struct pthreadpool_tevent_job_state);
+
+ if (state->pool != NULL) {
+ DLIST_REMOVE(state->pool->jobs, state);
+ state->pool = NULL;
+ }
+
+ if (state->req == NULL) {
+ /*
+ * There was a talloc_free() state->req
+ * while the job was pending,
+ * which mean we're reparented on a longterm
+ * talloc context.
+ *
+ * We just cleanup here...
+ */
+ talloc_free(state);
+ return;
+ }
+
+ tevent_req_done(state->req);
+}
+
+int pthreadpool_tevent_job_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
diff --git a/lib/pthreadpool/pthreadpool_tevent.h b/lib/pthreadpool/pthreadpool_tevent.h
new file mode 100644
index 0000000..10d3a71
--- /dev/null
+++ b/lib/pthreadpool/pthreadpool_tevent.h
@@ -0,0 +1,40 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * threadpool implementation based on pthreads
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PTHREADPOOL_TEVENT_H__
+#define __PTHREADPOOL_TEVENT_H__
+
+#include <tevent.h>
+
+struct pthreadpool_tevent;
+
+int pthreadpool_tevent_init(TALLOC_CTX *mem_ctx, unsigned max_threads,
+ struct pthreadpool_tevent **presult);
+
+size_t pthreadpool_tevent_max_threads(struct pthreadpool_tevent *pool);
+size_t pthreadpool_tevent_queued_jobs(struct pthreadpool_tevent *pool);
+
+struct tevent_req *pthreadpool_tevent_job_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct pthreadpool_tevent *pool,
+ void (*fn)(void *private_data), void *private_data);
+
+int pthreadpool_tevent_job_recv(struct tevent_req *req);
+
+#endif
diff --git a/lib/pthreadpool/tests.c b/lib/pthreadpool/tests.c
new file mode 100644
index 0000000..08cb59e
--- /dev/null
+++ b/lib/pthreadpool/tests.c
@@ -0,0 +1,517 @@
+#include <stdio.h>
+#include <string.h>
+#include <poll.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include "pthreadpool_pipe.h"
+#include "pthreadpool_tevent.h"
+
+static int test_init(void)
+{
+ struct pthreadpool_pipe *p;
+ int ret;
+
+ ret = pthreadpool_pipe_init(1, &p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+ ret = pthreadpool_pipe_destroy(p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+ return 0;
+}
+
+static void test_sleep(void *ptr)
+{
+ int *ptimeout = (int *)ptr;
+ int ret;
+ ret = poll(NULL, 0, *ptimeout);
+ if (ret != 0) {
+ fprintf(stderr, "poll returned %d (%s)\n",
+ ret, strerror(errno));
+ }
+}
+
+static int test_jobs(int num_threads, int num_jobs)
+{
+ char *finished;
+ struct pthreadpool_pipe *p;
+ int timeout = 1;
+ int i, ret;
+
+ finished = (char *)calloc(1, num_jobs);
+ if (finished == NULL) {
+ fprintf(stderr, "calloc failed\n");
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_init(num_threads, &p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
+ strerror(ret));
+ free(finished);
+ return -1;
+ }
+
+ for (i=0; i<num_jobs; i++) {
+ ret = pthreadpool_pipe_add_job(p, i, test_sleep, &timeout);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_add_job failed: "
+ "%s\n", strerror(ret));
+ free(finished);
+ return -1;
+ }
+ }
+
+ for (i=0; i<num_jobs; i++) {
+ int jobid = -1;
+ ret = pthreadpool_pipe_finished_jobs(p, &jobid, 1);
+ if (ret < 0) {
+ fprintf(stderr, "pthreadpool_pipe_finished_jobs "
+ "failed: %s\n", strerror(-ret));
+ free(finished);
+ return -1;
+ }
+ if ((ret != 1) || (jobid >= num_jobs)) {
+ fprintf(stderr, "invalid job number %d\n", jobid);
+ free(finished);
+ return -1;
+ }
+ finished[jobid] += 1;
+ }
+
+ for (i=0; i<num_jobs; i++) {
+ if (finished[i] != 1) {
+ fprintf(stderr, "finished[%d] = %d\n",
+ i, finished[i]);
+ free(finished);
+ return -1;
+ }
+ }
+
+ ret = pthreadpool_pipe_destroy(p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
+ strerror(ret));
+ free(finished);
+ return -1;
+ }
+
+ free(finished);
+ return 0;
+}
+
+static int test_busydestroy(void)
+{
+ struct pthreadpool_pipe *p;
+ int timeout = 50;
+ struct pollfd pfd;
+ int ret, jobid;
+
+ ret = pthreadpool_pipe_init(1, &p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+ ret = pthreadpool_pipe_add_job(p, 1, test_sleep, &timeout);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_add_job failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+ ret = pthreadpool_pipe_destroy(p);
+ if (ret != EBUSY) {
+ fprintf(stderr, "Could destroy a busy pool\n");
+ return -1;
+ }
+
+ pfd.fd = pthreadpool_pipe_signal_fd(p);
+ pfd.events = POLLIN|POLLERR;
+
+ do {
+ ret = poll(&pfd, 1, -1);
+ } while ((ret == -1) && (errno == EINTR));
+
+ ret = pthreadpool_pipe_finished_jobs(p, &jobid, 1);
+ if (ret < 0) {
+ fprintf(stderr, "pthreadpool_pipe_finished_jobs failed: %s\n",
+ strerror(-ret));
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_destroy(p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+ return 0;
+}
+
+static int test_fork(void)
+{
+ struct pthreadpool_pipe *p;
+ pid_t child, waited;
+ int status, ret;
+
+ ret = pthreadpool_pipe_init(1, &p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+ ret = pthreadpool_pipe_destroy(p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+
+ child = fork();
+ if (child < 0) {
+ perror("fork failed");
+ return -1;
+ }
+ if (child == 0) {
+ exit(0);
+ }
+ waited = wait(&status);
+ if (waited == -1) {
+ perror("wait failed");
+ return -1;
+ }
+ if (waited != child) {
+ fprintf(stderr, "expected child %d, got %d\n",
+ (int)child, (int)waited);
+ return -1;
+ }
+ return 0;
+}
+
+static void busyfork_job(void *private_data)
+{
+ return;
+}
+
+static int test_busyfork(void)
+{
+ struct pthreadpool_pipe *p;
+ int fds[2];
+ struct pollfd pfd;
+ pid_t child, waitret;
+ int ret, jobnum, wstatus;
+
+ ret = pipe(fds);
+ if (ret == -1) {
+ perror("pipe failed");
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_init(1, &p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_add_job(p, 1, busyfork_job, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_add_job failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_finished_jobs(p, &jobnum, 1);
+ if (ret != 1) {
+ fprintf(stderr, "pthreadpool_pipe_finished_jobs failed\n");
+ return -1;
+ }
+
+ ret = poll(NULL, 0, 200);
+ if (ret == -1) {
+ perror("poll failed");
+ return -1;
+ }
+
+ child = fork();
+ if (child < 0) {
+ perror("fork failed");
+ return -1;
+ }
+
+ if (child == 0) {
+ ret = pthreadpool_pipe_destroy(p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_destroy failed: "
+ "%s\n", strerror(ret));
+ exit(1);
+ }
+ exit(0);
+ }
+
+ ret = close(fds[1]);
+ if (ret == -1) {
+ perror("close failed");
+ return -1;
+ }
+
+ pfd = (struct pollfd) { .fd = fds[0], .events = POLLIN };
+
+ ret = poll(&pfd, 1, 5000);
+ if (ret == -1) {
+ perror("poll failed");
+ return -1;
+ }
+ if (ret == 0) {
+ fprintf(stderr, "Child did not exit for 5 seconds\n");
+ /*
+ * The child might hang forever in
+ * pthread_cond_destroy for example. Be kind to the
+ * system and kill it.
+ */
+ kill(child, SIGTERM);
+ return -1;
+ }
+ if (ret != 1) {
+ fprintf(stderr, "poll returned %d -- huh??\n", ret);
+ return -1;
+ }
+
+ ret = poll(NULL, 0, 200);
+ if (ret == -1) {
+ perror("poll failed");
+ return -1;
+ }
+
+ waitret = waitpid(child, &wstatus, WNOHANG);
+ if (waitret != child) {
+ fprintf(stderr, "waitpid returned %d\n", (int)waitret);
+ return -1;
+ }
+
+ if (!WIFEXITED(wstatus)) {
+ fprintf(stderr, "child did not properly exit\n");
+ return -1;
+ }
+
+ ret = WEXITSTATUS(wstatus);
+ if (ret != 0) {
+ fprintf(stderr, "child returned %d\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int test_busyfork2(void)
+{
+ struct pthreadpool_pipe *p;
+ pid_t child;
+ int ret, jobnum;
+ struct pollfd pfd;
+
+ ret = pthreadpool_pipe_init(1, &p);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_add_job(p, 1, busyfork_job, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_add_job failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_finished_jobs(p, &jobnum, 1);
+ if (ret != 1) {
+ fprintf(stderr, "pthreadpool_pipe_finished_jobs failed\n");
+ return -1;
+ }
+
+ ret = poll(NULL, 0, 10);
+ if (ret == -1) {
+ perror("poll failed");
+ return -1;
+ }
+
+ ret = pthreadpool_pipe_add_job(p, 1, busyfork_job, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_add_job failed: %s\n",
+ strerror(ret));
+ return -1;
+ }
+
+ /*
+ * Do the fork right after the add_job. This tests a race
+ * where the atfork prepare handler gets all idle threads off
+ * the condvar. If we are faster doing the fork than the
+ * existing idle thread could get out of idle and take the
+ * job, after the fork we end up with no threads to take care
+ * of the job.
+ */
+
+ child = fork();
+ if (child < 0) {
+ perror("fork failed");
+ return -1;
+ }
+
+ if (child == 0) {
+ exit(0);
+ }
+
+ pfd = (struct pollfd) {
+ .fd = pthreadpool_pipe_signal_fd(p),
+ .events = POLLIN|POLLERR
+ };
+
+ do {
+ ret = poll(&pfd, 1, 5000);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret == 0) {
+ fprintf(stderr, "job unfinished after 5 seconds\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void test_tevent_wait(void *private_data)
+{
+ int *timeout = private_data;
+ poll(NULL, 0, *timeout);
+}
+
+static int test_tevent_1(void)
+{
+ struct tevent_context *ev;
+ struct pthreadpool_tevent *pool;
+ struct tevent_req *req1, *req2;
+ int timeout10 = 10;
+ int timeout100 = 100;
+ int ret;
+ bool ok;
+
+ ev = tevent_context_init(NULL);
+ if (ev == NULL) {
+ ret = errno;
+ fprintf(stderr, "tevent_context_init failed: %s\n",
+ strerror(ret));
+ return ret;
+ }
+ ret = pthreadpool_tevent_init(ev, UINT_MAX, &pool);
+ if (ret != 0) {
+ fprintf(stderr, "pthreadpool_tevent_init failed: %s\n",
+ strerror(ret));
+ TALLOC_FREE(ev);
+ return ret;
+ }
+ req1 = pthreadpool_tevent_job_send(
+ ev, ev, pool, test_tevent_wait, &timeout10);
+ if (req1 == NULL) {
+ fprintf(stderr, "pthreadpool_tevent_job_send failed\n");
+ TALLOC_FREE(ev);
+ return ENOMEM;
+ }
+ req2 = pthreadpool_tevent_job_send(
+ ev, ev, pool, test_tevent_wait, &timeout100);
+ if (req2 == NULL) {
+ fprintf(stderr, "pthreadpool_tevent_job_send failed\n");
+ TALLOC_FREE(ev);
+ return ENOMEM;
+ }
+ ok = tevent_req_poll(req2, ev);
+ if (!ok) {
+ ret = errno;
+ fprintf(stderr, "tevent_req_poll failed: %s\n",
+ strerror(ret));
+ TALLOC_FREE(ev);
+ return ret;
+ }
+ ret = pthreadpool_tevent_job_recv(req1);
+ TALLOC_FREE(req1);
+ if (ret != 0) {
+ fprintf(stderr, "tevent_req_poll failed: %s\n",
+ strerror(ret));
+ TALLOC_FREE(ev);
+ return ret;
+ }
+
+ TALLOC_FREE(req2);
+
+ ret = tevent_loop_wait(ev);
+ if (ret != 0) {
+ fprintf(stderr, "tevent_loop_wait failed\n");
+ return ret;
+ }
+
+ TALLOC_FREE(pool);
+ TALLOC_FREE(ev);
+ return 0;
+}
+
+int main(void)
+{
+ int ret;
+
+ ret = test_tevent_1();
+ if (ret != 0) {
+ fprintf(stderr, "test_event_1 failed: %s\n",
+ strerror(ret));
+ return 1;
+ }
+
+ ret = test_init();
+ if (ret != 0) {
+ fprintf(stderr, "test_init failed\n");
+ return 1;
+ }
+
+ ret = test_fork();
+ if (ret != 0) {
+ fprintf(stderr, "test_fork failed\n");
+ return 1;
+ }
+
+ ret = test_jobs(10, 10000);
+ if (ret != 0) {
+ fprintf(stderr, "test_jobs failed\n");
+ return 1;
+ }
+
+ ret = test_busydestroy();
+ if (ret != 0) {
+ fprintf(stderr, "test_busydestroy failed\n");
+ return 1;
+ }
+
+ ret = test_busyfork();
+ if (ret != 0) {
+ fprintf(stderr, "test_busyfork failed\n");
+ return 1;
+ }
+
+ ret = test_busyfork2();
+ if (ret != 0) {
+ fprintf(stderr, "test_busyfork2 failed\n");
+ return 1;
+ }
+
+ printf("success\n");
+ return 0;
+}
diff --git a/lib/pthreadpool/tests_cmocka.c b/lib/pthreadpool/tests_cmocka.c
new file mode 100644
index 0000000..e6af884
--- /dev/null
+++ b/lib/pthreadpool/tests_cmocka.c
@@ -0,0 +1,247 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * cmocka tests for thread pool implementation
+ * Copyright (C) Christof Schmitt 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <talloc.h>
+#include <tevent.h>
+#include <pthreadpool_tevent.h>
+
+#include <cmocka.h>
+#include <poll.h>
+
+struct pthreadpool_tevent_test {
+ struct tevent_context *ev;
+ struct pthreadpool_tevent *upool;
+ struct pthreadpool_tevent *spool;
+ struct pthreadpool_tevent *opool;
+};
+
+static int setup_pthreadpool_tevent(void **state)
+{
+ struct pthreadpool_tevent_test *t;
+ int ret;
+ size_t max_threads;
+
+ t = talloc_zero(NULL, struct pthreadpool_tevent_test);
+ assert_non_null(t);
+
+ t->ev = tevent_context_init(t);
+ assert_non_null(t->ev);
+
+ ret = pthreadpool_tevent_init(t->ev, UINT_MAX, &t->upool);
+ assert_int_equal(ret, 0);
+
+ max_threads = pthreadpool_tevent_max_threads(t->upool);
+ assert_int_equal(max_threads, UINT_MAX);
+
+ ret = pthreadpool_tevent_init(t->ev, 1, &t->opool);
+ assert_int_equal(ret, 0);
+
+ max_threads = pthreadpool_tevent_max_threads(t->opool);
+ assert_int_equal(max_threads, 1);
+
+ ret = pthreadpool_tevent_init(t->ev, 0, &t->spool);
+ assert_int_equal(ret, 0);
+
+ max_threads = pthreadpool_tevent_max_threads(t->spool);
+ assert_int_equal(max_threads, 0);
+
+ *state = t;
+
+ return 0;
+}
+
+static int teardown_pthreadpool_tevent(void **state)
+{
+ struct pthreadpool_tevent_test *t = *state;
+
+ TALLOC_FREE(t);
+
+ return 0;
+}
+
+int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg);
+int __real_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg);
+
+int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ int error;
+
+ error = mock_type(int);
+ if (error != 0) {
+ return error;
+ }
+
+ return __real_pthread_create(thread, attr, start_routine, arg);
+}
+
+static void test_job_threadid(void *ptr)
+{
+ pthread_t *threadid = ptr;
+
+ *threadid = pthread_self();
+}
+
+static int test_create_do(struct tevent_context *ev,
+ struct pthreadpool_tevent *pool,
+ bool *executed,
+ bool *in_main_thread)
+{
+ struct tevent_req *req;
+ pthread_t zero_thread;
+ pthread_t main_thread;
+ pthread_t worker_thread;
+ bool ok;
+ int ret;
+
+ *executed = false;
+ *in_main_thread = false;
+
+ memset(&zero_thread, 0, sizeof(zero_thread));
+ main_thread = pthread_self();
+ worker_thread = zero_thread;
+
+ req = pthreadpool_tevent_job_send(
+ ev, ev, pool, test_job_threadid, &worker_thread);
+ if (req == NULL) {
+ fprintf(stderr, "pthreadpool_tevent_job_send failed\n");
+ return ENOMEM;
+ }
+
+ ok = tevent_req_poll(req, ev);
+ if (!ok) {
+ ret = errno;
+ fprintf(stderr, "tevent_req_poll failed: %s\n",
+ strerror(ret));
+ *executed = !pthread_equal(worker_thread, zero_thread);
+ *in_main_thread = pthread_equal(worker_thread, main_thread);
+ return ret;
+ }
+
+
+ ret = pthreadpool_tevent_job_recv(req);
+ TALLOC_FREE(req);
+ *executed = !pthread_equal(worker_thread, zero_thread);
+ *in_main_thread = pthread_equal(worker_thread, main_thread);
+ if (ret != 0) {
+ fprintf(stderr, "tevent_req_recv failed: %s\n",
+ strerror(ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+static void test_create(void **state)
+{
+ struct pthreadpool_tevent_test *t = *state;
+ bool executed;
+ bool in_main_thread;
+ int ret;
+
+ /*
+ * When pthreadpool cannot create the first worker thread,
+ * this job will run in the sync fallback in the main thread.
+ */
+ will_return(__wrap_pthread_create, EAGAIN);
+ ret = test_create_do(t->ev, t->upool, &executed, &in_main_thread);
+ assert_int_equal(ret, EAGAIN);
+ assert_false(executed);
+ assert_false(in_main_thread);
+
+ /*
+ * The sync pool won't trigger pthread_create()
+ * It will be triggered by the one pool.
+ */
+ will_return(__wrap_pthread_create, EAGAIN);
+
+ ret = test_create_do(t->ev, t->spool, &executed, &in_main_thread);
+ assert_int_equal(ret, 0);
+ assert_true(executed);
+ assert_true(in_main_thread);
+
+ ret = test_create_do(t->ev, t->opool, &executed, &in_main_thread);
+ assert_int_equal(ret, EAGAIN);
+ assert_false(executed);
+ assert_false(in_main_thread);
+
+ /*
+ * When a thread can be created, the job will run in the worker thread.
+ */
+ will_return(__wrap_pthread_create, 0);
+ ret = test_create_do(t->ev, t->upool, &executed, &in_main_thread);
+ assert_int_equal(ret, 0);
+ assert_true(executed);
+ assert_false(in_main_thread);
+
+ poll(NULL, 0, 10);
+
+ /*
+ * Workerthread will still be active for a second; immediately
+ * running another job will also use the worker thread, even
+ * if a new thread cannot be created.
+ */
+ ret = test_create_do(t->ev, t->upool, &executed, &in_main_thread);
+ assert_int_equal(ret, 0);
+ assert_true(executed);
+ assert_false(in_main_thread);
+
+ /*
+ * When a thread can be created, the job will run in the worker thread.
+ */
+ will_return(__wrap_pthread_create, 0);
+ ret = test_create_do(t->ev, t->opool, &executed, &in_main_thread);
+ assert_int_equal(ret, 0);
+ assert_true(executed);
+ assert_false(in_main_thread);
+
+ poll(NULL, 0, 10);
+
+ /*
+ * Workerthread will still be active for a second; immediately
+ * running another job will also use the worker thread, even
+ * if a new thread cannot be created.
+ */
+ ret = test_create_do(t->ev, t->opool, &executed, &in_main_thread);
+ assert_int_equal(ret, 0);
+ assert_true(executed);
+ assert_false(in_main_thread);
+}
+
+int main(int argc, char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_create,
+ setup_pthreadpool_tevent,
+ teardown_pthreadpool_tevent),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/pthreadpool/wscript_build b/lib/pthreadpool/wscript_build
new file mode 100644
index 0000000..e270f90
--- /dev/null
+++ b/lib/pthreadpool/wscript_build
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+if bld.env.WITH_PTHREADPOOL:
+ extra_libs=''
+
+ # Link to librt if needed for clock_gettime()
+ if bld.CONFIG_SET('HAVE_LIBRT'): extra_libs += ' rt'
+
+ bld.SAMBA_SUBSYSTEM('PTHREADPOOL',
+ source='''pthreadpool.c
+ pthreadpool_pipe.c
+ pthreadpool_tevent.c
+ ''',
+ deps='pthread replace tevent-util' + extra_libs)
+else:
+ bld.SAMBA_SUBSYSTEM('PTHREADPOOL',
+ source='''pthreadpool_sync.c
+ pthreadpool_pipe.c
+ pthreadpool_tevent.c
+ ''',
+ deps='replace tevent-util')
+
+
+bld.SAMBA_BINARY('pthreadpooltest',
+ source='tests.c',
+ deps='PTHREADPOOL',
+ enabled=bld.env.WITH_PTHREADPOOL,
+ for_selftest=True)
+
+bld.SAMBA_BINARY('pthreadpooltest_cmocka',
+ source='tests_cmocka.c',
+ deps='PTHREADPOOL cmocka',
+ ldflags='-Wl,--wrap=pthread_create',
+ enabled=bld.env.WITH_PTHREADPOOL and bld.env['HAVE_LDWRAP'],
+ for_selftest=True)
diff --git a/lib/replace/.checker_innocent b/lib/replace/.checker_innocent
new file mode 100644
index 0000000..e619176
--- /dev/null
+++ b/lib/replace/.checker_innocent
@@ -0,0 +1,4 @@
+>>>MISTAKE21_create_files_6a9e68ada99a97cb
+>>>MISTAKE21_os2_delete_9b2bfa7f38711d09
+>>>MISTAKE21_os2_delete_2fcc29aaa99a97cb
+>>>SECURITY2_os2_delete_9b2bfa7f1c9396ca
diff --git a/lib/replace/Makefile b/lib/replace/Makefile
new file mode 100644
index 0000000..a123a37
--- /dev/null
+++ b/lib/replace/Makefile
@@ -0,0 +1,64 @@
+# simple makefile wrapper to run waf
+
+WAF_BINARY=$(PYTHON) ../../buildtools/bin/waf
+WAF=PYTHONHASHSEED=1 WAF_MAKE=1 $(WAF_BINARY)
+
+all:
+ $(WAF) build
+
+install:
+ $(WAF) install
+
+uninstall:
+ $(WAF) uninstall
+
+test:
+ $(WAF) test $(TEST_OPTIONS)
+
+testenv:
+ $(WAF) test --testenv $(TEST_OPTIONS)
+
+quicktest:
+ $(WAF) test --quick $(TEST_OPTIONS)
+
+dist:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) dist
+
+distcheck:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) distcheck
+
+clean:
+ $(WAF) clean
+
+distclean:
+ $(WAF) distclean
+
+reconfigure: configure
+ $(WAF) reconfigure
+
+show_waf_options:
+ $(WAF) --help
+
+# some compatibility make targets
+everything: all
+
+testsuite: all
+
+check: test
+
+torture: all
+
+# this should do an install as well, once install is finished
+installcheck: test
+
+etags:
+ $(WAF) etags
+
+ctags:
+ $(WAF) ctags
+
+bin/%:: FORCE
+ $(WAF) --targets=`basename $@`
+FORCE:
diff --git a/lib/replace/README b/lib/replace/README
new file mode 100644
index 0000000..6612eab
--- /dev/null
+++ b/lib/replace/README
@@ -0,0 +1,128 @@
+This subsystem ensures that we can always use a certain core set of
+functions and types, that are either provided by the OS or by replacement
+functions / definitions in this subsystem. The aim is to try to stick
+to POSIX functions in here as much as possible. Convenience functions
+that are available on no platform at all belong in other subsystems
+(such as LIBUTIL).
+
+The following functions are guaranteed:
+
+ftruncate
+strlcpy
+strlcat
+mktime
+rename
+initgroups
+memmove
+strdup
+setlinebuf
+vsyslog
+timegm
+setenv
+unsetenv
+strndup
+strnlen
+waitpid
+seteuid
+setegid
+asprintf
+snprintf
+vasprintf
+vsnprintf
+opendir
+readdir
+telldir
+seekdir
+clock_gettime
+closedir
+dlopen
+dlclose
+dlsym
+dlerror
+chroot
+bzero
+strerror
+errno
+mkdtemp
+mkstemp (a secure one!)
+pread
+pwrite
+chown
+lchown
+readline (the library)
+inet_ntoa
+inet_ntop
+inet_pton
+inet_aton
+strtoll
+strtoull
+socketpair
+strptime
+getaddrinfo
+freeaddrinfo
+getnameinfo
+gai_strerror
+getifaddrs
+freeifaddrs
+utime
+utimes
+dup2
+link
+readlink
+symlink
+realpath
+poll
+setproctitle
+memset_s
+
+Types:
+bool
+socklen_t
+uint{8,16,32,64}_t
+int{8,16,32,64}_t
+intptr_t
+sig_atomic_t
+blksize_t
+blkcnt_t
+
+Constants:
+PATH_NAME_MAX
+UINT{16,32,64}_MAX
+INT32_MAX
+RTLD_LAZY
+HOST_NAME_MAX
+UINT16_MAX
+UINT32_MAX
+UINT64_MAX
+CHAR_BIT
+
+Macros:
+va_copy
+__FUNCTION__
+__FILE__
+__LINE__
+__LINESTR__
+__location__
+__STRING
+__STRINGSTRING
+MIN
+MAX
+QSORT_CAST
+ZERO_STRUCT
+ZERO_STRUCTP
+ZERO_STRUCTPN
+ZERO_ARRAY
+ARRAY_SIZE
+PTR_DIFF
+
+Headers:
+stdint.h
+stdbool.h
+
+Optional C keywords:
+volatile
+
+Prerequisites:
+memset (for bzero)
+syslog (for vsyslog)
+mktemp (for mkstemp and mkdtemp)
diff --git a/lib/replace/closefrom.c b/lib/replace/closefrom.c
new file mode 100644
index 0000000..bef53e4
--- /dev/null
+++ b/lib/replace/closefrom.c
@@ -0,0 +1,138 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+
+static int closefrom_sysconf(int lower)
+{
+ long max_files, fd;
+
+ max_files = sysconf(_SC_OPEN_MAX);
+ if (max_files == -1) {
+ max_files = 65536;
+ }
+
+ for (fd=lower; fd<max_files; fd++) {
+ close(fd);
+ }
+
+ return 0;
+}
+
+static int closefrom_procfs(int lower)
+{
+ DIR *dirp;
+ int dir_fd;
+ struct dirent *dp;
+ int *fds = NULL;
+ size_t num_fds = 0;
+ size_t fd_array_size = 0;
+ size_t i;
+ int ret = ENOMEM;
+
+ dirp = opendir("/proc/self/fd");
+ if (dirp == NULL) {
+ return errno;
+ }
+
+ dir_fd = dirfd(dirp);
+ if (dir_fd == -1) {
+ ret = errno;
+ goto fail;
+ }
+
+ while ((dp = readdir(dirp)) != NULL) {
+ char *endptr;
+ unsigned long long fd;
+
+ errno = 0;
+
+ fd = strtoull(dp->d_name, &endptr, 10);
+ if ((fd == 0) && (errno == EINVAL)) {
+ continue;
+ }
+ if ((fd == ULLONG_MAX) && (errno == ERANGE)) {
+ continue;
+ }
+ if (*endptr != '\0') {
+ continue;
+ }
+ if (fd == dir_fd) {
+ continue;
+ }
+ if (fd > INT_MAX) {
+ continue;
+ }
+ if (fd < lower) {
+ continue;
+ }
+
+ if (num_fds >= (fd_array_size / sizeof(int))) {
+ void *tmp;
+
+ if (fd_array_size == 0) {
+ fd_array_size = 16 * sizeof(int);
+ } else {
+ if (fd_array_size + fd_array_size <
+ fd_array_size) {
+ /* overflow */
+ goto fail;
+ }
+ fd_array_size = fd_array_size + fd_array_size;
+ }
+
+ tmp = realloc(fds, fd_array_size);
+ if (tmp == NULL) {
+ goto fail;
+ }
+ fds = tmp;
+ }
+
+ fds[num_fds++] = fd;
+ }
+
+ for (i=0; i<num_fds; i++) {
+ close(fds[i]);
+ }
+
+ ret = 0;
+fail:
+ closedir(dirp);
+ free(fds);
+ return ret;
+}
+
+int rep_closefrom(int lower)
+{
+ int ret;
+
+ ret = closefrom_procfs(lower);
+ if (ret == 0) {
+ return 0;
+ }
+
+ return closefrom_sysconf(lower);
+}
diff --git a/lib/replace/configure b/lib/replace/configure
new file mode 100755
index 0000000..af76185
--- /dev/null
+++ b/lib/replace/configure
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PREVPATH=$(dirname $0)
+
+if [ -f $PREVPATH/../../buildtools/bin/waf ]; then
+ WAF=../../buildtools/bin/waf
+elif [ -f $PREVPATH/buildtools/bin/waf ]; then
+ WAF=./buildtools/bin/waf
+else
+ echo "replace: Unable to find waf"
+ exit 1
+fi
+
+# using JOBS=1 gives maximum compatibility with
+# systems like AIX which have broken threading in python
+JOBS=1
+export JOBS
+
+# Make sure we don't have any library preloaded.
+unset LD_PRELOAD
+
+# Make sure we get stable hashes
+PYTHONHASHSEED=1
+export PYTHONHASHSEED
+
+cd . || exit 1
+$PYTHON $WAF configure "$@" || exit 1
+cd $PREVPATH
diff --git a/lib/replace/dlfcn.c b/lib/replace/dlfcn.c
new file mode 100644
index 0000000..88431ed
--- /dev/null
+++ b/lib/replace/dlfcn.c
@@ -0,0 +1,76 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2002
+ Copyright (C) Jelmer Vernooij 2006
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#ifdef HAVE_DL_H
+#include <dl.h>
+#endif
+
+#ifndef HAVE_DLOPEN
+#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS
+void *rep_dlopen(const char *name, unsigned int flags)
+#else
+void *rep_dlopen(const char *name, int flags)
+#endif
+{
+#ifdef HAVE_SHL_LOAD
+ if (name == NULL)
+ return PROG_HANDLE;
+ return (void *)shl_load(name, flags, 0);
+#else
+ return NULL;
+#endif
+}
+#endif
+
+#ifndef HAVE_DLSYM
+void *rep_dlsym(void *handle, const char *symbol)
+{
+#ifdef HAVE_SHL_FINDSYM
+ void *sym_addr;
+ if (!shl_findsym((shl_t *)&handle, symbol, TYPE_UNDEFINED, &sym_addr))
+ return sym_addr;
+#endif
+ return NULL;
+}
+#endif
+
+#ifndef HAVE_DLERROR
+char *rep_dlerror(void)
+{
+ return "dynamic loading of objects not supported on this platform";
+}
+#endif
+
+#ifndef HAVE_DLCLOSE
+int rep_dlclose(void *handle)
+{
+#ifdef HAVE_SHL_CLOSE
+ return shl_unload((shl_t)handle);
+#else
+ return 0;
+#endif
+}
+#endif
diff --git a/lib/replace/getaddrinfo.c b/lib/replace/getaddrinfo.c
new file mode 100644
index 0000000..8440d8e
--- /dev/null
+++ b/lib/replace/getaddrinfo.c
@@ -0,0 +1,493 @@
+/*
+PostgreSQL Database Management System
+(formerly known as Postgres, then as Postgres95)
+
+Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
+
+Portions Copyright (c) 1994, The Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this paragraph
+and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+*/
+
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.c
+ * Support getaddrinfo() on platforms that don't have it.
+ *
+ * We also supply getnameinfo() here, assuming that the platform will have
+ * it if and only if it has getaddrinfo(). If this proves false on some
+ * platform, we'll need to split this file and provide a separate configure
+ * test for getnameinfo().
+ *
+ * Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ *
+ * Copyright (C) 2007 Jeremy Allison.
+ * Modified to return multiple IPv4 addresses for Samba.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+#ifndef SMB_MALLOC
+#define SMB_MALLOC(s) malloc(s)
+#endif
+
+#ifndef SMB_STRDUP
+#define SMB_STRDUP(s) strdup(s)
+#endif
+
+static int check_hostent_err(struct hostent *hp)
+{
+ if (!hp) {
+ switch (h_errno) {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ return EAI_NONAME;
+ case TRY_AGAIN:
+ return EAI_AGAIN;
+ case NO_RECOVERY:
+ default:
+ return EAI_FAIL;
+ }
+ }
+ if (!hp->h_name || hp->h_addrtype != AF_INET) {
+ return EAI_FAIL;
+ }
+ return 0;
+}
+
+static char *canon_name_from_hostent(struct hostent *hp,
+ int *perr)
+{
+ char *ret = NULL;
+
+ *perr = check_hostent_err(hp);
+ if (*perr) {
+ return NULL;
+ }
+ ret = SMB_STRDUP(hp->h_name);
+ if (!ret) {
+ *perr = EAI_MEMORY;
+ }
+ return ret;
+}
+
+static char *get_my_canon_name(int *perr)
+{
+ char name[HOST_NAME_MAX+1];
+
+ if (gethostname(name, HOST_NAME_MAX) == -1) {
+ *perr = EAI_FAIL;
+ return NULL;
+ }
+ /* Ensure null termination. */
+ name[HOST_NAME_MAX] = '\0';
+ return canon_name_from_hostent(gethostbyname(name), perr);
+}
+
+static char *get_canon_name_from_addr(struct in_addr ip,
+ int *perr)
+{
+ return canon_name_from_hostent(
+ gethostbyaddr(&ip, sizeof(ip), AF_INET),
+ perr);
+}
+
+static struct addrinfo *alloc_entry(const struct addrinfo *hints,
+ struct in_addr ip,
+ unsigned short port)
+{
+ struct sockaddr_in *psin = NULL;
+ struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
+
+ if (!ai) {
+ return NULL;
+ }
+ memset(ai, '\0', sizeof(*ai));
+
+ psin = SMB_MALLOC(sizeof(*psin));
+ if (!psin) {
+ free(ai);
+ return NULL;
+ }
+
+ memset(psin, '\0', sizeof(*psin));
+
+ psin->sin_family = AF_INET;
+ psin->sin_port = htons(port);
+ psin->sin_addr = ip;
+
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints->ai_socktype;
+ ai->ai_protocol = hints->ai_protocol;
+ ai->ai_addrlen = sizeof(*psin);
+ ai->ai_addr = (struct sockaddr *) psin;
+ ai->ai_canonname = NULL;
+ ai->ai_next = NULL;
+
+ return ai;
+}
+
+/*
+ * get address info for a single ipv4 address.
+ *
+ * Bugs: - servname can only be a number, not text.
+ */
+
+static int getaddr_info_single_addr(const char *service,
+ uint32_t addr,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+
+ struct addrinfo *ai = NULL;
+ struct in_addr ip;
+ unsigned short port = 0;
+
+ if (service) {
+ port = (unsigned short)atoi(service);
+ }
+ ip.s_addr = htonl(addr);
+
+ ai = alloc_entry(hints, ip, port);
+ if (!ai) {
+ return EAI_MEMORY;
+ }
+
+ /* If we're asked for the canonical name,
+ * make sure it returns correctly. */
+ if (!(hints->ai_flags & AI_NUMERICSERV) &&
+ hints->ai_flags & AI_CANONNAME) {
+ int err;
+ if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
+ ai->ai_canonname = get_my_canon_name(&err);
+ } else {
+ ai->ai_canonname =
+ get_canon_name_from_addr(ip,&err);
+ }
+ if (ai->ai_canonname == NULL) {
+ freeaddrinfo(ai);
+ return err;
+ }
+ }
+
+ *res = ai;
+ return 0;
+}
+
+/*
+ * get address info for multiple ipv4 addresses.
+ *
+ * Bugs: - servname can only be a number, not text.
+ */
+
+static int getaddr_info_name(const char *node,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ struct addrinfo *listp = NULL, *prevp = NULL;
+ char **pptr = NULL;
+ int err;
+ struct hostent *hp = NULL;
+ unsigned short port = 0;
+
+ if (service) {
+ port = (unsigned short)atoi(service);
+ }
+
+ hp = gethostbyname(node);
+ err = check_hostent_err(hp);
+ if (err) {
+ return err;
+ }
+
+ for(pptr = hp->h_addr_list; *pptr; pptr++) {
+ struct in_addr ip = *(struct in_addr *)*pptr;
+ struct addrinfo *ai = alloc_entry(hints, ip, port);
+
+ if (!ai) {
+ freeaddrinfo(listp);
+ return EAI_MEMORY;
+ }
+
+ if (!listp) {
+ listp = ai;
+ prevp = ai;
+ ai->ai_canonname = SMB_STRDUP(hp->h_name);
+ if (!ai->ai_canonname) {
+ freeaddrinfo(listp);
+ return EAI_MEMORY;
+ }
+ } else {
+ prevp->ai_next = ai;
+ prevp = ai;
+ }
+ }
+ *res = listp;
+ return 0;
+}
+
+/*
+ * get address info for ipv4 sockets.
+ *
+ * Bugs: - servname can only be a number, not text.
+ */
+
+int rep_getaddrinfo(const char *node,
+ const char *service,
+ const struct addrinfo * hintp,
+ struct addrinfo ** res)
+{
+ struct addrinfo hints;
+
+ /* Setup the hints struct. */
+ if (hintp == NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ } else {
+ memcpy(&hints, hintp, sizeof(hints));
+ }
+
+ if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
+ return EAI_FAMILY;
+ }
+
+ if (hints.ai_socktype == 0) {
+ hints.ai_socktype = SOCK_STREAM;
+ }
+
+ if (!node && !service) {
+ return EAI_NONAME;
+ }
+
+ if (node) {
+ if (node[0] == '\0') {
+ return getaddr_info_single_addr(service,
+ INADDR_ANY,
+ &hints,
+ res);
+ } else if (hints.ai_flags & AI_NUMERICHOST) {
+ struct in_addr ip;
+ if (!inet_aton(node, &ip)) {
+ return EAI_FAIL;
+ }
+ return getaddr_info_single_addr(service,
+ ntohl(ip.s_addr),
+ &hints,
+ res);
+ } else {
+ return getaddr_info_name(node,
+ service,
+ &hints,
+ res);
+ }
+ } else if (hints.ai_flags & AI_PASSIVE) {
+ return getaddr_info_single_addr(service,
+ INADDR_ANY,
+ &hints,
+ res);
+ }
+ return getaddr_info_single_addr(service,
+ INADDR_LOOPBACK,
+ &hints,
+ res);
+}
+
+
+void rep_freeaddrinfo(struct addrinfo *res)
+{
+ struct addrinfo *next = NULL;
+
+ for (;res; res = next) {
+ next = res->ai_next;
+ free(res->ai_canonname);
+ free(res->ai_addr);
+ free(res);
+ }
+}
+
+
+const char *rep_gai_strerror(int errcode)
+{
+#ifdef HAVE_HSTRERROR
+ int hcode;
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ hcode = HOST_NOT_FOUND;
+ break;
+ case EAI_AGAIN:
+ hcode = TRY_AGAIN;
+ break;
+ case EAI_FAIL:
+ default:
+ hcode = NO_RECOVERY;
+ break;
+ }
+
+ return hstrerror(hcode);
+#else /* !HAVE_HSTRERROR */
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ return "Unknown host";
+ case EAI_AGAIN:
+ return "Host name lookup failure";
+#ifdef EAI_BADFLAGS
+ case EAI_BADFLAGS:
+ return "Invalid argument";
+#endif
+#ifdef EAI_FAMILY
+ case EAI_FAMILY:
+ return "Address family not supported";
+#endif
+#ifdef EAI_MEMORY
+ case EAI_MEMORY:
+ return "Not enough memory";
+#endif
+#ifdef EAI_NODATA
+ case EAI_NODATA:
+ return "No host data of that type was found";
+#endif
+#ifdef EAI_SERVICE
+ case EAI_SERVICE:
+ return "Class type not found";
+#endif
+#ifdef EAI_SOCKTYPE
+ case EAI_SOCKTYPE:
+ return "Socket type not supported";
+#endif
+ default:
+ return "Unknown server error";
+ }
+#endif /* HAVE_HSTRERROR */
+}
+
+static int gethostnameinfo(const struct sockaddr *sa,
+ char *node,
+ size_t nodelen,
+ int flags)
+{
+ int ret = -1;
+ char *p = NULL;
+
+ if (!(flags & NI_NUMERICHOST)) {
+ struct hostent *hp = gethostbyaddr(
+ &((struct sockaddr_in *)sa)->sin_addr,
+ sizeof(struct in_addr),
+ sa->sa_family);
+ ret = check_hostent_err(hp);
+ if (ret == 0) {
+ /* Name looked up successfully. */
+ ret = snprintf(node, nodelen, "%s", hp->h_name);
+ if (ret < 0 || (size_t)ret >= nodelen) {
+ return EAI_MEMORY;
+ }
+ if (flags & NI_NOFQDN) {
+ p = strchr(node,'.');
+ if (p) {
+ *p = '\0';
+ }
+ }
+ return 0;
+ }
+
+ if (flags & NI_NAMEREQD) {
+ /* If we require a name and didn't get one,
+ * automatically fail. */
+ return ret;
+ }
+ /* Otherwise just fall into the numeric host code... */
+ }
+ p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
+ ret = snprintf(node, nodelen, "%s", p);
+ if (ret < 0 || (size_t)ret >= nodelen) {
+ return EAI_MEMORY;
+ }
+ return 0;
+}
+
+static int getservicenameinfo(const struct sockaddr *sa,
+ char *service,
+ size_t servicelen,
+ int flags)
+{
+ int ret = -1;
+ int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+
+ if (!(flags & NI_NUMERICSERV)) {
+ struct servent *se = getservbyport(
+ port,
+ (flags & NI_DGRAM) ? "udp" : "tcp");
+ if (se && se->s_name) {
+ /* Service name looked up successfully. */
+ ret = snprintf(service, servicelen, "%s", se->s_name);
+ if (ret < 0 || (size_t)ret >= servicelen) {
+ return EAI_MEMORY;
+ }
+ return 0;
+ }
+ /* Otherwise just fall into the numeric service code... */
+ }
+ ret = snprintf(service, servicelen, "%d", port);
+ if (ret < 0 || (size_t)ret >= servicelen) {
+ return EAI_MEMORY;
+ }
+ return 0;
+}
+
+/*
+ * Convert an ipv4 address to a hostname.
+ *
+ * Bugs: - No IPv6 support.
+ */
+int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *node, size_t nodelen,
+ char *service, size_t servicelen, int flags)
+{
+
+ /* Invalid arguments. */
+ if (sa == NULL || (node == NULL && service == NULL)) {
+ return EAI_FAIL;
+ }
+
+ if (sa->sa_family != AF_INET) {
+ return EAI_FAIL;
+ }
+
+ if (salen < sizeof(struct sockaddr_in)) {
+ return EAI_FAIL;
+ }
+
+ if (node) {
+ return gethostnameinfo(sa, node, nodelen, flags);
+ }
+
+ if (service) {
+ return getservicenameinfo(sa, service, servicelen, flags);
+ }
+ return 0;
+}
diff --git a/lib/replace/getaddrinfo.h b/lib/replace/getaddrinfo.h
new file mode 100644
index 0000000..cf040da
--- /dev/null
+++ b/lib/replace/getaddrinfo.h
@@ -0,0 +1,91 @@
+/*
+PostgreSQL Database Management System
+(formerly known as Postgres, then as Postgres95)
+
+Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
+
+Portions Copyright (c) 1994, The Regents of the University of California
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose, without fee, and without a written agreement
+is hereby granted, provided that the above copyright notice and this paragraph
+and the following two paragraphs appear in all copies.
+
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
+EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+*/
+
+/*-------------------------------------------------------------------------
+ *
+ * getaddrinfo.h
+ * Support getaddrinfo() on platforms that don't have it.
+ *
+ * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO,
+ * whether or not the library routine getaddrinfo() can be found. This
+ * policy is needed because on some platforms a manually installed libbind.a
+ * may provide getaddrinfo(), yet the system headers may not provide the
+ * struct definitions needed to call it. To avoid conflict with the libbind
+ * definition in such cases, we rename our routines to pg_xxx() via macros.
+ *
+
+in lib/replace we use rep_xxx()
+
+ * This code will also work on platforms where struct addrinfo is defined
+ * in the system headers but no getaddrinfo() can be located.
+ *
+ * Copyright (c) 2003-2007, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef GETADDRINFO_H
+#define GETADDRINFO_H
+
+#ifndef HAVE_GETADDRINFO
+
+/* Rename private copies per comments above */
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo rep_getaddrinfo
+#define HAVE_GETADDRINFO
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo rep_freeaddrinfo
+#define HAVE_FREEADDRINFO
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror rep_gai_strerror
+#define HAVE_GAI_STRERROR
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo rep_getnameinfo
+#ifndef HAVE_GETNAMEINFO
+#define HAVE_GETNAMEINFO
+#endif
+
+extern int rep_getaddrinfo(const char *node, const char *service,
+ const struct addrinfo * hints, struct addrinfo ** res);
+extern void rep_freeaddrinfo(struct addrinfo * res);
+extern const char *rep_gai_strerror(int errcode);
+extern int rep_getnameinfo(const struct sockaddr * sa, socklen_t salen,
+ char *node, size_t nodelen,
+ char *service, size_t servicelen, int flags);
+#endif /* HAVE_GETADDRINFO */
+
+#endif /* GETADDRINFO_H */
diff --git a/lib/replace/getifaddrs.c b/lib/replace/getifaddrs.c
new file mode 100644
index 0000000..a55ef7e
--- /dev/null
+++ b/lib/replace/getifaddrs.c
@@ -0,0 +1,383 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifndef SIOCGIFCONF
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#endif
+
+#ifdef HAVE_IFACE_GETIFADDRS
+#define _FOUND_IFACE_ANY
+#else
+
+void rep_freeifaddrs(struct ifaddrs *ifp)
+{
+ if (ifp != NULL) {
+ free(ifp->ifa_name);
+ free(ifp->ifa_addr);
+ free(ifp->ifa_netmask);
+ free(ifp->ifa_dstaddr);
+ freeifaddrs(ifp->ifa_next);
+ free(ifp);
+ }
+}
+
+static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
+{
+ struct sockaddr *ret;
+ socklen_t socklen;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ socklen = sa->sa_len;
+#else
+ socklen = sizeof(struct sockaddr_storage);
+#endif
+ ret = calloc(1, socklen);
+ if (ret == NULL)
+ return NULL;
+ memcpy(ret, sa, socklen);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_IFACE_IFCONF
+
+/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
+ V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
+
+ It probably also works on any BSD style system. */
+
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ struct ifconf ifc;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
+
+ *ifap = NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ n = ifc.ifc_len / sizeof(struct ifreq);
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i=n-1; i>=0; i--) {
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
+ freeifaddrs(*ifap);
+ close(fd);
+ return -1;
+ }
+
+ curif = calloc(1, sizeof(struct ifaddrs));
+ if (curif == NULL) {
+ freeifaddrs(*ifap);
+ close(fd);
+ return -1;
+ }
+ curif->ifa_name = strdup(ifr[i].ifr_name);
+ if (curif->ifa_name == NULL) {
+ free(curif);
+ freeifaddrs(*ifap);
+ close(fd);
+ return -1;
+ }
+ curif->ifa_flags = ifr[i].ifr_flags;
+ curif->ifa_dstaddr = NULL;
+ curif->ifa_data = NULL;
+ curif->ifa_next = NULL;
+
+ curif->ifa_addr = NULL;
+ if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
+ curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
+ if (curif->ifa_addr == NULL) {
+ free(curif->ifa_name);
+ free(curif);
+ freeifaddrs(*ifap);
+ close(fd);
+ return -1;
+ }
+ }
+
+ curif->ifa_netmask = NULL;
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
+ curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
+ if (curif->ifa_netmask == NULL) {
+ if (curif->ifa_addr != NULL) {
+ free(curif->ifa_addr);
+ }
+ free(curif->ifa_name);
+ free(curif);
+ freeifaddrs(*ifap);
+ close(fd);
+ return -1;
+ }
+ }
+
+ if (lastif == NULL) {
+ *ifap = curif;
+ } else {
+ lastif->ifa_next = curif;
+ }
+ lastif = curif;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_IFCONF */
+#ifdef HAVE_IFACE_IFREQ
+
+#ifndef I_STR
+#include <sys/stropts.h>
+#endif
+
+/****************************************************************************
+this should cover most of the streams based systems
+Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
+****************************************************************************/
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ char buff[8192];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
+
+ *ifap = NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ strioctl.ic_cmd = SIOCGIFCONF;
+ strioctl.ic_dp = buff;
+ strioctl.ic_len = sizeof(buff);
+ if (ioctl(fd, I_STR, &strioctl) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ /* we can ignore the possible sizeof(int) here as the resulting
+ number of interface structures won't change */
+ n = strioctl.ic_len / sizeof(struct ifreq);
+
+ /* we will assume that the kernel returns the length as an int
+ at the start of the buffer if the offered size is a
+ multiple of the structure size plus an int */
+ if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
+ ifr = (struct ifreq *)(buff + sizeof(int));
+ } else {
+ ifr = (struct ifreq *)buff;
+ }
+
+ /* Loop through interfaces */
+
+ for (i = 0; i<n; i++) {
+ ifreq = ifr[i];
+
+ curif = calloc(1, sizeof(struct ifaddrs));
+ if (lastif == NULL) {
+ *ifap = curif;
+ } else {
+ lastif->ifa_next = curif;
+ }
+
+ strioctl.ic_cmd = SIOCGIFFLAGS;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ freeifaddrs(*ifap);
+ return -1;
+ }
+
+ curif->ifa_flags = ifreq.ifr_flags;
+
+ strioctl.ic_cmd = SIOCGIFADDR;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ freeifaddrs(*ifap);
+ return -1;
+ }
+
+ curif->ifa_name = strdup(ifreq.ifr_name);
+ curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
+ curif->ifa_dstaddr = NULL;
+ curif->ifa_data = NULL;
+ curif->ifa_next = NULL;
+ curif->ifa_netmask = NULL;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+ freeifaddrs(*ifap);
+ return -1;
+ }
+
+ curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
+
+ lastif = curif;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_IFREQ */
+#ifdef HAVE_IFACE_AIX
+
+/****************************************************************************
+this one is for AIX (tested on 4.2)
+****************************************************************************/
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ char buff[8192];
+ int fd, i;
+ struct ifconf ifc;
+ struct ifreq *ifr=NULL;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
+
+ *ifap = NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ /* Loop through interfaces */
+ i = ifc.ifc_len;
+
+ while (i > 0) {
+ unsigned int inc;
+
+ inc = ifr->ifr_addr.sa_len;
+
+ if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
+ freeaddrinfo(*ifap);
+ return -1;
+ }
+
+ curif = calloc(1, sizeof(struct ifaddrs));
+ if (lastif == NULL) {
+ *ifap = curif;
+ } else {
+ lastif->ifa_next = curif;
+ }
+
+ curif->ifa_name = strdup(ifr->ifr_name);
+ curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
+ curif->ifa_dstaddr = NULL;
+ curif->ifa_data = NULL;
+ curif->ifa_netmask = NULL;
+ curif->ifa_next = NULL;
+
+ if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
+ freeaddrinfo(*ifap);
+ return -1;
+ }
+
+ curif->ifa_flags = ifr->ifr_flags;
+
+ if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
+ freeaddrinfo(*ifap);
+ return -1;
+ }
+
+ curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
+
+ lastif = curif;
+
+ next:
+ /*
+ * Patch from Archie Cobbs (archie@whistle.com). The
+ * addresses in the SIOCGIFCONF interface list have a
+ * minimum size. Usually this doesn't matter, but if
+ * your machine has tunnel interfaces, etc. that have
+ * a zero length "link address", this does matter. */
+
+ if (inc < sizeof(ifr->ifr_addr))
+ inc = sizeof(ifr->ifr_addr);
+ inc += IFNAMSIZ;
+
+ ifr = (struct ifreq*) (((char*) ifr) + inc);
+ i -= inc;
+ }
+
+ close(fd);
+ return 0;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_AIX */
+#ifndef _FOUND_IFACE_ANY
+int rep_getifaddrs(struct ifaddrs **ifap)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
diff --git a/lib/replace/hdr_replace.h b/lib/replace/hdr_replace.h
new file mode 100644
index 0000000..6cfa50f
--- /dev/null
+++ b/lib/replace/hdr_replace.h
@@ -0,0 +1,2 @@
+/* this is a replacement header for a missing system header */
+#include "replace.h"
diff --git a/lib/replace/inet_aton.c b/lib/replace/inet_aton.c
new file mode 100644
index 0000000..c6b3bb1
--- /dev/null
+++ b/lib/replace/inet_aton.c
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * replacement functions
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+/**
+ * We know that we have inet_pton from earlier libreplace checks.
+ */
+int rep_inet_aton(const char *src, struct in_addr *dst)
+{
+ return (inet_pton(AF_INET, src, dst) > 0) ? 1 : 0;
+}
diff --git a/lib/replace/inet_ntoa.c b/lib/replace/inet_ntoa.c
new file mode 100644
index 0000000..e3b80eb
--- /dev/null
+++ b/lib/replace/inet_ntoa.c
@@ -0,0 +1,39 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * replacement routines for broken systems
+ * Copyright (C) Andrew Tridgell 2003
+ * Copyright (C) Michael Adam 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+/**
+ * NOTE: this is not thread safe, but it can't be, either
+ * since it returns a pointer to static memory.
+ */
+char *rep_inet_ntoa(struct in_addr ip)
+{
+ uint8_t *p = (uint8_t *)&ip.s_addr;
+ static char buf[18];
+ slprintf(buf, 17, "%d.%d.%d.%d",
+ (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+ return buf;
+}
diff --git a/lib/replace/inet_ntop.c b/lib/replace/inet_ntop.c
new file mode 100644
index 0000000..d6d4158
--- /dev/null
+++ b/lib/replace/inet_ntop.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include "replace.h"
+#include "system/network.h"
+
+#define NS_INT16SZ 2
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const unsigned char *src, char *dst,
+ socklen_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst,
+ socklen_t size);
+#endif
+
+/* char *
+ * isc_net_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+rep_inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * return:
+ * `dst' (as a const)
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, socklen_t size)
+{
+ char tmp[sizeof("255.255.255.255")];
+ size_t len;
+
+ len = snprintf(tmp,
+ sizeof(tmp),
+ "%hhu.%hhu.%hhu.%hhu",
+ src[0],
+ src[1],
+ src[2],
+ src[3]);
+ if (len >= size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ memcpy(dst, tmp, len + 1);
+
+ return (dst);
+}
+
+/* const char *
+ * isc_inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, socklen_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i, inc;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ inc = snprintf(tp, 5, "%x", words[i]);
+ if (inc >= 5) {
+ abort();
+ }
+ tp += inc;
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ memcpy(dst, tmp, tp - tmp);
+ return (dst);
+}
+#endif /* AF_INET6 */
diff --git a/lib/replace/inet_pton.c b/lib/replace/inet_pton.c
new file mode 100644
index 0000000..80e4865
--- /dev/null
+++ b/lib/replace/inet_pton.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef AF_INET6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+rep_inet_pton(int af,
+ const char *src,
+ void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+ const char *src;
+ unsigned char *dst;
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static int
+inet_pton6(src, dst)
+ const char *src;
+ unsigned char *dst;
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+#endif
diff --git a/lib/replace/poll.c b/lib/replace/poll.c
new file mode 100644
index 0000000..1105617
--- /dev/null
+++ b/lib/replace/poll.c
@@ -0,0 +1,139 @@
+/*
+ Unix SMB/CIFS implementation.
+ poll.c - poll wrapper
+
+ This file is based on code from libssh (LGPLv2.1+ at the time it
+ was downloaded), thus the following copyrights:
+
+ Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org>
+ Copyright (c) 2003-2009 by Aris Adamantiadis
+ Copyright (c) 2009 Aleksandar Kanchev
+ Copyright (C) Volker Lendecke 2011
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/select.h"
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+
+int rep_poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+ fd_set rfds, wfds, efds;
+ struct timeval tv, *ptv;
+ int max_fd;
+ int rc;
+ nfds_t i;
+
+ if ((fds == NULL) && (nfds != 0)) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+
+ rc = 0;
+ max_fd = 0;
+
+ /* compute fd_sets and find largest descriptor */
+ for (i = 0; i < nfds; i++) {
+ if ((fds[i].fd < 0) || (fds[i].fd >= FD_SETSIZE)) {
+ fds[i].revents = POLLNVAL;
+ continue;
+ }
+
+ if (fds[i].events & (POLLIN | POLLRDNORM)) {
+ FD_SET(fds[i].fd, &rfds);
+ }
+ if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
+ FD_SET(fds[i].fd, &wfds);
+ }
+ if (fds[i].events & (POLLPRI | POLLRDBAND)) {
+ FD_SET(fds[i].fd, &efds);
+ }
+ if (fds[i].fd > max_fd &&
+ (fds[i].events & (POLLIN | POLLOUT | POLLPRI |
+ POLLRDNORM | POLLRDBAND |
+ POLLWRNORM | POLLWRBAND))) {
+ max_fd = fds[i].fd;
+ }
+ }
+
+ if (timeout < 0) {
+ ptv = NULL;
+ } else {
+ ptv = &tv;
+ if (timeout == 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ } else {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ }
+ }
+
+ rc = select(max_fd + 1, &rfds, &wfds, &efds, ptv);
+ if (rc < 0) {
+ return -1;
+ }
+
+ for (rc = 0, i = 0; i < nfds; i++) {
+ if ((fds[i].fd < 0) || (fds[i].fd >= FD_SETSIZE)) {
+ continue;
+ }
+
+ fds[i].revents = 0;
+
+ if (FD_ISSET(fds[i].fd, &rfds)) {
+ int err = errno;
+ int available = 0;
+ int ret;
+
+ /* support for POLLHUP */
+ ret = ioctl(fds[i].fd, FIONREAD, &available);
+ if ((ret == -1) || (available == 0)) {
+ fds[i].revents |= POLLHUP;
+ } else {
+ fds[i].revents |= fds[i].events
+ & (POLLIN | POLLRDNORM);
+ }
+
+ errno = err;
+ }
+ if (FD_ISSET(fds[i].fd, &wfds)) {
+ fds[i].revents |= fds[i].events
+ & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ }
+ if (FD_ISSET(fds[i].fd, &efds)) {
+ fds[i].revents |= fds[i].events
+ & (POLLPRI | POLLRDBAND);
+ }
+ if (fds[i].revents & ~POLLHUP) {
+ rc++;
+ }
+ }
+ return rc;
+}
diff --git a/lib/replace/replace-test.h b/lib/replace/replace-test.h
new file mode 100644
index 0000000..ed8e75e
--- /dev/null
+++ b/lib/replace/replace-test.h
@@ -0,0 +1,9 @@
+#ifndef __LIB_REPLACE_REPLACE_TEST_H__
+#define __LIB_REPLACE_REPLACE_TEST_H__
+
+int libreplace_test_strptime(void);
+int test_readdir_os2_delete(void);
+int getifaddrs_test(void);
+
+#endif /* __LIB_REPLACE_REPLACE_TEST_H__ */
+
diff --git a/lib/replace/replace-testsuite.h b/lib/replace/replace-testsuite.h
new file mode 100644
index 0000000..b28dbec
--- /dev/null
+++ b/lib/replace/replace-testsuite.h
@@ -0,0 +1,10 @@
+#ifndef __LIB_REPLACE_REPLACE_TESTSUITE_H__
+#define __LIB_REPLACE_REPLACE_TESTSUITE_H__
+
+#include <stdbool.h>
+struct torture_context;
+
+bool torture_local_replace(struct torture_context *ctx);
+
+#endif /* __LIB_REPLACE_REPLACE_TESTSUITE_H__ */
+
diff --git a/lib/replace/replace.c b/lib/replace/replace.c
new file mode 100644
index 0000000..68829f2
--- /dev/null
+++ b/lib/replace/replace.c
@@ -0,0 +1,1145 @@
+/*
+ Unix SMB/CIFS implementation.
+ replacement routines for broken systems
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jelmer Vernooij 2005-2008
+ Copyright (C) Matthieu Patou 2010
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/network.h"
+#include "system/passwd.h"
+#include "system/syslog.h"
+#include "system/locale.h"
+#include "system/wait.h"
+
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
+
+#ifdef _WIN32
+#define mkdir(d,m) _mkdir(d)
+#endif
+
+void replace_dummy(void);
+void replace_dummy(void) {}
+
+#ifndef HAVE_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+int rep_ftruncate(int f, off_t l)
+{
+#ifdef HAVE_CHSIZE
+ return chsize(f,l);
+#elif defined(F_FREESP)
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = l;
+ fl.l_type = F_WRLCK;
+ return fcntl(f, F_FREESP, &fl);
+#else
+#error "you must have a ftruncate function"
+#endif
+}
+#endif /* HAVE_FTRUNCATE */
+
+
+#ifndef HAVE_STRLCPY
+/*
+ * Like strncpy but does not 0 fill the buffer and always null
+ * terminates. bufsize is the size of the destination buffer.
+ * Returns the length of s.
+ */
+size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
+{
+ size_t len = strlen(s);
+ size_t ret = len;
+
+ if (bufsize <= 0) {
+ return 0;
+ }
+ if (len >= bufsize) {
+ len = bufsize - 1;
+ }
+ memcpy(d, s, len);
+ d[len] = 0;
+ return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/* like strncat but does not 0 fill the buffer and always null
+ terminates. bufsize is the length of the buffer, which should
+ be one more than the maximum resulting string length */
+size_t rep_strlcat(char *d, const char *s, size_t bufsize)
+{
+ size_t len1 = strnlen(d, bufsize);
+ size_t len2 = strlen(s);
+ size_t ret = len1 + len2;
+
+ if (len1+len2 >= bufsize) {
+ if (bufsize < (len1+1)) {
+ return ret;
+ }
+ len2 = bufsize - (len1+1);
+ }
+ if (len2 > 0) {
+ memcpy(d+len1, s, len2);
+ d[len1+len2] = 0;
+ }
+ return ret;
+}
+#endif
+
+#ifndef HAVE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by
+C.A. Lademann <cal@zls.com>
+Corrections by richard.kettlewell@kewill.com
+********************************************************************/
+
+#define MINUTE 60
+#define HOUR 60*MINUTE
+#define DAY 24*HOUR
+#define YEAR 365*DAY
+time_t rep_mktime(struct tm *t)
+{
+ struct tm *u;
+ time_t epoch = 0;
+ int n;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ y, m, i;
+
+ if(t->tm_year < 70)
+ return((time_t)-1);
+
+ n = t->tm_year + 1900 - 1;
+ epoch = (t->tm_year - 70) * YEAR +
+ ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
+
+ y = t->tm_year + 1900;
+ m = 0;
+
+ for(i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+ epoch += DAY;
+
+ if(++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ if((u = localtime(&epoch)) != NULL) {
+ t->tm_sec = u->tm_sec;
+ t->tm_min = u->tm_min;
+ t->tm_hour = u->tm_hour;
+ t->tm_mday = u->tm_mday;
+ t->tm_mon = u->tm_mon;
+ t->tm_year = u->tm_year;
+ t->tm_wday = u->tm_wday;
+ t->tm_yday = u->tm_yday;
+ t->tm_isdst = u->tm_isdst;
+ }
+
+ return(epoch);
+}
+#endif /* !HAVE_MKTIME */
+
+
+#ifndef HAVE_INITGROUPS
+/****************************************************************************
+ some systems don't have an initgroups call
+****************************************************************************/
+int rep_initgroups(char *name, gid_t id)
+{
+#ifndef HAVE_SETGROUPS
+ /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+ errno = ENOSYS;
+ return -1;
+#else /* HAVE_SETGROUPS */
+
+#include <grp.h>
+
+ gid_t *grouplst = NULL;
+ int max_gr = NGROUPS_MAX;
+ int ret;
+ int i,j;
+ struct group *g;
+ char *gr;
+
+ if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ grouplst[0] = id;
+ i = 1;
+ while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
+ if (g->gr_gid == id)
+ continue;
+ j = 0;
+ gr = g->gr_mem[0];
+ while (gr && (*gr != (char)NULL)) {
+ if (strcmp(name,gr) == 0) {
+ grouplst[i] = g->gr_gid;
+ i++;
+ gr = (char *)NULL;
+ break;
+ }
+ gr = g->gr_mem[++j];
+ }
+ }
+ endgrent();
+ ret = setgroups(i, grouplst);
+ free(grouplst);
+ return ret;
+#endif /* HAVE_SETGROUPS */
+}
+#endif /* HAVE_INITGROUPS */
+
+
+#ifndef HAVE_MEMMOVE
+/*******************************************************************
+safely copies memory, ensuring no overlap problems.
+this is only used if the machine does not have its own memmove().
+this is not the fastest algorithm in town, but it will do for our
+needs.
+********************************************************************/
+void *rep_memmove(void *dest,const void *src,int size)
+{
+ unsigned long d,s;
+ int i;
+ if (dest==src || !size) return(dest);
+
+ d = (unsigned long)dest;
+ s = (unsigned long)src;
+
+ if ((d >= (s+size)) || (s >= (d+size))) {
+ /* no overlap */
+ memcpy(dest,src,size);
+ return(dest);
+ }
+
+ if (d < s) {
+ /* we can forward copy */
+ if (s-d >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=0;i<size;i++) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=0;i<size;i++) cdest[i] = csrc[i];
+ }
+ } else {
+ /* must backward copy */
+ if (d-s >= sizeof(int) &&
+ !(s%sizeof(int)) &&
+ !(d%sizeof(int)) &&
+ !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=size-1;i>=0;i--) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
+ }
+ }
+ return(dest);
+}
+#endif /* HAVE_MEMMOVE */
+
+#ifndef HAVE_STRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+char *rep_strdup(const char *s)
+{
+ size_t len;
+ char *ret;
+
+ if (!s) return(NULL);
+
+ len = strlen(s)+1;
+ ret = (char *)malloc(len);
+ if (!ret) return(NULL);
+ memcpy(ret,s,len);
+ return(ret);
+}
+#endif /* HAVE_STRDUP */
+
+#ifndef HAVE_SETLINEBUF
+void rep_setlinebuf(FILE *stream)
+{
+ setvbuf(stream, (char *)NULL, _IOLBF, 0);
+}
+#endif /* HAVE_SETLINEBUF */
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
+{
+ char *msg = NULL;
+ vasprintf(&msg, format, arglist);
+ if (!msg)
+ return;
+ syslog(facility_priority, "%s", msg);
+ free(msg);
+}
+#endif /* HAVE_SYSLOG */
+#endif /* HAVE_VSYSLOG */
+
+#ifndef HAVE_STRNLEN
+/**
+ Some platforms don't have strnlen
+**/
+ size_t rep_strnlen(const char *s, size_t max)
+{
+ size_t len;
+
+ for (len = 0; len < max; len++) {
+ if (s[len] == '\0') {
+ break;
+ }
+ }
+ return len;
+}
+#endif
+
+#ifndef HAVE_STRNDUP
+/**
+ Some platforms don't have strndup.
+**/
+char *rep_strndup(const char *s, size_t n)
+{
+ char *ret;
+
+ n = strnlen(s, n);
+ ret = malloc(n+1);
+ if (!ret)
+ return NULL;
+ memcpy(ret, s, n);
+ ret[n] = 0;
+
+ return ret;
+}
+#endif
+
+#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
+int rep_waitpid(pid_t pid,int *status,int options)
+{
+ return wait4(pid, status, options, NULL);
+}
+#endif
+
+#ifndef HAVE_SETEUID
+int rep_seteuid(uid_t euid)
+{
+#ifdef HAVE_SETRESUID
+ return setresuid(-1, euid, -1);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif
+
+#ifndef HAVE_SETEGID
+int rep_setegid(gid_t egid)
+{
+#ifdef HAVE_SETRESGID
+ return setresgid(-1, egid, -1);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif
+
+/*******************************************************************
+os/2 also doesn't have chroot
+********************************************************************/
+#ifndef HAVE_CHROOT
+int rep_chroot(const char *dname)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+/*****************************************************************
+ Possibly replace mkstemp if it is broken.
+*****************************************************************/
+
+#ifndef HAVE_SECURE_MKSTEMP
+int rep_mkstemp(char *template)
+{
+ /* have a reasonable go at emulating it. Hope that
+ the system mktemp() isn't completely hopeless */
+ mktemp(template);
+ if (template[0] == 0)
+ return -1;
+ return open(template, O_CREAT|O_EXCL|O_RDWR, 0600);
+}
+#endif
+
+#ifndef HAVE_MKDTEMP
+char *rep_mkdtemp(char *template)
+{
+ char *dname;
+
+ if ((dname = mktemp(template))) {
+ if (mkdir(dname, 0700) >= 0) {
+ return dname;
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
+
+#ifndef HAVE_PREAD
+ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
+{
+ if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+ return -1;
+ }
+ return read(__fd, __buf, __nbytes);
+}
+#endif
+
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
+
+#ifndef HAVE_PWRITE
+ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
+{
+ if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+ return -1;
+ }
+ return write(__fd, __buf, __nbytes);
+}
+#endif
+
+#ifndef HAVE_STRCASESTR
+char *rep_strcasestr(const char *haystack, const char *needle)
+{
+ const char *s;
+ size_t nlen = strlen(needle);
+ for (s=haystack;*s;s++) {
+ if (toupper(*needle) == toupper(*s) &&
+ strncasecmp(s, needle, nlen) == 0) {
+ return (char *)((uintptr_t)s);
+ }
+ }
+ return NULL;
+}
+#endif
+
+#ifndef HAVE_STRSEP
+char *rep_strsep(char **pps, const char *delim)
+{
+ char *ret = *pps;
+ char *p = *pps;
+
+ if (p == NULL) {
+ return NULL;
+ }
+ p += strcspn(p, delim);
+ if (*p == '\0') {
+ *pps = NULL;
+ } else {
+ *p = '\0';
+ *pps = p + 1;
+ }
+ return ret;
+}
+#endif
+
+#ifndef HAVE_STRTOK_R
+/* based on GLIBC version, copyright Free Software Foundation */
+char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
+{
+ char *token;
+
+ if (s == NULL) s = *save_ptr;
+
+ s += strspn(s, delim);
+ if (*s == '\0') {
+ *save_ptr = s;
+ return NULL;
+ }
+
+ token = s;
+ s = strpbrk(token, delim);
+ if (s == NULL) {
+ *save_ptr = token + strlen(token);
+ } else {
+ *s = '\0';
+ *save_ptr = s + 1;
+ }
+
+ return token;
+}
+#endif
+
+
+#ifndef HAVE_STRTOLL
+long long int rep_strtoll(const char *str, char **endptr, int base)
+{
+#ifdef HAVE_STRTOQ
+ return strtoq(str, endptr, base);
+#elif defined(HAVE___STRTOLL)
+ return __strtoll(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+ return (long long int) strtol(str, endptr, base);
+#else
+# error "You need a strtoll function"
+#endif
+}
+#else
+#ifdef HAVE_BSD_STRTOLL
+#undef strtoll
+long long int rep_strtoll(const char *str, char **endptr, int base)
+{
+ int saved_errno = errno;
+ long long int nb = strtoll(str, endptr, base);
+ /* With glibc EINVAL is only returned if base is not ok */
+ if (errno == EINVAL) {
+ if (base == 0 || (base >1 && base <37)) {
+ /* Base was ok so it's because we were not
+ * able to make the conversion.
+ * Let's reset errno.
+ */
+ errno = saved_errno;
+ }
+ }
+ return nb;
+}
+#endif /* HAVE_BSD_STRTOLL */
+#endif /* HAVE_STRTOLL */
+
+
+#ifndef HAVE_STRTOULL
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
+{
+#ifdef HAVE_STRTOUQ
+ return strtouq(str, endptr, base);
+#elif defined(HAVE___STRTOULL)
+ return __strtoull(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+ return (unsigned long long int) strtoul(str, endptr, base);
+#else
+# error "You need a strtoull function"
+#endif
+}
+#else
+#ifdef HAVE_BSD_STRTOLL
+#undef strtoull
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
+{
+ int saved_errno = errno;
+ unsigned long long int nb = strtoull(str, endptr, base);
+ /* With glibc EINVAL is only returned if base is not ok */
+ if (errno == EINVAL) {
+ if (base == 0 || (base >1 && base <37)) {
+ /* Base was ok so it's because we were not
+ * able to make the conversion.
+ * Let's reset errno.
+ */
+ errno = saved_errno;
+ }
+ }
+ return nb;
+}
+#endif /* HAVE_BSD_STRTOLL */
+#endif /* HAVE_STRTOULL */
+
+#ifndef HAVE_SETENV
+int rep_setenv(const char *name, const char *value, int overwrite)
+{
+ char *p;
+ size_t l1, l2;
+ int ret;
+
+ if (!overwrite && getenv(name)) {
+ return 0;
+ }
+
+ l1 = strlen(name);
+ l2 = strlen(value);
+
+ p = malloc(l1+l2+2);
+ if (p == NULL) {
+ return -1;
+ }
+ memcpy(p, name, l1);
+ p[l1] = '=';
+ memcpy(p+l1+1, value, l2);
+ p[l1+l2+1] = 0;
+
+ ret = putenv(p);
+ if (ret != 0) {
+ free(p);
+ }
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_UNSETENV
+int rep_unsetenv(const char *name)
+{
+ extern char **environ;
+ size_t len = strlen(name);
+ size_t i, count;
+
+ if (environ == NULL || getenv(name) == NULL) {
+ return 0;
+ }
+
+ for (i=0;environ[i];i++) /* noop */ ;
+
+ count=i;
+
+ for (i=0;i<count;) {
+ if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
+ /* note: we do _not_ free the old variable here. It is unsafe to
+ do so, as the pointer may not have come from malloc */
+ memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
+ count--;
+ } else {
+ i++;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef HAVE_UTIME
+int rep_utime(const char *filename, const struct utimbuf *buf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_UTIMES
+int rep_utimes(const char *filename, const struct timeval tv[2])
+{
+ struct utimbuf u;
+
+ u.actime = tv[0].tv_sec;
+ if (tv[0].tv_usec > 500000) {
+ u.actime += 1;
+ }
+
+ u.modtime = tv[1].tv_sec;
+ if (tv[1].tv_usec > 500000) {
+ u.modtime += 1;
+ }
+
+ return utime(filename, &u);
+}
+#endif
+
+#ifndef HAVE_DUP2
+int rep_dup2(int oldfd, int newfd)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_CHOWN
+/**
+chown isn't used much but OS/2 doesn't have it
+**/
+int rep_chown(const char *fname, uid_t uid, gid_t gid)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_LINK
+int rep_link(const char *oldpath, const char *newpath)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_READLINK
+int rep_readlink(const char *path, char *buf, size_t bufsiz)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_SYMLINK
+int rep_symlink(const char *oldpath, const char *newpath)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_LCHOWN
+int rep_lchown(const char *fname,uid_t uid,gid_t gid)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_REALPATH
+char *rep_realpath(const char *path, char *resolved_path)
+{
+ /* As realpath is not a system call we can't return ENOSYS. */
+ errno = EINVAL;
+ return NULL;
+}
+#endif
+
+
+#ifndef HAVE_MEMMEM
+void *rep_memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ if (needlelen == 0) {
+ return discard_const(haystack);
+ }
+ while (haystacklen >= needlelen) {
+ char *p = (char *)memchr(haystack, *(const char *)needle,
+ haystacklen-(needlelen-1));
+ if (!p) return NULL;
+ if (memcmp(p, needle, needlelen) == 0) {
+ return p;
+ }
+ haystack = p+1;
+ haystacklen -= (p - (const char *)haystack) + 1;
+ }
+ return NULL;
+}
+#endif
+
+#if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+int rep_vdprintf(int fd, const char *format, va_list ap)
+{
+ char *s = NULL;
+ int ret;
+
+ vasprintf(&s, format, ap);
+ if (s == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ ret = write(fd, s, strlen(s));
+ free(s);
+ return ret;
+}
+#endif
+
+#if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+int rep_dprintf(int fd, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, format);
+ ret = vdprintf(fd, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_GET_CURRENT_DIR_NAME
+char *rep_get_current_dir_name(void)
+{
+ char buf[PATH_MAX+1];
+ char *p;
+ p = getcwd(buf, sizeof(buf));
+ if (p == NULL) {
+ return NULL;
+ }
+ return strdup(p);
+}
+#endif
+
+#ifndef HAVE_STRERROR_R
+int rep_strerror_r(int errnum, char *buf, size_t buflen)
+{
+ char *s = strerror(errnum);
+ if (strlen(s)+1 > buflen) {
+ errno = ERANGE;
+ return -1;
+ }
+ strncpy(buf, s, buflen);
+ return 0;
+}
+#elif (!defined(STRERROR_R_XSI_NOT_GNU))
+#undef strerror_r
+int rep_strerror_r(int errnum, char *buf, size_t buflen)
+{
+ char *s = strerror_r(errnum, buf, buflen);
+ if (s == NULL) {
+ /* Shouldn't happen, should always get a string */
+ return EINVAL;
+ }
+ if (s != buf) {
+ strlcpy(buf, s, buflen);
+ if (strlen(s) > buflen - 1) {
+ return ERANGE;
+ }
+ }
+ return 0;
+
+}
+#endif
+
+#ifndef HAVE_CLOCK_GETTIME
+int rep_clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+ struct timeval tval;
+ switch (clk_id) {
+ case 0: /* CLOCK_REALTIME :*/
+#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
+ gettimeofday(&tval,NULL);
+#else
+ gettimeofday(&tval);
+#endif
+ tp->tv_sec = tval.tv_sec;
+ tp->tv_nsec = tval.tv_usec * 1000;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#ifndef HAVE_MEMALIGN
+void *rep_memalign( size_t align, size_t size )
+{
+#if defined(HAVE_POSIX_MEMALIGN)
+ void *p = NULL;
+ int ret = posix_memalign( &p, align, size );
+ if ( ret == 0 )
+ return p;
+
+ return NULL;
+#else
+ /* On *BSD systems memaligns doesn't exist, but memory will
+ * be aligned on allocations of > pagesize. */
+#if defined(SYSCONF_SC_PAGESIZE)
+ size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+ size_t pagesize = (size_t)getpagesize();
+#else
+ size_t pagesize = (size_t)-1;
+#endif
+ if (pagesize == (size_t)-1) {
+ errno = ENOSYS;
+ return NULL;
+ }
+ if (size < pagesize) {
+ size = pagesize;
+ }
+ return malloc(size);
+#endif
+}
+#endif
+
+#ifndef HAVE_GETPEEREID
+int rep_getpeereid(int s, uid_t *uid, gid_t *gid)
+{
+#if defined(HAVE_PEERCRED)
+ struct ucred cred;
+ socklen_t cred_len = sizeof(struct ucred);
+ int ret;
+
+#undef getsockopt
+ ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
+ if (ret != 0) {
+ return -1;
+ }
+
+ if (cred_len != sizeof(struct ucred)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *uid = cred.uid;
+ *gid = cred.gid;
+ return 0;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif
+
+#ifndef HAVE_USLEEP
+int rep_usleep(useconds_t sec)
+{
+ struct timeval tval;
+ /*
+ * Fake it with select...
+ */
+ tval.tv_sec = 0;
+ tval.tv_usec = usecs/1000;
+ select(0,NULL,NULL,NULL,&tval);
+ return 0;
+}
+#endif /* HAVE_USLEEP */
+
+#ifndef HAVE_SETPROCTITLE
+void rep_setproctitle(const char *fmt, ...)
+{
+}
+#endif
+#ifndef HAVE_SETPROCTITLE_INIT
+void rep_setproctitle_init(int argc, char *argv[], char *envp[])
+{
+}
+#endif
+
+#ifndef HAVE_MEMSET_S
+# ifndef RSIZE_MAX
+# define RSIZE_MAX (SIZE_MAX >> 1)
+# endif
+
+int rep_memset_s(void *dest, size_t destsz, int ch, size_t count)
+{
+ if (dest == NULL) {
+ return EINVAL;
+ }
+
+ if (destsz > RSIZE_MAX ||
+ count > RSIZE_MAX ||
+ count > destsz) {
+ return ERANGE;
+ }
+
+#if defined(HAVE_MEMSET_EXPLICIT)
+ memset_explicit(dest, destsz, ch, count);
+#else /* HAVE_MEMSET_EXPLICIT */
+ memset(dest, ch, count);
+# if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
+ /* See http://llvm.org/bugs/show_bug.cgi?id=15495 */
+ __asm__ volatile("" : : "g"(dest) : "memory");
+# endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
+#endif /* HAVE_MEMSET_EXPLICIT */
+
+ return 0;
+}
+#endif /* HAVE_MEMSET_S */
+
+#ifndef HAVE_GETPROGNAME
+# ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
+# define PROGNAME_SIZE 32
+static char rep_progname[PROGNAME_SIZE];
+# endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
+
+const char *rep_getprogname(void)
+{
+#ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME
+ return program_invocation_short_name;
+#else /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
+ FILE *fp = NULL;
+ char cmdline[4096] = {0};
+ char *p = NULL;
+ pid_t pid;
+ size_t nread;
+ int len;
+ int rc;
+
+ if (rep_progname[0] != '\0') {
+ return rep_progname;
+ }
+
+ len = snprintf(rep_progname, sizeof(rep_progname), "%s", "<unknown>");
+ if (len <= 0) {
+ return NULL;
+ }
+
+ pid = getpid();
+ if (pid <= 1 || pid == (pid_t)-1) {
+ return NULL;
+ }
+
+ len = snprintf(cmdline,
+ sizeof(cmdline),
+ "/proc/%u/cmdline",
+ (unsigned int)pid);
+ if (len <= 0 || len == sizeof(cmdline)) {
+ return NULL;
+ }
+
+ fp = fopen(cmdline, "r");
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ nread = fread(cmdline, 1, sizeof(cmdline) - 1, fp);
+
+ rc = fclose(fp);
+ if (rc != 0) {
+ return NULL;
+ }
+
+ if (nread == 0) {
+ return NULL;
+ }
+
+ cmdline[nread] = '\0';
+
+ p = strrchr(cmdline, '/');
+ if (p != NULL) {
+ p++;
+ } else {
+ p = cmdline;
+ }
+
+ len = strlen(p);
+ if (len > PROGNAME_SIZE) {
+ p[PROGNAME_SIZE - 1] = '\0';
+ }
+
+ (void)snprintf(rep_progname, sizeof(rep_progname), "%s", p);
+
+ return rep_progname;
+#endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
+}
+#endif /* HAVE_GETPROGNAME */
+
+#ifndef HAVE_COPY_FILE_RANGE
+ssize_t rep_copy_file_range(int fd_in,
+ loff_t *off_in,
+ int fd_out,
+ loff_t *off_out,
+ size_t len,
+ unsigned int flags)
+{
+# ifdef HAVE_SYSCALL_COPY_FILE_RANGE
+ return syscall(__NR_copy_file_range,
+ fd_in,
+ off_in,
+ fd_out,
+ off_out,
+ len,
+ flags);
+# endif /* HAVE_SYSCALL_COPY_FILE_RANGE */
+ errno = ENOSYS;
+ return -1;
+}
+#endif /* HAVE_COPY_FILE_RANGE */
+
+#ifndef HAVE_OPENAT2
+
+/* fallback known wellknown __NR_openat2 values */
+#ifndef __NR_openat2
+# if defined(LINUX) && defined(HAVE_SYS_SYSCALL_H)
+# if defined(__i386__)
+# define __NR_openat2 437
+# elif defined(__x86_64__) && defined(__LP64__)
+# define __NR_openat2 437 /* 437 0x1B5 */
+# elif defined(__x86_64__) && defined(__ILP32__)
+# define __NR_openat2 1073742261 /* 1073742261 0x400001B5 */
+# elif defined(__aarch64__)
+# define __NR_openat2 437
+# elif defined(__arm__)
+# define __NR_openat2 437
+# elif defined(__sparc__)
+# define __NR_openat2 437
+# endif
+# endif /* defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) */
+#endif /* !__NR_openat2 */
+
+#ifdef DISABLE_OPATH
+/*
+ * systems without O_PATH also don't have openat2,
+ * so make sure we at a realistic combination.
+ */
+#undef __NR_openat2
+#endif /* DISABLE_OPATH */
+
+long rep_openat2(int dirfd, const char *pathname,
+ struct open_how *how, size_t size)
+{
+#ifdef __NR_openat2
+#if _FILE_OFFSET_BITS == 64 && SIZE_MAX == 0xffffffffUL && defined(O_LARGEFILE)
+ struct open_how __how;
+
+#if defined(O_PATH) && ! defined(DISABLE_OPATH)
+ if ((how->flags & O_PATH) == 0)
+#endif
+ {
+ if (sizeof(__how) == size) {
+ __how = *how;
+
+ __how.flags |= O_LARGEFILE;
+ how = &__how;
+ }
+ }
+#endif
+
+ return syscall(__NR_openat2,
+ dirfd,
+ pathname,
+ how,
+ size);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif /* !HAVE_OPENAT2 */
diff --git a/lib/replace/replace.h b/lib/replace/replace.h
new file mode 100644
index 0000000..a6a2b40
--- /dev/null
+++ b/lib/replace/replace.h
@@ -0,0 +1,1112 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ macros to go along with the lib/replace/ portability layer code
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2006-2008
+ Copyright (C) Jeremy Allison 2007.
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LIBREPLACE_REPLACE_H
+#define _LIBREPLACE_REPLACE_H
+
+#ifndef NO_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STANDARDS_H
+#include <standards.h>
+#endif
+
+/*
+ * Needs to be defined before std*.h and string*.h are included
+ * As it's also needed when Python.h is the first header we
+ * require a global -D__STDC_WANT_LIB_EXT1__=1
+ */
+#if __STDC_WANT_LIB_EXT1__ != 1
+#error -D__STDC_WANT_LIB_EXT1__=1 required
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#ifndef HAVE_DECL_EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include "win32_replace.h"
+#endif
+
+
+#ifdef HAVE_INTTYPES_H
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+/* force off HAVE_INTTYPES_H so that roken doesn't try to include both,
+ which causes a warning storm on irix */
+#undef HAVE_INTTYPES_H
+#endif
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifndef __PRI64_PREFIX
+# if __WORDSIZE == 64 && ! defined __APPLE__
+# define __PRI64_PREFIX "l"
+# else
+# define __PRI64_PREFIX "ll"
+# endif
+#endif
+
+/* Decimal notation. */
+#ifndef PRId8
+# define PRId8 "d"
+#endif
+#ifndef PRId16
+# define PRId16 "d"
+#endif
+#ifndef PRId32
+# define PRId32 "d"
+#endif
+#ifndef PRId64
+# define PRId64 __PRI64_PREFIX "d"
+#endif
+
+#ifndef PRIi8
+# define PRIi8 "i"
+#endif
+#ifndef PRIi16
+# define PRIi16 "i"
+#endif
+#ifndef PRIi32
+# define PRIi32 "i"
+#endif
+#ifndef PRIi64
+# define PRIi64 __PRI64_PREFIX "i"
+#endif
+
+#ifndef PRIu8
+# define PRIu8 "u"
+#endif
+#ifndef PRIu16
+# define PRIu16 "u"
+#endif
+#ifndef PRIu32
+# define PRIu32 "u"
+#endif
+#ifndef PRIu64
+# define PRIu64 __PRI64_PREFIX "u"
+#endif
+
+#ifndef SCNd8
+# define SCNd8 "hhd"
+#endif
+#ifndef SCNd16
+# define SCNd16 "hd"
+#endif
+#ifndef SCNd32
+# define SCNd32 "d"
+#endif
+#ifndef SCNd64
+# define SCNd64 __PRI64_PREFIX "d"
+#endif
+
+#ifndef SCNi8
+# define SCNi8 "hhi"
+#endif
+#ifndef SCNi16
+# define SCNi16 "hi"
+#endif
+#ifndef SCNi32
+# define SCNi32 "i"
+#endif
+#ifndef SCNi64
+# define SCNi64 __PRI64_PREFIX "i"
+#endif
+
+#ifndef SCNu8
+# define SCNu8 "hhu"
+#endif
+#ifndef SCNu16
+# define SCNu16 "hu"
+#endif
+#ifndef SCNu32
+# define SCNu32 "u"
+#endif
+#ifndef SCNu64
+# define SCNu64 __PRI64_PREFIX "u"
+#endif
+
+#ifdef HAVE_BSD_STRING_H
+#include <bsd/string.h>
+#endif
+
+#ifdef HAVE_BSD_UNISTD_H
+#include <bsd/unistd.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
+
+#ifdef HAVE_SETPROCTITLE_H
+#include <setproctitle.h>
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_LINUX_TYPES_H
+/*
+ * This is needed as some broken header files require this to be included early
+ */
+#include <linux/types.h>
+#endif
+
+#ifndef HAVE_STRERROR
+extern const char *const sys_errlist[];
+#define strerror(i) sys_errlist[i]
+#endif
+
+#ifndef HAVE_ERRNO_DECL
+extern int errno;
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup rep_strdup
+char *rep_strdup(const char *s);
+#endif
+
+#ifndef HAVE_MEMMOVE
+#define memmove rep_memmove
+void *rep_memmove(void *dest,const void *src,int size);
+#endif
+
+#ifndef HAVE_MEMMEM
+#define memmem rep_memmem
+void *rep_memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+#endif
+
+#ifndef HAVE_MEMALIGN
+#define memalign rep_memalign
+void *rep_memalign(size_t boundary, size_t size);
+#endif
+
+#ifndef HAVE_MKTIME
+#define mktime rep_mktime
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_TIMEGM
+#define timegm rep_timegm
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_UTIME
+#define utime rep_utime
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_UTIMES
+#define utimes rep_utimes
+/* prototype is in "system/time.h" */
+#endif
+
+#ifndef HAVE_STRLCPY
+#define strlcpy rep_strlcpy
+size_t rep_strlcpy(char *d, const char *s, size_t bufsize);
+#endif
+
+#ifndef HAVE_STRLCAT
+#define strlcat rep_strlcat
+size_t rep_strlcat(char *d, const char *s, size_t bufsize);
+#endif
+
+#ifndef HAVE_CLOSEFROM
+#define closefrom rep_closefrom
+int rep_closefrom(int lower);
+#endif
+
+
+#if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP))
+#undef HAVE_STRNDUP
+#define strndup rep_strndup
+char *rep_strndup(const char *s, size_t n);
+#endif
+
+#if (defined(BROKEN_STRNLEN) || !defined(HAVE_STRNLEN))
+#undef HAVE_STRNLEN
+#define strnlen rep_strnlen
+size_t rep_strnlen(const char *s, size_t n);
+#endif
+
+#if !defined(HAVE_DECL_ENVIRON)
+# ifdef __APPLE__
+# include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+# else /* __APPLE__ */
+extern char **environ;
+# endif /* __APPLE */
+#endif /* !defined(HAVE_DECL_ENVIRON) */
+
+#ifndef HAVE_SETENV
+#define setenv rep_setenv
+int rep_setenv(const char *name, const char *value, int overwrite);
+#else
+#ifndef HAVE_SETENV_DECL
+int setenv(const char *name, const char *value, int overwrite);
+#endif
+#endif
+
+#ifndef HAVE_UNSETENV
+#define unsetenv rep_unsetenv
+int rep_unsetenv(const char *name);
+#endif
+
+#ifndef HAVE_SETEUID
+#define seteuid rep_seteuid
+int rep_seteuid(uid_t);
+#endif
+
+#ifndef HAVE_SETEGID
+#define setegid rep_setegid
+int rep_setegid(gid_t);
+#endif
+
+#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESUID_DECL))
+/* stupid glibc */
+int setresuid(uid_t ruid, uid_t euid, uid_t suid);
+#endif
+#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESGID_DECL))
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+#endif
+
+#ifndef HAVE_CHOWN
+#define chown rep_chown
+int rep_chown(const char *path, uid_t uid, gid_t gid);
+#endif
+
+#ifndef HAVE_CHROOT
+#define chroot rep_chroot
+int rep_chroot(const char *dirname);
+#endif
+
+#ifndef HAVE_LINK
+#define link rep_link
+int rep_link(const char *oldpath, const char *newpath);
+#endif
+
+#ifndef HAVE_READLINK
+#define readlink rep_readlink
+ssize_t rep_readlink(const char *path, char *buf, size_t bufsize);
+#endif
+
+#ifndef HAVE_SYMLINK
+#define symlink rep_symlink
+int rep_symlink(const char *oldpath, const char *newpath);
+#endif
+
+#ifndef HAVE_REALPATH
+#define realpath rep_realpath
+char *rep_realpath(const char *path, char *resolved_path);
+#endif
+
+#ifndef HAVE_LCHOWN
+#define lchown rep_lchown
+int rep_lchown(const char *fname,uid_t uid,gid_t gid);
+#endif
+
+#ifdef HAVE_UNIX_H
+#include <unix.h>
+#endif
+
+#ifndef HAVE_SETLINEBUF
+#define setlinebuf rep_setlinebuf
+void rep_setlinebuf(FILE *);
+#endif
+
+#ifndef HAVE_STRCASESTR
+#define strcasestr rep_strcasestr
+char *rep_strcasestr(const char *haystack, const char *needle);
+#endif
+
+#ifndef HAVE_STRSEP
+#define strsep rep_strsep
+char *rep_strsep(char **pps, const char *delim);
+#endif
+
+#ifndef HAVE_STRTOK_R
+#define strtok_r rep_strtok_r
+char *rep_strtok_r(char *s, const char *delim, char **save_ptr);
+#endif
+
+
+
+#ifndef HAVE_STRTOLL
+#define strtoll rep_strtoll
+long long int rep_strtoll(const char *str, char **endptr, int base);
+#else
+#ifdef HAVE_BSD_STRTOLL
+#define strtoll rep_strtoll
+long long int rep_strtoll(const char *str, char **endptr, int base);
+#endif
+#endif
+
+#ifndef HAVE_STRTOULL
+#define strtoull rep_strtoull
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base);
+#else
+#ifdef HAVE_BSD_STRTOLL /* yes, it's not HAVE_BSD_STRTOULL */
+#define strtoull rep_strtoull
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base);
+#endif
+#endif
+
+#ifndef HAVE_FTRUNCATE
+#define ftruncate rep_ftruncate
+int rep_ftruncate(int,off_t);
+#endif
+
+#ifndef HAVE_INITGROUPS
+#define initgroups rep_initgroups
+int rep_initgroups(char *name, gid_t id);
+#endif
+
+#if !defined(HAVE_BZERO) && defined(HAVE_MEMSET)
+#define bzero(a,b) memset((a),'\0',(b))
+#endif
+
+#ifndef HAVE_DLERROR
+#define dlerror rep_dlerror
+char *rep_dlerror(void);
+#endif
+
+#ifndef HAVE_DLOPEN
+#define dlopen rep_dlopen
+#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS
+void *rep_dlopen(const char *name, unsigned int flags);
+#else
+void *rep_dlopen(const char *name, int flags);
+#endif
+#endif
+
+#ifndef HAVE_DLSYM
+#define dlsym rep_dlsym
+void *rep_dlsym(void *handle, const char *symbol);
+#endif
+
+#ifndef HAVE_DLCLOSE
+#define dlclose rep_dlclose
+int rep_dlclose(void *handle);
+#endif
+
+#ifndef HAVE_SOCKETPAIR
+#define socketpair rep_socketpair
+/* prototype is in system/network.h */
+#endif
+
+/* for old gcc releases that don't have the feature test macro __has_attribute */
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if __has_attribute(format) || (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+#ifndef _DEPRECATED_
+#if __has_attribute(deprecated) || (__GNUC__ >= 3)
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+
+#if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define vdprintf rep_vdprintf
+int rep_vdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+#endif
+
+#if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define dprintf rep_dprintf
+int rep_dprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+#endif
+
+#if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define vasprintf rep_vasprintf
+int rep_vasprintf(char **ptr, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define snprintf rep_snprintf
+int rep_snprintf(char *,size_t ,const char *, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define vsnprintf rep_vsnprintf
+int rep_vsnprintf(char *,size_t ,const char *, va_list ap) PRINTF_ATTRIBUTE(3,0);
+#endif
+
+#if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+#define asprintf rep_asprintf
+int rep_asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
+#endif
+
+#if !defined(HAVE_C99_VSNPRINTF)
+#ifdef REPLACE_BROKEN_PRINTF
+/*
+ * We do not redefine printf by default
+ * as it breaks the build if system headers
+ * use __attribute__((format(printf, 3, 0)))
+ * instead of __attribute__((format(__printf__, 3, 0)))
+ */
+#define printf rep_printf
+#endif
+int rep_printf(const char *, ...) PRINTF_ATTRIBUTE(1,2);
+#endif
+
+#if !defined(HAVE_C99_VSNPRINTF)
+#define fprintf rep_fprintf
+int rep_fprintf(FILE *stream, const char *, ...) PRINTF_ATTRIBUTE(2,3);
+#endif
+
+#ifndef HAVE_VSYSLOG
+#ifdef HAVE_SYSLOG
+#define vsyslog rep_vsyslog
+void rep_vsyslog (int facility_priority, const char *format, va_list arglist) PRINTF_ATTRIBUTE(2,0);
+#endif
+#endif
+
+/* we used to use these fns, but now we have good replacements
+ for snprintf and vsnprintf */
+#define slprintf snprintf
+
+
+#ifndef HAVE_VA_COPY
+#undef va_copy
+#ifdef HAVE___VA_COPY
+#define va_copy(dest, src) __va_copy(dest, src)
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+#ifndef HAVE_VOLATILE
+#define volatile
+#endif
+
+#ifndef HAVE_COMPARISON_FN_T
+typedef int (*comparison_fn_t)(const void *, const void *);
+#endif
+
+#ifndef HAVE_WORKING_STRPTIME
+#define strptime rep_strptime
+struct tm;
+char *rep_strptime(const char *buf, const char *format, struct tm *tm);
+#endif
+
+#ifndef HAVE_DUP2
+#define dup2 rep_dup2
+int rep_dup2(int oldfd, int newfd);
+#endif
+
+/* Load header file for dynamic linking stuff */
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+#ifndef HAVE_SECURE_MKSTEMP
+#define mkstemp(path) rep_mkstemp(path)
+int rep_mkstemp(char *temp);
+#endif
+
+#ifndef HAVE_MKDTEMP
+#define mkdtemp rep_mkdtemp
+char *rep_mkdtemp(char *template);
+#endif
+
+#ifndef HAVE_PREAD
+#define pread rep_pread
+ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset);
+#define LIBREPLACE_PREAD_REPLACED 1
+#else
+#define LIBREPLACE_PREAD_NOT_REPLACED 1
+#endif
+
+#ifndef HAVE_PWRITE
+#define pwrite rep_pwrite
+ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset);
+#define LIBREPLACE_PWRITE_REPLACED 1
+#else
+#define LIBREPLACE_PWRITE_NOT_REPLACED 1
+#endif
+
+#if !defined(HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA)
+#define inet_ntoa rep_inet_ntoa
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_PTON
+#define inet_pton rep_inet_pton
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_NTOP
+#define inet_ntop rep_inet_ntop
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_INET_ATON
+#define inet_aton rep_inet_aton
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_CONNECT
+#define connect rep_connect
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+#define gethostbyname rep_gethostbyname
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GETIFADDRS
+#define getifaddrs rep_getifaddrs
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_FREEIFADDRS
+#define freeifaddrs rep_freeifaddrs
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GET_CURRENT_DIR_NAME
+#define get_current_dir_name rep_get_current_dir_name
+char *rep_get_current_dir_name(void);
+#endif
+
+#if (!defined(HAVE_STRERROR_R) || !defined(STRERROR_R_XSI_NOT_GNU))
+#define strerror_r rep_strerror_r
+int rep_strerror_r(int errnum, char *buf, size_t buflen);
+#endif
+
+#if !defined(HAVE_CLOCK_GETTIME)
+#define clock_gettime rep_clock_gettime
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+/* The extra casts work around common compiler bugs. */
+#define _TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
+ It is necessary at least when t == time_t. */
+#define _TYPE_MINIMUM(t) ((t) (_TYPE_SIGNED (t) \
+ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
+#define _TYPE_MAXIMUM(t) ((t) (~ (t) 0 - _TYPE_MINIMUM (t)))
+
+#ifndef UINT16_MAX
+#define UINT16_MAX 65535
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef UINT64_MAX
+#define UINT64_MAX ((uint64_t)-1)
+#endif
+
+#ifndef INT64_MAX
+#define INT64_MAX 9223372036854775807LL
+#endif
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef INT32_MAX
+#define INT32_MAX _TYPE_MAXIMUM(int32_t)
+#endif
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+#ifndef HAVE_BOOL
+#error Need a real boolean type
+#endif
+
+#if !defined(HAVE_INTPTR_T)
+typedef long long intptr_t ;
+#define __intptr_t_defined
+#endif
+
+#if !defined(HAVE_UINTPTR_T)
+typedef unsigned long long uintptr_t ;
+#define __uintptr_t_defined
+#endif
+
+#if !defined(HAVE_PTRDIFF_T)
+typedef unsigned long long ptrdiff_t ;
+#endif
+
+/*
+ * to prevent <rpcsvc/yp_prot.h> from doing a redefine of 'bool'
+ *
+ * IRIX, HPUX, MacOS 10 and Solaris need BOOL_DEFINED
+ * Tru64 needs _BOOL_EXISTS
+ * AIX needs _BOOL,_TRUE,_FALSE
+ */
+#ifndef BOOL_DEFINED
+#define BOOL_DEFINED
+#endif
+#ifndef _BOOL_EXISTS
+#define _BOOL_EXISTS
+#endif
+#ifndef _BOOL
+#define _BOOL
+#endif
+
+#ifndef __bool_true_false_are_defined
+#define __bool_true_false_are_defined
+#endif
+
+#ifndef true
+#define true (1)
+#endif
+#ifndef false
+#define false (0)
+#endif
+
+#ifndef _TRUE
+#define _TRUE true
+#endif
+#ifndef _FALSE
+#define _FALSE false
+#endif
+
+#ifndef HAVE_FUNCTION_MACRO
+#ifdef HAVE_func_MACRO
+#define __FUNCTION__ __func__
+#else
+#define __FUNCTION__ ("")
+#endif
+#endif
+
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#if !defined(HAVE_VOLATILE)
+#define volatile
+#endif
+
+/**
+ this is a warning hack. The idea is to use this everywhere that we
+ get the "discarding const" warning from gcc. That doesn't actually
+ fix the problem of course, but it means that when we do get to
+ cleaning them up we can do it by searching the code for
+ discard_const.
+
+ It also means that other error types aren't as swamped by the noise
+ of hundreds of const warnings, so we are more likely to notice when
+ we get new errors.
+
+ Please only add more uses of this macro when you find it
+ _really_ hard to fix const warnings. Our aim is to eventually use
+ this function in only a very few places.
+
+ Also, please call this via the discard_const_p() macro interface, as that
+ makes the return type safe.
+*/
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+
+/** Type-safe version of discard_const */
+#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
+
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+#ifndef __STRINGSTRING
+#define __STRINGSTRING(x) __STRING(x)
+#endif
+
+#ifndef __LINESTR__
+#define __LINESTR__ __STRINGSTRING(__LINE__)
+#endif
+
+#ifndef __location__
+#define __location__ __FILE__ ":" __LINESTR__
+#endif
+
+/**
+ * Zero a structure.
+ */
+#define ZERO_STRUCT(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x))
+
+/**
+ * Zero a structure given a pointer to the structure.
+ */
+#define ZERO_STRUCTP(x) do { \
+ if ((x) != NULL) { \
+ memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x))); \
+ } \
+} while(0)
+
+/**
+ * Zero a structure given a pointer to the structure - no zero check
+ */
+#define ZERO_STRUCTPN(x) memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x)))
+
+/**
+ * Zero an array - note that sizeof(array) must work - ie. it must not be a
+ * pointer
+ */
+#define ZERO_ARRAY(x) memset_s((char *)(x), sizeof(x), 0, sizeof(x))
+
+/**
+ * Zero a given len of an array
+ */
+#define ZERO_ARRAY_LEN(x, l) memset_s((char *)(x), (l), 0, (l))
+
+/**
+ * Explicitly zero data from memory. This is guaranteed to be not optimized
+ * away.
+ */
+#define BURN_DATA(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x))
+
+/**
+ * Explicitly zero data from memory. This is guaranteed to be not optimized
+ * away.
+ */
+#define BURN_DATA_SIZE(x, s) memset_s((char *)&(x), (s), 0, (s))
+
+/**
+ * Explicitly zero data from memory. This is guaranteed to be not optimized
+ * away.
+ */
+#define BURN_PTR_SIZE(x, s) memset_s((x), (s), 0, (s))
+
+/**
+ * Explicitly zero data in string. This is guaranteed to be not optimized
+ * away.
+ */
+#define BURN_STR(x) do { \
+ if ((x) != NULL) { \
+ size_t s = strlen(x); \
+ memset_s((x), s, 0, s); \
+ } \
+ } while(0)
+
+/**
+ * Work out how many elements there are in a static array.
+ */
+#ifdef ARRAY_SIZE
+#undef ARRAY_SIZE
+#endif
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/**
+ * Remove an array element by moving the rest one down
+ */
+#define ARRAY_DEL_ELEMENT(a,i,n) \
+if((i)<((n)-1)){memmove(&((a)[(i)]),&((a)[(i)+1]),(sizeof(*(a))*((n)-(i)-1)));}
+
+/**
+ * Insert an array element by moving the rest one up
+ *
+ */
+#define ARRAY_INSERT_ELEMENT(__array,__old_last_idx,__new_elem,__new_idx) do { \
+ if ((__new_idx) < (__old_last_idx)) { \
+ const void *__src = &((__array)[(__new_idx)]); \
+ void *__dst = &((__array)[(__new_idx)+1]); \
+ size_t __num = (__old_last_idx)-(__new_idx); \
+ size_t __len = sizeof(*(__array)) * __num; \
+ memmove(__dst, __src, __len); \
+ } \
+ (__array)[(__new_idx)] = (__new_elem); \
+} while(0)
+
+/**
+ * Pointer difference macro
+ */
+#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
+
+#ifdef __COMPAR_FN_T
+#define QSORT_CAST (__compar_fn_t)
+#endif
+
+#ifndef QSORT_CAST
+#define QSORT_CAST (int (*)(const void *, const void *))
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifndef MAX_DNS_NAME_LENGTH
+#define MAX_DNS_NAME_LENGTH 256 /* Actually 255 but +1 for terminating null. */
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+/* these macros gain us a few percent of speed on gcc */
+#if (__GNUC__ >= 3)
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+ as its first argument */
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+#ifndef HAVE_FDATASYNC
+#define fdatasync(fd) fsync(fd)
+#elif !defined(HAVE_DECL_FDATASYNC)
+int fdatasync(int );
+#endif
+
+/* these are used to mark symbols as local to a shared lib, or
+ * publicly available via the shared lib API */
+#ifndef _PUBLIC_
+#ifdef HAVE_VISIBILITY_ATTR
+#define _PUBLIC_ __attribute__((visibility("default")))
+#else
+#define _PUBLIC_
+#endif
+#endif
+
+#ifndef _PRIVATE_
+#ifdef HAVE_VISIBILITY_ATTR
+# define _PRIVATE_ __attribute__((visibility("hidden")))
+#else
+# define _PRIVATE_
+#endif
+#endif
+
+#ifndef HAVE_POLL
+#define poll rep_poll
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GETPEEREID
+#define getpeereid rep_getpeereid
+int rep_getpeereid(int s, uid_t *uid, gid_t *gid);
+#endif
+
+#ifndef HAVE_USLEEP
+#define usleep rep_usleep
+typedef long useconds_t;
+int usleep(useconds_t);
+#endif
+
+#ifndef HAVE_SETPROCTITLE
+#define setproctitle rep_setproctitle
+void rep_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
+#endif
+
+#ifndef HAVE_SETPROCTITLE_INIT
+#define setproctitle_init rep_setproctitle_init
+void rep_setproctitle_init(int argc, char *argv[], char *envp[]);
+#endif
+
+#ifndef HAVE_MEMSET_S
+#define memset_s rep_memset_s
+int rep_memset_s(void *dest, size_t destsz, int ch, size_t count);
+#endif
+
+#ifndef HAVE_GETPROGNAME
+#define getprogname rep_getprogname
+const char *rep_getprogname(void);
+#endif
+
+#ifndef HAVE_COPY_FILE_RANGE
+#define copy_file_range rep_copy_file_range
+ssize_t rep_copy_file_range(int fd_in,
+ loff_t *off_in,
+ int fd_out,
+ loff_t *off_out,
+ size_t len,
+ unsigned int flags);
+#endif /* HAVE_COPY_FILE_RANGE */
+
+#ifndef FALL_THROUGH
+# ifdef HAVE_FALLTHROUGH_ATTRIBUTE
+# define FALL_THROUGH __attribute__ ((fallthrough))
+# else /* HAVE_FALLTHROUGH_ATTRIBUTE */
+# define FALL_THROUGH ((void)0)
+# endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
+#endif /* FALL_THROUGH */
+
+struct __rep_cwrap_enabled_state {
+ const char *fnname;
+ bool cached;
+ bool retval;
+};
+
+static inline bool __rep_cwrap_enabled_fn(struct __rep_cwrap_enabled_state *state)
+{
+ bool (*__wrapper_enabled_fn)(void) = NULL;
+
+ if (state->cached) {
+ return state->retval;
+ }
+ state->retval = false;
+ state->cached = true;
+
+ __wrapper_enabled_fn = (bool (*)(void))dlsym(RTLD_DEFAULT, state->fnname);
+ if (__wrapper_enabled_fn == NULL) {
+ return state->retval;
+ }
+
+ state->retval = __wrapper_enabled_fn();
+ return state->retval;
+}
+
+static inline bool nss_wrapper_enabled(void)
+{
+ struct __rep_cwrap_enabled_state state = {
+ .fnname = "nss_wrapper_enabled",
+ };
+ return __rep_cwrap_enabled_fn(&state);
+}
+static inline bool nss_wrapper_hosts_enabled(void)
+{
+ struct __rep_cwrap_enabled_state state = {
+ .fnname = "nss_wrapper_hosts_enabled",
+ };
+ return __rep_cwrap_enabled_fn(&state);
+}
+static inline bool socket_wrapper_enabled(void)
+{
+ struct __rep_cwrap_enabled_state state = {
+ .fnname = "socket_wrapper_enabled",
+ };
+ return __rep_cwrap_enabled_fn(&state);
+}
+static inline bool uid_wrapper_enabled(void)
+{
+ struct __rep_cwrap_enabled_state state = {
+ .fnname = "uid_wrapper_enabled",
+ };
+ return __rep_cwrap_enabled_fn(&state);
+}
+
+static inline bool _hexcharval(char c, uint8_t *val)
+{
+ if ((c >= '0') && (c <= '9')) { *val = c - '0'; return true; }
+ if ((c >= 'a') && (c <= 'f')) { *val = c - 'a' + 10; return true; }
+ if ((c >= 'A') && (c <= 'F')) { *val = c - 'A' + 10; return true; }
+ return false;
+}
+
+static inline bool hex_byte(const char *in, uint8_t *out)
+{
+ uint8_t hi=0, lo=0;
+ bool ok = _hexcharval(in[0], &hi) && _hexcharval(in[1], &lo);
+ *out = (hi<<4)+lo;
+ return ok;
+}
+
+/* Needed for Solaris atomic_add_XX functions. */
+#if defined(HAVE_SYS_ATOMIC_H)
+#include <sys/atomic.h>
+#endif
+
+/*
+ * This handles the case of missing pthread support and ensures code can use
+ * __thread unconditionally, such that when built on a platform without pthread
+ * support, the __thread qualifier is an empty define.
+ */
+#ifndef HAVE___THREAD
+# ifdef HAVE_PTHREAD
+# error Configure failed to detect pthread library with missing TLS support
+# endif
+#define HAVE___THREAD
+#endif
+
+#endif /* _LIBREPLACE_REPLACE_H */
diff --git a/lib/replace/snprintf.c b/lib/replace/snprintf.c
new file mode 100644
index 0000000..dd878fc
--- /dev/null
+++ b/lib/replace/snprintf.c
@@ -0,0 +1,1536 @@
+/*
+ * NOTE: If you change this file, please merge it into rsync, samba, etc.
+ */
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nasty effects.
+ *
+ * More Recently:
+ * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything
+ * from the normal C string format, at least as far as I can tell from
+ * the Solaris 2.5 printf(3S) man page.
+ *
+ * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ * Ok, added some minimal floating point support, which means this
+ * probably requires libm on most operating systems. Don't yet
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
+ * was pretty badly broken, it just wasn't being exercised in ways
+ * which showed it, so that's been fixed. Also, formatted the code
+ * to mutt conventions, and removed dead code left over from the
+ * original. Also, there is now a builtin-test, just compile with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ * and run snprintf for results.
+ *
+ * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ * The original code assumed that both snprintf() and vsnprintf() were
+ * missing. Some systems only have snprintf() but not vsnprintf(), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * Andrew Tridgell (tridge@samba.org) Oct 1998
+ * fixed handling of %.0f
+ * added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ * got rid of fcvt code (twas buggy and made testing harder)
+ * added C99 semantics
+ *
+ * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
+ * actually print args for %g and %e
+ *
+ * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
+ * Since includes.h isn't included here, VA_COPY has to be defined here. I don't
+ * see any include file that is guaranteed to be here, so I'm defining it
+ * locally. Fixes AIX and Solaris builds.
+ *
+ * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
+ * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
+ * functions
+ *
+ * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
+ * Fix usage of va_list passed as an arg. Use __va_copy before using it
+ * when it exists.
+ *
+ * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
+ * Fix incorrect zpadlen handling in fmtfp.
+ * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * added the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp@samba.org) April 2003
+ * Remove NO_CONFIG_H so that the test case can be built within a source
+ * tree with less trouble.
+ * Remove unnecessary SAFE_FREE() definition.
+ *
+ * Martin Pool (mbp@samba.org) May 2003
+ * Put in a prototype for dummy_snprintf() to quiet compiler warnings.
+ *
+ * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
+ * if the C library has some snprintf functions already.
+ *
+ * Darren Tucker (dtucker@zip.com.au) 2005
+ * Fix bug allowing read overruns of the source string with "%.*s"
+ * Usually harmless unless the read runs outside the process' allocation
+ * (eg if your malloc does guard pages) in which case it will segfault.
+ * From OpenSSH. Also added test for same.
+ *
+ * Simo Sorce (idra@samba.org) Jan 2006
+ *
+ * Add support for position independent parameters
+ * fix fmtstr now it conforms to sprintf wrt min.max
+ *
+ **************************************************************/
+
+#include "replace.h"
+#include "system/locale.h"
+
+#ifdef TEST_SNPRINTF /* need math library headers for testing */
+
+/* In test mode, we pretend that this system doesn't have any snprintf
+ * functions, regardless of what config.h says. */
+# undef HAVE_SNPRINTF
+# undef HAVE_VSNPRINTF
+# undef HAVE_C99_VSNPRINTF
+# undef HAVE_ASPRINTF
+# undef HAVE_VASPRINTF
+# include <math.h>
+#endif /* TEST_SNPRINTF */
+
+#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
+/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
+#include <stdio.h>
+ /* make the compiler happy with an empty file */
+ void dummy_snprintf(void);
+ void dummy_snprintf(void) {}
+#endif /* HAVE_SNPRINTF, etc */
+
+/* yes this really must be a ||. Don't muck with this (tridge) */
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+
+#ifdef HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+#ifndef VA_COPY
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#else
+#ifdef HAVE___VA_COPY
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS 1
+#define DP_S_MIN 2
+#define DP_S_DOT 3
+#define DP_S_MAX 4
+#define DP_S_MOD 5
+#define DP_S_CONV 6
+#define DP_S_DONE 7
+
+/* format flags - Bits */
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_CHAR 1
+#define DP_C_SHORT 2
+#define DP_C_LONG 3
+#define DP_C_LDOUBLE 4
+#define DP_C_LLONG 5
+#define DP_C_SIZET 6
+
+/* Chunk types */
+#define CNK_FMT_STR 0
+#define CNK_INT 1
+#define CNK_OCTAL 2
+#define CNK_UINT 3
+#define CNK_HEX 4
+#define CNK_FLOAT 5
+#define CNK_CHAR 6
+#define CNK_STRING 7
+#define CNK_PTR 8
+#define CNK_NUM 9
+#define CNK_PRCNT 10
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+struct pr_chunk {
+ int type; /* chunk type */
+ int num; /* parameter number */
+ int min;
+ int max;
+ int flags;
+ int cflags;
+ int start;
+ int len;
+ LLONG value;
+ LDOUBLE fvalue;
+ char *strvalue;
+ void *pnum;
+ struct pr_chunk *min_star;
+ struct pr_chunk *max_star;
+ struct pr_chunk *next;
+};
+
+struct pr_chunk_x {
+ struct pr_chunk **chunks;
+ int num;
+};
+
+static int dopr(char *buffer, size_t maxlen, const char *format,
+ va_list args_in);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+static struct pr_chunk *new_chunk(void);
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+ int max_num, struct pr_chunk *chunk);
+
+static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
+{
+ char ch;
+ int state;
+ int pflag;
+ int pnum;
+ int pfirst;
+ size_t currlen;
+ va_list args;
+ const char *base;
+ struct pr_chunk *chunks = NULL;
+ struct pr_chunk *cnk = NULL;
+ struct pr_chunk_x *clist = NULL;
+ int max_pos;
+ int ret = -1;
+
+ VA_COPY(args, args_in);
+
+ state = DP_S_DEFAULT;
+ pfirst = 1;
+ pflag = 0;
+ pnum = 0;
+
+ max_pos = 0;
+ base = format;
+ ch = *format++;
+
+ /* retrieve the string structure as chunks */
+ while (state != DP_S_DONE) {
+ if (ch == '\0')
+ state = DP_S_DONE;
+
+ switch(state) {
+ case DP_S_DEFAULT:
+
+ if (cnk) {
+ cnk->next = new_chunk();
+ cnk = cnk->next;
+ } else {
+ cnk = new_chunk();
+ }
+ if (!cnk) goto done;
+ if (!chunks) chunks = cnk;
+
+ if (ch == '%') {
+ state = DP_S_FLAGS;
+ ch = *format++;
+ } else {
+ cnk->type = CNK_FMT_STR;
+ cnk->start = format - base -1;
+ while ((ch != '\0') && (ch != '%')) ch = *format++;
+ cnk->len = format - base - cnk->start -1;
+ }
+ break;
+ case DP_S_FLAGS:
+ switch (ch) {
+ case '-':
+ cnk->flags |= DP_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ cnk->flags |= DP_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ cnk->flags |= DP_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ cnk->flags |= DP_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ cnk->flags |= DP_F_ZERO;
+ ch = *format++;
+ break;
+ case 'I':
+ /* internationalization not supported yet */
+ ch = *format++;
+ break;
+ default:
+ state = DP_S_MIN;
+ break;
+ }
+ break;
+ case DP_S_MIN:
+ if (isdigit((unsigned char)ch)) {
+ cnk->min = 10 * cnk->min + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '$') {
+ if (!pfirst && !pflag) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ if (pfirst) {
+ pfirst = 0;
+ pflag = 1;
+ }
+ if (cnk->min == 0) /* what ?? */
+ goto done;
+ cnk->num = cnk->min;
+ cnk->min = 0;
+ ch = *format++;
+ } else if (ch == '*') {
+ if (pfirst) pfirst = 0;
+ cnk->min_star = new_chunk();
+ if (!cnk->min_star) /* out of memory :-( */
+ goto done;
+ cnk->min_star->type = CNK_INT;
+ if (pflag) {
+ int num;
+ ch = *format++;
+ if (!isdigit((unsigned char)ch)) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+ num = 10 * num + char_to_int(ch);
+ }
+ cnk->min_star->num = num;
+ if (ch != '$') /* what ?? */
+ goto done;
+ } else {
+ cnk->min_star->num = ++pnum;
+ }
+ max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
+ if (max_pos == 0) /* out of memory :-( */
+ goto done;
+ ch = *format++;
+ state = DP_S_DOT;
+ } else {
+ if (pfirst) pfirst = 0;
+ state = DP_S_DOT;
+ }
+ break;
+ case DP_S_DOT:
+ if (ch == '.') {
+ state = DP_S_MAX;
+ ch = *format++;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MAX:
+ if (isdigit((unsigned char)ch)) {
+ if (cnk->max < 0)
+ cnk->max = 0;
+ cnk->max = 10 * cnk->max + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '$') {
+ if (!pfirst && !pflag) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ if (cnk->max <= 0) /* what ?? */
+ goto done;
+ cnk->num = cnk->max;
+ cnk->max = -1;
+ ch = *format++;
+ } else if (ch == '*') {
+ cnk->max_star = new_chunk();
+ if (!cnk->max_star) /* out of memory :-( */
+ goto done;
+ cnk->max_star->type = CNK_INT;
+ if (pflag) {
+ int num;
+ ch = *format++;
+ if (!isdigit((unsigned char)ch)) {
+ /* parameters must be all positioned or none */
+ goto done;
+ }
+ for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+ num = 10 * num + char_to_int(ch);
+ }
+ cnk->max_star->num = num;
+ if (ch != '$') /* what ?? */
+ goto done;
+ } else {
+ cnk->max_star->num = ++pnum;
+ }
+ max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
+ if (max_pos == 0) /* out of memory :-( */
+ goto done;
+
+ ch = *format++;
+ state = DP_S_MOD;
+ } else {
+ state = DP_S_MOD;
+ }
+ break;
+ case DP_S_MOD:
+ switch (ch) {
+ case 'h':
+ cnk->cflags = DP_C_SHORT;
+ ch = *format++;
+ if (ch == 'h') {
+ cnk->cflags = DP_C_CHAR;
+ ch = *format++;
+ }
+ break;
+ case 'l':
+ cnk->cflags = DP_C_LONG;
+ ch = *format++;
+ if (ch == 'l') { /* It's a long long */
+ cnk->cflags = DP_C_LLONG;
+ ch = *format++;
+ }
+ break;
+ case 'j':
+ cnk->cflags = DP_C_LLONG;
+ ch = *format++;
+ break;
+ case 'L':
+ cnk->cflags = DP_C_LDOUBLE;
+ ch = *format++;
+ break;
+ case 'z':
+ cnk->cflags = DP_C_SIZET;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ state = DP_S_CONV;
+ break;
+ case DP_S_CONV:
+ if (cnk->num == 0) cnk->num = ++pnum;
+ max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
+ if (max_pos == 0) /* out of memory :-( */
+ goto done;
+
+ switch (ch) {
+ case 'd':
+ case 'i':
+ cnk->type = CNK_INT;
+ break;
+ case 'o':
+ cnk->type = CNK_OCTAL;
+ cnk->flags |= DP_F_UNSIGNED;
+ break;
+ case 'u':
+ cnk->type = CNK_UINT;
+ cnk->flags |= DP_F_UNSIGNED;
+ break;
+ case 'X':
+ cnk->flags |= DP_F_UP;
+ case 'x':
+ cnk->type = CNK_HEX;
+ cnk->flags |= DP_F_UNSIGNED;
+ break;
+ case 'A':
+ /* hex float not supported yet */
+ case 'E':
+ case 'G':
+ case 'F':
+ cnk->flags |= DP_F_UP;
+ case 'a':
+ /* hex float not supported yet */
+ case 'e':
+ case 'f':
+ case 'g':
+ cnk->type = CNK_FLOAT;
+ break;
+ case 'c':
+ cnk->type = CNK_CHAR;
+ break;
+ case 's':
+ cnk->type = CNK_STRING;
+ break;
+ case 'p':
+ cnk->type = CNK_PTR;
+ cnk->flags |= DP_F_UNSIGNED;
+ break;
+ case 'n':
+ cnk->type = CNK_NUM;
+ break;
+ case '%':
+ cnk->type = CNK_PRCNT;
+ break;
+ default:
+ /* Unknown, bail out*/
+ goto done;
+ }
+ ch = *format++;
+ state = DP_S_DEFAULT;
+ break;
+ case DP_S_DONE:
+ break;
+ default:
+ /* hmm? */
+ break; /* some picky compilers need this */
+ }
+ }
+
+ /* retrieve the format arguments */
+ for (pnum = 0; pnum < max_pos; pnum++) {
+ int i;
+
+ if (clist[pnum].num == 0) {
+ /* ignoring a parameter should not be permitted
+ * all parameters must be matched at least once
+ * BUT seem some system ignore this rule ...
+ * at least my glibc based system does --SSS
+ */
+#ifdef DEBUG_SNPRINTF
+ printf("parameter at position %d not used\n", pnum+1);
+#endif
+ /* eat the parameter */
+ va_arg (args, int);
+ continue;
+ }
+ for (i = 1; i < clist[pnum].num; i++) {
+ if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
+ /* nooo no no!
+ * all the references to a parameter
+ * must be of the same type
+ */
+ goto done;
+ }
+ }
+ cnk = clist[pnum].chunks[0];
+ switch (cnk->type) {
+ case CNK_INT:
+ if (cnk->cflags == DP_C_SHORT)
+ cnk->value = va_arg (args, int);
+ else if (cnk->cflags == DP_C_LONG)
+ cnk->value = va_arg (args, long int);
+ else if (cnk->cflags == DP_C_LLONG)
+ cnk->value = va_arg (args, LLONG);
+ else if (cnk->cflags == DP_C_SIZET)
+ cnk->value = va_arg (args, ssize_t);
+ else
+ cnk->value = va_arg (args, int);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->value = cnk->value;
+ }
+ break;
+
+ case CNK_OCTAL:
+ case CNK_UINT:
+ case CNK_HEX:
+ if (cnk->cflags == DP_C_SHORT)
+ cnk->value = va_arg (args, unsigned int);
+ else if (cnk->cflags == DP_C_LONG)
+ cnk->value = (unsigned long int)va_arg (args, unsigned long int);
+ else if (cnk->cflags == DP_C_LLONG)
+ cnk->value = (LLONG)va_arg (args, unsigned LLONG);
+ else if (cnk->cflags == DP_C_SIZET)
+ cnk->value = (size_t)va_arg (args, size_t);
+ else
+ cnk->value = (unsigned int)va_arg (args, unsigned int);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->value = cnk->value;
+ }
+ break;
+
+ case CNK_FLOAT:
+ if (cnk->cflags == DP_C_LDOUBLE)
+ cnk->fvalue = va_arg (args, LDOUBLE);
+ else
+ cnk->fvalue = va_arg (args, double);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->fvalue = cnk->fvalue;
+ }
+ break;
+
+ case CNK_CHAR:
+ cnk->value = va_arg (args, int);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->value = cnk->value;
+ }
+ break;
+
+ case CNK_STRING:
+ cnk->strvalue = va_arg (args, char *);
+ if (!cnk->strvalue) cnk->strvalue = "(NULL)";
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+ }
+ break;
+
+ case CNK_PTR:
+ cnk->strvalue = va_arg (args, void *);
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+ }
+ break;
+
+ case CNK_NUM:
+ if (cnk->cflags == DP_C_CHAR)
+ cnk->pnum = va_arg (args, char *);
+ else if (cnk->cflags == DP_C_SHORT)
+ cnk->pnum = va_arg (args, short int *);
+ else if (cnk->cflags == DP_C_LONG)
+ cnk->pnum = va_arg (args, long int *);
+ else if (cnk->cflags == DP_C_LLONG)
+ cnk->pnum = va_arg (args, LLONG *);
+ else if (cnk->cflags == DP_C_SIZET)
+ cnk->pnum = va_arg (args, ssize_t *);
+ else
+ cnk->pnum = va_arg (args, int *);
+
+ for (i = 1; i < clist[pnum].num; i++) {
+ clist[pnum].chunks[i]->pnum = cnk->pnum;
+ }
+ break;
+
+ case CNK_PRCNT:
+ break;
+
+ default:
+ /* what ?? */
+ goto done;
+ }
+ }
+ /* print out the actual string from chunks */
+ currlen = 0;
+ cnk = chunks;
+ while (cnk) {
+ int len, min, max;
+
+ if (cnk->min_star) min = cnk->min_star->value;
+ else min = cnk->min;
+ if (cnk->max_star) max = cnk->max_star->value;
+ else max = cnk->max;
+
+ switch (cnk->type) {
+
+ case CNK_FMT_STR:
+ if (maxlen != 0 && maxlen > currlen) {
+ if (maxlen > (currlen + cnk->len)) len = cnk->len;
+ else len = maxlen - currlen;
+
+ memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
+ }
+ currlen += cnk->len;
+
+ break;
+
+ case CNK_INT:
+ case CNK_UINT:
+ fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
+ break;
+
+ case CNK_OCTAL:
+ fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
+ break;
+
+ case CNK_HEX:
+ fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
+ break;
+
+ case CNK_FLOAT:
+ fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
+ break;
+
+ case CNK_CHAR:
+ dopr_outch (buffer, &currlen, maxlen, cnk->value);
+ break;
+
+ case CNK_STRING:
+ if (max == -1) {
+ max = strlen(cnk->strvalue);
+ }
+ fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
+ break;
+
+ case CNK_PTR:
+ fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
+ break;
+
+ case CNK_NUM:
+ if (cnk->cflags == DP_C_CHAR)
+ *((char *)(cnk->pnum)) = (char)currlen;
+ else if (cnk->cflags == DP_C_SHORT)
+ *((short int *)(cnk->pnum)) = (short int)currlen;
+ else if (cnk->cflags == DP_C_LONG)
+ *((long int *)(cnk->pnum)) = (long int)currlen;
+ else if (cnk->cflags == DP_C_LLONG)
+ *((LLONG *)(cnk->pnum)) = (LLONG)currlen;
+ else if (cnk->cflags == DP_C_SIZET)
+ *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen;
+ else
+ *((int *)(cnk->pnum)) = (int)currlen;
+ break;
+
+ case CNK_PRCNT:
+ dopr_outch (buffer, &currlen, maxlen, '%');
+ break;
+
+ default:
+ /* what ?? */
+ goto done;
+ }
+ cnk = cnk->next;
+ }
+ if (maxlen != 0) {
+ if (currlen < maxlen - 1)
+ buffer[currlen] = '\0';
+ else if (maxlen > 0)
+ buffer[maxlen - 1] = '\0';
+ }
+ ret = currlen;
+
+done:
+ va_end(args);
+
+ while (chunks) {
+ cnk = chunks->next;
+ if (chunks->min_star) free(chunks->min_star);
+ if (chunks->max_star) free(chunks->max_star);
+ free(chunks);
+ chunks = cnk;
+ }
+ if (clist) {
+ for (pnum = 0; pnum < max_pos; pnum++) {
+ if (clist[pnum].chunks) free(clist[pnum].chunks);
+ }
+ free(clist);
+ }
+ return ret;
+}
+
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max)
+{
+ int padlen, strln; /* amount to pad */
+ int cnt = 0;
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+ if (value == 0) {
+ value = "<NULL>";
+ }
+
+ for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
+ padlen = min - strln;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justify */
+
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ while (*value && (cnt < max)) {
+ dopr_outch (buffer, currlen, maxlen, *value++);
+ ++cnt;
+ }
+ while (padlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ LLONG value, int base, int min, int max, int flags)
+{
+ int signvalue = 0;
+ unsigned LLONG uvalue;
+ char convert[22+1]; /* 64-bit value in octal: 22 digits + \0 */
+ int place = 0;
+ int spadlen = 0; /* amount to space pad */
+ int zpadlen = 0; /* amount to zero pad */
+ int caps = 0;
+
+ if (max < 0)
+ max = 0;
+
+ uvalue = value;
+
+ if(!(flags & DP_F_UNSIGNED)) {
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ } else {
+ if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+ do {
+ convert[place++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")
+ [uvalue % (unsigned)base ];
+ uvalue = (uvalue / (unsigned)base );
+ } while(uvalue && (place < sizeof(convert)));
+ if (place == sizeof(convert)) place--;
+ convert[place] = 0;
+
+ zpadlen = max - place;
+ spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+ if (zpadlen < 0) zpadlen = 0;
+ if (spadlen < 0) spadlen = 0;
+ if (flags & DP_F_ZERO) {
+ zpadlen = MAX(zpadlen, spadlen);
+ spadlen = 0;
+ }
+ if (flags & DP_F_MINUS)
+ spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+ printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+ zpadlen, spadlen, min, max, place);
+#endif
+
+ /* Spaces */
+ while (spadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --spadlen;
+ }
+
+ /* Sign */
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ /* Zeros */
+ if (zpadlen > 0) {
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+ }
+
+ /* Digits */
+ while (place > 0)
+ dopr_outch (buffer, currlen, maxlen, convert[--place]);
+
+ /* Left Justified spaces */
+ while (spadlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++spadlen;
+ }
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+ LDOUBLE result = value;
+
+ if (value < 0)
+ result = -value;
+
+ return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+ LDOUBLE result = 1;
+
+ while (exp) {
+ result *= 10;
+ exp--;
+ }
+
+ return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+ LLONG intpart;
+
+ intpart = (LLONG)value;
+ value = value - intpart;
+ if (value >= 0.5) intpart++;
+
+ return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+ be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+ int i;
+ LLONG l=0;
+ double x = x0;
+ double f = 1.0;
+
+ for (i=0;i<100;i++) {
+ l = (long)x;
+ if (l <= (x+1) && l >= (x-1)) break;
+ x *= 0.1;
+ f *= 10.0;
+ }
+
+ if (i == 100) {
+ /* yikes! the number is beyond what we can handle. What do we do? */
+ (*iptr) = 0;
+ return 0;
+ }
+
+ if (i != 0) {
+ double i2;
+ double ret;
+
+ ret = my_modf(x0-l*f, &i2);
+ (*iptr) = l*f + i2;
+ return ret;
+ }
+
+ (*iptr) = l;
+ return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+ LDOUBLE fvalue, int min, int max, int flags)
+{
+ int signvalue = 0;
+ double ufvalue;
+ char iconvert[311];
+ char fconvert[311];
+ int iplace = 0;
+ int fplace = 0;
+ int padlen = 0; /* amount to pad */
+ int zpadlen = 0;
+ int caps = 0;
+ int idx;
+ double intpart;
+ double fracpart;
+ double temp;
+
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+ * is 6, and sprintf on AIX defaults to 6
+ */
+ if (max < 0)
+ max = 6;
+
+ ufvalue = abs_val (fvalue);
+
+ if (fvalue < 0) {
+ signvalue = '-';
+ } else {
+ if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+ signvalue = '+';
+ } else {
+ if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+ }
+
+#if 0
+ if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+ if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+ /*
+ * Sorry, we only support 9 digits past the decimal because of our
+ * conversion method
+ */
+ if (max > 9)
+ max = 9;
+
+ /* We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of 10
+ */
+
+ temp = ufvalue;
+ my_modf(temp, &intpart);
+
+ fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+
+ if (fracpart >= POW10(max)) {
+ intpart++;
+ fracpart -= POW10(max);
+ }
+
+
+ /* Convert integer part */
+ do {
+ temp = intpart*0.1;
+ my_modf(temp, &intpart);
+ idx = (int) ((temp -intpart +0.05)* 10.0);
+ /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+ /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+ iconvert[iplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+ } while (intpart && (iplace < 311));
+ if (iplace == 311) iplace--;
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
+ if (fracpart)
+ {
+ do {
+ temp = fracpart*0.1;
+ my_modf(temp, &fracpart);
+ idx = (int) ((temp -fracpart +0.05)* 10.0);
+ /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+ /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+ fconvert[fplace++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+ } while(fracpart && (fplace < 311));
+ if (fplace == 311) fplace--;
+ }
+ fconvert[fplace] = 0;
+
+ /* -1 for decimal point, another -1 if we are printing a sign */
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ zpadlen = max - fplace;
+ if (zpadlen < 0) zpadlen = 0;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justifty */
+
+ if ((flags & DP_F_ZERO) && (padlen > 0)) {
+ if (signvalue) {
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --padlen;
+ }
+ }
+ while (padlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ if (signvalue)
+ dopr_outch (buffer, currlen, maxlen, signvalue);
+
+ while (iplace > 0)
+ dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+#ifdef DEBUG_SNPRINTF
+ printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+ /*
+ * Decimal point. This should probably use locale to find the correct
+ * char to print out.
+ */
+ if (max > 0) {
+ dopr_outch (buffer, currlen, maxlen, '.');
+
+ while (zpadlen > 0) {
+ dopr_outch (buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+
+ while (fplace > 0)
+ dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+ }
+
+ while (padlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+}
+
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+ if (*currlen < maxlen) {
+ buffer[(*currlen)] = c;
+ }
+ (*currlen)++;
+}
+
+static struct pr_chunk *new_chunk(void) {
+ struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
+
+ if (!new_c)
+ return NULL;
+
+ new_c->type = 0;
+ new_c->num = 0;
+ new_c->min = 0;
+ new_c->min_star = NULL;
+ new_c->max = -1;
+ new_c->max_star = NULL;
+ new_c->flags = 0;
+ new_c->cflags = 0;
+ new_c->start = 0;
+ new_c->len = 0;
+ new_c->value = 0;
+ new_c->fvalue = 0;
+ new_c->strvalue = NULL;
+ new_c->pnum = NULL;
+ new_c->next = NULL;
+
+ return new_c;
+}
+
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+ int max_num, struct pr_chunk *chunk) {
+ struct pr_chunk_x *l;
+ struct pr_chunk **c;
+ int max;
+ int cnum;
+ int i, pos;
+
+ if (chunk->num > max_num) {
+ max = chunk->num;
+
+ if (*list == NULL) {
+ l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
+ pos = 0;
+ } else {
+ l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
+ pos = max_num;
+ }
+ if (l == NULL) {
+ for (i = 0; i < max; i++) {
+ if ((*list)[i].chunks) free((*list)[i].chunks);
+ }
+ return 0;
+ }
+ for (i = pos; i < max; i++) {
+ l[i].chunks = NULL;
+ l[i].num = 0;
+ }
+ } else {
+ l = *list;
+ max = max_num;
+ }
+
+ i = chunk->num - 1;
+ cnum = l[i].num + 1;
+ if (l[i].chunks == NULL) {
+ c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum);
+ } else {
+ c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
+ }
+ if (c == NULL) {
+ for (i = 0; i < max; i++) {
+ if (l[i].chunks) free(l[i].chunks);
+ }
+ return 0;
+ }
+ c[l[i].num] = chunk;
+ l[i].chunks = c;
+ l[i].num = cnum;
+
+ *list = l;
+ return max;
+}
+
+ int rep_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+ return dopr(str, count, fmt, args);
+}
+#endif
+
+/* yes this really must be a ||. Don't muck with this (tridge)
+ *
+ * The logic for these two is that we need our own definition if the
+ * OS *either* has no definition of *sprintf, or if it does have one
+ * that doesn't work properly according to the autoconf test.
+ */
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+ int rep_snprintf(char *str,size_t count,const char *fmt,...)
+{
+ size_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(str, count, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+#endif
+
+#ifndef HAVE_C99_VSNPRINTF
+ int rep_printf(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *s;
+
+ s = NULL;
+ va_start(ap, fmt);
+ ret = vasprintf(&s, fmt, ap);
+ va_end(ap);
+
+ if (s) {
+ fwrite(s, 1, strlen(s), stdout);
+ }
+ free(s);
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_C99_VSNPRINTF
+ int rep_fprintf(FILE *stream, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *s;
+
+ s = NULL;
+ va_start(ap, fmt);
+ ret = vasprintf(&s, fmt, ap);
+ va_end(ap);
+
+ if (s) {
+ fwrite(s, 1, strlen(s), stream);
+ }
+ free(s);
+
+ return ret;
+}
+#endif
+
+#endif
+
+#if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+ int rep_vasprintf(char **ptr, const char *format, va_list ap)
+{
+ int ret;
+ va_list ap2;
+
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(NULL, 0, format, ap2);
+ va_end(ap2);
+ if (ret < 0) return ret;
+
+ (*ptr) = (char *)malloc(ret+1);
+ if (!*ptr) return -1;
+
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(*ptr, ret+1, format, ap2);
+ va_end(ap2);
+
+ return ret;
+}
+#endif
+
+#if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+ int rep_asprintf(char **ptr, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ *ptr = NULL;
+ va_start(ap, format);
+ ret = vasprintf(ptr, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
+
+#ifdef TEST_SNPRINTF
+
+ int sprintf(char *str,const char *fmt,...);
+ int printf(const char *fmt,...);
+
+ int main (void)
+{
+ char buf1[1024];
+ char buf2[1024];
+ char *buf3;
+ char *fp_fmt[] = {
+ "%1.1f",
+ "%-1.5f",
+ "%1.5f",
+ "%123.9f",
+ "%10.5f",
+ "% 10.5f",
+ "%+22.9f",
+ "%+4.9f",
+ "%01.3f",
+ "%4f",
+ "%3.1f",
+ "%3.2f",
+ "%.0f",
+ "%f",
+ "%-8.8f",
+ "%-9.9f",
+ NULL
+ };
+ double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
+ 0.9996, 1.996, 4.136, 5.030201, 0.00205,
+ /* END LIST */ 0};
+ char *int_fmt[] = {
+ "%-1.5d",
+ "%1.5d",
+ "%123.9d",
+ "%5.5d",
+ "%10.5d",
+ "% 10.5d",
+ "%+22.33d",
+ "%01.3d",
+ "%4d",
+ "%d",
+ NULL
+ };
+ long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0};
+ char *str_fmt[] = {
+ "%10.5s",
+ "%-10.5s",
+ "%5.10s",
+ "%-5.10s",
+ "%10.1s",
+ "%0.10s",
+ "%10.0s",
+ "%1.10s",
+ "%s",
+ "%.1s",
+ "%.10s",
+ "%10s",
+ NULL
+ };
+ char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
+#ifdef HAVE_LONG_LONG
+ char *ll_fmt[] = {
+ "%llu",
+ NULL
+ };
+ LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0};
+#endif
+ int x, y;
+ int fail = 0;
+ int num = 0;
+ int l1, l2;
+ char *ss_fmt[] = {
+ "%zd",
+ "%zu",
+ NULL
+ };
+ size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0};
+
+ printf ("Testing snprintf format codes against system sprintf...\n");
+
+ for (x = 0; fp_fmt[x] ; x++) {
+ for (y = 0; fp_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
+ l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ fp_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; int_fmt[x] ; x++) {
+ for (y = 0; int_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
+ l2 = sprintf (buf2, int_fmt[x], int_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ int_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+ for (x = 0; str_fmt[x] ; x++) {
+ for (y = 0; str_vals[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
+ l2 = sprintf (buf2, str_fmt[x], str_vals[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ str_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+
+#ifdef HAVE_LONG_LONG
+ for (x = 0; ll_fmt[x] ; x++) {
+ for (y = 0; ll_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
+ l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ ll_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+#endif
+
+#define BUFSZ 2048
+
+ buf1[0] = buf2[0] = '\0';
+ if ((buf3 = malloc(BUFSZ)) == NULL) {
+ fail++;
+ } else {
+ num++;
+ memset(buf3, 'a', BUFSZ);
+ snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
+ buf1[1023] = '\0';
+ if (strcmp(buf1, "a") != 0) {
+ printf("length limit buf1 '%s' expected 'a'\n", buf1);
+ fail++;
+ }
+ }
+
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+ l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+ fail++;
+ }
+
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+ l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+ fail++;
+ }
+
+ for (x = 0; ss_fmt[x] ; x++) {
+ for (y = 0; ss_nums[y] != 0 ; y++) {
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]);
+ l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp (buf1, buf2) || (l1 != l2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ ss_fmt[x], l1, buf1, l2, buf2);
+ fail++;
+ }
+ num++;
+ }
+ }
+#if 0
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
+ l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%lld", l1, buf1, l2, buf2);
+ fail++;
+ }
+
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
+ l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
+ buf1[1023] = buf2[1023] = '\0';
+ if (strcmp(buf1, buf2)) {
+ printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+ "%Lf", l1, buf1, l2, buf2);
+ fail++;
+ }
+#endif
+ printf ("%d tests failed out of %d.\n", fail, num);
+
+ printf("seeing how many digits we support\n");
+ {
+ double v0 = 0.12345678901234567890123456789012345678901;
+ for (x=0; x<100; x++) {
+ double p = pow(10, x);
+ double r = v0*p;
+ snprintf(buf1, sizeof(buf1), "%1.1f", r);
+ sprintf(buf2, "%1.1f", r);
+ if (strcmp(buf1, buf2)) {
+ printf("we seem to support %d digits\n", x-1);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* TEST_SNPRINTF */
diff --git a/lib/replace/socket.c b/lib/replace/socket.c
new file mode 100644
index 0000000..4cd9d2e
--- /dev/null
+++ b/lib/replace/socket.c
@@ -0,0 +1,39 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Dummy replacements for socket functions.
+ *
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+int rep_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+struct hostent *rep_gethostbyname(const char *name)
+{
+ errno = ENOSYS;
+ return NULL;
+}
diff --git a/lib/replace/socketpair.c b/lib/replace/socketpair.c
new file mode 100644
index 0000000..c775730
--- /dev/null
+++ b/lib/replace/socketpair.c
@@ -0,0 +1,46 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * replacement routines for broken systems
+ * Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2006
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+int rep_socketpair(int d, int type, int protocol, int sv[2])
+{
+ if (d != AF_UNIX) {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (protocol != 0) {
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+
+ if (type != SOCK_STREAM) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ return pipe(sv);
+}
diff --git a/lib/replace/strptime.c b/lib/replace/strptime.c
new file mode 100644
index 0000000..56ea1e0
--- /dev/null
+++ b/lib/replace/strptime.c
@@ -0,0 +1,995 @@
+/* Convert a string representation of time to a time value.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ see <http://www.gnu.org/licenses/>. */
+
+/* XXX This version of the implementation is not really complete.
+ Some of the fields cannot add information alone. But if seeing
+ some of them in the same format (such as year, week and weekday)
+ this is enough information for determining the date. */
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+
+#ifndef __P
+# if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+# define __P(args) args
+# else
+# define __P(args) ()
+# endif /* GCC. */
+#endif /* Not __P. */
+
+#if ! HAVE_LOCALTIME_R && ! defined localtime_r
+# ifdef _LIBC
+# define localtime_r __localtime_r
+# else
+/* Approximate localtime_r as best we can in its absence. */
+# define localtime_r my_localtime_r
+static struct tm *localtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+localtime_r (t, tp)
+ const time_t *t;
+ struct tm *tp;
+{
+ struct tm *l = localtime (t);
+ if (! l)
+ return 0;
+ *tp = *l;
+ return tp;
+}
+# endif /* ! _LIBC */
+#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
+
+
+#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
+#if defined __GNUC__ && __GNUC__ >= 2
+# define match_string(cs1, s2) \
+ ({ size_t len = strlen (cs1); \
+ int result = strncasecmp ((cs1), (s2), len) == 0; \
+ if (result) (s2) += len; \
+ result; })
+#else
+/* Oh come on. Get a reasonable compiler. */
+# define match_string(cs1, s2) \
+ (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
+#endif
+/* We intentionally do not use isdigit() for testing because this will
+ lead to problems with the wide character version. */
+#define get_number(from, to, n) \
+ do { \
+ int __n = n; \
+ val = 0; \
+ while (*rp == ' ') \
+ ++rp; \
+ if (*rp < '0' || *rp > '9') \
+ return NULL; \
+ do { \
+ val *= 10; \
+ val += *rp++ - '0'; \
+ } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
+ if (val < from || val > to) \
+ return NULL; \
+ } while (0)
+#ifdef _NL_CURRENT
+# define get_alt_number(from, to, n) \
+ ({ \
+ __label__ do_normal; \
+ if (*decided != raw) \
+ { \
+ const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
+ int __n = n; \
+ int any = 0; \
+ while (*rp == ' ') \
+ ++rp; \
+ val = 0; \
+ do { \
+ val *= 10; \
+ while (*alts != '\0') \
+ { \
+ size_t len = strlen (alts); \
+ if (strncasecmp (alts, rp, len) == 0) \
+ break; \
+ alts += len + 1; \
+ ++val; \
+ } \
+ if (*alts == '\0') \
+ { \
+ if (*decided == not && ! any) \
+ goto do_normal; \
+ /* If we haven't read anything it's an error. */ \
+ if (! any) \
+ return NULL; \
+ /* Correct the premature multiplication. */ \
+ val /= 10; \
+ break; \
+ } \
+ else \
+ *decided = loc; \
+ } while (--__n > 0 && val * 10 <= to); \
+ if (val < from || val > to) \
+ return NULL; \
+ } \
+ else \
+ { \
+ do_normal: \
+ get_number (from, to, n); \
+ } \
+ 0; \
+ })
+#else
+# define get_alt_number(from, to, n) \
+ /* We don't have the alternate representation. */ \
+ get_number(from, to, n)
+#endif
+#define recursive(new_fmt) \
+ (*(new_fmt) != '\0' \
+ && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL)
+
+
+#ifdef _LIBC
+/* This is defined in locale/C-time.c in the GNU libc. */
+extern const struct locale_data _nl_C_LC_TIME;
+extern const unsigned short int __mon_yday[2][13];
+
+# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
+# define ab_weekday_name \
+ (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
+# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
+# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
+# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
+# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
+# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
+# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
+# define HERE_T_FMT_AMPM \
+ (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
+# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
+
+# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
+#else
+static char const weekday_name[][10] =
+ {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+ };
+static char const ab_weekday_name[][4] =
+ {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+static char const month_name[][10] =
+ {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ };
+static char const ab_month_name[][4] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
+# define HERE_D_FMT "%m/%d/%y"
+# define HERE_AM_STR "AM"
+# define HERE_PM_STR "PM"
+# define HERE_T_FMT_AMPM "%I:%M:%S %p"
+# define HERE_T_FMT "%H:%M:%S"
+
+static const unsigned short int __mon_yday[2][13] =
+ {
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ };
+#endif
+
+/* Status of lookup: do we use the locale data or the raw data? */
+enum locale_status { not, loc, raw };
+
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+# define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+/* Compute the day of the week. */
+static void
+day_of_the_week (struct tm *tm)
+{
+ /* We know that January 1st 1970 was a Thursday (= 4). Compute the
+ the difference between this data in the one on TM and so determine
+ the weekday. */
+ int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
+ int wday = (-473
+ + (365 * (tm->tm_year - 70))
+ + (corr_year / 4)
+ - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
+ + (((corr_year / 4) / 25) / 4)
+ + __mon_yday[0][tm->tm_mon]
+ + tm->tm_mday - 1);
+ tm->tm_wday = ((wday % 7) + 7) % 7;
+}
+
+/* Compute the day of the year. */
+static void
+day_of_the_year (struct tm *tm)
+{
+ tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
+ + (tm->tm_mday - 1));
+}
+
+static char *
+#ifdef _LIBC
+internal_function
+#endif
+strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
+ enum locale_status *decided, int era_cnt));
+
+static char *
+#ifdef _LIBC
+internal_function
+#endif
+strptime_internal (rp, fmt, tm, decided, era_cnt)
+ const char *rp;
+ const char *fmt;
+ struct tm *tm;
+ enum locale_status *decided;
+ int era_cnt;
+{
+ int cnt;
+ size_t val;
+ int have_I, is_pm;
+ int century, want_century;
+ int want_era;
+ int have_wday, want_xday;
+ int have_yday;
+ int have_mon, have_mday;
+#ifdef _NL_CURRENT
+ const char *rp_backup;
+ size_t num_eras;
+ struct era_entry *era;
+
+ era = NULL;
+#endif
+
+ have_I = is_pm = 0;
+ century = -1;
+ want_century = 0;
+ want_era = 0;
+
+ have_wday = want_xday = have_yday = have_mon = have_mday = 0;
+
+ while (*fmt != '\0')
+ {
+ /* A white space in the format string matches 0 more or white
+ space in the input string. */
+ if (isspace (*fmt))
+ {
+ while (isspace (*rp))
+ ++rp;
+ ++fmt;
+ continue;
+ }
+
+ /* Any character but `%' must be matched by the same character
+ in the input string. */
+ if (*fmt != '%')
+ {
+ match_char (*fmt++, *rp++);
+ continue;
+ }
+
+ ++fmt;
+#ifndef _NL_CURRENT
+ /* We need this for handling the `E' modifier. */
+ start_over:
+#endif
+
+#ifdef _NL_CURRENT
+ /* Make back up of current processing pointer. */
+ rp_backup = rp;
+#endif
+
+ switch (*fmt++)
+ {
+ case '%':
+ /* Match the `%' character itself. */
+ match_char ('%', *rp++);
+ break;
+ case 'a':
+ case 'A':
+ /* Match day of week. */
+ for (cnt = 0; cnt < 7; ++cnt)
+ {
+#ifdef _NL_CURRENT
+ if (*decided !=raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
+ weekday_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
+ ab_weekday_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ }
+#endif
+ if (*decided != loc
+ && (match_string (weekday_name[cnt], rp)
+ || match_string (ab_weekday_name[cnt], rp)))
+ {
+ *decided = raw;
+ break;
+ }
+ }
+ if (cnt == 7)
+ /* Does not match a weekday name. */
+ return NULL;
+ tm->tm_wday = cnt;
+ have_wday = 1;
+ break;
+ case 'b':
+ case 'B':
+ case 'h':
+ /* Match month name. */
+ for (cnt = 0; cnt < 12; ++cnt)
+ {
+#ifdef _NL_CURRENT
+ if (*decided !=raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
+ month_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
+ ab_month_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ }
+#endif
+ if (match_string (month_name[cnt], rp)
+ || match_string (ab_month_name[cnt], rp))
+ {
+ *decided = raw;
+ break;
+ }
+ }
+ if (cnt == 12)
+ /* Does not match a month name. */
+ return NULL;
+ tm->tm_mon = cnt;
+ want_xday = 1;
+ break;
+ case 'c':
+ /* Match locale's date and time format. */
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not &&
+ strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!recursive (HERE_D_T_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'C':
+ /* Match century number. */
+#ifdef _NL_CURRENT
+ match_century:
+#endif
+ get_number (0, 99, 2);
+ century = val;
+ want_xday = 1;
+ break;
+ case 'd':
+ case 'e':
+ /* Match day of month. */
+ get_number (1, 31, 2);
+ tm->tm_mday = val;
+ have_mday = 1;
+ want_xday = 1;
+ break;
+ case 'F':
+ if (!recursive ("%Y-%m-%d"))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'x':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+
+ FALL_THROUGH;
+ case 'D':
+ /* Match standard day format. */
+ if (!recursive (HERE_D_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'k':
+ case 'H':
+ /* Match hour in 24-hour clock. */
+ get_number (0, 23, 2);
+ tm->tm_hour = val;
+ have_I = 0;
+ break;
+ case 'I':
+ /* Match hour in 12-hour clock. */
+ get_number (1, 12, 2);
+ tm->tm_hour = val % 12;
+ have_I = 1;
+ break;
+ case 'j':
+ /* Match day number of year. */
+ get_number (1, 366, 3);
+ tm->tm_yday = val - 1;
+ have_yday = 1;
+ break;
+ case 'm':
+ /* Match number of month. */
+ get_number (1, 12, 2);
+ tm->tm_mon = val - 1;
+ have_mon = 1;
+ want_xday = 1;
+ break;
+ case 'M':
+ /* Match minute. */
+ get_number (0, 59, 2);
+ tm->tm_min = val;
+ break;
+ case 'n':
+ case 't':
+ /* Match any white space. */
+ while (isspace (*rp))
+ ++rp;
+ break;
+ case 'p':
+ /* Match locale's equivalent of AM/PM. */
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
+ *decided = loc;
+ is_pm = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!match_string (HERE_AM_STR, rp)) {
+ if (match_string (HERE_PM_STR, rp)) {
+ is_pm = 1;
+ } else {
+ return NULL;
+ }
+ }
+ break;
+ case 'r':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not &&
+ strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
+ HERE_T_FMT_AMPM))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!recursive (HERE_T_FMT_AMPM))
+ return NULL;
+ break;
+ case 'R':
+ if (!recursive ("%H:%M"))
+ return NULL;
+ break;
+ case 's':
+ {
+ /* The number of seconds may be very high so we cannot use
+ the `get_number' macro. Instead read the number
+ character for character and construct the result while
+ doing this. */
+ time_t secs = 0;
+ if (*rp < '0' || *rp > '9')
+ /* We need at least one digit. */
+ return NULL;
+
+ do
+ {
+ secs *= 10;
+ secs += *rp++ - '0';
+ }
+ while (*rp >= '0' && *rp <= '9');
+
+ if (localtime_r (&secs, tm) == NULL)
+ /* Error in function. */
+ return NULL;
+ }
+ break;
+ case 'S':
+ get_number (0, 61, 2);
+ tm->tm_sec = val;
+ break;
+ case 'X':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+
+ FALL_THROUGH;
+ case 'T':
+ if (!recursive (HERE_T_FMT))
+ return NULL;
+ break;
+ case 'u':
+ get_number (1, 7, 1);
+ tm->tm_wday = val % 7;
+ have_wday = 1;
+ break;
+ case 'g':
+ get_number (0, 99, 2);
+ /* XXX This cannot determine any field in TM. */
+ break;
+ case 'G':
+ if (*rp < '0' || *rp > '9')
+ return NULL;
+ /* XXX Ignore the number since we would need some more
+ information to compute a real date. */
+ do
+ ++rp;
+ while (*rp >= '0' && *rp <= '9');
+ break;
+ case 'U':
+ case 'V':
+ case 'W':
+ get_number (0, 53, 2);
+ /* XXX This cannot determine any field in TM without some
+ information. */
+ break;
+ case 'w':
+ /* Match number of weekday. */
+ get_number (0, 6, 1);
+ tm->tm_wday = val;
+ have_wday = 1;
+ break;
+ case 'y':
+#ifdef _NL_CURRENT
+ match_year_in_century:
+#endif
+ /* Match year within century. */
+ get_number (0, 99, 2);
+ /* The "Year 2000: The Millennium Rollover" paper suggests that
+ values in the range 69-99 refer to the twentieth century. */
+ tm->tm_year = val >= 69 ? val : val + 100;
+ /* Indicate that we want to use the century, if specified. */
+ want_century = 1;
+ want_xday = 1;
+ break;
+ case 'Y':
+ /* Match year including century number. */
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ want_century = 0;
+ want_xday = 1;
+ break;
+ case 'Z':
+ /* XXX How to handle this? */
+ break;
+ case 'E':
+#ifdef _NL_CURRENT
+ switch (*fmt++)
+ {
+ case 'c':
+ /* Match locale's alternate date and time format. */
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_D_T_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+ /* The C locale has no era information, so use the
+ normal representation. */
+ if (!recursive (HERE_D_T_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'C':
+ if (*decided != raw)
+ {
+ if (era_cnt >= 0)
+ {
+ era = _nl_select_era_entry (era_cnt);
+ if (match_string (era->era_name, rp))
+ {
+ *decided = loc;
+ break;
+ }
+ else
+ return NULL;
+ }
+ else
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+ _NL_TIME_ERA_NUM_ENTRIES);
+ for (era_cnt = 0; era_cnt < (int) num_eras;
+ ++era_cnt, rp = rp_backup)
+ {
+ era = _nl_select_era_entry (era_cnt);
+ if (match_string (era->era_name, rp))
+ {
+ *decided = loc;
+ break;
+ }
+ }
+ if (era_cnt == (int) num_eras)
+ {
+ era_cnt = -1;
+ if (*decided == loc)
+ return NULL;
+ }
+ else
+ break;
+ }
+
+ *decided = raw;
+ }
+ /* The C locale has no era information, so use the
+ normal representation. */
+ goto match_century;
+ case 'y':
+ if (*decided == raw)
+ goto match_year_in_century;
+
+ get_number(0, 9999, 4);
+ tm->tm_year = val;
+ want_era = 1;
+ want_xday = 1;
+ break;
+ case 'Y':
+ if (*decided != raw)
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+ _NL_TIME_ERA_NUM_ENTRIES);
+ for (era_cnt = 0; era_cnt < (int) num_eras;
+ ++era_cnt, rp = rp_backup)
+ {
+ era = _nl_select_era_entry (era_cnt);
+ if (recursive (era->era_format))
+ break;
+ }
+ if (era_cnt == (int) num_eras)
+ {
+ era_cnt = -1;
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ *decided = loc;
+ era_cnt = -1;
+ break;
+ }
+
+ *decided = raw;
+ }
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ want_century = 0;
+ want_xday = 1;
+ break;
+ case 'x':
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, D_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_D_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+ if (!recursive (HERE_D_FMT))
+ return NULL;
+ break;
+ case 'X':
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, T_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_T_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+ if (!recursive (HERE_T_FMT))
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+ break;
+#else
+ /* We have no information about the era format. Just use
+ the normal format. */
+ if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
+ && *fmt != 'x' && *fmt != 'X')
+ /* This is an illegal format. */
+ return NULL;
+
+ goto start_over;
+#endif
+ case 'O':
+ switch (*fmt++)
+ {
+ case 'd':
+ case 'e':
+ /* Match day of month using alternate numeric symbols. */
+ get_alt_number (1, 31, 2);
+ tm->tm_mday = val;
+ have_mday = 1;
+ want_xday = 1;
+ break;
+ case 'H':
+ /* Match hour in 24-hour clock using alternate numeric
+ symbols. */
+ get_alt_number (0, 23, 2);
+ tm->tm_hour = val;
+ have_I = 0;
+ break;
+ case 'I':
+ /* Match hour in 12-hour clock using alternate numeric
+ symbols. */
+ get_alt_number (1, 12, 2);
+ tm->tm_hour = val - 1;
+ have_I = 1;
+ break;
+ case 'm':
+ /* Match month using alternate numeric symbols. */
+ get_alt_number (1, 12, 2);
+ tm->tm_mon = val - 1;
+ have_mon = 1;
+ want_xday = 1;
+ break;
+ case 'M':
+ /* Match minutes using alternate numeric symbols. */
+ get_alt_number (0, 59, 2);
+ tm->tm_min = val;
+ break;
+ case 'S':
+ /* Match seconds using alternate numeric symbols. */
+ get_alt_number (0, 61, 2);
+ tm->tm_sec = val;
+ break;
+ case 'U':
+ case 'V':
+ case 'W':
+ get_alt_number (0, 53, 2);
+ /* XXX This cannot determine any field in TM without
+ further information. */
+ break;
+ case 'w':
+ /* Match number of weekday using alternate numeric symbols. */
+ get_alt_number (0, 6, 1);
+ tm->tm_wday = val;
+ have_wday = 1;
+ break;
+ case 'y':
+ /* Match year within century using alternate numeric symbols. */
+ get_alt_number (0, 99, 2);
+ tm->tm_year = val >= 69 ? val : val + 100;
+ want_xday = 1;
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ if (have_I && is_pm)
+ tm->tm_hour += 12;
+
+ if (century != -1)
+ {
+ if (want_century)
+ tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
+ else
+ /* Only the century, but not the year. Strange, but so be it. */
+ tm->tm_year = (century - 19) * 100;
+ }
+
+#ifdef _NL_CURRENT
+ if (era_cnt != -1)
+ {
+ era = _nl_select_era_entry(era_cnt);
+ if (want_era)
+ tm->tm_year = (era->start_date[0]
+ + ((tm->tm_year - era->offset)
+ * era->absolute_direction));
+ else
+ /* Era start year assumed. */
+ tm->tm_year = era->start_date[0];
+ }
+ else
+#endif
+ if (want_era)
+ return NULL;
+
+ if (want_xday && !have_wday)
+ {
+ if ( !(have_mon && have_mday) && have_yday)
+ {
+ /* We don't have tm_mon and/or tm_mday, compute them. */
+ int t_mon = 0;
+ while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
+ t_mon++;
+ if (!have_mon)
+ tm->tm_mon = t_mon - 1;
+ if (!have_mday)
+ tm->tm_mday =
+ (tm->tm_yday
+ - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
+ }
+ day_of_the_week (tm);
+ }
+ if (want_xday && !have_yday)
+ day_of_the_year (tm);
+
+ return discard_const_p(char, rp);
+}
+
+
+char *rep_strptime(const char *buf, const char *format, struct tm *tm)
+{
+ enum locale_status decided;
+
+#ifdef _NL_CURRENT
+ decided = not;
+#else
+ decided = raw;
+#endif
+ return strptime_internal (buf, format, tm, &decided, -1);
+}
diff --git a/lib/replace/system/README b/lib/replace/system/README
new file mode 100644
index 0000000..69a2b80
--- /dev/null
+++ b/lib/replace/system/README
@@ -0,0 +1,4 @@
+This directory contains wrappers around logical groups of system
+include files. The idea is to avoid #ifdef blocks in the main code,
+and instead put all the necessary conditional includes in subsystem
+specific header files in this directory.
diff --git a/lib/replace/system/capability.h b/lib/replace/system/capability.h
new file mode 100644
index 0000000..44b8d51
--- /dev/null
+++ b/lib/replace/system/capability.h
@@ -0,0 +1,57 @@
+#ifndef _system_capability_h
+#define _system_capability_h
+/*
+ Unix SMB/CIFS implementation.
+
+ capability system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_SYS_CAPABILITY_H
+
+#if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H) && !defined(_PPC_STATFS_H)
+#define _I386_STATFS_H
+#define _PPC_STATFS_H
+#define BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
+
+#if defined(BROKEN_RHEL5_SYS_CAP_HEADER) && !defined(_LINUX_TYPES_H)
+#define BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#endif
+
+#ifdef HAVE_POSIX_CAPABILITIES
+#include <sys/capability.h>
+#endif
+
+#ifdef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#undef _LINUX_TYPES_H
+#undef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND
+#endif
+
+#ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#undef _PPC_STATFS_H
+#undef _I386_STATFS_H
+#undef BROKEN_REDHAT_7_STATFS_WORKAROUND
+#endif
+
+#endif
+
+#endif
diff --git a/lib/replace/system/dir.h b/lib/replace/system/dir.h
new file mode 100644
index 0000000..497b5a7
--- /dev/null
+++ b/lib/replace/system/dir.h
@@ -0,0 +1,71 @@
+#ifndef _system_dir_h
+#define _system_dir_h
+/*
+ Unix SMB/CIFS implementation.
+
+ directory system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#ifndef HAVE_MKDIR_MODE
+#define mkdir(dir, mode) mkdir(dir)
+#endif
+
+#ifdef HAVE_LIBGEN_H
+# include <libgen.h>
+#endif
+
+/* Test whether a file name is the "." or ".." directory entries.
+ * These really should be inline functions.
+ */
+#ifndef ISDOT
+#define ISDOT(path) ( \
+ *((const char *)(path)) == '.' && \
+ *(((const char *)(path)) + 1) == '\0' \
+ )
+#endif
+
+#ifndef ISDOTDOT
+#define ISDOTDOT(path) ( \
+ *((const char *)(path)) == '.' && \
+ *(((const char *)(path)) + 1) == '.' && \
+ *(((const char *)(path)) + 2) == '\0' \
+ )
+#endif
+
+#endif
diff --git a/lib/replace/system/filesys.h b/lib/replace/system/filesys.h
new file mode 100644
index 0000000..8005b18
--- /dev/null
+++ b/lib/replace/system/filesys.h
@@ -0,0 +1,281 @@
+#ifndef _system_filesys_h
+#define _system_filesys_h
+/*
+ Unix SMB/CIFS implementation.
+
+ filesystem system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+/* This include is required on UNIX (*BSD, AIX, ...) for statfs() */
+#if !defined(LINUX) && defined(HAVE_SYS_MOUNT_H)
+#include <sys/mount.h>
+#endif
+
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+/* This include is required on Linux for statfs() */
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+
+#ifdef HAVE_SYS_FS_S5PARAM_H
+#include <sys/fs/s5param.h>
+#endif
+
+#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY)
+#include <sys/filsys.h>
+#endif
+
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif
+
+#ifdef HAVE_DUSTAT_H
+#include <sys/dustat.h>
+#endif
+
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_MODE_H
+/* apparently AIX needs this for S_ISLNK */
+#ifndef S_ISLNK
+#include <sys/mode.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+/* mutually exclusive (SuSE 8.2) */
+#if defined(HAVE_SYS_XATTR_H)
+#include <sys/xattr.h>
+#elif defined(HAVE_ATTR_XATTR_H)
+#include <attr/xattr.h>
+#elif defined(HAVE_SYS_ATTRIBUTES_H)
+#include <sys/attributes.h>
+#elif defined(HAVE_ATTR_ATTRIBUTES_H)
+#include <attr/attributes.h>
+#endif
+
+#ifdef HAVE_SYS_EA_H
+#include <sys/ea.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#ifndef XATTR_CREATE
+#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */
+#endif
+
+#ifndef XATTR_REPLACE
+#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
+#endif
+
+/* Some POSIX definitions for those without */
+
+#ifndef S_IFDIR
+#define S_IFDIR 0x4000
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode) ((mode & 0xF000) == S_IFDIR)
+#endif
+#ifndef S_IRWXU
+#define S_IRWXU 00700 /* read, write, execute: owner */
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 00400 /* read permission: owner */
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200 /* write permission: owner */
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100 /* execute permission: owner */
+#endif
+#ifndef S_IRWXG
+#define S_IRWXG 00070 /* read, write, execute: group */
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040 /* read permission: group */
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 00020 /* write permission: group */
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010 /* execute permission: group */
+#endif
+#ifndef S_IRWXO
+#define S_IRWXO 00007 /* read, write, execute: other */
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004 /* read permission: other */
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 00002 /* write permission: other */
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001 /* execute permission: other */
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 256
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifdef _WIN32
+#define mkdir(d,m) _mkdir(d)
+#endif
+
+#ifdef DISABLE_OPATH
+#undef O_PATH
+#endif
+
+/*
+ this allows us to use a uniform error handling for our xattr
+ wrappers
+*/
+#ifndef ENOATTR
+#define ENOATTR ENODATA
+#endif
+
+
+#if !defined(HAVE_XATTR_XATTR) || defined(XATTR_ADDITIONAL_OPTIONS)
+
+ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size);
+#define getxattr(path, name, value, size) rep_getxattr(path, name, value, size)
+/* define is in "replace.h" */
+ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size);
+#define fgetxattr(filedes, name, value, size) rep_fgetxattr(filedes, name, value, size)
+/* define is in "replace.h" */
+ssize_t rep_listxattr (const char *path, char *list, size_t size);
+#define listxattr(path, list, size) rep_listxattr(path, list, size)
+/* define is in "replace.h" */
+ssize_t rep_flistxattr (int filedes, char *list, size_t size);
+#define flistxattr(filedes, value, size) rep_flistxattr(filedes, value, size)
+/* define is in "replace.h" */
+int rep_removexattr (const char *path, const char *name);
+#define removexattr(path, name) rep_removexattr(path, name)
+/* define is in "replace.h" */
+int rep_fremovexattr (int filedes, const char *name);
+#define fremovexattr(filedes, name) rep_fremovexattr(filedes, name)
+/* define is in "replace.h" */
+int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags);
+#define setxattr(path, name, value, size, flags) rep_setxattr(path, name, value, size, flags)
+/* define is in "replace.h" */
+int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags);
+#define fsetxattr(filedes, name, value, size, flags) rep_fsetxattr(filedes, name, value, size, flags)
+/* define is in "replace.h" */
+
+#endif /* !defined(HAVE_XATTR_XATTR) || defined(XATTR_ADDITIONAL_OPTIONS) */
+
+#ifdef HAVE_LINUX_OPENAT2_H
+#include <linux/openat2.h>
+#else /* ! HAVE_LINUX_OPENAT2_H */
+/* how->resolve flags for openat2(2). */
+#define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings
+ (includes bind-mounts). */
+#define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
+ "magic-links". */
+#define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks
+ (implies OEXT_NO_MAGICLINKS) */
+#define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like
+ "..", symlinks, and absolute
+ paths which escape the dirfd. */
+#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
+ be scoped inside the dirfd
+ (similar to chroot(2)). */
+#define RESOLVE_CACHED 0x20 /* Only complete if resolution can be
+ completed through cached lookup. May
+ return -EAGAIN if that's not
+ possible. */
+struct __rep_open_how {
+ uint64_t flags;
+ uint64_t mode;
+ uint64_t resolve;
+};
+#define open_how __rep_open_how
+#endif /* ! HAVE_LINUX_OPENAT2_H */
+
+#ifndef HAVE_OPENAT2
+long rep_openat2(int dirfd, const char *pathname,
+ struct open_how *how, size_t size);
+#define openat2(dirfd, pathname, how, size) \
+ rep_openat2(dirfd, pathname, how, size)
+#endif /* !HAVE_OPENAT2 */
+
+#endif
diff --git a/lib/replace/system/glob.h b/lib/replace/system/glob.h
new file mode 100644
index 0000000..3e23db6
--- /dev/null
+++ b/lib/replace/system/glob.h
@@ -0,0 +1,37 @@
+#ifndef _system_glob_h
+#define _system_glob_h
+/*
+ Unix SMB/CIFS implementation.
+
+ glob system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
+#endif
diff --git a/lib/replace/system/gssapi.h b/lib/replace/system/gssapi.h
new file mode 100644
index 0000000..d8632d7
--- /dev/null
+++ b/lib/replace/system/gssapi.h
@@ -0,0 +1,53 @@
+#ifndef _system_gssapi_h
+#define _system_gssapi_h
+
+/*
+ Unix SMB/CIFS implementation.
+
+ GSSAPI system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_GSSAPI
+
+#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
+#include <gssapi/gssapi_ext.h>
+#elif defined(HAVE_GSSAPI_GSSAPI_H)
+#include <gssapi/gssapi.h>
+#elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H)
+#include <gssapi/gssapi_generic.h>
+#elif defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
+#endif
+
+#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H
+#include <gssapi/gssapi_krb5.h>
+#endif
+
+#ifdef HAVE_GSSAPI_GSSAPI_SPNEGO_H
+#include <gssapi/gssapi_spnego.h>
+#elif defined(HAVE_GSSAPI_SPNEGO_H)
+#include <gssapi_spnego.h>
+#endif
+
+#endif
+#endif
diff --git a/lib/replace/system/iconv.h b/lib/replace/system/iconv.h
new file mode 100644
index 0000000..3c8a71f
--- /dev/null
+++ b/lib/replace/system/iconv.h
@@ -0,0 +1,57 @@
+#ifndef _system_iconv_h
+#define _system_iconv_h
+/*
+ Unix SMB/CIFS implementation.
+
+ iconv memory system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined(HAVE_ICONV) && defined(HAVE_ICONV_H)
+#define HAVE_ICONV
+#endif
+
+#if !defined(HAVE_GICONV) && defined(HAVE_GICONV_H)
+#define HAVE_GICONV
+#endif
+
+#if !defined(HAVE_BICONV) && defined(HAVE_BICONV_H)
+#define HAVE_BICONV
+#endif
+
+#ifdef HAVE_NATIVE_ICONV
+#if defined(HAVE_ICONV)
+#include <iconv.h>
+#elif defined(HAVE_GICONV)
+#include <giconv.h>
+#elif defined(HAVE_BICONV)
+#include <biconv.h>
+#endif
+#endif /* HAVE_NATIVE_ICONV */
+
+/* needed for some systems without iconv. Doesn't really matter
+ what error code we use */
+#ifndef EILSEQ
+#define EILSEQ EIO
+#endif
+
+#endif
diff --git a/lib/replace/system/kerberos.h b/lib/replace/system/kerberos.h
new file mode 100644
index 0000000..ebd8657
--- /dev/null
+++ b/lib/replace/system/kerberos.h
@@ -0,0 +1,41 @@
+#ifndef _system_kerberos_h
+#define _system_kerberos_h
+
+/*
+ Unix SMB/CIFS implementation.
+
+ kerberos system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_KRB5
+
+#ifdef HAVE_KRB5_H
+#include <krb5.h>
+#endif
+
+#ifdef HAVE_COM_ERR_H
+#include <com_err.h>
+#endif
+
+#endif
+#endif
diff --git a/lib/replace/system/locale.h b/lib/replace/system/locale.h
new file mode 100644
index 0000000..504a3bb
--- /dev/null
+++ b/lib/replace/system/locale.h
@@ -0,0 +1,42 @@
+#ifndef _system_locale_h
+#define _system_locale_h
+
+/*
+ Unix SMB/CIFS implementation.
+
+ locale include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
+#endif
diff --git a/lib/replace/system/network.h b/lib/replace/system/network.h
new file mode 100644
index 0000000..1721d65
--- /dev/null
+++ b/lib/replace/system/network.h
@@ -0,0 +1,391 @@
+#ifndef _system_network_h
+#define _system_network_h
+/*
+ Unix SMB/CIFS implementation.
+
+ networking system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Jelmer Vernooij 2007
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef LIBREPLACE_NETWORK_CHECKS
+#error "AC_LIBREPLACE_NETWORK_CHECKS missing in configure"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_UNIXSOCKET
+#include <sys/un.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+/*
+ * The next three defines are needed to access the IPTOS_* options
+ * on some systems.
+ */
+
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_IP_H
+#include <netinet/in_ip.h>
+#endif
+
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+
+#include <limits.h>
+
+#ifndef HAVE_SOCKLEN_T
+#define HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#if !defined (HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA)
+/* define is in "replace.h" */
+char *rep_inet_ntoa(struct in_addr ip);
+#endif
+
+#ifndef HAVE_INET_PTON
+/* define is in "replace.h" */
+int rep_inet_pton(int af, const char *src, void *dst);
+#endif
+
+#ifndef HAVE_INET_NTOP
+/* define is in "replace.h" */
+const char *rep_inet_ntop(int af, const void *src, char *dst, socklen_t size);
+#endif
+
+#ifndef HAVE_INET_ATON
+/* define is in "replace.h" */
+int rep_inet_aton(const char *src, struct in_addr *dst);
+#endif
+
+#ifndef HAVE_CONNECT
+/* define is in "replace.h" */
+int rep_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+/* define is in "replace.h" */
+struct hostent *rep_gethostbyname(const char *name);
+#endif
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
+#ifndef HAVE_STRUCT_IFADDRS
+struct ifaddrs {
+ struct ifaddrs *ifa_next; /* Pointer to next struct */
+ char *ifa_name; /* Interface name */
+ unsigned int ifa_flags; /* Interface flags */
+ struct sockaddr *ifa_addr; /* Interface address */
+ struct sockaddr *ifa_netmask; /* Interface netmask */
+#undef ifa_dstaddr
+ struct sockaddr *ifa_dstaddr; /* P2P interface destination */
+ void *ifa_data; /* Address specific data */
+};
+#endif
+
+#ifndef HAVE_GETIFADDRS
+int rep_getifaddrs(struct ifaddrs **);
+#endif
+
+#ifndef HAVE_FREEIFADDRS
+void rep_freeifaddrs(struct ifaddrs *);
+#endif
+
+#ifndef HAVE_SOCKETPAIR
+/* define is in "replace.h" */
+int rep_socketpair(int d, int type, int protocol, int sv[2]);
+#endif
+
+/*
+ * Some systems have getaddrinfo but not the
+ * defines needed to use it.
+ */
+
+/* Various macros that ought to be in <netdb.h>, but might not be */
+
+#ifndef EAI_FAIL
+#define EAI_BADFLAGS (-1)
+#define EAI_NONAME (-2)
+#define EAI_AGAIN (-3)
+#define EAI_FAIL (-4)
+#define EAI_FAMILY (-6)
+#define EAI_SOCKTYPE (-7)
+#define EAI_SERVICE (-8)
+#define EAI_MEMORY (-10)
+#define EAI_SYSTEM (-11)
+#endif /* !EAI_FAIL */
+
+#ifndef AI_PASSIVE
+#define AI_PASSIVE 0x0001
+#endif
+
+#ifndef AI_CANONNAME
+#define AI_CANONNAME 0x0002
+#endif
+
+#ifndef AI_NUMERICHOST
+/*
+ * some platforms don't support AI_NUMERICHOST; define as zero if using
+ * the system version of getaddrinfo...
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_NUMERICHOST 0
+#else
+#define AI_NUMERICHOST 0x0004
+#endif
+#endif
+
+/*
+ * Some of the functions in source3/lib/util_sock.c use AI_ADDRCONFIG. On QNX
+ * 6.3.0, this macro is defined but, if it's used, getaddrinfo will fail. This
+ * prevents smbd from opening any sockets.
+ *
+ * If I undefine AI_ADDRCONFIG on such systems and define it to be 0,
+ * this works around the issue.
+ */
+#ifdef __QNX__
+#include <sys/neutrino.h>
+#if _NTO_VERSION == 630
+#undef AI_ADDRCONFIG
+#endif
+#endif
+#ifndef AI_ADDRCONFIG
+/*
+ * logic copied from AI_NUMERICHOST
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_ADDRCONFIG 0
+#else
+#define AI_ADDRCONFIG 0x0020
+#endif
+#endif
+
+#ifndef AI_NUMERICSERV
+/*
+ * logic copied from AI_NUMERICHOST
+ */
+#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
+#define AI_NUMERICSERV 0
+#else
+#define AI_NUMERICSERV 0x0400
+#endif
+#endif
+
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST 1
+#endif
+
+#ifndef NI_NUMERICSERV
+#define NI_NUMERICSERV 2
+#endif
+
+#ifndef NI_NOFQDN
+#define NI_NOFQDN 4
+#endif
+
+#ifndef NI_NAMEREQD
+#define NI_NAMEREQD 8
+#endif
+
+#ifndef NI_DGRAM
+#define NI_DGRAM 16
+#endif
+
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+
+/*
+ * glibc on linux doesn't seem to have MSG_WAITALL
+ * defined. I think the kernel has it though..
+ */
+#ifndef MSG_WAITALL
+#define MSG_WAITALL 0
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT EINVAL
+#endif
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN HOST_NAME_MAX
+#endif
+
+#ifndef HAVE_SA_FAMILY_T
+#define HAVE_SA_FAMILY_T
+typedef unsigned short int sa_family_t;
+#endif
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+#define HAVE_STRUCT_SOCKADDR_STORAGE
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+#define sockaddr_storage sockaddr_in6
+#define ss_family sin6_family
+#define HAVE_SS_FAMILY 1
+#else /*HAVE_STRUCT_SOCKADDR_IN6*/
+#define sockaddr_storage sockaddr_in
+#define ss_family sin_family
+#define HAVE_SS_FAMILY 1
+#endif /*HAVE_STRUCT_SOCKADDR_IN6*/
+#endif /*HAVE_STRUCT_SOCKADDR_STORAGE*/
+
+#ifndef HAVE_SS_FAMILY
+#ifdef HAVE___SS_FAMILY
+#define ss_family __ss_family
+#define HAVE_SS_FAMILY 1
+#endif
+#endif
+
+#ifndef IOV_MAX
+# ifdef UIO_MAXIOV
+# define IOV_MAX UIO_MAXIOV
+# else
+# ifdef __sgi
+ /*
+ * IRIX 6.5 has sysconf(_SC_IOV_MAX)
+ * which might return 512 or bigger
+ */
+# define IOV_MAX 512
+# endif
+# ifdef __GNU__
+ /*
+ * GNU/Hurd does not have such hardcoded limitations. Use a reasonable
+ * amount.
+ */
+# define IOV_MAX 512
+# endif
+# endif
+#endif
+
+#ifndef PIPE_BUF
+# ifdef __GNU__
+ /*
+ * GNU/Hurd does not have such hardcoded limitations. But it has to support
+ * the minimum POSIX value anyway.
+ */
+# define PIPE_BUF 512
+# endif
+#endif
+
+#ifndef HAVE_STRUCT_ADDRINFO
+#define HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ socklen_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+#endif /* HAVE_STRUCT_ADDRINFO */
+
+#if !defined(HAVE_GETADDRINFO)
+#include "getaddrinfo.h"
+#endif
+
+/* Needed for some systems that don't define it (Solaris). */
+#ifndef ifr_netmask
+#define ifr_netmask ifr_addr
+#endif
+
+/* Some old Linux systems have broken header files */
+#ifdef HAVE_IPV6
+#ifdef HAVE_LINUX_IPV6_V6ONLY_26
+#define IPV6_V6ONLY 26
+#endif /* HAVE_LINUX_IPV6_V6ONLY_26 */
+#endif /* HAVE_IPV6 */
+
+#ifndef SCOPE_DELIMITER
+#define SCOPE_DELIMITER '%'
+#endif
+
+#endif
diff --git a/lib/replace/system/passwd.h b/lib/replace/system/passwd.h
new file mode 100644
index 0000000..ecc9f60
--- /dev/null
+++ b/lib/replace/system/passwd.h
@@ -0,0 +1,92 @@
+#ifndef _system_passwd_h
+#define _system_passwd_h
+
+/*
+ Unix SMB/CIFS implementation.
+
+ passwd system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#ifdef HAVE_SYS_SECURITY_H
+#include <sys/security.h>
+#include <prot.h>
+#define PASSWORD_LENGTH 16
+#endif /* HAVE_SYS_SECURITY_H */
+
+#ifdef HAVE_GETPWANAM
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+
+#ifdef HAVE_COMPAT_H
+#include <compat.h>
+#endif
+
+#ifndef NGROUPS_MAX
+#define NGROUPS_MAX 32 /* Guess... */
+#endif
+
+/* what is the longest significant password available on your system?
+ Knowing this speeds up password searches a lot */
+#ifndef PASSWORD_LENGTH
+#define PASSWORD_LENGTH 8
+#endif
+
+
+#ifndef ALLOW_CHANGE_PASSWORD
+#if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
+#define ALLOW_CHANGE_PASSWORD 1
+#endif
+#endif
+
+#if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID)
+#define ULTRIX_AUTH 1
+#endif
+
+#endif
diff --git a/lib/replace/system/python.h b/lib/replace/system/python.h
new file mode 100644
index 0000000..b242bae
--- /dev/null
+++ b/lib/replace/system/python.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SAMBA_PYTHON_H
+#define _SAMBA_PYTHON_H
+
+/*
+ * With Python 3.6 Cpython started to require C99. With Python 3.12 they
+ * started to mix code and variable declarations so disable the warnings.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
+#include <Python.h>
+#pragma GCC diagnostic pop
+
+#endif /* _SAMBA_PYTHON_H */
diff --git a/lib/replace/system/readline.h b/lib/replace/system/readline.h
new file mode 100644
index 0000000..2937962
--- /dev/null
+++ b/lib/replace/system/readline.h
@@ -0,0 +1,61 @@
+#ifndef _system_readline_h
+#define _system_readline_h
+/*
+ Unix SMB/CIFS implementation.
+
+ Readline wrappers
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_LIBREADLINE
+# ifdef HAVE_READLINE_READLINE_H
+# ifdef HAVE_READLINE_READLINE_WORKAROUND
+# define _FUNCTION_DEF
+# endif
+# include <readline/readline.h>
+# ifdef HAVE_READLINE_HISTORY_H
+# include <readline/history.h>
+# endif
+# else
+# ifdef HAVE_READLINE_H
+# include <readline.h>
+# ifdef HAVE_HISTORY_H
+# include <history.h>
+# endif
+# else
+# undef HAVE_LIBREADLINE
+# endif
+# endif
+#endif
+
+#ifdef HAVE_NEW_LIBREADLINE
+#ifdef HAVE_CPPFUNCTION
+# define RL_COMPLETION_CAST (CPPFunction *)
+#elif defined(HAVE_RL_COMPLETION_T)
+# define RL_COMPLETION_CAST (rl_completion_t *)
+#else
+# define RL_COMPLETION_CAST
+#endif
+#else
+/* This type is missing from libreadline<4.0 (approximately) */
+# define RL_COMPLETION_CAST
+#endif /* HAVE_NEW_LIBREADLINE */
+
+#endif
diff --git a/lib/replace/system/select.h b/lib/replace/system/select.h
new file mode 100644
index 0000000..11c5390
--- /dev/null
+++ b/lib/replace/system/select.h
@@ -0,0 +1,77 @@
+#ifndef _system_select_h
+#define _system_select_h
+/*
+ Unix SMB/CIFS implementation.
+
+ select system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_EPOLL_H
+#include <sys/epoll.h>
+#endif
+
+#ifndef SELECT_CAST
+#define SELECT_CAST
+#endif
+
+#ifdef HAVE_POLL
+
+#include <poll.h>
+
+#else
+
+/* Type used for the number of file descriptors. */
+typedef unsigned long int nfds_t;
+
+/* Data structure describing a polling request. */
+struct pollfd
+{
+ int fd; /* File descriptor to poll. */
+ short int events; /* Types of events poller cares about. */
+ short int revents; /* Types of events that actually occurred. */
+};
+
+/* Event types that can be polled for. These bits may be set in `events'
+ to indicate the interesting event types; they will appear in `revents'
+ to indicate the status of the file descriptor. */
+#define POLLIN 0x001 /* There is data to read. */
+#define POLLPRI 0x002 /* There is urgent data to read. */
+#define POLLOUT 0x004 /* Writing now will not block. */
+#define POLLRDNORM 0x040 /* Normal data may be read. */
+#define POLLRDBAND 0x080 /* Priority data may be read. */
+#define POLLWRNORM 0x100 /* Writing now will not block. */
+#define POLLWRBAND 0x200 /* Priority data may be written. */
+#define POLLERR 0x008 /* Error condition. */
+#define POLLHUP 0x010 /* Hung up. */
+#define POLLNVAL 0x020 /* Invalid polling request. */
+
+/* define is in "replace.h" */
+int rep_poll(struct pollfd *fds, nfds_t nfds, int timeout);
+
+#endif
+
+#endif
diff --git a/lib/replace/system/shmem.h b/lib/replace/system/shmem.h
new file mode 100644
index 0000000..64fe39b
--- /dev/null
+++ b/lib/replace/system/shmem.h
@@ -0,0 +1,59 @@
+#ifndef _system_shmem_h
+#define _system_shmem_h
+/*
+ Unix SMB/CIFS implementation.
+
+ shared memory system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#if defined(HAVE_SYS_IPC_H)
+#include <sys/ipc.h>
+#endif /* HAVE_SYS_IPC_H */
+
+#if defined(HAVE_SYS_SHM_H)
+#include <sys/shm.h>
+#endif /* HAVE_SYS_SHM_H */
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+/* NetBSD doesn't have these */
+#ifndef SHM_R
+#define SHM_R 0400
+#endif
+
+#ifndef SHM_W
+#define SHM_W 0200
+#endif
+
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#endif
diff --git a/lib/replace/system/syslog.h b/lib/replace/system/syslog.h
new file mode 100644
index 0000000..104be1d
--- /dev/null
+++ b/lib/replace/system/syslog.h
@@ -0,0 +1,70 @@
+#ifndef _system_syslog_h
+#define _system_syslog_h
+/*
+ Unix SMB/CIFS implementation.
+
+ syslog system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#else
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
+#endif
+
+/* For sys_adminlog(). */
+#ifndef LOG_EMERG
+#define LOG_EMERG 0 /* system is unusable */
+#endif
+
+#ifndef LOG_ALERT
+#define LOG_ALERT 1 /* action must be taken immediately */
+#endif
+
+#ifndef LOG_CRIT
+#define LOG_CRIT 2 /* critical conditions */
+#endif
+
+#ifndef LOG_ERR
+#define LOG_ERR 3 /* error conditions */
+#endif
+
+#ifndef LOG_WARNING
+#define LOG_WARNING 4 /* warning conditions */
+#endif
+
+#ifndef LOG_NOTICE
+#define LOG_NOTICE 5 /* normal but significant condition */
+#endif
+
+#ifndef LOG_INFO
+#define LOG_INFO 6 /* informational */
+#endif
+
+#ifndef LOG_DEBUG
+#define LOG_DEBUG 7 /* debug-level messages */
+#endif
+
+#endif
diff --git a/lib/replace/system/terminal.h b/lib/replace/system/terminal.h
new file mode 100644
index 0000000..9ad601a
--- /dev/null
+++ b/lib/replace/system/terminal.h
@@ -0,0 +1,46 @@
+#ifndef _system_terminal_h
+#define _system_terminal_h
+/*
+ Unix SMB/CIFS implementation.
+
+ terminal system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef SUNOS4
+/* on SUNOS4 termios.h conflicts with sys/ioctl.h */
+#undef HAVE_TERMIOS_H
+#endif
+
+
+#if defined(HAVE_TERMIOS_H)
+/* POSIX terminal handling. */
+#include <termios.h>
+#elif defined(HAVE_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <termio.h>
+#elif defined(HAVE_SYS_TERMIO_H)
+/* Older SYSV terminal handling - don't use if we can avoid it. */
+#include <sys/termio.h>
+#endif
+
+#endif
diff --git a/lib/replace/system/threads.h b/lib/replace/system/threads.h
new file mode 100644
index 0000000..d189ed6
--- /dev/null
+++ b/lib/replace/system/threads.h
@@ -0,0 +1,72 @@
+#ifndef _system_threads_h
+#define _system_threads_h
+/*
+ Unix SMB/CIFS implementation.
+
+ macros to go along with the lib/replace/ portability layer code
+
+ Copyright (C) Volker Lendecke 2012
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <pthread.h>
+
+#if defined(HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP) && \
+ !defined(HAVE_PTHREAD_MUTEXATTR_SETROBUST)
+#define pthread_mutexattr_setrobust pthread_mutexattr_setrobust_np
+#endif
+
+#if defined(HAVE_DECL_PTHREAD_MUTEX_ROBUST_NP) && \
+ !defined(HAVE_DECL_PTHREAD_MUTEX_ROBUST)
+#define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP
+#endif
+
+#if defined(HAVE_PTHREAD_MUTEX_CONSISTENT_NP) && \
+ !defined(HAVE_PTHREAD_MUTEX_CONSISTENT)
+#define pthread_mutex_consistent pthread_mutex_consistent_np
+#endif
+
+#ifdef HAVE_STDATOMIC_H
+#include <stdatomic.h>
+#endif
+
+#ifndef HAVE_ATOMIC_THREAD_FENCE
+#ifdef HAVE___ATOMIC_THREAD_FENCE
+#define atomic_thread_fence(__ignore_order) __atomic_thread_fence(__ATOMIC_SEQ_CST)
+#define HAVE_ATOMIC_THREAD_FENCE 1
+#endif /* HAVE___ATOMIC_THREAD_FENCE */
+#endif /* not HAVE_ATOMIC_THREAD_FENCE */
+
+#ifndef HAVE_ATOMIC_THREAD_FENCE
+#ifdef HAVE___SYNC_SYNCHRONIZE
+#define atomic_thread_fence(__ignore_order) __sync_synchronize()
+#define HAVE_ATOMIC_THREAD_FENCE 1
+#endif /* HAVE___SYNC_SYNCHRONIZE */
+#endif /* not HAVE_ATOMIC_THREAD_FENCE */
+
+#ifndef HAVE_ATOMIC_THREAD_FENCE
+#ifdef HAVE_ATOMIC_THREAD_FENCE_SUPPORT
+#error mismatch_error_between_configure_test_and_header
+#endif
+/* make sure the build fails if someone uses it without checking the define */
+#define atomic_thread_fence(__order) \
+ __function__atomic_thread_fence_not_available_on_this_platform__()
+#endif /* not HAVE_ATOMIC_THREAD_FENCE */
+
+#endif
diff --git a/lib/replace/system/time.h b/lib/replace/system/time.h
new file mode 100644
index 0000000..272fe84
--- /dev/null
+++ b/lib/replace/system/time.h
@@ -0,0 +1,106 @@
+#ifndef _system_time_h
+#define _system_time_h
+/*
+ Unix SMB/CIFS implementation.
+
+ time system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#else
+struct utimbuf {
+ time_t actime; /* access time */
+ time_t modtime; /* modification time */
+};
+#endif
+
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec {
+ time_t tv_sec; /* Seconds. */
+ long tv_nsec; /* Nanoseconds. */
+};
+#endif
+
+#ifndef HAVE_MKTIME
+/* define is in "replace.h" */
+time_t rep_mktime(struct tm *t);
+#endif
+
+#ifndef HAVE_TIMEGM
+/* define is in "replace.h" */
+time_t rep_timegm(struct tm *tm);
+#endif
+
+#ifndef HAVE_UTIME
+/* define is in "replace.h" */
+int rep_utime(const char *filename, const struct utimbuf *buf);
+#endif
+
+#ifndef HAVE_UTIMES
+/* define is in "replace.h" */
+int rep_utimes(const char *filename, const struct timeval tv[2]);
+#endif
+
+#ifndef HAVE_CLOCK_GETTIME
+/* CLOCK_REALTIME is required by POSIX */
+#define CLOCK_REALTIME 0
+typedef int clockid_t;
+int rep_clock_gettime(clockid_t clk_id, struct timespec *tp);
+#endif
+/* make sure we have a best effort CUSTOM_CLOCK_MONOTONIC we can rely on.
+ *
+ * on AIX the values of CLOCK_* are cast expressions, not integer constants,
+ * this prevents them from being compared against in a preprocessor directive.
+ * The following ...IS_* macros can be used to check which clock is in use.
+ */
+#if defined(CLOCK_MONOTONIC)
+#define CUSTOM_CLOCK_MONOTONIC CLOCK_MONOTONIC
+#define CUSTOM_CLOCK_MONOTONIC_IS_MONOTONIC
+#elif defined(CLOCK_HIGHRES)
+#define CUSTOM_CLOCK_MONOTONIC CLOCK_HIGHRES
+#define CUSTOM_CLOCK_MONOTONIC_IS_HIGHRES
+#else
+#define CUSTOM_CLOCK_MONOTONIC CLOCK_REALTIME
+#define CUSTOM_CLOCK_MONOTONIC_IS_REALTIME
+#endif
+
+#ifndef UTIME_NOW
+#define UTIME_NOW ((1l << 30) - 1l)
+#endif
+#ifndef UTIME_OMIT
+#define UTIME_OMIT ((1l << 30) - 2l)
+#endif
+
+#endif
diff --git a/lib/replace/system/wait.h b/lib/replace/system/wait.h
new file mode 100644
index 0000000..1f5fcd9
--- /dev/null
+++ b/lib/replace/system/wait.h
@@ -0,0 +1,55 @@
+#ifndef _system_wait_h
+#define _system_wait_h
+/*
+ Unix SMB/CIFS implementation.
+
+ waitpid system include wrappers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef HAVE_SYS_UCONTEXT_H
+#include <sys/ucontext.h>
+#endif
+
+#if !defined(HAVE_SIG_ATOMIC_T_TYPE)
+typedef int sig_atomic_t;
+#endif
+
+#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
+int rep_waitpid(pid_t pid,int *status,int options);
+#endif
+
+#endif
diff --git a/lib/replace/system/wscript_configure b/lib/replace/system/wscript_configure
new file mode 100644
index 0000000..b51d917
--- /dev/null
+++ b/lib/replace/system/wscript_configure
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# solaris variants of getXXent_r
+conf.CHECK_C_PROTOTYPE('getpwent_r',
+ 'struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)',
+ define='SOLARIS_GETPWENT_R', headers='pwd.h')
+conf.CHECK_C_PROTOTYPE('getgrent_r',
+ 'struct group *getgrent_r(struct group *src, char *buf, int buflen)',
+ define='SOLARIS_GETGRENT_R', headers='grp.h')
+
+# the irix variants
+conf.CHECK_C_PROTOTYPE('getpwent_r',
+ 'struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)',
+ define='SOLARIS_GETPWENT_R', headers='pwd.h')
+conf.CHECK_C_PROTOTYPE('getgrent_r',
+ 'struct group *getgrent_r(struct group *src, char *buf, size_t buflen)',
+ define='SOLARIS_GETGRENT_R', headers='grp.h')
+
diff --git a/lib/replace/tests/getifaddrs.c b/lib/replace/tests/getifaddrs.c
new file mode 100644
index 0000000..8d575af
--- /dev/null
+++ b/lib/replace/tests/getifaddrs.c
@@ -0,0 +1,105 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * libreplace getifaddrs test
+ *
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * ** NOTE! The following LGPL license applies to the replace
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AUTOCONF_TEST
+#include "replace.h"
+#include "system/network.h"
+#include "replace-test.h"
+#endif
+
+#ifdef HAVE_INET_NTOP
+#define rep_inet_ntop inet_ntop
+#endif
+
+static const char *format_sockaddr(struct sockaddr *addr,
+ char *addrstring,
+ socklen_t addrlen)
+{
+ const char *result = NULL;
+
+ if (addr->sa_family == AF_INET) {
+ result = rep_inet_ntop(AF_INET,
+ &((struct sockaddr_in *)addr)->sin_addr,
+ addrstring,
+ addrlen);
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ } else if (addr->sa_family == AF_INET6) {
+ result = rep_inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *)addr)->sin6_addr,
+ addrstring,
+ addrlen);
+#endif
+ }
+ return result;
+}
+
+int getifaddrs_test(void)
+{
+ struct ifaddrs *ifs = NULL;
+ struct ifaddrs *ifs_head = NULL;
+ int ret;
+
+ ret = getifaddrs(&ifs);
+ ifs_head = ifs;
+ if (ret != 0) {
+ fprintf(stderr, "getifaddrs() failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ while (ifs) {
+ printf("%-10s ", ifs->ifa_name);
+ if (ifs->ifa_addr != NULL) {
+ char addrstring[INET6_ADDRSTRLEN];
+ const char *result;
+
+ result = format_sockaddr(ifs->ifa_addr,
+ addrstring,
+ sizeof(addrstring));
+ if (result != NULL) {
+ printf("IP=%s ", addrstring);
+ }
+
+ if (ifs->ifa_netmask != NULL) {
+ result = format_sockaddr(ifs->ifa_netmask,
+ addrstring,
+ sizeof(addrstring));
+ if (result != NULL) {
+ printf("NETMASK=%s", addrstring);
+ }
+ } else {
+ printf("AF=%d ", ifs->ifa_addr->sa_family);
+ }
+ } else {
+ printf("<no address>");
+ }
+
+ printf("\n");
+ ifs = ifs->ifa_next;
+ }
+
+ freeifaddrs(ifs_head);
+
+ return 0;
+}
diff --git a/lib/replace/tests/incoherent_mmap.c b/lib/replace/tests/incoherent_mmap.c
new file mode 100644
index 0000000..ee288fd
--- /dev/null
+++ b/lib/replace/tests/incoherent_mmap.c
@@ -0,0 +1,83 @@
+/* In OpenBSD, if you write to a file, another process doesn't see it
+ * in its mmap. Returns with exit status 0 if that is the case, 1 if
+ * it's coherent, and other if there's a problem. */
+#include <err.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define DATA "coherent.mmap"
+
+int main(int argc, char *argv[])
+{
+ int tochild[2], toparent[2];
+ int fd;
+ volatile unsigned char *map;
+ unsigned char *page;
+ const char *fname = argv[1];
+ char c = 0;
+
+ if (pipe(tochild) != 0 || pipe(toparent) != 0)
+ err(2, "Creating pipe");
+
+ if (!fname)
+ fname = DATA;
+
+ fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ if (fd < 0)
+ err(2, "opening %s", fname);
+ unlink(fname);
+
+ switch (fork()) {
+ case -1:
+ err(2, "Fork");
+ case 0:
+ close(tochild[1]);
+ close(toparent[0]);
+
+ /* Wait for parent to create file. */
+ if (read(tochild[0], &c, 1) != 1)
+ err(2, "reading from parent");
+
+ /* Alter first byte. */
+ pwrite(fd, &c, 1, 0);
+
+ if (write(toparent[1], &c, 1) != 1)
+ err(2, "writing to parent");
+ exit(0);
+
+ default:
+ close(tochild[0]);
+ close(toparent[1]);
+
+ /* Create a file and mmap it. */
+ page = malloc(getpagesize());
+ memset(page, 0x42, getpagesize());
+ if (write(fd, page, getpagesize()) != getpagesize())
+ err(2, "writing first page");
+ map = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED)
+ err(2, "mapping file");
+
+ if (*map != 0x42)
+ errx(2, "first byte isn't 0x42!");
+
+ /* Tell child to alter file. */
+ if (write(tochild[1], &c, 1) != 1)
+ err(2, "writing to child");
+
+ if (read(toparent[0], &c, 1) != 1)
+ err(2, "reading from child");
+
+ if (*map)
+ errx(0, "mmap incoherent: first byte isn't 0.");
+
+ exit(1);
+ }
+}
diff --git a/lib/replace/tests/main.c b/lib/replace/tests/main.c
new file mode 100644
index 0000000..94264d7
--- /dev/null
+++ b/lib/replace/tests/main.c
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libreplace tests
+
+ Copyright (C) Jelmer Vernooij 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "replace-testsuite.h"
+
+int main(void)
+{
+ bool ret = torture_local_replace(NULL);
+ if (ret)
+ return 0;
+ return -1;
+}
diff --git a/lib/replace/tests/os2_delete.c b/lib/replace/tests/os2_delete.c
new file mode 100644
index 0000000..a3e45f7
--- /dev/null
+++ b/lib/replace/tests/os2_delete.c
@@ -0,0 +1,135 @@
+/*
+ test readdir/unlink pattern that OS/2 uses
+ tridge@samba.org July 2005
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include "replace-test.h"
+
+#define NUM_FILES 700
+#define READDIR_SIZE 100
+#define DELETE_SIZE 4
+
+#define TESTDIR "test.dir"
+
+static int test_readdir_os2_delete_ret;
+
+#define FAILED(d) (printf("failure: readdir [\nFailed for %s - %d = %s\n]\n", d, errno, strerror(errno)), test_readdir_os2_delete_ret = 1)
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifdef _WIN32
+#define mkdir(d,m) _mkdir(d)
+#endif
+
+static void cleanup(void)
+{
+ /* I'm a lazy bastard */
+ if (system("rm -rf " TESTDIR)) {
+ FAILED("system");
+ }
+ mkdir(TESTDIR, 0700) == 0 || FAILED("mkdir");
+}
+
+static void create_files(void)
+{
+ int i;
+ for (i=0;i<NUM_FILES;i++) {
+ char fname[40];
+ int fd;
+ snprintf(fname, sizeof(fname), TESTDIR "/test%u.txt", i);
+ fd = open(fname, O_CREAT|O_RDWR, 0600);
+ if (fd < 0) {
+ FAILED("open");
+ }
+ if (close(fd) != 0) {
+ FAILED("close");
+ }
+ }
+}
+
+static int os2_delete(DIR *d)
+{
+ off_t offsets[READDIR_SIZE];
+ int i, j;
+ struct dirent *de;
+ char names[READDIR_SIZE][256];
+
+ /* scan, remembering offsets */
+ for (i=0, de=readdir(d);
+ de && i < READDIR_SIZE;
+ de=readdir(d), i++) {
+ offsets[i] = telldir(d);
+ /* strlcpy not available here */
+ snprintf(names[i], sizeof(names[i]), "%s", de->d_name);
+ }
+
+ if (i == 0) {
+ return 0;
+ }
+
+ /* delete the first few */
+ for (j=0; j<MIN(i, DELETE_SIZE); j++) {
+ char fname[40];
+ snprintf(fname, sizeof(fname), TESTDIR "/%s", names[j]);
+ unlink(fname) == 0 || FAILED("unlink");
+ }
+
+ /* seek to just after the deletion */
+ seekdir(d, offsets[j-1]);
+
+ /* return number deleted */
+ return j;
+}
+
+int test_readdir_os2_delete(void)
+{
+ int total_deleted = 0;
+ DIR *d;
+ struct dirent *de;
+
+ test_readdir_os2_delete_ret = 0;
+
+ cleanup();
+ create_files();
+
+ d = opendir(TESTDIR "/test0.txt");
+ if (d != NULL) FAILED("opendir() on file succeed");
+ if (errno != ENOTDIR) FAILED("opendir() on file didn't give ENOTDIR");
+ if (d != NULL) closedir(d);
+
+ d = opendir(TESTDIR);
+
+ /* skip past . and .. */
+ de = readdir(d);
+ strcmp(de->d_name, ".") == 0 || FAILED("match .");
+ de = readdir(d);
+ strcmp(de->d_name, "..") == 0 || FAILED("match ..");
+
+ while (1) {
+ int n = os2_delete(d);
+ if (n == 0) break;
+ total_deleted += n;
+ }
+ closedir(d);
+
+ fprintf(stderr, "Deleted %d files of %d\n", total_deleted, NUM_FILES);
+
+ rmdir(TESTDIR) == 0 || FAILED("rmdir");
+
+ if (system("rm -rf " TESTDIR) == -1) {
+ FAILED("system");
+ }
+
+ return test_readdir_os2_delete_ret;
+}
diff --git a/lib/replace/tests/shared_mmap.c b/lib/replace/tests/shared_mmap.c
new file mode 100644
index 0000000..9d6e3fc
--- /dev/null
+++ b/lib/replace/tests/shared_mmap.c
@@ -0,0 +1,71 @@
+/* this tests whether we can use a shared writeable mmap on a file -
+ as needed for the mmap variant of FAST_SHARE_MODES */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define DATA "conftest.mmap"
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+int main(void)
+{
+ int *buf;
+ int i;
+ int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666);
+ int count=7;
+
+ if (fd == -1) exit(1);
+
+ for (i=0;i<10000;i++) {
+ write(fd,&i,sizeof(i));
+ }
+
+ close(fd);
+
+ if (fork() == 0) {
+ fd = open(DATA,O_RDWR);
+ if (fd == -1) exit(1);
+
+ buf = (int *)mmap(NULL, 10000*sizeof(int),
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ fd, 0);
+
+ while (count-- && buf[9124] != 55732) sleep(1);
+
+ if (count <= 0) exit(1);
+
+ buf[1763] = 7268;
+ exit(0);
+ }
+
+ fd = open(DATA,O_RDWR);
+ if (fd == -1) exit(1);
+
+ buf = (int *)mmap(NULL, 10000*sizeof(int),
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ fd, 0);
+
+ if (buf == (int *)-1) exit(1);
+
+ buf[9124] = 55732;
+
+ while (count-- && buf[1763] != 7268) sleep(1);
+
+ unlink(DATA);
+
+ if (count > 0) exit(0);
+ exit(1);
+}
diff --git a/lib/replace/tests/shared_mremap.c b/lib/replace/tests/shared_mremap.c
new file mode 100644
index 0000000..08040e2
--- /dev/null
+++ b/lib/replace/tests/shared_mremap.c
@@ -0,0 +1,51 @@
+/* this tests whether we can use mremap */
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define DATA "conftest.mmap"
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED (int *)-1
+#endif
+
+int main(void)
+{
+ int *buf;
+ int fd;
+ int err = 1;
+
+ fd = open(DATA, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd == -1) {
+ exit(1);
+ }
+
+ buf = (int *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, fd, 0);
+ if (buf == MAP_FAILED) {
+ goto done;
+ }
+
+ buf = mremap(buf, 0x1000, 0x2000, MREMAP_MAYMOVE);
+ if (buf == MAP_FAILED) {
+ goto done;
+ }
+
+ err = 0;
+done:
+ close(fd);
+ unlink(DATA);
+ exit(err);
+}
diff --git a/lib/replace/tests/snprintf.c b/lib/replace/tests/snprintf.c
new file mode 100644
index 0000000..77473f0
--- /dev/null
+++ b/lib/replace/tests/snprintf.c
@@ -0,0 +1,29 @@
+void foo(const char *format, ...)
+{
+ va_list ap;
+ int len;
+ char buf[20];
+ long long l = 1234567890;
+ l *= 100;
+
+ va_start(ap, format);
+ len = vsnprintf(buf, 0, format, ap);
+ va_end(ap);
+ if (len != 5) exit(1);
+
+ va_start(ap, format);
+ len = vsnprintf(0, 0, format, ap);
+ va_end(ap);
+ if (len != 5) exit(2);
+
+ if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(3);
+
+ if (snprintf(buf, 20, "%lld", l) != 12 || strcmp(buf, "123456789000") != 0) exit(4);
+ if (snprintf(buf, 20, "%zu", 123456789) != 9 || strcmp(buf, "123456789") != 0) exit(5);
+ if (snprintf(buf, 20, "%2\$d %1\$d", 3, 4) != 3 || strcmp(buf, "4 3") != 0) exit(6);
+ if (snprintf(buf, 20, "%s", 0) < 3) exit(7);
+
+ printf("1");
+ exit(0);
+}
+int main(void) { foo("hello"); }
diff --git a/lib/replace/tests/strptime.c b/lib/replace/tests/strptime.c
new file mode 100644
index 0000000..5bf03f5
--- /dev/null
+++ b/lib/replace/tests/strptime.c
@@ -0,0 +1,173 @@
+
+#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define true 1
+#define false 0
+
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+/* make printf a no-op */
+#define printf if(0) printf
+
+#else /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */
+
+#include "replace.h"
+#include "system/time.h"
+#include "replace-test.h"
+
+#endif /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */
+
+int libreplace_test_strptime(void)
+{
+ const char *s = "20070414101546Z";
+ char *ret;
+ struct tm t, t2;
+
+ memset(&t, 0, sizeof(t));
+ memset(&t2, 0, sizeof(t2));
+
+ printf("test: strptime\n");
+
+ ret = strptime(s, "%Y%m%d%H%M%S", &t);
+ if ( ret == NULL ) {
+ printf("failure: strptime [\n"
+ "returned NULL\n"
+ "]\n");
+ return false;
+ }
+
+ if ( *ret != 'Z' ) {
+ printf("failure: strptime [\n"
+ "ret doesn't point to 'Z'\n"
+ "]\n");
+ return false;
+ }
+
+ ret = strptime(s, "%Y%m%d%H%M%SZ", &t2);
+ if ( ret == NULL ) {
+ printf("failure: strptime [\n"
+ "returned NULL with Z\n"
+ "]\n");
+ return false;
+ }
+
+ if ( *ret != '\0' ) {
+ printf("failure: strptime [\n"
+ "ret doesn't point to '\\0'\n"
+ "]\n");
+ return false;
+ }
+
+#define CMP_TM_ELEMENT(t1,t2,elem) \
+ if (t1.elem != t2.elem) { \
+ printf("failure: strptime [\n" \
+ "result differs if the format string has a 'Z' at the end\n" \
+ "element: %s %d != %d\n" \
+ "]\n", \
+ __STRING(elen), t1.elem, t2.elem); \
+ return false; \
+ }
+
+ CMP_TM_ELEMENT(t,t2,tm_sec);
+ CMP_TM_ELEMENT(t,t2,tm_min);
+ CMP_TM_ELEMENT(t,t2,tm_hour);
+ CMP_TM_ELEMENT(t,t2,tm_mday);
+ CMP_TM_ELEMENT(t,t2,tm_mon);
+ CMP_TM_ELEMENT(t,t2,tm_year);
+ CMP_TM_ELEMENT(t,t2,tm_wday);
+ CMP_TM_ELEMENT(t,t2,tm_yday);
+ CMP_TM_ELEMENT(t,t2,tm_isdst);
+
+ if (t.tm_sec != 46) {
+ printf("failure: strptime [\n"
+ "tm_sec: expected: 46, got: %d\n"
+ "]\n",
+ t.tm_sec);
+ return false;
+ }
+
+ if (t.tm_min != 15) {
+ printf("failure: strptime [\n"
+ "tm_min: expected: 15, got: %d\n"
+ "]\n",
+ t.tm_min);
+ return false;
+ }
+
+ if (t.tm_hour != 10) {
+ printf("failure: strptime [\n"
+ "tm_hour: expected: 10, got: %d\n"
+ "]\n",
+ t.tm_hour);
+ return false;
+ }
+
+ if (t.tm_mday != 14) {
+ printf("failure: strptime [\n"
+ "tm_mday: expected: 14, got: %d\n"
+ "]\n",
+ t.tm_mday);
+ return false;
+ }
+
+ if (t.tm_mon != 3) {
+ printf("failure: strptime [\n"
+ "tm_mon: expected: 3, got: %d\n"
+ "]\n",
+ t.tm_mon);
+ return false;
+ }
+
+ if (t.tm_year != 107) {
+ printf("failure: strptime [\n"
+ "tm_year: expected: 107, got: %d\n"
+ "]\n",
+ t.tm_year);
+ return false;
+ }
+
+ if (t.tm_wday != 6) { /* saturday */
+ printf("failure: strptime [\n"
+ "tm_wday: expected: 6, got: %d\n"
+ "]\n",
+ t.tm_wday);
+ return false;
+ }
+
+ if (t.tm_yday != 103) {
+ printf("failure: strptime [\n"
+ "tm_yday: expected: 103, got: %d\n"
+ "]\n",
+ t.tm_yday);
+ return false;
+ }
+
+ /* we don't test this as it depends on the host configuration
+ if (t.tm_isdst != 0) {
+ printf("failure: strptime [\n"
+ "tm_isdst: expected: 0, got: %d\n"
+ "]\n",
+ t.tm_isdst);
+ return false;
+ }*/
+
+ printf("success: strptime\n");
+
+ return true;
+}
+
+#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME
+int main (void)
+{
+ int ret;
+ ret = libreplace_test_strptime();
+ if (ret == false) return 1;
+ return 0;
+}
+#endif
diff --git a/lib/replace/tests/testsuite.c b/lib/replace/tests/testsuite.c
new file mode 100644
index 0000000..58624f1
--- /dev/null
+++ b/lib/replace/tests/testsuite.c
@@ -0,0 +1,1227 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libreplace tests
+
+ Copyright (C) Jelmer Vernooij 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "replace-test.h"
+#include "replace-testsuite.h"
+
+/*
+ we include all the system/ include files here so that libreplace tests
+ them in the build farm
+*/
+#include "system/capability.h"
+#include "system/dir.h"
+#include "system/filesys.h"
+#include "system/glob.h"
+#include "system/iconv.h"
+#include "system/locale.h"
+#include "system/network.h"
+#include "system/passwd.h"
+#include "system/readline.h"
+#include "system/select.h"
+#include "system/shmem.h"
+#include "system/syslog.h"
+#include "system/terminal.h"
+#include "system/time.h"
+#include "system/wait.h"
+
+#define TESTFILE "testfile.dat"
+
+
+/*
+ test ftruncate() function
+ */
+static int test_ftruncate(void)
+{
+ struct stat st;
+ int fd;
+ const int size = 1234;
+ printf("test: ftruncate\n");
+ unlink(TESTFILE);
+ fd = open(TESTFILE, O_RDWR|O_CREAT, 0600);
+ if (fd == -1) {
+ printf("failure: ftruncate [\n"
+ "creating '%s' failed - %s\n]\n", TESTFILE, strerror(errno));
+ return false;
+ }
+ if (ftruncate(fd, size) != 0) {
+ printf("failure: ftruncate [\n%s\n]\n", strerror(errno));
+ close(fd);
+ return false;
+ }
+ if (fstat(fd, &st) != 0) {
+ printf("failure: ftruncate [\nfstat failed - %s\n]\n", strerror(errno));
+ close(fd);
+ return false;
+ }
+ if (st.st_size != size) {
+ printf("failure: ftruncate [\ngave wrong size %d - expected %d\n]\n",
+ (int)st.st_size, size);
+ close(fd);
+ return false;
+ }
+ unlink(TESTFILE);
+ printf("success: ftruncate\n");
+ close(fd);
+ return true;
+}
+
+/*
+ test strlcpy() function.
+ see http://www.gratisoft.us/todd/papers/strlcpy.html
+ */
+static int test_strlcpy(void)
+{
+ char buf[4];
+ const struct {
+ const char *src;
+ size_t result;
+ } tests[] = {
+ { "abc", 3 },
+ { "abcdef", 6 },
+ { "abcd", 4 },
+ { "", 0 },
+ { NULL, 0 }
+ };
+ int i;
+ printf("test: strlcpy\n");
+ for (i=0;tests[i].src;i++) {
+ if (strlcpy(buf, tests[i].src, sizeof(buf)) != tests[i].result) {
+ printf("failure: strlcpy [\ntest %d failed\n]\n", i);
+ return false;
+ }
+ }
+ printf("success: strlcpy\n");
+ return true;
+}
+
+static int test_strlcat(void)
+{
+ char tmp[10];
+ printf("test: strlcat\n");
+ strlcpy(tmp, "", sizeof(tmp));
+ if (strlcat(tmp, "bla", 3) != 3) {
+ printf("failure: strlcat [\ninvalid return code\n]\n");
+ return false;
+ }
+ if (strcmp(tmp, "bl") != 0) {
+ printf("failure: strlcat [\nexpected \"bl\", got \"%s\"\n]\n",
+ tmp);
+ return false;
+ }
+
+ strlcpy(tmp, "da", sizeof(tmp));
+ if (strlcat(tmp, "me", 4) != 4) {
+ printf("failure: strlcat [\nexpected \"dam\", got \"%s\"\n]\n",
+ tmp);
+ return false;
+ }
+
+ printf("success: strlcat\n");
+ return true;
+}
+
+static int test_mktime(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_initgroups(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_memmove(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_strdup(void)
+{
+ char *x;
+ int cmp;
+
+ printf("test: strdup\n");
+ x = strdup("bla");
+
+ cmp = strcmp("bla", x);
+ if (cmp != 0) {
+ printf("failure: strdup [\nfailed: expected \"bla\", got \"%s\"\n]\n",
+ x);
+ free(x);
+ return false;
+ }
+ free(x);
+ printf("success: strdup\n");
+ return true;
+}
+
+static int test_setlinebuf(void)
+{
+ printf("test: setlinebuf\n");
+ setlinebuf(stdout);
+ printf("success: setlinebuf\n");
+ return true;
+}
+
+static int test_vsyslog(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_timegm(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_setenv(void)
+{
+#define TEST_SETENV(key, value, overwrite, result) do { \
+ int _ret; \
+ char *_v; \
+ _ret = setenv(key, value, overwrite); \
+ if (_ret != 0) { \
+ printf("failure: setenv [\n" \
+ "setenv(%s, %s, %d) failed\n" \
+ "]\n", \
+ key, value, overwrite); \
+ return false; \
+ } \
+ _v=getenv(key); \
+ if (!_v) { \
+ printf("failure: setenv [\n" \
+ "getenv(%s) returned NULL\n" \
+ "]\n", \
+ key); \
+ return false; \
+ } \
+ if (strcmp(result, _v) != 0) { \
+ printf("failure: setenv [\n" \
+ "getenv(%s): '%s' != '%s'\n" \
+ "]\n", \
+ key, result, _v); \
+ return false; \
+ } \
+} while(0)
+
+#define TEST_UNSETENV(key) do { \
+ char *_v; \
+ unsetenv(key); \
+ _v=getenv(key); \
+ if (_v) { \
+ printf("failure: setenv [\n" \
+ "getenv(%s): NULL != '%s'\n" \
+ "]\n", \
+ SETENVTEST_KEY, _v); \
+ return false; \
+ } \
+} while (0)
+
+#define SETENVTEST_KEY "SETENVTESTKEY"
+#define SETENVTEST_VAL "SETENVTESTVAL"
+
+ printf("test: setenv\n");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"1", 0, SETENVTEST_VAL"1");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"2", 0, SETENVTEST_VAL"1");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"3", 1, SETENVTEST_VAL"3");
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"4", 1, SETENVTEST_VAL"4");
+ TEST_UNSETENV(SETENVTEST_KEY);
+ TEST_UNSETENV(SETENVTEST_KEY);
+ TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"5", 0, SETENVTEST_VAL"5");
+ TEST_UNSETENV(SETENVTEST_KEY);
+ TEST_UNSETENV(SETENVTEST_KEY);
+ printf("success: setenv\n");
+ return true;
+}
+
+static int test_strndup(void)
+{
+ char *x;
+ int cmp;
+
+ printf("test: strndup\n");
+ x = strndup("bla", 0);
+ cmp = strcmp(x, "");
+ free(x);
+ if (cmp != 0) {
+ printf("failure: strndup [\ninvalid\n]\n");
+ return false;
+ }
+
+ x = strndup("bla", 2);
+ cmp = strcmp(x, "bl");
+ free(x);
+ if (cmp != 0) {
+ printf("failure: strndup [\ninvalid\n]\n");
+ return false;
+ }
+
+#ifdef __GNUC__
+# if __GNUC__ < 11
+ /*
+ * This code will not compile with gcc11 -O3 anymore.
+ *
+ * error: ‘strndup’ specified bound 10 exceeds source size 4 [-Werror=stringop-overread]
+ * x = strndup("bla", 10);
+ * ^~~~~~~~~~~~~~~~~~
+ */
+ x = strndup("bla", 10);
+ cmp = strcmp(x, "bla");
+ free(x);
+ if (cmp != 0) {
+ printf("failure: strndup [\ninvalid\n]\n");
+ return false;
+ }
+# endif
+#endif /* __GNUC__ */
+
+ printf("success: strndup\n");
+ return true;
+}
+
+static int test_strnlen(void)
+{
+ char longlen[20] = { 0 };
+
+ printf("test: strnlen\n");
+ if (strnlen("bla", 2) != 2) {
+ printf("failure: strnlen [\nunexpected length\n]\n");
+ return false;
+ }
+
+ if (strnlen("some text\n", 0) != 0) {
+ printf("failure: strnlen [\nunexpected length\n]\n");
+ return false;
+ }
+
+ memcpy(longlen, "some text", 10);
+
+ if (strnlen(longlen, 20) != 9) {
+ printf("failure: strnlen [\nunexpected length\n]\n");
+ return false;
+ }
+
+ printf("success: strnlen\n");
+ return true;
+}
+
+static int test_waitpid(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_seteuid(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_setegid(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_asprintf(void)
+{
+ char *x = NULL;
+
+ printf("test: asprintf\n");
+ if (asprintf(&x, "%d", 9) != 1) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ free(x);
+ return false;
+ }
+ if (strcmp(x, "9") != 0) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ free(x);
+ return false;
+ }
+ if (asprintf(&x, "dat%s", "a") != 4) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ free(x);
+ return false;
+ }
+ if (strcmp(x, "data") != 0) {
+ printf("failure: asprintf [\ngenerate asprintf\n]\n");
+ free(x);
+ return false;
+ }
+ free(x);
+ printf("success: asprintf\n");
+ return true;
+}
+
+static int test_snprintf(void)
+{
+ char tmp[10];
+ printf("test: snprintf\n");
+ if (snprintf(tmp, 3, "foo%d", 9) != 4) {
+ printf("failure: snprintf [\nsnprintf return code failed\n]\n");
+ return false;
+ }
+
+ if (strcmp(tmp, "fo") != 0) {
+ printf("failure: snprintf [\nsnprintf failed\n]\n");
+ return false;
+ }
+
+ printf("success: snprintf\n");
+ return true;
+}
+
+static int test_vasprintf(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_vsnprintf(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_opendir(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_readdir(void)
+{
+ printf("test: readdir\n");
+ if (test_readdir_os2_delete() != 0) {
+ return false;
+ }
+ printf("success: readdir\n");
+ return true;
+}
+
+static int test_telldir(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_seekdir(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_dlopen(void)
+{
+ /* FIXME: test dlopen, dlsym, dlclose, dlerror */
+ return true;
+}
+
+
+static int test_chroot(void)
+{
+ /* FIXME: chroot() */
+ return true;
+}
+
+static int test_bzero(void)
+{
+ /* FIXME: bzero */
+ return true;
+}
+
+static int test_strerror(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_errno(void)
+{
+ printf("test: errno\n");
+ errno = 3;
+ if (errno != 3) {
+ printf("failure: errno [\nerrno failed\n]\n");
+ return false;
+ }
+
+ printf("success: errno\n");
+ return true;
+}
+
+static int test_mkdtemp(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_mkstemp(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_pread(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_pwrite(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_inet_ntoa(void)
+{
+ /* FIXME */
+ return true;
+}
+
+#define TEST_STRTO_X(type,fmt,func,str,base,res,diff,rrnoo) do {\
+ type _v; \
+ char _s[64]; \
+ char *_p = NULL;\
+ char *_ep = NULL; \
+ strlcpy(_s, str, sizeof(_s));\
+ if (diff >= 0) { \
+ _ep = &_s[diff]; \
+ } \
+ errno = 0; \
+ _v = func(_s, &_p, base); \
+ if (errno != rrnoo) { \
+ printf("failure: %s [\n" \
+ "\t%s\n" \
+ "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \
+ "\terrno: %d != %d\n" \
+ "]\n", \
+ __STRING(func), __location__, __STRING(func), \
+ str, diff, base, res, _v, rrnoo, errno); \
+ return false; \
+ } else if (_v != res) { \
+ printf("failure: %s [\n" \
+ "\t%s\n" \
+ "\t%s(\"%s\",%d,%d): " fmt " != " fmt "\n" \
+ "]\n", \
+ __STRING(func), __location__, __STRING(func), \
+ str, diff, base, res, _v); \
+ return false; \
+ } else if (_p != _ep) { \
+ printf("failure: %s [\n" \
+ "\t%s\n" \
+ "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \
+ "\tptr: %p - %p = %d != %d\n" \
+ "]\n", \
+ __STRING(func), __location__, __STRING(func), \
+ str, diff, base, res, _v, _ep, _p, (int)(diff - (_ep - _p)), diff); \
+ return false; \
+ } \
+} while (0)
+
+static int test_strtoll(void)
+{
+ printf("test: strtoll\n");
+
+#define TEST_STRTOLL(str,base,res,diff,errnoo) TEST_STRTO_X(long long int, "%lld", strtoll,str,base,res,diff,errnoo)
+
+ TEST_STRTOLL("15", 10, 15LL, 2, 0);
+ TEST_STRTOLL(" 15", 10, 15LL, 4, 0);
+ TEST_STRTOLL("15", 0, 15LL, 2, 0);
+ TEST_STRTOLL(" 15 ", 0, 15LL, 3, 0);
+ TEST_STRTOLL("+15", 10, 15LL, 3, 0);
+ TEST_STRTOLL(" +15", 10, 15LL, 5, 0);
+ TEST_STRTOLL("+15", 0, 15LL, 3, 0);
+ TEST_STRTOLL(" +15 ", 0, 15LL, 4, 0);
+ TEST_STRTOLL("-15", 10, -15LL, 3, 0);
+ TEST_STRTOLL(" -15", 10, -15LL, 5, 0);
+ TEST_STRTOLL("-15", 0, -15LL, 3, 0);
+ TEST_STRTOLL(" -15 ", 0, -15LL, 4, 0);
+ TEST_STRTOLL("015", 10, 15LL, 3, 0);
+ TEST_STRTOLL(" 015", 10, 15LL, 5, 0);
+ TEST_STRTOLL("015", 0, 13LL, 3, 0);
+ TEST_STRTOLL(" 015", 0, 13LL, 5, 0);
+ TEST_STRTOLL("0x15", 10, 0LL, 1, 0);
+ TEST_STRTOLL(" 0x15", 10, 0LL, 3, 0);
+ TEST_STRTOLL("0x15", 0, 21LL, 4, 0);
+ TEST_STRTOLL(" 0x15", 0, 21LL, 6, 0);
+
+ TEST_STRTOLL("10", 16, 16LL, 2, 0);
+ TEST_STRTOLL(" 10 ", 16, 16LL, 4, 0);
+ TEST_STRTOLL("0x10", 16, 16LL, 4, 0);
+ TEST_STRTOLL("0x10", 0, 16LL, 4, 0);
+ TEST_STRTOLL(" 0x10 ", 0, 16LL, 5, 0);
+ TEST_STRTOLL("+10", 16, 16LL, 3, 0);
+ TEST_STRTOLL(" +10 ", 16, 16LL, 5, 0);
+ TEST_STRTOLL("+0x10", 16, 16LL, 5, 0);
+ TEST_STRTOLL("+0x10", 0, 16LL, 5, 0);
+ TEST_STRTOLL(" +0x10 ", 0, 16LL, 6, 0);
+ TEST_STRTOLL("-10", 16, -16LL, 3, 0);
+ TEST_STRTOLL(" -10 ", 16, -16LL, 5, 0);
+ TEST_STRTOLL("-0x10", 16, -16LL, 5, 0);
+ TEST_STRTOLL("-0x10", 0, -16LL, 5, 0);
+ TEST_STRTOLL(" -0x10 ", 0, -16LL, 6, 0);
+ TEST_STRTOLL("010", 16, 16LL, 3, 0);
+ TEST_STRTOLL(" 010 ", 16, 16LL, 5, 0);
+ TEST_STRTOLL("-010", 16, -16LL, 4, 0);
+
+ TEST_STRTOLL("11", 8, 9LL, 2, 0);
+ TEST_STRTOLL("011", 8, 9LL, 3, 0);
+ TEST_STRTOLL("011", 0, 9LL, 3, 0);
+ TEST_STRTOLL("-11", 8, -9LL, 3, 0);
+ TEST_STRTOLL("-011", 8, -9LL, 4, 0);
+ TEST_STRTOLL("-011", 0, -9LL, 4, 0);
+
+ TEST_STRTOLL("011", 8, 9LL, 3, 0);
+ TEST_STRTOLL("011", 0, 9LL, 3, 0);
+ TEST_STRTOLL("-11", 8, -9LL, 3, 0);
+ TEST_STRTOLL("-011", 8, -9LL, 4, 0);
+ TEST_STRTOLL("-011", 0, -9LL, 4, 0);
+
+ TEST_STRTOLL("Text", 0, 0LL, 0, 0);
+
+ TEST_STRTOLL("9223372036854775807", 10, 9223372036854775807LL, 19, 0);
+ TEST_STRTOLL("9223372036854775807", 0, 9223372036854775807LL, 19, 0);
+ TEST_STRTOLL("9223372036854775808", 0, 9223372036854775807LL, 19, ERANGE);
+ TEST_STRTOLL("9223372036854775808", 10, 9223372036854775807LL, 19, ERANGE);
+ TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LL, 18, 0);
+ TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 18, 0);
+ TEST_STRTOLL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 16, 0);
+ TEST_STRTOLL("0x8000000000000000", 0, 9223372036854775807LL, 18, ERANGE);
+ TEST_STRTOLL("0x8000000000000000", 16, 9223372036854775807LL, 18, ERANGE);
+ TEST_STRTOLL("80000000000000000", 16, 9223372036854775807LL, 17, ERANGE);
+ TEST_STRTOLL("0777777777777777777777", 0, 9223372036854775807LL, 22, 0);
+ TEST_STRTOLL("0777777777777777777777", 8, 9223372036854775807LL, 22, 0);
+ TEST_STRTOLL("777777777777777777777", 8, 9223372036854775807LL, 21, 0);
+ TEST_STRTOLL("01000000000000000000000", 0, 9223372036854775807LL, 23, ERANGE);
+ TEST_STRTOLL("01000000000000000000000", 8, 9223372036854775807LL, 23, ERANGE);
+ TEST_STRTOLL("1000000000000000000000", 8, 9223372036854775807LL, 22, ERANGE);
+
+ TEST_STRTOLL("-9223372036854775808", 10, -9223372036854775807LL -1, 20, 0);
+ TEST_STRTOLL("-9223372036854775808", 0, -9223372036854775807LL -1, 20, 0);
+ TEST_STRTOLL("-9223372036854775809", 0, -9223372036854775807LL -1, 20, ERANGE);
+ TEST_STRTOLL("-9223372036854775809", 10, -9223372036854775807LL -1, 20, ERANGE);
+ TEST_STRTOLL("-0x8000000000000000", 0, -9223372036854775807LL -1, 19, 0);
+ TEST_STRTOLL("-0x8000000000000000", 16, -9223372036854775807LL -1, 19, 0);
+ TEST_STRTOLL("-8000000000000000", 16, -9223372036854775807LL -1, 17, 0);
+ TEST_STRTOLL("-0x8000000000000001", 0, -9223372036854775807LL -1, 19, ERANGE);
+ TEST_STRTOLL("-0x8000000000000001", 16, -9223372036854775807LL -1, 19, ERANGE);
+ TEST_STRTOLL("-80000000000000001", 16, -9223372036854775807LL -1, 18, ERANGE);
+ TEST_STRTOLL("-01000000000000000000000",0, -9223372036854775807LL -1, 24, 0);
+ TEST_STRTOLL("-01000000000000000000000",8, -9223372036854775807LL -1, 24, 0);
+ TEST_STRTOLL("-1000000000000000000000", 8, -9223372036854775807LL -1, 23, 0);
+ TEST_STRTOLL("-01000000000000000000001",0, -9223372036854775807LL -1, 24, ERANGE);
+ TEST_STRTOLL("-01000000000000000000001",8, -9223372036854775807LL -1, 24, ERANGE);
+ TEST_STRTOLL("-1000000000000000000001", 8, -9223372036854775807LL -1, 23, ERANGE);
+
+ printf("success: strtoll\n");
+ return true;
+}
+
+static int test_strtoull(void)
+{
+ printf("test: strtoull\n");
+
+#define TEST_STRTOULL(str,base,res,diff,errnoo) TEST_STRTO_X(long long unsigned int,"%llu",strtoull,str,base,res,diff,errnoo)
+
+ TEST_STRTOULL("15", 10, 15LLU, 2, 0);
+ TEST_STRTOULL(" 15", 10, 15LLU, 4, 0);
+ TEST_STRTOULL("15", 0, 15LLU, 2, 0);
+ TEST_STRTOULL(" 15 ", 0, 15LLU, 3, 0);
+ TEST_STRTOULL("+15", 10, 15LLU, 3, 0);
+ TEST_STRTOULL(" +15", 10, 15LLU, 5, 0);
+ TEST_STRTOULL("+15", 0, 15LLU, 3, 0);
+ TEST_STRTOULL(" +15 ", 0, 15LLU, 4, 0);
+ TEST_STRTOULL("-15", 10, 18446744073709551601LLU, 3, 0);
+ TEST_STRTOULL(" -15", 10, 18446744073709551601LLU, 5, 0);
+ TEST_STRTOULL("-15", 0, 18446744073709551601LLU, 3, 0);
+ TEST_STRTOULL(" -15 ", 0, 18446744073709551601LLU, 4, 0);
+ TEST_STRTOULL("015", 10, 15LLU, 3, 0);
+ TEST_STRTOULL(" 015", 10, 15LLU, 5, 0);
+ TEST_STRTOULL("015", 0, 13LLU, 3, 0);
+ TEST_STRTOULL(" 015", 0, 13LLU, 5, 0);
+ TEST_STRTOULL("0x15", 10, 0LLU, 1, 0);
+ TEST_STRTOULL(" 0x15", 10, 0LLU, 3, 0);
+ TEST_STRTOULL("0x15", 0, 21LLU, 4, 0);
+ TEST_STRTOULL(" 0x15", 0, 21LLU, 6, 0);
+
+ TEST_STRTOULL("10", 16, 16LLU, 2, 0);
+ TEST_STRTOULL(" 10 ", 16, 16LLU, 4, 0);
+ TEST_STRTOULL("0x10", 16, 16LLU, 4, 0);
+ TEST_STRTOULL("0x10", 0, 16LLU, 4, 0);
+ TEST_STRTOULL(" 0x10 ", 0, 16LLU, 5, 0);
+ TEST_STRTOULL("+10", 16, 16LLU, 3, 0);
+ TEST_STRTOULL(" +10 ", 16, 16LLU, 5, 0);
+ TEST_STRTOULL("+0x10", 16, 16LLU, 5, 0);
+ TEST_STRTOULL("+0x10", 0, 16LLU, 5, 0);
+ TEST_STRTOULL(" +0x10 ", 0, 16LLU, 6, 0);
+ TEST_STRTOULL("-10", 16, -16LLU, 3, 0);
+ TEST_STRTOULL(" -10 ", 16, -16LLU, 5, 0);
+ TEST_STRTOULL("-0x10", 16, -16LLU, 5, 0);
+ TEST_STRTOULL("-0x10", 0, -16LLU, 5, 0);
+ TEST_STRTOULL(" -0x10 ", 0, -16LLU, 6, 0);
+ TEST_STRTOULL("010", 16, 16LLU, 3, 0);
+ TEST_STRTOULL(" 010 ", 16, 16LLU, 5, 0);
+ TEST_STRTOULL("-010", 16, -16LLU, 4, 0);
+
+ TEST_STRTOULL("11", 8, 9LLU, 2, 0);
+ TEST_STRTOULL("011", 8, 9LLU, 3, 0);
+ TEST_STRTOULL("011", 0, 9LLU, 3, 0);
+ TEST_STRTOULL("-11", 8, -9LLU, 3, 0);
+ TEST_STRTOULL("-011", 8, -9LLU, 4, 0);
+ TEST_STRTOULL("-011", 0, -9LLU, 4, 0);
+
+ TEST_STRTOULL("011", 8, 9LLU, 3, 0);
+ TEST_STRTOULL("011", 0, 9LLU, 3, 0);
+ TEST_STRTOULL("-11", 8, -9LLU, 3, 0);
+ TEST_STRTOULL("-011", 8, -9LLU, 4, 0);
+ TEST_STRTOULL("-011", 0, -9LLU, 4, 0);
+
+ TEST_STRTOULL("Text", 0, 0LLU, 0, 0);
+
+ TEST_STRTOULL("9223372036854775807", 10, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("9223372036854775807", 0, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("9223372036854775808", 0, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("9223372036854775808", 10, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LLU, 18, 0);
+ TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 18, 0);
+ TEST_STRTOULL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 16, 0);
+ TEST_STRTOULL("0x8000000000000000", 0, 9223372036854775808LLU, 18, 0);
+ TEST_STRTOULL("0x8000000000000000", 16, 9223372036854775808LLU, 18, 0);
+ TEST_STRTOULL("8000000000000000", 16, 9223372036854775808LLU, 16, 0);
+ TEST_STRTOULL("0777777777777777777777", 0, 9223372036854775807LLU, 22, 0);
+ TEST_STRTOULL("0777777777777777777777", 8, 9223372036854775807LLU, 22, 0);
+ TEST_STRTOULL("777777777777777777777", 8, 9223372036854775807LLU, 21, 0);
+ TEST_STRTOULL("01000000000000000000000",0, 9223372036854775808LLU, 23, 0);
+ TEST_STRTOULL("01000000000000000000000",8, 9223372036854775808LLU, 23, 0);
+ TEST_STRTOULL("1000000000000000000000", 8, 9223372036854775808LLU, 22, 0);
+
+ TEST_STRTOULL("-9223372036854775808", 10, 9223372036854775808LLU, 20, 0);
+ TEST_STRTOULL("-9223372036854775808", 0, 9223372036854775808LLU, 20, 0);
+ TEST_STRTOULL("-9223372036854775809", 0, 9223372036854775807LLU, 20, 0);
+ TEST_STRTOULL("-9223372036854775809", 10, 9223372036854775807LLU, 20, 0);
+ TEST_STRTOULL("-0x8000000000000000", 0, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("-0x8000000000000000", 16, 9223372036854775808LLU, 19, 0);
+ TEST_STRTOULL("-8000000000000000", 16, 9223372036854775808LLU, 17, 0);
+ TEST_STRTOULL("-0x8000000000000001", 0, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("-0x8000000000000001", 16, 9223372036854775807LLU, 19, 0);
+ TEST_STRTOULL("-8000000000000001", 16, 9223372036854775807LLU, 17, 0);
+ TEST_STRTOULL("-01000000000000000000000",0, 9223372036854775808LLU, 24, 0);
+ TEST_STRTOULL("-01000000000000000000000",8, 9223372036854775808LLU, 24, 0);
+ TEST_STRTOULL("-1000000000000000000000",8, 9223372036854775808LLU, 23, 0);
+ TEST_STRTOULL("-01000000000000000000001",0, 9223372036854775807LLU, 24, 0);
+ TEST_STRTOULL("-01000000000000000000001",8, 9223372036854775807LLU, 24, 0);
+ TEST_STRTOULL("-1000000000000000000001",8, 9223372036854775807LLU, 23, 0);
+
+ TEST_STRTOULL("18446744073709551615", 0, 18446744073709551615LLU, 20, 0);
+ TEST_STRTOULL("18446744073709551615", 10, 18446744073709551615LLU, 20, 0);
+ TEST_STRTOULL("18446744073709551616", 0, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("18446744073709551616", 10, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 0, 18446744073709551615LLU, 18, 0);
+ TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 18, 0);
+ TEST_STRTOULL("FFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 16, 0);
+ TEST_STRTOULL("0x10000000000000000", 0, 18446744073709551615LLU, 19, ERANGE);
+ TEST_STRTOULL("0x10000000000000000", 16, 18446744073709551615LLU, 19, ERANGE);
+ TEST_STRTOULL("10000000000000000", 16, 18446744073709551615LLU, 17, ERANGE);
+ TEST_STRTOULL("01777777777777777777777",0, 18446744073709551615LLU, 23, 0);
+ TEST_STRTOULL("01777777777777777777777",8, 18446744073709551615LLU, 23, 0);
+ TEST_STRTOULL("1777777777777777777777", 8, 18446744073709551615LLU, 22, 0);
+ TEST_STRTOULL("02000000000000000000000",0, 18446744073709551615LLU, 23, ERANGE);
+ TEST_STRTOULL("02000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE);
+ TEST_STRTOULL("2000000000000000000000", 8, 18446744073709551615LLU, 22, ERANGE);
+
+ TEST_STRTOULL("-18446744073709551615", 0, 1LLU, 21, 0);
+ TEST_STRTOULL("-18446744073709551615", 10, 1LLU, 21, 0);
+ TEST_STRTOULL("-18446744073709551616", 0, 18446744073709551615LLU, 21, ERANGE);
+ TEST_STRTOULL("-18446744073709551616", 10, 18446744073709551615LLU, 21, ERANGE);
+ TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 0, 1LLU, 19, 0);
+ TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 16, 1LLU, 19, 0);
+ TEST_STRTOULL("-FFFFFFFFFFFFFFFF", 16, 1LLU, 17, 0);
+ TEST_STRTOULL("-0x10000000000000000", 0, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("-0x10000000000000000", 16, 18446744073709551615LLU, 20, ERANGE);
+ TEST_STRTOULL("-10000000000000000", 16, 18446744073709551615LLU, 18, ERANGE);
+ TEST_STRTOULL("-01777777777777777777777",0, 1LLU, 24, 0);
+ TEST_STRTOULL("-01777777777777777777777",8, 1LLU, 24, 0);
+ TEST_STRTOULL("-1777777777777777777777",8, 1LLU, 23, 0);
+ TEST_STRTOULL("-02000000000000000000000",0, 18446744073709551615LLU, 24, ERANGE);
+ TEST_STRTOULL("-02000000000000000000000",8, 18446744073709551615LLU, 24, ERANGE);
+ TEST_STRTOULL("-2000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE);
+
+ printf("success: strtoull\n");
+ return true;
+}
+
+/*
+FIXME:
+Types:
+bool
+socklen_t
+uint{8,16,32,64}_t
+int{8,16,32,64}_t
+intptr_t
+
+Constants:
+PATH_NAME_MAX
+UINT{16,32,64}_MAX
+INT32_MAX
+*/
+
+static int test_va_copy(void)
+{
+ /* FIXME */
+ return true;
+}
+
+static int test_FUNCTION(void)
+{
+ printf("test: FUNCTION\n");
+ if (strcmp(__FUNCTION__, "test_FUNCTION") != 0) {
+ printf("failure: FUNCTION [\nFUNCTION invalid\n]\n");
+ return false;
+ }
+ printf("success: FUNCTION\n");
+ return true;
+}
+
+static int test_MIN(void)
+{
+ printf("test: MIN\n");
+ if (MIN(20, 1) != 1) {
+ printf("failure: MIN [\nMIN invalid\n]\n");
+ return false;
+ }
+ if (MIN(1, 20) != 1) {
+ printf("failure: MIN [\nMIN invalid\n]\n");
+ return false;
+ }
+ printf("success: MIN\n");
+ return true;
+}
+
+static int test_MAX(void)
+{
+ printf("test: MAX\n");
+ if (MAX(20, 1) != 20) {
+ printf("failure: MAX [\nMAX invalid\n]\n");
+ return false;
+ }
+ if (MAX(1, 20) != 20) {
+ printf("failure: MAX [\nMAX invalid\n]\n");
+ return false;
+ }
+ printf("success: MAX\n");
+ return true;
+}
+
+static int test_socketpair(void)
+{
+ int sock[2];
+ char buf[20];
+
+ printf("test: socketpair\n");
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1) {
+ printf("failure: socketpair [\n"
+ "socketpair() failed\n"
+ "]\n");
+ return false;
+ }
+
+ if (write(sock[1], "automatisch", 12) != 12) {
+ printf("failure: socketpair [\n"
+ "write() failed: %s\n"
+ "]\n", strerror(errno));
+ return false;
+ }
+
+ if (read(sock[0], buf, 12) != 12) {
+ printf("failure: socketpair [\n"
+ "read() failed: %s\n"
+ "]\n", strerror(errno));
+ return false;
+ }
+
+ if (strcmp(buf, "automatisch") != 0) {
+ printf("failure: socketpair [\n"
+ "expected: automatisch, got: %s\n"
+ "]\n", buf);
+ return false;
+ }
+
+ printf("success: socketpair\n");
+
+ return true;
+}
+
+extern int libreplace_test_strptime(void);
+
+static int test_strptime(void)
+{
+ return libreplace_test_strptime();
+}
+
+extern int getifaddrs_test(void);
+
+static int test_getifaddrs(void)
+{
+
+ printf("test: getifaddrs\n");
+
+ if (getifaddrs_test() != 0) {
+ printf("failure: getifaddrs\n");
+ return false;
+ }
+
+ printf("success: getifaddrs\n");
+ return true;
+}
+
+static int test_utime(void)
+{
+ struct utimbuf u;
+ struct stat st1, st2, st3;
+ int fd;
+
+ printf("test: utime\n");
+ unlink(TESTFILE);
+
+ fd = open(TESTFILE, O_RDWR|O_CREAT, 0600);
+ if (fd == -1) {
+ printf("failure: utime [\n"
+ "creating '%s' failed - %s\n]\n",
+ TESTFILE, strerror(errno));
+ return false;
+ }
+
+ if (fstat(fd, &st1) != 0) {
+ printf("failure: utime [\n"
+ "fstat (1) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ u.actime = st1.st_atime + 300;
+ u.modtime = st1.st_mtime - 300;
+ if (utime(TESTFILE, &u) != 0) {
+ printf("failure: utime [\n"
+ "utime(&u) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ if (fstat(fd, &st2) != 0) {
+ printf("failure: utime [\n"
+ "fstat (2) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ if (utime(TESTFILE, NULL) != 0) {
+ printf("failure: utime [\n"
+ "utime(NULL) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ if (fstat(fd, &st3) != 0) {
+ printf("failure: utime [\n"
+ "fstat (3) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+#define CMP_VAL(a,c,b) do { \
+ if (a c b) { \
+ printf("failure: utime [\n" \
+ "%s: %s(%d) %s %s(%d)\n]\n", \
+ __location__, \
+ #a, (int)a, #c, #b, (int)b); \
+ close(fd); \
+ return false; \
+ } \
+} while(0)
+#define EQUAL_VAL(a,b) CMP_VAL(a,!=,b)
+#define GREATER_VAL(a,b) CMP_VAL(a,<=,b)
+#define LESSER_VAL(a,b) CMP_VAL(a,>=,b)
+
+ EQUAL_VAL(st2.st_atime, st1.st_atime + 300);
+ EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300);
+ LESSER_VAL(st3.st_atime, st2.st_atime);
+ GREATER_VAL(st3.st_mtime, st2.st_mtime);
+
+#undef CMP_VAL
+#undef EQUAL_VAL
+#undef GREATER_VAL
+#undef LESSER_VAL
+
+ unlink(TESTFILE);
+ printf("success: utime\n");
+ close(fd);
+ return true;
+}
+
+static int test_utimes(void)
+{
+ struct timeval tv[2];
+ struct stat st1, st2;
+ int fd;
+
+ printf("test: utimes\n");
+ unlink(TESTFILE);
+
+ fd = open(TESTFILE, O_RDWR|O_CREAT, 0600);
+ if (fd == -1) {
+ printf("failure: utimes [\n"
+ "creating '%s' failed - %s\n]\n",
+ TESTFILE, strerror(errno));
+ return false;
+ }
+
+ if (fstat(fd, &st1) != 0) {
+ printf("failure: utimes [\n"
+ "fstat (1) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ ZERO_STRUCT(tv);
+ tv[0].tv_sec = st1.st_atime + 300;
+ tv[1].tv_sec = st1.st_mtime - 300;
+ if (utimes(TESTFILE, tv) != 0) {
+ printf("failure: utimes [\n"
+ "utimes(tv) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ if (fstat(fd, &st2) != 0) {
+ printf("failure: utimes [\n"
+ "fstat (2) failed - %s\n]\n",
+ strerror(errno));
+ close(fd);
+ return false;
+ }
+
+#define EQUAL_VAL(a,b) do { \
+ if (a != b) { \
+ printf("failure: utimes [\n" \
+ "%s: %s(%d) != %s(%d)\n]\n", \
+ __location__, \
+ #a, (int)a, #b, (int)b); \
+ close(fd); \
+ return false; \
+ } \
+} while(0)
+
+ EQUAL_VAL(st2.st_atime, st1.st_atime + 300);
+ EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300);
+
+#undef EQUAL_VAL
+
+ unlink(TESTFILE);
+ printf("success: utimes\n");
+ close(fd);
+ return true;
+}
+
+static int test_memmem(void)
+{
+ char *s;
+
+ printf("test: memmem\n");
+
+ s = (char *)memmem("foo", 3, "fo", 2);
+ if (strcmp(s, "foo") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ s = (char *)memmem("foo", 3, "", 0);
+ /* it is allowable for this to return NULL (as happens on
+ FreeBSD) */
+ if (s && strcmp(s, "foo") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ s = (char *)memmem("foo", 4, "o", 1);
+ if (strcmp(s, "oo") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ s = (char *)memmem("foobarfodx", 11, "fod", 3);
+ if (strcmp(s, "fodx") != 0) {
+ printf(__location__ ": Failed memmem\n");
+ return false;
+ }
+
+ printf("success: memmem\n");
+
+ return true;
+}
+
+static bool test_closefrom(void)
+{
+ int i, fd;
+
+ for (i=0; i<100; i++) {
+ fd = dup(0);
+ if (fd == -1) {
+ perror("dup failed");
+ closefrom(3);
+ return false;
+ }
+
+ /* 1000 is just an arbitrarily chosen upper bound */
+
+ if (fd >= 1000) {
+ printf("fd=%d\n", fd);
+ closefrom(3);
+ return false;
+ }
+ }
+
+ closefrom(3);
+
+ for (i=3; i<=fd; i++) {
+ off_t off;
+ off = lseek(i, 0, SEEK_CUR);
+ if ((off != (off_t)-1) || (errno != EBADF)) {
+ printf("fd %d not closed\n", i);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool test_array_del_element(void)
+{
+ int a[] = { 1,2,3,4,5 };
+
+ printf("test: array_del_element\n");
+
+ ARRAY_DEL_ELEMENT(a, 4, ARRAY_SIZE(a));
+
+ if ((a[0] != 1) ||
+ (a[1] != 2) ||
+ (a[2] != 3) ||
+ (a[3] != 4) ||
+ (a[4] != 5)) {
+ return false;
+ }
+
+ ARRAY_DEL_ELEMENT(a, 0, ARRAY_SIZE(a));
+
+ if ((a[0] != 2) ||
+ (a[1] != 3) ||
+ (a[2] != 4) ||
+ (a[3] != 5) ||
+ (a[4] != 5)) {
+ return false;
+ }
+
+ ARRAY_DEL_ELEMENT(a, 2, ARRAY_SIZE(a));
+
+ if ((a[0] != 2) ||
+ (a[1] != 3) ||
+ (a[2] != 5) ||
+ (a[3] != 5) ||
+ (a[4] != 5)) {
+ return false;
+ }
+
+ printf("success: array_del_element\n");
+
+ return true;
+}
+
+bool torture_local_replace(struct torture_context *ctx)
+{
+ bool ret = true;
+ ret &= test_ftruncate();
+ ret &= test_strlcpy();
+ ret &= test_strlcat();
+ ret &= test_mktime();
+ ret &= test_initgroups();
+ ret &= test_memmove();
+ ret &= test_strdup();
+ ret &= test_setlinebuf();
+ ret &= test_vsyslog();
+ ret &= test_timegm();
+ ret &= test_setenv();
+ ret &= test_strndup();
+ ret &= test_strnlen();
+ ret &= test_waitpid();
+ ret &= test_seteuid();
+ ret &= test_setegid();
+ ret &= test_asprintf();
+ ret &= test_snprintf();
+ ret &= test_vasprintf();
+ ret &= test_vsnprintf();
+ ret &= test_opendir();
+ ret &= test_readdir();
+ ret &= test_telldir();
+ ret &= test_seekdir();
+ ret &= test_dlopen();
+ ret &= test_chroot();
+ ret &= test_bzero();
+ ret &= test_strerror();
+ ret &= test_errno();
+ ret &= test_mkdtemp();
+ ret &= test_mkstemp();
+ ret &= test_pread();
+ ret &= test_pwrite();
+ ret &= test_inet_ntoa();
+ ret &= test_strtoll();
+ ret &= test_strtoull();
+ ret &= test_va_copy();
+ ret &= test_FUNCTION();
+ ret &= test_MIN();
+ ret &= test_MAX();
+ ret &= test_socketpair();
+ ret &= test_strptime();
+ ret &= test_getifaddrs();
+ ret &= test_utime();
+ ret &= test_utimes();
+ ret &= test_memmem();
+ ret &= test_closefrom();
+ ret &= test_array_del_element();
+
+ return ret;
+}
diff --git a/lib/replace/timegm.c b/lib/replace/timegm.c
new file mode 100644
index 0000000..93263a2
--- /dev/null
+++ b/lib/replace/timegm.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 INSTITUTE OR CONTRIBUTORS 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.
+ */
+
+/*
+ adapted for Samba4 by Andrew Tridgell
+*/
+
+#include "replace.h"
+#include "system/time.h"
+
+static int is_leap(unsigned y)
+{
+ y += 1900;
+ return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
+}
+
+time_t rep_timegm(struct tm *tm)
+{
+ static const unsigned ndays[2][12] ={
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+ time_t res = 0;
+ unsigned i;
+
+ if (tm->tm_mon > 12 ||
+ tm->tm_mon < 0 ||
+ tm->tm_mday > 31 ||
+ tm->tm_min > 60 ||
+ tm->tm_sec > 60 ||
+ tm->tm_hour > 24) {
+ /* invalid tm structure */
+ return 0;
+ }
+
+ for (i = 70; i < tm->tm_year; ++i)
+ res += is_leap(i) ? 366 : 365;
+
+ for (i = 0; i < tm->tm_mon; ++i)
+ res += ndays[is_leap(tm->tm_year)][i];
+ res += tm->tm_mday - 1;
+ res *= 24;
+ res += tm->tm_hour;
+ res *= 60;
+ res += tm->tm_min;
+ res *= 60;
+ res += tm->tm_sec;
+ return res;
+}
diff --git a/lib/replace/win32_replace.h b/lib/replace/win32_replace.h
new file mode 100644
index 0000000..9901e72
--- /dev/null
+++ b/lib/replace/win32_replace.h
@@ -0,0 +1,159 @@
+#ifndef _WIN32_REPLACE_H
+#define _WIN32_REPLACE_H
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+/* Map BSD Socket errorcodes to the WSA errorcodes (if possible) */
+
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ECONNREFUSED WSAECONNREFUSED
+#define EINPROGRESS WSAEINPROGRESS
+#define EMSGSIZE WSAEMSGSIZE
+#define ENOBUFS WSAENOBUFS
+#define ENOTSOCK WSAENOTSOCK
+#define ENETUNREACH WSAENETUNREACH
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define ENOTCONN WSAENOTCONN
+#define ENOTSUP 134
+
+/* We undefine the following constants due to conflicts with the w32api headers
+ * and the Windows Platform SDK/DDK.
+ */
+
+#undef interface
+
+#undef ERROR_INVALID_PARAMETER
+#undef ERROR_INSUFFICIENT_BUFFER
+#undef ERROR_INVALID_DATATYPE
+
+#undef FILE_GENERIC_READ
+#undef FILE_GENERIC_WRITE
+#undef FILE_GENERIC_EXECUTE
+#undef FILE_ATTRIBUTE_READONLY
+#undef FILE_ATTRIBUTE_HIDDEN
+#undef FILE_ATTRIBUTE_SYSTEM
+#undef FILE_ATTRIBUTE_DIRECTORY
+#undef FILE_ATTRIBUTE_ARCHIVE
+#undef FILE_ATTRIBUTE_DEVICE
+#undef FILE_ATTRIBUTE_NORMAL
+#undef FILE_ATTRIBUTE_TEMPORARY
+#undef FILE_ATTRIBUTE_REPARSE_POINT
+#undef FILE_ATTRIBUTE_COMPRESSED
+#undef FILE_ATTRIBUTE_OFFLINE
+#undef FILE_ATTRIBUTE_ENCRYPTED
+#undef FILE_FLAG_WRITE_THROUGH
+#undef FILE_FLAG_NO_BUFFERING
+#undef FILE_FLAG_RANDOM_ACCESS
+#undef FILE_FLAG_SEQUENTIAL_SCAN
+#undef FILE_FLAG_DELETE_ON_CLOSE
+#undef FILE_FLAG_BACKUP_SEMANTICS
+#undef FILE_FLAG_POSIX_SEMANTICS
+#undef FILE_TYPE_DISK
+#undef FILE_TYPE_UNKNOWN
+#undef FILE_CASE_SENSITIVE_SEARCH
+#undef FILE_CASE_PRESERVED_NAMES
+#undef FILE_UNICODE_ON_DISK
+#undef FILE_PERSISTENT_ACLS
+#undef FILE_FILE_COMPRESSION
+#undef FILE_VOLUME_QUOTAS
+#undef FILE_VOLUME_IS_COMPRESSED
+#undef FILE_NOTIFY_CHANGE_FILE_NAME
+#undef FILE_NOTIFY_CHANGE_DIR_NAME
+#undef FILE_NOTIFY_CHANGE_ATTRIBUTES
+#undef FILE_NOTIFY_CHANGE_SIZE
+#undef FILE_NOTIFY_CHANGE_LAST_WRITE
+#undef FILE_NOTIFY_CHANGE_LAST_ACCESS
+#undef FILE_NOTIFY_CHANGE_CREATION
+#undef FILE_NOTIFY_CHANGE_EA
+#undef FILE_NOTIFY_CHANGE_SECURITY
+#undef FILE_NOTIFY_CHANGE_STREAM_NAME
+#undef FILE_NOTIFY_CHANGE_STREAM_SIZE
+#undef FILE_NOTIFY_CHANGE_STREAM_WRITE
+#undef FILE_NOTIFY_CHANGE_NAME
+
+#undef PRINTER_ATTRIBUTE_QUEUED
+#undef PRINTER_ATTRIBUTE_DIRECT
+#undef PRINTER_ATTRIBUTE_DEFAULT
+#undef PRINTER_ATTRIBUTE_SHARED
+#undef PRINTER_ATTRIBUTE_NETWORK
+#undef PRINTER_ATTRIBUTE_HIDDEN
+#undef PRINTER_ATTRIBUTE_LOCAL
+#undef PRINTER_ATTRIBUTE_ENABLE_DEVQ
+#undef PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
+#undef PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST
+#undef PRINTER_ATTRIBUTE_WORK_OFFLINE
+#undef PRINTER_ATTRIBUTE_ENABLE_BIDI
+#undef PRINTER_ATTRIBUTE_RAW_ONLY
+#undef PRINTER_ATTRIBUTE_PUBLISHED
+#undef PRINTER_ENUM_DEFAULT
+#undef PRINTER_ENUM_LOCAL
+#undef PRINTER_ENUM_CONNECTIONS
+#undef PRINTER_ENUM_FAVORITE
+#undef PRINTER_ENUM_NAME
+#undef PRINTER_ENUM_REMOTE
+#undef PRINTER_ENUM_SHARED
+#undef PRINTER_ENUM_NETWORK
+#undef PRINTER_ENUM_EXPAND
+#undef PRINTER_ENUM_CONTAINER
+#undef PRINTER_ENUM_ICON1
+#undef PRINTER_ENUM_ICON2
+#undef PRINTER_ENUM_ICON3
+#undef PRINTER_ENUM_ICON4
+#undef PRINTER_ENUM_ICON5
+#undef PRINTER_ENUM_ICON6
+#undef PRINTER_ENUM_ICON7
+#undef PRINTER_ENUM_ICON8
+#undef PRINTER_STATUS_PAUSED
+#undef PRINTER_STATUS_ERROR
+#undef PRINTER_STATUS_PENDING_DELETION
+#undef PRINTER_STATUS_PAPER_JAM
+#undef PRINTER_STATUS_PAPER_OUT
+#undef PRINTER_STATUS_MANUAL_FEED
+#undef PRINTER_STATUS_PAPER_PROBLEM
+#undef PRINTER_STATUS_OFFLINE
+#undef PRINTER_STATUS_IO_ACTIVE
+#undef PRINTER_STATUS_BUSY
+#undef PRINTER_STATUS_PRINTING
+#undef PRINTER_STATUS_OUTPUT_BIN_FULL
+#undef PRINTER_STATUS_NOT_AVAILABLE
+#undef PRINTER_STATUS_WAITING
+#undef PRINTER_STATUS_PROCESSING
+#undef PRINTER_STATUS_INITIALIZING
+#undef PRINTER_STATUS_WARMING_UP
+#undef PRINTER_STATUS_TONER_LOW
+#undef PRINTER_STATUS_NO_TONER
+#undef PRINTER_STATUS_PAGE_PUNT
+#undef PRINTER_STATUS_USER_INTERVENTION
+#undef PRINTER_STATUS_OUT_OF_MEMORY
+#undef PRINTER_STATUS_DOOR_OPEN
+#undef PRINTER_STATUS_SERVER_UNKNOWN
+#undef PRINTER_STATUS_POWER_SAVE
+
+#undef DWORD
+#undef HKEY_CLASSES_ROOT
+#undef HKEY_CURRENT_USER
+#undef HKEY_LOCAL_MACHINE
+#undef HKEY_USERS
+#undef HKEY_PERFORMANCE_DATA
+#undef HKEY_CURRENT_CONFIG
+#undef HKEY_DYN_DATA
+#undef REG_DWORD
+#undef REG_QWORD
+
+#undef SERVICE_STATE_ALL
+
+#undef SE_GROUP_MANDATORY
+#undef SE_GROUP_ENABLED_BY_DEFAULT
+#undef SE_GROUP_ENABLED
+
+#endif /* _WIN32_REPLACE_H */
diff --git a/lib/replace/wscript b/lib/replace/wscript
new file mode 100644
index 0000000..77e655b
--- /dev/null
+++ b/lib/replace/wscript
@@ -0,0 +1,1010 @@
+#!/usr/bin/env python
+
+APPNAME = 'libreplace'
+VERSION = '1.2.1'
+
+import sys
+import os
+
+# find the buildtools directory
+top = '.'
+while not os.path.exists(top+'/buildtools') and len(top.split('/')) < 5:
+ top = top + '/..'
+sys.path.insert(0, top + '/buildtools/wafsamba')
+
+out = 'bin'
+
+import wafsamba
+from wafsamba import samba_dist
+from waflib import Options, Utils, Logs, Context
+
+samba_dist.DIST_DIRS('lib/replace buildtools:buildtools third_party/waf:third_party/waf')
+
+def options(opt):
+ opt.BUILTIN_DEFAULT('NONE')
+ opt.PRIVATE_EXTENSION_DEFAULT('')
+ opt.RECURSE('buildtools/wafsamba')
+
+@Utils.run_once
+def configure(conf):
+ conf.RECURSE('buildtools/wafsamba')
+
+ conf.env.standalone_replace = conf.IN_LAUNCH_DIR()
+
+ if sys.platform.rfind('linux') > -1:
+ conf.DEFINE('LINUX', '1')
+
+ conf.DEFINE('BOOL_DEFINED', 1)
+ conf.DEFINE('HAVE_LIBREPLACE', 1)
+ conf.DEFINE('LIBREPLACE_NETWORK_CHECKS', 1)
+
+ conf.CHECK_HEADERS('linux/types.h crypt.h locale.h acl/libacl.h compat.h')
+ conf.CHECK_HEADERS('acl/libacl.h attr/xattr.h compat.h ctype.h dustat.h')
+ conf.CHECK_HEADERS('fcntl.h fnmatch.h glob.h history.h krb5.h langinfo.h')
+ conf.CHECK_HEADERS('locale.h ndir.h pwd.h')
+ conf.CHECK_HEADERS('shadow.h sys/acl.h')
+ conf.CHECK_HEADERS('sys/attributes.h attr/attributes.h sys/capability.h sys/dir.h sys/epoll.h')
+ conf.CHECK_HEADERS('sys/fcntl.h sys/filio.h sys/filsys.h sys/fs/s5param.h')
+ conf.CHECK_HEADERS('sys/id.h sys/ioctl.h sys/ipc.h sys/mman.h sys/mode.h sys/ndir.h sys/priv.h')
+ conf.CHECK_HEADERS('sys/resource.h sys/security.h sys/shm.h sys/statfs.h sys/statvfs.h sys/termio.h')
+ conf.CHECK_HEADERS('sys/vfs.h sys/xattr.h termio.h termios.h sys/file.h')
+ conf.CHECK_HEADERS('sys/ucontext.h sys/wait.h sys/stat.h')
+
+ if not conf.CHECK_DECLS('malloc', headers='stdlib.h'):
+ conf.CHECK_HEADERS('malloc.h')
+
+ conf.CHECK_HEADERS('grp.h')
+ conf.CHECK_HEADERS('sys/select.h setjmp.h utime.h sys/syslog.h syslog.h')
+ conf.CHECK_HEADERS('stdarg.h vararg.h sys/mount.h mntent.h')
+ conf.CHECK_HEADERS('stropts.h unix.h string.h strings.h sys/param.h limits.h')
+ conf.CHECK_HEADERS('''sys/socket.h netinet/in.h netdb.h arpa/inet.h netinet/in_systm.h
+ netinet/ip.h netinet/tcp.h netinet/in_ip.h
+ sys/sockio.h sys/un.h''', together=True)
+ conf.CHECK_HEADERS('sys/uio.h ifaddrs.h direct.h dirent.h')
+ conf.CHECK_HEADERS('windows.h winsock2.h ws2tcpip.h')
+ conf.CHECK_HEADERS('errno.h')
+ conf.CHECK_HEADERS('getopt.h iconv.h')
+ conf.CHECK_HEADERS('memory.h nss.h sasl/sasl.h')
+ conf.CHECK_HEADERS('linux/openat2.h')
+
+ conf.CHECK_FUNCS_IN('inotify_init', 'inotify', checklibc=True,
+ headers='sys/inotify.h')
+
+ conf.CHECK_HEADERS('security/pam_appl.h zlib.h asm/unistd.h')
+ conf.CHECK_HEADERS('sys/unistd.h alloca.h float.h')
+
+ conf.SET_TARGET_TYPE('tirpc', 'EMPTY')
+
+ if conf.CHECK_CODE(
+ '\n#ifndef _TIRPC_RPC_H\n#error "no tirpc headers in system path"\n#endif\n',
+ 'HAVE_RPC_RPC_HEADERS',
+ headers=['rpc/rpc.h', 'rpc/nettype.h'],
+ msg='Checking for tirpc rpc headers in default system path'):
+ if conf.CONFIG_SET('HAVE_RPC_RPC_H'):
+ conf.undefine('HAVE_RPC_RPC_H')
+
+ if not conf.CONFIG_SET('HAVE_RPC_RPC_H'):
+ if conf.CHECK_CFG(package='libtirpc', args='--cflags --libs',
+ msg='Checking for libtirpc headers',
+ uselib_store='TIRPC'):
+ conf.CHECK_HEADERS('rpc/rpc.h rpc/nettype.h', lib='tirpc', together=True)
+ conf.SET_TARGET_TYPE('tirpc', 'SYSLIB')
+ if not conf.CONFIG_SET('HAVE_RPC_RPC_H'):
+ if conf.CHECK_CFG(package='libntirpc', args='--cflags',
+ msg='Checking for libntirpc headers',
+ uselib_store='TIRPC'):
+ conf.CHECK_HEADERS('rpc/rpc.h rpc/nettype.h', lib='tirpc', together=True)
+ conf.SET_TARGET_TYPE('tirpc', 'SYSLIB')
+ if not conf.CONFIG_SET('HAVE_RPC_RPC_H'):
+ Logs.warn('No rpc/rpc.h header found, tirpc or libntirpc missing?')
+
+ # This file is decprecated with glibc >= 2.30 so we need to check if it
+ # includes a deprecation warning:
+ # #warning "The <sys/sysctl.h> header is deprecated and will be removed."
+ conf.CHECK_CODE('''
+ #include <sys/sysctl.h>
+ int main(void) { return 0; }
+ ''',
+ define='HAVE_SYS_SYSCTL_H',
+ cflags=['-Werror=cpp'],
+ addmain=False,
+ msg='Checking for header sys/sysctl.h')
+
+ conf.CHECK_HEADERS('sys/fileio.h sys/filesys.h sys/dustat.h sys/sysmacros.h')
+ conf.CHECK_HEADERS('xfs/libxfs.h netgroup.h')
+
+ conf.CHECK_HEADERS('valgrind.h valgrind/valgrind.h')
+ conf.CHECK_HEADERS('valgrind/memcheck.h valgrind/helgrind.h valgrind/callgrind.h')
+ conf.CHECK_HEADERS('nss_common.h nsswitch.h ns_api.h')
+ conf.CHECK_HEADERS('sys/extattr.h sys/ea.h sys/proplist.h sys/cdefs.h')
+ conf.CHECK_HEADERS('utmp.h utmpx.h lastlog.h')
+ conf.CHECK_HEADERS('syscall.h sys/syscall.h inttypes.h')
+ conf.CHECK_HEADERS('sys/atomic.h stdatomic.h')
+ conf.CHECK_HEADERS('libgen.h')
+
+ if conf.CHECK_CFLAGS('-Wno-format-truncation'):
+ conf.define('HAVE_WNO_FORMAT_TRUNCATION', '1')
+
+ if conf.CHECK_CFLAGS('-Wno-unused-function'):
+ conf.define('HAVE_WNO_UNUSED_FUNCTION', '1')
+
+ if conf.CHECK_CFLAGS('-Wno-strict-overflow'):
+ conf.define('HAVE_WNO_STRICT_OVERFLOW', '1')
+
+ if conf.CHECK_CFLAGS('-Wno-unused-but-set-variable'):
+ conf.define('HAVE_WNO_UNUSED_BUT_SET_VARIABLE', '1')
+
+ if conf.CHECK_CFLAGS('-Wuse-after-free=1'):
+ conf.define('HAVE_WUSE_AFTER_FREE_1', '1')
+
+ # Check for process set name support
+ conf.CHECK_CODE('''
+ #include <sys/prctl.h>
+ int main(void) {
+ prctl(0);
+ return 0;
+ }
+ ''',
+ 'HAVE_PRCTL',
+ addmain=False,
+ headers='sys/prctl.h',
+ msg='Checking for prctl syscall')
+
+ conf.CHECK_CODE('''
+ #include <unistd.h>
+ #ifdef HAVE_FCNTL_H
+ #include <fcntl.h>
+ #endif
+ int main(void) { int fd = open("/dev/null", O_DIRECT); }
+ ''',
+ define='HAVE_OPEN_O_DIRECT',
+ addmain=False,
+ msg='Checking for O_DIRECT flag to open(2)')
+
+ conf.CHECK_TYPES('"long long" intptr_t uintptr_t ptrdiff_t comparison_fn_t')
+ if not conf.CHECK_TYPE('bool', define='HAVE_BOOL', headers='stdbool.h'):
+ raise Errors.WafError('Samba requires a genuine boolean type')
+
+ conf.CHECK_TYPE('int8_t', 'char')
+ conf.CHECK_TYPE('uint8_t', 'unsigned char')
+ conf.CHECK_TYPE('int16_t', 'short')
+ conf.CHECK_TYPE('uint16_t', 'unsigned short')
+ conf.CHECK_TYPE('int32_t', 'int')
+ conf.CHECK_TYPE('uint32_t', 'unsigned')
+ conf.CHECK_TYPE('int64_t', 'long long')
+ conf.CHECK_TYPE('uint64_t', 'unsigned long long')
+ conf.CHECK_TYPE('size_t', 'unsigned int')
+ conf.CHECK_TYPE('ssize_t', 'int')
+ conf.CHECK_TYPE('ino_t', 'unsigned')
+ conf.CHECK_TYPE('loff_t', 'off_t')
+ conf.CHECK_TYPE('offset_t', 'loff_t')
+ conf.CHECK_TYPE('volatile int', define='HAVE_VOLATILE')
+ conf.CHECK_TYPE('uint_t', 'unsigned int')
+ conf.CHECK_TYPE('blksize_t', 'long', headers='sys/types.h sys/stat.h unistd.h')
+ conf.CHECK_TYPE('blkcnt_t', 'long', headers='sys/types.h sys/stat.h unistd.h')
+
+ conf.CHECK_SIZEOF('bool char int "long long" long short size_t ssize_t')
+ sizeof_int = conf.env["SIZEOF_INT"]
+ if sizeof_int < 4:
+ conf.fatal(f"Samba won't work with int of size {sizeof_int} (requires >= 4)")
+
+ conf.CHECK_SIZEOF('int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t')
+ conf.CHECK_SIZEOF('void*', define='SIZEOF_VOID_P')
+ conf.CHECK_SIZEOF('off_t dev_t ino_t time_t')
+
+ conf.CHECK_TYPES('socklen_t', headers='sys/socket.h')
+ conf.CHECK_TYPE_IN('struct ifaddrs', 'ifaddrs.h')
+ conf.CHECK_TYPE_IN('struct addrinfo', 'netdb.h')
+ conf.CHECK_TYPE_IN('struct sockaddr', 'sys/socket.h')
+ conf.CHECK_CODE('struct sockaddr_in6 x', define='HAVE_STRUCT_SOCKADDR_IN6',
+ headers='sys/socket.h netdb.h netinet/in.h')
+ conf.CHECK_TYPE_IN('struct sockaddr_storage', 'sys/socket.h')
+ conf.CHECK_TYPE_IN('sa_family_t', 'sys/socket.h')
+
+ conf.CHECK_TYPE_IN('sig_atomic_t', 'signal.h', define='HAVE_SIG_ATOMIC_T_TYPE')
+ conf.CHECK_FUNCS('sigsetmask siggetmask sigprocmask sigblock sigaction sigset')
+
+ # Those functions are normally available in libc
+ if not conf.CHECK_FUNCS('''
+ inet_ntoa
+ inet_aton
+ inet_ntop
+ inet_pton
+ connect
+ gethostbyname
+ getaddrinfo
+ getnameinfo
+ freeaddrinfo
+ gai_strerror
+ socketpair''',
+ headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h'):
+ conf.CHECK_FUNCS_IN('''
+ inet_ntoa
+ inet_aton
+ inet_ntop
+ inet_pton
+ connect
+ gethostbyname
+ getaddrinfo
+ getnameinfo
+ freeaddrinfo
+ gai_strerror
+ socketpair''',
+ 'socket nsl',
+ headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h')
+ conf.DEFINE('REPLACE_REQUIRES_LIBSOCKET_LIBNSL', 1)
+
+ conf.CHECK_FUNCS('memset_s memset_explicit')
+
+ conf.CHECK_CODE('''
+ #include <string.h>
+
+ int main(void)
+ {
+ char buf[] = "This is some content";
+ memset(buf, '\0', sizeof(buf)); __asm__ volatile("" : : "g"(&buf) : "memory");
+ return 0;
+ }
+ ''',
+ define='HAVE_GCC_VOLATILE_MEMORY_PROTECTION',
+ addmain=False,
+ msg='Checking for volatile memory protection',
+ local_include=False)
+
+ # Some old Linux systems have broken header files and
+ # miss the IPV6_V6ONLY define in netinet/in.h,
+ # but have it in linux/in6.h.
+ # We can't include both files so we just check if the value
+ # if defined and do the replacement in system/network.h
+ if not conf.CHECK_VARIABLE('IPV6_V6ONLY',
+ headers='sys/socket.h netdb.h netinet/in.h'):
+ conf.CHECK_CODE('''
+ #include <linux/in6.h>
+ #if (IPV6_V6ONLY != 26)
+ #error no IPV6_V6ONLY support on linux
+ #endif
+ int main(void) { return IPV6_V6ONLY; }
+ ''',
+ define='HAVE_LINUX_IPV6_V6ONLY_26',
+ addmain=False,
+ msg='Checking for IPV6_V6ONLY in linux/in6.h',
+ local_include=False)
+
+ conf.CHECK_CODE('''
+ struct sockaddr_storage sa_store;
+ struct addrinfo *ai = NULL;
+ struct in6_addr in6addr;
+ int idx = if_nametoindex("iface1");
+ int s = socket(AF_INET6, SOCK_STREAM, 0);
+ int ret = getaddrinfo(NULL, NULL, NULL, &ai);
+ if (ret != 0) {
+ const char *es = gai_strerror(ret);
+ }
+ freeaddrinfo(ai);
+ {
+ int val = 1;
+ #ifdef HAVE_LINUX_IPV6_V6ONLY_26
+ #define IPV6_V6ONLY 26
+ #endif
+ ret = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ (const void *)&val, sizeof(val));
+ }
+ ''',
+ define='HAVE_IPV6',
+ lib='nsl socket',
+ headers='sys/socket.h netdb.h netinet/in.h net/if.h')
+
+ if conf.CONFIG_SET('HAVE_SYS_UCONTEXT_H') and conf.CONFIG_SET('HAVE_SIGNAL_H'):
+ conf.CHECK_CODE('''
+ ucontext_t uc;
+ sigaddset(&uc.uc_sigmask, SIGUSR1);
+ ''',
+ 'HAVE_UCONTEXT_T',
+ msg="Checking whether we have ucontext_t",
+ headers='signal.h sys/ucontext.h')
+
+ # Check for atomic builtins. */
+ conf.CHECK_CODE('''
+ int i;
+ (void)__sync_fetch_and_add(&i, 1);
+ ''',
+ 'HAVE___SYNC_FETCH_AND_ADD',
+ msg='Checking for __sync_fetch_and_add compiler builtin')
+
+ conf.CHECK_CODE('''
+ int i;
+ (void)__sync_add_and_fetch(&i, 1);
+ ''',
+ 'HAVE___SYNC_ADD_AND_FETCH',
+ msg='Checking for __sync_add_and_fetch compiler builtin')
+
+ conf.CHECK_CODE('''
+ int32_t i;
+ atomic_add_32(&i, 1);
+ ''',
+ 'HAVE_ATOMIC_ADD_32',
+ headers='stdint.h sys/atomic.h',
+ msg='Checking for atomic_add_32 compiler builtin')
+
+ conf.CHECK_CODE('''
+ uint32_t i,j;
+ j = __atomic_add_fetch(&i,1,__ATOMIC_SEQ_CST)
+ ''',
+ 'HAVE___ATOMIC_ADD_FETCH',
+ headers='stdint.h',
+ msg='Checking for __atomic_add_fetch compiler builtin')
+
+ conf.CHECK_CODE('''
+ uint32_t i,j;
+ __atomic_load(&i,&j,__ATOMIC_SEQ_CST)
+ ''',
+ 'HAVE___ATOMIC_ADD_LOAD',
+ headers='stdint.h',
+ msg='Checking for __atomic_load compiler builtin')
+
+ # Check for thread fence. */
+ tf = conf.CHECK_CODE('atomic_thread_fence(memory_order_seq_cst);',
+ 'HAVE_ATOMIC_THREAD_FENCE',
+ headers='stdatomic.h',
+ msg='Checking for atomic_thread_fence(memory_order_seq_cst) in stdatomic.h')
+ if not tf:
+ tf = conf.CHECK_CODE('__atomic_thread_fence(__ATOMIC_SEQ_CST);',
+ 'HAVE___ATOMIC_THREAD_FENCE',
+ msg='Checking for __atomic_thread_fence(__ATOMIC_SEQ_CST)')
+ if not tf:
+ # __sync_synchronize() is available since 2005 in gcc.
+ tf = conf.CHECK_CODE('__sync_synchronize();',
+ 'HAVE___SYNC_SYNCHRONIZE',
+ msg='Checking for __sync_synchronize')
+ if tf:
+ conf.DEFINE('HAVE_ATOMIC_THREAD_FENCE_SUPPORT', 1)
+
+ conf.CHECK_CODE('''
+ #define FALL_THROUGH __attribute__((fallthrough))
+
+ enum direction_e {
+ UP = 0,
+ DOWN,
+ };
+
+ int main(void) {
+ enum direction_e key = UP;
+ int i = 10;
+ int j = 0;
+
+ switch (key) {
+ case UP:
+ i = 5;
+ FALL_THROUGH;
+ case DOWN:
+ j = i * 2;
+ break;
+ default:
+ break;
+ }
+
+ if (j < i) {
+ return 1;
+ }
+
+ return 0;
+ }
+ ''',
+ 'HAVE_FALLTHROUGH_ATTRIBUTE',
+ addmain=False,
+ strict=True,
+ cflags=['-Werror=missing-declarations'],
+ msg='Checking for fallthrough attribute')
+
+ # these may be builtins, so we need the link=False strategy
+ conf.CHECK_FUNCS('strdup memmem printf memset memcpy memmove strcpy strncpy bzero', link=False)
+
+ # See https://bugzilla.samba.org/show_bug.cgi?id=1097
+ #
+ # Ported in from autoconf where it was added with this commit:
+ # commit 804cfb20a067b4b687089dc72a8271b3abf20f31
+ # Author: Simo Sorce <idra@samba.org>
+ # Date: Wed Aug 25 14:24:16 2004 +0000
+ # r2070: Let's try to overload srnlen and strndup for AIX where they are natly broken.
+
+ host_os = sys.platform
+ if host_os.rfind('aix') > -1:
+ conf.DEFINE('BROKEN_STRNLEN', 1)
+ conf.DEFINE('BROKEN_STRNDUP', 1)
+
+ conf.CHECK_FUNCS('shl_load shl_unload shl_findsym')
+ conf.CHECK_FUNCS('pipe strftime srandom random srand rand usleep setbuffer')
+ conf.CHECK_FUNCS('lstat getpgrp utime utimes setuid seteuid setreuid setresuid setgid setegid')
+ conf.CHECK_FUNCS('setregid setresgid chroot strerror vsyslog setlinebuf mktime')
+ conf.CHECK_FUNCS('ftruncate chsize rename waitpid wait4')
+ conf.CHECK_FUNCS('initgroups pread pwrite strndup strcasestr strsep')
+ conf.CHECK_FUNCS('strtok_r mkdtemp dup2 dprintf vdprintf isatty chown lchown')
+ conf.CHECK_FUNCS('link readlink symlink realpath snprintf vsnprintf')
+ conf.CHECK_FUNCS('asprintf vasprintf setenv unsetenv strnlen strtoull __strtoull')
+ conf.CHECK_FUNCS('strtouq strtoll __strtoll strtoq memalign posix_memalign')
+ conf.CHECK_FUNCS('fmemopen')
+
+ if conf.CONFIG_SET('HAVE_MEMALIGN'):
+ conf.CHECK_DECLS('memalign', headers='malloc.h')
+
+ # glibc up to 2.3.6 had dangerously broken posix_fallocate(). DON'T USE IT.
+ if conf.CHECK_CODE('''
+#define _XOPEN_SOURCE 600
+#include <stdlib.h>
+#if defined(__GLIBC__) && ((__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 4))
+#error probably broken posix_fallocate
+#endif
+''',
+ '_POSIX_FALLOCATE_CAPABLE_LIBC',
+ msg='Checking for posix_fallocate-capable libc'):
+ conf.CHECK_FUNCS('posix_fallocate')
+
+ conf.CHECK_FUNCS('prctl dirname basename')
+
+ strlcpy_in_bsd = False
+
+ # libbsd on some platforms provides strlcpy and strlcat
+ if not conf.CHECK_FUNCS('strlcpy strlcat'):
+ if conf.CHECK_FUNCS_IN('strlcpy strlcat', 'bsd', headers='bsd/string.h',
+ checklibc=True):
+ strlcpy_in_bsd = True
+ elif conf.env.enable_fuzzing:
+ # Just to complicate it more, some versions of Honggfuzz have
+ # got strlcpy and strlcat in libc, but not in <string.h>
+ # (unless it is there coincidentally, on a BSD). Therefore we
+ # can't use CHECK_FUNCS alone to decide whether to add the
+ # headers to replace.h.
+ #
+ # As this is only known to happen on a fuzzing compiler, we'll
+ # skip the check when not in fuzzing mode.
+ conf.CHECK_HEADERS('bsd/string.h')
+
+ if not conf.CHECK_FUNCS('getpeereid'):
+ conf.CHECK_FUNCS_IN('getpeereid', 'bsd', headers='sys/types.h bsd/unistd.h')
+ if not conf.CHECK_FUNCS_IN('setproctitle', 'setproctitle', headers='setproctitle.h'):
+ conf.CHECK_FUNCS_IN('setproctitle', 'bsd', headers='sys/types.h bsd/unistd.h')
+ if not conf.CHECK_FUNCS('setproctitle_init'):
+ conf.CHECK_FUNCS_IN('setproctitle_init', 'bsd', headers='sys/types.h bsd/unistd.h')
+
+ if not conf.CHECK_FUNCS('closefrom'):
+ conf.CHECK_FUNCS_IN('closefrom', 'bsd', headers='bsd/unistd.h')
+
+ conf.CHECK_CODE('''
+ struct ucred cred;
+ socklen_t cred_len;
+ int ret = getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len);''',
+ 'HAVE_PEERCRED',
+ msg="Checking whether we can use SO_PEERCRED to get socket credentials",
+ headers='sys/types.h sys/socket.h')
+
+ #Some OS (ie. freebsd) return EINVAL if the conversion could not be done, it's not what we expect
+ #Let's detect those cases
+ if conf.CONFIG_SET('HAVE_STRTOLL'):
+ conf.CHECK_CODE('''
+ long long nb = strtoll("Text", NULL, 0);
+ if (errno == EINVAL) {
+ return 0;
+ } else {
+ return 1;
+ }
+ ''',
+ msg="Checking correct behavior of strtoll",
+ headers = 'errno.h',
+ execute = True,
+ define = 'HAVE_BSD_STRTOLL',
+ )
+ conf.CHECK_FUNCS('if_nameindex if_nametoindex strerror_r')
+ conf.CHECK_FUNCS('syslog')
+ conf.CHECK_FUNCS('gai_strerror get_current_dir_name')
+ conf.CHECK_FUNCS('timegm getifaddrs freeifaddrs mmap setgroups syscall setsid')
+ conf.CHECK_FUNCS('getgrent_r getgrgid_r getgrnam_r getgrouplist getpagesize')
+ conf.CHECK_FUNCS('getpwent_r getpwnam_r getpwuid_r epoll_create1')
+ conf.CHECK_FUNCS('getprogname')
+ if not conf.CHECK_FUNCS('copy_file_range'):
+ conf.CHECK_CODE('''
+syscall(SYS_copy_file_range,0,NULL,0,NULL,0,0);
+ ''',
+ 'HAVE_SYSCALL_COPY_FILE_RANGE',
+ headers='sys/syscall.h unistd.h',
+ msg='Checking whether we have copy_file_range system call')
+
+ conf.SET_TARGET_TYPE('attr', 'EMPTY')
+
+ xattr_headers='sys/attributes.h attr/xattr.h sys/xattr.h'
+
+ # default to 1, we set it to 0 if we don't find any EA implementation below:
+ conf.DEFINE('HAVE_XATTR_SUPPORT', 1)
+ if conf.CHECK_FUNCS_IN('getxattr', 'attr', checklibc=True, headers=xattr_headers):
+ conf.DEFINE('HAVE_XATTR_XATTR', 1)
+ # Darwin has extra options to xattr-family functions
+ conf.CHECK_CODE('getxattr(NULL, NULL, NULL, 0, 0, 0)',
+ headers=xattr_headers, local_include=False,
+ define='XATTR_ADDITIONAL_OPTIONS',
+ msg="Checking whether xattr interface takes additional options")
+ elif conf.CHECK_FUNCS_IN('attr_listf', 'attr', checklibc=True, headers=xattr_headers):
+ conf.DEFINE('HAVE_XATTR_ATTR', 1)
+ elif conf.CHECK_FUNCS('extattr_list_fd'):
+ conf.DEFINE('HAVE_XATTR_EXTATTR', 1)
+ elif conf.CHECK_FUNCS('flistea'):
+ conf.DEFINE('HAVE_XATTR_EA', 1)
+ elif not conf.CHECK_FUNCS('attropen'):
+ conf.DEFINE('HAVE_XATTR_SUPPORT', 0)
+
+
+ conf.CHECK_FUNCS_IN('dlopen dlsym dlerror dlclose', 'dl',
+ checklibc=True, headers='dlfcn.h dl.h')
+
+ conf.CHECK_C_PROTOTYPE('dlopen', 'void *dlopen(const char* filename, unsigned int flags)',
+ define='DLOPEN_TAKES_UNSIGNED_FLAGS', headers='dlfcn.h dl.h')
+
+ #
+ # Check for clock_gettime and fdatasync
+ #
+ # First check libc to avoid linking libreplace against librt.
+ #
+ if conf.CHECK_FUNCS('fdatasync'):
+ # some systems are missing the declaration
+ conf.CHECK_DECLS('fdatasync')
+ else:
+ if conf.CHECK_FUNCS_IN('fdatasync', 'rt'):
+ # some systems are missing the declaration
+ conf.CHECK_DECLS('fdatasync')
+
+ has_clock_gettime = False
+ if conf.CHECK_FUNCS('clock_gettime'):
+ has_clock_gettime = True
+
+ if not has_clock_gettime:
+ if conf.CHECK_FUNCS_IN('clock_gettime', 'rt', checklibc=True):
+ has_clock_gettime = True
+
+ if has_clock_gettime:
+ for c in ['CLOCK_MONOTONIC', 'CLOCK_PROCESS_CPUTIME_ID', 'CLOCK_REALTIME']:
+ conf.CHECK_CODE('''
+ #if TIME_WITH_SYS_TIME
+ # include <sys/time.h>
+ # include <time.h>
+ #else
+ # if HAVE_SYS_TIME_H
+ # include <sys/time.h>
+ # else
+ # include <time.h>
+ # endif
+ #endif
+ clockid_t clk = %s''' % c,
+ 'HAVE_%s' % c,
+ msg='Checking whether the clock_gettime clock ID %s is available' % c)
+
+ conf.CHECK_TYPE('struct timespec', headers='sys/time.h time.h')
+
+ # these headers need to be tested as a group on freebsd
+ conf.CHECK_HEADERS(headers='sys/socket.h net/if.h', together=True)
+ conf.CHECK_HEADERS(headers='netinet/in.h arpa/nameser.h resolv.h', together=True)
+ conf.CHECK_FUNCS_IN('res_search', 'resolv', checklibc=True,
+ headers='netinet/in.h arpa/nameser.h resolv.h')
+
+
+ # try to find libintl (if --without-gettext is not given)
+ conf.env.intl_libs=''
+ if not Options.options.disable_gettext:
+ conf.CHECK_HEADERS('libintl.h')
+ conf.CHECK_LIB('intl')
+ conf.CHECK_DECLS('dgettext gettext bindtextdomain textdomain bind_textdomain_codeset', headers="libintl.h")
+ # *textdomain functions are not strictly necessary
+ conf.CHECK_FUNCS_IN('bindtextdomain textdomain bind_textdomain_codeset',
+ '', checklibc=True, headers='libintl.h')
+ # gettext and dgettext must exist
+ # on some systems (the ones with glibc, those are in libc)
+ if conf.CHECK_FUNCS_IN('dgettext gettext', '', checklibc=True, headers='libintl.h'):
+ # save for dependency definitions
+ conf.env.intl_libs=''
+ # others (e.g. FreeBSD) have separate libintl
+ elif conf.CHECK_FUNCS_IN('dgettext gettext', 'intl', checklibc=False, headers='libintl.h'):
+ # save for dependency definitions
+ conf.env.intl_libs='intl'
+ # recheck with libintl
+ conf.CHECK_FUNCS_IN('bindtextdomain textdomain bind_textdomain_codeset',
+ 'intl', checklibc=False, headers='libintl.h')
+ else:
+ # Some hosts need lib iconv for linking with lib intl
+ # So we try with flags just in case it helps.
+ oldflags = list(conf.env['EXTRA_LDFLAGS']);
+ conf.env['EXTRA_LDFLAGS'].extend(["-liconv"])
+ conf.CHECK_FUNCS_IN('dgettext gettext bindtextdomain textdomain bind_textdomain_codeset',
+ 'intl', checklibc=False, headers='libintl.h')
+ conf.env['EXTRA_LDFLAGS'] = oldflags
+ if conf.env['HAVE_GETTEXT'] and conf.env['HAVE_DGETTEXT']:
+ # save for dependency definitions
+ conf.env.intl_libs='iconv intl'
+
+ # did we find both prototypes and a library to link against?
+ # if not, unset the detected values (see Bug #9911)
+ if not (conf.env['HAVE_GETTEXT'] and conf.env['HAVE_DECL_GETTEXT']):
+ conf.undefine('HAVE_GETTEXT')
+ conf.undefine('HAVE_DECL_GETTEXT')
+ if not (conf.env['HAVE_DGETTEXT'] and conf.env['HAVE_DECL_DGETTEXT']):
+ conf.undefine('HAVE_DGETTEXT')
+ conf.undefine('HAVE_DECL_DGETTEXT')
+
+ conf.CHECK_FUNCS_IN('pthread_create', 'pthread', checklibc=True, headers='pthread.h')
+
+ PTHREAD_CFLAGS='error'
+ PTHREAD_LDFLAGS='error'
+
+ if PTHREAD_LDFLAGS == 'error':
+ # Check if pthread_attr_init() is provided by libc first!
+ if conf.CHECK_FUNCS('pthread_attr_init'):
+ PTHREAD_CFLAGS='-D_REENTRANT'
+ PTHREAD_LDFLAGS=''
+ if PTHREAD_LDFLAGS == 'error':
+ if conf.CHECK_FUNCS_IN('pthread_attr_init', 'pthread'):
+ PTHREAD_CFLAGS='-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS'
+ PTHREAD_LDFLAGS='-lpthread'
+ if PTHREAD_LDFLAGS == 'error':
+ if conf.CHECK_FUNCS_IN('pthread_attr_init', 'pthreads'):
+ PTHREAD_CFLAGS='-D_THREAD_SAFE'
+ PTHREAD_LDFLAGS='-lpthreads'
+ if PTHREAD_LDFLAGS == 'error':
+ if conf.CHECK_FUNCS_IN('pthread_attr_init', 'c_r'):
+ PTHREAD_CFLAGS='-D_THREAD_SAFE -pthread'
+ PTHREAD_LDFLAGS='-pthread'
+
+ # especially for HP-UX, where the CHECK_FUNC macro fails to test for
+ # pthread_attr_init. On pthread_mutex_lock it works there...
+ if PTHREAD_LDFLAGS == 'error':
+ if conf.CHECK_FUNCS_IN('pthread_mutex_lock', 'pthread'):
+ PTHREAD_CFLAGS='-D_REENTRANT'
+ PTHREAD_LDFLAGS='-lpthread'
+
+ if PTHREAD_CFLAGS != 'error' and PTHREAD_LDFLAGS != 'error':
+ if conf.CONFIG_SET('replace_add_global_pthread'):
+ conf.ADD_CFLAGS(PTHREAD_CFLAGS)
+ conf.ADD_LDFLAGS(PTHREAD_LDFLAGS)
+ conf.CHECK_HEADERS('pthread.h')
+ conf.DEFINE('HAVE_PTHREAD', '1')
+
+ if conf.CONFIG_SET('HAVE_PTHREAD'):
+
+ conf.CHECK_FUNCS_IN('pthread_mutexattr_setrobust', 'pthread',
+ checklibc=True, headers='pthread.h')
+ if not conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST'):
+ conf.CHECK_FUNCS_IN('pthread_mutexattr_setrobust_np', 'pthread',
+ checklibc=True, headers='pthread.h')
+
+ conf.CHECK_DECLS('PTHREAD_MUTEX_ROBUST', headers='pthread.h')
+ if not conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST'):
+ conf.CHECK_DECLS('PTHREAD_MUTEX_ROBUST_NP', headers='pthread.h')
+
+ conf.CHECK_FUNCS_IN('pthread_mutex_consistent', 'pthread',
+ checklibc=True, headers='pthread.h')
+ if not conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT'):
+ conf.CHECK_FUNCS_IN('pthread_mutex_consistent_np', 'pthread',
+ checklibc=True, headers='pthread.h')
+
+ if ((conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST') or
+ conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP')) and
+ (conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST') or
+ conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST_NP')) and
+ (conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT') or
+ conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT_NP'))):
+ conf.DEFINE('HAVE_ROBUST_MUTEXES', 1)
+
+ # __thread is available in Solaris Studio, IBM XL,
+ # gcc, Clang and Intel C Compiler
+ conf.CHECK_CODE('''
+ __thread int tls;
+
+ int main(void) {
+ return 0;
+ }
+ ''',
+ 'HAVE___THREAD',
+ addmain=False,
+ msg='Checking for __thread local storage')
+
+ if conf.CONFIG_SET('HAVE_PTHREAD') and not conf.CONFIG_SET('HAVE___THREAD'):
+ conf.fatal('Missing required TLS support in pthread library')
+
+ conf.CHECK_FUNCS_IN('crypt', 'crypt', checklibc=True)
+ conf.CHECK_FUNCS_IN('crypt_r', 'crypt', checklibc=True)
+ conf.CHECK_FUNCS_IN('crypt_rn', 'crypt', checklibc=True)
+
+ conf.CHECK_VARIABLE('rl_event_hook', define='HAVE_DECL_RL_EVENT_HOOK', always=True,
+ headers='readline.h readline/readline.h readline/history.h')
+ conf.CHECK_VARIABLE('program_invocation_short_name', headers='errno.h')
+
+ conf.CHECK_DECLS('snprintf vsnprintf asprintf vasprintf')
+
+ conf.CHECK_DECLS('errno', headers='errno.h', reverse=True)
+ conf.CHECK_DECLS('EWOULDBLOCK', headers='errno.h')
+ conf.CHECK_DECLS('environ', reverse=True, headers='unistd.h')
+ conf.CHECK_DECLS('getgrent_r getpwent_r', reverse=True, headers='pwd.h grp.h')
+ conf.CHECK_DECLS('pread pwrite setenv setresgid setresuid', reverse=True)
+
+ if conf.CONFIG_SET('HAVE_EPOLL_CREATE1') and conf.CONFIG_SET('HAVE_SYS_EPOLL_H'):
+ conf.DEFINE('HAVE_EPOLL', 1)
+
+ if conf.CHECK_FUNCS('eventfd', headers='sys/eventfd.h'):
+ conf.DEFINE('HAVE_EVENTFD', 1)
+
+ conf.CHECK_HEADERS('poll.h')
+ conf.CHECK_FUNCS('poll')
+
+ conf.CHECK_FUNCS('strptime')
+ conf.CHECK_DECLS('strptime', headers='time.h')
+ conf.CHECK_CODE('''#define LIBREPLACE_CONFIGURE_TEST_STRPTIME
+ #include "tests/strptime.c"''',
+ define='HAVE_WORKING_STRPTIME',
+ execute=True,
+ addmain=False,
+ msg='Checking for working strptime')
+
+ conf.CHECK_C_PROTOTYPE('gettimeofday',
+ 'int gettimeofday(struct timeval *tv, struct timezone *tz)',
+ define='HAVE_GETTIMEOFDAY_TZ', headers='sys/time.h')
+
+ conf.CHECK_C_PROTOTYPE('gettimeofday',
+ 'int gettimeofday(struct timeval *tv, void *tz)',
+ define='HAVE_GETTIMEOFDAY_TZ_VOID',
+ headers='sys/time.h')
+
+ conf.CHECK_CODE('#include "tests/snprintf.c"',
+ define="HAVE_C99_VSNPRINTF",
+ execute=True,
+ addmain=False,
+ msg="Checking for C99 vsnprintf")
+
+ conf.CHECK_CODE('#include "tests/shared_mmap.c"',
+ addmain=False, add_headers=False, execute=True,
+ define='HAVE_SHARED_MMAP',
+ msg="Checking for HAVE_SHARED_MMAP")
+
+ conf.CHECK_CODE('#include "tests/shared_mremap.c"',
+ addmain=False, add_headers=False, execute=True,
+ define='HAVE_MREMAP',
+ msg="Checking for HAVE_MREMAP")
+
+ # OpenBSD (and I've heard HPUX) doesn't sync between mmap and write.
+ # FIXME: Anything other than a 0 or 1 exit code should abort configure!
+ conf.CHECK_CODE('#include "tests/incoherent_mmap.c"',
+ addmain=False, add_headers=False, execute=True,
+ define='HAVE_INCOHERENT_MMAP',
+ msg="Checking for HAVE_INCOHERENT_MMAP")
+
+ conf.SAMBA_BUILD_ENV()
+
+ conf.CHECK_CODE('''
+ typedef struct {unsigned x;} FOOBAR;
+ #define X_FOOBAR(x) ((FOOBAR) { x })
+ #define FOO_ONE X_FOOBAR(1)
+ FOOBAR f = FOO_ONE;
+ static const struct {
+ FOOBAR y;
+ } f2[] = {
+ {FOO_ONE}
+ };
+ static const FOOBAR f3[] = {FOO_ONE};
+ ''',
+ define='HAVE_IMMEDIATE_STRUCTURES')
+
+ conf.CHECK_CODE('mkdir("foo",0777)', define='HAVE_MKDIR_MODE', headers='sys/stat.h')
+
+ # we need the st_rdev test under two names
+ conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_rdev',
+ define='HAVE_STRUCT_STAT_ST_RDEV',
+ headers='sys/stat.h')
+ conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_rdev', define='HAVE_ST_RDEV',
+ headers='sys/stat.h')
+ conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_storage', 'ss_family',
+ headers='sys/socket.h netinet/in.h')
+ conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_storage', '__ss_family',
+ headers='sys/socket.h netinet/in.h')
+
+
+ if conf.CHECK_STRUCTURE_MEMBER('struct sockaddr', 'sa_len',
+ headers='sys/socket.h netinet/in.h',
+ define='HAVE_SOCKADDR_SA_LEN'):
+ # the old build system produced both defines
+ conf.DEFINE('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
+
+ conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_in', 'sin_len',
+ headers='sys/socket.h netinet/in.h',
+ define='HAVE_SOCK_SIN_LEN')
+
+ conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_in6', 'sin6_len',
+ headers='sys/socket.h netinet/in.h',
+ define='HAVE_SOCK_SIN6_LEN')
+
+ conf.CHECK_CODE('struct sockaddr_un sunaddr; sunaddr.sun_family = AF_UNIX;',
+ define='HAVE_UNIXSOCKET', headers='sys/socket.h sys/un.h')
+
+
+ conf.CHECK_CODE('''
+ struct stat st;
+ char tpl[20]="/tmp/test.XXXXXX";
+ char tpl2[20]="/tmp/test.XXXXXX";
+ int fd = mkstemp(tpl);
+ int fd2 = mkstemp(tpl2);
+ if (fd == -1) {
+ if (fd2 != -1) {
+ unlink(tpl2);
+ }
+ exit(1);
+ }
+ if (fd2 == -1) exit(1);
+ unlink(tpl);
+ unlink(tpl2);
+ if (fstat(fd, &st) != 0) exit(1);
+ if ((st.st_mode & 0777) != 0600) exit(1);
+ if (strcmp(tpl, "/tmp/test.XXXXXX") == 0) {
+ exit(1);
+ }
+ if (strcmp(tpl, tpl2) == 0) {
+ exit(1);
+ }
+ exit(0);
+ ''',
+ define='HAVE_SECURE_MKSTEMP',
+ execute=True,
+ mandatory=True) # lets see if we get a mandatory failure for this one
+
+ # look for a method of finding the list of network interfaces
+ for method in ['HAVE_IFACE_GETIFADDRS', 'HAVE_IFACE_AIX', 'HAVE_IFACE_IFCONF', 'HAVE_IFACE_IFREQ']:
+ bsd_for_strlcpy = ''
+ if strlcpy_in_bsd:
+ bsd_for_strlcpy = ' bsd'
+ if conf.CHECK_CODE('''
+ #define %s 1
+ #define NO_CONFIG_H 1
+ #define AUTOCONF_TEST 1
+ #include "replace.c"
+ #include "inet_ntop.c"
+ #include "snprintf.c"
+ #include "getifaddrs.c"
+ #define getifaddrs_test main
+ #include "tests/getifaddrs.c"
+ ''' % method,
+ method,
+ lib='nsl socket' + bsd_for_strlcpy,
+ addmain=False,
+ execute=True):
+ break
+
+ conf.RECURSE('system')
+ conf.SAMBA_CONFIG_H()
+ if conf.CHECK_FUNCS('strerror_r'):
+ # Check if strerror_r is XSI-Compatable, the default GNU implementation
+ # is not
+ conf.CHECK_CODE('int strerror_r(int errnum, char *buf, size_t buflen);',
+ 'STRERROR_R_XSI_NOT_GNU',
+ headers='string.h', addmain=False, link=False,
+ msg="Checking for XSI (rather than GNU) prototype for strerror_r")
+
+
+REPLACEMENT_FUNCTIONS = {
+ 'replace.c': ['ftruncate', 'strlcpy', 'strlcat', 'mktime', 'initgroups',
+ 'memmove', 'strdup', 'setlinebuf', 'vsyslog', 'strnlen',
+ 'strndup', 'waitpid', 'seteuid', 'setegid', 'chroot',
+ 'mkstemp', 'mkdtemp', 'pread', 'pwrite', 'strcasestr',
+ 'strsep', 'strtok_r', 'strtoll', 'strtoull', 'setenv', 'unsetenv',
+ 'utime', 'utimes', 'dup2', 'chown', 'link', 'readlink',
+ 'symlink', 'lchown', 'realpath', 'memmem', 'vdprintf',
+ 'dprintf', 'get_current_dir_name', 'copy_file_range',
+ 'strerror_r', 'clock_gettime', 'memset_s'],
+ 'timegm.c': ['timegm'],
+ # Note: C99_VSNPRINTF is not a function, but a special condition
+ # for replacement
+ 'snprintf.c': ['C99_VSNPRINTF', 'snprintf', 'vsnprintf', 'asprintf', 'vasprintf'],
+ # Note: WORKING_STRPTIME is not a function, but a special condition
+ # for replacement
+ 'strptime.c': ['WORKING_STRPTIME', 'strptime'],
+ }
+
+
+def build(bld):
+ bld.RECURSE('buildtools/wafsamba')
+
+ REPLACE_HOSTCC_SOURCE = ''
+
+ for filename in REPLACEMENT_FUNCTIONS.keys():
+ for function in REPLACEMENT_FUNCTIONS[filename]:
+ if not bld.CONFIG_SET('HAVE_%s' % function.upper()):
+ REPLACE_HOSTCC_SOURCE += ' %s' % filename
+ break
+
+ extra_libs = ''
+ if bld.CONFIG_SET('HAVE_LIBBSD'): extra_libs += ' bsd'
+ if bld.CONFIG_SET('HAVE_LIBRT'): extra_libs += ' rt'
+ if bld.CONFIG_SET('REPLACE_REQUIRES_LIBSOCKET_LIBNSL'): extra_libs += ' socket nsl'
+
+ if not bld.CONFIG_SET('HAVE_CLOSEFROM'):
+ REPLACE_HOSTCC_SOURCE += ' closefrom.c'
+
+ bld.SAMBA_SUBSYSTEM('LIBREPLACE_HOSTCC',
+ REPLACE_HOSTCC_SOURCE,
+ use_hostcc=True,
+ use_global_deps=False,
+ group='hostcc_base_build_main',
+ deps = extra_libs
+ )
+
+ REPLACE_SOURCE = REPLACE_HOSTCC_SOURCE
+
+ if not bld.CONFIG_SET('HAVE_DLOPEN'): REPLACE_SOURCE += ' dlfcn.c'
+ if not bld.CONFIG_SET('HAVE_POLL'): REPLACE_SOURCE += ' poll.c'
+
+ if not bld.CONFIG_SET('HAVE_SOCKETPAIR'): REPLACE_SOURCE += ' socketpair.c'
+ if not bld.CONFIG_SET('HAVE_CONNECT'): REPLACE_SOURCE += ' socket.c'
+ if not bld.CONFIG_SET('HAVE_GETIFADDRS'): REPLACE_SOURCE += ' getifaddrs.c'
+ if not bld.CONFIG_SET('HAVE_GETADDRINFO'): REPLACE_SOURCE += ' getaddrinfo.c'
+ if not bld.CONFIG_SET('HAVE_INET_NTOA'): REPLACE_SOURCE += ' inet_ntoa.c'
+ if not bld.CONFIG_SET('HAVE_INET_ATON'): REPLACE_SOURCE += ' inet_aton.c'
+ if not bld.CONFIG_SET('HAVE_INET_NTOP'): REPLACE_SOURCE += ' inet_ntop.c'
+ if not bld.CONFIG_SET('HAVE_INET_PTON'): REPLACE_SOURCE += ' inet_pton.c'
+ if not bld.CONFIG_SET('HAVE_GETXATTR') or bld.CONFIG_SET('XATTR_ADDITIONAL_OPTIONS'):
+ REPLACE_SOURCE += ' xattr.c'
+
+ if not bld.CONFIG_SET('HAVE_CLOSEFROM'):
+ REPLACE_SOURCE += ' closefrom.c'
+
+ bld.SAMBA_LIBRARY('replace',
+ source=REPLACE_SOURCE,
+ group='base_libraries',
+ # FIXME: Ideally symbols should be hidden here so they
+ # don't appear in the global namespace when Samba
+ # libraries are loaded, but this doesn't appear to work
+ # at the moment:
+ # hide_symbols=bld.BUILTIN_LIBRARY('replace'),
+ private_library=True,
+ provide_builtin_linking=True,
+ deps='dl attr' + extra_libs)
+
+ replace_test_cflags = ''
+ if bld.CONFIG_SET('HAVE_WNO_FORMAT_TRUNCATION'):
+ replace_test_cflags += " -Wno-format-truncation"
+ bld.SAMBA_SUBSYSTEM('replace-test',
+ source='''tests/testsuite.c tests/strptime.c
+ tests/os2_delete.c tests/getifaddrs.c''',
+ deps='replace',
+ cflags=replace_test_cflags)
+
+ bld.SAMBA_BINARY('replace_testsuite',
+ source='tests/main.c',
+ deps='replace replace-test',
+ install=False)
+
+ # build replacements for stdint.h and stdbool.h if needed
+ bld.SAMBA_GENERATOR('replace_stdint_h',
+ rule='cp ${SRC} ${TGT}',
+ source='hdr_replace.h',
+ target='stdint.h',
+ enabled = not bld.CONFIG_SET('HAVE_STDINT_H'))
+ bld.SAMBA_GENERATOR('replace_stdbool_h',
+ rule='cp ${SRC} ${TGT}',
+ source='hdr_replace.h',
+ target='stdbool.h',
+ enabled = not bld.CONFIG_SET('HAVE_STDBOOL_H'))
+
+ bld.SAMBA_SUBSYSTEM('samba_intl', source='', use_global_deps=False,deps=bld.env.intl_libs)
+
+def testonly(ctx):
+ '''run talloc testsuite'''
+ import samba_utils
+
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared')
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private')
+
+ cmd = os.path.join(Context.g_module.out, 'replace_testsuite')
+ ret = samba_utils.RUN_COMMAND(cmd)
+ print("testsuite returned %d" % ret)
+ sys.exit(ret)
+
+# WAF doesn't build the unit tests for this, maybe because they don't link with talloc?
+# This forces it
+def test(ctx):
+ Options.commands.append('build')
+ Options.commands.append('testonly')
+
+def dist():
+ '''makes a tarball for distribution'''
+ samba_dist.dist()
diff --git a/lib/replace/xattr.c b/lib/replace/xattr.c
new file mode 100644
index 0000000..c9b7126
--- /dev/null
+++ b/lib/replace/xattr.c
@@ -0,0 +1,852 @@
+/*
+ Unix SMB/CIFS implementation.
+ replacement routines for xattr implementations
+ Copyright (C) Jeremy Allison 1998-2005
+ Copyright (C) Timur Bakeyev 2005
+ Copyright (C) Bjoern Jacke 2006-2007
+ Copyright (C) Herb Lewis 2003
+ Copyright (C) Andrew Bartlett 2012
+
+ ** NOTE! The following LGPL license applies to the replace
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define UID_WRAPPER_NOT_REPLACE
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+
+/******** Solaris EA helper function prototypes ********/
+#ifdef HAVE_ATTROPEN
+#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
+static int solaris_write_xattr(int attrfd, const char *value, size_t size);
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
+static int solaris_unlinkat(int attrdirfd, const char *name);
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
+#endif
+
+/**************************************************************************
+ Wrappers for extended attribute calls. Based on the Linux package with
+ support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
+****************************************************************************/
+
+ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
+{
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ return getxattr(path, name, value, size);
+#else
+
+/* So that we do not recursively call this function */
+#undef getxattr
+ int options = 0;
+ return getxattr(path, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_XATTR_EA)
+ return getea(path, name, value, size);
+#elif defined(HAVE_XATTR_EXTATTR)
+ ssize_t retval;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * The BSD implementation has a nasty habit of silently truncating
+ * the returned value to the size of the buffer, so we have to check
+ * that the buffer is large enough to fit the returned value.
+ */
+ if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
+ if (size == 0) {
+ return retval;
+ } else if (retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
+ return retval;
+ }
+
+ return -1;
+#elif defined(HAVE_XATTR_ATTR)
+ int retval, flags = 0;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
+ if (size == 0 && retval == -1 && errno == E2BIG) {
+ return valuelength;
+ }
+
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
+{
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ return fgetxattr(filedes, name, value, size);
+#else
+
+/* So that we do not recursively call this function */
+#undef fgetxattr
+ int options = 0;
+ return fgetxattr(filedes, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_XATTR_EA)
+ return fgetea(filedes, name, value, size);
+#elif defined(HAVE_XATTR_EXTATTR)
+ ssize_t retval;
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
+ if (size == 0) {
+ return retval;
+ } else if (retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
+ return retval;
+ }
+
+ return -1;
+#elif defined(HAVE_XATTR_ATTR)
+ int retval, flags = 0;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
+ if (size == 0 && retval == -1 && errno == E2BIG) {
+ return valuelength;
+ }
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+#if defined(HAVE_XATTR_EXTATTR)
+
+#define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
+
+static struct {
+ int space;
+ const char *name;
+ size_t len;
+}
+extattr[] = {
+ { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
+ { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
+};
+
+typedef union {
+ const char *path;
+ int filedes;
+} extattr_arg;
+
+static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
+{
+ ssize_t list_size, total_size = 0;
+ int i, len;
+ size_t t;
+ char *buf;
+ /* Iterate through extattr(2) namespaces */
+ for(t = 0; t < ARRAY_SIZE(extattr); t++) {
+ if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) {
+ /* ignore all but user namespace when we are not root, see bug 10247 */
+ continue;
+ }
+ switch(type) {
+ case 0:
+ list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
+ break;
+ case 1:
+ list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
+ break;
+ case 2:
+ list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
+ break;
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+ /* Some error happened. Errno should be set by the previous call */
+ if(list_size < 0)
+ return -1;
+ /* No attributes */
+ if(list_size == 0)
+ continue;
+ /* XXX: Call with an empty buffer may be used to calculate
+ necessary buffer size. Unfortunately, we can't say, how
+ many attributes were returned, so here is the potential
+ problem with the emulation.
+ */
+ if(list == NULL) {
+ /* Take the worse case of one char attribute names -
+ two bytes per name plus one more for sanity.
+ */
+ total_size += list_size + (list_size/2 + 1)*extattr[t].len;
+ continue;
+ }
+ /* Count necessary offset to fit namespace prefixes */
+ len = 0;
+ for(i = 0; i < list_size; i += list[i] + 1)
+ len += extattr[t].len;
+
+ total_size += list_size + len;
+ /* Buffer is too small to fit the results */
+ if(total_size > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ /* Shift results back, so we can prepend prefixes */
+ buf = (char *)memmove(list + len, list, list_size);
+
+ for(i = 0; i < list_size; i += len + 1) {
+ len = buf[i];
+
+ /*
+ * If for some reason we receive a truncated
+ * return from call to list xattrs the pascal
+ * string lengths will not be changed and
+ * therefore we must check that we're not
+ * reading garbage data or off end of array
+ */
+ if (len + i >= list_size) {
+ errno = ERANGE;
+ return -1;
+ }
+ strncpy(list, extattr[t].name, extattr[t].len + 1);
+ list += extattr[t].len;
+ strncpy(list, buf + i + 1, len);
+ list[len] = '\0';
+ list += len + 1;
+ }
+ size -= total_size;
+ }
+ return total_size;
+}
+
+#endif
+
+#if defined(HAVE_XATTR_ATTR) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
+static char attr_buffer[ATTR_MAX_VALUELEN];
+
+static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
+{
+ int retval = 0, index;
+ attrlist_cursor_t *cursor = 0;
+ int total_size = 0;
+ attrlist_t * al = (attrlist_t *)attr_buffer;
+ attrlist_ent_t *ae;
+ size_t ent_size, left = size;
+ char *bp = list;
+
+ while (true) {
+ if (filedes)
+ retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ else
+ retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ if (retval) break;
+ for (index = 0; index < al->al_count; index++) {
+ ae = ATTR_ENTRY(attr_buffer, index);
+ ent_size = strlen(ae->a_name) + sizeof("user.");
+ if (left >= ent_size) {
+ strncpy(bp, "user.", sizeof("user."));
+ strncat(bp, ae->a_name, ent_size - sizeof("user."));
+ bp += ent_size;
+ left -= ent_size;
+ } else if (size) {
+ errno = ERANGE;
+ retval = -1;
+ break;
+ }
+ total_size += ent_size;
+ }
+ if (al->al_more == 0) break;
+ }
+ if (retval == 0) {
+ flags |= ATTR_ROOT;
+ cursor = 0;
+ while (true) {
+ if (filedes)
+ retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ else
+ retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ if (retval) break;
+ for (index = 0; index < al->al_count; index++) {
+ ae = ATTR_ENTRY(attr_buffer, index);
+ ent_size = strlen(ae->a_name) + sizeof("system.");
+ if (left >= ent_size) {
+ strncpy(bp, "system.", sizeof("system."));
+ strncat(bp, ae->a_name, ent_size - sizeof("system."));
+ bp += ent_size;
+ left -= ent_size;
+ } else if (size) {
+ errno = ERANGE;
+ retval = -1;
+ break;
+ }
+ total_size += ent_size;
+ }
+ if (al->al_more == 0) break;
+ }
+ }
+ return (ssize_t)(retval ? retval : total_size);
+}
+
+#endif
+
+ssize_t rep_listxattr (const char *path, char *list, size_t size)
+{
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ return listxattr(path, list, size);
+#else
+/* So that we do not recursively call this function */
+#undef listxattr
+ int options = 0;
+ return listxattr(path, list, size, options);
+#endif
+#elif defined(HAVE_XATTR_EA)
+ return listea(path, list, size);
+#elif defined(HAVE_XATTR_EXTATTR)
+ extattr_arg arg;
+ arg.path = path;
+ return bsd_attr_list(0, arg, list, size);
+#elif defined(HAVE_XATTR_ATTR) && defined(HAVE_SYS_ATTRIBUTES_H)
+ return irix_attr_list(path, 0, list, size, 0);
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_list_xattr(attrdirfd, list, size);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t rep_flistxattr (int filedes, char *list, size_t size)
+{
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ return flistxattr(filedes, list, size);
+#else
+/* So that we do not recursively call this function */
+#undef flistxattr
+ int options = 0;
+ return flistxattr(filedes, list, size, options);
+#endif
+#elif defined(HAVE_XATTR_EA)
+ return flistea(filedes, list, size);
+#elif defined(HAVE_XATTR_EXTATTR)
+ extattr_arg arg;
+ arg.filedes = filedes;
+ return bsd_attr_list(2, arg, list, size);
+#elif defined(HAVE_XATTR_ATTR)
+ return irix_attr_list(NULL, filedes, list, size, 0);
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_list_xattr(attrdirfd, list, size);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int rep_removexattr (const char *path, const char *name)
+{
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ return removexattr(path, name);
+#else
+/* So that we do not recursively call this function */
+#undef removexattr
+ int options = 0;
+ return removexattr(path, name, options);
+#endif
+#elif defined(HAVE_XATTR_EA)
+ return removeea(path, name);
+#elif defined(HAVE_XATTR_EXTATTR)
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return extattr_delete_file(path, attrnamespace, attrname);
+#elif defined(HAVE_XATTR_ATTR)
+ int flags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_unlinkat(attrdirfd, name);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int rep_fremovexattr (int filedes, const char *name)
+{
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ return fremovexattr(filedes, name);
+#else
+/* So that we do not recursively call this function */
+#undef fremovexattr
+ int options = 0;
+ return fremovexattr(filedes, name, options);
+#endif
+#elif defined(HAVE_XATTR_EA)
+ return fremoveea(filedes, name);
+#elif defined(HAVE_XATTR_EXTATTR)
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return extattr_delete_fd(filedes, attrnamespace, attrname);
+#elif defined(HAVE_XATTR_ATTR)
+ int flags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ return attr_removef(filedes, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_unlinkat(attrdirfd, name);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
+{
+ int retval = -1;
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ retval = setxattr(path, name, value, size, flags);
+ if (retval < 0) {
+ if (errno == ENOSPC || errno == E2BIG) {
+ errno = ENAMETOOLONG;
+ }
+ }
+ return retval;
+#else
+/* So that we do not recursively call this function */
+#undef setxattr
+ retval = setxattr(path, name, value, size, 0, flags);
+ if (retval < 0) {
+ if (errno == E2BIG) {
+ errno = ENAMETOOLONG;
+ }
+ }
+ return retval;
+#endif
+#elif defined(HAVE_XATTR_EA)
+ if (flags) {
+ retval = getea(path, name, NULL, 0);
+ if (retval < 0) {
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ return -1;
+ }
+ } else {
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = setea(path, name, value, size, 0);
+ return retval;
+#elif defined(HAVE_XATTR_EXTATTR)
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = extattr_set_file(path, attrnamespace, attrname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_XATTR_ATTR)
+ int myflags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ retval = attr_set(path, attrname, (const char *)value, size, myflags);
+ if (retval < 0) {
+ if (errno == E2BIG) {
+ errno = ENAMETOOLONG;
+ }
+ }
+ return retval;
+#elif defined(HAVE_ATTROPEN)
+ int myflags = O_RDWR;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ retval = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return retval;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
+{
+ int retval = -1;
+#if defined(HAVE_XATTR_XATTR)
+#ifndef XATTR_ADDITIONAL_OPTIONS
+ retval = fsetxattr(filedes, name, value, size, flags);
+ if (retval < 0) {
+ if (errno == ENOSPC) {
+ errno = ENAMETOOLONG;
+ }
+ }
+ return retval;
+#else
+/* So that we do not recursively call this function */
+#undef fsetxattr
+ retval = fsetxattr(filedes, name, value, size, 0, flags);
+ if (retval < 0) {
+ if (errno == E2BIG) {
+ errno = ENAMETOOLONG;
+ }
+ }
+ return retval;
+#endif
+#elif defined(HAVE_XATTR_EA)
+ if (flags) {
+ retval = fgetea(filedes, name, NULL, 0);
+ if (retval < 0) {
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ return -1;
+ }
+ } else {
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = fsetea(filedes, name, value, size, 0);
+ return retval;
+#elif defined(HAVE_XATTR_EXTATTR)
+ int attrnamespace;
+ const char *attrname;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ attrname = name + 7;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrname = name + 5;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_XATTR_ATTR)
+ int myflags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ return attr_setf(filedes, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+ int myflags = O_RDWR | O_XATTR;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ retval = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return retval;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/**************************************************************************
+ helper functions for Solaris' EA support
+****************************************************************************/
+#ifdef HAVE_ATTROPEN
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
+{
+ struct stat sbuf;
+
+ if (fstat(attrfd, &sbuf) == -1) {
+ errno = ENOATTR;
+ return -1;
+ }
+
+ /* This is to return the current size of the named extended attribute */
+ if (size == 0) {
+ return sbuf.st_size;
+ }
+
+ /* check size and read xattr */
+ if (sbuf.st_size > size) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ return read(attrfd, value, sbuf.st_size);
+}
+
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
+{
+ ssize_t len = 0;
+ DIR *dirp;
+ struct dirent *de;
+ int newfd = dup(attrdirfd);
+ /* CAUTION: The originating file descriptor should not be
+ used again following the call to fdopendir().
+ For that reason we dup() the file descriptor
+ here to make things more clear. */
+ dirp = fdopendir(newfd);
+
+ while ((de = readdir(dirp))) {
+ size_t listlen = strlen(de->d_name) + 1;
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ /* we don't want "." and ".." here: */
+ continue;
+ }
+
+ if (size == 0) {
+ /* return the current size of the list of extended attribute names*/
+ len += listlen;
+ } else {
+ /* check size and copy entrieѕ + nul into list. */
+ if ((len + listlen) > size) {
+ errno = ERANGE;
+ len = -1;
+ break;
+ } else {
+ strlcpy(list + len, de->d_name, listlen);
+ len += listlen;
+ }
+ }
+ }
+
+ if (closedir(dirp) == -1) {
+ return -1;
+ }
+ return len;
+}
+
+static int solaris_unlinkat(int attrdirfd, const char *name)
+{
+ if (unlinkat(attrdirfd, name, 0) == -1) {
+ if (errno == ENOENT) {
+ errno = ENOATTR;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
+{
+ int filedes = attropen(path, attrpath, oflag, mode);
+ if (filedes == -1) {
+ if (errno == EINVAL) {
+ errno = ENOTSUP;
+ } else {
+ errno = ENOATTR;
+ }
+ }
+ return filedes;
+}
+
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
+{
+ int filedes = openat(fildes, path, oflag, mode);
+ if (filedes == -1) {
+ if (errno == EINVAL) {
+ errno = ENOTSUP;
+ } else {
+ errno = ENOATTR;
+ }
+ }
+ return filedes;
+}
+
+static int solaris_write_xattr(int attrfd, const char *value, size_t size)
+{
+ if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+#endif /*HAVE_ATTROPEN*/
+
+
diff --git a/lib/smbconf/pysmbconf.c b/lib/smbconf/pysmbconf.c
new file mode 100644
index 0000000..2538127
--- /dev/null
+++ b/lib/smbconf/pysmbconf.c
@@ -0,0 +1,813 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library - Python bindings
+ *
+ * Copyright (C) John Mulligan <phlogistonjohn@asynchrono.us> 2022
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lib/replace/system/python.h"
+#include "includes.h"
+#include "python/py3compat.h"
+
+#include "lib/smbconf/smbconf.h"
+#include "lib/smbconf/smbconf_txt.h"
+#include "lib/smbconf/pysmbconf.h"
+
+static PyObject *PyExc_SMBConfError;
+
+static void py_raise_SMBConfError(sbcErr err)
+{
+ PyObject *v = NULL;
+ PyObject *args = NULL;
+
+ /*
+ * TODO: have the exception type accept arguments in new/init
+ */
+ args = Py_BuildValue("(is)", err, sbcErrorString(err));
+ if (args == NULL) {
+ PyErr_Format(PyExc_SMBConfError, "[%d]: %s", err,
+ sbcErrorString(err));
+ return;
+ }
+ v = PyObject_Call(PyExc_SMBConfError, args, NULL);
+ if (v == NULL) {
+ Py_CLEAR(args);
+ return;
+ }
+ /*
+ * It's clearer to set an explicit error_code attribute for use in calling
+ * code to check what kind of SMBConfError was raised.
+ */
+ if (PyObject_SetAttrString(v, "error_code", PyTuple_GetItem(args, 0)) == -1) {
+ Py_CLEAR(v);
+ Py_CLEAR(args);
+ return;
+ }
+ Py_CLEAR(args);
+ PyErr_SetObject((PyObject *) Py_TYPE(v), v);
+ Py_DECREF(v);
+}
+
+/*
+ * py_from_smbconf_service returns a python tuple that is basically equivalent
+ * to the struct smbconf_service type content-wise.
+ */
+static PyObject *py_from_smbconf_service(struct smbconf_service *svc)
+{
+ uint32_t count;
+ PyObject *plist = PyList_New(svc->num_params);
+ if (plist == NULL) {
+ return NULL;
+ }
+
+ for (count = 0; count < svc->num_params; count++) {
+ PyObject *pt = Py_BuildValue("(ss)",
+ svc->param_names[count],
+ svc->param_values[count]);
+ if (pt == NULL) {
+ Py_CLEAR(plist);
+ return NULL;
+ }
+ if (PyList_SetItem(plist, count, pt) < 0) {
+ Py_CLEAR(pt);
+ Py_CLEAR(plist);
+ return NULL;
+ }
+ }
+ return Py_BuildValue("(sO)", svc->name, plist);
+}
+
+static PyObject *obj_new(PyTypeObject * type, PyObject * args, PyObject * kwds)
+{
+ py_SMBConf_Object *self = (py_SMBConf_Object *) type->tp_alloc(type, 0);
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->mem_ctx = talloc_new(NULL);
+ if (self->mem_ctx == NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static void obj_dealloc(py_SMBConf_Object * self)
+{
+ if (self->conf_ctx != NULL) {
+ smbconf_shutdown(self->conf_ctx);
+ }
+ talloc_free(self->mem_ctx);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+static bool obj_ready(py_SMBConf_Object * self)
+{
+ if (self->conf_ctx == NULL) {
+ PyErr_Format(PyExc_RuntimeError,
+ "attempt to use an uninitialized SMBConf object");
+ return false;
+ }
+ return true;
+}
+
+static PyObject *obj_requires_messaging(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ if (!obj_ready(self)) {
+ return NULL;
+ }
+ if (smbconf_backend_requires_messaging(self->conf_ctx)) {
+ Py_RETURN_TRUE;
+ }
+ Py_RETURN_FALSE;
+}
+
+static PyObject *obj_is_writable(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ if (!obj_ready(self)) {
+ return NULL;
+ }
+ if (smbconf_is_writeable(self->conf_ctx)) {
+ Py_RETURN_TRUE;
+ }
+ Py_RETURN_FALSE;
+}
+
+static PyObject *obj_share_names(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ sbcErr err;
+ uint32_t count;
+ uint32_t num_shares;
+ char **share_names = NULL;
+ PyObject *slist = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (!obj_ready(self)) {
+ return NULL;
+ }
+
+ mem_ctx = talloc_new(self->mem_ctx);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ err =
+ smbconf_get_share_names(self->conf_ctx, mem_ctx, &num_shares,
+ &share_names);
+ if (err != SBC_ERR_OK) {
+ talloc_free(mem_ctx);
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+
+ slist = PyList_New(num_shares);
+ if (slist == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ for (count = 0; count < num_shares; count++) {
+ PyObject *ustr = PyUnicode_FromString(share_names[count]);
+ if (ustr == NULL) {
+ Py_CLEAR(slist);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ if (PyList_SetItem(slist, count, ustr) < 0) {
+ Py_CLEAR(ustr);
+ Py_CLEAR(slist);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ }
+ talloc_free(mem_ctx);
+ return slist;
+}
+
+static PyObject *obj_get_share(py_SMBConf_Object * self, PyObject * args)
+{
+ sbcErr err;
+ char *servicename = NULL;
+ struct smbconf_service *svc = NULL;
+ PyObject *plist = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &servicename)) {
+ return NULL;
+ }
+
+ if (!obj_ready(self)) {
+ return NULL;
+ }
+
+ mem_ctx = talloc_new(self->mem_ctx);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ err = smbconf_get_share(self->conf_ctx, mem_ctx, servicename, &svc);
+ if (err != SBC_ERR_OK) {
+ talloc_free(mem_ctx);
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ /*
+ * if py_from_smbconf_service returns NULL, then an exception should
+ * already be set. No special error handling needed.
+ */
+ plist = py_from_smbconf_service(svc);
+ talloc_free(mem_ctx);
+ return plist;
+}
+
+static PyObject *obj_get_config(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ sbcErr err;
+ PyObject *svclist = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ uint32_t count;
+ uint32_t num_shares;
+ struct smbconf_service **svcs = NULL;
+
+ if (!obj_ready(self)) {
+ return NULL;
+ }
+
+ mem_ctx = talloc_new(self->mem_ctx);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ err = smbconf_get_config(self->conf_ctx, mem_ctx, &num_shares, &svcs);
+ if (err != SBC_ERR_OK) {
+ talloc_free(mem_ctx);
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+
+ svclist = PyList_New(num_shares);
+ if (svclist == NULL) {
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ for (count = 0; count < num_shares; count++) {
+ PyObject *svcobj = py_from_smbconf_service(svcs[count]);
+ if (svcobj == NULL) {
+ Py_CLEAR(svclist);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ if (PyList_SetItem(svclist, count, svcobj) < 0) {
+ Py_CLEAR(svcobj);
+ Py_CLEAR(svclist);
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+ }
+
+ talloc_free(mem_ctx);
+ return svclist;
+}
+
+static PyObject *obj_create_share(py_SMBConf_Object * self, PyObject * args)
+{
+ sbcErr err;
+ char *servicename = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &servicename)) {
+ return NULL;
+ }
+
+ err = smbconf_create_share(self->conf_ctx, servicename);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_drop(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ sbcErr err;
+
+ err = smbconf_drop(self->conf_ctx);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_set_parameter(py_SMBConf_Object * self, PyObject * args)
+{
+ sbcErr err;
+ char *servicename = NULL;
+ char *param = NULL;
+ char *val = NULL;
+
+ if (!PyArg_ParseTuple(args, "sss", &servicename, &param, &val)) {
+ return NULL;
+ }
+
+ err = smbconf_set_parameter(self->conf_ctx, servicename, param, val);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_set_global_parameter(py_SMBConf_Object * self,
+ PyObject * args)
+{
+ sbcErr err;
+ char *param = NULL;
+ char *val = NULL;
+
+ if (!PyArg_ParseTuple(args, "ss", &param, &val)) {
+ return NULL;
+ }
+
+ err = smbconf_set_global_parameter(self->conf_ctx, param, val);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_delete_share(py_SMBConf_Object * self, PyObject * args)
+{
+ sbcErr err;
+ char *servicename = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &servicename)) {
+ return NULL;
+ }
+
+ err = smbconf_delete_share(self->conf_ctx, servicename);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static char *py_get_kv_str(TALLOC_CTX * mem_ctx, PyObject * obj, Py_ssize_t idx)
+{
+ char *ss = NULL;
+ PyObject *pystr = PySequence_GetItem(obj, idx);
+ if (pystr == NULL) {
+ return NULL;
+ }
+ if (!PyUnicode_Check(pystr)) {
+ PyErr_SetString(PyExc_TypeError, "keys/values expect a str");
+ Py_CLEAR(pystr);
+ return NULL;
+ }
+ ss = talloc_strdup(mem_ctx, PyUnicode_AsUTF8(pystr));
+ Py_CLEAR(pystr);
+ return ss;
+}
+
+static PyObject *obj_create_set_share(py_SMBConf_Object * self, PyObject * args)
+{
+ sbcErr err;
+ char *servicename = NULL;
+ PyObject *kvs = NULL;
+ Py_ssize_t size, idx;
+ struct smbconf_service *tmp_service = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(self->mem_ctx);
+
+ if (!PyArg_ParseTuple(args, "sO", &servicename, &kvs)) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ if (PySequence_Check(kvs) == 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "a sequence object is required");
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ size = PySequence_Size(kvs);
+ if (size == -1) {
+ PyErr_SetString(PyExc_ValueError, "failed to get size");
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ tmp_service = talloc_zero(tmp_ctx, struct smbconf_service);
+ if (tmp_service == NULL) {
+ PyErr_NoMemory();
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ tmp_service->name = talloc_strdup(tmp_service, servicename);
+ if (tmp_service->name == NULL) {
+ PyErr_NoMemory();
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ tmp_service->num_params = (uint32_t) size;
+ tmp_service->param_names = talloc_array(tmp_ctx, char *, size);
+ if (tmp_service->param_names == NULL) {
+ PyErr_NoMemory();
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ tmp_service->param_values = talloc_array(tmp_ctx, char *, size);
+ if (tmp_service->param_values == NULL) {
+ PyErr_NoMemory();
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ for (idx = 0; idx < size; idx++) {
+ char *tmp_str = NULL;
+ PyObject *tmp_pair = PySequence_GetItem(kvs, idx);
+ if (tmp_pair == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ if (PySequence_Size(tmp_pair) != 2) {
+ PyErr_SetString(PyExc_ValueError,
+ "expecting two-item tuples");
+ Py_CLEAR(tmp_pair);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ /* fetch key */
+ tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 0);
+ if (tmp_str == NULL) {
+ Py_CLEAR(tmp_pair);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ tmp_service->param_names[idx] = tmp_str;
+
+ /* fetch value */
+ tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 1);
+ if (tmp_str == NULL) {
+ Py_CLEAR(tmp_pair);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ tmp_service->param_values[idx] = tmp_str;
+
+ Py_CLEAR(tmp_pair);
+ }
+
+ err = smbconf_create_set_share(self->conf_ctx, tmp_service);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ talloc_free(tmp_ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_delete_parameter(py_SMBConf_Object * self, PyObject * args)
+{
+ sbcErr err;
+ char *servicename = NULL;
+ char *param_name = NULL;
+
+ if (!PyArg_ParseTuple(args, "ss", &servicename, &param_name)) {
+ return NULL;
+ }
+
+ err = smbconf_delete_parameter(self->conf_ctx, servicename, param_name);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_delete_global_parameter(py_SMBConf_Object * self,
+ PyObject * args)
+{
+ sbcErr err;
+ char *param_name = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &param_name)) {
+ return NULL;
+ }
+
+ err = smbconf_delete_global_parameter(self->conf_ctx, param_name);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_start(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ sbcErr err = smbconf_transaction_start(self->conf_ctx);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_commit(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ sbcErr err = smbconf_transaction_commit(self->conf_ctx);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_cancel(py_SMBConf_Object * self,
+ PyObject * Py_UNUSED(ignored))
+{
+ sbcErr err = smbconf_transaction_cancel(self->conf_ctx);
+ if (err != SBC_ERR_OK) {
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(obj_requires_messaging_doc,
+"requires_messaging() -> bool\n"
+"\n"
+"Returns true if the backend requires interprocess messaging.\n");
+
+PyDoc_STRVAR(obj_is_writable_doc,
+"is_writeable() -> bool\n"
+"\n"
+"Returns true if the SMBConf object's backend is writable.\n");
+
+PyDoc_STRVAR(obj_share_names_doc,
+"share_names() -> list[str]\n"
+"\n"
+"Return a list of the share names currently configured.\n"
+"Includes the global section as a share name.\n");
+
+PyDoc_STRVAR(obj_get_share_doc,
+"get_share() -> (str, list[(str, str)])\n"
+"\n"
+"Given the name of a share, return a tuple of \n"
+"(share_name, share_parms) where share_params is a list of\n"
+"(param_name, param_value) tuples.\n"
+"The term global can be specified to get global section parameters.\n");
+
+PyDoc_STRVAR(obj_get_config_doc,
+"get_config() -> list[(str, list[(str, str)])]\n"
+"Return a list of tuples for every section/share of the current\n"
+"configuration. Each tuple in the list is the same as described\n"
+"for get_share().\n");
+
+PyDoc_STRVAR(obj_create_share_doc,
+"create_share(name: str) -> None\n"
+"Create a new empty share in the configuration. The share\n"
+"name must not exist or an error will be raised.\n");
+
+PyDoc_STRVAR(obj_drop_doc,
+"drop() -> None\n"
+"Drop the entire configuration, resetting it to an empty state.\n");
+
+PyDoc_STRVAR(obj_set_parameter_doc,
+"set_parameter(str, str, str) -> None\n"
+"Set a configuration parameter. Specify service name, parameter name,\n"
+"and parameter value.\n");
+
+PyDoc_STRVAR(obj_set_global_parameter_doc,
+"set_global_parameter(str, str) -> None\n"
+"Set a global configuration parameter. Specify the parameter name\n"
+"and parameter value.\n");
+
+PyDoc_STRVAR(obj_delete_share_doc,
+"delete_share(str) -> None\n"
+"Delete a service from the configuration.\n");
+
+PyDoc_STRVAR(obj_create_set_share_doc,
+"create_set_share(str, [(str, str)...]) -> None\n"
+"Create and set the definition of a service.\n");
+
+PyDoc_STRVAR(obj_delete_parameter_doc,
+"delete_parameter(str, str) -> None\n"
+"Delete a single configuration parameter.\n");
+
+PyDoc_STRVAR(obj_delete_global_parameter_doc,
+"delete_parameter(str, str) -> None\n"
+"Delete a single global configuration parameter.\n");
+
+PyDoc_STRVAR(obj_transaction_start_doc,
+"transaction_start() -> None\n"
+"Start a transaction.\n"
+"Transactions allow making compound sets of changes atomically.\n");
+
+PyDoc_STRVAR(obj_transaction_commit_doc,
+"transaction_commit() -> None\n"
+"Commit the transaction.\n");
+
+PyDoc_STRVAR(obj_transaction_cancel_doc,
+"transaction_cancel() -> None\n"
+"Cancel the transaction.\n");
+
+static PyMethodDef py_smbconf_obj_methods[] = {
+ { "requires_messaging", (PyCFunction) obj_requires_messaging,
+ METH_NOARGS, obj_requires_messaging_doc },
+ { "is_writeable", (PyCFunction) obj_is_writable, METH_NOARGS,
+ obj_is_writable_doc },
+ { "share_names", (PyCFunction) obj_share_names, METH_NOARGS,
+ obj_share_names_doc },
+ { "get_share", (PyCFunction) obj_get_share, METH_VARARGS,
+ obj_get_share_doc },
+ { "get_config", (PyCFunction) obj_get_config, METH_NOARGS,
+ obj_get_config_doc },
+ { "create_share", (PyCFunction) obj_create_share, METH_VARARGS,
+ obj_create_share_doc },
+ { "create_set_share", (PyCFunction) obj_create_set_share, METH_VARARGS,
+ obj_create_set_share_doc },
+ { "drop", (PyCFunction) obj_drop, METH_NOARGS,
+ obj_drop_doc },
+ { "set_parameter", (PyCFunction) obj_set_parameter, METH_VARARGS,
+ obj_set_parameter_doc },
+ { "set_global_parameter", (PyCFunction) obj_set_global_parameter,
+ METH_VARARGS, obj_set_global_parameter_doc },
+ { "delete_share", (PyCFunction) obj_delete_share, METH_VARARGS,
+ obj_delete_share_doc },
+ { "delete_parameter", (PyCFunction) obj_delete_parameter, METH_VARARGS,
+ obj_delete_parameter_doc },
+ { "delete_global_parameter", (PyCFunction) obj_delete_global_parameter,
+ METH_VARARGS, obj_delete_global_parameter_doc },
+ { "transaction_start", (PyCFunction) obj_transaction_start, METH_NOARGS,
+ obj_transaction_start_doc },
+ { "transaction_commit", (PyCFunction) obj_transaction_commit,
+ METH_NOARGS, obj_transaction_commit_doc },
+ { "transaction_cancel", (PyCFunction) obj_transaction_cancel,
+ METH_NOARGS, obj_transaction_cancel_doc },
+ { 0 },
+};
+
+PyDoc_STRVAR(py_SMBConf_type_doc,
+"SMBConf objects provide uniform access to Samba configuration backends.\n"
+"\n"
+"The SMBConf type should not be instantiated directly. Rather, use a\n"
+"backend specific init function like init_txt.\n");
+
+static PyTypeObject py_SMBConf_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "smbconf.SMBConf",
+ .tp_doc = py_SMBConf_type_doc,
+ .tp_basicsize = sizeof(py_SMBConf_Object),
+ .tp_methods = py_smbconf_obj_methods,
+ .tp_new = obj_new,
+ .tp_dealloc = (destructor) obj_dealloc,
+};
+
+static PyObject *py_init_txt(PyObject * module, PyObject * args)
+{
+ py_SMBConf_Object *obj;
+ sbcErr err;
+ char *path = NULL;
+ struct smbconf_ctx *conf_ctx = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &path)) {
+ return NULL;
+ }
+
+ obj = (py_SMBConf_Object *) obj_new(&py_SMBConf_Type, NULL, NULL);
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ err = smbconf_init_txt(obj->mem_ctx, &conf_ctx, path);
+ if (err != SBC_ERR_OK) {
+ Py_DECREF(obj);
+ py_raise_SMBConfError(err);
+ return NULL;
+ }
+ obj->conf_ctx = conf_ctx;
+ return (PyObject *) obj;
+}
+
+static PyObject *py_smbconf_error(PyObject * module, PyObject * args)
+{
+ sbcErr errcode;
+
+ if (!PyArg_ParseTuple(args, "i", &errcode)) {
+ return NULL;
+ }
+
+ /* this always raises an exception. it doesn't return the exception. */
+ py_raise_SMBConfError(errcode);
+ return NULL;
+}
+
+static PyMethodDef pysmbconf_methods[] = {
+ { "init_txt", (PyCFunction) py_init_txt, METH_VARARGS,
+ "Return an SMBConf object for the given text config file." },
+ { "_smbconf_error", (PyCFunction) py_smbconf_error, METH_VARARGS,
+ "Raise an SMBConfError based on the given error code." },
+ { 0 },
+};
+
+PyDoc_STRVAR(py_smbconf_doc,
+"The smbconf module is a wrapper for Samba's smbconf library.\n"
+"This library supports common functions to access the contents\n"
+"of a configuration backend, such as the text-based smb.conf file\n"
+"or the read-write registry backend.\n"
+"The read-only functions on the SMBConf type function on both backend\n"
+"types. Future, write based functions need a writable backend (registry).\n"
+"\n"
+"Note that the registry backend will be provided by a different\n"
+"library module from the source3 tree (implementation TBD).\n");
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "smbconf",
+ .m_doc = py_smbconf_doc,
+ .m_size = -1,
+ .m_methods = pysmbconf_methods,
+};
+
+MODULE_INIT_FUNC(smbconf)
+{
+ PyObject *m = PyModule_Create(&moduledef);
+ if (m == NULL) {
+ return NULL;
+ }
+
+ if (PyType_Ready(&py_SMBConf_Type) < 0) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ Py_INCREF(&py_SMBConf_Type);
+ if (PyModule_AddObject(m, "SMBConf", (PyObject *) & py_SMBConf_Type) <
+ 0) {
+ Py_DECREF(&py_SMBConf_Type);
+ Py_DECREF(m);
+ return NULL;
+ }
+
+ PyExc_SMBConfError =
+ PyErr_NewException(discard_const_p(char, "smbconf.SMBConfError"),
+ NULL, NULL);
+ if (PyExc_SMBConfError == NULL) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ Py_INCREF(PyExc_SMBConfError);
+ if (PyModule_AddObject(m, "SMBConfError", PyExc_SMBConfError) < 0) {
+ Py_DECREF(PyExc_SMBConfError);
+ Py_DECREF(m);
+ return NULL;
+ }
+
+/*
+ * ADD_FLAGS macro borrowed from source3/libsmb/pylibsmb.c
+ */
+#define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
+
+ ADD_FLAGS(SBC_ERR_OK);
+ ADD_FLAGS(SBC_ERR_NOT_IMPLEMENTED);
+ ADD_FLAGS(SBC_ERR_NOT_SUPPORTED);
+ ADD_FLAGS(SBC_ERR_UNKNOWN_FAILURE);
+ ADD_FLAGS(SBC_ERR_NOMEM);
+ ADD_FLAGS(SBC_ERR_INVALID_PARAM);
+ ADD_FLAGS(SBC_ERR_BADFILE);
+ ADD_FLAGS(SBC_ERR_NO_SUCH_SERVICE);
+ ADD_FLAGS(SBC_ERR_IO_FAILURE);
+ ADD_FLAGS(SBC_ERR_CAN_NOT_COMPLETE);
+ ADD_FLAGS(SBC_ERR_NO_MORE_ITEMS);
+ ADD_FLAGS(SBC_ERR_FILE_EXISTS);
+ ADD_FLAGS(SBC_ERR_ACCESS_DENIED);
+
+ return m;
+}
diff --git a/lib/smbconf/pysmbconf.h b/lib/smbconf/pysmbconf.h
new file mode 100644
index 0000000..1e57bfb
--- /dev/null
+++ b/lib/smbconf/pysmbconf.h
@@ -0,0 +1,36 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library - Python bindings
+ *
+ * Copyright (C) John Mulligan <phlogistonjohn@asynchrono.us> 2022
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PYSMBCONF_H_
+#define _PYSMBCONF_H_
+
+#include "lib/replace/system/python.h"
+#include "lib/smbconf/smbconf.h"
+
+typedef struct {
+ PyObject_HEAD
+
+ /* C values embedded in our python type */
+ TALLOC_CTX * mem_ctx;
+ struct smbconf_ctx *conf_ctx;
+} py_SMBConf_Object;
+
+
+#endif /* _PYSMBCONF_H_ */
diff --git a/lib/smbconf/smbconf.c b/lib/smbconf/smbconf.c
new file mode 100644
index 0000000..4129ea5
--- /dev/null
+++ b/lib/smbconf/smbconf.c
@@ -0,0 +1,511 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library
+ * Copyright (C) Michael Adam 2007-2008
+ * Copyright (C) Guenther Deschner 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+
+/**********************************************************************
+ *
+ * internal helper functions
+ *
+ **********************************************************************/
+
+static sbcErr smbconf_global_check(struct smbconf_ctx *ctx)
+{
+ if (!smbconf_share_exists(ctx, GLOBAL_NAME)) {
+ return smbconf_create_share(ctx, GLOBAL_NAME);
+ }
+
+ return SBC_ERR_OK;
+}
+
+
+/**********************************************************************
+ *
+ * The actual libsmbconf API functions that are exported.
+ *
+ **********************************************************************/
+
+const char *sbcErrorString(sbcErr error)
+{
+ switch (error) {
+ case SBC_ERR_OK:
+ return "SBC_ERR_OK";
+ case SBC_ERR_NOT_IMPLEMENTED:
+ return "SBC_ERR_NOT_IMPLEMENTED";
+ case SBC_ERR_NOT_SUPPORTED:
+ return "SBC_ERR_NOT_SUPPORTED";
+ case SBC_ERR_UNKNOWN_FAILURE:
+ return "SBC_ERR_UNKNOWN_FAILURE";
+ case SBC_ERR_NOMEM:
+ return "SBC_ERR_NOMEM";
+ case SBC_ERR_INVALID_PARAM:
+ return "SBC_ERR_INVALID_PARAM";
+ case SBC_ERR_BADFILE:
+ return "SBC_ERR_BADFILE";
+ case SBC_ERR_NO_SUCH_SERVICE:
+ return "SBC_ERR_NO_SUCH_SERVICE";
+ case SBC_ERR_IO_FAILURE:
+ return "SBC_ERR_IO_FAILURE";
+ case SBC_ERR_CAN_NOT_COMPLETE:
+ return "SBC_ERR_CAN_NOT_COMPLETE";
+ case SBC_ERR_NO_MORE_ITEMS:
+ return "SBC_ERR_NO_MORE_ITEMS";
+ case SBC_ERR_FILE_EXISTS:
+ return "SBC_ERR_FILE_EXISTS";
+ case SBC_ERR_ACCESS_DENIED:
+ return "SBC_ERR_ACCESS_DENIED";
+ }
+
+ return "unknown sbcErr value";
+}
+
+
+/**
+ * Tell whether the backend requires messaging to be set up
+ * for the backend to work correctly.
+ */
+bool smbconf_backend_requires_messaging(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->requires_messaging(ctx);
+}
+
+/**
+ * Tell whether the source is writeable.
+ */
+bool smbconf_is_writeable(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->is_writeable(ctx);
+}
+
+/**
+ * Close the configuration.
+ */
+void smbconf_shutdown(struct smbconf_ctx *ctx)
+{
+ talloc_free(ctx);
+}
+
+/**
+ * Detect changes in the configuration.
+ * The given csn struct is filled with the current csn.
+ * smbconf_changed() can also be used for initial retrieval
+ * of the csn.
+ */
+bool smbconf_changed(struct smbconf_ctx *ctx, struct smbconf_csn *csn,
+ const char *service, const char *param)
+{
+ struct smbconf_csn old_csn;
+
+ if (csn == NULL) {
+ return false;
+ }
+
+ old_csn = *csn;
+
+ ctx->ops->get_csn(ctx, csn, service, param);
+ return (csn->csn != old_csn.csn);
+}
+
+/**
+ * Drop the whole configuration (restarting empty).
+ */
+sbcErr smbconf_drop(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->drop(ctx);
+}
+
+/**
+ * Get the whole configuration as lists of strings with counts:
+ *
+ * num_shares : number of shares
+ * share_names : list of length num_shares of share names
+ * num_params : list of length num_shares of parameter counts for each share
+ * param_names : list of lists of parameter names for each share
+ * param_values : list of lists of parameter values for each share
+ */
+sbcErr smbconf_get_config(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ struct smbconf_service ***services)
+{
+ sbcErr err;
+ TALLOC_CTX *tmp_ctx = NULL;
+ uint32_t tmp_num_shares;
+ char **tmp_share_names;
+ struct smbconf_service **tmp_services;
+ uint32_t count;
+
+ if ((num_shares == NULL) || (services == NULL)) {
+ err = SBC_ERR_INVALID_PARAM;
+ goto done;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ err = smbconf_get_share_names(ctx, tmp_ctx, &tmp_num_shares,
+ &tmp_share_names);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+
+ tmp_services = talloc_array(tmp_ctx, struct smbconf_service *,
+ tmp_num_shares);
+ if (tmp_services == NULL) {
+ err = SBC_ERR_NOMEM;
+ goto done;
+ }
+
+ for (count = 0; count < tmp_num_shares; count++) {
+ err = smbconf_get_share(ctx, tmp_services,
+ tmp_share_names[count],
+ &tmp_services[count]);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+ }
+
+ err = SBC_ERR_OK;
+
+ *num_shares = tmp_num_shares;
+ if (tmp_num_shares > 0) {
+ *services = talloc_move(mem_ctx, &tmp_services);
+ } else {
+ *services = NULL;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return err;
+}
+
+/**
+ * get the list of share names defined in the configuration.
+ */
+sbcErr smbconf_get_share_names(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names)
+{
+ return ctx->ops->get_share_names(ctx, mem_ctx, num_shares,
+ share_names);
+}
+
+/**
+ * check if a share/service of a given name exists
+ */
+bool smbconf_share_exists(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ return ctx->ops->share_exists(ctx, servicename);
+}
+
+/**
+ * Add a service if it does not already exist.
+ */
+sbcErr smbconf_create_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ if ((servicename != NULL) && smbconf_share_exists(ctx, servicename)) {
+ return SBC_ERR_FILE_EXISTS;
+ }
+
+ return ctx->ops->create_share(ctx, servicename);
+}
+
+/**
+ * create and set the definition for a new share (service).
+ */
+sbcErr smbconf_create_set_share(struct smbconf_ctx *ctx,
+ struct smbconf_service *service)
+{
+ sbcErr err, err2;
+ int i;
+ uint32_t num_includes = 0;
+ char **includes = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ if ((service->name != NULL) && smbconf_share_exists(ctx, service->name))
+ {
+ return SBC_ERR_FILE_EXISTS;
+ }
+
+ err = smbconf_transaction_start(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ err = smbconf_create_share(ctx, service->name);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto cancel;
+ }
+
+ for (i = 0; i < service->num_params; i++) {
+ if (strequal(service->param_names[i], "include")) {
+ includes = talloc_realloc(tmp_ctx, includes, char *,
+ num_includes+1);
+ if (includes == NULL) {
+ err = SBC_ERR_NOMEM;
+ goto cancel;
+ }
+ includes[num_includes] = talloc_strdup(includes,
+ service->param_values[i]);
+ if (includes[num_includes] == NULL) {
+ err = SBC_ERR_NOMEM;
+ goto cancel;
+ }
+ num_includes++;
+ } else {
+ err = smbconf_set_parameter(ctx,
+ service->name,
+ service->param_names[i],
+ service->param_values[i]);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto cancel;
+ }
+ }
+ }
+
+ err = smbconf_set_includes(ctx, service->name, num_includes,
+ discard_const_p(const char *, includes));
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto cancel;
+ }
+
+ err = smbconf_transaction_commit(ctx);
+
+ goto done;
+
+cancel:
+ err2 = smbconf_transaction_cancel(ctx);
+ if (!SBC_ERROR_IS_OK(err2)) {
+ DEBUG(5, (__location__ ": Error cancelling transaction: %s\n",
+ sbcErrorString(err2)));
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return err;
+}
+
+/**
+ * get a definition of a share (service) from configuration.
+ */
+sbcErr smbconf_get_share(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service)
+{
+ return ctx->ops->get_share(ctx, mem_ctx, servicename, service);
+}
+
+/**
+ * delete a service from configuration
+ */
+sbcErr smbconf_delete_share(struct smbconf_ctx *ctx, const char *servicename)
+{
+ if (!smbconf_share_exists(ctx, servicename)) {
+ return SBC_ERR_NO_SUCH_SERVICE;
+ }
+
+ return ctx->ops->delete_share(ctx, servicename);
+}
+
+/**
+ * set a configuration parameter to the value provided.
+ */
+sbcErr smbconf_set_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr)
+{
+ return ctx->ops->set_parameter(ctx, service, param, valstr);
+}
+
+/**
+ * Set a global parameter
+ * (i.e. a parameter in the [global] service).
+ *
+ * This also creates [global] when it does not exist.
+ */
+sbcErr smbconf_set_global_parameter(struct smbconf_ctx *ctx,
+ const char *param, const char *val)
+{
+ sbcErr err;
+
+ err = smbconf_global_check(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+ err = smbconf_set_parameter(ctx, GLOBAL_NAME, param, val);
+
+ return err;
+}
+
+/**
+ * get the value of a configuration parameter as a string
+ */
+sbcErr smbconf_get_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr)
+{
+ if (valstr == NULL) {
+ return SBC_ERR_INVALID_PARAM;
+ }
+
+ return ctx->ops->get_parameter(ctx, mem_ctx, service, param, valstr);
+}
+
+/**
+ * Get the value of a global parameter.
+ *
+ * Create [global] if it does not exist.
+ */
+sbcErr smbconf_get_global_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *param,
+ char **valstr)
+{
+ sbcErr err;
+
+ err = smbconf_global_check(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ err = smbconf_get_parameter(ctx, mem_ctx, GLOBAL_NAME, param,
+ valstr);
+
+ return err;
+}
+
+/**
+ * delete a parameter from configuration
+ */
+sbcErr smbconf_delete_parameter(struct smbconf_ctx *ctx,
+ const char *service, const char *param)
+{
+ return ctx->ops->delete_parameter(ctx, service, param);
+}
+
+/**
+ * Delete a global parameter.
+ *
+ * Create [global] if it does not exist.
+ */
+sbcErr smbconf_delete_global_parameter(struct smbconf_ctx *ctx,
+ const char *param)
+{
+ sbcErr err;
+
+ err = smbconf_global_check(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+ err = smbconf_delete_parameter(ctx, GLOBAL_NAME, param);
+
+ return err;
+}
+
+sbcErr smbconf_get_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes, char ***includes)
+{
+ return ctx->ops->get_includes(ctx, mem_ctx, service, num_includes,
+ includes);
+}
+
+sbcErr smbconf_get_global_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_includes, char ***includes)
+{
+ sbcErr err;
+
+ err = smbconf_global_check(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+ err = smbconf_get_includes(ctx, mem_ctx, GLOBAL_NAME,
+ num_includes, includes);
+
+ return err;
+}
+
+sbcErr smbconf_set_includes(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes, const char **includes)
+{
+ return ctx->ops->set_includes(ctx, service, num_includes, includes);
+}
+
+sbcErr smbconf_set_global_includes(struct smbconf_ctx *ctx,
+ uint32_t num_includes,
+ const char **includes)
+{
+ sbcErr err;
+
+ err = smbconf_global_check(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+ err = smbconf_set_includes(ctx, GLOBAL_NAME,
+ num_includes, includes);
+
+ return err;
+}
+
+
+sbcErr smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service)
+{
+ return ctx->ops->delete_includes(ctx, service);
+}
+
+sbcErr smbconf_delete_global_includes(struct smbconf_ctx *ctx)
+{
+ sbcErr err;
+
+ err = smbconf_global_check(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+ err = smbconf_delete_includes(ctx, GLOBAL_NAME);
+
+ return err;
+}
+
+sbcErr smbconf_transaction_start(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->transaction_start(ctx);
+}
+
+sbcErr smbconf_transaction_commit(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->transaction_commit(ctx);
+}
+
+sbcErr smbconf_transaction_cancel(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->transaction_cancel(ctx);
+}
diff --git a/lib/smbconf/smbconf.h b/lib/smbconf/smbconf.h
new file mode 100644
index 0000000..e5f138f
--- /dev/null
+++ b/lib/smbconf/smbconf.h
@@ -0,0 +1,505 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBSMBCONF_H__
+#define __LIBSMBCONF_H__
+
+/**
+ * @defgroup libsmbconf The smbconf API
+ *
+ * libsmbconf is a library to read or, based on the backend, modify the Samba
+ * configuration.
+ *
+ * @{
+ */
+
+/**
+ * @brief Status codes returned from smbconf functions
+ */
+enum _sbcErrType {
+ SBC_ERR_OK = 0, /**< Successful completion **/
+ SBC_ERR_NOT_IMPLEMENTED, /**< Function not implemented **/
+ SBC_ERR_NOT_SUPPORTED, /**< Function not supported **/
+ SBC_ERR_UNKNOWN_FAILURE, /**< General failure **/
+ SBC_ERR_NOMEM, /**< Memory allocation error **/
+ SBC_ERR_INVALID_PARAM, /**< An Invalid parameter was supplied **/
+ SBC_ERR_BADFILE, /**< A bad file was supplied **/
+ SBC_ERR_NO_SUCH_SERVICE, /**< There is no such service provided **/
+ SBC_ERR_IO_FAILURE, /**< There was an IO error **/
+ SBC_ERR_CAN_NOT_COMPLETE,/**< Can not complete action **/
+ SBC_ERR_NO_MORE_ITEMS, /**< No more items left **/
+ SBC_ERR_FILE_EXISTS, /**< File already exists **/
+ SBC_ERR_ACCESS_DENIED, /**< Access has been denied **/
+};
+
+typedef enum _sbcErrType sbcErr;
+
+#define SBC_ERROR_IS_OK(x) ((x) == SBC_ERR_OK)
+#define SBC_ERROR_EQUAL(x,y) ((x) == (y))
+
+struct smbconf_ctx;
+
+/* the change sequence number */
+struct smbconf_csn {
+ uint64_t csn;
+};
+
+/** Information about a service */
+struct smbconf_service {
+ char *name; /**< The name of the share */
+ uint32_t num_params; /**< List of length num_shares of parameter counts for each share */
+ char **param_names; /**< List of lists of parameter names for each share */
+ char **param_values; /**< List of lists of parameter values for each share */
+};
+
+/*
+ * The smbconf API functions
+ */
+
+/**
+ * @brief Translate an error value into a string
+ *
+ * @param error
+ *
+ * @return a pointer to a static string
+ **/
+const char *sbcErrorString(sbcErr error);
+
+/**
+ * @brief Check if the backend requires messaging to be set up.
+ *
+ * Tell whether the backend requires messaging to be set up
+ * for the backend to work correctly.
+ *
+ * @param[in] ctx The smbconf context to check.
+ *
+ * @return True if needed, false if not.
+ */
+bool smbconf_backend_requires_messaging(struct smbconf_ctx *ctx);
+
+/**
+ * @brief Tell whether the source is writeable.
+ *
+ * @param[in] ctx The smbconf context to check.
+ *
+ * @return True if it is writeable, false if not.
+ */
+bool smbconf_is_writeable(struct smbconf_ctx *ctx);
+
+/**
+ * @brief Close the configuration.
+ *
+ * @param[in] ctx The smbconf context to close.
+ */
+void smbconf_shutdown(struct smbconf_ctx *ctx);
+
+/**
+ * @brief Detect changes in the configuration.
+ *
+ * Get the change sequence number of the given service/parameter. Service and
+ * parameter strings may be NULL.
+ *
+ * The given change sequence number (csn) struct is filled with the current
+ * csn. smbconf_changed() can also be used for initial retrieval of the csn.
+ *
+ * @param[in] ctx The smbconf context to check for changes.
+ *
+ * @param[inout] csn The smbconf csn to be filled.
+ *
+ * @param[in] service The service name to check or NULL.
+ *
+ * @param[in] param The param to check or NULL.
+ *
+ * @return True if it has been changed, false if not.
+ */
+bool smbconf_changed(struct smbconf_ctx *ctx, struct smbconf_csn *csn,
+ const char *service, const char *param);
+
+/**
+ * @brief Drop the whole configuration (restarting empty).
+ *
+ * @param[in] ctx The smbconf context to drop the config.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_drop(struct smbconf_ctx *ctx);
+
+/**
+ * @brief Get the whole configuration as lists of strings with counts.
+ *
+ * @param[in] ctx The smbconf context to get the lists from.
+ *
+ * @param[in] mem_ctx The memory context to use.
+ *
+ * @param[in] num_shares A pointer to store the number of shares.
+ *
+ * @param[out] services A pointer to store the services.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ *
+ * @see smbconf_service
+ */
+sbcErr smbconf_get_config(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ struct smbconf_service ***services);
+
+/**
+ * @brief Get the list of share names defined in the configuration.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] mem_ctx The memory context to use.
+ *
+ * @param[in] num_shares A pointer to store the number of shares.
+ *
+ * @param[in] share_names A pointer to store the share names.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_get_share_names(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names);
+
+/**
+ * @brief Check if a share/service of a given name exists.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] servicename The service name to check if it exists.
+ *
+ * @return True if it exists, false if not.
+ */
+bool smbconf_share_exists(struct smbconf_ctx *ctx, const char *servicename);
+
+/**
+ * @brief Add a service if it does not already exist.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] servicename The name of the service to add.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_create_share(struct smbconf_ctx *ctx, const char *servicename);
+
+/**
+ * @brief create and set the definition for a new service.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] service The definition for the added service.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_create_set_share(struct smbconf_ctx *ctx,
+ struct smbconf_service *service);
+
+/**
+ * @brief Get a definition of a share (service) from configuration.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] mem_ctx A memory context to allocate the result.
+ *
+ * @param[in] servicename The service name to get the information from.
+ *
+ * @param[out] service A pointer to store the service information about the
+ * share.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ *
+ * @see smbconf_service
+ */
+sbcErr smbconf_get_share(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service);
+
+/**
+ * @brief Delete a service from configuration.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] servicename The service name to delete.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_delete_share(struct smbconf_ctx *ctx,
+ const char *servicename);
+
+/**
+ * @brief Set a configuration parameter to the value provided.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] service The service name to set the parameter.
+ *
+ * @param[in] param The name of the parameter to set.
+ *
+ * @param[in] valstr The value to set.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_set_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr);
+
+/**
+ * @brief Set a global configuration parameter to the value provided.
+ *
+ * This adds a paramet in the [global] service. It also creates [global] if it
+ * doesn't exist.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] param The name of the parameter to set.
+ *
+ * @param[in] val The value to set.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_set_global_parameter(struct smbconf_ctx *ctx,
+ const char *param, const char *val);
+
+/**
+ * @brief Get the value of a configuration parameter as a string.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] mem_ctx The memory context to allocate the string on.
+ *
+ * @param[in] service The name of the service where to find the parameter.
+ *
+ * @param[in] param The parameter to get.
+ *
+ * @param[out] valstr A pointer to store the value as a string.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_get_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr);
+
+/**
+ * @brief Get the value of a global configuration parameter as a string.
+ *
+ * It also creates [global] if it doesn't exist.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] mem_ctx The memory context to allocate the string on.
+ *
+ * @param[in] param The parameter to get.
+ *
+ * @param[out] valstr A pointer to store the value as a string.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_get_global_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *param,
+ char **valstr);
+
+/**
+ * @brief Delete a parameter from the configuration.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] service The service where the parameter can be found.
+ *
+ * @param[in] param The name of the parameter to delete.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_delete_parameter(struct smbconf_ctx *ctx,
+ const char *service, const char *param);
+
+/**
+ * @brief Delete a global parameter from the configuration.
+ *
+ * It also creates [global] if it doesn't exist.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] param The name of the parameter to delete.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_delete_global_parameter(struct smbconf_ctx *ctx,
+ const char *param);
+
+/**
+ * @brief Get the list of names of included files.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] mem_ctx The memory context to allocate the names.
+ *
+ * @param[in] service The service name to get the include files.
+ *
+ * @param[out] num_includes A pointer to store the number of included files.
+ *
+ * @param[out] includes A pointer to store the paths of the included files.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_get_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes, char ***includes);
+
+/**
+ * @brief Get the list of globally included files.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] mem_ctx The memory context to allocate the names.
+ *
+ * @param[out] num_includes A pointer to store the number of included files.
+ *
+ * @param[out] includes A pointer to store the paths of the included files.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_get_global_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_includes, char ***includes);
+
+/**
+ * @brief Set a list of config files to include on the given service.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] service The service to add includes.
+ *
+ * @param[in] num_includes The number of includes to set.
+ *
+ * @param[in] includes A list of paths to include.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_set_includes(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes, const char **includes);
+
+/**
+ * @brief Set a list of config files to include globally.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] num_includes The number of includes to set.
+ *
+ * @param[in] includes A list of paths to include.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_set_global_includes(struct smbconf_ctx *ctx,
+ uint32_t num_includes,
+ const char **includes);
+
+/**
+ * @brief Delete include parameter on the given service.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @param[in] service The name of the service to delete the includes from.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service);
+
+/**
+ * @brief Delete include parameter from the global service.
+ *
+ * @param[in] ctx The smbconf context to use.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_delete_global_includes(struct smbconf_ctx *ctx);
+
+/**
+ * @brief Start a transaction on the configuration backend.
+ *
+ * Transactions are exposed in order to make it possible
+ * to create atomic compound writing commands.
+ *
+ * @param[in] ctx The smbconf context to start the transaction.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ */
+sbcErr smbconf_transaction_start(struct smbconf_ctx *ctx);
+
+/**
+ * @brief Commit a transaction on the configuration backend.
+ *
+ * Transactions are exposed in order to make it possible
+ * to create atomic compound writing commands.
+ *
+ * @param[in] ctx The smbconf context to commit the transaction.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ *
+ * @see smbconf_transaction_start()
+ */
+sbcErr smbconf_transaction_commit(struct smbconf_ctx *ctx);
+
+/**
+ * @brief Cancel a transaction on the configuration backend.
+ *
+ * Transactions are exposed in order to make it possible
+ * to create atomic compound writing commands.
+ *
+ * @param[in] ctx The smbconf context to cancel the transaction.
+ *
+ * @return SBC_ERR_OK on success, a corresponding sbcErr if an
+ * error occurred.
+ *
+ * @see smbconf_transaction_start()
+ */
+sbcErr smbconf_transaction_cancel(struct smbconf_ctx *ctx);
+
+/* @} ******************************************************************/
+
+#endif /* _LIBSMBCONF_H_ */
diff --git a/lib/smbconf/smbconf_private.h b/lib/smbconf/smbconf_private.h
new file mode 100644
index 0000000..e768c30
--- /dev/null
+++ b/lib/smbconf/smbconf_private.h
@@ -0,0 +1,96 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBSMBCONF_PRIVATE_H__
+#define __LIBSMBCONF_PRIVATE_H__
+
+#ifndef GLOBAL_NAME
+#define GLOBAL_NAME "global"
+#endif
+
+#include "lib/smbconf/smbconf.h"
+
+struct smbconf_ops {
+ sbcErr (*init)(struct smbconf_ctx *ctx, const char *path);
+ int (*shutdown)(struct smbconf_ctx *ctx);
+ bool (*requires_messaging)(struct smbconf_ctx *ctx);
+ bool (*is_writeable)(struct smbconf_ctx *ctx);
+ sbcErr (*open_conf)(struct smbconf_ctx *ctx);
+ int (*close_conf)(struct smbconf_ctx *ctx);
+ void (*get_csn)(struct smbconf_ctx *ctx, struct smbconf_csn *csn,
+ const char *service, const char *param);
+ sbcErr (*drop)(struct smbconf_ctx *ctx);
+ sbcErr (*get_share_names)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names);
+ bool (*share_exists)(struct smbconf_ctx *ctx, const char *service);
+ sbcErr (*create_share)(struct smbconf_ctx *ctx, const char *service);
+ sbcErr (*get_share)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service);
+ sbcErr (*delete_share)(struct smbconf_ctx *ctx,
+ const char *servicename);
+ sbcErr (*set_parameter)(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr);
+ sbcErr (*get_parameter)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr);
+ sbcErr (*delete_parameter)(struct smbconf_ctx *ctx,
+ const char *service, const char *param);
+ sbcErr (*get_includes)(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes, char ***includes);
+ sbcErr (*set_includes)(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes, const char **includes);
+ sbcErr (*delete_includes)(struct smbconf_ctx *ctx,
+ const char *service);
+ sbcErr (*transaction_start)(struct smbconf_ctx *ctx);
+ sbcErr (*transaction_commit)(struct smbconf_ctx *ctx);
+ sbcErr (*transaction_cancel)(struct smbconf_ctx *ctx);
+};
+
+struct smbconf_ctx {
+ const char *path;
+ struct smbconf_ops *ops;
+ void *data; /* private data for use in backends */
+};
+
+sbcErr smbconf_init_internal(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *path, struct smbconf_ops *ops);
+
+sbcErr smbconf_add_string_to_array(TALLOC_CTX *mem_ctx,
+ char ***array,
+ uint32_t count,
+ const char *string);
+
+bool smbconf_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry);
+
+bool smbconf_reverse_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry);
+
+#endif
diff --git a/lib/smbconf/smbconf_txt.c b/lib/smbconf/smbconf_txt.c
new file mode 100644
index 0000000..70a35ec
--- /dev/null
+++ b/lib/smbconf/smbconf_txt.c
@@ -0,0 +1,682 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library, text backend
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This is a sample implementation of a libsmbconf text backend
+ * using the params.c parser.
+ *
+ * It is read only.
+ * Don't expect brilliant performance, since it is not hashing the lists.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+#include "lib/smbconf/smbconf_txt.h"
+
+struct txt_cache {
+ uint32_t current_share;
+ uint32_t num_shares;
+ char **share_names;
+ uint32_t *num_params;
+ char ***param_names;
+ char ***param_values;
+};
+
+struct txt_private_data {
+ struct txt_cache *cache;
+ uint64_t csn;
+ bool verbatim;
+};
+
+/**********************************************************************
+ *
+ * helper functions
+ *
+ **********************************************************************/
+
+/**
+ * a convenience helper to cast the private data structure
+ */
+static struct txt_private_data *pd(struct smbconf_ctx *ctx)
+{
+ return (struct txt_private_data *)(ctx->data);
+}
+
+static bool smbconf_txt_do_section(const char *section, void *private_data)
+{
+ sbcErr err;
+ uint32_t idx;
+ struct txt_private_data *tpd = (struct txt_private_data *)private_data;
+ struct txt_cache *cache = tpd->cache;
+
+ if (smbconf_find_in_array(section, cache->share_names,
+ cache->num_shares, &idx))
+ {
+ cache->current_share = idx;
+ return true;
+ }
+
+ err = smbconf_add_string_to_array(cache, &(cache->share_names),
+ cache->num_shares, section);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return false;
+ }
+ cache->current_share = cache->num_shares;
+ cache->num_shares++;
+
+ cache->param_names = talloc_realloc(cache,
+ cache->param_names,
+ char **,
+ cache->num_shares);
+ if (cache->param_names == NULL) {
+ return false;
+ }
+ cache->param_names[cache->current_share] = NULL;
+
+ cache->param_values = talloc_realloc(cache,
+ cache->param_values,
+ char **,
+ cache->num_shares);
+ if (cache->param_values == NULL) {
+ return false;
+ }
+ cache->param_values[cache->current_share] = NULL;
+
+ cache->num_params = talloc_realloc(cache,
+ cache->num_params,
+ uint32_t,
+ cache->num_shares);
+ if (cache->num_params == NULL) {
+ return false;
+ }
+ cache->num_params[cache->current_share] = 0;
+
+ return true;
+}
+
+static bool smbconf_txt_do_parameter(const char *param_name,
+ const char *param_value,
+ void *private_data)
+{
+ sbcErr err;
+ char **param_names, **param_values;
+ uint32_t num_params;
+ uint32_t idx;
+ struct txt_private_data *tpd = (struct txt_private_data *)private_data;
+ struct txt_cache *cache = tpd->cache;
+
+ if (cache->num_shares == 0) {
+ /*
+ * not in any share yet,
+ * initialize the "empty" section (NULL):
+ * parameters without a previous [section] are stored here.
+ */
+ if (!smbconf_txt_do_section(NULL, private_data)) {
+ return false;
+ }
+ }
+
+ param_names = cache->param_names[cache->current_share];
+ param_values = cache->param_values[cache->current_share];
+ num_params = cache->num_params[cache->current_share];
+
+ if (!(tpd->verbatim) &&
+ smbconf_find_in_array(param_name, param_names, num_params, &idx))
+ {
+ talloc_free(param_values[idx]);
+ param_values[idx] = talloc_strdup(cache, param_value);
+ if (param_values[idx] == NULL) {
+ return false;
+ }
+ return true;
+ }
+ err = smbconf_add_string_to_array(cache,
+ &(cache->param_names[cache->current_share]),
+ num_params, param_name);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return false;
+ }
+ err = smbconf_add_string_to_array(cache,
+ &(cache->param_values[cache->current_share]),
+ num_params, param_value);
+ cache->num_params[cache->current_share]++;
+ return SBC_ERROR_IS_OK(err);
+}
+
+static void smbconf_txt_flush_cache(struct smbconf_ctx *ctx)
+{
+ talloc_free(pd(ctx)->cache);
+ pd(ctx)->cache = NULL;
+}
+
+static sbcErr smbconf_txt_init_cache(struct smbconf_ctx *ctx)
+{
+ if (pd(ctx)->cache != NULL) {
+ smbconf_txt_flush_cache(ctx);
+ }
+
+ pd(ctx)->cache = talloc_zero(pd(ctx), struct txt_cache);
+
+ if (pd(ctx)->cache == NULL) {
+ return SBC_ERR_NOMEM;
+ }
+
+ return SBC_ERR_OK;
+}
+
+static sbcErr smbconf_txt_load_file(struct smbconf_ctx *ctx)
+{
+ sbcErr err;
+ uint64_t new_csn;
+ int rc;
+ struct timespec mt = {0};
+
+ if (!file_exist(ctx->path)) {
+ return SBC_ERR_BADFILE;
+ }
+
+ rc = file_modtime(ctx->path, &mt);
+ if (rc != 0) {
+ /*
+ * Not worth mapping errno returned
+ * in rc to SBC_ERR_XXX. Just assume
+ * access denied.
+ */
+ return SBC_ERR_ACCESS_DENIED;
+ }
+ new_csn = (uint64_t)mt.tv_sec;
+ if (new_csn == pd(ctx)->csn) {
+ return SBC_ERR_OK;
+ }
+
+ err = smbconf_txt_init_cache(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ if (!pm_process(ctx->path, smbconf_txt_do_section,
+ smbconf_txt_do_parameter, pd(ctx)))
+ {
+ return SBC_ERR_CAN_NOT_COMPLETE;
+ }
+
+ pd(ctx)->csn = new_csn;
+
+ return SBC_ERR_OK;
+}
+
+
+/**********************************************************************
+ *
+ * smbconf operations: text backend implementations
+ *
+ **********************************************************************/
+
+/**
+ * initialize the text based smbconf backend
+ */
+static sbcErr smbconf_txt_init(struct smbconf_ctx *ctx, const char *path)
+{
+ if (path == NULL) {
+ return SBC_ERR_BADFILE;
+ }
+ ctx->path = talloc_strdup(ctx, path);
+ if (ctx->path == NULL) {
+ return SBC_ERR_NOMEM;
+ }
+
+ ctx->data = talloc_zero(ctx, struct txt_private_data);
+ if (ctx->data == NULL) {
+ return SBC_ERR_NOMEM;
+ }
+
+ pd(ctx)->verbatim = true;
+
+ return SBC_ERR_OK;
+}
+
+static int smbconf_txt_shutdown(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->close_conf(ctx);
+}
+
+static bool smbconf_txt_requires_messaging(struct smbconf_ctx *ctx)
+{
+ return false;
+}
+
+static bool smbconf_txt_is_writeable(struct smbconf_ctx *ctx)
+{
+ /* no write support in this backend yet... */
+ return false;
+}
+
+static sbcErr smbconf_txt_open(struct smbconf_ctx *ctx)
+{
+ return smbconf_txt_load_file(ctx);
+}
+
+static int smbconf_txt_close(struct smbconf_ctx *ctx)
+{
+ smbconf_txt_flush_cache(ctx);
+ return 0;
+}
+
+/**
+ * Get the change sequence number of the given service/parameter.
+ * service and parameter strings may be NULL.
+ */
+static void smbconf_txt_get_csn(struct smbconf_ctx *ctx,
+ struct smbconf_csn *csn,
+ const char *service, const char *param)
+{
+ struct timespec mt = {0};
+
+ if (csn == NULL) {
+ return;
+ }
+
+ (void)file_modtime(ctx->path, &mt);
+ csn->csn = (uint64_t)mt.tv_sec;
+}
+
+/**
+ * Drop the whole configuration (restarting empty)
+ */
+static sbcErr smbconf_txt_drop(struct smbconf_ctx *ctx)
+{
+ return SBC_ERR_NOT_SUPPORTED;
+}
+
+/**
+ * get the list of share names defined in the configuration.
+ */
+static sbcErr smbconf_txt_get_share_names(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *num_shares,
+ char ***share_names)
+{
+ uint32_t count;
+ uint32_t added_count = 0;
+ TALLOC_CTX *tmp_ctx = NULL;
+ sbcErr err = SBC_ERR_OK;
+ char **tmp_share_names = NULL;
+
+ if ((num_shares == NULL) || (share_names == NULL)) {
+ return SBC_ERR_INVALID_PARAM;
+ }
+
+ err = smbconf_txt_load_file(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ /* make sure "global" is always listed first,
+ * possibly after NULL section */
+
+ if (smbconf_share_exists(ctx, NULL)) {
+ err = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ 0, NULL);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ if (smbconf_share_exists(ctx, GLOBAL_NAME)) {
+ err = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ added_count, GLOBAL_NAME);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ for (count = 0; count < pd(ctx)->cache->num_shares; count++) {
+ if (strequal(pd(ctx)->cache->share_names[count], GLOBAL_NAME) ||
+ (pd(ctx)->cache->share_names[count] == NULL))
+ {
+ continue;
+ }
+
+ err = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
+ added_count,
+ pd(ctx)->cache->share_names[count]);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+ added_count++;
+ }
+
+ *num_shares = added_count;
+ if (added_count > 0) {
+ *share_names = talloc_move(mem_ctx, &tmp_share_names);
+ } else {
+ *share_names = NULL;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return err;
+}
+
+/**
+ * check if a share/service of a given name exists
+ */
+static bool smbconf_txt_share_exists(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ sbcErr err;
+
+ err = smbconf_txt_load_file(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return false;
+ }
+
+ return smbconf_find_in_array(servicename,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares, NULL);
+}
+
+/**
+ * Add a service if it does not already exist
+ */
+static sbcErr smbconf_txt_create_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ return SBC_ERR_NOT_SUPPORTED;
+}
+
+/**
+ * get a definition of a share (service) from configuration.
+ */
+static sbcErr smbconf_txt_get_share(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *servicename,
+ struct smbconf_service **service)
+{
+ sbcErr err;
+ uint32_t sidx, count;
+ bool found;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct smbconf_service *tmp_service = NULL;
+
+ err = smbconf_txt_load_file(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ found = smbconf_find_in_array(servicename,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares,
+ &sidx);
+ if (!found) {
+ return SBC_ERR_NO_SUCH_SERVICE;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ tmp_service = talloc_zero(tmp_ctx, struct smbconf_service);
+ if (tmp_service == NULL) {
+ err = SBC_ERR_NOMEM;
+ goto done;
+ }
+
+ if (servicename != NULL) {
+ tmp_service->name = talloc_strdup(tmp_service, servicename);
+ if (tmp_service->name == NULL) {
+ err = SBC_ERR_NOMEM;
+ goto done;
+ }
+ }
+
+ for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
+ err = smbconf_add_string_to_array(tmp_service,
+ &(tmp_service->param_names),
+ count,
+ pd(ctx)->cache->param_names[sidx][count]);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+ err = smbconf_add_string_to_array(tmp_service,
+ &(tmp_service->param_values),
+ count,
+ pd(ctx)->cache->param_values[sidx][count]);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+ }
+
+ tmp_service->num_params = count;
+ *service = talloc_move(mem_ctx, &tmp_service);
+
+done:
+ talloc_free(tmp_ctx);
+ return err;
+}
+
+/**
+ * delete a service from configuration
+ */
+static sbcErr smbconf_txt_delete_share(struct smbconf_ctx *ctx,
+ const char *servicename)
+{
+ return SBC_ERR_NOT_SUPPORTED;
+}
+
+/**
+ * set a configuration parameter to the value provided.
+ */
+static sbcErr smbconf_txt_set_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param,
+ const char *valstr)
+{
+ return SBC_ERR_NOT_SUPPORTED;
+}
+
+/**
+ * get the value of a configuration parameter as a string
+ */
+static sbcErr smbconf_txt_get_parameter(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ const char *param,
+ char **valstr)
+{
+ sbcErr err;
+ bool found;
+ uint32_t share_index, param_index;
+
+ err = smbconf_txt_load_file(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ found = smbconf_find_in_array(service,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares,
+ &share_index);
+ if (!found) {
+ return SBC_ERR_NO_SUCH_SERVICE;
+ }
+
+ found = smbconf_reverse_find_in_array(param,
+ pd(ctx)->cache->param_names[share_index],
+ pd(ctx)->cache->num_params[share_index],
+ &param_index);
+ if (!found) {
+ return SBC_ERR_INVALID_PARAM;
+ }
+
+ *valstr = talloc_strdup(mem_ctx,
+ pd(ctx)->cache->param_values[share_index][param_index]);
+
+ if (*valstr == NULL) {
+ return SBC_ERR_NOMEM;
+ }
+
+ return SBC_ERR_OK;
+}
+
+/**
+ * delete a parameter from configuration
+ */
+static sbcErr smbconf_txt_delete_parameter(struct smbconf_ctx *ctx,
+ const char *service,
+ const char *param)
+{
+ return SBC_ERR_NOT_SUPPORTED;
+}
+
+static sbcErr smbconf_txt_get_includes(struct smbconf_ctx *ctx,
+ TALLOC_CTX *mem_ctx,
+ const char *service,
+ uint32_t *num_includes,
+ char ***includes)
+{
+ sbcErr err;
+ bool found;
+ uint32_t sidx, count;
+ TALLOC_CTX *tmp_ctx = NULL;
+ uint32_t tmp_num_includes = 0;
+ char **tmp_includes = NULL;
+
+ err = smbconf_txt_load_file(ctx);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ found = smbconf_find_in_array(service,
+ pd(ctx)->cache->share_names,
+ pd(ctx)->cache->num_shares,
+ &sidx);
+ if (!found) {
+ return SBC_ERR_NO_SUCH_SERVICE;
+ }
+
+ tmp_ctx = talloc_stackframe();
+
+ for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
+ if (strequal(pd(ctx)->cache->param_names[sidx][count],
+ "include"))
+ {
+ err = smbconf_add_string_to_array(tmp_ctx,
+ &tmp_includes,
+ tmp_num_includes,
+ pd(ctx)->cache->param_values[sidx][count]);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto done;
+ }
+ tmp_num_includes++;
+ }
+ }
+
+ *num_includes = tmp_num_includes;
+ if (*num_includes > 0) {
+ *includes = talloc_move(mem_ctx, &tmp_includes);
+ if (*includes == NULL) {
+ err = SBC_ERR_NOMEM;
+ goto done;
+ }
+ } else {
+ *includes = NULL;
+ }
+
+ err = SBC_ERR_OK;
+
+done:
+ talloc_free(tmp_ctx);
+ return err;
+}
+
+static sbcErr smbconf_txt_set_includes(struct smbconf_ctx *ctx,
+ const char *service,
+ uint32_t num_includes,
+ const char **includes)
+{
+ return SBC_ERR_NOT_SUPPORTED;
+}
+
+static sbcErr smbconf_txt_delete_includes(struct smbconf_ctx *ctx,
+ const char *service)
+{
+ return SBC_ERR_NOT_SUPPORTED;
+}
+
+static sbcErr smbconf_txt_transaction_start(struct smbconf_ctx *ctx)
+{
+ return SBC_ERR_OK;
+}
+
+static sbcErr smbconf_txt_transaction_commit(struct smbconf_ctx *ctx)
+{
+ return SBC_ERR_OK;
+}
+
+static sbcErr smbconf_txt_transaction_cancel(struct smbconf_ctx *ctx)
+{
+ return SBC_ERR_OK;
+}
+
+static struct smbconf_ops smbconf_ops_txt = {
+ .init = smbconf_txt_init,
+ .shutdown = smbconf_txt_shutdown,
+ .requires_messaging = smbconf_txt_requires_messaging,
+ .is_writeable = smbconf_txt_is_writeable,
+ .open_conf = smbconf_txt_open,
+ .close_conf = smbconf_txt_close,
+ .get_csn = smbconf_txt_get_csn,
+ .drop = smbconf_txt_drop,
+ .get_share_names = smbconf_txt_get_share_names,
+ .share_exists = smbconf_txt_share_exists,
+ .create_share = smbconf_txt_create_share,
+ .get_share = smbconf_txt_get_share,
+ .delete_share = smbconf_txt_delete_share,
+ .set_parameter = smbconf_txt_set_parameter,
+ .get_parameter = smbconf_txt_get_parameter,
+ .delete_parameter = smbconf_txt_delete_parameter,
+ .get_includes = smbconf_txt_get_includes,
+ .set_includes = smbconf_txt_set_includes,
+ .delete_includes = smbconf_txt_delete_includes,
+ .transaction_start = smbconf_txt_transaction_start,
+ .transaction_commit = smbconf_txt_transaction_commit,
+ .transaction_cancel = smbconf_txt_transaction_cancel,
+};
+
+
+/**
+ * initialize the smbconf text backend
+ * the only function that is exported from this module
+ */
+sbcErr smbconf_init_txt(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx **conf_ctx,
+ const char *path)
+{
+ sbcErr err;
+
+ err = smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_txt);
+ if (!SBC_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ return smbconf_txt_load_file(*conf_ctx);
+}
diff --git a/lib/smbconf/smbconf_txt.h b/lib/smbconf/smbconf_txt.h
new file mode 100644
index 0000000..72d6207
--- /dev/null
+++ b/lib/smbconf/smbconf_txt.h
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library
+ * Copyright (C) Michael Adam 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBSMBCONF_TXT_H__
+#define __LIBSMBCONF_TXT_H__
+
+struct smbconf_ctx;
+
+/**
+ * initialization functions for the text/file backend modules
+ */
+
+sbcErr smbconf_init_txt(TALLOC_CTX *mem_ctx,
+ struct smbconf_ctx **conf_ctx,
+ const char *path);
+
+#endif /* _LIBSMBCONF_TXT_H_ */
diff --git a/lib/smbconf/smbconf_util.c b/lib/smbconf/smbconf_util.c
new file mode 100644
index 0000000..86a9598
--- /dev/null
+++ b/lib/smbconf/smbconf_util.c
@@ -0,0 +1,151 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * libsmbconf - Samba configuration library, utility functions
+ * Copyright (C) Michael Adam 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smbconf_private.h"
+
+
+static int smbconf_destroy_ctx(struct smbconf_ctx *ctx)
+{
+ return ctx->ops->shutdown(ctx);
+}
+
+/**
+ * Initialize the configuration.
+ *
+ * This should be the first function in a sequence of calls to smbconf
+ * functions:
+ *
+ * Upon success, this creates and returns the conf context
+ * that should be passed around in subsequent calls to the other
+ * smbconf functions.
+ *
+ * After the work with the configuration is completed, smbconf_shutdown()
+ * should be called.
+ */
+sbcErr smbconf_init_internal(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
+ const char *path, struct smbconf_ops *ops)
+{
+ sbcErr err = SBC_ERR_OK;
+ struct smbconf_ctx *ctx;
+
+ if (conf_ctx == NULL) {
+ return SBC_ERR_INVALID_PARAM;
+ }
+
+ ctx = talloc_zero(mem_ctx, struct smbconf_ctx);
+ if (ctx == NULL) {
+ return SBC_ERR_NOMEM;
+ }
+
+ ctx->ops = ops;
+
+ err = ctx->ops->init(ctx, path);
+ if (!SBC_ERROR_IS_OK(err)) {
+ goto fail;
+ }
+
+ talloc_set_destructor(ctx, smbconf_destroy_ctx);
+
+ *conf_ctx = ctx;
+ return err;
+
+fail:
+ talloc_free(ctx);
+ return err;
+}
+
+
+/**
+ * add a string to a talloced array of strings.
+ */
+sbcErr smbconf_add_string_to_array(TALLOC_CTX *mem_ctx,
+ char ***array,
+ uint32_t count,
+ const char *string)
+{
+ char **new_array = NULL;
+
+ if (array == NULL) {
+ return SBC_ERR_INVALID_PARAM;
+ }
+
+ new_array = talloc_realloc(mem_ctx, *array, char *, count + 1);
+ if (new_array == NULL) {
+ return SBC_ERR_NOMEM;
+ }
+
+ if (string == NULL) {
+ new_array[count] = NULL;
+ } else {
+ new_array[count] = talloc_strdup(new_array, string);
+ if (new_array[count] == NULL) {
+ talloc_free(new_array);
+ return SBC_ERR_NOMEM;
+ }
+ }
+
+ *array = new_array;
+
+ return SBC_ERR_OK;
+}
+
+bool smbconf_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry)
+{
+ uint32_t i;
+
+ if (list == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if (((string == NULL) && (list[i] == NULL)) ||
+ strequal(string, list[i]))
+ {
+ if (entry != NULL) {
+ *entry = i;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool smbconf_reverse_find_in_array(const char *string, char **list,
+ uint32_t num_entries, uint32_t *entry)
+{
+ int32_t i;
+
+ if ((string == NULL) || (list == NULL) || (num_entries == 0)) {
+ return false;
+ }
+
+ for (i = num_entries - 1; i >= 0; i--) {
+ if (strequal(string, list[i])) {
+ if (entry != NULL) {
+ *entry = i;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/smbconf/wscript_build b/lib/smbconf/wscript_build
new file mode 100644
index 0000000..97d6b18
--- /dev/null
+++ b/lib/smbconf/wscript_build
@@ -0,0 +1,10 @@
+bld.SAMBA_SUBSYSTEM('LIBSMBCONF',
+ source='smbconf.c smbconf_txt.c smbconf_util.c',
+ deps='talloc sendfile'
+ )
+
+bld.SAMBA3_PYTHON('pysmbconf',
+ source='pysmbconf.c',
+ public_deps=' '.join(['samba-util', 'tdb', 'talloc', 'smbconf']),
+ realname='samba/smbconf.so'
+ )
diff --git a/lib/socket/interfaces.c b/lib/socket/interfaces.c
new file mode 100644
index 0000000..4908b0f
--- /dev/null
+++ b/lib/socket/interfaces.c
@@ -0,0 +1,435 @@
+/*
+ Unix SMB/CIFS implementation.
+ return a list of network interfaces
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "system/network.h"
+#include "interfaces.h"
+#include "lib/util/tsort.h"
+#include "librpc/gen_ndr/ioctl.h"
+
+#ifdef HAVE_ETHTOOL
+#include "linux/sockios.h"
+#include "linux/ethtool.h"
+#endif
+
+/****************************************************************************
+ Create a struct sockaddr_storage with the netmask bits set to 1.
+****************************************************************************/
+
+bool make_netmask(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ unsigned long masklen)
+{
+ *pss_out = *pss_in;
+ /* Now apply masklen bits of mask. */
+#if defined(HAVE_IPV6)
+ if (pss_in->ss_family == AF_INET6) {
+ char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
+ unsigned int i;
+
+ if (masklen > 128) {
+ return false;
+ }
+ for (i = 0; masklen >= 8; masklen -= 8, i++) {
+ *p++ = 0xff;
+ }
+ /* Deal with the partial byte. */
+ *p++ &= (0xff & ~(0xff>>masklen));
+ i++;
+ for (;i < sizeof(struct in6_addr); i++) {
+ *p++ = '\0';
+ }
+ return true;
+ }
+#endif
+ if (pss_in->ss_family == AF_INET) {
+ if (masklen > 32) {
+ return false;
+ }
+ ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
+ htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+ Create a struct sockaddr_storage set to the broadcast or network address from
+ an incoming sockaddr_storage.
+****************************************************************************/
+
+static void make_bcast_or_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask,
+ bool make_bcast_p)
+{
+ unsigned int i = 0, len = 0;
+ const char *pmask = NULL;
+ char *p = NULL;
+ *pss_out = *pss_in;
+
+ /* Set all zero netmask bits to 1. */
+#if defined(HAVE_IPV6)
+ if (pss_in->ss_family == AF_INET6) {
+ p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
+ pmask = (const char *)&((const struct sockaddr_in6 *)nmask)->sin6_addr;
+ len = 16;
+ }
+#endif
+ if (pss_in->ss_family == AF_INET) {
+ p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
+ pmask = (const char *)&((const struct sockaddr_in *)nmask)->sin_addr;
+ len = 4;
+ }
+
+ for (i = 0; i < len; i++, p++, pmask++) {
+ if (make_bcast_p) {
+ *p = (*p & *pmask) | (*pmask ^ 0xff);
+ } else {
+ /* make_net */
+ *p = (*p & *pmask);
+ }
+ }
+}
+
+void make_bcast(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask)
+{
+ make_bcast_or_net(pss_out, pss_in, nmask, true);
+}
+
+void make_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask)
+{
+ make_bcast_or_net(pss_out, pss_in, nmask, false);
+}
+
+#ifdef HAVE_ETHTOOL
+static void query_iface_speed_from_name(const char *name, uint64_t *speed)
+{
+ int ret = 0;
+ struct ethtool_cmd ecmd;
+ struct ethtool_value edata;
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (fd == -1) {
+ DBG_ERR("Failed to open socket.\n");
+ return;
+ }
+
+ if (strlen(name) >= IF_NAMESIZE) {
+ DBG_ERR("Interface name too long.\n");
+ goto done;
+ }
+
+ ZERO_STRUCT(ifr);
+ strlcpy(ifr.ifr_name, name, IF_NAMESIZE);
+
+ ifr.ifr_data = (void *)&edata;
+ ZERO_STRUCT(edata);
+ edata.cmd = ETHTOOL_GLINK;
+ ret = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (ret == -1) {
+ goto done;
+ }
+ if (edata.data == 0) {
+ /* no link detected */
+ *speed = 0;
+ goto done;
+ }
+
+ ifr.ifr_data = (void *)&ecmd;
+ ZERO_STRUCT(ecmd);
+ ecmd.cmd = ETHTOOL_GSET;
+ ret = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (ret == -1) {
+ goto done;
+ }
+ *speed = ((uint64_t)ethtool_cmd_speed(&ecmd)) * 1000 * 1000;
+
+done:
+ (void)close(fd);
+}
+
+static void query_iface_rx_queues_from_name(const char *name,
+ uint64_t *rx_queues)
+{
+ int ret = 0;
+ struct ethtool_rxnfc rxcmd;
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (fd == -1) {
+ DBG_ERR("Failed to open socket.\n");
+ return;
+ }
+
+ if (strlen(name) >= IF_NAMESIZE) {
+ DBG_ERR("Interface name too long.\n");
+ goto done;
+ }
+
+ ZERO_STRUCT(ifr);
+ strlcpy(ifr.ifr_name, name, IF_NAMESIZE);
+
+ ifr.ifr_data = (void *)&rxcmd;
+ ZERO_STRUCT(rxcmd);
+ rxcmd.cmd = ETHTOOL_GRXRINGS;
+ ret = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (ret == -1) {
+ goto done;
+ }
+
+ *rx_queues = rxcmd.data;
+
+done:
+ (void)close(fd);
+}
+#endif
+
+/****************************************************************************
+ Try the "standard" getifaddrs/freeifaddrs interfaces.
+ Also gets IPv6 interfaces.
+****************************************************************************/
+
+/****************************************************************************
+ Get the netmask address for a local interface.
+****************************************************************************/
+
+static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
+{
+ struct iface_struct *ifaces;
+ struct ifaddrs *iflist = NULL;
+ struct ifaddrs *ifptr = NULL;
+ int count;
+ int total = 0;
+ size_t copy_size;
+
+ if (getifaddrs(&iflist) < 0) {
+ return -1;
+ }
+
+ count = 0;
+ for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
+ if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
+ continue;
+ }
+ if (!(ifptr->ifa_flags & IFF_UP)) {
+ continue;
+ }
+ count += 1;
+ }
+
+ ifaces = talloc_array(mem_ctx, struct iface_struct, count);
+ if (ifaces == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* Loop through interfaces, looking for given IP address */
+ for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
+ uint64_t if_speed = 1000 * 1000 * 1000; /* 1Gbps */
+ uint64_t rx_queues = 1;
+
+ if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
+ continue;
+ }
+
+ /* Check the interface is up. */
+ if (!(ifptr->ifa_flags & IFF_UP)) {
+ continue;
+ }
+
+ memset(&ifaces[total], '\0', sizeof(ifaces[total]));
+
+ copy_size = sizeof(struct sockaddr_in);
+
+ ifaces[total].flags = ifptr->ifa_flags;
+
+#if defined(HAVE_IPV6)
+ if (ifptr->ifa_addr->sa_family == AF_INET6) {
+ copy_size = sizeof(struct sockaddr_in6);
+ }
+#endif
+
+ memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
+ memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
+
+ /* calculate broadcast address */
+#if defined(HAVE_IPV6)
+ if (ifptr->ifa_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6 *)ifptr->ifa_addr;
+ struct in6_addr *in6 =
+ (struct in6_addr *)&sin6->sin6_addr;
+
+ if (IN6_IS_ADDR_LINKLOCAL(in6) || IN6_IS_ADDR_V4COMPAT(in6)) {
+ continue;
+ }
+ /* IPv6 does not have broadcast it uses multicast. */
+ memset(&ifaces[total].bcast, '\0', copy_size);
+ } else
+#endif
+ if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
+ make_bcast(&ifaces[total].bcast,
+ &ifaces[total].ip,
+ &ifaces[total].netmask);
+ } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
+ ifptr->ifa_dstaddr ) {
+ memcpy(&ifaces[total].bcast,
+ ifptr->ifa_dstaddr,
+ copy_size);
+ } else {
+ continue;
+ }
+
+ ifaces[total].if_index = if_nametoindex(ifptr->ifa_name);
+ if (ifaces[total].if_index == 0) {
+ DBG_ERR("Failed to retrieve interface index for '%s': "
+ "%s\n", ifptr->ifa_name, strerror(errno));
+ }
+
+#ifdef HAVE_ETHTOOL
+ query_iface_speed_from_name(ifptr->ifa_name, &if_speed);
+ query_iface_rx_queues_from_name(ifptr->ifa_name, &rx_queues);
+#endif
+ ifaces[total].linkspeed = if_speed;
+ ifaces[total].capability = FSCTL_NET_IFACE_NONE_CAPABLE;
+ if (rx_queues > 1) {
+ ifaces[total].capability |= FSCTL_NET_IFACE_RSS_CAPABLE;
+ }
+
+ if (strlcpy(ifaces[total].name, ifptr->ifa_name,
+ sizeof(ifaces[total].name)) >=
+ sizeof(ifaces[total].name)) {
+ /* Truncation ! Ignore. */
+ continue;
+ }
+ total++;
+ }
+
+ freeifaddrs(iflist);
+
+ *pifaces = ifaces;
+ return total;
+}
+
+static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
+{
+ int r;
+
+#if defined(HAVE_IPV6)
+ /*
+ * If we have IPv6 - sort these interfaces lower
+ * than any IPv4 ones.
+ */
+ if (i1->ip.ss_family == AF_INET6 &&
+ i2->ip.ss_family == AF_INET) {
+ return -1;
+ } else if (i1->ip.ss_family == AF_INET &&
+ i2->ip.ss_family == AF_INET6) {
+ return 1;
+ }
+
+ if (i1->ip.ss_family == AF_INET6) {
+ struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
+ struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
+
+ r = memcmp(&s1->sin6_addr,
+ &s2->sin6_addr,
+ sizeof(struct in6_addr));
+ if (r) {
+ return r;
+ }
+
+ s1 = (struct sockaddr_in6 *)&i1->netmask;
+ s2 = (struct sockaddr_in6 *)&i2->netmask;
+
+ r = memcmp(&s1->sin6_addr,
+ &s2->sin6_addr,
+ sizeof(struct in6_addr));
+ if (r) {
+ return r;
+ }
+ }
+#endif
+
+ /* AIX uses __ss_family instead of ss_family inside of
+ sockaddr_storage. Instead of trying to figure out which field to
+ use, we can just cast it to a sockaddr.
+ */
+
+ if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
+ struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
+ struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
+
+ r = ntohl(s1->sin_addr.s_addr) -
+ ntohl(s2->sin_addr.s_addr);
+ if (r) {
+ return r;
+ }
+
+ s1 = (struct sockaddr_in *)&i1->netmask;
+ s2 = (struct sockaddr_in *)&i2->netmask;
+
+ return ntohl(s1->sin_addr.s_addr) -
+ ntohl(s2->sin_addr.s_addr);
+ }
+ return 0;
+}
+
+/* this wrapper is used to remove duplicates from the interface list generated
+ above */
+int get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
+{
+ struct iface_struct *ifaces = NULL;
+ int total, i, j;
+
+ total = _get_interfaces(mem_ctx, &ifaces);
+ /* If we have an error, no interface or just one we can leave */
+ if (total <= 1) {
+ *pifaces = ifaces;
+ return total;
+ }
+
+ /* now we need to remove duplicates */
+ TYPESAFE_QSORT(ifaces, total, iface_comp);
+
+ for (i=1;i<total;) {
+ if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
+ for (j=i-1;j<total-1;j++) {
+ ifaces[j] = ifaces[j+1];
+ }
+ total--;
+ } else {
+ i++;
+ }
+ }
+
+ *pifaces = ifaces;
+ return total;
+}
diff --git a/lib/socket/interfaces.h b/lib/socket/interfaces.h
new file mode 100644
index 0000000..0876f09
--- /dev/null
+++ b/lib/socket/interfaces.h
@@ -0,0 +1,47 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ structures for lib/netif/
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "system/network.h"
+
+struct iface_struct {
+ char name[16];
+ int flags;
+ struct sockaddr_storage ip;
+ struct sockaddr_storage netmask;
+ struct sockaddr_storage bcast;
+ uint32_t if_index;
+ uint64_t linkspeed;
+ uint32_t capability;
+};
+
+struct interface;
+
+bool make_netmask(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ unsigned long masklen);
+void make_bcast(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask);
+void make_net(struct sockaddr_storage *pss_out,
+ const struct sockaddr_storage *pss_in,
+ const struct sockaddr_storage *nmask);
+
+int get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces);
diff --git a/lib/socket/wscript b/lib/socket/wscript
new file mode 100644
index 0000000..d8c269a
--- /dev/null
+++ b/lib/socket/wscript
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+def configure(conf):
+ conf.CHECK_HEADERS('linux/sockios.h linux/ethtool.h')
+ if (conf.CONFIG_SET('HAVE_LINUX_SOCKIOS_H') and \
+ conf.CONFIG_SET('HAVE_LINUX_ETHTOOL_H')):
+ conf.DEFINE('HAVE_ETHTOOL', 1)
diff --git a/lib/socket/wscript_build b/lib/socket/wscript_build
new file mode 100644
index 0000000..92e5aef
--- /dev/null
+++ b/lib/socket/wscript_build
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('interfaces',
+ source='interfaces.c',
+ deps='samba-util samba-debug',
+ private_library=True
+ )
diff --git a/lib/talloc/ABI/pytalloc-util-2.0.6.sigs b/lib/talloc/ABI/pytalloc-util-2.0.6.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.0.6.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.0.7.sigs b/lib/talloc/ABI/pytalloc-util-2.0.7.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.0.7.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.0.8.sigs b/lib/talloc/ABI/pytalloc-util-2.0.8.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.0.8.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.0.sigs b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.1.sigs b/lib/talloc/ABI/pytalloc-util-2.1.1.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.1.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.10.sigs b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.11.sigs b/lib/talloc/ABI/pytalloc-util-2.1.11.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.11.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.12.sigs b/lib/talloc/ABI/pytalloc-util-2.1.12.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.12.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.13.sigs b/lib/talloc/ABI/pytalloc-util-2.1.13.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.13.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.14.sigs b/lib/talloc/ABI/pytalloc-util-2.1.14.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.14.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.15.sigs b/lib/talloc/ABI/pytalloc-util-2.1.15.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.15.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.16.sigs b/lib/talloc/ABI/pytalloc-util-2.1.16.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.16.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.2.sigs b/lib/talloc/ABI/pytalloc-util-2.1.2.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.2.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.3.sigs b/lib/talloc/ABI/pytalloc-util-2.1.3.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.3.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.4.sigs b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.5.sigs b/lib/talloc/ABI/pytalloc-util-2.1.5.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.5.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.6.sigs b/lib/talloc/ABI/pytalloc-util-2.1.6.sigs
new file mode 100644
index 0000000..666fec0
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.6.sigs
@@ -0,0 +1,13 @@
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.7.sigs b/lib/talloc/ABI/pytalloc-util-2.1.7.sigs
new file mode 100644
index 0000000..666fec0
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.7.sigs
@@ -0,0 +1,13 @@
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.8.sigs b/lib/talloc/ABI/pytalloc-util-2.1.8.sigs
new file mode 100644
index 0000000..666fec0
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.8.sigs
@@ -0,0 +1,13 @@
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.1.9.sigs b/lib/talloc/ABI/pytalloc-util-2.1.9.sigs
new file mode 100644
index 0000000..9d4d4d1
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.9.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.2.0.sigs b/lib/talloc/ABI/pytalloc-util-2.2.0.sigs
new file mode 100644
index 0000000..62f066f
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.2.0.sigs
@@ -0,0 +1,15 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.3.0.sigs b/lib/talloc/ABI/pytalloc-util-2.3.0.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.3.0.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.3.1.sigs b/lib/talloc/ABI/pytalloc-util-2.3.1.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.3.1.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.3.2.sigs b/lib/talloc/ABI/pytalloc-util-2.3.2.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.3.2.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.3.3.sigs b/lib/talloc/ABI/pytalloc-util-2.3.3.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.3.3.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.3.4.sigs b/lib/talloc/ABI/pytalloc-util-2.3.4.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.3.4.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.3.5.sigs b/lib/talloc/ABI/pytalloc-util-2.3.5.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.3.5.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.4.0.sigs b/lib/talloc/ABI/pytalloc-util-2.4.0.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.4.0.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.4.1.sigs b/lib/talloc/ABI/pytalloc-util-2.4.1.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.4.1.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/pytalloc-util-2.4.2.sigs b/lib/talloc/ABI/pytalloc-util-2.4.2.sigs
new file mode 100644
index 0000000..6056577
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.4.2.sigs
@@ -0,0 +1,16 @@
+_pytalloc_check_type: int (PyObject *, const char *)
+_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *)
+_pytalloc_get_name: const char *(PyObject *)
+_pytalloc_get_ptr: void *(PyObject *)
+_pytalloc_get_type: void *(PyObject *, const char *)
+pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *)
+pytalloc_BaseObject_check: int (PyObject *)
+pytalloc_BaseObject_size: size_t (void)
+pytalloc_Check: int (PyObject *)
+pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *)
+pytalloc_GetBaseObjectType: PyTypeObject *(void)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/talloc-2.0.2.sigs b/lib/talloc/ABI/talloc-2.0.2.sigs
new file mode 100644
index 0000000..6e236d5
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.0.2.sigs
@@ -0,0 +1,62 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.0.3.sigs b/lib/talloc/ABI/talloc-2.0.3.sigs
new file mode 100644
index 0000000..6e236d5
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.0.3.sigs
@@ -0,0 +1,62 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.0.4.sigs b/lib/talloc/ABI/talloc-2.0.4.sigs
new file mode 100644
index 0000000..6e236d5
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.0.4.sigs
@@ -0,0 +1,62 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.0.5.sigs b/lib/talloc/ABI/talloc-2.0.5.sigs
new file mode 100644
index 0000000..6e236d5
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.0.5.sigs
@@ -0,0 +1,62 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.0.6.sigs b/lib/talloc/ABI/talloc-2.0.6.sigs
new file mode 100644
index 0000000..6e236d5
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.0.6.sigs
@@ -0,0 +1,62 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.0.7.sigs b/lib/talloc/ABI/talloc-2.0.7.sigs
new file mode 100644
index 0000000..6e236d5
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.0.7.sigs
@@ -0,0 +1,62 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.0.8.sigs b/lib/talloc/ABI/talloc-2.0.8.sigs
new file mode 100644
index 0000000..15a9e95
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.0.8.sigs
@@ -0,0 +1,63 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.0.sigs b/lib/talloc/ABI/talloc-2.1.0.sigs
new file mode 100644
index 0000000..eae12cc
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.0.sigs
@@ -0,0 +1,64 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.1.sigs b/lib/talloc/ABI/talloc-2.1.1.sigs
new file mode 100644
index 0000000..eae12cc
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.1.sigs
@@ -0,0 +1,64 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.10.sigs b/lib/talloc/ABI/talloc-2.1.10.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.10.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.11.sigs b/lib/talloc/ABI/talloc-2.1.11.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.11.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.12.sigs b/lib/talloc/ABI/talloc-2.1.12.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.12.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.13.sigs b/lib/talloc/ABI/talloc-2.1.13.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.13.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.14.sigs b/lib/talloc/ABI/talloc-2.1.14.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.14.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.15.sigs b/lib/talloc/ABI/talloc-2.1.15.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.15.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.16.sigs b/lib/talloc/ABI/talloc-2.1.16.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.16.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.2.sigs b/lib/talloc/ABI/talloc-2.1.2.sigs
new file mode 100644
index 0000000..eae12cc
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.2.sigs
@@ -0,0 +1,64 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.3.sigs b/lib/talloc/ABI/talloc-2.1.3.sigs
new file mode 100644
index 0000000..eae12cc
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.3.sigs
@@ -0,0 +1,64 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.4.sigs b/lib/talloc/ABI/talloc-2.1.4.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.4.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.5.sigs b/lib/talloc/ABI/talloc-2.1.5.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.5.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.6.sigs b/lib/talloc/ABI/talloc-2.1.6.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.6.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.7.sigs b/lib/talloc/ABI/talloc-2.1.7.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.7.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.8.sigs b/lib/talloc/ABI/talloc-2.1.8.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.8.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.1.9.sigs b/lib/talloc/ABI/talloc-2.1.9.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.9.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.2.0.sigs b/lib/talloc/ABI/talloc-2.2.0.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.2.0.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.3.0.sigs b/lib/talloc/ABI/talloc-2.3.0.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.3.0.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.3.1.sigs b/lib/talloc/ABI/talloc-2.3.1.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.3.1.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.3.2.sigs b/lib/talloc/ABI/talloc-2.3.2.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.3.2.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.3.3.sigs b/lib/talloc/ABI/talloc-2.3.3.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.3.3.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.3.4.sigs b/lib/talloc/ABI/talloc-2.3.4.sigs
new file mode 100644
index 0000000..9969ce3
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.3.4.sigs
@@ -0,0 +1,65 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.3.5.sigs b/lib/talloc/ABI/talloc-2.3.5.sigs
new file mode 100644
index 0000000..ec3cee4
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.3.5.sigs
@@ -0,0 +1,66 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_addbuf: void (char **, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.4.0.sigs b/lib/talloc/ABI/talloc-2.4.0.sigs
new file mode 100644
index 0000000..ec3cee4
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.4.0.sigs
@@ -0,0 +1,66 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_addbuf: void (char **, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.4.1.sigs b/lib/talloc/ABI/talloc-2.4.1.sigs
new file mode 100644
index 0000000..ec3cee4
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.4.1.sigs
@@ -0,0 +1,66 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_addbuf: void (char **, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/ABI/talloc-2.4.2.sigs b/lib/talloc/ABI/talloc-2.4.2.sigs
new file mode 100644
index 0000000..ec3cee4
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.4.2.sigs
@@ -0,0 +1,66 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_addbuf: void (char **, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_test_get_magic: int (void)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/Makefile b/lib/talloc/Makefile
new file mode 100644
index 0000000..ff8e585
--- /dev/null
+++ b/lib/talloc/Makefile
@@ -0,0 +1,65 @@
+# simple makefile wrapper to run waf
+
+WAF_BIN=`PATH=buildtools/bin:../../buildtools/bin:$$PATH which waf`
+WAF_BINARY=$(PYTHON) $(WAF_BIN)
+WAF=PYTHONHASHSEED=1 WAF_MAKE=1 $(WAF_BINARY)
+
+all:
+ $(WAF) build
+
+install:
+ $(WAF) install
+
+uninstall:
+ $(WAF) uninstall
+
+test:
+ $(WAF) test $(TEST_OPTIONS)
+
+testenv:
+ $(WAF) test --testenv $(TEST_OPTIONS)
+
+quicktest:
+ $(WAF) test --quick $(TEST_OPTIONS)
+
+dist:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) dist
+
+distcheck:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) distcheck
+
+clean:
+ $(WAF) clean
+
+distclean:
+ $(WAF) distclean
+
+reconfigure: configure
+ $(WAF) reconfigure
+
+show_waf_options:
+ $(WAF) --help
+
+# some compatibility make targets
+everything: all
+
+testsuite: all
+
+check: test
+
+torture: all
+
+# this should do an install as well, once install is finished
+installcheck: test
+
+etags:
+ $(WAF) etags
+
+ctags:
+ $(WAF) ctags
+
+bin/%:: FORCE
+ $(WAF) --targets=`basename $@`
+FORCE:
diff --git a/lib/talloc/NEWS b/lib/talloc/NEWS
new file mode 100644
index 0000000..e5b3aa0
--- /dev/null
+++ b/lib/talloc/NEWS
@@ -0,0 +1,13 @@
+1.0.1 26 May 2007
+
+ BUGS
+
+ * Set name of correctly when using talloc_append_string() (metze)
+
+ LICENSE
+
+ * Change license of files in lib/replace to LGPL (was GPL). (jelmer)
+
+1.0.0 30 April 2007
+
+ Initial release.
diff --git a/lib/talloc/compat/talloc_compat1.c b/lib/talloc/compat/talloc_compat1.c
new file mode 100644
index 0000000..519e8c3
--- /dev/null
+++ b/lib/talloc/compat/talloc_compat1.c
@@ -0,0 +1,51 @@
+/*
+ Samba trivial allocation library - compat functions
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This file contains only function to build a
+ * compat talloc.so.1 library on top of talloc.so.2
+ */
+
+#include "replace.h"
+#include "talloc.h"
+
+void *_talloc_reference(const void *context, const void *ptr);
+void *_talloc_reference(const void *context, const void *ptr) {
+ return _talloc_reference_loc(context, ptr,
+ "Called from talloc compat1 "
+ "_talloc_reference");
+}
+
+void *_talloc_steal(const void *new_ctx, const void *ptr);
+void *_talloc_steal(const void *new_ctx, const void *ptr)
+{
+ return talloc_reparent(talloc_parent(ptr), new_ctx, ptr);
+}
+
+#undef talloc_free
+int talloc_free(void *ptr);
+int talloc_free(void *ptr)
+{
+ return talloc_unlink(talloc_parent(ptr), ptr);
+}
+
diff --git a/lib/talloc/compat/talloc_compat1.mk b/lib/talloc/compat/talloc_compat1.mk
new file mode 100644
index 0000000..d1817f0
--- /dev/null
+++ b/lib/talloc/compat/talloc_compat1.mk
@@ -0,0 +1,21 @@
+talloccompatdir := $(tallocdir)/compat
+
+TALLOC_COMPAT1_VERSION_MAJOR = 1
+TALLOC_COMPAT1_OBJ = $(talloccompatdir)/talloc_compat1.o
+
+TALLOC_COMPAT1_SOLIB = libtalloc-compat1-$(TALLOC_VERSION).$(SHLIBEXT)
+TALLOC_COMPAT1_SONAME = libtalloc.$(SHLIBEXT).$(TALLOC_COMPAT1_VERSION_MAJOR)
+
+$(TALLOC_COMPAT1_SOLIB): $(TALLOC_COMPAT1_OBJ) $(TALLOC_SOLIB)
+ $(SHLD) $(SHLD_FLAGS) -o $@ $(TALLOC_COMPAT1_OBJ) \
+ $(TALLOC_SOLIB) $(SONAMEFLAG)$(TALLOC_COMPAT1_SONAME)
+
+all:: $(TALLOC_COMPAT1_SOLIB)
+
+install::
+ ${INSTALLCMD} -d $(DESTDIR)$(libdir)
+ ${INSTALLCMD} -m 755 $(TALLOC_COMPAT1_SOLIB) $(DESTDIR)$(libdir)
+
+clean::
+ rm -f $(TALLOC_COMPAT1_OBJ) $(TALLOC_COMPAT1_SOLIB)
+
diff --git a/lib/talloc/configure b/lib/talloc/configure
new file mode 100755
index 0000000..af76185
--- /dev/null
+++ b/lib/talloc/configure
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PREVPATH=$(dirname $0)
+
+if [ -f $PREVPATH/../../buildtools/bin/waf ]; then
+ WAF=../../buildtools/bin/waf
+elif [ -f $PREVPATH/buildtools/bin/waf ]; then
+ WAF=./buildtools/bin/waf
+else
+ echo "replace: Unable to find waf"
+ exit 1
+fi
+
+# using JOBS=1 gives maximum compatibility with
+# systems like AIX which have broken threading in python
+JOBS=1
+export JOBS
+
+# Make sure we don't have any library preloaded.
+unset LD_PRELOAD
+
+# Make sure we get stable hashes
+PYTHONHASHSEED=1
+export PYTHONHASHSEED
+
+cd . || exit 1
+$PYTHON $WAF configure "$@" || exit 1
+cd $PREVPATH
diff --git a/lib/talloc/doc/context.png b/lib/talloc/doc/context.png
new file mode 100644
index 0000000..48a6ca0
--- /dev/null
+++ b/lib/talloc/doc/context.png
Binary files differ
diff --git a/lib/talloc/doc/context_tree.png b/lib/talloc/doc/context_tree.png
new file mode 100644
index 0000000..9723459
--- /dev/null
+++ b/lib/talloc/doc/context_tree.png
Binary files differ
diff --git a/lib/talloc/doc/mainpage.dox b/lib/talloc/doc/mainpage.dox
new file mode 100644
index 0000000..ece6ccb
--- /dev/null
+++ b/lib/talloc/doc/mainpage.dox
@@ -0,0 +1,111 @@
+/**
+ * @mainpage
+ *
+ * talloc is a hierarchical, reference counted memory pool system with
+ * destructors. It is the core memory allocator used in Samba.
+ *
+ * @section talloc_download Download
+ *
+ * You can download the latest releases of talloc from the
+ * <a href="http://samba.org/ftp/talloc" target="_blank">talloc directory</a>
+ * on the samba public source archive.
+ *
+ * @section main-tutorial Tutorial
+ *
+ * You should start by reading @subpage libtalloc_tutorial, then reading the documentation of
+ * the interesting functions as you go.
+
+ * @section talloc_bugs Discussion and bug reports
+ *
+ * talloc does not currently have its own mailing list or bug tracking system.
+ * For now, please use the
+ * <a href="https://lists.samba.org/mailman/listinfo/samba-technical" target="_blank">samba-technical</a>
+ * mailing list, and the
+ * <a href="http://bugzilla.samba.org/" target="_blank">Samba bugzilla</a>
+ * bug tracking system.
+ *
+ * @section talloc_devel Development
+ * You can download the latest code either via git or rsync.
+ *
+ * To fetch via git see the following guide:
+ *
+ * <a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development" target="_blank">Using Git for Samba Development</a>
+ *
+ * Once you have cloned the tree switch to the master branch and cd into the
+ * lib/tevent directory.
+ *
+ * To fetch via rsync use this command:
+ *
+ * rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/talloc .
+ *
+ * @section talloc_preample Preamble
+ *
+ * talloc is a hierarchical, reference counted memory pool system with
+ * destructors.
+ *
+ * Perhaps the biggest difference from other memory pool systems is that there
+ * is no distinction between a "talloc context" and a "talloc pointer". Any
+ * pointer returned from talloc() is itself a valid talloc context. This means
+ * you can do this:
+ *
+ * @code
+ * struct foo *X = talloc(mem_ctx, struct foo);
+ * X->name = talloc_strdup(X, "foo");
+ * @endcode
+ *
+ * The pointer X->name would be a "child" of the talloc context "X" which is
+ * itself a child of mem_ctx. So if you do talloc_free(mem_ctx) then it is all
+ * destroyed, whereas if you do talloc_free(X) then just X and X->name are
+ * destroyed, and if you do talloc_free(X->name) then just the name element of
+ * X is destroyed.
+ *
+ * If you think about this, then what this effectively gives you is an n-ary
+ * tree, where you can free any part of the tree with talloc_free().
+ *
+ * If you find this confusing, then run the testsuite to watch talloc in
+ * action. You may also like to add your own tests to testsuite.c to clarify
+ * how some particular situation is handled.
+ *
+ * @section talloc_performance Performance
+ *
+ * All the additional features of talloc() over malloc() do come at a price. We
+ * have a simple performance test in Samba4 that measures talloc() versus
+ * malloc() performance, and it seems that talloc() is about 4% slower than
+ * malloc() on my x86 Debian Linux box. For Samba, the great reduction in code
+ * complexity that we get by using talloc makes this worthwhile, especially as
+ * the total overhead of talloc/malloc in Samba is already quite small.
+ *
+ * @section talloc_named Named blocks
+ *
+ * Every talloc chunk has a name that can be used as a dynamic type-checking
+ * system. If for some reason like a callback function you had to cast a
+ * "struct foo *" to a "void *" variable, later you can safely reassign the
+ * "void *" pointer to a "struct foo *" by using the talloc_get_type() or
+ * talloc_get_type_abort() macros.
+ *
+ * @code
+ * struct foo *X = talloc_get_type_abort(ptr, struct foo);
+ * @endcode
+ *
+ * This will abort if "ptr" does not contain a pointer that has been created
+ * with talloc(mem_ctx, struct foo).
+ *
+ * @section talloc_threading Multi-threading
+ *
+ * talloc itself does not deal with threads. It is thread-safe (assuming the
+ * underlying "malloc" is), as long as each thread uses different memory
+ * contexts.
+ *
+ * If two threads uses the same context then they need to synchronize in order
+ * to be safe. In particular:
+ *
+ * - when using talloc_enable_leak_report(), giving directly NULL as a parent
+ * context implicitly refers to a hidden "null context" global variable, so
+ * this should not be used in a multi-threaded environment without proper
+ * synchronization. In threaded code turn off null tracking using
+ * talloc_disable_null_tracking().
+ * - the context returned by talloc_autofree_context() is also global so
+ * shouldn't be used by several threads simultaneously without
+ * synchronization.
+ *
+ */
diff --git a/lib/talloc/doc/stealing.png b/lib/talloc/doc/stealing.png
new file mode 100644
index 0000000..8833e06
--- /dev/null
+++ b/lib/talloc/doc/stealing.png
Binary files differ
diff --git a/lib/talloc/doc/tutorial_bestpractices.dox b/lib/talloc/doc/tutorial_bestpractices.dox
new file mode 100644
index 0000000..3634446
--- /dev/null
+++ b/lib/talloc/doc/tutorial_bestpractices.dox
@@ -0,0 +1,192 @@
+/**
+@page libtalloc_bestpractices Chapter 7: Best practises
+
+The following sections contain several best practices and good manners that were
+found by the <a href="http://www.samba.org">Samba</a> and
+<a href="https://fedorahosted.org/sssd">SSSD</a> developers over the years.
+These will help you to write code which is better, easier to debug and with as
+few (hopefully none) memory leaks as possible.
+
+@section bp-hierarchy Keep the context hierarchy steady
+
+The talloc is a hierarchy memory allocator. The hierarchy nature is what makes
+the programming more error proof. It makes the memory easier to manage and to
+free. Therefore, the first thing we should have on our mind is: always project
+your data structures into the talloc context hierarchy.
+
+That means if we have a structure, we should always use it as a parent context
+for its elements. This way we will not encounter any troubles when freeing the
+structure or when changing its parent. The same rule applies for arrays.
+
+For example, the structure <code>user</code> from section @ref context-hierarchy
+should be created with the context hierarchy illustrated on the next image.
+
+@image html context_tree.png
+
+@section bp-tmpctx Every function should use its own context
+
+It is a good practice to create a temporary talloc context at the function
+beginning and free the context just before the return statement. All the data
+must be allocated on this context or on its children. This ensures that no
+memory leaks are created as long as we do not forget to free the temporary
+context.
+
+This pattern applies to both situations - when a function does not return any
+dynamically allocated value and when it does. However, it needs a little
+extension for the latter case.
+
+@subsection bp-tmpctx-1 Functions that do not return any dynamically allocated
+value
+
+If the function does not return any value created on the heap, we will just obey
+the aforementioned pattern.
+
+@code
+int bar()
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ /* allocate data on tmp_ctx or on its descendants */
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+@endcode
+
+@subsection bp-tmpctx-2 Functions returning dynamically allocated values
+
+If our function returns any dynamically allocated data, its first parameter
+should always be the destination talloc context. This context serves as a parent
+for the output values. But again, we will create the output values as the
+descendants of the temporary context. If everything goes well, we will change
+the parent of the output values from the temporary to the destination talloc
+context.
+
+This pattern ensures that if an error occurs (e.g. I/O error or insufficient
+amount of the memory), all allocated data is freed and no garbage appears on
+the destination context.
+
+@code
+int struct_foo_init(TALLOC_CTX *mem_ctx, struct foo **_foo)
+{
+ int ret;
+ struct foo *foo = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ foo = talloc_zero(tmp_ctx, struct foo);
+ /* ... */
+ *_foo = talloc_steal(mem_ctx, foo);
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+@endcode
+
+@section bp-null Allocate temporary contexts on NULL
+
+As it can be seen on the previous listing, instead of allocating the temporary
+context directly on <code>mem_ctx</code>, we created a new top level context
+using <code>NULL</code> as the parameter for <code>talloc_new()</code> function.
+Take a look at the following example:
+
+@code
+char *create_user_filter(TALLOC_CTX *mem_ctx,
+ uid_t uid, const char *username)
+{
+ char *filter = NULL;
+ char *sanitized_username = NULL;
+ /* tmp_ctx is a child of mem_ctx */
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ sanitized_username = sanitize_string(tmp_ctx, username);
+ if (sanitized_username == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ filter = talloc_aprintf(tmp_ctx,"(|(uid=%llu)(uname=%s))",
+ uid, sanitized_username);
+ if (filter == NULL) {
+ return NULL; /* tmp_ctx is not freed */ (*@\label{lst:tmp-ctx-3:leak}@*)
+ }
+
+ /* filter becomes a child of mem_ctx */
+ filter = talloc_steal(mem_ctx, filter);
+ talloc_free(tmp_ctx);
+ return filter;
+}
+@endcode
+
+We forgot to free <code>tmp_ctx</code> before the <code>return</code> statement
+in the <code>filter == NULL</code> condition. However, it is created as a child
+of <code>mem_ctx</code> context and as such it will be freed as soon as the
+<code>mem_ctx</code> is freed. Therefore, no detectable memory leak is created.
+
+On the other hand, we do not have any way to access the allocated data
+and for all we know <code>mem_ctx</code> may exist for the lifetime of our
+application. For these reasons this should be considered as a memory leak. How
+can we detect if it is unreferenced but still attached to its parent context?
+The only way is to notice the mistake in the source code.
+
+But if we create the temporary context as a top level context, it will not be
+freed and memory diagnostic tools
+(e.g. <a href="http://valgrind.org">valgrind</a>) are able to do their job.
+
+@section bp-pool Temporary contexts and the talloc pool
+
+If we want to take the advantage of the talloc pool but also keep to the
+pattern introduced in the previous section, we are unable to do it directly. The
+best thing to do is to create a conditional build where we can decide how do we
+want to create the temporary context. For example, we can create the following
+macros:
+
+@code
+#ifdef USE_POOL_CONTEXT
+ #define CREATE_POOL_CTX(ctx, size) talloc_pool(ctx, size)
+ #define CREATE_TMP_CTX(ctx) talloc_new(ctx)
+#else
+ #define CREATE_POOL_CTX(ctx, size) talloc_new(ctx)
+ #define CREATE_TMP_CTX(ctx) talloc_new(NULL)
+#endif
+@endcode
+
+Now if our application is under development, we will build it with macro
+<code>USE_POOL_CONTEXT</code> undefined. This way, we can use memory diagnostic
+utilities to detect memory leaks.
+
+The release version will be compiled with the macro defined. This will enable
+pool contexts and therefore reduce the <code>malloc()</code> calls, which will
+end up in a little bit faster processing.
+
+@code
+int struct_foo_init(TALLOC_CTX *mem_ctx, struct foo **_foo)
+{
+ int ret;
+ struct foo *foo = NULL;
+ TALLOC_CTX *tmp_ctx = CREATE_TMP_CTX(mem_ctx);
+ /* ... */
+}
+
+errno_t handle_request(TALLOC_CTX mem_ctx)
+{
+ int ret;
+ struct foo *foo = NULL;
+ TALLOC_CTX *pool_ctx = CREATE_POOL_CTX(NULL, 1024);
+ ret = struct_foo_init(mem_ctx, &foo);
+ /* ... */
+}
+@endcode
+
+*/
diff --git a/lib/talloc/doc/tutorial_context.dox b/lib/talloc/doc/tutorial_context.dox
new file mode 100644
index 0000000..b8bfe26
--- /dev/null
+++ b/lib/talloc/doc/tutorial_context.dox
@@ -0,0 +1,198 @@
+/**
+@page libtalloc_context Chapter 1: Talloc context
+@section context Talloc context
+
+The talloc context is the most important part of this library and is
+responsible for every single feature of this memory allocator. It is a logical
+unit which represents a memory space managed by talloc.
+
+From the programmer's point of view, the talloc context is completely
+equivalent to a pointer that would be returned by the memory routines from the
+C standard library. This means that every context that is returned from the
+talloc library can be used directly in functions that do not use talloc
+internally. For example we can do the following:
+
+@code
+char *str1 = strdup("I am NOT a talloc context");
+char *str2 = talloc_strdup(NULL, "I AM a talloc context");
+
+printf("%d\n", strcmp(str1, str2) == 0);
+
+free(str1);
+talloc_free(str2); /* we can not use free() on str2 */
+@endcode
+
+This is possible because the context is internally handled as a special
+fixed-length structure called talloc chunk. Each chunk stores context metadata
+followed by the memory space requested by the programmer. When a talloc
+function returns a context (pointer), it will in fact return a pointer to the user
+space portion of the talloc chunk. If we to manipulate this context using
+talloc functions, the talloc library transforms the user-space pointer back to
+the starting address of the chunk. This is also the reason why we were unable
+to use <code>free(str2)</code> in the previous example - because
+<code>str2</code> does not point at the beginning of the allocated block of
+memory. This is illustrated on the next image:
+
+@image html context.png
+
+The type TALLOC_CTX is defined in talloc.h to identify a talloc context in
+function parameters. However, this type is just an alias for <code>void</code>
+and exists only for semantical reasons - thus we can differentiate between
+<code>void *</code> (arbitrary data) and <code>TALLOC_CTX *</code> (talloc
+context).
+
+@subsection metadata Context meta data
+
+Every talloc context carries several pieces of internal information along with
+the allocated memory:
+
+ - name - which is used in reports of context hierarchy and to simulate
+ a dynamic type system,
+ - size of the requested memory in bytes - this can be used to determine
+ the number of elements in arrays,
+ - attached destructor - which is executed just before the memory block is
+ about to be freed,
+ - references to the context
+ - children and parent contexts - create the hierarchical view on the
+ memory.
+
+@section context-hierarchy Hierarchy of talloc context
+
+Every talloc context contains information about its parent and children. Talloc
+uses this information to create a hierarchical model of memory or to be more
+precise, it creates an n-ary tree where each node represents a single talloc
+context. The root node of the tree is referred to as a top level context - a
+context without any parent.
+
+This approach has several advantages:
+
+ - as a consequence of freeing a talloc context, all of its children
+ will be properly deallocated as well,
+ - the parent of a context can be changed at any time, which
+ results in moving the whole subtree under another node,
+ - it creates a more natural way of managing data structures.
+
+@subsection Example
+
+We have a structure that stores basic information about a user - his/her name,
+identification number and groups he/she is a member of:
+
+@code
+struct user {
+ uid_t uid;
+ char *username;
+ size_t num_groups;
+ char **groups;
+};
+@endcode
+
+We will allocate this structure using talloc. The result will be the following
+context tree:
+
+@image html context_tree.png
+
+@code
+/* create new top level context */
+struct user *user = talloc(NULL, struct user);
+
+user->uid = 1000;
+user->num_groups = N;
+
+/* make user the parent of following contexts */
+user->username = talloc_strdup(user, "Test user");
+user->groups = talloc_array(user, char*, user->num_groups);
+
+for (i = 0; i < user->num_groups; i++) {
+ /* make user->groups the parent of following context */
+ user->groups[i] = talloc_asprintf(user->groups,
+ "Test group %d", i);
+}
+@endcode
+
+This way, we have gained a lot of additional capabilities, one of which is
+very simple deallocation of the structure and all of its elements.
+
+With the C standard library we need first to iterate over the array of groups
+and free every element separately. Then we must deallocate the array that stores
+them. Next we deallocate the username and as the last step free the structure
+itself. But with talloc, the only operation we need to execute is freeing the
+structure context. Its descendants will be freed automatically.
+
+@code
+talloc_free(user);
+@endcode
+
+@section keep-hierarchy Always keep the hieararchy steady!
+
+The talloc is a hierarchy memory allocator. The hierarchy nature is what makes
+the programming more error proof. It makes the memory easier to manage and to
+free. Therefore, the first thing we should have on our mind is: <strong>always
+project our data structures into the talloc context hierarchy</strong>.
+
+That means if we have a structure, we should always use it as a parent context
+for its elements. This way we will not encounter any troubles when freeing this
+structure or when changing its parent. The same rule applies for arrays.
+
+@section creating-context Creating a talloc context
+
+Here are the most important functions that create a new talloc context.
+
+@subsection type-safe Type-safe functions
+
+It allocates the size that is necessary for the given type and returns a new,
+properly-casted pointer. This is the preferred way to create a new context as
+we can rely on the compiler to detect type mismatches.
+
+The name of the context is automatically set to the name of the data type which
+is used to simulate a dynamic type system.
+
+@code
+struct user *user = talloc(ctx, struct user);
+
+/* initialize to default values */
+user->uid = 0;
+user->name = NULL;
+user->num_groups = 0;
+user->groups = NULL;
+
+/* or we can achieve the same result with */
+struct user *user_zero = talloc_zero(ctx, struct user);
+@endcode
+
+@subsection zero-length Zero-length contexts
+
+The zero-length context is basically a context without any special semantical
+meaning. We can use it the same way as any other context. The only difference
+is that it consists only of the meta data about the context. Therefore, it is
+strictly of type <code>TALLOC_CTX*</code>. It is often used in cases where we
+want to aggregate several data structures under one parent (zero-length)
+context, such as a temporary context to contain memory needed within a single
+function that is not interesting to the caller. Allocating on a zero-length
+temporary context will make clean-up of the function simpler.
+
+@code
+TALLOC_CTX *tmp_ctx = NULL;
+struct foo *foo = NULL;
+struct bar *bar = NULL;
+
+/* new zero-length top level context */
+tmp_ctx = talloc_new(NULL);
+if (tmp_ctx == NULL) {
+ return ENOMEM;
+}
+
+foo = talloc(tmp_ctx, struct foo);
+bar = talloc(tmp_ctx, struct bar);
+
+/* free everything at once */
+talloc_free(tmp_ctx);
+@endcode
+
+@subsection context-see-also See also
+
+- talloc_size()
+- talloc_named()
+- @ref talloc_array
+- @ref talloc_string
+
+*/
diff --git a/lib/talloc/doc/tutorial_debugging.dox b/lib/talloc/doc/tutorial_debugging.dox
new file mode 100644
index 0000000..aadbb0d
--- /dev/null
+++ b/lib/talloc/doc/tutorial_debugging.dox
@@ -0,0 +1,116 @@
+/**
+@page libtalloc_debugging Chapter 6: Debugging
+
+Although talloc makes memory management significantly easier than the C standard
+library, developers are still only humans and can make mistakes. Therefore, it
+can be handy to know some tools for the inspection of talloc memory usage.
+
+@section log-abort Talloc log and abort
+
+We have already encountered the abort function in section @ref dts.
+In that case it was used when a type mismatch was detected. However, talloc
+calls this abort function in several more situations:
+
+- when the provided pointer is not a valid talloc context,
+- when the meta data is invalid - probably due to memory corruption,
+- and when an access after free is detected.
+
+The third one is probably the most interesting. It can help us with detecting
+an attempt to double-free a context or any other manipulation with it via
+talloc functions (using it as a parent, stealing it, etc.).
+
+Before the context is freed talloc sets a flag in the meta data. This is then
+used to detect the access after free. It basically works on the assumption that
+the memory stays unchanged (at least for a while) even when it is properly
+deallocated. This will work even if the memory is filled with the value
+specified in <code>TALLOC_FREE_FILL</code> environment variable, because it
+fills only the data part and leaves the meta data intact.
+
+Apart from the abort function, talloc uses a log function to provide additional
+information to the aforementioned violations. To enable logging we shall set the
+log function with one of:
+
+- talloc_set_log_fn()
+- talloc_set_log_stderr()
+
+The following code is a sample output of accessing a context after it has been
+freed:
+
+@code
+talloc_set_log_stderr();
+TALLOC_CTX *ctx = talloc_new(NULL);
+
+talloc_free(ctx);
+talloc_free(ctx);
+
+results in:
+talloc: access after free error - first free may be at ../src/main.c:55
+Bad talloc magic value - access after free
+@endcode
+
+Another example is an invalid context:
+
+@code
+talloc_set_log_stderr();
+TALLOC_CTX *ctx = talloc_new(NULL);
+char *str = strdup("not a talloc context");
+talloc_steal(ctx, str);
+
+results in:
+Bad talloc magic value - unknown value
+@endcode
+
+@section reports Memory usage reports
+
+Talloc can print reports of memory usage of a specified talloc context to a
+file (to <code>stdout</code> or <code>stderr</code>). The report can be
+simple or full. The simple report provides information only about the context
+itself and its direct descendants. The full report goes recursively through the
+entire context tree. See:
+
+- talloc_report()
+- talloc_report_full()
+
+We will use the following code to retrieve the sample report:
+
+@code
+struct foo {
+ char *str;
+};
+
+TALLOC_CTX *ctx = talloc_new(NULL);
+char *str = talloc_strdup(ctx, "my string");
+struct foo *foo = talloc_zero(ctx, struct foo);
+foo->str = talloc_strdup(foo, "I am Foo");
+char *str2 = talloc_strdup(foo, "Foo is my parent");
+
+/* print full report */
+talloc_report_full(ctx, stdout);
+@endcode
+
+It will print a full report of <code>ctx</code> to the standard output.
+The message should be similar to:
+
+@code
+full talloc report on 'talloc_new: ../src/main.c:82' (total 46 bytes in 5 blocks)
+ struct foo contains 34 bytes in 3 blocks (ref 0) 0x1495130
+ Foo is my parent contains 17 bytes in 1 blocks (ref 0) 0x1495200
+ I am Foo contains 9 bytes in 1 blocks (ref 0) 0x1495190
+ my string contains 10 bytes in 1 blocks (ref 0) 0x14950c0
+@endcode
+
+We can notice in this report that something is wrong with the context containing
+<code>struct foo</code>. We know that the structure has only one string element.
+However, we can see in the report that it has two children. This indicates that
+we have either violated the memory hierarchy or forgotten to free it as
+temporary data. Looking into the code, we can see that <code>"Foo is my parent"
+</code> should be attached to <code>ctx</code>.
+
+See also:
+
+- talloc_enable_null_tracking()
+- talloc_disable_null_tracking()
+- talloc_enable_leak_report()
+- talloc_enable_leak_report_full()
+
+*/
diff --git a/lib/talloc/doc/tutorial_destructors.dox b/lib/talloc/doc/tutorial_destructors.dox
new file mode 100644
index 0000000..ed06387
--- /dev/null
+++ b/lib/talloc/doc/tutorial_destructors.dox
@@ -0,0 +1,82 @@
+/**
+@page libtalloc_destructors Chapter 4: Using destructors
+
+@section destructors Using destructors
+
+Destructors are well known methods in the world of object oriented programming.
+A destructor is a method of an object that is automatically run when the object
+is destroyed. It is usually used to return resources taken by the object back to
+the system (e.g. closing file descriptors, terminating connection to a database,
+deallocating memory).
+
+With talloc we can take the advantage of destructors even in C. We can easily
+attach our own destructor to a talloc context. When the context is freed, the
+destructor will run automatically.
+
+To attach/detach a destructor to a talloc context use: talloc_set_destructor().
+
+@section destructors-example Example
+
+Imagine that we have a dynamically created linked list. Before we deallocate an
+element of the list, we need to make sure that we have successfully removed it
+from the list. Normally, this would be done by two commands in the exact order:
+remove it from the list and then free the element. With talloc, we can do this
+at once by setting a destructor on the element which will remove it from the
+list and talloc_free() will do the rest.
+
+The destructor would be:
+
+@code
+int list_remove(void *ctx)
+{
+ struct list_el *el = NULL;
+ el = talloc_get_type_abort(ctx, struct list_el);
+ /* remove element from the list */
+}
+@endcode
+
+GCC version 3 and newer can check for the types during the compilation. So if
+it is our major compiler, we can use a more advanced destructor:
+
+@code
+int list_remove(struct list_el *el)
+{
+ /* remove element from the list */
+}
+@endcode
+
+Now we will assign the destructor to the list element. We can do this directly
+in the function that inserts it.
+
+@code
+struct list_el* list_insert(TALLOC_CTX *mem_ctx,
+ struct list_el *where,
+ void *ptr)
+{
+ struct list_el *el = talloc(mem_ctx, struct list_el);
+ el->data = ptr;
+ /* insert into list */
+
+ talloc_set_destructor(el, list_remove);
+ return el;
+}
+@endcode
+
+Because talloc is a hierarchical memory allocator, we can go a step further and
+free the data with the element as well:
+
+@code
+struct list_el* list_insert_free(TALLOC_CTX *mem_ctx,
+ struct list_el *where,
+ void *ptr)
+{
+ struct list_el *el = NULL;
+ el = list_insert(mem_ctx, where, ptr);
+
+ talloc_steal(el, ptr);
+
+ return el;
+}
+@endcode
+
+*/
diff --git a/lib/talloc/doc/tutorial_dts.dox b/lib/talloc/doc/tutorial_dts.dox
new file mode 100644
index 0000000..75b5172
--- /dev/null
+++ b/lib/talloc/doc/tutorial_dts.dox
@@ -0,0 +1,109 @@
+/**
+@page libtalloc_dts Chapter 3: Dynamic type system
+
+@section dts Dynamic type system
+
+Generic programming in the C language is very difficult. There is no inheritance
+nor templates known from object oriented languages. There is no dynamic type
+system. Therefore, generic programming in this language is usually done by
+type-casting a variable to <code>void*</code> and transferring it through
+a generic function to a specialized callback as illustrated on the next listing.
+
+@code
+void generic_function(callback_fn cb, void *pvt)
+{
+ /* do some stuff and call the callback */
+ cb(pvt);
+}
+
+void specific_callback(void *pvt)
+{
+ struct specific_struct *data;
+ data = (struct specific_struct*)pvt;
+ /* ... */
+}
+
+void specific_function()
+{
+ struct specific_struct data;
+ generic_function(callback, &data);
+}
+@endcode
+
+Unfortunately, the type information is lost as a result of this type cast. The
+compiler cannot check the type during the compilation nor are we able to do it
+at runtime. Providing an invalid data type to the callback will result in
+unexpected behaviour (not necessarily a crash) of the application. This mistake
+is usually hard to detect because it is not the first thing which comes the
+mind.
+
+As we already know, every talloc context contains a name. This name is available
+at any time and it can be used to determine the type of a context even if we
+lose the type of a variable.
+
+Although the name of the context can be set to any arbitrary string, the best
+way of using it to simulate the dynamic type system is to set it directly to the
+type of the variable.
+
+It is recommended to use one of talloc() and talloc_array() (or its
+variants) to create the context as they set its name to the name of the
+given type automatically.
+
+If we have a context with such as a name, we can use two similar functions that
+do both the type check and the type cast for us:
+
+- talloc_get_type()
+- talloc_get_type_abort()
+
+@section dts-examples Examples
+
+The following example will show how generic programming with talloc is handled -
+if we provide invalid data to the callback, the program will be aborted. This
+is a sufficient reaction for such an error in most applications.
+
+@code
+void foo_callback(void *pvt)
+{
+ struct foo *data = talloc_get_type_abort(pvt, struct foo);
+ /* ... */
+}
+
+int do_foo()
+{
+ struct foo *data = talloc_zero(NULL, struct foo);
+ /* ... */
+ return generic_function(foo_callback, data);
+}
+@endcode
+
+But what if we are creating a service application that should be running for the
+uptime of a server, we may want to abort the application during the development
+process (to make sure the error is not overlooked) and try to recover from the
+error in the customer release. This can be achieved by creating a custom abort
+function with a conditional build.
+
+@code
+void my_abort(const char *reason)
+{
+ fprintf(stderr, "talloc abort: %s\n", reason);
+#ifdef ABORT_ON_TYPE_MISMATCH
+ abort();
+#endif
+}
+@endcode
+
+The usage of talloc_get_type_abort() would be then:
+
+@code
+talloc_set_abort_fn(my_abort);
+
+TALLOC_CTX *ctx = talloc_new(NULL);
+char *str = talloc_get_type_abort(ctx, char);
+if (str == NULL) {
+ /* recovery code */
+}
+/* talloc abort: ../src/main.c:25: Type mismatch:
+ name[talloc_new: ../src/main.c:24] expected[char] */
+@endcode
+
+*/
diff --git a/lib/talloc/doc/tutorial_introduction.dox b/lib/talloc/doc/tutorial_introduction.dox
new file mode 100644
index 0000000..418c38b
--- /dev/null
+++ b/lib/talloc/doc/tutorial_introduction.dox
@@ -0,0 +1,45 @@
+/**
+@page libtalloc_tutorial The Tutorial
+@section introduction Introduction
+
+Talloc is a hierarchical, reference counted memory pool system with destructors.
+It is built atop the C standard library and it defines a set of utility
+functions that altogether simplifies allocation and deallocation of data,
+especially for complex structures that contain many dynamically allocated
+elements such as strings and arrays.
+
+The main goals of this library are: removing the needs for creating a cleanup
+function for every complex structure, providing a logical organization of
+allocated memory blocks and reducing the likelihood of creating memory leaks in
+long-running applications. All of this is achieved by allocating memory in a
+hierarchical structure of talloc contexts such that deallocating one context
+recursively frees all of its descendants as well.
+
+@section main-features Main features
+- An open source project
+- A hierarchical memory model
+- Natural projection of data structures into the memory space
+- Simplifies memory management of large data structures
+- Automatic execution of a destructor before the memory is freed
+- Simulates a dynamic type system
+- Implements a transparent memory pool
+
+@section toc Table of contents:
+
+@subpage libtalloc_context
+
+@subpage libtalloc_stealing
+
+@subpage libtalloc_dts
+
+@subpage libtalloc_destructors
+
+@subpage libtalloc_pools
+
+@subpage libtalloc_debugging
+
+@subpage libtalloc_bestpractices
+
+@subpage libtalloc_threads
+
+*/
diff --git a/lib/talloc/doc/tutorial_pools.dox b/lib/talloc/doc/tutorial_pools.dox
new file mode 100644
index 0000000..a0d1e1a
--- /dev/null
+++ b/lib/talloc/doc/tutorial_pools.dox
@@ -0,0 +1,93 @@
+/**
+@page libtalloc_pools Chapter 5: Memory pools
+
+@section pools Memory pools
+
+Allocation of a new memory is an expensive operation and large programs can
+contain thousands of calls of malloc() for a single computation, where every
+call allocates only a very small amount of the memory. This can result in an
+undesirable slowdown of the application. We can avoid this slowdown by
+decreasing the number of malloc() calls by using a memory pool.
+
+A memory pool is a preallocated memory space with a fixed size. If we need to
+allocate new data we will take the desired amount of the memory from the pool
+instead of requesting a new memory from the system. This is done by creating a
+pointer that points inside the preallocated memory. Such a pool must not be
+reallocated as it would change its location - pointers that were pointing
+inside the pool would become invalid. Therefore, a memory pool requires a very
+good estimate of the required memory space.
+
+The talloc library contains its own implementation of a memory pool. It is
+highly transparent for the programmer. The only thing that needs to be done is
+an initialization of a new pool context using talloc_pool() -
+which can be used in the same way as any other context.
+
+Refactoring of existing code (that uses talloc) to take the advantage of a
+memory pool is quite simple due to the following properties of the pool context:
+
+- if we are allocating data on a pool context, it takes the desired
+ amount of memory from the pool,
+- if the context is a descendant of the pool context, it takes the space
+ from the pool as well,
+- if the pool does not have sufficient portion of memory left, it will
+ create a new non-pool context, leaving the pool intact
+
+@code
+/* allocate 1KiB in a pool */
+TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024);
+
+/* Take 512B from the pool, 512B is left there */
+void *ptr = talloc_size(pool_ctx, 512);
+
+/* 1024B > 512B, this will create new talloc chunk outside
+ the pool */
+void *ptr2 = talloc_size(ptr, 1024);
+
+/* The pool still contains 512 free bytes
+ * this will take 200B from them. */
+void *ptr3 = talloc_size(ptr, 200);
+
+/* This will destroy context 'ptr3' but the memory
+ * is not freed, the available space in the pool
+ * will increase to 512B. */
+talloc_free(ptr3);
+
+/* This will free memory taken by 'pool_ctx'
+ * and 'ptr2' as well. */
+talloc_free(pool_ctx);
+@endcode
+
+The above given is very convenient, but there is one big issue to be kept in
+mind. If the parent of a talloc pool child is changed to a parent that is
+outside of this pool, the whole pool memory will not be freed until the child is
+freed. For this reason we must be very careful when stealing a descendant of a
+pool context.
+
+@code
+TALLOC_CTX *mem_ctx = talloc_new(NULL);
+TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024);
+struct foo *foo = talloc(pool_ctx, struct foo);
+
+/* mem_ctx is not in the pool */
+talloc_steal(mem_ctx, foo);
+
+/* pool_ctx is marked as freed but the memory is not
+ deallocated, accessing the pool_ctx again will cause
+ an error */
+talloc_free(pool_ctx);
+
+/* This deallocates the pool_ctx. */
+talloc_free(mem_ctx);
+@endcode
+
+It may often be better to copy the memory we want instead of stealing it to
+avoid this problem. If we do not need to retain the context name (to keep the
+type information), we can use talloc_memdup() to do this.
+
+Copying the memory out of the pool may, however, discard all the performance
+boost given by the pool, depending on the size of the copied memory. Therefore,
+the code should be well profiled before taking this path. In general, the
+golden rule is: if we need to steal from the pool context, we should not
+use a pool context.
+
+*/
diff --git a/lib/talloc/doc/tutorial_stealing.dox b/lib/talloc/doc/tutorial_stealing.dox
new file mode 100644
index 0000000..67eae1d
--- /dev/null
+++ b/lib/talloc/doc/tutorial_stealing.dox
@@ -0,0 +1,55 @@
+/**
+@page libtalloc_stealing Chapter 2: Stealing a context
+
+@section stealing Stealing a context
+
+Talloc has the ability to change the parent of a talloc context to another
+one. This operation is commonly referred to as stealing and it is one of
+the most important actions performed with talloc contexts.
+
+Stealing a context is necessary if we want the pointer to outlive the context it
+is created on. This has many possible use cases, for instance stealing a result
+of a database search to an in-memory cache context, changing the parent of a
+field of a generic structure to a more specific one or vice-versa. The most
+common scenario, at least in Samba, is to steal output data from a function-specific
+context to the output context given as an argument of that function.
+
+@code
+struct foo {
+ char *a1;
+ char *a2;
+ char *a3;
+};
+
+struct bar {
+ char *wurst;
+ struct foo *foo;
+};
+
+struct foo *foo = talloc_zero(ctx, struct foo);
+foo->a1 = talloc_strdup(foo, "a1");
+foo->a2 = talloc_strdup(foo, "a2");
+foo->a3 = talloc_strdup(foo, "a3");
+
+struct bar *bar = talloc_zero(NULL, struct bar);
+/* change parent of foo from ctx to bar */
+bar->foo = talloc_steal(bar, foo);
+
+/* or do the same but assign foo = NULL */
+bar->foo = talloc_move(bar, &foo);
+@endcode
+
+The talloc_move() function is similar to the talloc_steal() function but
+additionally sets the source pointer to NULL.
+
+In general, the source pointer itself is not changed (it only replaces the
+parent in the meta data). But the common usage is that the result is
+assigned to another variable, thus further accessing the pointer from the
+original variable should be avoided unless it is necessary. In this case
+talloc_move() is the preferred way of stealing a context. Additionally sets the
+source pointer to NULL, thus.protects the pointer from being accidentally freed
+and accessed using the old variable after its parent has been changed.
+
+@image html stealing.png
+
+*/
diff --git a/lib/talloc/doc/tutorial_threads.dox b/lib/talloc/doc/tutorial_threads.dox
new file mode 100644
index 0000000..111bbf5
--- /dev/null
+++ b/lib/talloc/doc/tutorial_threads.dox
@@ -0,0 +1,203 @@
+/**
+@page libtalloc_threads Chapter 8: Using threads with talloc
+
+@section Talloc and thread safety
+
+The talloc library is not internally thread-safe, in that accesses
+to variables on a talloc context are not controlled by mutexes or
+other thread-safe primitives.
+
+However, so long as talloc_disable_null_tracking() is called from
+the main thread to disable global variable access within talloc,
+then each thread can safely use its own top level talloc context
+allocated off the NULL context.
+
+For example:
+
+@code
+static void *thread_fn(void *arg)
+{
+ const char *ctx_name = (const char *)arg;
+ /*
+ * Create a new top level talloc hierarchy in
+ * this thread.
+ */
+ void *top_ctx = talloc_named_const(NULL, 0, "top");
+ if (top_ctx == NULL) {
+ return NULL;
+ }
+ sub_ctx = talloc_named_const(top_ctx, 100, ctx_name);
+ if (sub_ctx == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Do more processing/talloc calls on top_ctx
+ * and its children.
+ */
+ ......
+
+ talloc_free(top_ctx);
+ return value;
+}
+@endcode
+
+is a perfectly safe use of talloc within a thread.
+
+The problem comes when one thread wishes to move some
+memory allocated on its local top level talloc context
+to another thread. Care must be taken to add data access
+exclusion to prevent memory corruption. One method would
+be to lock a mutex before any talloc call on each thread,
+but this would push the burden of total talloc thread-safety
+on the poor user of the library.
+
+A much easier way to transfer talloced memory between
+threads is by the use of an intermediate, mutex locked,
+intermediate variable.
+
+An example of this is below - taken from test code inside
+the talloc testsuite.
+
+The main thread creates 1000 sub-threads, and then accepts
+the transfer of some thread-talloc'ed memory onto its top
+level context from each thread in turn.
+
+A pthread mutex and condition variable are used to
+synchronize the transfer via the intermediate_ptr
+variable.
+
+@code
+/* Required sync variables. */
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
+
+/* Intermediate talloc pointer for transfer. */
+static void *intermediate_ptr;
+
+/* Subthread. */
+static void *thread_fn(void *arg)
+{
+ int ret;
+ const char *ctx_name = (const char *)arg;
+ void *sub_ctx = NULL;
+ /*
+ * Do stuff that creates a new talloc hierarchy in
+ * this thread.
+ */
+ void *top_ctx = talloc_named_const(NULL, 0, "top");
+ if (top_ctx == NULL) {
+ return NULL;
+ }
+ sub_ctx = talloc_named_const(top_ctx, 100, ctx_name);
+ if (sub_ctx == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Now transfer a pointer from our hierarchy
+ * onto the intermediate ptr.
+ */
+ ret = pthread_mutex_lock(&mtx);
+ if (ret != 0) {
+ talloc_free(top_ctx);
+ return NULL;
+ }
+
+ /* Wait for intermediate_ptr to be free. */
+ while (intermediate_ptr != NULL) {
+ ret = pthread_cond_wait(&condvar, &mtx);
+ if (ret != 0) {
+ talloc_free(top_ctx);
+ return NULL;
+ }
+ }
+
+ /* and move our memory onto it from our toplevel hierarchy. */
+ intermediate_ptr = talloc_move(NULL, &sub_ctx);
+
+ /* Tell the main thread it's ready for pickup. */
+ pthread_cond_broadcast(&condvar);
+ pthread_mutex_unlock(&mtx);
+
+ talloc_free(top_ctx);
+ return NULL;
+}
+
+/* Main thread. */
+
+#define NUM_THREADS 1000
+
+static bool test_pthread_talloc_passing(void)
+{
+ int i;
+ int ret;
+ char str_array[NUM_THREADS][20];
+ pthread_t thread_id;
+ void *mem_ctx;
+
+ /*
+ * Important ! Null tracking breaks threaded talloc.
+ * It *must* be turned off.
+ */
+ talloc_disable_null_tracking();
+
+ /* Main thread toplevel context. */
+ mem_ctx = talloc_named_const(NULL, 0, "toplevel");
+ if (mem_ctx == NULL) {
+ return false;
+ }
+
+ /*
+ * Spin off NUM_THREADS threads.
+ * They will use their own toplevel contexts.
+ */
+ for (i = 0; i < NUM_THREADS; i++) {
+ (void)snprintf(str_array[i],
+ 20,
+ "thread:%d",
+ i);
+ if (str_array[i] == NULL) {
+ return false;
+ }
+ ret = pthread_create(&thread_id,
+ NULL,
+ thread_fn,
+ str_array[i]);
+ if (ret != 0) {
+ return false;
+ }
+ }
+
+ /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */
+ for (i = 0; i < NUM_THREADS; i++) {
+ ret = pthread_mutex_lock(&mtx);
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ /* Wait for intermediate_ptr to have our data. */
+ while (intermediate_ptr == NULL) {
+ ret = pthread_cond_wait(&condvar, &mtx);
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+ }
+
+ /* and move it onto our toplevel hierarchy. */
+ (void)talloc_move(mem_ctx, &intermediate_ptr);
+
+ /* Tell the sub-threads we're ready for another. */
+ pthread_cond_broadcast(&condvar);
+ pthread_mutex_unlock(&mtx);
+ }
+
+ /* Dump the hierarchy. */
+ talloc_report(mem_ctx, stdout);
+ talloc_free(mem_ctx);
+ return true;
+}
+@endcode
+*/
diff --git a/lib/talloc/doxy.config b/lib/talloc/doxy.config
new file mode 100644
index 0000000..0e27d61
--- /dev/null
+++ b/lib/talloc/doxy.config
@@ -0,0 +1,1807 @@
+# Doxyfile 1.8.0
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = talloc
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 2.0
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = . \
+ doc
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS = *.cpp \
+ *.cc \
+ *.c \
+ *.h \
+ *.hh \
+ *.hpp \
+ *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */.git/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = doc
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# style sheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN \
+ PRINTF_ATTRIBUTE(x,y)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/lib/talloc/man/talloc.3.xml b/lib/talloc/man/talloc.3.xml
new file mode 100644
index 0000000..c51061f
--- /dev/null
+++ b/lib/talloc/man/talloc.3.xml
@@ -0,0 +1,814 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry>
+ <refentryinfo><date>2015-04-10</date></refentryinfo>
+ <refmeta>
+ <refentrytitle>talloc</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>talloc</refname>
+<refpurpose>hierarchical reference counted memory pool system with destructors</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+<synopsis>#include &lt;talloc.h&gt;</synopsis>
+ </refsynopsisdiv>
+ <refsect1><title>DESCRIPTION</title>
+ <para>
+ If you are used to talloc from Samba3 then please read this
+ carefully, as talloc has changed a lot.
+ </para>
+ <para>
+ The new talloc is a hierarchical, reference counted memory pool
+ system with destructors. Quite a mouthful really, but not too bad
+ once you get used to it.
+ </para>
+ <para>
+ Perhaps the biggest change from Samba3 is that there is no
+ distinction between a "talloc context" and a "talloc pointer". Any
+ pointer returned from talloc() is itself a valid talloc context.
+ This means you can do this:
+ </para>
+ <programlisting>
+ struct foo *X = talloc(mem_ctx, struct foo);
+ X->name = talloc_strdup(X, "foo");
+ </programlisting>
+ <para>
+ and the pointer <literal role="code">X-&gt;name</literal>
+ would be a "child" of the talloc context <literal
+ role="code">X</literal> which is itself a child of
+ <literal role="code">mem_ctx</literal>. So if you do
+ <literal role="code">talloc_free(mem_ctx)</literal> then
+ it is all destroyed, whereas if you do <literal
+ role="code">talloc_free(X)</literal> then just <literal
+ role="code">X</literal> and <literal
+ role="code">X-&gt;name</literal> are destroyed, and if
+ you do <literal
+ role="code">talloc_free(X-&gt;name)</literal> then just
+ the name element of <literal role="code">X</literal> is
+ destroyed.
+ </para>
+ <para>
+ If you think about this, then what this effectively gives you is an
+ n-ary tree, where you can free any part of the tree with
+ talloc_free().
+ </para>
+ <para>
+ If you find this confusing, then I suggest you run the <literal
+ role="code">testsuite</literal> program to watch talloc
+ in action. You may also like to add your own tests to <literal
+ role="code">testsuite.c</literal> to clarify how some
+ particular situation is handled.
+ </para>
+ </refsect1>
+ <refsect1><title>TALLOC API</title>
+ <para>
+ The following is a complete guide to the talloc API. Read it all at
+ least twice.
+ </para>
+ <refsect2><title>(type *)talloc(const void *ctx, type);</title>
+ <para>
+ The talloc() macro is the core of the talloc library. It takes a
+ memory <emphasis role="italic">ctx</emphasis> and a <emphasis
+ role="italic">type</emphasis>, and returns a pointer to a new
+ area of memory of the given <emphasis
+ role="italic">type</emphasis>.
+ </para>
+ <para>
+ The returned pointer is itself a talloc context, so you can use
+ it as the <emphasis role="italic">ctx</emphasis> argument to more
+ calls to talloc() if you wish.
+ </para>
+ <para>
+ The returned pointer is a "child" of the supplied context. This
+ means that if you talloc_free() the <emphasis
+ role="italic">ctx</emphasis> then the new child disappears as
+ well. Alternatively you can free just the child.
+ </para>
+ <para>
+ The <emphasis role="italic">ctx</emphasis> argument to talloc()
+ can be NULL, in which case a new top level context is created.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_size(const void *ctx, size_t size);</title>
+ <para>
+ The function talloc_size() should be used when you don't have a
+ convenient type to pass to talloc(). Unlike talloc(), it is not
+ type safe (as it returns a void *), so you are on your own for
+ type checking.
+ </para>
+ </refsect2>
+ <refsect2><title>(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);</title>
+ <para>
+ The talloc_ptrtype() macro should be used when you have a pointer and
+ want to allocate memory to point at with this pointer. When compiling
+ with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+ and talloc_get_name() will return the current location in the source file.
+ and not the type.
+ </para>
+ </refsect2>
+ <refsect2><title>int talloc_free(void *ptr);</title>
+ <para>
+ The talloc_free() function frees a piece of talloc memory, and
+ all its children. You can call talloc_free() on any pointer
+ returned by talloc().
+ </para>
+ <para>
+ The return value of talloc_free() indicates success or failure,
+ with 0 returned for success and -1 for failure. The only
+ possible failure condition is if <emphasis
+ role="italic">ptr</emphasis> had a destructor attached to it and
+ the destructor returned -1. See <link
+ linkend="talloc_set_destructor"><quote>talloc_set_destructor()</quote></link>
+ for details on destructors.
+ </para>
+ <para>
+ If this pointer has an additional parent when talloc_free() is
+ called then the memory is not actually released, but instead the
+ most recently established parent is destroyed. See <link
+ linkend="talloc_reference"><quote>talloc_reference()</quote></link>
+ for details on establishing additional parents.
+ </para>
+ <para>
+ For more control on which parent is removed, see <link
+ linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+ </para>
+ <para>
+ talloc_free() operates recursively on its children.
+ </para>
+ <para>
+ From the 2.0 version of talloc, as a special case,
+ talloc_free() is refused on pointers that have more than one
+ parent, as talloc would have no way of knowing which parent
+ should be removed. To free a pointer that has more than one
+ parent please use talloc_unlink().
+ </para>
+ <para>
+ To help you find problems in your code caused by this behaviour, if
+ you do try and free a pointer with more than one parent then the
+ talloc logging function will be called to give output like this:
+ </para>
+ <para>
+ <screen format="linespecific">
+ ERROR: talloc_free with references at some_dir/source/foo.c:123
+ reference at some_dir/source/other.c:325
+ reference at some_dir/source/third.c:121
+ </screen>
+ </para>
+ <para>
+ Please see the documentation for talloc_set_log_fn() and
+ talloc_set_log_stderr() for more information on talloc logging
+ functions.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_reference"><title>void *talloc_reference(const void *ctx, const void *ptr);</title>
+ <para>
+ The talloc_reference() function makes <emphasis
+ role="italic">ctx</emphasis> an additional parent of <emphasis
+ role="italic">ptr</emphasis>.
+ </para>
+ <para>
+ The return value of talloc_reference() is always the original
+ pointer <emphasis role="italic">ptr</emphasis>, unless talloc ran
+ out of memory in creating the reference in which case it will
+ return NULL (each additional reference consumes around 48 bytes
+ of memory on intel x86 platforms).
+ </para>
+ <para>
+ If <emphasis role="italic">ptr</emphasis> is NULL, then the
+ function is a no-op, and simply returns NULL.
+ </para>
+ <para>
+ After creating a reference you can free it in one of the
+ following ways:
+ </para>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ you can talloc_free() any parent of the original pointer.
+ That will reduce the number of parents of this pointer by 1,
+ and will cause this pointer to be freed if it runs out of
+ parents.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ you can talloc_free() the pointer itself if it has at maximum one
+ parent. This behaviour has been changed since the release of version
+ 2.0. Further information in the description of "talloc_free".
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ For more control on which parent to remove, see <link
+ linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_unlink"><title>int talloc_unlink(const void *ctx, void *ptr);</title>
+ <para>
+ The talloc_unlink() function removes a specific parent from
+ <emphasis role="italic">ptr</emphasis>. The <emphasis
+ role="italic">ctx</emphasis> passed must either be a context used
+ in talloc_reference() with this pointer, or must be a direct
+ parent of ptr.
+ </para>
+ <para>
+ Note that if the parent has already been removed using
+ talloc_free() then this function will fail and will return -1.
+ Likewise, if <emphasis role="italic">ptr</emphasis> is NULL, then
+ the function will make no modifications and return -1.
+ </para>
+ <para>
+ Usually you can just use talloc_free() instead of
+ talloc_unlink(), but sometimes it is useful to have the
+ additional control on which parent is removed.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_set_destructor"><title>void talloc_set_destructor(const void *ptr, int (*destructor)(void *));</title>
+ <para>
+ The function talloc_set_destructor() sets the <emphasis
+ role="italic">destructor</emphasis> for the pointer <emphasis
+ role="italic">ptr</emphasis>. A <emphasis
+ role="italic">destructor</emphasis> is a function that is called
+ when the memory used by a pointer is about to be released. The
+ destructor receives <emphasis role="italic">ptr</emphasis> as an
+ argument, and should return 0 for success and -1 for failure.
+ </para>
+ <para>
+ The <emphasis role="italic">destructor</emphasis> can do anything
+ it wants to, including freeing other pieces of memory. A common
+ use for destructors is to clean up operating system resources
+ (such as open file descriptors) contained in the structure the
+ destructor is placed on.
+ </para>
+ <para>
+ You can only place one destructor on a pointer. If you need more
+ than one destructor then you can create a zero-length child of
+ the pointer and place an additional destructor on that.
+ </para>
+ <para>
+ To remove a destructor call talloc_set_destructor() with NULL for
+ the destructor.
+ </para>
+ <para>
+ If your destructor attempts to talloc_free() the pointer that it
+ is the destructor for then talloc_free() will return -1 and the
+ free will be ignored. This would be a pointless operation
+ anyway, as the destructor is only called when the memory is just
+ about to go away.
+ </para>
+ </refsect2>
+ <refsect2><title>int talloc_increase_ref_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_increase_ref_count(<emphasis
+ role="italic">ptr</emphasis>) function is exactly equivalent to:
+ </para>
+ <programlisting>talloc_reference(NULL, ptr);</programlisting>
+ <para>
+ You can use either syntax, depending on which you think is
+ clearer in your code.
+ </para>
+ <para>
+ It returns 0 on success and -1 on failure.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_reference_count(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ Return the number of references to the pointer.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_set_name"><title>void talloc_set_name(const void *ptr, const char *fmt, ...);</title>
+ <para>
+ Each talloc pointer has a "name". The name is used principally
+ for debugging purposes, although it is also possible to set and
+ get the name on a pointer in as a way of "marking" pointers in
+ your code.
+ </para>
+ <para>
+ The main use for names on pointer is for "talloc reports". See
+ <link
+ linkend="talloc_report"><quote>talloc_report_depth_cb()</quote></link>,
+ <link
+ linkend="talloc_report"><quote>talloc_report_depth_file()</quote></link>,
+ <link
+ linkend="talloc_report"><quote>talloc_report()</quote></link>
+ <link
+ linkend="talloc_report"><quote>talloc_report()</quote></link>
+ and <link
+ linkend="talloc_report_full"><quote>talloc_report_full()</quote></link>
+ for details. Also see <link
+ linkend="talloc_enable_leak_report"><quote>talloc_enable_leak_report()</quote></link>
+ and <link
+ linkend="talloc_enable_leak_report_full"><quote>talloc_enable_leak_report_full()</quote></link>.
+ </para>
+ <para>
+ The talloc_set_name() function allocates memory as a child of the
+ pointer. It is logically equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));</programlisting>
+ <para>
+ Note that multiple calls to talloc_set_name() will allocate more
+ memory without releasing the name. All of the memory is released
+ when the ptr is freed using talloc_free().
+ </para>
+ </refsect2>
+ <refsect2><title>void talloc_set_name_const(const void *<emphasis role="italic">ptr</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+ <para>
+ The function talloc_set_name_const() is just like
+ talloc_set_name(), but it takes a string constant, and is much
+ faster. It is extensively used by the "auto naming" macros, such
+ as talloc_p().
+ </para>
+ <para>
+ This function does not allocate any memory. It just copies the
+ supplied pointer into the internal representation of the talloc
+ ptr. This means you must not pass a <emphasis
+ role="italic">name</emphasis> pointer to memory that will
+ disappear before <emphasis role="italic">ptr</emphasis> is freed
+ with talloc_free().
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_named(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ The talloc_named() function creates a named talloc pointer. It
+ is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name(ptr, fmt, ....);</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_named_const(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title>
+ <para>
+ This is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+talloc_set_name_const(ptr, name);</programlisting>
+ </refsect2>
+ <refsect2><title>const char *talloc_get_name(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ This returns the current name for the given talloc pointer,
+ <emphasis role="italic">ptr</emphasis>. See <link
+ linkend="talloc_set_name"><quote>talloc_set_name()</quote></link>
+ for details.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_init(const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ This function creates a zero length named talloc context as a top
+ level context. It is equivalent to:
+ </para>
+ <programlisting>talloc_named(NULL, 0, fmt, ...);</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_new(void *<emphasis role="italic">ctx</emphasis>);</title>
+ <para>
+ This is a utility macro that creates a new memory context hanging
+ off an existing context, automatically naming it "talloc_new:
+ __location__" where __location__ is the source line it is called
+ from. It is particularly useful for creating a new temporary
+ working context.
+ </para>
+ </refsect2>
+ <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_realloc(const void *<emphasis role="italic">ctx</emphasis>, void *<emphasis role="italic">ptr</emphasis>, <emphasis role="italic">type</emphasis>, <emphasis role="italic">count</emphasis>);</title>
+ <para>
+ The talloc_realloc() macro changes the size of a talloc pointer.
+ It has the following equivalences:
+ </para>
+ <programlisting>talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr);</programlisting>
+ <para>
+ The <emphasis role="italic">ctx</emphasis> argument is only used
+ if <emphasis role="italic">ptr</emphasis> is not NULL, otherwise
+ it is ignored.
+ </para>
+ <para>
+ talloc_realloc() returns the new pointer, or NULL on failure.
+ The call will fail either due to a lack of memory, or because the
+ pointer has more than one parent (see <link
+ linkend="talloc_reference"><quote>talloc_reference()</quote></link>).
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);</title>
+ <para>
+ the talloc_realloc_size() function is useful when the type is not
+ known so the type-safe talloc_realloc() cannot be used.
+ </para>
+ </refsect2>
+ <refsect2><title>TYPE *talloc_steal(const void *<emphasis role="italic">new_ctx</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_steal() function changes the parent context of a
+ talloc pointer. It is typically used when the context that the
+ pointer is currently a child of is going to be freed and you wish
+ to keep the memory for a longer time.
+ </para>
+ <para>
+ The talloc_steal() function returns the pointer that you pass it.
+ It does not have any failure modes.
+ </para>
+ <para>
+ It is possible to produce loops in the parent/child
+ relationship if you are not careful with talloc_steal(). No
+ guarantees are provided as to your sanity or the safety of your
+ data if you do this.
+ </para>
+ <para>
+ Note that if you try and call talloc_steal() on a pointer that has
+ more than one parent then the result is ambiguous. Talloc will choose
+ to remove the parent that is currently indicated by talloc_parent()
+ and replace it with the chosen parent. You will also get a message
+ like this via the talloc logging functions:
+ </para>
+ <para>
+ <screen format="linespecific">
+ WARNING: talloc_steal with references at some_dir/source/foo.c:123
+ reference at some_dir/source/other.c:325
+ reference at some_dir/source/third.c:121
+ </screen>
+ </para>
+ <para>
+ To unambiguously change the parent of a pointer please see
+ the
+ function <link linkend="talloc_reference"><quote>talloc_reparent()</quote></link>. See
+ the talloc_set_log_fn() documentation for more information
+ on talloc logging.
+ </para>
+ </refsect2>
+ <refsect2><title>TYPE *talloc_reparent(const void *<emphasis role="italic">old_parent</emphasis>, const void *<emphasis role="italic">new_parent</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_reparent() function changes the parent context of a talloc
+ pointer. It is typically used when the context that the pointer is
+ currently a child of is going to be freed and you wish to keep the
+ memory for a longer time.
+ </para>
+ <para>
+ The talloc_reparent() function returns the pointer that you pass it. It
+ does not have any failure modes.
+ </para>
+ <para>
+ The difference between talloc_reparent() and talloc_steal() is that
+ talloc_reparent() can specify which parent you wish to change. This is
+ useful when a pointer has multiple parents via references.
+ </para>
+ </refsect2>
+ <refsect2><title>TYPE *talloc_move(const void *<emphasis role="italic">new_ctx</emphasis>, TYPE **<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_move() function is a wrapper around
+ talloc_steal() which zeros the source pointer after the
+ move. This avoids a potential source of bugs where a
+ programmer leaves a pointer in two structures, and uses the
+ pointer from the old structure after it has been moved to a
+ new one.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_total_size(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_total_size() function returns the total size in bytes
+ used by this pointer and all child pointers. Mostly useful for
+ debugging.
+ </para>
+ <para>
+ Passing NULL is allowed, but it will only give a meaningful
+ result if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() has been called.
+ </para>
+ </refsect2>
+ <refsect2><title>size_t talloc_total_blocks(const void *<emphasis role="italic">ptr</emphasis>);</title>
+ <para>
+ The talloc_total_blocks() function returns the total memory block
+ count used by this pointer and all child pointers. Mostly useful
+ for debugging.
+ </para>
+ <para>
+ Passing NULL is allowed, but it will only give a meaningful
+ result if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report"><title>void talloc_report(const void *ptr, FILE *f);</title>
+ <para>
+ The talloc_report() function prints a summary report of all
+ memory used by <emphasis role="italic">ptr</emphasis>. One line
+ of report is printed for each immediate child of ptr, showing the
+ total memory and number of blocks used by that child.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_full"><title>void talloc_report_full(const void *<emphasis role="italic">ptr</emphasis>, FILE *<emphasis role="italic">f</emphasis>);</title>
+ <para>
+ This provides a more detailed report than talloc_report(). It
+ will recursively print the entire tree of memory referenced by
+ the pointer. References in the tree are shown by giving the name
+ of the pointer that is referenced.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_depth_cb">
+ <funcsynopsis><funcprototype>
+ <funcdef>void <function>talloc_report_depth_cb</function></funcdef>
+ <paramdef><parameter>const void *ptr</parameter></paramdef>
+ <paramdef><parameter>int depth</parameter></paramdef>
+ <paramdef><parameter>int max_depth</parameter></paramdef>
+ <paramdef><parameter>void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</parameter></paramdef>
+ <paramdef><parameter>void *priv</parameter></paramdef>
+ </funcprototype></funcsynopsis>
+ <para>
+ This provides a more flexible reports than talloc_report(). It
+ will recursively call the callback for the entire tree of memory
+ referenced by the pointer. References in the tree are passed with
+ <emphasis role="italic">is_ref = 1</emphasis> and the pointer that is referenced.
+ </para>
+ <para>
+ You can pass NULL for the pointer, in which case a report is
+ printed for the top level memory context, but only if
+ talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ has been called.
+ </para>
+ <para>
+ The recursion is stopped when depth >= max_depth.
+ max_depth = -1 means only stop at leaf nodes.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_report_depth_file">
+ <funcsynopsis><funcprototype>
+ <funcdef>void <function>talloc_report_depth_file</function></funcdef>
+ <paramdef><parameter>const void *ptr</parameter></paramdef>
+ <paramdef><parameter>int depth</parameter></paramdef>
+ <paramdef><parameter>int max_depth</parameter></paramdef>
+ <paramdef><parameter>FILE *f</parameter></paramdef>
+ </funcprototype></funcsynopsis>
+ <para>
+ This provides a more flexible reports than talloc_report(). It
+ will let you specify the depth and max_depth.
+ </para>
+ </refsect2>
+ <refsect2 id="talloc_enable_leak_report"><title>void talloc_enable_leak_report(void);</title>
+ <para>
+ This enables calling of talloc_report(NULL, stderr) when the
+ program exits. In Samba4 this is enabled by using the
+ --leak-report command line option.
+ </para>
+ <para>
+ For it to be useful, this function must be called before any
+ other talloc function as it establishes a "null context" that
+ acts as the top of the tree. If you don't call this function
+ first then passing NULL to talloc_report() or
+ talloc_report_full() won't give you the full tree printout.
+ </para>
+ <para>
+ Here is a typical talloc report:
+ </para>
+ <screen format="linespecific">talloc report on 'null_context' (total 267 bytes in 15 blocks)
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+iconv(UTF8,CP850) contains 42 bytes in 2 blocks
+libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+iconv(CP850,UTF8) contains 42 bytes in 2 blocks
+iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
+iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
+ </screen>
+ </refsect2>
+ <refsect2 id="talloc_enable_leak_report_full"><title>void talloc_enable_leak_report_full(void);</title>
+ <para>
+ This enables calling of talloc_report_full(NULL, stderr) when the
+ program exits. In Samba4 this is enabled by using the
+ --leak-report-full command line option.
+ </para>
+ <para>
+ For it to be useful, this function must be called before any
+ other talloc function as it establishes a "null context" that
+ acts as the top of the tree. If you don't call this function
+ first then passing NULL to talloc_report() or
+ talloc_report_full() won't give you the full tree printout.
+ </para>
+ <para>
+ Here is a typical full report:
+ </para>
+ <screen format="linespecific">full talloc report on 'root' (total 18 bytes in 8 blocks)
+p1 contains 18 bytes in 7 blocks (ref 0)
+ r1 contains 13 bytes in 2 blocks (ref 0)
+ reference to: p2
+ p2 contains 1 bytes in 1 blocks (ref 1)
+ x3 contains 1 bytes in 1 blocks (ref 0)
+ x2 contains 1 bytes in 1 blocks (ref 0)
+ x1 contains 1 bytes in 1 blocks (ref 0)
+ </screen>
+ </refsect2>
+ <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_zero(const void *<emphasis role="italic">ctx</emphasis>, <emphasis role="italic">type</emphasis>);</title>
+ <para>
+ The talloc_zero() macro is equivalent to:
+ </para>
+ <programlisting>ptr = talloc(ctx, type);
+if (ptr) memset(ptr, 0, sizeof(type));</programlisting>
+ </refsect2>
+ <refsect2><title>void *talloc_zero_size(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>)</title>
+ <para>
+ The talloc_zero_size() function is useful when you don't have a
+ known type.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_memdup(const void *<emphasis role="italic">ctx</emphasis>, const void *<emphasis role="italic">p</emphasis>, size_t size);</title>
+ <para>
+ The talloc_memdup() function is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, size);
+if (ptr) memcpy(ptr, p, size);</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_strdup(const void *<emphasis role="italic">ctx</emphasis>, const char *<emphasis role="italic">p</emphasis>);</title>
+ <para>
+ The talloc_strdup() function is equivalent to:
+ </para>
+ <programlisting>ptr = talloc_size(ctx, strlen(p)+1);
+if (ptr) memcpy(ptr, p, strlen(p)+1);</programlisting>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_strndup(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">p</emphasis>, size_t <emphasis role="italic">n</emphasis>);</title>
+ <para>
+ The talloc_strndup() function is the talloc equivalent of the C
+ library function strndup(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_vasprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, va_list <emphasis role="italic">ap</emphasis>);</title>
+ <para>
+ The talloc_vasprintf() function is the talloc equivalent of the C
+ library function vasprintf(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_asprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title>
+ <para>
+ The talloc_asprintf() function is the talloc equivalent of the C
+ library function asprintf(3).
+ </para>
+ <para>
+ This function sets the name of the new pointer to the passed
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>char *talloc_asprintf_append(char *s, const char *fmt, ...);</title>
+ <para>
+ The talloc_asprintf_append() function appends the given formatted
+ string to the given string.
+ </para>
+ <para>
+ This function sets the name of the new pointer to the new
+ string. This is equivalent to:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, ptr)</programlisting>
+ </refsect2>
+ <refsect2><title>(type *)talloc_array(const void *ctx, type, unsigned int count);</title>
+ <para>
+ The talloc_array() macro is equivalent to:
+ </para>
+ <programlisting>(type *)talloc_size(ctx, sizeof(type) * count);</programlisting>
+ <para>
+ except that it provides integer overflow protection for the
+ multiply, returning NULL if the multiply overflows.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_array_size(const void *ctx, size_t size, unsigned int count);</title>
+ <para>
+ The talloc_array_size() function is useful when the type is not
+ known. It operates in the same way as talloc_array(), but takes a
+ size instead of a type.
+ </para>
+ </refsect2>
+ <refsect2><title>(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, unsigned int count);</title>
+ <para>
+ The talloc_ptrtype() macro should be used when you have a pointer to an array
+ and want to allocate memory of an array to point at with this pointer. When compiling
+ with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+ and talloc_get_name() will return the current location in the source file.
+ and not the type.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)</title>
+ <para>
+ This is a non-macro version of talloc_realloc(), which is useful
+ as libraries sometimes want a realloc function pointer. A
+ realloc(3) implementation encapsulates the functionality of
+ malloc(3), free(3) and realloc(3) in one call, which is why it is
+ useful to be able to pass around a single function pointer.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_autofree_context(void);</title>
+ <para>
+ This is a handy utility function that returns a talloc context
+ which will be automatically freed on program exit. This can be
+ used to reduce the noise in memory leak reports.
+ </para>
+ </refsect2>
+ <refsect2><title>void *talloc_check_name(const void *ptr, const char *name);</title>
+ <para>
+ This function checks if a pointer has the specified <emphasis
+ role="italic">name</emphasis>. If it does then the pointer is
+ returned. It it doesn't then NULL is returned.
+ </para>
+ </refsect2>
+ <refsect2><title>(type *)talloc_get_type(const void *ptr, type);</title>
+ <para>
+ This macro allows you to do type checking on talloc pointers. It
+ is particularly useful for void* private pointers. It is
+ equivalent to this:
+ </para>
+ <programlisting>(type *)talloc_check_name(ptr, #type)</programlisting>
+ </refsect2>
+ <refsect2><title>talloc_set_type(const void *ptr, type);</title>
+ <para>
+ This macro allows you to force the name of a pointer to be a
+ particular <emphasis>type</emphasis>. This can be
+ used in conjunction with talloc_get_type() to do type checking on
+ void* pointers.
+ </para>
+ <para>
+ It is equivalent to this:
+ </para>
+ <programlisting>talloc_set_name_const(ptr, #type)</programlisting>
+ </refsect2>
+ <refsect2><title>talloc_set_log_fn(void (*log_fn)(const char *message));</title>
+ <para>
+ This function sets a logging function that talloc will use for
+ warnings and errors. By default talloc will not print any warnings or
+ errors.
+ </para>
+ </refsect2>
+ <refsect2><title>talloc_set_log_stderr(void);</title>
+ <para>
+ This sets the talloc log function to write log messages to stderr
+ </para>
+ </refsect2>
+ </refsect1>
+ <refsect1><title>PERFORMANCE</title>
+ <para>
+ All the additional features of talloc(3) over malloc(3) do come at a
+ price. We have a simple performance test in Samba4 that measures
+ talloc() versus malloc() performance, and it seems that talloc() is
+ about 10% slower than malloc() on my x86 Debian Linux box. For
+ Samba, the great reduction in code complexity that we get by using
+ talloc makes this worthwhile, especially as the total overhead of
+ talloc/malloc in Samba is already quite small.
+ </para>
+ </refsect1>
+ <refsect1><title>SEE ALSO</title>
+ <para>
+ malloc(3), strndup(3), vasprintf(3), asprintf(3),
+ <ulink url="http://talloc.samba.org/"/>
+ </para>
+ </refsect1>
+
+ <refsect1><title>AUTHOR</title>
+ <para> The original Samba software and related utilities were
+ created by Andrew Tridgell. Samba is now developed by the
+ Samba Team as an Open Source project similar to the way the
+ Linux kernel is developed.
+ </para>
+ </refsect1>
+
+ <refsect1><title>COPYRIGHT/LICENSE</title>
+ <para>
+ Copyright (C) Andrew Tridgell 2004
+ </para>
+ <para>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+ </para>
+ <para>
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+ </para>
+ <para>
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see http://www.gnu.org/licenses/.
+ </para>
+ </refsect1>
+</refentry>
diff --git a/lib/talloc/pytalloc-util.pc.in b/lib/talloc/pytalloc-util.pc.in
new file mode 100644
index 0000000..06f83e2
--- /dev/null
+++ b/lib/talloc/pytalloc-util.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: pytalloc-util@PYTHON_SO_ABI_FLAG@
+Description: Utility functions for using talloc objects with Python
+Version: @TALLOC_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util@PYTHON_LIBNAME_SO_ABI_FLAG@
+Cflags: -I${includedir}
+URL: http://talloc.samba.org/
diff --git a/lib/talloc/pytalloc.c b/lib/talloc/pytalloc.c
new file mode 100644
index 0000000..f6f0681
--- /dev/null
+++ b/lib/talloc/pytalloc.c
@@ -0,0 +1,269 @@
+/*
+ Unix SMB/CIFS implementation.
+ Python Talloc Module
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2010-2011
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include <talloc.h>
+#include <pytalloc.h>
+#include "pytalloc_private.h"
+
+static PyTypeObject TallocObject_Type;
+
+/* print a talloc tree report for a talloc python object */
+static PyObject *pytalloc_report_full(PyObject *self, PyObject *args)
+{
+ PyObject *py_obj = Py_None;
+
+ if (!PyArg_ParseTuple(args, "|O", &py_obj))
+ return NULL;
+
+ if (py_obj == Py_None) {
+ talloc_report_full(NULL, stdout);
+ } else {
+ talloc_report_full(pytalloc_get_mem_ctx(py_obj), stdout);
+ }
+ Py_RETURN_NONE;
+}
+
+/* enable null tracking */
+static PyObject *pytalloc_enable_null_tracking(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ talloc_enable_null_tracking();
+ Py_RETURN_NONE;
+}
+
+/* return the number of talloc blocks */
+static PyObject *pytalloc_total_blocks(PyObject *self, PyObject *args)
+{
+ PyObject *py_obj = Py_None;
+
+ if (!PyArg_ParseTuple(args, "|O", &py_obj))
+ return NULL;
+
+ if (py_obj == Py_None) {
+ return PyLong_FromLong(talloc_total_blocks(NULL));
+ }
+
+ return PyLong_FromLong(talloc_total_blocks(pytalloc_get_mem_ctx(py_obj)));
+}
+
+static PyMethodDef talloc_methods[] = {
+ { "report_full", (PyCFunction)pytalloc_report_full, METH_VARARGS,
+ "show a talloc tree for an object"},
+ { "enable_null_tracking", (PyCFunction)pytalloc_enable_null_tracking, METH_NOARGS,
+ "enable tracking of the NULL object"},
+ { "total_blocks", (PyCFunction)pytalloc_total_blocks, METH_VARARGS,
+ "return talloc block count"},
+ {0}
+};
+
+/**
+ * Default (but only slightly more useful than the default) implementation of Repr().
+ */
+static PyObject *pytalloc_default_repr(PyObject *obj)
+{
+ pytalloc_Object *talloc_obj = (pytalloc_Object *)obj;
+ PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
+
+ return PyUnicode_FromFormat("<%s talloc object at %p>",
+ type->tp_name, talloc_obj->ptr);
+}
+
+/**
+ * Simple dealloc for talloc-wrapping PyObjects
+ */
+static void pytalloc_dealloc(PyObject* self)
+{
+ pytalloc_Object *obj = (pytalloc_Object *)self;
+ assert(talloc_unlink(NULL, obj->talloc_ctx) != -1);
+ obj->talloc_ctx = NULL;
+ self->ob_type->tp_free(self);
+}
+
+/**
+ * Default objects do not support ordered comparisons, but talloc
+ * objects do, sorting by pointers clustered by type.
+ */
+static PyObject *pytalloc_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+ void *ptr1;
+ void *ptr2;
+ if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
+ /* When types match, compare pointers */
+ ptr1 = pytalloc_get_ptr(obj1);
+ ptr2 = pytalloc_get_ptr(obj2);
+ } else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
+ /* Otherwise, compare types */
+ ptr1 = Py_TYPE(obj1);
+ ptr2 = Py_TYPE(obj2);
+ } else {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ switch (op) {
+ case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
+ case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
+ case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
+ case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
+ case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
+ case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
+ }
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+static PyTypeObject TallocObject_Type = {
+ .tp_name = "talloc.Object",
+ .tp_doc = "Python wrapper for a talloc-maintained object.",
+ .tp_basicsize = sizeof(pytalloc_Object),
+ .tp_dealloc = (destructor)pytalloc_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_repr = pytalloc_default_repr,
+ .tp_richcompare = pytalloc_default_richcmp,
+};
+
+/**
+ * Default (but only slightly more useful than the default) implementation of Repr().
+ */
+static PyObject *pytalloc_base_default_repr(PyObject *obj)
+{
+ pytalloc_BaseObject *talloc_obj = (pytalloc_BaseObject *)obj;
+ PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
+
+ return PyUnicode_FromFormat("<%s talloc based object at %p>",
+ type->tp_name, talloc_obj->ptr);
+}
+
+/**
+ * Simple dealloc for talloc-wrapping PyObjects
+ */
+static void pytalloc_base_dealloc(PyObject* self)
+{
+ pytalloc_BaseObject *obj = (pytalloc_BaseObject *)self;
+ assert(talloc_unlink(NULL, obj->talloc_ctx) != -1);
+ obj->talloc_ctx = NULL;
+ self->ob_type->tp_free(self);
+}
+
+/**
+ * Default objects do not support ordered comparisons, but talloc
+ * objects do, sorting by pointers clustered by type.
+ */
+static PyObject *pytalloc_base_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+ void *ptr1;
+ void *ptr2;
+ if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
+ /* When types match, compare pointers */
+ ptr1 = pytalloc_get_ptr(obj1);
+ ptr2 = pytalloc_get_ptr(obj2);
+ } else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
+ /* Otherwise, compare types */
+ ptr1 = Py_TYPE(obj1);
+ ptr2 = Py_TYPE(obj2);
+ } else {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ switch (op) {
+ case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
+ case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
+ case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
+ case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
+ case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
+ case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
+ }
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+static PyTypeObject TallocBaseObject_Type = {
+ .tp_name = "talloc.BaseObject",
+ .tp_doc = "Python wrapper for a talloc-maintained object.",
+ .tp_basicsize = sizeof(pytalloc_BaseObject),
+ .tp_dealloc = (destructor)pytalloc_base_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_repr = pytalloc_base_default_repr,
+ .tp_richcompare = pytalloc_base_default_richcmp,
+};
+
+static PyTypeObject TallocGenericObject_Type = {
+ .tp_name = "talloc.GenericObject",
+ .tp_doc = "Python wrapper for a talloc-maintained object.",
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_base = &TallocBaseObject_Type,
+ .tp_basicsize = sizeof(pytalloc_BaseObject),
+};
+
+#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "talloc",
+ .m_doc = MODULE_DOC,
+ .m_size = -1,
+ .m_methods = talloc_methods,
+};
+
+static PyObject *module_init(void);
+static PyObject *module_init(void)
+{
+ PyObject *m;
+
+ if (PyType_Ready(&TallocObject_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&TallocBaseObject_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&TallocGenericObject_Type) < 0)
+ return NULL;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ Py_INCREF(&TallocObject_Type);
+ if (PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type)) {
+ goto err;
+ }
+ Py_INCREF(&TallocBaseObject_Type);
+ if (PyModule_AddObject(m, "BaseObject", (PyObject *)&TallocBaseObject_Type)) {
+ goto err;
+ }
+ Py_INCREF(&TallocGenericObject_Type);
+ if (PyModule_AddObject(m, "GenericObject", (PyObject *)&TallocGenericObject_Type)) {
+ goto err;
+ }
+ return m;
+
+err:
+ Py_DECREF(m);
+ return NULL;
+}
+
+PyMODINIT_FUNC PyInit_talloc(void);
+PyMODINIT_FUNC PyInit_talloc(void)
+{
+ return module_init();
+}
diff --git a/lib/talloc/pytalloc.h b/lib/talloc/pytalloc.h
new file mode 100644
index 0000000..c1f9b44
--- /dev/null
+++ b/lib/talloc/pytalloc.h
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PYTALLOC_H_
+#define _PYTALLOC_H_
+
+#include <Python.h>
+#include <talloc.h>
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *talloc_ctx;
+ void *ptr; /* eg the array element */
+} pytalloc_Object;
+
+/* Return the PyTypeObject for pytalloc_Object. Returns a borrowed reference. */
+_PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void);
+
+/* Return the PyTypeObject for pytalloc_BaseObject. Returns a borrowed reference. */
+_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void);
+
+/* Check whether a specific object is a talloc Object. */
+_PUBLIC_ int pytalloc_Check(PyObject *);
+
+_PUBLIC_ int pytalloc_BaseObject_check(PyObject *);
+
+_PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name);
+#define pytalloc_check_type(py_obj, type) \
+ _pytalloc_check_type((PyObject *)(py_obj), #type)
+
+/* Retrieve the pointer for a pytalloc_object. Like talloc_get_type()
+ * but for pytalloc_Objects. */
+_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name);
+#define pytalloc_get_type(py_obj, type) ((type *)_pytalloc_get_type((PyObject *)(py_obj), #type))
+
+_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj);
+#define pytalloc_get_ptr(py_obj) _pytalloc_get_ptr((PyObject *)(py_obj))
+_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj);
+#define pytalloc_get_mem_ctx(py_obj) _pytalloc_get_mem_ctx((PyObject *)(py_obj))
+
+_PUBLIC_ const char *_pytalloc_get_name(PyObject *py_obj);
+#define pytalloc_get_name(py_obj) _pytalloc_get_name((PyObject *)(py_obj))
+
+
+_PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr);
+_PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr);
+_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr);
+#define pytalloc_reference(py_type, talloc_ptr) pytalloc_reference_ex(py_type, talloc_ptr, talloc_ptr)
+
+#define pytalloc_new(type, typeobj) pytalloc_steal(typeobj, talloc_zero(NULL, type))
+
+/*
+ * Wrap a generic talloc pointer into a talloc.GenericObject,
+ * this is a subclass of talloc.BaseObject.
+ */
+_PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr);
+#define pytalloc_GenericObject_steal(talloc_ptr) \
+ pytalloc_GenericObject_steal_ex(talloc_ptr, talloc_ptr)
+_PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr);
+#define pytalloc_GenericObject_reference(talloc_ptr) \
+ pytalloc_GenericObject_reference_ex(talloc_ptr, talloc_ptr)
+
+_PUBLIC_ size_t pytalloc_BaseObject_size(void);
+
+_PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type);
+
+#endif /* _PYTALLOC_H_ */
diff --git a/lib/talloc/pytalloc_guide.txt b/lib/talloc/pytalloc_guide.txt
new file mode 100644
index 0000000..85705de
--- /dev/null
+++ b/lib/talloc/pytalloc_guide.txt
@@ -0,0 +1,252 @@
+Using talloc in Samba4
+======================
+
+.. contents::
+
+Jelmer Vernooij
+August 2013
+
+The most current version of this document is available at
+ http://samba.org/ftp/unpacked/talloc/pytalloc_guide.txt
+
+pytalloc is a small library that provides glue for wrapping
+talloc-allocated objects from C in Python objects.
+
+What is pytalloc, and what is it not?
+-------------------------------------
+
+pytalloc is merely a helper library - it provides a convenient base type object
+for objects that wrap talloc-maintained memory in C. It won't write your
+bindings for you but it will make it easier to write C bindings that involve
+talloc, and take away some of the boiler plate.
+
+Python 3
+--------
+
+pytalloc can be used with Python 3. Usage from Python extension remains
+the same, but for the C utilities, the library to link to is tagged with
+Python's PEP3149 ABI tag, for example "pytalloc.cpython34m".
+To make a build for Python 3, configure with PYTHON=/usr/bin/python3.
+.
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+pytalloc_Object / pytalloc_BaseObject
+
+This is the new base class that all Python objects that wrap talloc pointers
+derive from. It is itself a subclass of the "Object" type that all objects
+in Python derive from.
+
+Note that you will almost never create objects of the pytalloc_Object type
+itself, as they are just opaque pointers that can not be accessed from
+Python. A common pattern is other objects that subclass pytalloc_Object and
+rely on it for their memory management.
+
+Each `pytalloc_Object` wraps two core of information - a talloc context
+and a pointer. The pointer is the actual data that is wrapped. The talloc
+context is used for memory management purposes only; when the wrapping Python object
+goes away, it unlinks the talloc context. The talloc context pointer and the ptr
+can (and often do) have the same value.
+
+Each pytalloc_Object has a custom __repr__ implementation that
+describes that it is a talloc object and the location of the
+pointer it is wrapping. it also has a custom __cmp__/__eq__/__neq__ method that
+compares the pointers the object is wrapping rather than the objects
+themselves (since there can be multiple objects that wrap the same talloc
+pointer).
+
+It is preferred to use pytalloc_BaseObject as this implementation
+exposes less in the C ABI and correctly supports pointers in C arrays
+in the way needed by PIDL.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyTypeObject *pytalloc_GetObjectType(void)
+
+Obtain a pointer to the PyTypeObject for `pytalloc_Object`. The
+reference counter for the object will be NOT incremented, so the
+caller MUST NOT decrement it when it no longer needs it (eg by using
+`Py_DECREF`).
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyTypeObject *pytalloc_GetBaseObjectType(void)
+
+Obtain a pointer to the PyTypeObject for `pytalloc_BaseObject`. The
+reference counter for the object will be NOT incremented, so the
+caller MUST NOT decrement it when it no longer needs it (eg by using
+`Py_DECREF`).
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type);
+
+Wrapper for PyType_Ready() that will set the correct values into
+the PyTypeObject to create a BaseObject
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_Check(PyObject *)
+
+Check whether a specific object is a talloc Object. Returns non-zero if it is
+a pytalloc_Object and zero otherwise.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_BaseObject_Check(PyObject *)
+
+Check whether a specific object is a talloc BaseObject. Returns non-zero if it is
+a pytalloc_BaseObject and zero otherwise.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int pytalloc_check_type(PyObject *py_obj, type)
+
+Check if the object based on `pytalloc_*Object` py_obj. type should be a
+C type, similar to a type passed to `talloc_get_type`.
+This can be used as a check before using pytalloc_get_type()
+or an alternative codepath. Returns non-zero if it is
+an object of the expected type and zero otherwise.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+type *pytalloc_get_type(PyObject *py_obj, type)
+
+Retrieve the pointer from a `pytalloc_Object` py_obj. type should be a
+C type, similar to a type passed to `talloc_get_type`.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+pytalloc_get_ptr(PyObject *py_obj)
+
+Retrieve the pointer from a `pytalloc_Object` or `pytalloc_BaseObject`
+py_obj. There is no type checking - use `pytalloc_get_type` if
+possible.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+TALLOC_CTX *pytalloc_get_mem_ctx(PyObject *py_obj)
+
+Retrieve the talloc context associated with a pytalloc_Object or pytalloc_BaseObject.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
+
+Create a new Python wrapping object for a talloc pointer and context, with
+py_type as associated Python sub type object. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
+
+This will *not* increment the reference counter for the talloc context,
+so the caller should make sure such an increment has happened. When the Python
+object goes away, it will unreference the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
+
+Create a new Python wrapping object for a talloc pointer and context, with
+py_type as associated Python sub type object. The pointer will also be used
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
+
+This will *not* increment the reference counter for the talloc context,
+so the caller should make sure such an increment has happened. When the Python
+object goes away, it will unreference the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
+
+Create a new Python wrapping object for a talloc pointer and context, with
+py_type as associated Python sub type object. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
+
+This will increment the reference counter for the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_reference(PyTypeObject *py_type, void *talloc_ptr)
+
+Create a new Python wrapping object for a talloc pointer, with
+py_type as associated Python sub type object. The pointer will also be used
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
+
+This will increment the reference counter for the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_new(type, PyTypeObject *typeobj)
+
+Create a new, empty pytalloc_Object with the specified Python type object. type
+should be a C type, similar to talloc_new().
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_GenericObject_steal_ex(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
+
+This will *not* increment the reference counter for the talloc context,
+so the caller should make sure such an increment has happened. When the Python
+object goes away, it will unreference the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_GenericObject_steal(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. The pointer will also be used
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
+
+This will *not* increment the reference counter for the talloc context,
+so the caller should make sure such an increment has happened. When the Python
+object goes away, it will unreference the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_GenericObject_reference_ex(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. This typically used
+when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element.
+`pytalloc_get_ptr()` can be used to get the pointer out of the object again.
+
+This will increment the reference counter for the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+PyObject *pytalloc_GenericObject_reference(void *ptr)
+
+Create a new Python wrapping object for a generic talloc pointer,
+as sub type of `pytalloc_BaseObject`. The pointer will also be used
+as the talloc context. `pytalloc_get_type()` can be used to get
+the pointer out of the object again.
+
+This will increment the reference counter for the talloc context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+DEPRECATED! PyObject *pytalloc_CObject_FromTallocPtr(void *);
+
+Create a new pytalloc_Object for an arbitrary talloc-maintained C pointer. This will
+use a generic VoidPtr Python type, which just provides an opaque object in
+Python. The caller is responsible for incrementing the talloc reference count before calling
+this function - it will dereference the talloc pointer when it is garbage collected.
+
+This function is deprecated and only available on Python 2.
+Use pytalloc_GenericObject_{reference,steal}[_ex]() instead.
+
+Debug function for talloc in Python
+-----------------------------------
+
+The "talloc" module in Python provides a couple of functions that can be used
+to debug issues with objects wrapped by pytalloc.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+report_full(obj?)
+
+Print a full report on a specific object or on all allocated objects by Python.
+Same behaviour as the `talloc_report_full()` function that is provided by
+C talloc.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+enable_null_tracking()
+
+This enables tracking of the NULL memory context without enabling leak
+reporting on exit. Useful for when you want to do your own leak
+reporting call via talloc_report_null_full().
+
+This must be done in the top level script, not an imported module.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+pytalloc_total_blocks(obj?)
+
+Return the talloc block count for all allocated objects or a specific object if
+specified.
diff --git a/lib/talloc/pytalloc_private.h b/lib/talloc/pytalloc_private.h
new file mode 100644
index 0000000..b23cdfc
--- /dev/null
+++ b/lib/talloc/pytalloc_private.h
@@ -0,0 +1,26 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *talloc_ctx;
+ TALLOC_CTX *talloc_ptr_ctx; /* eg the start of the array */
+ void *ptr; /* eg the array element */
+} pytalloc_BaseObject;
diff --git a/lib/talloc/pytalloc_util.c b/lib/talloc/pytalloc_util.c
new file mode 100644
index 0000000..766938a
--- /dev/null
+++ b/lib/talloc/pytalloc_util.c
@@ -0,0 +1,334 @@
+/*
+ Unix SMB/CIFS implementation.
+ Python/Talloc glue
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include "replace.h"
+#include <talloc.h>
+#include "pytalloc.h"
+#include <assert.h>
+#include "pytalloc_private.h"
+
+static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type,
+ TALLOC_CTX *mem_ctx, void *ptr, bool steal);
+
+_PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
+{
+ static PyTypeObject *type = NULL;
+ PyObject *mod;
+
+ mod = PyImport_ImportModule("talloc");
+ if (mod == NULL) {
+ return NULL;
+ }
+
+ type = (PyTypeObject *)PyObject_GetAttrString(mod, "Object");
+ Py_DECREF(mod);
+
+ return type;
+}
+
+_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
+{
+ static PyTypeObject *type = NULL;
+ PyObject *mod;
+
+ mod = PyImport_ImportModule("talloc");
+ if (mod == NULL) {
+ return NULL;
+ }
+
+ type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
+ Py_DECREF(mod);
+
+ return type;
+}
+
+static PyTypeObject *pytalloc_GetGenericObjectType(void)
+{
+ static PyTypeObject *type = NULL;
+ PyObject *mod;
+
+ mod = PyImport_ImportModule("talloc");
+ if (mod == NULL) {
+ return NULL;
+ }
+
+ type = (PyTypeObject *)PyObject_GetAttrString(mod, "GenericObject");
+ Py_DECREF(mod);
+
+ return type;
+}
+
+/**
+ * Import an existing talloc pointer into a Python object.
+ */
+_PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
+ void *ptr)
+{
+ return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, true);
+}
+
+/**
+ * Import an existing talloc pointer into a Python object.
+ */
+_PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
+{
+ return pytalloc_steal_or_reference(py_type, ptr, ptr, true);
+}
+
+
+/**
+ * Import an existing talloc pointer into a Python object, leaving the
+ * original parent, and creating a reference to the object in the python
+ * object.
+ *
+ * We remember the object we hold the reference to (a
+ * possibly-non-talloc pointer), the existing parent (typically the
+ * start of the array) and the new referenced parent. That way we can
+ * cope with the fact that we will have multiple parents, one per time
+ * python sees the object.
+ */
+_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
+ TALLOC_CTX *mem_ctx, void *ptr)
+{
+ return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, false);
+}
+
+
+/**
+ * Internal function that either steals or references the talloc
+ * pointer into a new talloc context.
+ */
+static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type,
+ TALLOC_CTX *mem_ctx, void *ptr, bool steal)
+{
+ bool ok = false;
+ TALLOC_CTX *talloc_ctx = NULL;
+ bool is_baseobject = false;
+ PyObject *obj = NULL;
+ PyTypeObject *BaseObjectType = NULL, *ObjectType = NULL;
+
+ BaseObjectType = pytalloc_GetBaseObjectType();
+ if (BaseObjectType == NULL) {
+ goto err;
+ }
+ ObjectType = pytalloc_GetObjectType();
+ if (ObjectType == NULL) {
+ goto err;
+ }
+
+ /* this should have been tested by caller */
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ is_baseobject = PyType_IsSubtype(py_type, BaseObjectType);
+ if (!is_baseobject) {
+ if (!PyType_IsSubtype(py_type, ObjectType)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Expected type based on talloc");
+ return NULL;
+ }
+ }
+
+ obj = py_type->tp_alloc(py_type, 0);
+ if (obj == NULL) {
+ goto err;
+ }
+
+ talloc_ctx = talloc_new(NULL);
+ if (talloc_ctx == NULL) {
+ PyErr_NoMemory();
+ goto err;
+ }
+
+ if (steal) {
+ ok = (talloc_steal(talloc_ctx, mem_ctx) != NULL);
+ } else {
+ ok = (talloc_reference(talloc_ctx, mem_ctx) != NULL);
+ }
+ if (!ok) {
+ goto err;
+ }
+ talloc_set_name_const(talloc_ctx, py_type->tp_name);
+
+ if (is_baseobject) {
+ pytalloc_BaseObject *ret = (pytalloc_BaseObject*)obj;
+ ret->talloc_ctx = talloc_ctx;
+ ret->talloc_ptr_ctx = mem_ctx;
+ ret->ptr = ptr;
+ } else {
+ pytalloc_Object *ret = (pytalloc_Object*)obj;
+ ret->talloc_ctx = talloc_ctx;
+ ret->ptr = ptr;
+ }
+ return obj;
+
+err:
+ TALLOC_FREE(talloc_ctx);
+ Py_XDECREF(obj);
+ return NULL;
+}
+
+/*
+ * Wrap a generic talloc pointer into a talloc.GenericObject,
+ * this is a subclass of talloc.BaseObject.
+ */
+_PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr)
+{
+ PyTypeObject *tp = pytalloc_GetGenericObjectType();
+ return pytalloc_steal_ex(tp, mem_ctx, ptr);
+}
+
+/*
+ * Wrap a generic talloc pointer into a talloc.GenericObject,
+ * this is a subclass of talloc.BaseObject.
+ */
+_PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr)
+{
+ PyTypeObject *tp = pytalloc_GetGenericObjectType();
+ return pytalloc_reference_ex(tp, mem_ctx, ptr);
+}
+
+_PUBLIC_ int pytalloc_Check(PyObject *obj)
+{
+ PyTypeObject *tp = pytalloc_GetObjectType();
+
+ return PyObject_TypeCheck(obj, tp);
+}
+
+_PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
+{
+ PyTypeObject *tp = pytalloc_GetBaseObjectType();
+
+ return PyObject_TypeCheck(obj, tp);
+}
+
+_PUBLIC_ size_t pytalloc_BaseObject_size(void)
+{
+ return sizeof(pytalloc_BaseObject);
+}
+
+static void *_pytalloc_get_checked_type(PyObject *py_obj, const char *type_name,
+ bool check_only, const char *function)
+{
+ TALLOC_CTX *mem_ctx;
+ void *ptr = NULL;
+ void *type_obj;
+
+ mem_ctx = _pytalloc_get_mem_ctx(py_obj);
+ ptr = _pytalloc_get_ptr(py_obj);
+
+ if (mem_ctx != ptr || ptr == NULL) {
+ if (check_only) {
+ return NULL;
+ }
+
+ PyErr_Format(PyExc_TypeError, "%s: expected %s, "
+ "but the pointer is no talloc pointer, "
+ "pytalloc_get_ptr() would get the raw pointer.",
+ function, type_name);
+ return NULL;
+ }
+
+ type_obj = talloc_check_name(ptr, type_name);
+ if (type_obj == NULL) {
+ const char *name = NULL;
+
+ if (check_only) {
+ return NULL;
+ }
+
+ name = talloc_get_name(ptr);
+ PyErr_Format(PyExc_TypeError, "%s: expected %s, got %s",
+ function, type_name, name);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+_PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name)
+{
+ void *ptr = NULL;
+
+ ptr = _pytalloc_get_checked_type(py_obj, type_name,
+ true, /* check_only */
+ "pytalloc_check_type");
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ return 1;
+}
+
+_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
+{
+ return _pytalloc_get_checked_type(py_obj, type_name,
+ false, /* not check_only */
+ "pytalloc_get_type");
+}
+
+_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
+{
+ if (pytalloc_BaseObject_check(py_obj)) {
+ return ((pytalloc_BaseObject *)py_obj)->ptr;
+ }
+ if (pytalloc_Check(py_obj)) {
+ return ((pytalloc_Object *)py_obj)->ptr;
+ }
+ return NULL;
+}
+
+_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
+{
+ if (pytalloc_BaseObject_check(py_obj)) {
+ return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
+ }
+ if (pytalloc_Check(py_obj)) {
+ return ((pytalloc_Object *)py_obj)->talloc_ctx;
+ }
+ return NULL;
+}
+
+_PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type)
+{
+ PyTypeObject *talloc_type = pytalloc_GetBaseObjectType();
+ if (talloc_type == NULL) {
+ return -1;
+ }
+
+ type->tp_base = talloc_type;
+ type->tp_basicsize = pytalloc_BaseObject_size();
+
+ return PyType_Ready(type);
+}
+
+_PUBLIC_ const char *_pytalloc_get_name(PyObject *obj)
+{
+ void *ptr = pytalloc_get_ptr(obj);
+ if (ptr == NULL) {
+ return "non-talloc object";
+ }
+ return talloc_get_name(ptr);
+}
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
new file mode 100644
index 0000000..3a93a82
--- /dev/null
+++ b/lib/talloc/talloc.c
@@ -0,0 +1,3070 @@
+/*
+ Samba Unix SMB/CIFS implementation.
+
+ Samba trivial allocation library - new interface
+
+ NOTE: Please read talloc_guide.txt for full documentation
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ inspired by http://swapped.cc/halloc/
+*/
+
+#include "replace.h"
+#include "talloc.h"
+
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+
+#if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR)
+#error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR"
+#endif
+
+#if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR)
+#error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR"
+#endif
+
+/* Special macros that are no-ops except when run under Valgrind on
+ * x86. They've moved a little bit from valgrind 1.0.4 to 1.9.4 */
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ /* memcheck.h includes valgrind.h */
+#include <valgrind/memcheck.h>
+#elif defined(HAVE_VALGRIND_H)
+#include <valgrind.h>
+#endif
+
+#define MAX_TALLOC_SIZE 0x10000000
+
+#define TALLOC_FLAG_FREE 0x01
+#define TALLOC_FLAG_LOOP 0x02
+#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */
+#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */
+
+/*
+ * Bits above this are random, used to make it harder to fake talloc
+ * headers during an attack. Try not to change this without good reason.
+ */
+#define TALLOC_FLAG_MASK 0x0F
+
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
+
+#define TALLOC_MAGIC_BASE 0xe814ec70
+#define TALLOC_MAGIC_NON_RANDOM ( \
+ ~TALLOC_FLAG_MASK & ( \
+ TALLOC_MAGIC_BASE + \
+ (TALLOC_BUILD_VERSION_MAJOR << 24) + \
+ (TALLOC_BUILD_VERSION_MINOR << 16) + \
+ (TALLOC_BUILD_VERSION_RELEASE << 8)))
+static unsigned int talloc_magic = TALLOC_MAGIC_NON_RANDOM;
+
+/* by default we abort when given a bad pointer (such as when talloc_free() is called
+ on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* these macros gain us a few percent of speed on gcc */
+#if (__GNUC__ >= 3)
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+ as its first argument */
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() is called, otherwise it remains
+ NULL
+*/
+static void *null_context;
+static bool talloc_report_null;
+static bool talloc_report_null_full;
+static void *autofree_context;
+
+static void talloc_setup_atexit(void);
+
+/* used to enable fill of memory on free, which can be useful for
+ * catching use after free errors when valgrind is too slow
+ */
+static struct {
+ bool initialised;
+ bool enabled;
+ uint8_t fill_value;
+} talloc_fill;
+
+#define TALLOC_FILL_ENV "TALLOC_FREE_FILL"
+
+/*
+ * do not wipe the header, to allow the
+ * double-free logic to still work
+ */
+#define TC_INVALIDATE_FULL_FILL_CHUNK(_tc) do { \
+ if (unlikely(talloc_fill.enabled)) { \
+ size_t _flen = (_tc)->size; \
+ char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \
+ memset(_fptr, talloc_fill.fill_value, _flen); \
+ } \
+} while (0)
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+/* Mark the whole chunk as not accessible */
+#define TC_INVALIDATE_FULL_VALGRIND_CHUNK(_tc) do { \
+ size_t _flen = TC_HDR_SIZE + (_tc)->size; \
+ char *_fptr = (char *)(_tc); \
+ VALGRIND_MAKE_MEM_NOACCESS(_fptr, _flen); \
+} while(0)
+#else
+#define TC_INVALIDATE_FULL_VALGRIND_CHUNK(_tc) do { } while (0)
+#endif
+
+#define TC_INVALIDATE_FULL_CHUNK(_tc) do { \
+ TC_INVALIDATE_FULL_FILL_CHUNK(_tc); \
+ TC_INVALIDATE_FULL_VALGRIND_CHUNK(_tc); \
+} while (0)
+
+#define TC_INVALIDATE_SHRINK_FILL_CHUNK(_tc, _new_size) do { \
+ if (unlikely(talloc_fill.enabled)) { \
+ size_t _flen = (_tc)->size - (_new_size); \
+ char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \
+ _fptr += (_new_size); \
+ memset(_fptr, talloc_fill.fill_value, _flen); \
+ } \
+} while (0)
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+/* Mark the unused bytes not accessible */
+#define TC_INVALIDATE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { \
+ size_t _flen = (_tc)->size - (_new_size); \
+ char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \
+ _fptr += (_new_size); \
+ VALGRIND_MAKE_MEM_NOACCESS(_fptr, _flen); \
+} while (0)
+#else
+#define TC_INVALIDATE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { } while (0)
+#endif
+
+#define TC_INVALIDATE_SHRINK_CHUNK(_tc, _new_size) do { \
+ TC_INVALIDATE_SHRINK_FILL_CHUNK(_tc, _new_size); \
+ TC_INVALIDATE_SHRINK_VALGRIND_CHUNK(_tc, _new_size); \
+} while (0)
+
+#define TC_UNDEFINE_SHRINK_FILL_CHUNK(_tc, _new_size) do { \
+ if (unlikely(talloc_fill.enabled)) { \
+ size_t _flen = (_tc)->size - (_new_size); \
+ char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \
+ _fptr += (_new_size); \
+ memset(_fptr, talloc_fill.fill_value, _flen); \
+ } \
+} while (0)
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+/* Mark the unused bytes as undefined */
+#define TC_UNDEFINE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { \
+ size_t _flen = (_tc)->size - (_new_size); \
+ char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \
+ _fptr += (_new_size); \
+ VALGRIND_MAKE_MEM_UNDEFINED(_fptr, _flen); \
+} while (0)
+#else
+#define TC_UNDEFINE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { } while (0)
+#endif
+
+#define TC_UNDEFINE_SHRINK_CHUNK(_tc, _new_size) do { \
+ TC_UNDEFINE_SHRINK_FILL_CHUNK(_tc, _new_size); \
+ TC_UNDEFINE_SHRINK_VALGRIND_CHUNK(_tc, _new_size); \
+} while (0)
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+/* Mark the new bytes as undefined */
+#define TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size) do { \
+ size_t _old_used = TC_HDR_SIZE + (_tc)->size; \
+ size_t _new_used = TC_HDR_SIZE + (_new_size); \
+ size_t _flen = _new_used - _old_used; \
+ char *_fptr = _old_used + (char *)(_tc); \
+ VALGRIND_MAKE_MEM_UNDEFINED(_fptr, _flen); \
+} while (0)
+#else
+#define TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size) do { } while (0)
+#endif
+
+#define TC_UNDEFINE_GROW_CHUNK(_tc, _new_size) do { \
+ TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size); \
+} while (0)
+
+struct talloc_reference_handle {
+ struct talloc_reference_handle *next, *prev;
+ void *ptr;
+ const char *location;
+};
+
+struct talloc_memlimit {
+ struct talloc_chunk *parent;
+ struct talloc_memlimit *upper;
+ size_t max_size;
+ size_t cur_size;
+};
+
+static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size);
+static inline void talloc_memlimit_grow(struct talloc_memlimit *limit,
+ size_t size);
+static inline void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+ size_t size);
+static inline void tc_memlimit_update_on_free(struct talloc_chunk *tc);
+
+static inline void _tc_set_name_const(struct talloc_chunk *tc,
+ const char *name);
+static struct talloc_chunk *_vasprintf_tc(const void *t,
+ const char *fmt,
+ va_list ap);
+
+typedef int (*talloc_destructor_t)(void *);
+
+struct talloc_pool_hdr;
+
+struct talloc_chunk {
+ /*
+ * flags includes the talloc magic, which is randomised to
+ * make overwrite attacks harder
+ */
+ unsigned flags;
+
+ /*
+ * If you have a logical tree like:
+ *
+ * <parent>
+ * / | \
+ * / | \
+ * / | \
+ * <child 1> <child 2> <child 3>
+ *
+ * The actual talloc tree is:
+ *
+ * <parent>
+ * |
+ * <child 1> - <child 2> - <child 3>
+ *
+ * The children are linked with next/prev pointers, and
+ * child 1 is linked to the parent with parent/child
+ * pointers.
+ */
+
+ struct talloc_chunk *next, *prev;
+ struct talloc_chunk *parent, *child;
+ struct talloc_reference_handle *refs;
+ talloc_destructor_t destructor;
+ const char *name;
+ size_t size;
+
+ /*
+ * limit semantics:
+ * if 'limit' is set it means all *new* children of the context will
+ * be limited to a total aggregate size ox max_size for memory
+ * allocations.
+ * cur_size is used to keep track of the current use
+ */
+ struct talloc_memlimit *limit;
+
+ /*
+ * For members of a pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
+ * is a pointer to the struct talloc_chunk of the pool that it was
+ * allocated from. This way children can quickly find the pool to chew
+ * from.
+ */
+ struct talloc_pool_hdr *pool;
+};
+
+union talloc_chunk_cast_u {
+ uint8_t *ptr;
+ struct talloc_chunk *chunk;
+};
+
+/* 16 byte alignment seems to keep everyone happy */
+#define TC_ALIGN16(s) (((s)+15)&~15)
+#define TC_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_chunk))
+#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+
+_PUBLIC_ int talloc_version_major(void)
+{
+ return TALLOC_VERSION_MAJOR;
+}
+
+_PUBLIC_ int talloc_version_minor(void)
+{
+ return TALLOC_VERSION_MINOR;
+}
+
+_PUBLIC_ int talloc_test_get_magic(void)
+{
+ return talloc_magic;
+}
+
+static inline void _talloc_chunk_set_free(struct talloc_chunk *tc,
+ const char *location)
+{
+ /*
+ * Mark this memory as free, and also over-stamp the talloc
+ * magic with the old-style magic.
+ *
+ * Why? This tries to avoid a memory read use-after-free from
+ * disclosing our talloc magic, which would then allow an
+ * attacker to prepare a valid header and so run a destructor.
+ *
+ */
+ tc->flags = TALLOC_MAGIC_NON_RANDOM | TALLOC_FLAG_FREE
+ | (tc->flags & TALLOC_FLAG_MASK);
+
+ /* we mark the freed memory with where we called the free
+ * from. This means on a double free error we can report where
+ * the first free came from
+ */
+ if (location) {
+ tc->name = location;
+ }
+}
+
+static inline void _talloc_chunk_set_not_free(struct talloc_chunk *tc)
+{
+ /*
+ * Mark this memory as not free.
+ *
+ * Why? This is memory either in a pool (and so available for
+ * talloc's re-use or after the realloc(). We need to mark
+ * the memory as free() before any realloc() call as we can't
+ * write to the memory after that.
+ *
+ * We put back the normal magic instead of the 'not random'
+ * magic.
+ */
+
+ tc->flags = talloc_magic |
+ ((tc->flags & TALLOC_FLAG_MASK) & ~TALLOC_FLAG_FREE);
+}
+
+static void (*talloc_log_fn)(const char *message);
+
+_PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message))
+{
+ talloc_log_fn = log_fn;
+}
+
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+#define CONSTRUCTOR __attribute__((constructor))
+#elif defined(HAVE_PRAGMA_INIT)
+#define CONSTRUCTOR
+#pragma init (talloc_lib_init)
+#endif
+#if defined(HAVE_CONSTRUCTOR_ATTRIBUTE) || defined(HAVE_PRAGMA_INIT)
+void talloc_lib_init(void) CONSTRUCTOR;
+void talloc_lib_init(void)
+{
+ uint32_t random_value;
+#if defined(HAVE_GETAUXVAL) && defined(AT_RANDOM)
+ uint8_t *p;
+ /*
+ * Use the kernel-provided random values used for
+ * ASLR. This won't change per-exec, which is ideal for us
+ */
+ p = (uint8_t *) getauxval(AT_RANDOM);
+ if (p) {
+ /*
+ * We get 16 bytes from getauxval. By calling rand(),
+ * a totally insecure PRNG, but one that will
+ * deterministically have a different value when called
+ * twice, we ensure that if two talloc-like libraries
+ * are somehow loaded in the same address space, that
+ * because we choose different bytes, we will keep the
+ * protection against collision of multiple talloc
+ * libs.
+ *
+ * This protection is important because the effects of
+ * passing a talloc pointer from one to the other may
+ * be very hard to determine.
+ */
+ int offset = rand() % (16 - sizeof(random_value));
+ memcpy(&random_value, p + offset, sizeof(random_value));
+ } else
+#endif
+ {
+ /*
+ * Otherwise, hope the location we are loaded in
+ * memory is randomised by someone else
+ */
+ random_value = ((uintptr_t)talloc_lib_init & 0xFFFFFFFF);
+ }
+ talloc_magic = random_value & ~TALLOC_FLAG_MASK;
+}
+#else
+#warning "No __attribute__((constructor)) support found on this platform, additional talloc security measures not available"
+#endif
+
+static void talloc_lib_atexit(void)
+{
+ TALLOC_FREE(autofree_context);
+
+ if (talloc_total_size(null_context) == 0) {
+ return;
+ }
+
+ if (talloc_report_null_full) {
+ talloc_report_full(null_context, stderr);
+ } else if (talloc_report_null) {
+ talloc_report(null_context, stderr);
+ }
+}
+
+static void talloc_setup_atexit(void)
+{
+ static bool done;
+
+ if (done) {
+ return;
+ }
+
+ atexit(talloc_lib_atexit);
+ done = true;
+}
+
+static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+static void talloc_log(const char *fmt, ...)
+{
+ va_list ap;
+ char *message;
+
+ if (!talloc_log_fn) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ message = talloc_vasprintf(NULL, fmt, ap);
+ va_end(ap);
+
+ talloc_log_fn(message);
+ talloc_free(message);
+}
+
+static void talloc_log_stderr(const char *message)
+{
+ fprintf(stderr, "%s", message);
+}
+
+_PUBLIC_ void talloc_set_log_stderr(void)
+{
+ talloc_set_log_fn(talloc_log_stderr);
+}
+
+static void (*talloc_abort_fn)(const char *reason);
+
+_PUBLIC_ void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+ talloc_abort_fn = abort_fn;
+}
+
+static void talloc_abort(const char *reason)
+{
+ talloc_log("%s\n", reason);
+
+ if (!talloc_abort_fn) {
+ TALLOC_ABORT(reason);
+ }
+
+ talloc_abort_fn(reason);
+}
+
+static void talloc_abort_access_after_free(void)
+{
+ talloc_abort("Bad talloc magic value - access after free");
+}
+
+static void talloc_abort_unknown_value(void)
+{
+ talloc_abort("Bad talloc magic value - unknown value");
+}
+
+/* panic if we get a bad magic value */
+static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
+{
+ const char *pp = (const char *)ptr;
+ struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
+ if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) != talloc_magic)) {
+ if ((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK))
+ == (TALLOC_MAGIC_NON_RANDOM | TALLOC_FLAG_FREE)) {
+ talloc_log("talloc: access after free error - first free may be at %s\n", tc->name);
+ talloc_abort_access_after_free();
+ return NULL;
+ }
+
+ talloc_abort_unknown_value();
+ return NULL;
+ }
+ return tc;
+}
+
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+
+/*
+ return the parent chunk of a pointer
+*/
+static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+ while (tc->prev) tc=tc->prev;
+
+ return tc->parent;
+}
+
+_PUBLIC_ void *talloc_parent(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
+}
+
+/*
+ find parents name
+*/
+_PUBLIC_ const char *talloc_parent_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? tc->name : NULL;
+}
+
+/*
+ A pool carries an in-pool object count count in the first 16 bytes.
+ bytes. This is done to support talloc_steal() to a parent outside of the
+ pool. The count includes the pool itself, so a talloc_free() on a pool will
+ only destroy the pool if the count has dropped to zero. A talloc_free() of a
+ pool member will reduce the count, and eventually also call free(3) on the
+ pool memory.
+
+ The object count is not put into "struct talloc_chunk" because it is only
+ relevant for talloc pools and the alignment to 16 bytes would increase the
+ memory footprint of each talloc chunk by those 16 bytes.
+*/
+
+struct talloc_pool_hdr {
+ void *end;
+ unsigned int object_count;
+ size_t poolsize;
+};
+
+union talloc_pool_hdr_cast_u {
+ uint8_t *ptr;
+ struct talloc_pool_hdr *hdr;
+};
+
+#define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr))
+
+static inline struct talloc_pool_hdr *talloc_pool_from_chunk(struct talloc_chunk *c)
+{
+ union talloc_chunk_cast_u tcc = { .chunk = c };
+ union talloc_pool_hdr_cast_u tphc = { tcc.ptr - TP_HDR_SIZE };
+ return tphc.hdr;
+}
+
+static inline struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h)
+{
+ union talloc_pool_hdr_cast_u tphc = { .hdr = h };
+ union talloc_chunk_cast_u tcc = { .ptr = tphc.ptr + TP_HDR_SIZE };
+ return tcc.chunk;
+}
+
+static inline void *tc_pool_end(struct talloc_pool_hdr *pool_hdr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr);
+ return (char *)tc + TC_HDR_SIZE + pool_hdr->poolsize;
+}
+
+static inline size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr)
+{
+ return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end;
+}
+
+/* If tc is inside a pool, this gives the next neighbour. */
+static inline void *tc_next_chunk(struct talloc_chunk *tc)
+{
+ return (char *)tc + TC_ALIGN16(TC_HDR_SIZE + tc->size);
+}
+
+static inline void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr);
+ return tc_next_chunk(tc);
+}
+
+/* Mark the whole remaining pool as not accessible */
+static inline void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr)
+{
+ size_t flen = tc_pool_space_left(pool_hdr);
+
+ if (unlikely(talloc_fill.enabled)) {
+ memset(pool_hdr->end, talloc_fill.fill_value, flen);
+ }
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+ VALGRIND_MAKE_MEM_NOACCESS(pool_hdr->end, flen);
+#endif
+}
+
+/*
+ Allocate from a pool
+*/
+
+static inline struct talloc_chunk *tc_alloc_pool(struct talloc_chunk *parent,
+ size_t size, size_t prefix_len)
+{
+ struct talloc_pool_hdr *pool_hdr = NULL;
+ union talloc_chunk_cast_u tcc;
+ size_t space_left;
+ struct talloc_chunk *result;
+ size_t chunk_size;
+
+ if (parent == NULL) {
+ return NULL;
+ }
+
+ if (parent->flags & TALLOC_FLAG_POOL) {
+ pool_hdr = talloc_pool_from_chunk(parent);
+ }
+ else if (parent->flags & TALLOC_FLAG_POOLMEM) {
+ pool_hdr = parent->pool;
+ }
+
+ if (pool_hdr == NULL) {
+ return NULL;
+ }
+
+ space_left = tc_pool_space_left(pool_hdr);
+
+ /*
+ * Align size to 16 bytes
+ */
+ chunk_size = TC_ALIGN16(size + prefix_len);
+
+ if (space_left < chunk_size) {
+ return NULL;
+ }
+
+ tcc = (union talloc_chunk_cast_u) {
+ .ptr = ((uint8_t *)pool_hdr->end) + prefix_len
+ };
+ result = tcc.chunk;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+ VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, chunk_size);
+#endif
+
+ pool_hdr->end = (void *)((char *)pool_hdr->end + chunk_size);
+
+ result->flags = talloc_magic | TALLOC_FLAG_POOLMEM;
+ result->pool = pool_hdr;
+
+ pool_hdr->object_count++;
+
+ return result;
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+static inline void *__talloc_with_prefix(const void *context,
+ size_t size,
+ size_t prefix_len,
+ struct talloc_chunk **tc_ret)
+{
+ struct talloc_chunk *tc = NULL;
+ struct talloc_memlimit *limit = NULL;
+ size_t total_len = TC_HDR_SIZE + size + prefix_len;
+ struct talloc_chunk *parent = NULL;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ if (unlikely(total_len < TC_HDR_SIZE)) {
+ return NULL;
+ }
+
+ if (likely(context != NULL)) {
+ parent = talloc_chunk_from_ptr(context);
+
+ if (parent->limit != NULL) {
+ limit = parent->limit;
+ }
+
+ tc = tc_alloc_pool(parent, TC_HDR_SIZE+size, prefix_len);
+ }
+
+ if (tc == NULL) {
+ uint8_t *ptr = NULL;
+ union talloc_chunk_cast_u tcc;
+
+ /*
+ * Only do the memlimit check/update on actual allocation.
+ */
+ if (!talloc_memlimit_check(limit, total_len)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ptr = malloc(total_len);
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+ tcc = (union talloc_chunk_cast_u) { .ptr = ptr + prefix_len };
+ tc = tcc.chunk;
+ tc->flags = talloc_magic;
+ tc->pool = NULL;
+
+ talloc_memlimit_grow(limit, total_len);
+ }
+
+ tc->limit = limit;
+ tc->size = size;
+ tc->destructor = NULL;
+ tc->child = NULL;
+ tc->name = NULL;
+ tc->refs = NULL;
+
+ if (likely(context != NULL)) {
+ if (parent->child) {
+ parent->child->parent = NULL;
+ tc->next = parent->child;
+ tc->next->prev = tc;
+ } else {
+ tc->next = NULL;
+ }
+ tc->parent = parent;
+ tc->prev = NULL;
+ parent->child = tc;
+ } else {
+ tc->next = tc->prev = tc->parent = NULL;
+ }
+
+ *tc_ret = tc;
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+static inline void *__talloc(const void *context,
+ size_t size,
+ struct talloc_chunk **tc)
+{
+ return __talloc_with_prefix(context, size, 0, tc);
+}
+
+/*
+ * Create a talloc pool
+ */
+
+static inline void *_talloc_pool(const void *context, size_t size)
+{
+ struct talloc_chunk *tc = NULL;
+ struct talloc_pool_hdr *pool_hdr;
+ void *result;
+
+ result = __talloc_with_prefix(context, size, TP_HDR_SIZE, &tc);
+
+ if (unlikely(result == NULL)) {
+ return NULL;
+ }
+
+ pool_hdr = talloc_pool_from_chunk(tc);
+
+ tc->flags |= TALLOC_FLAG_POOL;
+ tc->size = 0;
+
+ pool_hdr->object_count = 1;
+ pool_hdr->end = result;
+ pool_hdr->poolsize = size;
+
+ tc_invalidate_pool(pool_hdr);
+
+ return result;
+}
+
+_PUBLIC_ void *talloc_pool(const void *context, size_t size)
+{
+ return _talloc_pool(context, size);
+}
+
+/*
+ * Create a talloc pool correctly sized for a basic size plus
+ * a number of subobjects whose total size is given. Essentially
+ * a custom allocator for talloc to reduce fragmentation.
+ */
+
+_PUBLIC_ void *_talloc_pooled_object(const void *ctx,
+ size_t type_size,
+ const char *type_name,
+ unsigned num_subobjects,
+ size_t total_subobjects_size)
+{
+ size_t poolsize, subobjects_slack, tmp;
+ struct talloc_chunk *tc;
+ struct talloc_pool_hdr *pool_hdr;
+ void *ret;
+
+ poolsize = type_size + total_subobjects_size;
+
+ if ((poolsize < type_size) || (poolsize < total_subobjects_size)) {
+ goto overflow;
+ }
+
+ if (num_subobjects == UINT_MAX) {
+ goto overflow;
+ }
+ num_subobjects += 1; /* the object body itself */
+
+ /*
+ * Alignment can increase the pool size by at most 15 bytes per object
+ * plus alignment for the object itself
+ */
+ subobjects_slack = (TC_HDR_SIZE + TP_HDR_SIZE + 15) * num_subobjects;
+ if (subobjects_slack < num_subobjects) {
+ goto overflow;
+ }
+
+ tmp = poolsize + subobjects_slack;
+ if ((tmp < poolsize) || (tmp < subobjects_slack)) {
+ goto overflow;
+ }
+ poolsize = tmp;
+
+ ret = _talloc_pool(ctx, poolsize);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(ret);
+ tc->size = type_size;
+
+ pool_hdr = talloc_pool_from_chunk(tc);
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+ VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, type_size);
+#endif
+
+ pool_hdr->end = ((char *)pool_hdr->end + TC_ALIGN16(type_size));
+
+ _tc_set_name_const(tc, type_name);
+ return ret;
+
+overflow:
+ return NULL;
+}
+
+/*
+ setup a destructor to be called on free of a pointer
+ the destructor should return 0 on success, or -1 on failure.
+ if the destructor fails then the free is failed, and the memory can
+ be continued to be used
+*/
+_PUBLIC_ void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->destructor = destructor;
+}
+
+/*
+ increase the reference count on a piece of memory.
+*/
+_PUBLIC_ int talloc_increase_ref_count(const void *ptr)
+{
+ if (unlikely(!talloc_reference(null_context, ptr))) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ helper for talloc_reference()
+
+ this is referenced by a function pointer and should not be inline
+*/
+static int talloc_reference_destructor(struct talloc_reference_handle *handle)
+{
+ struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
+ _TLIST_REMOVE(ptr_tc->refs, handle);
+ return 0;
+}
+
+/*
+ more efficient way to add a name to a pointer - the name must point to a
+ true string constant
+*/
+static inline void _tc_set_name_const(struct talloc_chunk *tc,
+ const char *name)
+{
+ tc->name = name;
+}
+
+/*
+ internal talloc_named_const()
+*/
+static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
+{
+ void *ptr;
+ struct talloc_chunk *tc = NULL;
+
+ ptr = __talloc(context, size, &tc);
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ _tc_set_name_const(tc, name);
+
+ return ptr;
+}
+
+/*
+ make a secondary reference to a pointer, hanging off the given context.
+ the pointer remains valid until both the original caller and this given
+ context are freed.
+
+ the major use for this is when two different structures need to reference the
+ same underlying data, and you want to be able to free the two instances separately,
+ and in either order
+*/
+_PUBLIC_ void *_talloc_reference_loc(const void *context, const void *ptr, const char *location)
+{
+ struct talloc_chunk *tc;
+ struct talloc_reference_handle *handle;
+ if (unlikely(ptr == NULL)) return NULL;
+
+ tc = talloc_chunk_from_ptr(ptr);
+ handle = (struct talloc_reference_handle *)_talloc_named_const(context,
+ sizeof(struct talloc_reference_handle),
+ TALLOC_MAGIC_REFERENCE);
+ if (unlikely(handle == NULL)) return NULL;
+
+ /* note that we hang the destructor off the handle, not the
+ main context as that allows the caller to still setup their
+ own destructor on the context if they want to */
+ talloc_set_destructor(handle, talloc_reference_destructor);
+ handle->ptr = discard_const_p(void, ptr);
+ handle->location = location;
+ _TLIST_ADD(tc->refs, handle);
+ return handle->ptr;
+}
+
+static void *_talloc_steal_internal(const void *new_ctx, const void *ptr);
+
+static inline void _tc_free_poolmem(struct talloc_chunk *tc,
+ const char *location)
+{
+ struct talloc_pool_hdr *pool;
+ struct talloc_chunk *pool_tc;
+ void *next_tc;
+
+ pool = tc->pool;
+ pool_tc = talloc_chunk_from_pool(pool);
+ next_tc = tc_next_chunk(tc);
+
+ _talloc_chunk_set_free(tc, location);
+
+ TC_INVALIDATE_FULL_CHUNK(tc);
+
+ if (unlikely(pool->object_count == 0)) {
+ talloc_abort("Pool object count zero!");
+ return;
+ }
+
+ pool->object_count--;
+
+ if (unlikely(pool->object_count == 1
+ && !(pool_tc->flags & TALLOC_FLAG_FREE))) {
+ /*
+ * if there is just one object left in the pool
+ * and pool->flags does not have TALLOC_FLAG_FREE,
+ * it means this is the pool itself and
+ * the rest is available for new objects
+ * again.
+ */
+ pool->end = tc_pool_first_chunk(pool);
+ tc_invalidate_pool(pool);
+ return;
+ }
+
+ if (unlikely(pool->object_count == 0)) {
+ /*
+ * we mark the freed memory with where we called the free
+ * from. This means on a double free error we can report where
+ * the first free came from
+ */
+ pool_tc->name = location;
+
+ if (pool_tc->flags & TALLOC_FLAG_POOLMEM) {
+ _tc_free_poolmem(pool_tc, location);
+ } else {
+ /*
+ * The tc_memlimit_update_on_free()
+ * call takes into account the
+ * prefix TP_HDR_SIZE allocated before
+ * the pool talloc_chunk.
+ */
+ tc_memlimit_update_on_free(pool_tc);
+ TC_INVALIDATE_FULL_CHUNK(pool_tc);
+ free(pool);
+ }
+ return;
+ }
+
+ if (pool->end == next_tc) {
+ /*
+ * if pool->pool still points to end of
+ * 'tc' (which is stored in the 'next_tc' variable),
+ * we can reclaim the memory of 'tc'.
+ */
+ pool->end = tc;
+ return;
+ }
+
+ /*
+ * Do nothing. The memory is just "wasted", waiting for the pool
+ * itself to be freed.
+ */
+}
+
+static inline void _tc_free_children_internal(struct talloc_chunk *tc,
+ void *ptr,
+ const char *location);
+
+static inline int _talloc_free_internal(void *ptr, const char *location);
+
+/*
+ internal free call that takes a struct talloc_chunk *.
+*/
+static inline int _tc_free_internal(struct talloc_chunk *tc,
+ const char *location)
+{
+ void *ptr_to_free;
+ void *ptr = TC_PTR_FROM_CHUNK(tc);
+
+ if (unlikely(tc->refs)) {
+ int is_child;
+ /* check if this is a reference from a child or
+ * grandchild back to it's parent or grandparent
+ *
+ * in that case we need to remove the reference and
+ * call another instance of talloc_free() on the current
+ * pointer.
+ */
+ is_child = talloc_is_parent(tc->refs, ptr);
+ _talloc_free_internal(tc->refs, location);
+ if (is_child) {
+ return _talloc_free_internal(ptr, location);
+ }
+ return -1;
+ }
+
+ if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
+ /* we have a free loop - stop looping */
+ return 0;
+ }
+
+ if (unlikely(tc->destructor)) {
+ talloc_destructor_t d = tc->destructor;
+
+ /*
+ * Protect the destructor against some overwrite
+ * attacks, by explicitly checking it has the right
+ * magic here.
+ */
+ if (talloc_chunk_from_ptr(ptr) != tc) {
+ /*
+ * This can't actually happen, the
+ * call itself will panic.
+ */
+ TALLOC_ABORT("talloc_chunk_from_ptr failed!");
+ }
+
+ if (d == (talloc_destructor_t)-1) {
+ return -1;
+ }
+ tc->destructor = (talloc_destructor_t)-1;
+ if (d(ptr) == -1) {
+ /*
+ * Only replace the destructor pointer if
+ * calling the destructor didn't modify it.
+ */
+ if (tc->destructor == (talloc_destructor_t)-1) {
+ tc->destructor = d;
+ }
+ return -1;
+ }
+ tc->destructor = NULL;
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ tc->prev = tc->next = NULL;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ _tc_free_children_internal(tc, ptr, location);
+
+ _talloc_chunk_set_free(tc, location);
+
+ if (tc->flags & TALLOC_FLAG_POOL) {
+ struct talloc_pool_hdr *pool;
+
+ pool = talloc_pool_from_chunk(tc);
+
+ if (unlikely(pool->object_count == 0)) {
+ talloc_abort("Pool object count zero!");
+ return 0;
+ }
+
+ pool->object_count--;
+
+ if (likely(pool->object_count != 0)) {
+ return 0;
+ }
+
+ /*
+ * With object_count==0, a pool becomes a normal piece of
+ * memory to free. If it's allocated inside a pool, it needs
+ * to be freed as poolmem, else it needs to be just freed.
+ */
+ ptr_to_free = pool;
+ } else {
+ ptr_to_free = tc;
+ }
+
+ if (tc->flags & TALLOC_FLAG_POOLMEM) {
+ _tc_free_poolmem(tc, location);
+ return 0;
+ }
+
+ tc_memlimit_update_on_free(tc);
+
+ TC_INVALIDATE_FULL_CHUNK(tc);
+ free(ptr_to_free);
+ return 0;
+}
+
+/*
+ internal talloc_free call
+*/
+static inline int _talloc_free_internal(void *ptr, const char *location)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return -1;
+ }
+
+ /* possibly initialised the talloc fill value */
+ if (unlikely(!talloc_fill.initialised)) {
+ const char *fill = getenv(TALLOC_FILL_ENV);
+ if (fill != NULL) {
+ talloc_fill.enabled = true;
+ talloc_fill.fill_value = strtoul(fill, NULL, 0);
+ }
+ talloc_fill.initialised = true;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+ return _tc_free_internal(tc, location);
+}
+
+static inline size_t _talloc_total_limit_size(const void *ptr,
+ struct talloc_memlimit *old_limit,
+ struct talloc_memlimit *new_limit);
+
+/*
+ move a lump of memory from one talloc context to another returning the
+ ptr on success, or NULL if it could not be transferred.
+ passing NULL as ptr will always return NULL with no side effects.
+*/
+static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
+{
+ struct talloc_chunk *tc, *new_tc;
+ size_t ctx_size = 0;
+
+ if (unlikely(!ptr)) {
+ return NULL;
+ }
+
+ if (unlikely(new_ctx == NULL)) {
+ new_ctx = null_context;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->limit != NULL) {
+
+ ctx_size = _talloc_total_limit_size(ptr, NULL, NULL);
+
+ /* Decrement the memory limit from the source .. */
+ talloc_memlimit_shrink(tc->limit->upper, ctx_size);
+
+ if (tc->limit->parent == tc) {
+ tc->limit->upper = NULL;
+ } else {
+ tc->limit = NULL;
+ }
+ }
+
+ if (unlikely(new_ctx == NULL)) {
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->parent = tc->next = tc->prev = NULL;
+ return discard_const_p(void, ptr);
+ }
+
+ new_tc = talloc_chunk_from_ptr(new_ctx);
+
+ if (unlikely(tc == new_tc || tc->parent == new_tc)) {
+ return discard_const_p(void, ptr);
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ tc->prev = tc->next = NULL;
+ }
+
+ tc->parent = new_tc;
+ if (new_tc->child) new_tc->child->parent = NULL;
+ _TLIST_ADD(new_tc->child, tc);
+
+ if (tc->limit || new_tc->limit) {
+ ctx_size = _talloc_total_limit_size(ptr, tc->limit,
+ new_tc->limit);
+ /* .. and increment it in the destination. */
+ if (new_tc->limit) {
+ talloc_memlimit_grow(new_tc->limit, ctx_size);
+ }
+ }
+
+ return discard_const_p(void, ptr);
+}
+
+/*
+ move a lump of memory from one talloc context to another returning the
+ ptr on success, or NULL if it could not be transferred.
+ passing NULL as ptr will always return NULL with no side effects.
+*/
+_PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) {
+ struct talloc_reference_handle *h;
+
+ talloc_log("WARNING: talloc_steal with references at %s\n",
+ location);
+
+ for (h=tc->refs; h; h=h->next) {
+ talloc_log("\treference at %s\n",
+ h->location);
+ }
+ }
+
+#if 0
+ /* this test is probably too expensive to have on in the
+ normal build, but it useful for debugging */
+ if (talloc_is_parent(new_ctx, ptr)) {
+ talloc_log("WARNING: stealing into talloc child at %s\n", location);
+ }
+#endif
+
+ return _talloc_steal_internal(new_ctx, ptr);
+}
+
+/*
+ this is like a talloc_steal(), but you must supply the old
+ parent. This resolves the ambiguity in a talloc_steal() which is
+ called on a context that has more than one parent (via references)
+
+ The old parent can be either a reference or a parent
+*/
+_PUBLIC_ void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr)
+{
+ struct talloc_chunk *tc;
+ struct talloc_reference_handle *h;
+
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ if (old_parent == talloc_parent(ptr)) {
+ return _talloc_steal_internal(new_parent, ptr);
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+ for (h=tc->refs;h;h=h->next) {
+ if (talloc_parent(h) == old_parent) {
+ if (_talloc_steal_internal(new_parent, h) != h) {
+ return NULL;
+ }
+ return discard_const_p(void, ptr);
+ }
+ }
+
+ /* it wasn't a parent */
+ return NULL;
+}
+
+/*
+ remove a secondary reference to a pointer. This undo's what
+ talloc_reference() has done. The context and pointer arguments
+ must match those given to a talloc_reference()
+*/
+static inline int talloc_unreference(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ for (h=tc->refs;h;h=h->next) {
+ struct talloc_chunk *p = talloc_parent_chunk(h);
+ if (p == NULL) {
+ if (context == NULL) break;
+ } else if (TC_PTR_FROM_CHUNK(p) == context) {
+ break;
+ }
+ }
+ if (h == NULL) {
+ return -1;
+ }
+
+ return _talloc_free_internal(h, __location__);
+}
+
+/*
+ remove a specific parent context from a pointer. This is a more
+ controlled variant of talloc_free()
+*/
+
+/* coverity[ -tainted_data_sink : arg-1 ] */
+_PUBLIC_ int talloc_unlink(const void *context, void *ptr)
+{
+ struct talloc_chunk *tc_p, *new_p, *tc_c;
+ void *new_parent;
+
+ if (ptr == NULL) {
+ return -1;
+ }
+
+ if (context == NULL) {
+ context = null_context;
+ }
+
+ if (talloc_unreference(context, ptr) == 0) {
+ return 0;
+ }
+
+ if (context != NULL) {
+ tc_c = talloc_chunk_from_ptr(context);
+ } else {
+ tc_c = NULL;
+ }
+ if (tc_c != talloc_parent_chunk(ptr)) {
+ return -1;
+ }
+
+ tc_p = talloc_chunk_from_ptr(ptr);
+
+ if (tc_p->refs == NULL) {
+ return _talloc_free_internal(ptr, __location__);
+ }
+
+ new_p = talloc_parent_chunk(tc_p->refs);
+ if (new_p) {
+ new_parent = TC_PTR_FROM_CHUNK(new_p);
+ } else {
+ new_parent = NULL;
+ }
+
+ if (talloc_unreference(new_parent, ptr) != 0) {
+ return -1;
+ }
+
+ _talloc_steal_internal(new_parent, ptr);
+
+ return 0;
+}
+
+/*
+ add a name to an existing pointer - va_list version
+*/
+static inline const char *tc_set_name_v(struct talloc_chunk *tc,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+static inline const char *tc_set_name_v(struct talloc_chunk *tc,
+ const char *fmt,
+ va_list ap)
+{
+ struct talloc_chunk *name_tc = _vasprintf_tc(TC_PTR_FROM_CHUNK(tc),
+ fmt,
+ ap);
+ if (likely(name_tc)) {
+ tc->name = TC_PTR_FROM_CHUNK(name_tc);
+ _tc_set_name_const(name_tc, ".name");
+ } else {
+ tc->name = NULL;
+ }
+ return tc->name;
+}
+
+/*
+ add a name to an existing pointer
+*/
+_PUBLIC_ const char *talloc_set_name(const void *ptr, const char *fmt, ...)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ const char *name;
+ va_list ap;
+ va_start(ap, fmt);
+ name = tc_set_name_v(tc, fmt, ap);
+ va_end(ap);
+ return name;
+}
+
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+_PUBLIC_ void *talloc_named(const void *context, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+ struct talloc_chunk *tc = NULL;
+
+ ptr = __talloc(context, size, &tc);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = tc_set_name_v(tc, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free_internal(ptr, __location__);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+/*
+ return the name of a talloc ptr, or "UNNAMED"
+*/
+static inline const char *__talloc_get_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
+ return ".reference";
+ }
+ if (likely(tc->name)) {
+ return tc->name;
+ }
+ return "UNNAMED";
+}
+
+_PUBLIC_ const char *talloc_get_name(const void *ptr)
+{
+ return __talloc_get_name(ptr);
+}
+
+/*
+ check if a pointer has the given name. If it does, return the pointer,
+ otherwise return NULL
+*/
+_PUBLIC_ void *talloc_check_name(const void *ptr, const char *name)
+{
+ const char *pname;
+ if (unlikely(ptr == NULL)) return NULL;
+ pname = __talloc_get_name(ptr);
+ if (likely(pname == name || strcmp(pname, name) == 0)) {
+ return discard_const_p(void, ptr);
+ }
+ return NULL;
+}
+
+static void talloc_abort_type_mismatch(const char *location,
+ const char *name,
+ const char *expected)
+{
+ const char *reason;
+
+ reason = talloc_asprintf(NULL,
+ "%s: Type mismatch: name[%s] expected[%s]",
+ location,
+ name?name:"NULL",
+ expected);
+ if (!reason) {
+ reason = "Type mismatch";
+ }
+
+ talloc_abort(reason);
+}
+
+_PUBLIC_ void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
+{
+ const char *pname;
+
+ if (unlikely(ptr == NULL)) {
+ talloc_abort_type_mismatch(location, NULL, name);
+ return NULL;
+ }
+
+ pname = __talloc_get_name(ptr);
+ if (likely(pname == name || strcmp(pname, name) == 0)) {
+ return discard_const_p(void, ptr);
+ }
+
+ talloc_abort_type_mismatch(location, pname, name);
+ return NULL;
+}
+
+/*
+ this is for compatibility with older versions of talloc
+*/
+_PUBLIC_ void *talloc_init(const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+ struct talloc_chunk *tc = NULL;
+
+ ptr = __talloc(NULL, 0, &tc);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = tc_set_name_v(tc, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free_internal(ptr, __location__);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+static inline void _tc_free_children_internal(struct talloc_chunk *tc,
+ void *ptr,
+ const char *location)
+{
+ while (tc->child) {
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
+ const void *new_parent = null_context;
+ if (unlikely(tc->child->refs)) {
+ struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ if (unlikely(_tc_free_internal(tc->child, location) == -1)) {
+ if (talloc_parent_chunk(child) != tc) {
+ /*
+ * Destructor already reparented this child.
+ * No further reparenting needed.
+ */
+ continue;
+ }
+ if (new_parent == null_context) {
+ struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ _talloc_steal_internal(new_parent, child);
+ }
+ }
+}
+
+/*
+ this is a replacement for the Samba3 talloc_destroy_pool functionality. It
+ should probably not be used in new code. It's in here to keep the talloc
+ code consistent across Samba 3 and 4.
+*/
+_PUBLIC_ void talloc_free_children(void *ptr)
+{
+ struct talloc_chunk *tc_name = NULL;
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ /* we do not want to free the context name if it is a child .. */
+ if (likely(tc->child)) {
+ for (tc_name = tc->child; tc_name; tc_name = tc_name->next) {
+ if (tc->name == TC_PTR_FROM_CHUNK(tc_name)) break;
+ }
+ if (tc_name) {
+ _TLIST_REMOVE(tc->child, tc_name);
+ if (tc->child) {
+ tc->child->parent = tc;
+ }
+ }
+ }
+
+ _tc_free_children_internal(tc, ptr, __location__);
+
+ /* .. so we put it back after all other children have been freed */
+ if (tc_name) {
+ if (tc->child) {
+ tc->child->parent = NULL;
+ }
+ tc_name->parent = tc;
+ _TLIST_ADD(tc->child, tc_name);
+ }
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+_PUBLIC_ void *_talloc(const void *context, size_t size)
+{
+ struct talloc_chunk *tc;
+ return __talloc(context, size, &tc);
+}
+
+/*
+ externally callable talloc_set_name_const()
+*/
+_PUBLIC_ void talloc_set_name_const(const void *ptr, const char *name)
+{
+ _tc_set_name_const(talloc_chunk_from_ptr(ptr), name);
+}
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+_PUBLIC_ void *talloc_named_const(const void *context, size_t size, const char *name)
+{
+ return _talloc_named_const(context, size, name);
+}
+
+/*
+ free a talloc pointer. This also frees all child pointers of this
+ pointer recursively
+
+ return 0 if the memory is actually freed, otherwise -1. The memory
+ will not be freed if the ref_count is > 1 or the destructor (if
+ any) returns non-zero
+*/
+_PUBLIC_ int _talloc_free(void *ptr, const char *location)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return -1;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(tc->refs != NULL)) {
+ struct talloc_reference_handle *h;
+
+ if (talloc_parent(ptr) == null_context && tc->refs->next == NULL) {
+ /* in this case we do know which parent should
+ get this pointer, as there is really only
+ one parent */
+ return talloc_unlink(null_context, ptr);
+ }
+
+ talloc_log("ERROR: talloc_free with references at %s\n",
+ location);
+
+ for (h=tc->refs; h; h=h->next) {
+ talloc_log("\treference at %s\n",
+ h->location);
+ }
+ return -1;
+ }
+
+ return _talloc_free_internal(ptr, location);
+}
+
+
+
+/*
+ A talloc version of realloc. The context argument is only used if
+ ptr is NULL
+*/
+_PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
+{
+ struct talloc_chunk *tc;
+ void *new_ptr;
+ bool malloced = false;
+ struct talloc_pool_hdr *pool_hdr = NULL;
+ size_t old_size = 0;
+ size_t new_size = 0;
+
+ /* size zero is equivalent to free() */
+ if (unlikely(size == 0)) {
+ talloc_unlink(context, ptr);
+ return NULL;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ /* realloc(NULL) is equivalent to malloc() */
+ if (ptr == NULL) {
+ return _talloc_named_const(context, size, name);
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ /* don't allow realloc on referenced pointers */
+ if (unlikely(tc->refs)) {
+ return NULL;
+ }
+
+ /* don't let anybody try to realloc a talloc_pool */
+ if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
+ return NULL;
+ }
+
+ /* handle realloc inside a talloc_pool */
+ if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) {
+ pool_hdr = tc->pool;
+ }
+
+ /* don't shrink if we have less than 1k to gain */
+ if (size < tc->size && tc->limit == NULL) {
+ if (pool_hdr) {
+ void *next_tc = tc_next_chunk(tc);
+ TC_INVALIDATE_SHRINK_CHUNK(tc, size);
+ tc->size = size;
+ if (next_tc == pool_hdr->end) {
+ /* note: tc->size has changed, so this works */
+ pool_hdr->end = tc_next_chunk(tc);
+ }
+ return ptr;
+ } else if ((tc->size - size) < 1024) {
+ /*
+ * if we call TC_INVALIDATE_SHRINK_CHUNK() here
+ * we would need to call TC_UNDEFINE_GROW_CHUNK()
+ * after each realloc call, which slows down
+ * testing a lot :-(.
+ *
+ * That is why we only mark memory as undefined here.
+ */
+ TC_UNDEFINE_SHRINK_CHUNK(tc, size);
+
+ /* do not shrink if we have less than 1k to gain */
+ tc->size = size;
+ return ptr;
+ }
+ } else if (tc->size == size) {
+ /*
+ * do not change the pointer if it is exactly
+ * the same size.
+ */
+ return ptr;
+ }
+
+ /*
+ * by resetting magic we catch users of the old memory
+ *
+ * We mark this memory as free, and also over-stamp the talloc
+ * magic with the old-style magic.
+ *
+ * Why? This tries to avoid a memory read use-after-free from
+ * disclosing our talloc magic, which would then allow an
+ * attacker to prepare a valid header and so run a destructor.
+ *
+ * What else? We have to re-stamp back a valid normal magic
+ * on this memory once realloc() is done, as it will have done
+ * a memcpy() into the new valid memory. We can't do this in
+ * reverse as that would be a real use-after-free.
+ */
+ _talloc_chunk_set_free(tc, NULL);
+
+ if (pool_hdr) {
+ struct talloc_chunk *pool_tc;
+ void *next_tc = tc_next_chunk(tc);
+ size_t old_chunk_size = TC_ALIGN16(TC_HDR_SIZE + tc->size);
+ size_t new_chunk_size = TC_ALIGN16(TC_HDR_SIZE + size);
+ size_t space_needed;
+ size_t space_left;
+ unsigned int chunk_count = pool_hdr->object_count;
+
+ pool_tc = talloc_chunk_from_pool(pool_hdr);
+ if (!(pool_tc->flags & TALLOC_FLAG_FREE)) {
+ chunk_count -= 1;
+ }
+
+ if (chunk_count == 1) {
+ /*
+ * optimize for the case where 'tc' is the only
+ * chunk in the pool.
+ */
+ char *start = tc_pool_first_chunk(pool_hdr);
+ space_needed = new_chunk_size;
+ space_left = (char *)tc_pool_end(pool_hdr) - start;
+
+ if (space_left >= space_needed) {
+ size_t old_used = TC_HDR_SIZE + tc->size;
+ size_t new_used = TC_HDR_SIZE + size;
+ new_ptr = start;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+ {
+ /*
+ * The area from
+ * start -> tc may have
+ * been freed and thus been marked as
+ * VALGRIND_MEM_NOACCESS. Set it to
+ * VALGRIND_MEM_UNDEFINED so we can
+ * copy into it without valgrind errors.
+ * We can't just mark
+ * new_ptr -> new_ptr + old_used
+ * as this may overlap on top of tc,
+ * (which is why we use memmove, not
+ * memcpy below) hence the MIN.
+ */
+ size_t undef_len = MIN((((char *)tc) - ((char *)new_ptr)),old_used);
+ VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, undef_len);
+ }
+#endif
+
+ memmove(new_ptr, tc, old_used);
+
+ tc = (struct talloc_chunk *)new_ptr;
+ TC_UNDEFINE_GROW_CHUNK(tc, size);
+
+ /*
+ * first we do not align the pool pointer
+ * because we want to invalidate the padding
+ * too.
+ */
+ pool_hdr->end = new_used + (char *)new_ptr;
+ tc_invalidate_pool(pool_hdr);
+
+ /* now the aligned pointer */
+ pool_hdr->end = new_chunk_size + (char *)new_ptr;
+ goto got_new_ptr;
+ }
+
+ next_tc = NULL;
+ }
+
+ if (new_chunk_size == old_chunk_size) {
+ TC_UNDEFINE_GROW_CHUNK(tc, size);
+ _talloc_chunk_set_not_free(tc);
+ tc->size = size;
+ return ptr;
+ }
+
+ if (next_tc == pool_hdr->end) {
+ /*
+ * optimize for the case where 'tc' is the last
+ * chunk in the pool.
+ */
+ space_needed = new_chunk_size - old_chunk_size;
+ space_left = tc_pool_space_left(pool_hdr);
+
+ if (space_left >= space_needed) {
+ TC_UNDEFINE_GROW_CHUNK(tc, size);
+ _talloc_chunk_set_not_free(tc);
+ tc->size = size;
+ pool_hdr->end = tc_next_chunk(tc);
+ return ptr;
+ }
+ }
+
+ new_ptr = tc_alloc_pool(tc, size + TC_HDR_SIZE, 0);
+
+ if (new_ptr == NULL) {
+ /*
+ * Couldn't allocate from pool (pool size
+ * counts as already allocated for memlimit
+ * purposes). We must check memory limit
+ * before any real malloc.
+ */
+ if (tc->limit) {
+ /*
+ * Note we're doing an extra malloc,
+ * on top of the pool size, so account
+ * for size only, not the difference
+ * between old and new size.
+ */
+ if (!talloc_memlimit_check(tc->limit, size)) {
+ _talloc_chunk_set_not_free(tc);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+ new_ptr = malloc(TC_HDR_SIZE+size);
+ malloced = true;
+ new_size = size;
+ }
+
+ if (new_ptr) {
+ memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
+
+ _tc_free_poolmem(tc, __location__ "_talloc_realloc");
+ }
+ }
+ else {
+ /* We're doing realloc here, so record the difference. */
+ old_size = tc->size;
+ new_size = size;
+ /*
+ * We must check memory limit
+ * before any real realloc.
+ */
+ if (tc->limit && (size > old_size)) {
+ if (!talloc_memlimit_check(tc->limit,
+ (size - old_size))) {
+ _talloc_chunk_set_not_free(tc);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+ new_ptr = realloc(tc, size + TC_HDR_SIZE);
+ }
+got_new_ptr:
+
+ if (unlikely(!new_ptr)) {
+ /*
+ * Ok, this is a strange spot. We have to put back
+ * the old talloc_magic and any flags, except the
+ * TALLOC_FLAG_FREE as this was not free'ed by the
+ * realloc() call after all
+ */
+ _talloc_chunk_set_not_free(tc);
+ return NULL;
+ }
+
+ /*
+ * tc is now the new value from realloc(), the old memory we
+ * can't access any more and was preemptively marked as
+ * TALLOC_FLAG_FREE before the call. Now we mark it as not
+ * free again
+ */
+ tc = (struct talloc_chunk *)new_ptr;
+ _talloc_chunk_set_not_free(tc);
+ if (malloced) {
+ tc->flags &= ~TALLOC_FLAG_POOLMEM;
+ }
+ if (tc->parent) {
+ tc->parent->child = tc;
+ }
+ if (tc->child) {
+ tc->child->parent = tc;
+ }
+
+ if (tc->prev) {
+ tc->prev->next = tc;
+ }
+ if (tc->next) {
+ tc->next->prev = tc;
+ }
+
+ if (new_size > old_size) {
+ talloc_memlimit_grow(tc->limit, new_size - old_size);
+ } else if (new_size < old_size) {
+ talloc_memlimit_shrink(tc->limit, old_size - new_size);
+ }
+
+ tc->size = size;
+ _tc_set_name_const(tc, name);
+
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ a wrapper around talloc_steal() for situations where you are moving a pointer
+ between two structures, and want the old pointer to be set to NULL
+*/
+_PUBLIC_ void *_talloc_move(const void *new_ctx, const void *_pptr)
+{
+ const void **pptr = discard_const_p(const void *,_pptr);
+ void *ret = talloc_steal(new_ctx, discard_const_p(void, *pptr));
+ (*pptr) = NULL;
+ return ret;
+}
+
+enum talloc_mem_count_type {
+ TOTAL_MEM_SIZE,
+ TOTAL_MEM_BLOCKS,
+ TOTAL_MEM_LIMIT,
+};
+
+static inline size_t _talloc_total_mem_internal(const void *ptr,
+ enum talloc_mem_count_type type,
+ struct talloc_memlimit *old_limit,
+ struct talloc_memlimit *new_limit)
+{
+ size_t total = 0;
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (old_limit || new_limit) {
+ if (tc->limit && tc->limit->upper == old_limit) {
+ tc->limit->upper = new_limit;
+ }
+ }
+
+ /* optimize in the memlimits case */
+ if (type == TOTAL_MEM_LIMIT &&
+ tc->limit != NULL &&
+ tc->limit != old_limit &&
+ tc->limit->parent == tc) {
+ return tc->limit->cur_size;
+ }
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ if (old_limit || new_limit) {
+ if (old_limit == tc->limit) {
+ tc->limit = new_limit;
+ }
+ }
+
+ switch (type) {
+ case TOTAL_MEM_SIZE:
+ if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) {
+ total = tc->size;
+ }
+ break;
+ case TOTAL_MEM_BLOCKS:
+ total++;
+ break;
+ case TOTAL_MEM_LIMIT:
+ if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) {
+ /*
+ * Don't count memory allocated from a pool
+ * when calculating limits. Only count the
+ * pool itself.
+ */
+ if (!(tc->flags & TALLOC_FLAG_POOLMEM)) {
+ if (tc->flags & TALLOC_FLAG_POOL) {
+ /*
+ * If this is a pool, the allocated
+ * size is in the pool header, and
+ * remember to add in the prefix
+ * length.
+ */
+ struct talloc_pool_hdr *pool_hdr
+ = talloc_pool_from_chunk(tc);
+ total = pool_hdr->poolsize +
+ TC_HDR_SIZE +
+ TP_HDR_SIZE;
+ } else {
+ total = tc->size + TC_HDR_SIZE;
+ }
+ }
+ }
+ break;
+ }
+ for (c = tc->child; c; c = c->next) {
+ total += _talloc_total_mem_internal(TC_PTR_FROM_CHUNK(c), type,
+ old_limit, new_limit);
+ }
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
+ return total;
+}
+
+/*
+ return the total size of a talloc pool (subtree)
+*/
+_PUBLIC_ size_t talloc_total_size(const void *ptr)
+{
+ return _talloc_total_mem_internal(ptr, TOTAL_MEM_SIZE, NULL, NULL);
+}
+
+/*
+ return the total number of blocks in a talloc pool (subtree)
+*/
+_PUBLIC_ size_t talloc_total_blocks(const void *ptr)
+{
+ return _talloc_total_mem_internal(ptr, TOTAL_MEM_BLOCKS, NULL, NULL);
+}
+
+/*
+ return the number of external references to a pointer
+*/
+_PUBLIC_ size_t talloc_reference_count(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+ size_t ret = 0;
+
+ for (h=tc->refs;h;h=h->next) {
+ ret++;
+ }
+ return ret;
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+_PUBLIC_ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data)
+{
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) return;
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return;
+ }
+
+ callback(ptr, depth, max_depth, 0, private_data);
+
+ if (max_depth >= 0 && depth >= max_depth) {
+ return;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+ for (c=tc->child;c;c=c->next) {
+ if (c->name == TALLOC_MAGIC_REFERENCE) {
+ struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
+ callback(h->ptr, depth + 1, max_depth, 1, private_data);
+ } else {
+ talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
+ }
+ }
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+}
+
+static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
+{
+ const char *name = __talloc_get_name(ptr);
+ struct talloc_chunk *tc;
+ FILE *f = (FILE *)_f;
+
+ if (is_ref) {
+ fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+ if (tc->limit && tc->limit->parent == tc) {
+ fprintf(f, "%*s%-30s is a memlimit context"
+ " (max_size = %lu bytes, cur_size = %lu bytes)\n",
+ depth*4, "",
+ name,
+ (unsigned long)tc->limit->max_size,
+ (unsigned long)tc->limit->cur_size);
+ }
+
+ if (depth == 0) {
+ fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
+ (max_depth < 0 ? "full " :""), name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr));
+ return;
+ }
+
+ fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
+ depth*4, "",
+ name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr),
+ (int)talloc_reference_count(ptr), ptr);
+
+#if 0
+ fprintf(f, "content: ");
+ if (talloc_total_size(ptr)) {
+ int tot = talloc_total_size(ptr);
+ int i;
+
+ for (i = 0; i < tot; i++) {
+ if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
+ fprintf(f, "%c", ((char *)ptr)[i]);
+ } else {
+ fprintf(f, "~%02x", ((char *)ptr)[i]);
+ }
+ }
+ }
+ fprintf(f, "\n");
+#endif
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+_PUBLIC_ void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
+{
+ if (f) {
+ talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
+ fflush(f);
+ }
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+_PUBLIC_ void talloc_report_full(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, -1, f);
+}
+
+/*
+ report on memory usage by all children of a pointer
+*/
+_PUBLIC_ void talloc_report(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, 1, f);
+}
+
+/*
+ enable tracking of the NULL context
+*/
+_PUBLIC_ void talloc_enable_null_tracking(void)
+{
+ if (null_context == NULL) {
+ null_context = _talloc_named_const(NULL, 0, "null_context");
+ if (autofree_context != NULL) {
+ talloc_reparent(NULL, null_context, autofree_context);
+ }
+ }
+}
+
+/*
+ enable tracking of the NULL context, not moving the autofree context
+ into the NULL context. This is needed for the talloc testsuite
+*/
+_PUBLIC_ void talloc_enable_null_tracking_no_autofree(void)
+{
+ if (null_context == NULL) {
+ null_context = _talloc_named_const(NULL, 0, "null_context");
+ }
+}
+
+/*
+ disable tracking of the NULL context
+*/
+_PUBLIC_ void talloc_disable_null_tracking(void)
+{
+ if (null_context != NULL) {
+ /* we have to move any children onto the real NULL
+ context */
+ struct talloc_chunk *tc, *tc2;
+ tc = talloc_chunk_from_ptr(null_context);
+ for (tc2 = tc->child; tc2; tc2=tc2->next) {
+ if (tc2->parent == tc) tc2->parent = NULL;
+ if (tc2->prev == tc) tc2->prev = NULL;
+ }
+ for (tc2 = tc->next; tc2; tc2=tc2->next) {
+ if (tc2->parent == tc) tc2->parent = NULL;
+ if (tc2->prev == tc) tc2->prev = NULL;
+ }
+ tc->child = NULL;
+ tc->next = NULL;
+ }
+ talloc_free(null_context);
+ null_context = NULL;
+}
+
+/*
+ enable leak reporting on exit
+*/
+_PUBLIC_ void talloc_enable_leak_report(void)
+{
+ talloc_enable_null_tracking();
+ talloc_report_null = true;
+ talloc_setup_atexit();
+}
+
+/*
+ enable full leak reporting on exit
+*/
+_PUBLIC_ void talloc_enable_leak_report_full(void)
+{
+ talloc_enable_null_tracking();
+ talloc_report_null_full = true;
+ talloc_setup_atexit();
+}
+
+/*
+ talloc and zero memory.
+*/
+_PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name)
+{
+ void *p = _talloc_named_const(ctx, size, name);
+
+ if (p) {
+ memset(p, '\0', size);
+ }
+
+ return p;
+}
+
+/*
+ memdup with a talloc.
+*/
+_PUBLIC_ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
+{
+ void *newp = NULL;
+
+ if (likely(size > 0) && unlikely(p == NULL)) {
+ return NULL;
+ }
+
+ newp = _talloc_named_const(t, size, name);
+ if (likely(newp != NULL) && likely(size > 0)) {
+ memcpy(newp, p, size);
+ }
+
+ return newp;
+}
+
+static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
+{
+ char *ret;
+ struct talloc_chunk *tc = NULL;
+
+ ret = (char *)__talloc(t, len + 1, &tc);
+ if (unlikely(!ret)) return NULL;
+
+ memcpy(ret, p, len);
+ ret[len] = 0;
+
+ _tc_set_name_const(tc, ret);
+ return ret;
+}
+
+/*
+ strdup with a talloc
+*/
+_PUBLIC_ char *talloc_strdup(const void *t, const char *p)
+{
+ if (unlikely(!p)) return NULL;
+ return __talloc_strlendup(t, p, strlen(p));
+}
+
+/*
+ strndup with a talloc
+*/
+_PUBLIC_ char *talloc_strndup(const void *t, const char *p, size_t n)
+{
+ if (unlikely(!p)) return NULL;
+ return __talloc_strlendup(t, p, strnlen(p, n));
+}
+
+static inline char *__talloc_strlendup_append(char *s, size_t slen,
+ const char *a, size_t alen)
+{
+ char *ret;
+
+ ret = talloc_realloc(NULL, s, char, slen + alen + 1);
+ if (unlikely(!ret)) return NULL;
+
+ /* append the string and the trailing \0 */
+ memcpy(&ret[slen], a, alen);
+ ret[slen+alen] = 0;
+
+ _tc_set_name_const(talloc_chunk_from_ptr(ret), ret);
+ return ret;
+}
+
+/*
+ * Appends at the end of the string.
+ */
+_PUBLIC_ char *talloc_strdup_append(char *s, const char *a)
+{
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+_PUBLIC_ char *talloc_strdup_append_buffer(char *s, const char *a)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_strlendup_append(s, slen, a, strlen(a));
+}
+
+/*
+ * Appends at the end of the string.
+ */
+_PUBLIC_ char *talloc_strndup_append(char *s, const char *a, size_t n)
+{
+ if (unlikely(!s)) {
+ return talloc_strndup(NULL, a, n);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+_PUBLIC_ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_strndup(NULL, a, n);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
+}
+
+#ifndef HAVE_VA_COPY
+#ifdef HAVE___VA_COPY
+#define va_copy(dest, src) __va_copy(dest, src)
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+static struct talloc_chunk *_vasprintf_tc(const void *t,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+static struct talloc_chunk *_vasprintf_tc(const void *t,
+ const char *fmt,
+ va_list ap)
+{
+ int vlen;
+ size_t len;
+ char *ret;
+ va_list ap2;
+ struct talloc_chunk *tc = NULL;
+ char buf[1024];
+
+ va_copy(ap2, ap);
+ vlen = vsnprintf(buf, sizeof(buf), fmt, ap2);
+ va_end(ap2);
+ if (unlikely(vlen < 0)) {
+ return NULL;
+ }
+ len = vlen;
+ if (unlikely(len + 1 < len)) {
+ return NULL;
+ }
+
+ ret = (char *)__talloc(t, len+1, &tc);
+ if (unlikely(!ret)) return NULL;
+
+ if (len < sizeof(buf)) {
+ memcpy(ret, buf, len+1);
+ } else {
+ va_copy(ap2, ap);
+ vsnprintf(ret, len+1, fmt, ap2);
+ va_end(ap2);
+ }
+
+ _tc_set_name_const(tc, ret);
+ return tc;
+}
+
+_PUBLIC_ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
+{
+ struct talloc_chunk *tc = _vasprintf_tc(t, fmt, ap);
+ if (tc == NULL) {
+ return NULL;
+ }
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+
+/*
+ Perform string formatting, and return a pointer to newly allocated
+ memory holding the result, inside a memory pool.
+ */
+_PUBLIC_ char *talloc_asprintf(const void *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+ const char *fmt, va_list ap)
+ PRINTF_ATTRIBUTE(3,0);
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+ const char *fmt, va_list ap)
+{
+ ssize_t alen;
+ va_list ap2;
+ char c;
+
+ va_copy(ap2, ap);
+ /* this call looks strange, but it makes it work on older solaris boxes */
+ alen = vsnprintf(&c, 1, fmt, ap2);
+ va_end(ap2);
+
+ if (alen <= 0) {
+ /* Either the vsnprintf failed or the format resulted in
+ * no characters being formatted. In the former case, we
+ * ought to return NULL, in the latter we ought to return
+ * the original string. Most current callers of this
+ * function expect it to never return NULL.
+ */
+ return s;
+ }
+
+ s = talloc_realloc(NULL, s, char, slen + alen + 1);
+ if (!s) return NULL;
+
+ vsnprintf(s + slen, alen + 1, fmt, ap);
+
+ _tc_set_name_const(talloc_chunk_from_ptr(s), s);
+ return s;
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Good for gradually
+ * accumulating output into a string buffer. Appends at the end
+ * of the string.
+ **/
+_PUBLIC_ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+ if (unlikely(!s)) {
+ return talloc_vasprintf(NULL, fmt, ap);
+ }
+
+ return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Always appends at the
+ * end of the talloc'ed buffer, not the end of the string.
+ **/
+_PUBLIC_ char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_vasprintf(NULL, fmt, ap);
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_vaslenprintf_append(s, slen, fmt, ap);
+}
+
+/*
+ Realloc @p s to append the formatted result of @p fmt and return @p
+ s, which may have moved. Good for gradually accumulating output
+ into a string buffer.
+ */
+_PUBLIC_ char *talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append(s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+/*
+ Realloc @p s to append the formatted result of @p fmt and return @p
+ s, which may have moved. Good for gradually accumulating output
+ into a buffer.
+ */
+_PUBLIC_ char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append_buffer(s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+_PUBLIC_ void talloc_asprintf_addbuf(char **ps, const char *fmt, ...)
+{
+ va_list ap;
+ char *s = *ps;
+ char *t = NULL;
+
+ if (s == NULL) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ t = talloc_vasprintf_append_buffer(s, fmt, ap);
+ va_end(ap);
+
+ if (t == NULL) {
+ /* signal failure to the next caller */
+ TALLOC_FREE(s);
+ *ps = NULL;
+ } else {
+ *ps = t;
+ }
+}
+
+/*
+ alloc an array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+ alloc an zero array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_zero(ctx, el_size * count, name);
+}
+
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_realloc(ctx, ptr, el_size * count, name);
+}
+
+/*
+ a function version of talloc_realloc(), so it can be passed as a function pointer
+ to libraries that want a realloc function (a realloc function encapsulates
+ all the basic capabilities of an allocation library, which is why this is useful)
+*/
+_PUBLIC_ void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
+{
+ return _talloc_realloc(context, ptr, size, NULL);
+}
+
+
+static int talloc_autofree_destructor(void *ptr)
+{
+ autofree_context = NULL;
+ return 0;
+}
+
+/*
+ return a context which will be auto-freed on exit
+ this is useful for reducing the noise in leak reports
+*/
+_PUBLIC_ void *talloc_autofree_context(void)
+{
+ if (autofree_context == NULL) {
+ autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
+ talloc_set_destructor(autofree_context, talloc_autofree_destructor);
+ talloc_setup_atexit();
+ }
+ return autofree_context;
+}
+
+_PUBLIC_ size_t talloc_get_size(const void *context)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+
+ return tc->size;
+}
+
+/*
+ find a parent of this context that has the given name, if any
+*/
+_PUBLIC_ void *talloc_find_parent_byname(const void *context, const char *name)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (tc->name && strcmp(tc->name, name) == 0) {
+ return TC_PTR_FROM_CHUNK(tc);
+ }
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ return NULL;
+}
+
+/*
+ show the parentage of a context
+*/
+_PUBLIC_ void talloc_show_parents(const void *context, FILE *file)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ fprintf(file, "talloc no parents for NULL\n");
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ fprintf(file, "talloc parents of '%s'\n", __talloc_get_name(context));
+ while (tc) {
+ fprintf(file, "\t'%s'\n", __talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ fflush(file);
+}
+
+/*
+ return 1 if ptr is a parent of context
+*/
+static int _talloc_is_parent(const void *context, const void *ptr, int depth)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (depth <= 0) {
+ return 0;
+ }
+ if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ depth--;
+ }
+ }
+ return 0;
+}
+
+/*
+ return 1 if ptr is a parent of context
+*/
+_PUBLIC_ int talloc_is_parent(const void *context, const void *ptr)
+{
+ return _talloc_is_parent(context, ptr, TALLOC_MAX_DEPTH);
+}
+
+/*
+ return the total size of memory used by this context and all children
+*/
+static inline size_t _talloc_total_limit_size(const void *ptr,
+ struct talloc_memlimit *old_limit,
+ struct talloc_memlimit *new_limit)
+{
+ return _talloc_total_mem_internal(ptr, TOTAL_MEM_LIMIT,
+ old_limit, new_limit);
+}
+
+static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size)
+{
+ struct talloc_memlimit *l;
+
+ for (l = limit; l != NULL; l = l->upper) {
+ if (l->max_size != 0 &&
+ ((l->max_size <= l->cur_size) ||
+ (l->max_size - l->cur_size < size))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*
+ Update memory limits when freeing a talloc_chunk.
+*/
+static void tc_memlimit_update_on_free(struct talloc_chunk *tc)
+{
+ size_t limit_shrink_size;
+
+ if (!tc->limit) {
+ return;
+ }
+
+ /*
+ * Pool entries don't count. Only the pools
+ * themselves are counted as part of the memory
+ * limits. Note that this also takes care of
+ * nested pools which have both flags
+ * TALLOC_FLAG_POOLMEM|TALLOC_FLAG_POOL set.
+ */
+ if (tc->flags & TALLOC_FLAG_POOLMEM) {
+ return;
+ }
+
+ /*
+ * If we are part of a memory limited context hierarchy
+ * we need to subtract the memory used from the counters
+ */
+
+ limit_shrink_size = tc->size+TC_HDR_SIZE;
+
+ /*
+ * If we're deallocating a pool, take into
+ * account the prefix size added for the pool.
+ */
+
+ if (tc->flags & TALLOC_FLAG_POOL) {
+ limit_shrink_size += TP_HDR_SIZE;
+ }
+
+ talloc_memlimit_shrink(tc->limit, limit_shrink_size);
+
+ if (tc->limit->parent == tc) {
+ free(tc->limit);
+ }
+
+ tc->limit = NULL;
+}
+
+/*
+ Increase memory limit accounting after a malloc/realloc.
+*/
+static void talloc_memlimit_grow(struct talloc_memlimit *limit,
+ size_t size)
+{
+ struct talloc_memlimit *l;
+
+ for (l = limit; l != NULL; l = l->upper) {
+ size_t new_cur_size = l->cur_size + size;
+ if (new_cur_size < l->cur_size) {
+ talloc_abort("logic error in talloc_memlimit_grow\n");
+ return;
+ }
+ l->cur_size = new_cur_size;
+ }
+}
+
+/*
+ Decrease memory limit accounting after a free/realloc.
+*/
+static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+ size_t size)
+{
+ struct talloc_memlimit *l;
+
+ for (l = limit; l != NULL; l = l->upper) {
+ if (l->cur_size < size) {
+ talloc_abort("logic error in talloc_memlimit_shrink\n");
+ return;
+ }
+ l->cur_size = l->cur_size - size;
+ }
+}
+
+_PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ctx);
+ struct talloc_memlimit *orig_limit;
+ struct talloc_memlimit *limit = NULL;
+
+ if (tc->limit && tc->limit->parent == tc) {
+ tc->limit->max_size = max_size;
+ return 0;
+ }
+ orig_limit = tc->limit;
+
+ limit = malloc(sizeof(struct talloc_memlimit));
+ if (limit == NULL) {
+ return 1;
+ }
+ limit->parent = tc;
+ limit->max_size = max_size;
+ limit->cur_size = _talloc_total_limit_size(ctx, tc->limit, limit);
+
+ if (orig_limit) {
+ limit->upper = orig_limit;
+ } else {
+ limit->upper = NULL;
+ }
+
+ return 0;
+}
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
new file mode 100644
index 0000000..eef1a70
--- /dev/null
+++ b/lib/talloc/talloc.h
@@ -0,0 +1,1972 @@
+#ifndef _TALLOC_H_
+#define _TALLOC_H_
+/*
+ Unix SMB/CIFS implementation.
+ Samba temporary memory allocation functions
+
+ Copyright (C) Andrew Tridgell 2004-2005
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* for old gcc releases that don't have the feature test macro __has_attribute */
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef _PUBLIC_
+#if __has_attribute(visibility)
+#define _PUBLIC_ __attribute__((visibility("default")))
+#else
+#define _PUBLIC_
+#endif
+#endif
+
+/**
+ * @defgroup talloc The talloc API
+ *
+ * talloc is a hierarchical, reference counted memory pool system with
+ * destructors. It is the core memory allocator used in Samba.
+ *
+ * @{
+ */
+
+#define TALLOC_VERSION_MAJOR 2
+#define TALLOC_VERSION_MINOR 4
+
+_PUBLIC_ int talloc_version_major(void);
+_PUBLIC_ int talloc_version_minor(void);
+/* This is mostly useful only for testing */
+_PUBLIC_ int talloc_test_get_magic(void);
+
+/**
+ * @brief Define a talloc parent type
+ *
+ * As talloc is a hierarchial memory allocator, every talloc chunk is a
+ * potential parent to other talloc chunks. So defining a separate type for a
+ * talloc chunk is not strictly necessary. TALLOC_CTX is defined nevertheless,
+ * as it provides an indicator for function arguments. You will frequently
+ * write code like
+ *
+ * @code
+ * struct foo *foo_create(TALLOC_CTX *mem_ctx)
+ * {
+ * struct foo *result;
+ * result = talloc(mem_ctx, struct foo);
+ * if (result == NULL) return NULL;
+ * ... initialize foo ...
+ * return result;
+ * }
+ * @endcode
+ *
+ * In this type of allocating functions it is handy to have a general
+ * TALLOC_CTX type to indicate which parent to put allocated structures on.
+ */
+typedef void TALLOC_CTX;
+
+/*
+ this uses a little trick to allow __LINE__ to be stringified
+*/
+#ifndef __location__
+#define __TALLOC_STRING_LINE1__(s) #s
+#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
+#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
+#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
+#endif
+
+#ifndef TALLOC_DEPRECATED
+#define TALLOC_DEPRECATED 0
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if __has_attribute(format) || (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+#ifndef _DEPRECATED_
+#if __has_attribute(deprecated) || (__GNUC__ >= 3)
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+#ifdef DOXYGEN
+
+/**
+ * @brief Create a new talloc context.
+ *
+ * The talloc() macro is the core of the talloc library. It takes a memory
+ * context and a type, and returns a pointer to a new area of memory of the
+ * given type.
+ *
+ * The returned pointer is itself a talloc context, so you can use it as the
+ * context argument to more calls to talloc if you wish.
+ *
+ * The returned pointer is a "child" of the supplied context. This means that if
+ * you talloc_free() the context then the new child disappears as well.
+ * Alternatively you can free just the child.
+ *
+ * @param[in] ctx A talloc context to create a new reference on or NULL to
+ * create a new top level context.
+ *
+ * @param[in] type The type of memory to allocate.
+ *
+ * @return A type casted talloc context or NULL on error.
+ *
+ * @code
+ * unsigned int *a, *b;
+ *
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ * @endcode
+ *
+ * @see talloc_zero
+ * @see talloc_array
+ * @see talloc_steal
+ * @see talloc_free
+ */
+_PUBLIC_ void *talloc(const void *ctx, #type);
+#else
+#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+_PUBLIC_ void *_talloc(const void *context, size_t size);
+#endif
+
+/**
+ * @brief Create a new top level talloc context.
+ *
+ * This function creates a zero length named talloc context as a top level
+ * context. It is equivalent to:
+ *
+ * @code
+ * talloc_named(NULL, 0, fmt, ...);
+ * @endcode
+ * @param[in] fmt Format string for the name.
+ *
+ * @param[in] ... Additional printf-style arguments.
+ *
+ * @return The allocated memory chunk, NULL on error.
+ *
+ * @see talloc_named()
+ */
+_PUBLIC_ void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+
+#ifdef DOXYGEN
+/**
+ * @brief Free a chunk of talloc memory.
+ *
+ * The talloc_free() function frees a piece of talloc memory, and all its
+ * children. You can call talloc_free() on any pointer returned by
+ * talloc().
+ *
+ * The return value of talloc_free() indicates success or failure, with 0
+ * returned for success and -1 for failure. A possible failure condition
+ * is if the pointer had a destructor attached to it and the destructor
+ * returned -1. See talloc_set_destructor() for details on
+ * destructors. Likewise, if "ptr" is NULL, then the function will make
+ * no modifications and return -1.
+ *
+ * From version 2.0 and onwards, as a special case, talloc_free() is
+ * refused on pointers that have more than one parent associated, as talloc
+ * would have no way of knowing which parent should be removed. This is
+ * different from older versions in the sense that always the reference to
+ * the most recently established parent has been destroyed. Hence to free a
+ * pointer that has more than one parent please use talloc_unlink().
+ *
+ * To help you find problems in your code caused by this behaviour, if
+ * you do try and free a pointer with more than one parent then the
+ * talloc logging function will be called to give output like this:
+ *
+ * @code
+ * ERROR: talloc_free with references at some_dir/source/foo.c:123
+ * reference at some_dir/source/other.c:325
+ * reference at some_dir/source/third.c:121
+ * @endcode
+ *
+ * Please see the documentation for talloc_set_log_fn() and
+ * talloc_set_log_stderr() for more information on talloc logging
+ * functions.
+ *
+ * If <code>TALLOC_FREE_FILL</code> environment variable is set,
+ * the memory occupied by the context is filled with the value of this variable.
+ * The value should be a numeric representation of the character you want to
+ * use.
+ *
+ * talloc_free() operates recursively on its children.
+ *
+ * @param[in] ptr The chunk to be freed.
+ *
+ * @return Returns 0 on success and -1 on error. A possible
+ * failure condition is if the pointer had a destructor
+ * attached to it and the destructor returned -1. Likewise,
+ * if "ptr" is NULL, then the function will make no
+ * modifications and returns -1.
+ *
+ * Example:
+ * @code
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ *
+ * talloc_free(a); // Frees a and b
+ * @endcode
+ *
+ * @see talloc_set_destructor()
+ * @see talloc_unlink()
+ */
+_PUBLIC_ int talloc_free(void *ptr);
+#else
+#define talloc_free(ctx) _talloc_free(ctx, __location__)
+_PUBLIC_ int _talloc_free(void *ptr, const char *location);
+#endif
+
+/**
+ * @brief Free a talloc chunk's children.
+ *
+ * The function walks along the list of all children of a talloc context and
+ * talloc_free()s only the children, not the context itself.
+ *
+ * A NULL argument is handled as no-op.
+ *
+ * @param[in] ptr The chunk that you want to free the children of
+ * (NULL is allowed too)
+ */
+_PUBLIC_ void talloc_free_children(void *ptr);
+
+#ifdef DOXYGEN
+/**
+ * @brief Assign a destructor function to be called when a chunk is freed.
+ *
+ * The function talloc_set_destructor() sets the "destructor" for the pointer
+ * "ptr". A destructor is a function that is called when the memory used by a
+ * pointer is about to be released. The destructor receives the pointer as an
+ * argument, and should return 0 for success and -1 for failure.
+ *
+ * The destructor can do anything it wants to, including freeing other pieces
+ * of memory. A common use for destructors is to clean up operating system
+ * resources (such as open file descriptors) contained in the structure the
+ * destructor is placed on.
+ *
+ * You can only place one destructor on a pointer. If you need more than one
+ * destructor then you can create a zero-length child of the pointer and place
+ * an additional destructor on that.
+ *
+ * To remove a destructor call talloc_set_destructor() with NULL for the
+ * destructor.
+ *
+ * If your destructor attempts to talloc_free() the pointer that it is the
+ * destructor for then talloc_free() will return -1 and the free will be
+ * ignored. This would be a pointless operation anyway, as the destructor is
+ * only called when the memory is just about to go away.
+ *
+ * @param[in] ptr The talloc chunk to add a destructor to.
+ *
+ * @param[in] destructor The destructor function to be called. NULL to remove
+ * it.
+ *
+ * Example:
+ * @code
+ * static int destroy_fd(int *fd) {
+ * close(*fd);
+ * return 0;
+ * }
+ *
+ * int *open_file(const char *filename) {
+ * int *fd = talloc(NULL, int);
+ * *fd = open(filename, O_RDONLY);
+ * if (*fd < 0) {
+ * talloc_free(fd);
+ * return NULL;
+ * }
+ * // Whenever they free this, we close the file.
+ * talloc_set_destructor(fd, destroy_fd);
+ * return fd;
+ * }
+ * @endcode
+ *
+ * @see talloc()
+ * @see talloc_free()
+ */
+_PUBLIC_ void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+
+/**
+ * @brief Change a talloc chunk's parent.
+ *
+ * The talloc_steal() function changes the parent context of a talloc
+ * pointer. It is typically used when the context that the pointer is
+ * currently a child of is going to be freed and you wish to keep the
+ * memory for a longer time.
+ *
+ * To make the changed hierarchy less error-prone, you might consider to use
+ * talloc_move().
+ *
+ * If you try and call talloc_steal() on a pointer that has more than one
+ * parent then the result is ambiguous. Talloc will choose to remove the
+ * parent that is currently indicated by talloc_parent() and replace it with
+ * the chosen parent. You will also get a message like this via the talloc
+ * logging functions:
+ *
+ * @code
+ * WARNING: talloc_steal with references at some_dir/source/foo.c:123
+ * reference at some_dir/source/other.c:325
+ * reference at some_dir/source/third.c:121
+ * @endcode
+ *
+ * To unambiguously change the parent of a pointer please see the function
+ * talloc_reparent(). See the talloc_set_log_fn() documentation for more
+ * information on talloc logging.
+ *
+ * @param[in] new_ctx The new parent context.
+ *
+ * @param[in] ptr The talloc chunk to move.
+ *
+ * @return Returns the pointer that you pass it. It does not have
+ * any failure modes.
+ *
+ * @note It is possible to produce loops in the parent/child relationship
+ * if you are not careful with talloc_steal(). No guarantees are provided
+ * as to your sanity or the safety of your data if you do this.
+ */
+_PUBLIC_ void *talloc_steal(const void *new_ctx, const void *ptr);
+#else /* DOXYGEN */
+/* try to make talloc_set_destructor() and talloc_steal() type safe,
+ if we have a recent gcc */
+#if (__GNUC__ >= 3)
+#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
+#define talloc_set_destructor(ptr, function) \
+ do { \
+ int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \
+ _talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
+ } while(0)
+/* this extremely strange macro is to avoid some braindamaged warning
+ stupidity in gcc 4.1.x */
+#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__); __talloc_steal_ret; })
+#else /* __GNUC__ >= 3 */
+#define talloc_set_destructor(ptr, function) \
+ _talloc_set_destructor((ptr), (int (*)(void *))(function))
+#define _TALLOC_TYPEOF(ptr) void *
+#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__)
+#endif /* __GNUC__ >= 3 */
+_PUBLIC_ void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *));
+_PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location);
+#endif /* DOXYGEN */
+
+/**
+ * @brief Assign a name to a talloc chunk.
+ *
+ * Each talloc pointer has a "name". The name is used principally for
+ * debugging purposes, although it is also possible to set and get the name on
+ * a pointer in as a way of "marking" pointers in your code.
+ *
+ * The main use for names on pointer is for "talloc reports". See
+ * talloc_report() and talloc_report_full() for details. Also see
+ * talloc_enable_leak_report() and talloc_enable_leak_report_full().
+ *
+ * The talloc_set_name() function allocates memory as a child of the
+ * pointer. It is logically equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
+ * @endcode
+ *
+ * @param[in] ptr The talloc chunk to assign a name to.
+ *
+ * @param[in] fmt Format string for the name.
+ *
+ * @param[in] ... Add printf-style additional arguments.
+ *
+ * @return The assigned name, NULL on error.
+ *
+ * @note Multiple calls to talloc_set_name() will allocate more memory without
+ * releasing the name. All of the memory is released when the ptr is freed
+ * using talloc_free().
+ */
+_PUBLIC_ const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+#ifdef DOXYGEN
+/**
+ * @brief Change a talloc chunk's parent.
+ *
+ * This function has the same effect as talloc_steal(), and additionally sets
+ * the source pointer to NULL. You would use it like this:
+ *
+ * @code
+ * struct foo *X = talloc(tmp_ctx, struct foo);
+ * struct foo *Y;
+ * Y = talloc_move(new_ctx, &X);
+ * @endcode
+ *
+ * @param[in] new_ctx The new parent context.
+ *
+ * @param[in] pptr Pointer to a pointer to the talloc chunk to move.
+ *
+ * @return The pointer to the talloc chunk that moved.
+ * It does not have any failure modes.
+ *
+ */
+_PUBLIC_ void *talloc_move(const void *new_ctx, void **pptr);
+#else
+#define talloc_move(ctx, pptr) (_TALLOC_TYPEOF(*(pptr)))_talloc_move((ctx),(void *)(pptr))
+_PUBLIC_ void *_talloc_move(const void *new_ctx, const void *pptr);
+#endif
+
+/**
+ * @brief Assign a name to a talloc chunk.
+ *
+ * The function is just like talloc_set_name(), but it takes a string constant,
+ * and is much faster. It is extensively used by the "auto naming" macros, such
+ * as talloc_p().
+ *
+ * This function does not allocate any memory. It just copies the supplied
+ * pointer into the internal representation of the talloc ptr. This means you
+ * must not pass a name pointer to memory that will disappear before the ptr
+ * is freed with talloc_free().
+ *
+ * @param[in] ptr The talloc chunk to assign a name to.
+ *
+ * @param[in] name Format string for the name.
+ */
+_PUBLIC_ void talloc_set_name_const(const void *ptr, const char *name);
+
+/**
+ * @brief Create a named talloc chunk.
+ *
+ * The talloc_named() function creates a named talloc pointer. It is
+ * equivalent to:
+ *
+ * @code
+ * ptr = talloc_size(context, size);
+ * talloc_set_name(ptr, fmt, ....);
+ * @endcode
+ *
+ * @param[in] context The talloc context to hang the result off.
+ *
+ * @param[in] size Number of char's that you want to allocate.
+ *
+ * @param[in] fmt Format string for the name.
+ *
+ * @param[in] ... Additional printf-style arguments.
+ *
+ * @return The allocated memory chunk, NULL on error.
+ *
+ * @see talloc_set_name()
+ */
+_PUBLIC_ void *talloc_named(const void *context, size_t size,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+/**
+ * @brief Basic routine to allocate a chunk of memory.
+ *
+ * This is equivalent to:
+ *
+ * @code
+ * ptr = talloc_size(context, size);
+ * talloc_set_name_const(ptr, name);
+ * @endcode
+ *
+ * @param[in] context The parent context.
+ *
+ * @param[in] size The number of char's that we want to allocate.
+ *
+ * @param[in] name The name the talloc block has.
+ *
+ * @return The allocated memory chunk, NULL on error.
+ */
+_PUBLIC_ void *talloc_named_const(const void *context, size_t size, const char *name);
+
+#ifdef DOXYGEN
+/**
+ * @brief Untyped allocation.
+ *
+ * The function should be used when you don't have a convenient type to pass to
+ * talloc(). Unlike talloc(), it is not type safe (as it returns a void *), so
+ * you are on your own for type checking.
+ *
+ * Best to use talloc() or talloc_array() instead.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] size Number of char's that you want to allocate.
+ *
+ * @return The allocated memory chunk, NULL on error.
+ *
+ * Example:
+ * @code
+ * void *mem = talloc_size(NULL, 100);
+ * @endcode
+ */
+_PUBLIC_ void *talloc_size(const void *ctx, size_t size);
+#else
+#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate into a typed pointer.
+ *
+ * The talloc_ptrtype() macro should be used when you have a pointer and want
+ * to allocate memory to point at with this pointer. When compiling with
+ * gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() and
+ * talloc_get_name() will return the current location in the source file and
+ * not the type.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] type The pointer you want to assign the result to.
+ *
+ * @return The properly casted allocated memory chunk, NULL on
+ * error.
+ *
+ * Example:
+ * @code
+ * unsigned int *a = talloc_ptrtype(NULL, a);
+ * @endcode
+ */
+_PUBLIC_ void *talloc_ptrtype(const void *ctx, #type);
+#else
+#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a new 0-sized talloc chunk.
+ *
+ * This is a utility macro that creates a new memory context hanging off an
+ * existing context, automatically naming it "talloc_new: __location__" where
+ * __location__ is the source line it is called from. It is particularly
+ * useful for creating a new temporary working context.
+ *
+ * @param[in] ctx The talloc parent context.
+ *
+ * @return A new talloc chunk, NULL on error.
+ */
+_PUBLIC_ void *talloc_new(const void *ctx);
+#else
+#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a 0-initizialized structure.
+ *
+ * The macro is equivalent to:
+ *
+ * @code
+ * ptr = talloc(ctx, type);
+ * if (ptr) memset(ptr, 0, sizeof(type));
+ * @endcode
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] type The type that we want to allocate.
+ *
+ * @return Pointer to a piece of memory, properly cast to 'type *',
+ * NULL on error.
+ *
+ * Example:
+ * @code
+ * unsigned int *a, *b;
+ * a = talloc_zero(NULL, unsigned int);
+ * b = talloc_zero(a, unsigned int);
+ * @endcode
+ *
+ * @see talloc()
+ * @see talloc_zero_size()
+ * @see talloc_zero_array()
+ */
+_PUBLIC_ void *talloc_zero(const void *ctx, #type);
+
+/**
+ * @brief Allocate untyped, 0-initialized memory.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] size Number of char's that you want to allocate.
+ *
+ * @return The allocated memory chunk.
+ */
+_PUBLIC_ void *talloc_zero_size(const void *ctx, size_t size);
+#else
+#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
+_PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name);
+#endif
+
+/**
+ * @brief Return the name of a talloc chunk.
+ *
+ * @param[in] ptr The talloc chunk.
+ *
+ * @return The current name for the given talloc pointer.
+ *
+ * @see talloc_set_name()
+ */
+_PUBLIC_ const char *talloc_get_name(const void *ptr);
+
+/**
+ * @brief Verify that a talloc chunk carries a specified name.
+ *
+ * This function checks if a pointer has the specified name. If it does
+ * then the pointer is returned.
+ *
+ * @param[in] ptr The talloc chunk to check.
+ *
+ * @param[in] name The name to check against.
+ *
+ * @return The pointer if the name matches, NULL if it doesn't.
+ */
+_PUBLIC_ void *talloc_check_name(const void *ptr, const char *name);
+
+/**
+ * @brief Get the parent chunk of a pointer.
+ *
+ * @param[in] ptr The talloc pointer to inspect.
+ *
+ * @return The talloc parent of ptr, NULL on error.
+ */
+_PUBLIC_ void *talloc_parent(const void *ptr);
+
+/**
+ * @brief Get a talloc chunk's parent name.
+ *
+ * @param[in] ptr The talloc pointer to inspect.
+ *
+ * @return The name of ptr's parent chunk.
+ */
+_PUBLIC_ const char *talloc_parent_name(const void *ptr);
+
+/**
+ * @brief Get the size of a talloc chunk.
+ *
+ * This function lets you know the amount of memory allocated so far by
+ * this context. It does NOT account for subcontext memory.
+ * This can be used to calculate the size of an array.
+ *
+ * @param[in] ctx The talloc chunk.
+ *
+ * @return The size of the talloc chunk.
+ */
+_PUBLIC_ size_t talloc_get_size(const void *ctx);
+
+/**
+ * @brief Get the total size of a talloc chunk including its children.
+ *
+ * The function returns the total size in bytes used by this pointer and all
+ * child pointers. Mostly useful for debugging.
+ *
+ * Passing NULL is allowed, but it will only give a meaningful result if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+ * been called.
+ *
+ * @param[in] ptr The talloc chunk.
+ *
+ * @return The total size.
+ */
+_PUBLIC_ size_t talloc_total_size(const void *ptr);
+
+/**
+ * @brief Get the number of talloc chunks hanging off a chunk.
+ *
+ * The talloc_total_blocks() function returns the total memory block
+ * count used by this pointer and all child pointers. Mostly useful for
+ * debugging.
+ *
+ * Passing NULL is allowed, but it will only give a meaningful result if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+ * been called.
+ *
+ * @param[in] ptr The talloc chunk.
+ *
+ * @return The total size.
+ */
+_PUBLIC_ size_t talloc_total_blocks(const void *ptr);
+
+#ifdef DOXYGEN
+/**
+ * @brief Duplicate a memory area into a talloc chunk.
+ *
+ * The function is equivalent to:
+ *
+ * @code
+ * ptr = talloc_size(ctx, size);
+ * if (ptr) memcpy(ptr, p, size);
+ * @endcode
+ *
+ * @param[in] t The talloc context to hang the result off.
+ *
+ * @param[in] p The memory chunk you want to duplicate.
+ *
+ * @param[in] size Number of chars that you want to copy.
+ *
+ * @return The allocated memory chunk.
+ *
+ * @see talloc_size()
+ */
+_PUBLIC_ void *talloc_memdup(const void *t, const void *p, size_t size);
+#else
+#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
+_PUBLIC_ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Assign a type to a talloc chunk.
+ *
+ * This macro allows you to force the name of a pointer to be of a particular
+ * type. This can be used in conjunction with talloc_get_type() to do type
+ * checking on void* pointers.
+ *
+ * It is equivalent to this:
+ *
+ * @code
+ * talloc_set_name_const(ptr, #type)
+ * @endcode
+ *
+ * @param[in] ptr The talloc chunk to assign the type to.
+ *
+ * @param[in] type The type to assign.
+ */
+_PUBLIC_ void talloc_set_type(const char *ptr, #type);
+
+/**
+ * @brief Get a typed pointer out of a talloc pointer.
+ *
+ * This macro allows you to do type checking on talloc pointers. It is
+ * particularly useful for void* private pointers. It is equivalent to
+ * this:
+ *
+ * @code
+ * (type *)talloc_check_name(ptr, #type)
+ * @endcode
+ *
+ * @param[in] ptr The talloc pointer to check.
+ *
+ * @param[in] type The type to check against.
+ *
+ * @return The properly casted pointer given by ptr, NULL on error.
+ */
+type *talloc_get_type(const void *ptr, #type);
+#else
+#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
+#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Safely turn a void pointer into a typed pointer.
+ *
+ * This macro is used together with talloc(mem_ctx, struct foo). If you had to
+ * assign the talloc chunk pointer to some void pointer variable,
+ * talloc_get_type_abort() is the recommended way to convert the void
+ * pointer back to a typed pointer.
+ *
+ * @param[in] ptr The void pointer to convert.
+ *
+ * @param[in] type The type that this chunk contains
+ *
+ * @return The same value as ptr, type-checked and properly cast.
+ */
+_PUBLIC_ void *talloc_get_type_abort(const void *ptr, #type);
+#else
+#ifdef TALLOC_GET_TYPE_ABORT_NOOP
+#define talloc_get_type_abort(ptr, type) (type *)(ptr)
+#else
+#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
+#endif
+_PUBLIC_ void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
+#endif
+
+/**
+ * @brief Find a parent context by name.
+ *
+ * Find a parent memory context of the current context that has the given
+ * name. This can be very useful in complex programs where it may be
+ * difficult to pass all information down to the level you need, but you
+ * know the structure you want is a parent of another context.
+ *
+ * @param[in] ctx The talloc chunk to start from.
+ *
+ * @param[in] name The name of the parent we look for.
+ *
+ * @return The memory context we are looking for, NULL if not
+ * found.
+ */
+_PUBLIC_ void *talloc_find_parent_byname(const void *ctx, const char *name);
+
+#ifdef DOXYGEN
+/**
+ * @brief Find a parent context by type.
+ *
+ * Find a parent memory context of the current context that has the given
+ * name. This can be very useful in complex programs where it may be
+ * difficult to pass all information down to the level you need, but you
+ * know the structure you want is a parent of another context.
+ *
+ * Like talloc_find_parent_byname() but takes a type, making it typesafe.
+ *
+ * @param[in] ptr The talloc chunk to start from.
+ *
+ * @param[in] type The type of the parent to look for.
+ *
+ * @return The memory context we are looking for, NULL if not
+ * found.
+ */
+_PUBLIC_ void *talloc_find_parent_bytype(const void *ptr, #type);
+#else
+#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
+#endif
+
+/**
+ * @brief Allocate a talloc pool.
+ *
+ * A talloc pool is a pure optimization for specific situations. In the
+ * release process for Samba 3.2 we found out that we had become considerably
+ * slower than Samba 3.0 was. Profiling showed that malloc(3) was a large CPU
+ * consumer in benchmarks. For Samba 3.2 we have internally converted many
+ * static buffers to dynamically allocated ones, so malloc(3) being beaten
+ * more was no surprise. But it made us slower.
+ *
+ * talloc_pool() is an optimization to call malloc(3) a lot less for the use
+ * pattern Samba has: The SMB protocol is mainly a request/response protocol
+ * where we have to allocate a certain amount of memory per request and free
+ * that after the SMB reply is sent to the client.
+ *
+ * talloc_pool() creates a talloc chunk that you can use as a talloc parent
+ * exactly as you would use any other ::TALLOC_CTX. The difference is that
+ * when you talloc a child of this pool, no malloc(3) is done. Instead, talloc
+ * just increments a pointer inside the talloc_pool. This also works
+ * recursively. If you use the child of the talloc pool as a parent for
+ * grand-children, their memory is also taken from the talloc pool.
+ *
+ * If there is not enough memory in the pool to allocate the new child,
+ * it will create a new talloc chunk as if the parent was a normal talloc
+ * context.
+ *
+ * If you talloc_free() children of a talloc pool, the memory is not given
+ * back to the system. Instead, free(3) is only called if the talloc_pool()
+ * itself is released with talloc_free().
+ *
+ * The downside of a talloc pool is that if you talloc_move() a child of a
+ * talloc pool to a talloc parent outside the pool, the whole pool memory is
+ * not free(3)'ed until that moved chunk is also talloc_free()ed.
+ *
+ * @param[in] context The talloc context to hang the result off.
+ *
+ * @param[in] size Size of the talloc pool.
+ *
+ * @return The allocated talloc pool, NULL on error.
+ */
+_PUBLIC_ void *talloc_pool(const void *context, size_t size);
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a talloc object as/with an additional pool.
+ *
+ * This is like talloc_pool(), but's it's more flexible
+ * and allows an object to be a pool for its children.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] type The type that we want to allocate.
+ *
+ * @param[in] num_subobjects The expected number of subobjects, which will
+ * be allocated within the pool. This allocates
+ * space for talloc_chunk headers.
+ *
+ * @param[in] total_subobjects_size The size that all subobjects can use in total.
+ *
+ *
+ * @return The allocated talloc object, NULL on error.
+ */
+_PUBLIC_ void *talloc_pooled_object(const void *ctx, #type,
+ unsigned num_subobjects,
+ size_t total_subobjects_size);
+#else
+#define talloc_pooled_object(_ctx, _type, \
+ _num_subobjects, \
+ _total_subobjects_size) \
+ (_type *)_talloc_pooled_object((_ctx), sizeof(_type), #_type, \
+ (_num_subobjects), \
+ (_total_subobjects_size))
+_PUBLIC_ void *_talloc_pooled_object(const void *ctx,
+ size_t type_size,
+ const char *type_name,
+ unsigned num_subobjects,
+ size_t total_subobjects_size);
+#endif
+
+/**
+ * @brief Free a talloc chunk and NULL out the pointer.
+ *
+ * TALLOC_FREE() frees a pointer and sets it to NULL. Use this if you want
+ * immediate feedback (i.e. crash) if you use a pointer after having free'ed
+ * it.
+ *
+ * @param[in] ctx The chunk to be freed.
+ */
+#define TALLOC_FREE(ctx) do { if (ctx != NULL) { talloc_free(ctx); ctx=NULL; } } while(0)
+
+/* @} ******************************************************************/
+
+/**
+ * \defgroup talloc_ref The talloc reference function.
+ * @ingroup talloc
+ *
+ * This module contains the definitions around talloc references
+ *
+ * @{
+ */
+
+/**
+ * @brief Increase the reference count of a talloc chunk.
+ *
+ * The talloc_increase_ref_count(ptr) function is exactly equivalent to:
+ *
+ * @code
+ * talloc_reference(NULL, ptr);
+ * @endcode
+ *
+ * You can use either syntax, depending on which you think is clearer in
+ * your code.
+ *
+ * @param[in] ptr The pointer to increase the reference count.
+ *
+ * @return 0 on success, -1 on error.
+ */
+_PUBLIC_ int talloc_increase_ref_count(const void *ptr);
+
+/**
+ * @brief Get the number of references to a talloc chunk.
+ *
+ * @param[in] ptr The pointer to retrieve the reference count from.
+ *
+ * @return The number of references.
+ */
+_PUBLIC_ size_t talloc_reference_count(const void *ptr);
+
+#ifdef DOXYGEN
+/**
+ * @brief Create an additional talloc parent to a pointer.
+ *
+ * The talloc_reference() function makes "context" an additional parent of
+ * ptr. Each additional reference consumes around 48 bytes of memory on intel
+ * x86 platforms.
+ *
+ * If ptr is NULL, then the function is a no-op, and simply returns NULL.
+ *
+ * After creating a reference you can free it in one of the following ways:
+ *
+ * - you can talloc_free() any parent of the original pointer. That
+ * will reduce the number of parents of this pointer by 1, and will
+ * cause this pointer to be freed if it runs out of parents.
+ *
+ * - you can talloc_free() the pointer itself if it has at maximum one
+ * parent. This behaviour has been changed since the release of version
+ * 2.0. Further information in the description of "talloc_free".
+ *
+ * For more control on which parent to remove, see talloc_unlink()
+ * @param[in] ctx The additional parent.
+ *
+ * @param[in] ptr The pointer you want to create an additional parent for.
+ *
+ * @return The original pointer 'ptr', NULL if talloc ran out of
+ * memory in creating the reference.
+ *
+ * @warning You should try to avoid using this interface. It turns a beautiful
+ * talloc-tree into a graph. It is often really hard to debug if you
+ * screw something up by accident.
+ *
+ * Example:
+ * @code
+ * unsigned int *a, *b, *c;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(NULL, unsigned int);
+ * c = talloc(a, unsigned int);
+ * // b also serves as a parent of c.
+ * talloc_reference(b, c);
+ * @endcode
+ *
+ * @see talloc_unlink()
+ */
+_PUBLIC_ void *talloc_reference(const void *ctx, const void *ptr);
+#else
+#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference_loc((ctx),(ptr), __location__)
+_PUBLIC_ void *_talloc_reference_loc(const void *context, const void *ptr, const char *location);
+#endif
+
+/**
+ * @brief Remove a specific parent from a talloc chunk.
+ *
+ * The function removes a specific parent from ptr. The context passed must
+ * either be a context used in talloc_reference() with this pointer, or must be
+ * a direct parent of ptr.
+ *
+ * You can just use talloc_free() instead of talloc_unlink() if there
+ * is at maximum one parent. This behaviour has been changed since the
+ * release of version 2.0. Further information in the description of
+ * "talloc_free".
+ *
+ * @param[in] context The talloc parent to remove.
+ *
+ * @param[in] ptr The talloc ptr you want to remove the parent from.
+ *
+ * @return 0 on success, -1 on error.
+ *
+ * @note If the parent has already been removed using talloc_free() then
+ * this function will fail and will return -1. Likewise, if ptr is NULL,
+ * then the function will make no modifications and return -1.
+ *
+ * @warning You should try to avoid using this interface. It turns a beautiful
+ * talloc-tree into a graph. It is often really hard to debug if you
+ * screw something up by accident.
+ *
+ * Example:
+ * @code
+ * unsigned int *a, *b, *c;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(NULL, unsigned int);
+ * c = talloc(a, unsigned int);
+ * // b also serves as a parent of c.
+ * talloc_reference(b, c);
+ * talloc_unlink(b, c);
+ * @endcode
+ */
+_PUBLIC_ int talloc_unlink(const void *context, void *ptr);
+
+/**
+ * @brief Provide a talloc context that is freed at program exit.
+ *
+ * This is a handy utility function that returns a talloc context
+ * which will be automatically freed on program exit. This can be used
+ * to reduce the noise in memory leak reports.
+ *
+ * Never use this in code that might be used in objects loaded with
+ * dlopen and unloaded with dlclose. talloc_autofree_context()
+ * internally uses atexit(3). Some platforms like modern Linux handles
+ * this fine, but for example FreeBSD does not deal well with dlopen()
+ * and atexit() used simultaneously: dlclose() does not clean up the
+ * list of atexit-handlers, so when the program exits the code that
+ * was registered from within talloc_autofree_context() is gone, the
+ * program crashes at exit.
+ *
+ * @return A talloc context, NULL on error.
+ */
+_PUBLIC_ void *talloc_autofree_context(void) _DEPRECATED_;
+
+/**
+ * @brief Show the parentage of a context.
+ *
+ * @param[in] context The talloc context to look at.
+ *
+ * @param[in] file The output to use, a file, stdout or stderr.
+ */
+_PUBLIC_ void talloc_show_parents(const void *context, FILE *file);
+
+/**
+ * @brief Check if a context is parent of a talloc chunk.
+ *
+ * This checks if context is referenced in the talloc hierarchy above ptr.
+ *
+ * @param[in] context The assumed talloc context.
+ *
+ * @param[in] ptr The talloc chunk to check.
+ *
+ * @return Return 1 if this is the case, 0 if not.
+ */
+_PUBLIC_ int talloc_is_parent(const void *context, const void *ptr);
+
+/**
+ * @brief Change the parent context of a talloc pointer.
+ *
+ * The function changes the parent context of a talloc pointer. It is typically
+ * used when the context that the pointer is currently a child of is going to be
+ * freed and you wish to keep the memory for a longer time.
+ *
+ * The difference between talloc_reparent() and talloc_steal() is that
+ * talloc_reparent() can specify which parent you wish to change. This is
+ * useful when a pointer has multiple parents via references.
+ *
+ * @param[in] old_parent
+ * @param[in] new_parent
+ * @param[in] ptr
+ *
+ * @return Return the pointer you passed. It does not have any
+ * failure modes.
+ */
+_PUBLIC_ void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr);
+
+/* @} ******************************************************************/
+
+/**
+ * @defgroup talloc_array The talloc array functions
+ * @ingroup talloc
+ *
+ * Talloc contains some handy helpers for handling Arrays conveniently
+ *
+ * @{
+ */
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate an array.
+ *
+ * The macro is equivalent to:
+ *
+ * @code
+ * (type *)talloc_size(ctx, sizeof(type) * count);
+ * @endcode
+ *
+ * except that it provides integer overflow protection for the multiply,
+ * returning NULL if the multiply overflows.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] type The type that we want to allocate.
+ *
+ * @param[in] count The number of 'type' elements you want to allocate.
+ *
+ * @return The allocated result, properly cast to 'type *', NULL on
+ * error.
+ *
+ * Example:
+ * @code
+ * unsigned int *a, *b;
+ * a = talloc_zero(NULL, unsigned int);
+ * b = talloc_array(a, unsigned int, 100);
+ * @endcode
+ *
+ * @see talloc()
+ * @see talloc_zero_array()
+ */
+_PUBLIC_ void *talloc_array(const void *ctx, #type, unsigned count);
+#else
+#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+_PUBLIC_ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate an array.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] size The size of an array element.
+ *
+ * @param[in] count The number of elements you want to allocate.
+ *
+ * @return The allocated result, NULL on error.
+ */
+_PUBLIC_ void *talloc_array_size(const void *ctx, size_t size, unsigned count);
+#else
+#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate an array into a typed pointer.
+ *
+ * The macro should be used when you have a pointer to an array and want to
+ * allocate memory of an array to point at with this pointer. When compiling
+ * with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+ * and talloc_get_name() will return the current location in the source file
+ * and not the type.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] ptr The pointer you want to assign the result to.
+ *
+ * @param[in] count The number of elements you want to allocate.
+ *
+ * @return The allocated memory chunk, properly casted. NULL on
+ * error.
+ */
+void *talloc_array_ptrtype(const void *ctx, const void *ptr, unsigned count);
+#else
+#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the number of elements in a talloc'ed array.
+ *
+ * A talloc chunk carries its own size, so for talloc'ed arrays it is not
+ * necessary to store the number of elements explicitly.
+ *
+ * @param[in] ctx The allocated array.
+ *
+ * @return The number of elements in ctx.
+ */
+size_t talloc_array_length(const void *ctx);
+#else
+#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx))
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a zero-initialized array
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] type The type that we want to allocate.
+ *
+ * @param[in] count The number of "type" elements you want to allocate.
+ *
+ * @return The allocated result casted to "type *", NULL on error.
+ *
+ * The talloc_zero_array() macro is equivalent to:
+ *
+ * @code
+ * ptr = talloc_array(ctx, type, count);
+ * if (ptr) memset(ptr, 0, sizeof(type) * count);
+ * @endcode
+ */
+void *talloc_zero_array(const void *ctx, #type, unsigned count);
+#else
+#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+_PUBLIC_ void *_talloc_zero_array(const void *ctx,
+ size_t el_size,
+ unsigned count,
+ const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Change the size of a talloc array.
+ *
+ * The macro changes the size of a talloc pointer. The 'count' argument is the
+ * number of elements of type 'type' that you want the resulting pointer to
+ * hold.
+ *
+ * talloc_realloc() has the following equivalences:
+ *
+ * @code
+ * talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type);
+ * talloc_realloc(ctx, NULL, type, N) ==> talloc_array(ctx, type, N);
+ * talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr);
+ * @endcode
+ *
+ * The "context" argument is only used if "ptr" is NULL, otherwise it is
+ * ignored.
+ *
+ * @param[in] ctx The parent context used if ptr is NULL.
+ *
+ * @param[in] ptr The chunk to be resized.
+ *
+ * @param[in] type The type of the array element inside ptr.
+ *
+ * @param[in] count The intended number of array elements.
+ *
+ * @return The new array, NULL on error. The call will fail either
+ * due to a lack of memory, or because the pointer has more
+ * than one parent (see talloc_reference()).
+ */
+_PUBLIC_ void *talloc_realloc(const void *ctx, void *ptr, #type, size_t count);
+#else
+#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
+_PUBLIC_ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Untyped realloc to change the size of a talloc array.
+ *
+ * The macro is useful when the type is not known so the typesafe
+ * talloc_realloc() cannot be used.
+ *
+ * @param[in] ctx The parent context used if 'ptr' is NULL.
+ *
+ * @param[in] ptr The chunk to be resized.
+ *
+ * @param[in] size The new chunk size.
+ *
+ * @return The new array, NULL on error.
+ */
+void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);
+#else
+#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
+_PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+#endif
+
+/**
+ * @brief Provide a function version of talloc_realloc_size.
+ *
+ * This is a non-macro version of talloc_realloc(), which is useful as
+ * libraries sometimes want a ralloc function pointer. A realloc()
+ * implementation encapsulates the functionality of malloc(), free() and
+ * realloc() in one call, which is why it is useful to be able to pass around
+ * a single function pointer.
+ *
+ * @param[in] context The parent context used if ptr is NULL.
+ *
+ * @param[in] ptr The chunk to be resized.
+ *
+ * @param[in] size The new chunk size.
+ *
+ * @return The new chunk, NULL on error.
+ */
+_PUBLIC_ void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
+
+/* @} ******************************************************************/
+
+/**
+ * @defgroup talloc_string The talloc string functions.
+ * @ingroup talloc
+ *
+ * talloc string allocation and manipulation functions.
+ * @{
+ */
+
+/**
+ * @brief Duplicate a string into a talloc chunk.
+ *
+ * This function is equivalent to:
+ *
+ * @code
+ * ptr = talloc_size(ctx, strlen(p)+1);
+ * if (ptr) memcpy(ptr, p, strlen(p)+1);
+ * @endcode
+ *
+ * This functions sets the name of the new pointer to the passed
+ * string. This is equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in] t The talloc context to hang the result off.
+ *
+ * @param[in] p The string you want to duplicate.
+ *
+ * @return The duplicated string, NULL on error.
+ */
+_PUBLIC_ char *talloc_strdup(const void *t, const char *p);
+
+/**
+ * @brief Append a string to given string.
+ *
+ * The destination string is reallocated to take
+ * <code>strlen(s) + strlen(a) + 1</code> characters.
+ *
+ * This functions sets the name of the new pointer to the new
+ * string. This is equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination to append to.
+ *
+ * @param[in] a The string you want to append.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strdup()
+ * @see talloc_strdup_append_buffer()
+ */
+_PUBLIC_ char *talloc_strdup_append(char *s, const char *a);
+
+/**
+ * @brief Append a string to a given buffer.
+ *
+ * This is a more efficient version of talloc_strdup_append(). It determines the
+ * length of the destination string by the size of the talloc context.
+ *
+ * Use this very carefully as it produces a different result than
+ * talloc_strdup_append() when a zero character is in the middle of the
+ * destination string.
+ *
+ * @code
+ * char *str_a = talloc_strdup(NULL, "hello world");
+ * char *str_b = talloc_strdup(NULL, "hello world");
+ * str_a[5] = str_b[5] = '\0'
+ *
+ * char *app = talloc_strdup_append(str_a, ", hello");
+ * char *buf = talloc_strdup_append_buffer(str_b, ", hello");
+ *
+ * printf("%s\n", app); // hello, hello (app = "hello, hello")
+ * printf("%s\n", buf); // hello (buf = "hello\0world, hello")
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination buffer to append to.
+ *
+ * @param[in] a The string you want to append.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strdup()
+ * @see talloc_strdup_append()
+ * @see talloc_array_length()
+ */
+_PUBLIC_ char *talloc_strdup_append_buffer(char *s, const char *a);
+
+/**
+ * @brief Duplicate a length-limited string into a talloc chunk.
+ *
+ * This function is the talloc equivalent of the C library function strndup(3).
+ *
+ * This functions sets the name of the new pointer to the passed string. This is
+ * equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in] t The talloc context to hang the result off.
+ *
+ * @param[in] p The string you want to duplicate.
+ *
+ * @param[in] n The maximum string length to duplicate.
+ *
+ * @return The duplicated string, NULL on error.
+ */
+_PUBLIC_ char *talloc_strndup(const void *t, const char *p, size_t n);
+
+/**
+ * @brief Append at most n characters of a string to given string.
+ *
+ * The destination string is reallocated to take
+ * <code>strlen(s) + strnlen(a, n) + 1</code> characters.
+ *
+ * This functions sets the name of the new pointer to the new
+ * string. This is equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination string to append to.
+ *
+ * @param[in] a The source string you want to append.
+ *
+ * @param[in] n The number of characters you want to append from the
+ * string.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strndup()
+ * @see talloc_strndup_append_buffer()
+ */
+_PUBLIC_ char *talloc_strndup_append(char *s, const char *a, size_t n);
+
+/**
+ * @brief Append at most n characters of a string to given buffer
+ *
+ * This is a more efficient version of talloc_strndup_append(). It determines
+ * the length of the destination string by the size of the talloc context.
+ *
+ * Use this very carefully as it produces a different result than
+ * talloc_strndup_append() when a zero character is in the middle of the
+ * destination string.
+ *
+ * @code
+ * char *str_a = talloc_strdup(NULL, "hello world");
+ * char *str_b = talloc_strdup(NULL, "hello world");
+ * str_a[5] = str_b[5] = '\0'
+ *
+ * char *app = talloc_strndup_append(str_a, ", hello", 7);
+ * char *buf = talloc_strndup_append_buffer(str_b, ", hello", 7);
+ *
+ * printf("%s\n", app); // hello, hello (app = "hello, hello")
+ * printf("%s\n", buf); // hello (buf = "hello\0world, hello")
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination buffer to append to.
+ *
+ * @param[in] a The source string you want to append.
+ *
+ * @param[in] n The number of characters you want to append from the
+ * string.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strndup()
+ * @see talloc_strndup_append()
+ * @see talloc_array_length()
+ */
+_PUBLIC_ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
+
+/**
+ * @brief Format a string given a va_list.
+ *
+ * This function is the talloc equivalent of the C library function
+ * vasprintf(3).
+ *
+ * This functions sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in] t The talloc context to hang the result off.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ap The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ */
+_PUBLIC_ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Format a string given a va_list and append it to the given destination
+ * string.
+ *
+ * @param[in] s The destination string to append to.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ap The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ *
+ * @see talloc_vasprintf()
+ */
+_PUBLIC_ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Format a string given a va_list and append it to the given destination
+ * buffer.
+ *
+ * @param[in] s The destination buffer to append to.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ap The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ *
+ * @see talloc_vasprintf()
+ */
+_PUBLIC_ char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Build up a string buffer, handle allocation failure
+ *
+ * @param[in] ps Pointer to the talloc'ed string to be extended
+ * @param[in] fmt The format string
+ * @param[in] ... The parameters used to fill fmt.
+ *
+ * This does nothing if *ps is NULL and sets *ps to NULL if the
+ * intermediate reallocation fails. Useful when building up a string
+ * step by step, no intermediate NULL checks are required.
+ */
+_PUBLIC_ void talloc_asprintf_addbuf(char **ps, const char *fmt, ...) \
+ PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * @brief Format a string.
+ *
+ * This function is the talloc equivalent of the C library function asprintf(3).
+ *
+ * This functions sets the name of the new pointer to the new string. This is
+ * equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * @param[in] t The talloc context to hang the result off.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ... The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ */
+_PUBLIC_ char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * @brief Append a formatted string to another string.
+ *
+ * This function appends the given formatted string to the given string. Use
+ * this variant when the string in the current talloc buffer may have been
+ * truncated in length.
+ *
+ * This functions sets the name of the new pointer to the new
+ * string. This is equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The string to append to.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ... The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ */
+_PUBLIC_ char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * @brief Append a formatted string to another string.
+ *
+ * This is a more efficient version of talloc_asprintf_append(). It determines
+ * the length of the destination string by the size of the talloc context.
+ *
+ * Use this very carefully as it produces a different result than
+ * talloc_asprintf_append() when a zero character is in the middle of the
+ * destination string.
+ *
+ * @code
+ * char *str_a = talloc_strdup(NULL, "hello world");
+ * char *str_b = talloc_strdup(NULL, "hello world");
+ * str_a[5] = str_b[5] = '\0'
+ *
+ * char *app = talloc_asprintf_append(str_a, "%s", ", hello");
+ * char *buf = talloc_strdup_append_buffer(str_b, "%s", ", hello");
+ *
+ * printf("%s\n", app); // hello, hello (app = "hello, hello")
+ * printf("%s\n", buf); // hello (buf = "hello\0world, hello")
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The string to append to
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ... The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ *
+ * @see talloc_asprintf()
+ * @see talloc_asprintf_append()
+ */
+_PUBLIC_ char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+/* @} ******************************************************************/
+
+/**
+ * @defgroup talloc_debug The talloc debugging support functions
+ * @ingroup talloc
+ *
+ * To aid memory debugging, talloc contains routines to inspect the currently
+ * allocated memory hierarchy.
+ *
+ * @{
+ */
+
+/**
+ * @brief Walk a complete talloc hierarchy.
+ *
+ * This provides a more flexible reports than talloc_report(). It
+ * will recursively call the callback for the entire tree of memory
+ * referenced by the pointer. References in the tree are passed with
+ * is_ref = 1 and the pointer that is referenced.
+ *
+ * You can pass NULL for the pointer, in which case a report is
+ * printed for the top level memory context, but only if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full()
+ * has been called.
+ *
+ * The recursion is stopped when depth >= max_depth.
+ * max_depth = -1 means only stop at leaf nodes.
+ *
+ * @param[in] ptr The talloc chunk.
+ *
+ * @param[in] depth Internal parameter to control recursion. Call with 0.
+ *
+ * @param[in] max_depth Maximum recursion level.
+ *
+ * @param[in] callback Function to be called on every chunk.
+ *
+ * @param[in] private_data Private pointer passed to callback.
+ */
+_PUBLIC_ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data);
+
+/**
+ * @brief Print a talloc hierarchy.
+ *
+ * This provides a more flexible reports than talloc_report(). It
+ * will let you specify the depth and max_depth.
+ *
+ * @param[in] ptr The talloc chunk.
+ *
+ * @param[in] depth Internal parameter to control recursion. Call with 0.
+ *
+ * @param[in] max_depth Maximum recursion level.
+ *
+ * @param[in] f The file handle to print to.
+ */
+_PUBLIC_ void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+
+/**
+ * @brief Print a summary report of all memory used by ptr.
+ *
+ * This provides a more detailed report than talloc_report(). It will
+ * recursively print the entire tree of memory referenced by the
+ * pointer. References in the tree are shown by giving the name of the
+ * pointer that is referenced.
+ *
+ * You can pass NULL for the pointer, in which case a report is printed
+ * for the top level memory context, but only if
+ * talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+ * been called.
+ *
+ * @param[in] ptr The talloc chunk.
+ *
+ * @param[in] f The file handle to print to.
+ *
+ * Example:
+ * @code
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ * fprintf(stderr, "Dumping memory tree for a:\n");
+ * talloc_report_full(a, stderr);
+ * @endcode
+ *
+ * @see talloc_report()
+ */
+_PUBLIC_ void talloc_report_full(const void *ptr, FILE *f);
+
+/**
+ * @brief Print a summary report of all memory used by ptr.
+ *
+ * This function prints a summary report of all memory used by ptr. One line of
+ * report is printed for each immediate child of ptr, showing the total memory
+ * and number of blocks used by that child.
+ *
+ * You can pass NULL for the pointer, in which case a report is printed
+ * for the top level memory context, but only if talloc_enable_leak_report()
+ * or talloc_enable_leak_report_full() has been called.
+ *
+ * @param[in] ptr The talloc chunk.
+ *
+ * @param[in] f The file handle to print to.
+ *
+ * Example:
+ * @code
+ * unsigned int *a, *b;
+ * a = talloc(NULL, unsigned int);
+ * b = talloc(a, unsigned int);
+ * fprintf(stderr, "Summary of memory tree for a:\n");
+ * talloc_report(a, stderr);
+ * @endcode
+ *
+ * @see talloc_report_full()
+ */
+_PUBLIC_ void talloc_report(const void *ptr, FILE *f);
+
+/**
+ * @brief Enable tracking the use of NULL memory contexts.
+ *
+ * This enables tracking of the NULL memory context without enabling leak
+ * reporting on exit. Useful for when you want to do your own leak
+ * reporting call via talloc_report_null_full();
+ */
+_PUBLIC_ void talloc_enable_null_tracking(void);
+
+/**
+ * @brief Enable tracking the use of NULL memory contexts.
+ *
+ * This enables tracking of the NULL memory context without enabling leak
+ * reporting on exit. Useful for when you want to do your own leak
+ * reporting call via talloc_report_null_full();
+ */
+_PUBLIC_ void talloc_enable_null_tracking_no_autofree(void);
+
+/**
+ * @brief Disable tracking of the NULL memory context.
+ *
+ * This disables tracking of the NULL memory context.
+ */
+_PUBLIC_ void talloc_disable_null_tracking(void);
+
+/**
+ * @brief Enable leak report when a program exits.
+ *
+ * This enables calling of talloc_report(NULL, stderr) when the program
+ * exits. In Samba4 this is enabled by using the --leak-report command
+ * line option.
+ *
+ * For it to be useful, this function must be called before any other
+ * talloc function as it establishes a "null context" that acts as the
+ * top of the tree. If you don't call this function first then passing
+ * NULL to talloc_report() or talloc_report_full() won't give you the
+ * full tree printout.
+ *
+ * Here is a typical talloc report:
+ *
+ * @code
+ * talloc report on 'null_context' (total 267 bytes in 15 blocks)
+ * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ * iconv(UTF8,CP850) contains 42 bytes in 2 blocks
+ * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ * iconv(CP850,UTF8) contains 42 bytes in 2 blocks
+ * iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
+ * iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
+ * @endcode
+ */
+_PUBLIC_ void talloc_enable_leak_report(void);
+
+/**
+ * @brief Enable full leak report when a program exits.
+ *
+ * This enables calling of talloc_report_full(NULL, stderr) when the
+ * program exits. In Samba4 this is enabled by using the
+ * --leak-report-full command line option.
+ *
+ * For it to be useful, this function must be called before any other
+ * talloc function as it establishes a "null context" that acts as the
+ * top of the tree. If you don't call this function first then passing
+ * NULL to talloc_report() or talloc_report_full() won't give you the
+ * full tree printout.
+ *
+ * Here is a typical full report:
+ *
+ * @code
+ * full talloc report on 'root' (total 18 bytes in 8 blocks)
+ * p1 contains 18 bytes in 7 blocks (ref 0)
+ * r1 contains 13 bytes in 2 blocks (ref 0)
+ * reference to: p2
+ * p2 contains 1 bytes in 1 blocks (ref 1)
+ * x3 contains 1 bytes in 1 blocks (ref 0)
+ * x2 contains 1 bytes in 1 blocks (ref 0)
+ * x1 contains 1 bytes in 1 blocks (ref 0)
+ * @endcode
+ */
+_PUBLIC_ void talloc_enable_leak_report_full(void);
+
+/**
+ * @brief Set a custom "abort" function that is called on serious error.
+ *
+ * The default "abort" function is <code>abort()</code>.
+ *
+ * The "abort" function is called when:
+ *
+ * <ul>
+ * <li>talloc_get_type_abort() fails</li>
+ * <li>the provided pointer is not a valid talloc context</li>
+ * <li>when the context meta data are invalid</li>
+ * <li>when access after free is detected</li>
+ * </ul>
+ *
+ * Example:
+ *
+ * @code
+ * void my_abort(const char *reason)
+ * {
+ * fprintf(stderr, "talloc abort: %s\n", reason);
+ * abort();
+ * }
+ *
+ * talloc_set_abort_fn(my_abort);
+ * @endcode
+ *
+ * @param[in] abort_fn The new "abort" function.
+ *
+ * @see talloc_set_log_fn()
+ * @see talloc_get_type()
+ */
+_PUBLIC_ void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
+
+/**
+ * @brief Set a logging function.
+ *
+ * @param[in] log_fn The logging function.
+ *
+ * @see talloc_set_log_stderr()
+ * @see talloc_set_abort_fn()
+ */
+_PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message));
+
+/**
+ * @brief Set stderr as the output for logs.
+ *
+ * @see talloc_set_log_fn()
+ * @see talloc_set_abort_fn()
+ */
+_PUBLIC_ void talloc_set_log_stderr(void);
+
+/**
+ * @brief Set a max memory limit for the current context hierarchy
+ * This affects all children of this context and constrain any
+ * allocation in the hierarchy to never exceed the limit set.
+ * The limit can be removed by setting 0 (unlimited) as the
+ * max_size by calling the function again on the same context.
+ * Memory limits can also be nested, meaning a child can have
+ * a stricter memory limit than a parent.
+ * Memory limits are enforced only at memory allocation time.
+ * Stealing a context into a 'limited' hierarchy properly
+ * updates memory usage but does *not* cause failure if the
+ * move causes the new parent to exceed its limits. However
+ * any further allocation on that hierarchy will then fail.
+ *
+ * @warning talloc memlimit functionality is deprecated. Please
+ * consider using cgroup memory limits instead.
+ *
+ * @param[in] ctx The talloc context to set the limit on
+ * @param[in] max_size The (new) max_size
+ */
+_PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size) _DEPRECATED_;
+
+/* @} ******************************************************************/
+
+#if TALLOC_DEPRECATED
+#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
+#define talloc_p(ctx, type) talloc(ctx, type)
+#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
+#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
+#endif
+
+#ifndef TALLOC_MAX_DEPTH
+#define TALLOC_MAX_DEPTH 10000
+#endif
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
diff --git a/lib/talloc/talloc.pc.in b/lib/talloc/talloc.pc.in
new file mode 100644
index 0000000..437281a
--- /dev/null
+++ b/lib/talloc/talloc.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: talloc
+Description: A hierarchical pool based memory system with destructors
+Version: @TALLOC_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -ltalloc
+Cflags: -I${includedir}
+URL: http://talloc.samba.org/
diff --git a/lib/talloc/talloc_guide.txt b/lib/talloc/talloc_guide.txt
new file mode 100644
index 0000000..dedda6c
--- /dev/null
+++ b/lib/talloc/talloc_guide.txt
@@ -0,0 +1,768 @@
+Using talloc in Samba4
+======================
+
+.. contents::
+
+Andrew Tridgell
+August 2009
+
+The most current version of this document is available at
+ http://samba.org/ftp/unpacked/talloc/talloc_guide.txt
+
+If you are used to the "old" talloc from Samba3 before 3.0.20 then please read
+this carefully, as talloc has changed a lot. With 3.0.20 (or 3.0.14?) the
+Samba4 talloc has been ported back to Samba3, so this guide applies to both.
+
+The new talloc is a hierarchical, reference counted memory pool system
+with destructors. Quite a mouthful really, but not too bad once you
+get used to it.
+
+Perhaps the biggest change from Samba3 is that there is no distinction
+between a "talloc context" and a "talloc pointer". Any pointer
+returned from talloc() is itself a valid talloc context. This means
+you can do this::
+
+ struct foo *X = talloc(mem_ctx, struct foo);
+ X->name = talloc_strdup(X, "foo");
+
+and the pointer X->name would be a "child" of the talloc context "X"
+which is itself a child of "mem_ctx". So if you do talloc_free(mem_ctx)
+then it is all destroyed, whereas if you do talloc_free(X) then just X
+and X->name are destroyed, and if you do talloc_free(X->name) then
+just the name element of X is destroyed.
+
+If you think about this, then what this effectively gives you is an
+n-ary tree, where you can free any part of the tree with
+talloc_free().
+
+If you find this confusing, then I suggest you run the testsuite to
+watch talloc in action. You may also like to add your own tests to
+testsuite.c to clarify how some particular situation is handled.
+
+
+Performance
+-----------
+
+All the additional features of talloc() over malloc() do come at a
+price. We have a simple performance test in Samba4 that measures
+talloc() versus malloc() performance, and it seems that talloc() is
+about 4% slower than malloc() on my x86 Debian Linux box. For Samba,
+the great reduction in code complexity that we get by using talloc
+makes this worthwhile, especially as the total overhead of
+talloc/malloc in Samba is already quite small.
+
+
+talloc API
+----------
+
+The following is a complete guide to the talloc API. Read it all at
+least twice.
+
+Multi-threading
+---------------
+
+talloc itself does not deal with threads. It is thread-safe (assuming
+the underlying "malloc" is), as long as each thread uses different
+memory contexts.
+If two threads use the same context then they need to synchronize in
+order to be safe. In particular:
+- when using talloc_enable_leak_report(), giving directly NULL as a
+parent context implicitly refers to a hidden "null context" global
+variable, so this should not be used in a multi-threaded environment
+without proper synchronization. In threaded code turn off null tracking using
+talloc_disable_null_tracking(). ;
+- the context returned by talloc_autofree_context() is also global so
+shouldn't be used by several threads simultaneously without
+synchronization.
+
+talloc and shared objects
+-------------------------
+
+talloc can be used in shared objects. Special care needs to be taken
+to never use talloc_autofree_context() in code that might be loaded
+with dlopen() and unloaded with dlclose(), as talloc_autofree_context()
+internally uses atexit(3). Some platforms like modern Linux handles
+this fine, but for example FreeBSD does not deal well with dlopen()
+and atexit() used simultaneously: dlclose() does not clean up the list
+of atexit-handlers, so when the program exits the code that was
+registered from within talloc_autofree_context() is gone, the program
+crashes at exit.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc(const void *context, type);
+
+The talloc() macro is the core of the talloc library. It takes a
+memory context and a type, and returns a pointer to a new area of
+memory of the given type.
+
+The returned pointer is itself a talloc context, so you can use it as
+the context argument to more calls to talloc if you wish.
+
+The returned pointer is a "child" of the supplied context. This means
+that if you talloc_free() the context then the new child disappears as
+well. Alternatively you can free just the child.
+
+The context argument to talloc() can be NULL, in which case a new top
+level context is created.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_size(const void *context, size_t size);
+
+The function talloc_size() should be used when you don't have a
+convenient type to pass to talloc(). Unlike talloc(), it is not type
+safe (as it returns a void *), so you are on your own for type checking.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);
+
+The talloc_ptrtype() macro should be used when you have a pointer and
+want to allocate memory to point at with this pointer. When compiling
+with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size()
+and talloc_get_name() will return the current location in the source file.
+and not the type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_free(void *ptr);
+
+The talloc_free() function frees a piece of talloc memory, and all its
+children. You can call talloc_free() on any pointer returned by
+talloc().
+
+The return value of talloc_free() indicates success or failure, with 0
+returned for success and -1 for failure. A possible failure condition
+is if the pointer had a destructor attached to it and the destructor
+returned -1. See talloc_set_destructor() for details on
+destructors. Likewise, if "ptr" is NULL, then the function will make
+no modifications and returns -1.
+
+From version 2.0 and onwards, as a special case, talloc_free() is
+refused on pointers that have more than one parent associated, as talloc
+would have no way of knowing which parent should be removed. This is
+different from older versions in the sense that always the reference to
+the most recently established parent has been destroyed. Hence to free a
+pointer that has more than one parent please use talloc_unlink().
+
+To help you find problems in your code caused by this behaviour, if
+you do try and free a pointer with more than one parent then the
+talloc logging function will be called to give output like this:
+
+ ERROR: talloc_free with references at some_dir/source/foo.c:123
+ reference at some_dir/source/other.c:325
+ reference at some_dir/source/third.c:121
+
+Please see the documentation for talloc_set_log_fn() and
+talloc_set_log_stderr() for more information on talloc logging
+functions.
+
+talloc_free() operates recursively on its children.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_free_children(void *ptr);
+
+The talloc_free_children() walks along the list of all children of a
+talloc context and talloc_free()s only the children, not the context
+itself.
+
+A NULL argument is handled as no-op.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_reference(const void *context, const void *ptr);
+
+The talloc_reference() function makes "context" an additional parent
+of "ptr".
+
+The return value of talloc_reference() is always the original pointer
+"ptr", unless talloc ran out of memory in creating the reference in
+which case it will return NULL (each additional reference consumes
+around 48 bytes of memory on intel x86 platforms).
+
+If "ptr" is NULL, then the function is a no-op, and simply returns NULL.
+
+After creating a reference you can free it in one of the following
+ways:
+
+ - you can talloc_free() any parent of the original pointer. That
+ will reduce the number of parents of this pointer by 1, and will
+ cause this pointer to be freed if it runs out of parents.
+
+ - you can talloc_free() the pointer itself if it has at maximum one
+ parent. This behaviour has been changed since the release of version
+ 2.0. Further information in the description of "talloc_free".
+
+For more control on which parent to remove, see talloc_unlink()
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_unlink(const void *context, void *ptr);
+
+The talloc_unlink() function removes a specific parent from ptr. The
+context passed must either be a context used in talloc_reference()
+with this pointer, or must be a direct parent of ptr.
+
+Note that if the parent has already been removed using talloc_free()
+then this function will fail and will return -1. Likewise, if "ptr"
+is NULL, then the function will make no modifications and return -1.
+
+You can just use talloc_free() instead of talloc_unlink() if there
+is at maximum one parent. This behaviour has been changed since the
+release of version 2.0. Further information in the description of
+"talloc_free".
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+
+The function talloc_set_destructor() sets the "destructor" for the
+pointer "ptr". A destructor is a function that is called when the
+memory used by a pointer is about to be released. The destructor
+receives the pointer as an argument, and should return 0 for success
+and -1 for failure.
+
+The destructor can do anything it wants to, including freeing other
+pieces of memory. A common use for destructors is to clean up
+operating system resources (such as open file descriptors) contained
+in the structure the destructor is placed on.
+
+You can only place one destructor on a pointer. If you need more than
+one destructor then you can create a zero-length child of the pointer
+and place an additional destructor on that.
+
+To remove a destructor call talloc_set_destructor() with NULL for the
+destructor.
+
+If your destructor attempts to talloc_free() the pointer that it is
+the destructor for then talloc_free() will return -1 and the free will
+be ignored. This would be a pointless operation anyway, as the
+destructor is only called when the memory is just about to go away.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+int talloc_increase_ref_count(const void *ptr);
+
+The talloc_increase_ref_count(ptr) function is exactly equivalent to:
+
+ talloc_reference(NULL, ptr);
+
+You can use either syntax, depending on which you think is clearer in
+your code.
+
+It returns 0 on success and -1 on failure.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_reference_count(const void *ptr);
+
+Return the number of references to the pointer.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_name(const void *ptr, const char *fmt, ...);
+
+Each talloc pointer has a "name". The name is used principally for
+debugging purposes, although it is also possible to set and get the
+name on a pointer in as a way of "marking" pointers in your code.
+
+The main use for names on pointer is for "talloc reports". See
+talloc_report() and talloc_report_full() for details. Also see
+talloc_enable_leak_report() and talloc_enable_leak_report_full().
+
+The talloc_set_name() function allocates memory as a child of the
+pointer. It is logically equivalent to:
+ talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));
+
+Note that multiple calls to talloc_set_name() will allocate more
+memory without releasing the name. All of the memory is released when
+the ptr is freed using talloc_free().
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_name_const(const void *ptr, const char *name);
+
+The function talloc_set_name_const() is just like talloc_set_name(),
+but it takes a string constant, and is much faster. It is extensively
+used by the "auto naming" macros, such as talloc_p().
+
+This function does not allocate any memory. It just copies the
+supplied pointer into the internal representation of the talloc
+ptr. This means you must not pass a name pointer to memory that will
+disappear before the ptr is freed with talloc_free().
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_named(const void *context, size_t size, const char *fmt, ...);
+
+The talloc_named() function creates a named talloc pointer. It is
+equivalent to:
+
+ ptr = talloc_size(context, size);
+ talloc_set_name(ptr, fmt, ....);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_named_const(const void *context, size_t size, const char *name);
+
+This is equivalent to::
+
+ ptr = talloc_size(context, size);
+ talloc_set_name_const(ptr, name);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+const char *talloc_get_name(const void *ptr);
+
+This returns the current name for the given talloc pointer. See
+talloc_set_name() for details.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_init(const char *fmt, ...);
+
+This function creates a zero length named talloc context as a top
+level context. It is equivalent to::
+
+ talloc_named(NULL, 0, fmt, ...);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_new(void *ctx);
+
+This is a utility macro that creates a new memory context hanging
+off an exiting context, automatically naming it "talloc_new: __location__"
+where __location__ is the source line it is called from. It is
+particularly useful for creating a new temporary working context.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_realloc(const void *context, void *ptr, type, count);
+
+The talloc_realloc() macro changes the size of a talloc
+pointer. The "count" argument is the number of elements of type "type"
+that you want the resulting pointer to hold.
+
+talloc_realloc() has the following equivalences::
+
+ talloc_realloc(context, NULL, type, 1) ==> talloc(context, type);
+ talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N);
+ talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr);
+
+The "context" argument is only used if "ptr" is NULL, otherwise it is
+ignored.
+
+talloc_realloc() returns the new pointer, or NULL on failure. The call
+will fail either due to a lack of memory, or because the pointer has
+more than one parent (see talloc_reference()).
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_realloc_size(const void *context, void *ptr, size_t size);
+
+the talloc_realloc_size() function is useful when the type is not
+known so the typesafe talloc_realloc() cannot be used.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_steal(const void *new_ctx, const void *ptr);
+
+The talloc_steal() function changes the parent context of a talloc
+pointer. It is typically used when the context that the pointer is
+currently a child of is going to be freed and you wish to keep the
+memory for a longer time.
+
+The talloc_steal() function returns the pointer that you pass it. It
+does not have any failure modes.
+
+NOTE: It is possible to produce loops in the parent/child relationship
+if you are not careful with talloc_steal(). No guarantees are provided
+as to your sanity or the safety of your data if you do this.
+
+talloc_steal (new_ctx, NULL) will return NULL with no sideeffects.
+
+Note that if you try and call talloc_steal() on a pointer that has
+more than one parent then the result is ambiguous. Talloc will choose
+to remove the parent that is currently indicated by talloc_parent()
+and replace it with the chosen parent. You will also get a message
+like this via the talloc logging functions:
+
+ WARNING: talloc_steal with references at some_dir/source/foo.c:123
+ reference at some_dir/source/other.c:325
+ reference at some_dir/source/third.c:121
+
+To unambiguously change the parent of a pointer please see the
+function talloc_reparent(). See the talloc_set_log_fn() documentation
+for more information on talloc logging.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr);
+
+The talloc_reparent() function changes the parent context of a talloc
+pointer. It is typically used when the context that the pointer is
+currently a child of is going to be freed and you wish to keep the
+memory for a longer time.
+
+The talloc_reparent() function returns the pointer that you pass it. It
+does not have any failure modes.
+
+The difference between talloc_reparent() and talloc_steal() is that
+talloc_reparent() can specify which parent you wish to change. This is
+useful when a pointer has multiple parents via references.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_parent(const void *ptr);
+
+The talloc_parent() function returns the current talloc parent. This
+is usually the pointer under which this memory was originally created,
+but it may have changed due to a talloc_steal() or talloc_reparent()
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_total_size(const void *ptr);
+
+The talloc_total_size() function returns the total size in bytes used
+by this pointer and all child pointers. Mostly useful for debugging.
+
+Passing NULL is allowed, but it will only give a meaningful result if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+size_t talloc_total_blocks(const void *ptr);
+
+The talloc_total_blocks() function returns the total memory block
+count used by this pointer and all child pointers. Mostly useful for
+debugging.
+
+Passing NULL is allowed, but it will only give a meaningful result if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *priv),
+ void *priv);
+
+This provides a more flexible reports than talloc_report(). It
+will recursively call the callback for the entire tree of memory
+referenced by the pointer. References in the tree are passed with
+is_ref = 1 and the pointer that is referenced.
+
+You can pass NULL for the pointer, in which case a report is
+printed for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full()
+has been called.
+
+The recursion is stopped when depth >= max_depth.
+max_depth = -1 means only stop at leaf nodes.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+
+This provides a more flexible reports than talloc_report(). It
+will let you specify the depth and max_depth.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report(const void *ptr, FILE *f);
+
+The talloc_report() function prints a summary report of all memory
+used by ptr. One line of report is printed for each immediate child of
+ptr, showing the total memory and number of blocks used by that child.
+
+You can pass NULL for the pointer, in which case a report is printed
+for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_report_full(const void *ptr, FILE *f);
+
+This provides a more detailed report than talloc_report(). It will
+recursively print the entire tree of memory referenced by the
+pointer. References in the tree are shown by giving the name of the
+pointer that is referenced.
+
+You can pass NULL for the pointer, in which case a report is printed
+for the top level memory context, but only if
+talloc_enable_leak_report() or talloc_enable_leak_report_full() has
+been called.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_leak_report(void);
+
+This enables calling of talloc_report(NULL, stderr) when the program
+exits. In Samba4 this is enabled by using the --leak-report command
+line option.
+
+For it to be useful, this function must be called before any other
+talloc function as it establishes a "null context" that acts as the
+top of the tree. If you don't call this function first then passing
+NULL to talloc_report() or talloc_report_full() won't give you the
+full tree printout.
+
+Here is a typical talloc report:
+
+talloc report on 'null_context' (total 267 bytes in 15 blocks)
+ libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ iconv(UTF8,CP850) contains 42 bytes in 2 blocks
+ libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks
+ iconv(CP850,UTF8) contains 42 bytes in 2 blocks
+ iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks
+ iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_leak_report_full(void);
+
+This enables calling of talloc_report_full(NULL, stderr) when the
+program exits. In Samba4 this is enabled by using the
+--leak-report-full command line option.
+
+For it to be useful, this function must be called before any other
+talloc function as it establishes a "null context" that acts as the
+top of the tree. If you don't call this function first then passing
+NULL to talloc_report() or talloc_report_full() won't give you the
+full tree printout.
+
+Here is a typical full report:
+
+full talloc report on 'root' (total 18 bytes in 8 blocks)
+ p1 contains 18 bytes in 7 blocks (ref 0)
+ r1 contains 13 bytes in 2 blocks (ref 0)
+ reference to: p2
+ p2 contains 1 bytes in 1 blocks (ref 1)
+ x3 contains 1 bytes in 1 blocks (ref 0)
+ x2 contains 1 bytes in 1 blocks (ref 0)
+ x1 contains 1 bytes in 1 blocks (ref 0)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_enable_null_tracking(void);
+
+This enables tracking of the NULL memory context without enabling leak
+reporting on exit. Useful for when you want to do your own leak
+reporting call via talloc_report_null_full();
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_disable_null_tracking(void);
+
+This disables tracking of the NULL memory context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_zero(const void *ctx, type);
+
+The talloc_zero() macro is equivalent to::
+
+ ptr = talloc(ctx, type);
+ if (ptr) memset(ptr, 0, sizeof(type));
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_zero_size(const void *ctx, size_t size)
+
+The talloc_zero_size() function is useful when you don't have a known type
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_memdup(const void *ctx, const void *p, size_t size);
+
+The talloc_memdup() function is equivalent to::
+
+ ptr = talloc_size(ctx, size);
+ if (ptr) memcpy(ptr, p, size);
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_strdup(const void *ctx, const char *p);
+
+The talloc_strdup() function is equivalent to::
+
+ ptr = talloc_size(ctx, strlen(p)+1);
+ if (ptr) memcpy(ptr, p, strlen(p)+1);
+
+This functions sets the name of the new pointer to the passed
+string. This is equivalent to::
+
+ talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_strndup(const void *t, const char *p, size_t n);
+
+The talloc_strndup() function is the talloc equivalent of the C
+library function strndup()
+
+This functions sets the name of the new pointer to the passed
+string. This is equivalent to:
+ talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_append_string(const void *t, char *orig, const char *append);
+
+The talloc_append_string() function appends the given formatted
+string to the given string.
+
+This function sets the name of the new pointer to the new
+string. This is equivalent to::
+
+ talloc_set_name_const(ptr, ptr)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap);
+
+The talloc_vasprintf() function is the talloc equivalent of the C
+library function vasprintf()
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf(const void *t, const char *fmt, ...);
+
+The talloc_asprintf() function is the talloc equivalent of the C
+library function asprintf()
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf_append(char *s, const char *fmt, ...);
+
+The talloc_asprintf_append() function appends the given formatted
+string to the given string.
+Use this variant when the string in the current talloc buffer may
+have been truncated in length.
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...);
+
+The talloc_asprintf_append() function appends the given formatted
+string to the end of the currently allocated talloc buffer.
+Use this variant when the string in the current talloc buffer has
+not been changed.
+
+This functions sets the name of the new pointer to the new
+string. This is equivalent to::
+
+ talloc_set_name_const(ptr, ptr)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+((type *)talloc_array(const void *ctx, type, unsigned int count);
+
+The talloc_array() macro is equivalent to::
+
+ (type *)talloc_size(ctx, sizeof(type) * count);
+
+except that it provides integer overflow protection for the multiply,
+returning NULL if the multiply overflows.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_array_size(const void *ctx, size_t size, unsigned int count);
+
+The talloc_array_size() function is useful when the type is not
+known. It operates in the same way as talloc_array(), but takes a size
+instead of a type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, unsigned int count);
+
+The talloc_ptrtype() macro should be used when you have a pointer to an array
+and want to allocate memory of an array to point at with this pointer. When compiling
+with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size()
+and talloc_get_name() will return the current location in the source file.
+and not the type.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size);
+
+This is a non-macro version of talloc_realloc(), which is useful
+as libraries sometimes want a ralloc function pointer. A realloc()
+implementation encapsulates the functionality of malloc(), free() and
+realloc() in one call, which is why it is useful to be able to pass
+around a single function pointer.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_autofree_context(void);
+
+This is a handy utility function that returns a talloc context
+which will be automatically freed on program exit. This can be used
+to reduce the noise in memory leak reports.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_check_name(const void *ptr, const char *name);
+
+This function checks if a pointer has the specified name. If it does
+then the pointer is returned. It it doesn't then NULL is returned.
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_get_type(const void *ptr, type);
+
+This macro allows you to do type checking on talloc pointers. It is
+particularly useful for void* private pointers. It is equivalent to
+this::
+
+ (type *)talloc_check_name(ptr, #type)
+
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+talloc_set_type(const void *ptr, type);
+
+This macro allows you to force the name of a pointer to be of a
+particular type. This can be used in conjunction with
+talloc_get_type() to do type checking on void* pointers.
+
+It is equivalent to this::
+
+ talloc_set_name_const(ptr, #type)
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+talloc_get_size(const void *ctx);
+
+This function lets you know the amount of memory allocated so far by
+this context. It does NOT account for subcontext memory.
+This can be used to calculate the size of an array.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void *talloc_find_parent_byname(const void *ctx, const char *name);
+
+Find a parent memory context of the current context that has the given
+name. This can be very useful in complex programs where it may be
+difficult to pass all information down to the level you need, but you
+know the structure you want is a parent of another context.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+(type *)talloc_find_parent_bytype(ctx, type);
+
+Like talloc_find_parent_byname() but takes a type, making it typesafe.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_log_fn(void (*log_fn)(const char *message));
+
+This function sets a logging function that talloc will use for
+warnings and errors. By default talloc will not print any warnings or
+errors.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+void talloc_set_log_stderr(void)
+
+This sets the talloc log function to write log messages to stderr.
diff --git a/lib/talloc/talloc_testsuite.h b/lib/talloc/talloc_testsuite.h
new file mode 100644
index 0000000..acb9701
--- /dev/null
+++ b/lib/talloc/talloc_testsuite.h
@@ -0,0 +1,7 @@
+#ifndef __LIB_TALLOC_TALLOC_TESTSUITE_H__
+#define __LIB_TALLOC_TALLOC_TESTSUITE_H__
+
+struct torture_context;
+bool torture_local_talloc(struct torture_context *tctx);
+
+#endif
diff --git a/lib/talloc/test_magic_differs.sh b/lib/talloc/test_magic_differs.sh
new file mode 100755
index 0000000..1b6ba2e
--- /dev/null
+++ b/lib/talloc/test_magic_differs.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# This test ensures that two different talloc processes do not use the same
+# magic value to lessen the opportunity for transferrable attacks.
+
+echo "test: magic differs"
+
+helper=$1
+m1=$($helper)
+m2=$($helper)
+
+if [ $m1 -eq $m2 ]; then
+ echo "failure: magic remained the same between executions ($m1 vs $m2)"
+ exit 1
+fi
+
+echo "success: magic differs"
diff --git a/lib/talloc/test_magic_differs_helper.c b/lib/talloc/test_magic_differs_helper.c
new file mode 100644
index 0000000..6798827
--- /dev/null
+++ b/lib/talloc/test_magic_differs_helper.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include "talloc.h"
+
+/*
+ * This program is called by a testing shell script in order to ensure that
+ * if the library is loaded into different processes it uses different magic
+ * values in order to thwart security attacks.
+ */
+int main(int argc, char *argv[]) {
+ printf("%i\n", talloc_test_get_magic());
+ return 0;
+}
diff --git a/lib/talloc/test_pytalloc.c b/lib/talloc/test_pytalloc.c
new file mode 100644
index 0000000..fb38585
--- /dev/null
+++ b/lib/talloc/test_pytalloc.c
@@ -0,0 +1,230 @@
+/*
+ Samba Unix SMB/CIFS implementation.
+
+ C utilities for the pytalloc test suite.
+ Provides the "_test_pytalloc" Python module.
+
+ NOTE: Please read talloc_guide.txt for full documentation
+
+ Copyright (C) Petr Viktorin 2015
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include <talloc.h>
+#include <pytalloc.h>
+
+static PyObject *testpytalloc_new(PyTypeObject *mod,
+ PyObject *Py_UNUSED(ignored))
+{
+ char *obj = talloc_strdup(NULL, "This is a test string");;
+ return pytalloc_steal(pytalloc_GetObjectType(), obj);
+}
+
+static PyObject *testpytalloc_get_object_type(PyObject *mod,
+ PyObject *Py_UNUSED(ignored))
+{
+ PyObject *type = (PyObject *)pytalloc_GetObjectType();
+ Py_INCREF(type);
+ return type;
+}
+
+static PyObject *testpytalloc_base_new(PyTypeObject *mod,
+ PyObject *Py_UNUSED(ignored))
+{
+ char *obj = talloc_strdup(NULL, "This is a test string for a BaseObject");;
+ return pytalloc_steal(pytalloc_GetBaseObjectType(), obj);
+}
+
+static PyObject *testpytalloc_base_get_object_type(PyObject *mod,
+ PyObject *Py_UNUSED(ignored))
+{
+ PyObject *type = (PyObject *)pytalloc_GetBaseObjectType();
+ Py_INCREF(type);
+ return type;
+}
+
+static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) {
+ PyObject *source = NULL;
+ void *ptr;
+
+ if (!PyArg_ParseTuple(args, "O!", pytalloc_GetObjectType(), &source))
+ return NULL;
+
+ ptr = pytalloc_get_ptr(source);
+ return pytalloc_reference_ex(pytalloc_GetObjectType(), ptr, ptr);
+}
+
+static PyObject *testpytalloc_base_reference(PyObject *mod, PyObject *args) {
+ PyObject *source = NULL;
+ void *mem_ctx;
+
+ if (!PyArg_ParseTuple(args, "O!", pytalloc_GetBaseObjectType(), &source)) {
+ return NULL;
+ }
+ mem_ctx = pytalloc_get_mem_ctx(source);
+ return pytalloc_reference_ex(pytalloc_GetBaseObjectType(), mem_ctx, mem_ctx);
+}
+
+static PyMethodDef test_talloc_methods[] = {
+ { "new", (PyCFunction)testpytalloc_new, METH_NOARGS,
+ "create a talloc Object with a testing string"},
+ { "get_object_type", (PyCFunction)testpytalloc_get_object_type, METH_NOARGS,
+ "call pytalloc_GetObjectType"},
+ { "base_new", (PyCFunction)testpytalloc_base_new, METH_NOARGS,
+ "create a talloc BaseObject with a testing string"},
+ { "base_get_object_type", (PyCFunction)testpytalloc_base_get_object_type, METH_NOARGS,
+ "call pytalloc_GetBaseObjectType"},
+ { "reference", (PyCFunction)testpytalloc_reference, METH_VARARGS,
+ "call pytalloc_reference_ex"},
+ { "base_reference", (PyCFunction)testpytalloc_base_reference, METH_VARARGS,
+ "call pytalloc_reference_ex"},
+ {0}
+};
+
+static PyTypeObject DObject_Type;
+
+static int dobject_destructor(void *ptr)
+{
+ PyObject *destructor_func = *talloc_get_type(ptr, PyObject*);
+ PyObject *ret;
+ ret = PyObject_CallObject(destructor_func, NULL);
+ Py_DECREF(destructor_func);
+ if (ret == NULL) {
+ PyErr_Print();
+ } else {
+ Py_DECREF(ret);
+ }
+ return 0;
+}
+
+static PyObject *dobject_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *destructor_func = NULL;
+ PyObject **obj;
+
+ if (!PyArg_ParseTuple(args, "O", &destructor_func))
+ return NULL;
+ Py_INCREF(destructor_func);
+
+ obj = talloc(NULL, PyObject*);
+ *obj = destructor_func;
+
+ talloc_set_destructor((void*)obj, dobject_destructor);
+ return pytalloc_steal(&DObject_Type, obj);
+}
+
+static PyTypeObject DObject_Type = {
+ .tp_name = "_test_pytalloc.DObject",
+ .tp_basicsize = sizeof(pytalloc_Object),
+ .tp_methods = NULL,
+ .tp_new = dobject_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "test talloc object that calls a function when underlying data is freed\n",
+};
+
+static PyTypeObject DBaseObject_Type;
+
+static int d_base_object_destructor(void *ptr)
+{
+ PyObject *destructor_func = *talloc_get_type(ptr, PyObject*);
+ PyObject *ret;
+ ret = PyObject_CallObject(destructor_func, NULL);
+ Py_DECREF(destructor_func);
+ if (ret == NULL) {
+ PyErr_Print();
+ } else {
+ Py_DECREF(ret);
+ }
+ return 0;
+}
+
+static PyObject *d_base_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *destructor_func = NULL;
+ PyObject **obj;
+
+ if (!PyArg_ParseTuple(args, "O", &destructor_func))
+ return NULL;
+ Py_INCREF(destructor_func);
+
+ obj = talloc(NULL, PyObject*);
+ *obj = destructor_func;
+
+ talloc_set_destructor((void*)obj, d_base_object_destructor);
+ return pytalloc_steal(&DBaseObject_Type, obj);
+}
+
+static PyTypeObject DBaseObject_Type = {
+ .tp_name = "_test_pytalloc.DBaseObject",
+ .tp_methods = NULL,
+ .tp_new = d_base_object_new,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "test talloc object that calls a function when underlying data is freed\n",
+};
+
+#define MODULE_DOC PyDoc_STR("Test utility module for pytalloc")
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "_test_pytalloc",
+ .m_doc = PyDoc_STR("Test utility module for pytalloc"),
+ .m_size = -1,
+ .m_methods = test_talloc_methods,
+};
+
+static PyObject *module_init(void);
+static PyObject *module_init(void)
+{
+ PyObject *m;
+
+ DObject_Type.tp_base = pytalloc_GetObjectType();
+ if (PyType_Ready(&DObject_Type) < 0) {
+ return NULL;
+ }
+
+ DBaseObject_Type.tp_basicsize = pytalloc_BaseObject_size();
+ DBaseObject_Type.tp_base = pytalloc_GetBaseObjectType();
+ if (PyType_Ready(&DBaseObject_Type) < 0) {
+ return NULL;
+ }
+
+ m = PyModule_Create(&moduledef);
+
+ if (m == NULL) {
+ return NULL;
+ }
+
+ Py_INCREF(&DObject_Type);
+ Py_INCREF(DObject_Type.tp_base);
+ PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type);
+
+ Py_INCREF(&DBaseObject_Type);
+ Py_INCREF(DBaseObject_Type.tp_base);
+ PyModule_AddObject(m, "DBaseObject", (PyObject *)&DBaseObject_Type);
+
+ return m;
+}
+
+
+PyMODINIT_FUNC PyInit__test_pytalloc(void);
+PyMODINIT_FUNC PyInit__test_pytalloc(void)
+{
+ return module_init();
+}
diff --git a/lib/talloc/test_pytalloc.py b/lib/talloc/test_pytalloc.py
new file mode 100644
index 0000000..809510f
--- /dev/null
+++ b/lib/talloc/test_pytalloc.py
@@ -0,0 +1,189 @@
+#!/usr/bin/env python3
+# Simple tests for the talloc python bindings.
+# Copyright (C) 2015 Petr Viktorin <pviktori@redhat.com>
+
+import unittest
+import subprocess
+import sys
+import gc
+
+import talloc
+import _test_pytalloc
+
+
+def dummy_func():
+ pass
+
+
+class TallocTests(unittest.TestCase):
+
+ def test_report_full(self):
+ # report_full is hardcoded to print to stdout, so use a subprocess
+ process = subprocess.Popen([
+ sys.executable, '-c',
+ """if True:
+ import talloc, _test_pytalloc
+ obj = _test_pytalloc.new()
+ talloc.report_full(obj)
+ """
+ ], stdout=subprocess.PIPE)
+ output, stderr = process.communicate()
+ output = str(output)
+ self.assertTrue("full talloc report on 'talloc.Object" in output)
+ self.assertTrue("This is a test string" in output)
+
+ def test_totalblocks(self):
+ obj = _test_pytalloc.new()
+ # Two blocks: the string, and the name
+ self.assertEqual(talloc.total_blocks(obj), 2)
+
+ def test_repr(self):
+ obj = _test_pytalloc.new()
+ prefix = '<talloc.Object talloc object at'
+ self.assertTrue(repr(obj).startswith(prefix))
+ self.assertEqual(repr(obj), str(obj))
+
+ def test_base_repr(self):
+ obj = _test_pytalloc.base_new()
+ prefix = '<talloc.BaseObject talloc based object at'
+ self.assertTrue(repr(obj).startswith(prefix))
+ self.assertEqual(repr(obj), str(obj))
+
+ def test_destructor(self):
+ # Check correct lifetime of the talloc'd data
+ lst = []
+ obj = _test_pytalloc.DObject(lambda: lst.append('dead'))
+ self.assertEqual(lst, [])
+ del obj
+ gc.collect()
+ self.assertEqual(lst, ['dead'])
+
+ def test_base_destructor(self):
+ # Check correct lifetime of the talloc'd data
+ lst = []
+ obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
+ self.assertEqual(lst, [])
+ del obj
+ gc.collect()
+ self.assertEqual(lst, ['dead'])
+
+
+class TallocComparisonTests(unittest.TestCase):
+
+ def test_compare_same(self):
+ obj1 = _test_pytalloc.new()
+ self.assertTrue(obj1 == obj1)
+ self.assertFalse(obj1 != obj1)
+ self.assertTrue(obj1 <= obj1)
+ self.assertFalse(obj1 < obj1)
+ self.assertTrue(obj1 >= obj1)
+ self.assertFalse(obj1 > obj1)
+
+ def test_compare_different(self):
+ # object comparison is consistent
+ obj1, obj2 = sorted([
+ _test_pytalloc.new(),
+ _test_pytalloc.new()])
+ self.assertFalse(obj1 == obj2)
+ self.assertTrue(obj1 != obj2)
+ self.assertTrue(obj1 <= obj2)
+ self.assertTrue(obj1 < obj2)
+ self.assertFalse(obj1 >= obj2)
+ self.assertFalse(obj1 > obj2)
+
+ def test_compare_different_types(self):
+ # object comparison falls back to comparing types
+ if sys.version_info >= (3, 0):
+ # In Python 3, types are unorderable -- nothing to test
+ return
+ if talloc.Object < _test_pytalloc.DObject:
+ obj1 = _test_pytalloc.new()
+ obj2 = _test_pytalloc.DObject(dummy_func)
+ else:
+ obj2 = _test_pytalloc.new()
+ obj1 = _test_pytalloc.DObject(dummy_func)
+ self.assertFalse(obj1 == obj2)
+ self.assertTrue(obj1 != obj2)
+ self.assertTrue(obj1 <= obj2)
+ self.assertTrue(obj1 < obj2)
+ self.assertFalse(obj1 >= obj2)
+ self.assertFalse(obj1 > obj2)
+
+
+class TallocBaseComparisonTests(unittest.TestCase):
+
+ def test_compare_same(self):
+ obj1 = _test_pytalloc.base_new()
+ self.assertTrue(obj1 == obj1)
+ self.assertFalse(obj1 != obj1)
+ self.assertTrue(obj1 <= obj1)
+ self.assertFalse(obj1 < obj1)
+ self.assertTrue(obj1 >= obj1)
+ self.assertFalse(obj1 > obj1)
+
+ def test_compare_different(self):
+ # object comparison is consistent
+ obj1, obj2 = sorted([
+ _test_pytalloc.base_new(),
+ _test_pytalloc.base_new()])
+ self.assertFalse(obj1 == obj2)
+ self.assertTrue(obj1 != obj2)
+ self.assertTrue(obj1 <= obj2)
+ self.assertTrue(obj1 < obj2)
+ self.assertFalse(obj1 >= obj2)
+ self.assertFalse(obj1 > obj2)
+
+ def test_compare_different_types(self):
+ # object comparison falls back to comparing types
+ if sys.version_info >= (3, 0):
+ # In Python 3, types are unorderable -- nothing to test
+ return
+ if talloc.BaseObject < _test_pytalloc.DBaseObject:
+ obj1 = _test_pytalloc.base_new()
+ obj2 = _test_pytalloc.DBaseObject(dummy_func)
+ else:
+ obj2 = _test_pytalloc.base_new()
+ obj1 = _test_pytalloc.DBaseObject(dummy_func)
+ self.assertFalse(obj1 == obj2)
+ self.assertTrue(obj1 != obj2)
+ self.assertTrue(obj1 <= obj2)
+ self.assertTrue(obj1 < obj2)
+ self.assertFalse(obj1 >= obj2)
+ self.assertFalse(obj1 > obj2)
+
+
+class TallocUtilTests(unittest.TestCase):
+
+ def test_get_type(self):
+ self.assertTrue(talloc.Object is _test_pytalloc.get_object_type())
+
+ def test_reference(self):
+ # Check correct lifetime of the talloc'd data with multiple references
+ lst = []
+ obj = _test_pytalloc.DObject(lambda: lst.append('dead'))
+ ref = _test_pytalloc.reference(obj)
+ del obj
+ gc.collect()
+ self.assertEqual(lst, [])
+ del ref
+ gc.collect()
+ self.assertEqual(lst, ['dead'])
+
+ def test_get_base_type(self):
+ self.assertTrue(talloc.BaseObject is _test_pytalloc.base_get_object_type())
+
+ def test_base_reference(self):
+ # Check correct lifetime of the talloc'd data with multiple references
+ lst = []
+ obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
+ ref = _test_pytalloc.base_reference(obj)
+ del obj
+ gc.collect()
+ self.assertEqual(lst, [])
+ del ref
+ gc.collect()
+ self.assertEqual(lst, ['dead'])
+
+
+if __name__ == '__main__':
+ unittest.TestProgram()
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
new file mode 100644
index 0000000..282ebc6
--- /dev/null
+++ b/lib/talloc/testsuite.c
@@ -0,0 +1,2288 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of talloc routines.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include <talloc.h>
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#include <unistd.h>
+#include <sys/wait.h>
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+
+#include "talloc_testsuite.h"
+
+static struct timeval private_timeval_current(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv;
+}
+
+static double private_timeval_elapsed(struct timeval *tv)
+{
+ struct timeval tv2 = private_timeval_current();
+ return (tv2.tv_sec - tv->tv_sec) +
+ (tv2.tv_usec - tv->tv_usec)*1.0e-6;
+}
+
+#define torture_assert(test, expr, str) if (!(expr)) { \
+ printf("failure: %s [\n%s: Expression %s failed: %s\n]\n", \
+ test, __location__, #expr, str); \
+ return false; \
+}
+
+#define torture_assert_str_equal(test, arg1, arg2, desc) \
+ if (arg1 == NULL && arg2 == NULL) { /* OK, both NULL == equal */ \
+ } else if (arg1 == NULL || arg2 == NULL) { \
+ return false; \
+ } else if (strcmp(arg1, arg2)) { \
+ printf("failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
+ test, __location__, arg1, arg2, desc); \
+ return false; \
+ }
+
+#define CHECK_SIZE(test, ptr, tsize) do { \
+ if (talloc_total_size(ptr) != (tsize)) { \
+ printf("failed: %s [\n%s: wrong '%s' tree size: got %u expected %u\n]\n", \
+ test, __location__, #ptr, \
+ (unsigned)talloc_total_size(ptr), \
+ (unsigned)tsize); \
+ talloc_report_full(ptr, stdout); \
+ return false; \
+ } \
+} while (0)
+
+#define CHECK_BLOCKS(test, ptr, tblocks) do { \
+ if (talloc_total_blocks(ptr) != (tblocks)) { \
+ printf("failed: %s [\n%s: wrong '%s' tree blocks: got %u expected %u\n]\n", \
+ test, __location__, #ptr, \
+ (unsigned)talloc_total_blocks(ptr), \
+ (unsigned)tblocks); \
+ talloc_report_full(ptr, stdout); \
+ return false; \
+ } \
+} while (0)
+
+#define CHECK_PARENT(test, ptr, parent) do { \
+ if (talloc_parent(ptr) != (parent)) { \
+ printf("failed: %s [\n%s: '%s' has wrong parent: got %p expected %p\n]\n", \
+ test, __location__, #ptr, \
+ talloc_parent(ptr), \
+ (parent)); \
+ talloc_report_full(ptr, stdout); \
+ talloc_report_full(parent, stdout); \
+ talloc_report_full(NULL, stdout); \
+ return false; \
+ } \
+} while (0)
+
+static unsigned int test_abort_count;
+
+#if 0
+static void test_abort_fn(const char *reason)
+{
+ printf("# test_abort_fn(%s)\n", reason);
+ test_abort_count++;
+}
+
+static void test_abort_start(void)
+{
+ test_abort_count = 0;
+ talloc_set_abort_fn(test_abort_fn);
+}
+#endif
+
+static void test_abort_stop(void)
+{
+ test_abort_count = 0;
+ talloc_set_abort_fn(NULL);
+}
+
+static void test_log_stdout(const char *message)
+{
+ fprintf(stdout, "%s", message);
+}
+
+/*
+ test references
+*/
+static bool test_ref1(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref1\n# SINGLE REFERENCE FREE\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ p2 = talloc_named_const(p1, 1, "p2");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 2, "x2");
+ talloc_named_const(p1, 3, "x3");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref1", p1, 5);
+ CHECK_BLOCKS("ref1", p2, 1);
+ CHECK_BLOCKS("ref1", ref, 1);
+ CHECK_BLOCKS("ref1", r1, 2);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_unlink(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref1", p1, 5);
+ CHECK_BLOCKS("ref1", p2, 1);
+ CHECK_BLOCKS("ref1", r1, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref1", r1, 1);
+
+ fprintf(stderr, "Freeing r1\n");
+ talloc_free(r1);
+ talloc_report_full(NULL, stderr);
+
+ fprintf(stderr, "Testing NULL\n");
+ if (talloc_reference(root, NULL)) {
+ return false;
+ }
+
+ CHECK_BLOCKS("ref1", root, 1);
+
+ CHECK_SIZE("ref1", root, 0);
+
+ talloc_free(root);
+ printf("success: ref1\n");
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref2(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref2\n# DOUBLE REFERENCE FREE\n");
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", p1, 5);
+ CHECK_BLOCKS("ref2", p2, 1);
+ CHECK_BLOCKS("ref2", r1, 2);
+
+ fprintf(stderr, "Freeing ref\n");
+ talloc_unlink(r1, ref);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", p1, 5);
+ CHECK_BLOCKS("ref2", p2, 1);
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_free(p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", p1, 4);
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref2", r1, 1);
+
+ fprintf(stderr, "Freeing r1\n");
+ talloc_free(r1);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("ref2", root, 0);
+
+ talloc_free(root);
+ printf("success: ref2\n");
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref3(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref3\n# PARENT REFERENCE FREE\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ p2 = talloc_named_const(root, 1, "p2");
+ r1 = talloc_named_const(p1, 1, "r1");
+ ref = talloc_reference(p2, r1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref3", p1, 2);
+ CHECK_BLOCKS("ref3", p2, 2);
+ CHECK_BLOCKS("ref3", r1, 1);
+ CHECK_BLOCKS("ref3", ref, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref3", p2, 2);
+ CHECK_BLOCKS("ref3", r1, 1);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_free(p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("ref3", root, 0);
+
+ talloc_free(root);
+
+ printf("success: ref3\n");
+ return true;
+}
+
+/*
+ test references
+*/
+static bool test_ref4(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: ref4\n# REFERRER REFERENCE FREE\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(root, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref4", p1, 5);
+ CHECK_BLOCKS("ref4", p2, 1);
+ CHECK_BLOCKS("ref4", ref, 1);
+ CHECK_BLOCKS("ref4", r1, 2);
+
+ fprintf(stderr, "Freeing r1\n");
+ talloc_free(r1);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref4", p1, 5);
+ CHECK_BLOCKS("ref4", p2, 1);
+
+ fprintf(stderr, "Freeing p2\n");
+ talloc_free(p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("ref4", p1, 4);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("ref4", root, 0);
+
+ talloc_free(root);
+
+ printf("success: ref4\n");
+ return true;
+}
+
+
+/*
+ test references
+*/
+static bool test_unlink1(void)
+{
+ void *root, *p1, *p2, *ref, *r1;
+
+ printf("test: unlink\n# UNLINK\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "p1");
+ talloc_named_const(p1, 1, "x1");
+ talloc_named_const(p1, 1, "x2");
+ talloc_named_const(p1, 1, "x3");
+ p2 = talloc_named_const(p1, 1, "p2");
+
+ r1 = talloc_named_const(p1, 1, "r1");
+ ref = talloc_reference(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("unlink", p1, 7);
+ CHECK_BLOCKS("unlink", p2, 1);
+ CHECK_BLOCKS("unlink", ref, 1);
+ CHECK_BLOCKS("unlink", r1, 2);
+
+ fprintf(stderr, "Unreferencing r1\n");
+ talloc_unlink(r1, p2);
+ talloc_report_full(root, stderr);
+
+ CHECK_BLOCKS("unlink", p1, 6);
+ CHECK_BLOCKS("unlink", p2, 1);
+ CHECK_BLOCKS("unlink", r1, 1);
+
+ fprintf(stderr, "Freeing p1\n");
+ talloc_free(p1);
+ talloc_report_full(root, stderr);
+
+ CHECK_SIZE("unlink", root, 0);
+
+ talloc_free(root);
+
+ printf("success: unlink\n");
+ return true;
+}
+
+static int fail_destructor(void *ptr)
+{
+ return -1;
+}
+
+/*
+ miscellaneous tests to try to get a higher test coverage percentage
+*/
+static bool test_misc(void)
+{
+ void *root, *p1;
+ char *p2;
+ double *d;
+ const char *name;
+
+ printf("test: misc\n# MISCELLANEOUS\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_size(root, 0x7fffffff);
+ torture_assert("misc", !p1, "failed: large talloc allowed\n");
+
+ p1 = talloc_strdup(root, "foo");
+ talloc_increase_ref_count(p1);
+ talloc_increase_ref_count(p1);
+ talloc_increase_ref_count(p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_unlink(NULL, p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_unlink(NULL, p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ p2 = talloc_strdup(p1, "foo");
+ torture_assert("misc", talloc_unlink(root, p2) == -1,
+ "failed: talloc_unlink() of non-reference context should return -1\n");
+ torture_assert("misc", talloc_unlink(p1, p2) == 0,
+ "failed: talloc_unlink() of parent should succeed\n");
+ talloc_unlink(NULL, p1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+
+ name = talloc_set_name(p1, "my name is %s", "foo");
+ torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo",
+ "failed: wrong name after talloc_set_name(my name is foo)");
+ torture_assert_str_equal("misc", talloc_get_name(p1), name,
+ "failed: wrong name after talloc_set_name(my name is foo)");
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+
+ talloc_set_name_const(p1, NULL);
+ torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED",
+ "failed: wrong name after talloc_set_name(NULL)");
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+
+ torture_assert("misc", talloc_free(NULL) == -1,
+ "talloc_free(NULL) should give -1\n");
+
+ talloc_set_destructor(p1, fail_destructor);
+ torture_assert("misc", talloc_free(p1) == -1,
+ "Failed destructor should cause talloc_free to fail\n");
+ talloc_set_destructor(p1, NULL);
+
+ talloc_report(root, stderr);
+
+
+ p2 = (char *)talloc_zero_size(p1, 20);
+ torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n");
+ talloc_free(p2);
+
+ torture_assert("misc", talloc_strdup(root, NULL) == NULL,
+ "failed: strdup on NULL should give NULL\n");
+
+ p2 = talloc_strndup(p1, "foo", 2);
+ torture_assert("misc", strcmp("fo", p2) == 0,
+ "strndup doesn't work\n");
+ p2 = talloc_asprintf_append_buffer(p2, "o%c", 'd');
+ torture_assert("misc", strcmp("food", p2) == 0,
+ "talloc_asprintf_append_buffer doesn't work\n");
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 3);
+
+ p2 = talloc_asprintf_append_buffer(NULL, "hello %s", "world");
+ torture_assert("misc", strcmp("hello world", p2) == 0,
+ "talloc_asprintf_append_buffer doesn't work\n");
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 3);
+ talloc_free(p2);
+
+ d = talloc_array(p1, double, 0x20000000);
+ torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+ d = talloc_realloc(p1, d, double, 0x20000000);
+ torture_assert("misc", !d, "failed: integer overflow not detected\n");
+
+ talloc_free(p1);
+ CHECK_BLOCKS("misc", root, 1);
+
+ p1 = talloc_named(root, 100, "%d bytes", 100);
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+ talloc_unlink(root, p1);
+
+ p1 = talloc_init("%d bytes", 200);
+ p2 = talloc_asprintf(p1, "my test '%s'", "string");
+ torture_assert_str_equal("misc", p2, "my test 'string'",
+ "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\"");
+ CHECK_BLOCKS("misc", p1, 3);
+ CHECK_SIZE("misc", p2, 17);
+ CHECK_BLOCKS("misc", root, 1);
+ talloc_unlink(NULL, p1);
+
+ p1 = talloc_named_const(root, 10, "p1");
+ p2 = (char *)talloc_named_const(root, 20, "p2");
+ (void)talloc_reference(p1, p2);
+ talloc_report_full(root, stderr);
+ talloc_unlink(root, p2);
+ talloc_report_full(root, stderr);
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 2);
+ CHECK_BLOCKS("misc", root, 3);
+ talloc_unlink(p1, p2);
+ talloc_unlink(root, p1);
+
+ p1 = talloc_named_const(root, 10, "p1");
+ p2 = (char *)talloc_named_const(root, 20, "p2");
+ (void)talloc_reference(NULL, p2);
+ talloc_report_full(root, stderr);
+ talloc_unlink(root, p2);
+ talloc_report_full(root, stderr);
+ CHECK_BLOCKS("misc", p2, 1);
+ CHECK_BLOCKS("misc", p1, 1);
+ CHECK_BLOCKS("misc", root, 2);
+ talloc_unlink(NULL, p2);
+ talloc_unlink(root, p1);
+
+ /* Test that talloc_unlink is a no-op */
+
+ torture_assert("misc", talloc_unlink(root, NULL) == -1,
+ "failed: talloc_unlink(root, NULL) == -1\n");
+
+ talloc_report(root, stderr);
+ talloc_report(NULL, stderr);
+
+ CHECK_SIZE("misc", root, 0);
+
+ talloc_free(root);
+
+ CHECK_SIZE("misc", NULL, 0);
+
+ talloc_enable_null_tracking_no_autofree();
+ talloc_enable_leak_report();
+ talloc_enable_leak_report_full();
+
+ printf("success: misc\n");
+
+ return true;
+}
+
+
+/*
+ test realloc
+*/
+static bool test_realloc(void)
+{
+ void *root, *p1, *p2;
+
+ printf("test: realloc\n# REALLOC\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_size(root, 10);
+ CHECK_SIZE("realloc", p1, 10);
+
+ p1 = talloc_realloc_size(NULL, p1, 20);
+ CHECK_SIZE("realloc", p1, 20);
+
+ talloc_new(p1);
+
+ p2 = talloc_realloc_size(p1, NULL, 30);
+
+ talloc_new(p1);
+
+ p2 = talloc_realloc_size(p1, p2, 40);
+
+ CHECK_SIZE("realloc", p2, 40);
+ CHECK_SIZE("realloc", root, 60);
+ CHECK_BLOCKS("realloc", p1, 4);
+
+ p1 = talloc_realloc_size(NULL, p1, 20);
+ CHECK_SIZE("realloc", p1, 60);
+
+ talloc_increase_ref_count(p2);
+ torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL,
+ "failed: talloc_realloc() on a referenced pointer should fail\n");
+ CHECK_BLOCKS("realloc", p1, 4);
+
+ talloc_realloc_size(NULL, p2, 0);
+ talloc_realloc_size(NULL, p2, 0);
+ CHECK_BLOCKS("realloc", p1, 4);
+ talloc_realloc_size(p1, p2, 0);
+ CHECK_BLOCKS("realloc", p1, 3);
+
+ torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL,
+ "failed: oversize talloc should fail\n");
+
+ talloc_realloc_size(NULL, p1, 0);
+ CHECK_BLOCKS("realloc", root, 4);
+ talloc_realloc_size(root, p1, 0);
+ CHECK_BLOCKS("realloc", root, 1);
+
+ CHECK_SIZE("realloc", root, 0);
+
+ talloc_free(root);
+
+ printf("success: realloc\n");
+
+ return true;
+}
+
+/*
+ test realloc with a child
+*/
+static bool test_realloc_child(void)
+{
+ void *root;
+ struct el2 {
+ const char *name;
+ } *el2, *el2_2, *el2_3, **el_list_save;
+ struct el1 {
+ int count;
+ struct el2 **list, **list2, **list3;
+ } *el1;
+
+ printf("test: REALLOC WITH CHILD\n");
+
+ root = talloc_new(NULL);
+
+ el1 = talloc(root, struct el1);
+ el1->list = talloc(el1, struct el2 *);
+ el1->list[0] = talloc(el1->list, struct el2);
+ el1->list[0]->name = talloc_strdup(el1->list[0], "testing");
+
+ el1->list2 = talloc(el1, struct el2 *);
+ el1->list2[0] = talloc(el1->list2, struct el2);
+ el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2");
+
+ el1->list3 = talloc(el1, struct el2 *);
+ el1->list3[0] = talloc(el1->list3, struct el2);
+ el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2");
+
+ el2 = talloc(el1->list, struct el2);
+ CHECK_PARENT("el2", el2, el1->list);
+ el2_2 = talloc(el1->list2, struct el2);
+ CHECK_PARENT("el2", el2_2, el1->list2);
+ el2_3 = talloc(el1->list3, struct el2);
+ CHECK_PARENT("el2", el2_3, el1->list3);
+
+ el_list_save = el1->list;
+ el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100);
+ if (el1->list == el_list_save) {
+ printf("failure: talloc_realloc didn't move pointer");
+ return false;
+ }
+
+ CHECK_PARENT("el1_after_realloc", el1->list, el1);
+ el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200);
+ CHECK_PARENT("el1_after_realloc", el1->list2, el1);
+ el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300);
+ CHECK_PARENT("el1_after_realloc", el1->list3, el1);
+
+ CHECK_PARENT("el2", el2, el1->list);
+ CHECK_PARENT("el2", el2_2, el1->list2);
+ CHECK_PARENT("el2", el2_3, el1->list3);
+
+ /* Finally check realloc with multiple children */
+ el1 = talloc_realloc(root, el1, struct el1, 100);
+ CHECK_PARENT("el1->list", el1->list, el1);
+ CHECK_PARENT("el1->list2", el1->list2, el1);
+ CHECK_PARENT("el1->list3", el1->list3, el1);
+
+ talloc_free(root);
+
+ printf("success: REALLOC WITH CHILD\n");
+ return true;
+}
+
+/*
+ test type checking
+*/
+static bool test_type(void)
+{
+ void *root;
+ struct el1 {
+ int count;
+ };
+ struct el2 {
+ int count;
+ };
+ struct el1 *el1;
+
+ printf("test: type\n# talloc type checking\n");
+
+ root = talloc_new(NULL);
+
+ el1 = talloc(root, struct el1);
+
+ el1->count = 1;
+
+ torture_assert("type", talloc_get_type(el1, struct el1) == el1,
+ "type check failed on el1\n");
+ torture_assert("type", talloc_get_type(el1, struct el2) == NULL,
+ "type check failed on el1 with el2\n");
+ talloc_set_type(el1, struct el2);
+ torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1,
+ "type set failed on el1 with el2\n");
+
+ talloc_free(root);
+
+ printf("success: type\n");
+ return true;
+}
+
+/*
+ test steal
+*/
+static bool test_steal(void)
+{
+ void *root, *p1, *p2;
+
+ printf("test: steal\n# STEAL\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_array(root, char, 10);
+ CHECK_SIZE("steal", p1, 10);
+
+ p2 = talloc_realloc(root, NULL, char, 20);
+ CHECK_SIZE("steal", p1, 10);
+ CHECK_SIZE("steal", root, 30);
+
+ torture_assert("steal", talloc_steal(p1, NULL) == NULL,
+ "failed: stealing NULL should give NULL\n");
+
+ torture_assert("steal", talloc_steal(p1, p1) == p1,
+ "failed: stealing to ourselves is a nop\n");
+ CHECK_BLOCKS("steal", root, 3);
+ CHECK_SIZE("steal", root, 30);
+
+ talloc_steal(NULL, p1);
+ talloc_steal(NULL, p2);
+ CHECK_BLOCKS("steal", root, 1);
+ CHECK_SIZE("steal", root, 0);
+
+ talloc_free(p1);
+ talloc_steal(root, p2);
+ CHECK_BLOCKS("steal", root, 2);
+ CHECK_SIZE("steal", root, 20);
+
+ talloc_free(p2);
+
+ CHECK_BLOCKS("steal", root, 1);
+ CHECK_SIZE("steal", root, 0);
+
+ talloc_free(root);
+
+ p1 = talloc_size(NULL, 3);
+ talloc_report_full(NULL, stderr);
+ CHECK_SIZE("steal", NULL, 3);
+ talloc_free(p1);
+
+ printf("success: steal\n");
+ return true;
+}
+
+/*
+ test move
+*/
+static bool test_move(void)
+{
+ void *root;
+ struct t_move {
+ char *p;
+ int *x;
+ } *t1, *t2;
+
+ printf("test: move\n# MOVE\n");
+
+ root = talloc_new(NULL);
+
+ t1 = talloc(root, struct t_move);
+ t2 = talloc(root, struct t_move);
+ t1->p = talloc_strdup(t1, "foo");
+ t1->x = talloc(t1, int);
+ *t1->x = 42;
+
+ t2->p = talloc_move(t2, &t1->p);
+ t2->x = talloc_move(t2, &t1->x);
+ torture_assert("move", t1->p == NULL && t1->x == NULL &&
+ strcmp(t2->p, "foo") == 0 && *t2->x == 42,
+ "talloc move failed");
+
+ talloc_free(root);
+
+ printf("success: move\n");
+
+ return true;
+}
+
+/*
+ test talloc_realloc_fn
+*/
+static bool test_realloc_fn(void)
+{
+ void *root, *p1;
+
+ printf("test: realloc_fn\n# talloc_realloc_fn\n");
+
+ root = talloc_new(NULL);
+
+ p1 = talloc_realloc_fn(root, NULL, 10);
+ CHECK_BLOCKS("realloc_fn", root, 2);
+ CHECK_SIZE("realloc_fn", root, 10);
+ p1 = talloc_realloc_fn(root, p1, 20);
+ CHECK_BLOCKS("realloc_fn", root, 2);
+ CHECK_SIZE("realloc_fn", root, 20);
+ p1 = talloc_realloc_fn(root, p1, 0);
+ CHECK_BLOCKS("realloc_fn", root, 1);
+ CHECK_SIZE("realloc_fn", root, 0);
+
+ talloc_free(root);
+
+ printf("success: realloc_fn\n");
+ return true;
+}
+
+
+static bool test_unref_reparent(void)
+{
+ void *root, *p1, *p2, *c1;
+
+ printf("test: unref_reparent\n# UNREFERENCE AFTER PARENT FREED\n");
+
+ root = talloc_named_const(NULL, 0, "root");
+ p1 = talloc_named_const(root, 1, "orig parent");
+ p2 = talloc_named_const(root, 1, "parent by reference");
+
+ c1 = talloc_named_const(p1, 1, "child");
+ talloc_reference(p2, c1);
+
+ CHECK_PARENT("unref_reparent", c1, p1);
+
+ talloc_free(p1);
+
+ CHECK_PARENT("unref_reparent", c1, p2);
+
+ talloc_unlink(p2, c1);
+
+ CHECK_SIZE("unref_reparent", root, 1);
+
+ talloc_free(p2);
+ talloc_free(root);
+
+ printf("success: unref_reparent\n");
+ return true;
+}
+
+/*
+ measure the speed of talloc versus malloc
+*/
+static bool test_speed(void)
+{
+ void *ctx = talloc_new(NULL);
+ unsigned count;
+ const int loop = 1000;
+ int i;
+ struct timeval tv;
+
+ printf("test: speed\n# TALLOC VS MALLOC SPEED\n");
+
+ tv = private_timeval_current();
+ count = 0;
+ do {
+ void *p1, *p2, *p3;
+ for (i=0;i<loop;i++) {
+ p1 = talloc_size(ctx, loop % 100);
+ p2 = talloc_strdup(p1, "foo bar");
+ p3 = talloc_size(p1, 300);
+ (void)p2;
+ (void)p3;
+ talloc_free(p1);
+ }
+ count += 3 * loop;
+ } while (private_timeval_elapsed(&tv) < 5.0);
+
+ fprintf(stderr, "talloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
+
+ talloc_free(ctx);
+
+ ctx = talloc_pool(NULL, 1024);
+
+ tv = private_timeval_current();
+ count = 0;
+ do {
+ void *p1, *p2, *p3;
+ for (i=0;i<loop;i++) {
+ p1 = talloc_size(ctx, loop % 100);
+ p2 = talloc_strdup(p1, "foo bar");
+ p3 = talloc_size(p1, 300);
+ (void)p2;
+ (void)p3;
+ talloc_free(p1);
+ }
+ count += 3 * loop;
+ } while (private_timeval_elapsed(&tv) < 5.0);
+
+ talloc_free(ctx);
+
+ fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
+
+ tv = private_timeval_current();
+ count = 0;
+ do {
+ void *p1, *p2, *p3;
+ for (i=0;i<loop;i++) {
+ p1 = malloc(loop % 100);
+ p2 = strdup("foo bar");
+ p3 = malloc(300);
+ free(p1);
+ free(p2);
+ free(p3);
+ }
+ count += 3 * loop;
+ } while (private_timeval_elapsed(&tv) < 5.0);
+ fprintf(stderr, "malloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv));
+
+ printf("success: speed\n");
+
+ return true;
+}
+
+static bool test_lifeless(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent, *child;
+ void *child_owner = talloc_new(NULL);
+
+ printf("test: lifeless\n# TALLOC_UNLINK LOOP\n");
+
+ parent = talloc_strdup(top, "parent");
+ child = talloc_strdup(parent, "child");
+ (void)talloc_reference(child, parent);
+ (void)talloc_reference(child_owner, child);
+ talloc_report_full(top, stderr);
+ talloc_unlink(top, parent);
+ talloc_unlink(top, child);
+ talloc_report_full(top, stderr);
+ talloc_free(top);
+ talloc_free(child_owner);
+ talloc_free(child);
+
+ printf("success: lifeless\n");
+ return true;
+}
+
+static int loop_destructor_count;
+
+static int test_loop_destructor(char *ptr)
+{
+ loop_destructor_count++;
+ return 0;
+}
+
+static bool test_loop(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent;
+ struct req1 {
+ char *req2, *req3;
+ } *req1;
+
+ printf("test: loop\n# TALLOC LOOP DESTRUCTION\n");
+
+ parent = talloc_strdup(top, "parent");
+ req1 = talloc(parent, struct req1);
+ req1->req2 = talloc_strdup(req1, "req2");
+ talloc_set_destructor(req1->req2, test_loop_destructor);
+ req1->req3 = talloc_strdup(req1, "req3");
+ (void)talloc_reference(req1->req3, req1);
+ talloc_report_full(top, stderr);
+ talloc_free(parent);
+ talloc_report_full(top, stderr);
+ talloc_report_full(NULL, stderr);
+ talloc_free(top);
+
+ torture_assert("loop", loop_destructor_count == 1,
+ "FAILED TO FIRE LOOP DESTRUCTOR\n");
+ loop_destructor_count = 0;
+
+ printf("success: loop\n");
+ return true;
+}
+
+static int realloc_parent_destructor_count;
+
+static int test_realloc_parent_destructor(char *ptr)
+{
+ realloc_parent_destructor_count++;
+ return 0;
+}
+
+static bool test_realloc_on_destructor_parent(void)
+{
+ void *top = talloc_new(NULL);
+ char *parent;
+ char *a, *b, *C, *D;
+ realloc_parent_destructor_count = 0;
+
+ printf("test: free_for_exit\n# TALLOC FREE FOR EXIT\n");
+
+ parent = talloc_strdup(top, "parent");
+ a = talloc_strdup(parent, "a");
+ b = talloc_strdup(a, "b");
+ C = talloc_strdup(a, "C");
+ D = talloc_strdup(b, "D");
+ talloc_set_destructor(D, test_realloc_parent_destructor);
+ /* Capitalised ones have destructors.
+ *
+ * parent --> a -> b -> D
+ * -> c
+ */
+
+ a = talloc_realloc(parent, a, char, 2048);
+
+ torture_assert("check talloc_realloc", a != NULL, "talloc_realloc failed");
+
+ talloc_set_destructor(C, test_realloc_parent_destructor);
+ /*
+ * parent --> a[2048] -> b -> D
+ * -> C
+ *
+ */
+
+ talloc_free(parent);
+
+ torture_assert("check destructor realloc_parent_destructor",
+ realloc_parent_destructor_count == 2,
+ "FAILED TO FIRE free_for_exit_destructor\n");
+
+
+ printf("success: free_for_exit\n");
+ talloc_free(top); /* make ASAN happy */
+
+ return true;
+}
+
+static int fail_destructor_str(char *ptr)
+{
+ return -1;
+}
+
+static bool test_free_parent_deny_child(void)
+{
+ void *top = talloc_new(NULL);
+ char *level1;
+ char *level2;
+ char *level3;
+
+ printf("test: free_parent_deny_child\n# TALLOC FREE PARENT DENY CHILD\n");
+
+ level1 = talloc_strdup(top, "level1");
+ level2 = talloc_strdup(level1, "level2");
+ level3 = talloc_strdup(level2, "level3");
+
+ talloc_set_destructor(level3, fail_destructor_str);
+ talloc_free(level1);
+ talloc_set_destructor(level3, NULL);
+
+ CHECK_PARENT("free_parent_deny_child", level3, top);
+
+ talloc_free(top);
+
+ printf("success: free_parent_deny_child\n");
+ return true;
+}
+
+struct new_parent {
+ void *new_parent;
+ char val[20];
+};
+
+static int reparenting_destructor(struct new_parent *np)
+{
+ talloc_set_destructor(np, NULL);
+ (void)talloc_move(np->new_parent, &np);
+ return -1;
+}
+
+static bool test_free_parent_reparent_child(void)
+{
+ void *top = talloc_new(NULL);
+ char *level1;
+ char *alternate_level1;
+ char *level2;
+ struct new_parent *level3;
+
+ printf("test: free_parent_reparent_child\n# "
+ "TALLOC FREE PARENT REPARENT CHILD\n");
+
+ level1 = talloc_strdup(top, "level1");
+ alternate_level1 = talloc_strdup(top, "alternate_level1");
+ level2 = talloc_strdup(level1, "level2");
+ level3 = talloc(level2, struct new_parent);
+ level3->new_parent = alternate_level1;
+ memset(level3->val, 'x', sizeof(level3->val));
+
+ talloc_set_destructor(level3, reparenting_destructor);
+ talloc_free(level1);
+
+ CHECK_PARENT("free_parent_reparent_child",
+ level3, alternate_level1);
+
+ talloc_free(top);
+
+ printf("success: free_parent_reparent_child\n");
+ return true;
+}
+
+static bool test_free_parent_reparent_child_in_pool(void)
+{
+ void *top = talloc_new(NULL);
+ char *level1;
+ char *alternate_level1;
+ char *level2;
+ void *pool;
+ struct new_parent *level3;
+
+ printf("test: free_parent_reparent_child_in_pool\n# "
+ "TALLOC FREE PARENT REPARENT CHILD IN POOL\n");
+
+ pool = talloc_pool(top, 1024);
+ level1 = talloc_strdup(pool, "level1");
+ alternate_level1 = talloc_strdup(top, "alternate_level1");
+ level2 = talloc_strdup(level1, "level2");
+ level3 = talloc(level2, struct new_parent);
+ level3->new_parent = alternate_level1;
+ memset(level3->val, 'x', sizeof(level3->val));
+
+ talloc_set_destructor(level3, reparenting_destructor);
+ talloc_free(level1);
+ talloc_set_destructor(level3, NULL);
+
+ CHECK_PARENT("free_parent_reparent_child_in_pool",
+ level3, alternate_level1);
+
+ /* Even freeing alternate_level1 should leave pool alone. */
+ talloc_free(alternate_level1);
+ talloc_free(top);
+
+ printf("success: free_parent_reparent_child_in_pool\n");
+ return true;
+}
+
+
+static bool test_talloc_ptrtype(void)
+{
+ void *top = talloc_new(NULL);
+ struct struct1 {
+ int foo;
+ int bar;
+ } *s1, *s2, **s3, ***s4;
+ const char *location1;
+ const char *location2;
+ const char *location3;
+ const char *location4;
+
+ printf("test: ptrtype\n# TALLOC PTRTYPE\n");
+
+ s1 = talloc_ptrtype(top, s1);location1 = __location__;
+
+ if (talloc_get_size(s1) != sizeof(struct struct1)) {
+ printf("failure: ptrtype [\n"
+ "talloc_ptrtype() allocated the wrong size %lu (should be %lu)\n"
+ "]\n", (unsigned long)talloc_get_size(s1),
+ (unsigned long)sizeof(struct struct1));
+ return false;
+ }
+
+ if (strcmp(location1, talloc_get_name(s1)) != 0) {
+ printf("failure: ptrtype [\n"
+ "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
+ talloc_get_name(s1), location1);
+ return false;
+ }
+
+ s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__;
+
+ if (talloc_get_size(s2) != (sizeof(struct struct1) * 10)) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() allocated the wrong size "
+ "%lu (should be %lu)\n]\n",
+ (unsigned long)talloc_get_size(s2),
+ (unsigned long)(sizeof(struct struct1)*10));
+ return false;
+ }
+
+ if (strcmp(location2, talloc_get_name(s2)) != 0) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n",
+ talloc_get_name(s2), location2);
+ return false;
+ }
+
+ s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__;
+
+ if (talloc_get_size(s3) != (sizeof(struct struct1 *) * 10)) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() allocated the wrong size "
+ "%lu (should be %lu)\n]\n",
+ (unsigned long)talloc_get_size(s3),
+ (unsigned long)(sizeof(struct struct1 *)*10));
+ return false;
+ }
+
+ torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3),
+ "talloc_array_ptrtype() sets the wrong name");
+
+ s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__;
+
+ if (talloc_get_size(s4) != (sizeof(struct struct1 **) * 10)) {
+ printf("failure: ptrtype [\n"
+ "talloc_array_ptrtype() allocated the wrong size "
+ "%lu (should be %lu)\n]\n",
+ (unsigned long)talloc_get_size(s4),
+ (unsigned long)(sizeof(struct struct1 **)*10));
+ return false;
+ }
+
+ torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4),
+ "talloc_array_ptrtype() sets the wrong name");
+
+ talloc_free(top);
+
+ printf("success: ptrtype\n");
+ return true;
+}
+
+static int _test_talloc_free_in_destructor(void **ptr)
+{
+ talloc_free(*ptr);
+ return 0;
+}
+
+static bool test_talloc_free_in_destructor(void)
+{
+ void *level0;
+ void *level1;
+ void *level2;
+ void *level3;
+ void *level4;
+ void **level5;
+
+ printf("test: free_in_destructor\n# TALLOC FREE IN DESTRUCTOR\n");
+
+ level0 = talloc_new(NULL);
+ level1 = talloc_new(level0);
+ level2 = talloc_new(level1);
+ level3 = talloc_new(level2);
+ level4 = talloc_new(level3);
+ level5 = talloc(level4, void *);
+
+ *level5 = level3;
+ (void)talloc_reference(level0, level3);
+ (void)talloc_reference(level3, level3);
+ (void)talloc_reference(level5, level3);
+
+ talloc_set_destructor(level5, _test_talloc_free_in_destructor);
+
+ talloc_free(level1);
+
+ talloc_free(level0);
+
+ talloc_free(level3); /* make ASAN happy */
+
+ printf("success: free_in_destructor\n");
+ return true;
+}
+
+static bool test_autofree(void)
+{
+#if _SAMBA_BUILD_ < 4
+ /* autofree test would kill smbtorture */
+ void *p;
+ printf("test: autofree\n# TALLOC AUTOFREE CONTEXT\n");
+
+ p = talloc_autofree_context();
+ talloc_free(p);
+
+ p = talloc_autofree_context();
+ talloc_free(p);
+
+ printf("success: autofree\n");
+#endif
+ return true;
+}
+
+static bool test_pool(void)
+{
+ void *pool;
+ void *p1, *p2, *p3, *p4;
+ void *p2_2;
+
+ pool = talloc_pool(NULL, 1024);
+
+ p1 = talloc_size(pool, 80);
+ memset(p1, 0x11, talloc_get_size(p1));
+ p2 = talloc_size(pool, 20);
+ memset(p2, 0x11, talloc_get_size(p2));
+ p3 = talloc_size(p1, 50);
+ memset(p3, 0x11, talloc_get_size(p3));
+ p4 = talloc_size(p3, 1000);
+ memset(p4, 0x11, talloc_get_size(p4));
+
+ p2_2 = talloc_realloc_size(pool, p2, 20+1);
+ torture_assert("pool realloc 20+1", p2_2 == p2, "failed: pointer changed");
+ memset(p2, 0x11, talloc_get_size(p2));
+ p2_2 = talloc_realloc_size(pool, p2, 20-1);
+ torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+ memset(p2, 0x11, talloc_get_size(p2));
+ p2_2 = talloc_realloc_size(pool, p2, 20-1);
+ torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ talloc_free(p3);
+
+ /* this should reclaim the memory of p4 and p3 */
+ p2_2 = talloc_realloc_size(pool, p2, 400);
+ torture_assert("pool realloc 400", p2_2 == p2, "failed: pointer changed");
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ talloc_free(p1);
+
+ /* this should reclaim the memory of p1 */
+ p2_2 = talloc_realloc_size(pool, p2, 800);
+ torture_assert("pool realloc 800", p2_2 == p1, "failed: pointer not changed");
+ p2 = p2_2;
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ /* this should do a malloc */
+ p2_2 = talloc_realloc_size(pool, p2, 1800);
+ torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
+ p2 = p2_2;
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ /* this should reclaim the memory from the pool */
+ p3 = talloc_size(pool, 80);
+ torture_assert("pool alloc 80", p3 == p1, "failed: pointer changed");
+ memset(p3, 0x11, talloc_get_size(p3));
+
+ talloc_free(p2);
+ talloc_free(p3);
+
+ p1 = talloc_size(pool, 80);
+ memset(p1, 0x11, talloc_get_size(p1));
+ p2 = talloc_size(pool, 20);
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ talloc_free(p1);
+
+ p2_2 = talloc_realloc_size(pool, p2, 20-1);
+ torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+ memset(p2, 0x11, talloc_get_size(p2));
+ p2_2 = talloc_realloc_size(pool, p2, 20-1);
+ torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed");
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ /* this should do a malloc */
+ p2_2 = talloc_realloc_size(pool, p2, 1800);
+ torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed");
+ p2 = p2_2;
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ /* this should reclaim the memory from the pool */
+ p3 = talloc_size(pool, 800);
+ torture_assert("pool alloc 800", p3 == p1, "failed: pointer changed");
+ memset(p3, 0x11, talloc_get_size(p3));
+
+ talloc_free(pool);
+
+ return true;
+}
+
+static bool test_pool_steal(void)
+{
+ void *root;
+ void *pool;
+ void *p1, *p2;
+ void *p1_2, *p2_2;
+ size_t hdr;
+ size_t ofs1, ofs2;
+
+ root = talloc_new(NULL);
+ pool = talloc_pool(root, 1024);
+
+ p1 = talloc_size(pool, 4 * 16);
+ torture_assert("pool allocate 4 * 16", p1 != NULL, "failed ");
+ memset(p1, 0x11, talloc_get_size(p1));
+ p2 = talloc_size(pool, 4 * 16);
+ torture_assert("pool allocate 4 * 16", p2 > p1, "failed: !(p2 > p1) ");
+ memset(p2, 0x11, talloc_get_size(p2));
+
+ ofs1 = PTR_DIFF(p2, p1);
+ hdr = ofs1 - talloc_get_size(p1);
+
+ talloc_steal(root, p1);
+ talloc_steal(root, p2);
+
+ talloc_free(pool);
+
+ p1_2 = p1;
+
+ p1_2 = talloc_realloc_size(root, p1, 5 * 16);
+ torture_assert("pool realloc 5 * 16", p1_2 > p2, "failed: pointer not changed");
+ memset(p1_2, 0x11, talloc_get_size(p1_2));
+ ofs1 = PTR_DIFF(p1_2, p2);
+ ofs2 = talloc_get_size(p2) + hdr;
+
+ torture_assert("pool realloc ", ofs1 == ofs2, "failed: pointer offset unexpected");
+
+ p2_2 = talloc_realloc_size(root, p2, 3 * 16);
+ torture_assert("pool realloc 5 * 16", p2_2 == p2, "failed: pointer changed");
+ memset(p2_2, 0x11, talloc_get_size(p2_2));
+
+ talloc_free(p1_2);
+
+ p2_2 = p2;
+
+ /* now we should reclaim the full pool */
+ p2_2 = talloc_realloc_size(root, p2, 8 * 16);
+ torture_assert("pool realloc 8 * 16", p2_2 == p1, "failed: pointer not expected");
+ p2 = p2_2;
+ memset(p2_2, 0x11, talloc_get_size(p2_2));
+
+ /* now we malloc and free the full pool space */
+ p2_2 = talloc_realloc_size(root, p2, 2 * 1024);
+ torture_assert("pool realloc 2 * 1024", p2_2 != p1, "failed: pointer not expected");
+ memset(p2_2, 0x11, talloc_get_size(p2_2));
+
+ talloc_free(p2_2);
+
+ talloc_free(root);
+
+ return true;
+}
+
+static bool test_pool_nest(void)
+{
+ void *p1, *p2, *p3;
+ void *e = talloc_new(NULL);
+
+ p1 = talloc_pool(NULL, 1024);
+ torture_assert("talloc_pool", p1 != NULL, "failed");
+
+ p2 = talloc_pool(p1, 500);
+ torture_assert("talloc_pool", p2 != NULL, "failed");
+
+ p3 = talloc_size(p2, 10);
+
+ talloc_steal(e, p3);
+
+ talloc_free(p2);
+
+ talloc_free(p3);
+
+ talloc_free(p1);
+
+ talloc_free(e); /* make ASAN happy */
+
+ return true;
+}
+
+struct pooled {
+ char *s1;
+ char *s2;
+ char *s3;
+};
+
+static bool test_pooled_object(void)
+{
+ struct pooled *p;
+ const char *s1 = "hello";
+ const char *s2 = "world";
+ const char *s3 = "";
+
+ p = talloc_pooled_object(NULL, struct pooled, 3,
+ strlen(s1)+strlen(s2)+strlen(s3)+3);
+
+ if (talloc_get_size(p) != sizeof(struct pooled)) {
+ return false;
+ }
+
+ p->s1 = talloc_strdup(p, s1);
+
+ TALLOC_FREE(p->s1);
+ p->s1 = talloc_strdup(p, s2);
+ TALLOC_FREE(p->s1);
+
+ p->s1 = talloc_strdup(p, s1);
+ p->s2 = talloc_strdup(p, s2);
+ p->s3 = talloc_strdup(p, s3);
+
+ TALLOC_FREE(p);
+ return true;
+}
+
+static bool test_free_ref_null_context(void)
+{
+ void *p1, *p2, *p3;
+ int ret;
+
+ talloc_disable_null_tracking();
+ p1 = talloc_new(NULL);
+ p2 = talloc_new(NULL);
+
+ p3 = talloc_reference(p2, p1);
+ torture_assert("reference", p3 == p1, "failed: reference on null");
+
+ ret = talloc_free(p1);
+ torture_assert("ref free with null parent", ret == 0, "failed: free with null parent");
+ talloc_free(p2);
+
+ talloc_enable_null_tracking_no_autofree();
+ p1 = talloc_new(NULL);
+ p2 = talloc_new(NULL);
+
+ p3 = talloc_reference(p2, p1);
+ torture_assert("reference", p3 == p1, "failed: reference on null");
+
+ ret = talloc_free(p1);
+ torture_assert("ref free with null tracked parent", ret == 0, "failed: free with null parent");
+ talloc_free(p2);
+
+ return true;
+}
+
+static bool test_rusty(void)
+{
+ void *root;
+ char *p1;
+
+ talloc_enable_null_tracking();
+ root = talloc_new(NULL);
+ p1 = talloc_strdup(root, "foo");
+ talloc_increase_ref_count(p1);
+ talloc_report_full(root, stdout);
+ talloc_free(root);
+ CHECK_BLOCKS("null_context", NULL, 2);
+ talloc_free(p1); /* make ASAN happy */
+
+ return true;
+}
+
+static bool test_free_children(void)
+{
+ void *root;
+ char *p1, *p2;
+ const char *name, *name2;
+
+ talloc_enable_null_tracking();
+ root = talloc_new(NULL);
+ p1 = talloc_strdup(root, "foo1");
+ p2 = talloc_strdup(p1, "foo2");
+ (void)p2;
+
+ talloc_set_name(p1, "%s", "testname");
+ talloc_free_children(p1);
+ /* check its still a valid talloc ptr */
+ talloc_get_size(talloc_get_name(p1));
+ if (strcmp(talloc_get_name(p1), "testname") != 0) {
+ return false;
+ }
+
+ talloc_set_name(p1, "%s", "testname");
+ name = talloc_get_name(p1);
+ talloc_free_children(p1);
+ /* check its still a valid talloc ptr */
+ talloc_get_size(talloc_get_name(p1));
+ torture_assert("name", name == talloc_get_name(p1), "name ptr changed");
+ torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname") == 0,
+ "wrong name");
+ CHECK_BLOCKS("name1", p1, 2);
+
+ /* note that this does not free the old child name */
+ talloc_set_name_const(p1, "testname2");
+ name2 = talloc_get_name(p1);
+ /* but this does */
+ talloc_free_children(p1);
+ (void)name2;
+ torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname2") == 0,
+ "wrong name");
+ CHECK_BLOCKS("name1", p1, 1);
+
+ talloc_report_full(root, stdout);
+ talloc_free(root);
+ return true;
+}
+
+static bool test_memlimit(void)
+{
+ void *root;
+ char *l1, *l2, *l3, *l4, *l5, *t;
+ char *pool;
+ int i;
+
+ printf("test: memlimit\n# MEMORY LIMITS\n");
+
+ printf("==== talloc_new(NULL)\n");
+ root = talloc_new(NULL);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_size(root, 2048)\n");
+ l1 = talloc_size(root, 2048);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_free(l1)\n");
+ talloc_free(l1);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(root, level 1)\n");
+ l1 = talloc_strdup(root, "level 1");
+ torture_assert("memlimit", l1 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_set_memlimit(l1, 2048)\n");
+ torture_assert("memlimit", talloc_set_memlimit(l1, 2048) == 0,
+ "failed: setting memlimit should never fail\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_size(root, 2048)\n");
+ l2 = talloc_size(l1, 2048);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(l1, level 2)\n");
+ l2 = talloc_strdup(l1, "level 2");
+ torture_assert("memlimit", l2 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_free(l2)\n");
+ talloc_free(l2);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_size(NULL, 2048)\n");
+ l2 = talloc_size(NULL, 2048);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_steal(l1, l2)\n");
+ talloc_steal(l1, l2);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(l2, level 3)\n");
+ l3 = talloc_strdup(l2, "level 3");
+ torture_assert("memlimit", l3 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_free(l2)\n");
+ talloc_free(l2);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(NULL, level 2)\n");
+ l2 = talloc_strdup(NULL, "level 2");
+ talloc_steal(l1, l2);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(l2, level 3)\n");
+ l3 = talloc_strdup(l2, "level 3");
+ torture_assert("memlimit", l3 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_set_memlimit(l3, 1024)\n");
+ torture_assert("memlimit", talloc_set_memlimit(l3, 1024) == 0,
+ "failed: setting memlimit should never fail\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(l3, level 4)\n");
+ l4 = talloc_strdup(l3, "level 4");
+ torture_assert("memlimit", l4 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_set_memlimit(l4, 512)\n");
+ torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0,
+ "failed: setting memlimit should never fail\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(l4, level 5)\n");
+ l5 = talloc_strdup(l4, "level 5");
+ torture_assert("memlimit", l5 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_realloc(NULL, l5, char, 600)\n");
+ t = talloc_realloc(NULL, l5, char, 600);
+ torture_assert("memlimit", t == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_realloc(NULL, l5, char, 5)\n");
+ l5 = talloc_realloc(NULL, l5, char, 5);
+ torture_assert("memlimit", l5 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(l3, level 4)\n");
+ l4 = talloc_strdup(l3, "level 4");
+ torture_assert("memlimit", l4 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_set_memlimit(l4, 512)\n");
+ torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0,
+ "failed: setting memlimit should never fail\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_strdup(l4, level 5)\n");
+ l5 = talloc_strdup(l4, "level 5");
+ torture_assert("memlimit", l5 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+
+ printf("==== Make new temp context and steal l5\n");
+ t = talloc_new(root);
+ talloc_steal(t, l5);
+
+ talloc_report_full(root, stdout);
+
+ printf("==== talloc_size(t, 2048)\n");
+ l1 = talloc_size(t, 2048);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(root, stdout);
+ talloc_free(root);
+
+ /* Test memlimits with pools. */
+ printf("==== talloc_pool(NULL, 10*1024)\n");
+ pool = talloc_pool(NULL, 10*1024);
+ torture_assert("memlimit", pool != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ printf("==== talloc_set_memlimit(pool, 10*1024)\n");
+ talloc_set_memlimit(pool, 10*1024);
+ for (i = 0; i < 9; i++) {
+ printf("==== talloc_size(pool, 1024) %i/10\n", i + 1);
+ l1 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+ talloc_report_full(pool, stdout);
+ }
+ /* The next alloc should fail. */
+ printf("==== talloc_size(pool, 1024) 10/10\n");
+ l2 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ /* Moving one of the children shouldn't change the limit,
+ as it's still inside the pool. */
+
+ printf("==== talloc_new(NULL)\n");
+ root = talloc_new(NULL);
+
+ printf("==== talloc_steal(root, l1)\n");
+ talloc_steal(root, l1);
+
+ printf("==== talloc_size(pool, 1024)\n");
+ l2 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ printf("==== talloc_free_children(pool)\n");
+ talloc_free(l1);
+ talloc_free_children(pool);
+
+ printf("==== talloc_size(pool, 1024)\n");
+ l1 = talloc_size(pool, 1024);
+
+ /* try reallocs of increasing size */
+ for (i = 1; i < 9; i++) {
+ printf("==== talloc_realloc_size(NULL, l1, %i*1024) %i/10\n", i, i + 1);
+ l1 = talloc_realloc_size(NULL, l1, i*1024);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: realloc should not fail due to memory limit\n");
+ talloc_report_full(pool, stdout);
+ }
+ /* The next alloc should fail. */
+ printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n");
+ l2 = talloc_realloc_size(NULL, l1, 10*1024);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: realloc should fail due to memory limit\n");
+
+ /* Increase the memlimit */
+ printf("==== talloc_set_memlimit(pool, 11*1024)\n");
+ talloc_set_memlimit(pool, 11*1024);
+
+ /* The final realloc should still fail
+ as the entire realloced chunk needs to be moved out of the pool */
+ printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n");
+ l2 = talloc_realloc_size(NULL, l1, 10*1024);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: realloc should fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ printf("==== talloc_set_memlimit(pool, 21*1024)\n");
+ talloc_set_memlimit(pool, 21*1024);
+
+ /* There's now sufficient space to move the chunk out of the pool */
+ printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n");
+ l2 = talloc_realloc_size(NULL, l1, 10*1024);
+ torture_assert("memlimit", l2 != NULL,
+ "failed: realloc should not fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ /* ...which should mean smaller allocations can now occur within the pool */
+ printf("==== talloc_size(pool, 9*1024)\n");
+ l1 = talloc_size(pool, 9*1024);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: new allocations should be allowed in the pool\n");
+
+ talloc_report_full(pool, stdout);
+
+ /* But reallocs bigger than the pool will still fail */
+ printf("==== talloc_realloc_size(NULL, l1, 10*1024)\n");
+ l2 = talloc_realloc_size(NULL, l1, 10*1024);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: realloc should fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ /* ..as well as allocs */
+ printf("==== talloc_size(pool, 1024)\n");
+ l1 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l1 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ printf("==== talloc_free_children(pool)\n");
+ talloc_free_children(pool);
+
+ printf("==== talloc_set_memlimit(pool, 1024)\n");
+ talloc_set_memlimit(pool, 1024);
+
+ /* We should still be able to allocate up to the pool limit
+ because the memlimit only applies to new heap allocations */
+ printf("==== talloc_size(pool, 9*1024)\n");
+ l1 = talloc_size(pool, 9*1024);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ l1 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l1 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ printf("==== talloc_free_children(pool)\n");
+ talloc_free_children(pool);
+
+ printf("==== talloc_set_memlimit(pool, 10*1024)\n");
+ talloc_set_memlimit(pool, 10*1024);
+
+ printf("==== talloc_size(pool, 1024)\n");
+ l1 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+
+ talloc_report_full(pool, stdout);
+
+ talloc_free(pool);
+ talloc_free(root);
+ printf("success: memlimit\n");
+
+ return true;
+}
+
+#ifdef HAVE_PTHREAD
+
+#define NUM_THREADS 100
+
+/* Sync variables. */
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
+static void *intermediate_ptr;
+
+/* Subthread. */
+static void *thread_fn(void *arg)
+{
+ int ret;
+ const char *ctx_name = (const char *)arg;
+ void *sub_ctx = NULL;
+ /*
+ * Do stuff that creates a new talloc hierarchy in
+ * this thread.
+ */
+ void *top_ctx = talloc_named_const(NULL, 0, "top");
+ if (top_ctx == NULL) {
+ return NULL;
+ }
+ sub_ctx = talloc_named_const(top_ctx, 100, ctx_name);
+ if (sub_ctx == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Now transfer a pointer from our hierarchy
+ * onto the intermediate ptr.
+ */
+ ret = pthread_mutex_lock(&mtx);
+ if (ret != 0) {
+ talloc_free(top_ctx);
+ return NULL;
+ }
+ /* Wait for intermediate_ptr to be free. */
+ while (intermediate_ptr != NULL) {
+ ret = pthread_cond_wait(&condvar, &mtx);
+ if (ret != 0) {
+ talloc_free(top_ctx);
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
+ return NULL;
+ }
+ }
+
+ /* and move our memory onto it from our toplevel hierarchy. */
+ intermediate_ptr = talloc_move(NULL, &sub_ctx);
+
+ /* Tell the main thread it's ready for pickup. */
+ pthread_cond_broadcast(&condvar);
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
+
+ talloc_free(top_ctx);
+ return NULL;
+}
+
+/* Main thread. */
+static bool test_pthread_talloc_passing(void)
+{
+ int i;
+ int ret;
+ char str_array[NUM_THREADS][20];
+ pthread_t thread_id;
+ void *mem_ctx;
+
+ /*
+ * Important ! Null tracking breaks threaded talloc.
+ * It *must* be turned off.
+ */
+ talloc_disable_null_tracking();
+
+ printf("test: pthread_talloc_passing\n# PTHREAD TALLOC PASSING\n");
+
+ /* Main thread toplevel context. */
+ mem_ctx = talloc_named_const(NULL, 0, "toplevel");
+ if (mem_ctx == NULL) {
+ printf("failed to create toplevel context\n");
+ return false;
+ }
+
+ /*
+ * Spin off NUM_THREADS threads.
+ * They will use their own toplevel contexts.
+ */
+ for (i = 0; i < NUM_THREADS; i++) {
+ ret = snprintf(str_array[i],
+ 20,
+ "thread:%d",
+ i);
+ if (ret < 0) {
+ printf("snprintf %d failed\n", i);
+ return false;
+ }
+ ret = pthread_create(&thread_id,
+ NULL,
+ thread_fn,
+ str_array[i]);
+ if (ret != 0) {
+ printf("failed to create thread %d (%d)\n", i, ret);
+ return false;
+ }
+ }
+
+ printf("Created %d threads\n", NUM_THREADS);
+
+ /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */
+ for (i = 0; i < NUM_THREADS; i++) {
+ ret = pthread_mutex_lock(&mtx);
+ if (ret != 0) {
+ printf("pthread_mutex_lock %d failed (%d)\n", i, ret);
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ /* Wait for intermediate_ptr to have our data. */
+ while (intermediate_ptr == NULL) {
+ ret = pthread_cond_wait(&condvar, &mtx);
+ if (ret != 0) {
+ printf("pthread_cond_wait %d failed (%d)\n", i,
+ ret);
+ talloc_free(mem_ctx);
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
+ }
+ }
+
+ /* and move it onto our toplevel hierarchy. */
+ (void)talloc_move(mem_ctx, &intermediate_ptr);
+
+ /* Tell the sub-threads we're ready for another. */
+ pthread_cond_broadcast(&condvar);
+ ret = pthread_mutex_unlock(&mtx);
+ assert(ret == 0);
+ }
+
+ CHECK_SIZE("pthread_talloc_passing", mem_ctx, NUM_THREADS * 100);
+#if 1
+ /* Dump the hierarchy. */
+ talloc_report(mem_ctx, stdout);
+#endif
+ talloc_free(mem_ctx);
+ printf("success: pthread_talloc_passing\n");
+ return true;
+}
+#endif
+
+static void test_magic_protection_abort(const char *reason)
+{
+ /* exit with errcode 42 to communicate successful test to the parent process */
+ if (strcmp(reason, "Bad talloc magic value - unknown value") == 0) {
+ _exit(42);
+ } else {
+ printf("talloc aborted for an unexpected reason\n");
+ }
+}
+
+static int test_magic_protection_destructor(int *ptr)
+{
+ _exit(404); /* Not 42 */
+}
+
+static bool test_magic_protection(void)
+{
+ void *pool = talloc_pool(NULL, 1024);
+ int *p1, *p2;
+ pid_t pid;
+ int exit_status;
+
+ printf("test: magic_protection\n");
+ p1 = talloc(pool, int);
+ p2 = talloc(pool, int);
+
+ /* To avoid complaints from the compiler assign values to the p1 & p2. */
+ *p1 = 6;
+ *p2 = 9;
+
+ pid = fork();
+ if (pid == 0) {
+ talloc_set_abort_fn(test_magic_protection_abort);
+ talloc_set_destructor(p2, test_magic_protection_destructor);
+
+ /*
+ * Simulate a security attack
+ * by triggering a buffer overflow in memset to overwrite the
+ * constructor in the next pool chunk.
+ *
+ * Real attacks would attempt to set a real destructor.
+ */
+ memset(p1, '\0', 32);
+
+ /* Then the attack takes effect when the memory's freed. */
+ talloc_free(pool);
+
+ /* Never reached. Make compilers happy */
+ return true;
+ }
+
+ while (wait(&exit_status) != pid);
+
+ talloc_free(pool); /* make ASAN happy */
+
+ if (!WIFEXITED(exit_status)) {
+ printf("Child exited through unexpected abnormal means\n");
+ return false;
+ }
+ if (WEXITSTATUS(exit_status) != 42) {
+ printf("Child exited with wrong exit status\n");
+ return false;
+ }
+ if (WIFSIGNALED(exit_status)) {
+ printf("Child received unexpected signal\n");
+ return false;
+ }
+
+ printf("success: magic_protection\n");
+ return true;
+}
+
+static void test_magic_free_protection_abort(const char *reason)
+{
+ /* exit with errcode 42 to communicate successful test to the parent process */
+ if (strcmp(reason, "Bad talloc magic value - access after free") == 0) {
+ _exit(42);
+ }
+ /* not 42 */
+ _exit(404);
+}
+
+static bool test_magic_free_protection(void)
+{
+ void *pool = talloc_pool(NULL, 1024);
+ int *p1, *p2, *p3;
+ pid_t pid;
+ int exit_status;
+
+ printf("test: magic_free_protection\n");
+ p1 = talloc(pool, int);
+ p2 = talloc(pool, int);
+
+ /* To avoid complaints from the compiler assign values to the p1 & p2. */
+ *p1 = 6;
+ *p2 = 9;
+
+ p3 = talloc_realloc(pool, p2, int, 2048);
+ torture_assert("pool realloc 2048",
+ p3 != p2,
+ "failed: pointer not changed");
+
+ /*
+ * Now access the memory in the pool after the realloc(). It
+ * should be marked as free, so use of the old pointer should
+ * trigger the abort function
+ */
+ pid = fork();
+ if (pid == 0) {
+ talloc_set_abort_fn(test_magic_free_protection_abort);
+
+ talloc_get_name(p2);
+
+ /* Never reached. Make compilers happy */
+ return true;
+ }
+
+ while (wait(&exit_status) != pid);
+
+ if (!WIFEXITED(exit_status)) {
+ printf("Child exited through unexpected abnormal means\n");
+ return false;
+ }
+ if (WEXITSTATUS(exit_status) != 42) {
+ printf("Child exited with wrong exit status\n");
+ return false;
+ }
+ if (WIFSIGNALED(exit_status)) {
+ printf("Child received unexpected signal\n");
+ return false;
+ }
+
+ talloc_free(pool);
+
+ printf("success: magic_free_protection\n");
+ return true;
+}
+
+static void test_reset(void)
+{
+ talloc_set_log_fn(test_log_stdout);
+ test_abort_stop();
+ talloc_disable_null_tracking();
+ talloc_enable_null_tracking_no_autofree();
+}
+
+bool torture_local_talloc(struct torture_context *tctx)
+{
+ bool ret = true;
+
+ setlinebuf(stdout);
+
+ test_reset();
+ ret &= test_pooled_object();
+ test_reset();
+ ret &= test_pool_nest();
+ test_reset();
+ ret &= test_ref1();
+ test_reset();
+ ret &= test_ref2();
+ test_reset();
+ ret &= test_ref3();
+ test_reset();
+ ret &= test_ref4();
+ test_reset();
+ ret &= test_unlink1();
+ test_reset();
+ ret &= test_misc();
+ test_reset();
+ ret &= test_realloc();
+ test_reset();
+ ret &= test_realloc_child();
+ test_reset();
+ ret &= test_steal();
+ test_reset();
+ ret &= test_move();
+ test_reset();
+ ret &= test_unref_reparent();
+ test_reset();
+ ret &= test_realloc_fn();
+ test_reset();
+ ret &= test_type();
+ test_reset();
+ ret &= test_lifeless();
+ test_reset();
+ ret &= test_loop();
+ test_reset();
+ ret &= test_free_parent_deny_child();
+ test_reset();
+ ret &= test_realloc_on_destructor_parent();
+ test_reset();
+ ret &= test_free_parent_reparent_child();
+ test_reset();
+ ret &= test_free_parent_reparent_child_in_pool();
+ test_reset();
+ ret &= test_talloc_ptrtype();
+ test_reset();
+ ret &= test_talloc_free_in_destructor();
+ test_reset();
+ ret &= test_pool();
+ test_reset();
+ ret &= test_pool_steal();
+ test_reset();
+ ret &= test_free_ref_null_context();
+ test_reset();
+ ret &= test_rusty();
+ test_reset();
+ ret &= test_free_children();
+ test_reset();
+ ret &= test_memlimit();
+#ifdef HAVE_PTHREAD
+ test_reset();
+ ret &= test_pthread_talloc_passing();
+#endif
+
+
+ if (ret) {
+ test_reset();
+ ret &= test_speed();
+ }
+ test_reset();
+ ret &= test_autofree();
+ test_reset();
+ ret &= test_magic_protection();
+ test_reset();
+ ret &= test_magic_free_protection();
+
+ test_reset();
+ talloc_disable_null_tracking();
+ return ret;
+}
diff --git a/lib/talloc/testsuite_main.c b/lib/talloc/testsuite_main.c
new file mode 100644
index 0000000..50ce0f8
--- /dev/null
+++ b/lib/talloc/testsuite_main.c
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of talloc routines.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+
+#include "talloc_testsuite.h"
+
+int main(void)
+{
+ bool ret = torture_local_talloc(NULL);
+ if (!ret)
+ return -1;
+ return 0;
+}
diff --git a/lib/talloc/web/index.html b/lib/talloc/web/index.html
new file mode 100644
index 0000000..388ec2c
--- /dev/null
+++ b/lib/talloc/web/index.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>talloc</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>talloc</h1>
+
+talloc is a hierarchical pool based memory allocator with
+destructors. It is the core memory allocator used in Samba, and has
+made a huge difference in many aspects of Samba4 development.<p>
+
+To get started with talloc, I would recommend you read the <a
+href="http://samba.org/ftp/unpacked/talloc/talloc_guide.txt">talloc guide</a>.
+
+<h2>Download</h2>
+You can download the latest releases of talloc from the <a
+href="http://samba.org/ftp/talloc">talloc directory</a> on the samba public
+source archive.
+
+<h2>Discussion and bug reports</h2>
+
+talloc does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+<h2>Development</h2>
+
+You can download the latest code either via git or rsync.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the master branch and cd into the lib/talloc directory.<br>
+<br>
+To fetch via rsync use this command:
+
+<pre>
+ rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/talloc .
+</pre>
+
+<hr>
+<tiny>
+<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br>
+talloc AT tridgell.net
+</tiny>
+
+</BODY>
+</HTML>
diff --git a/lib/talloc/wscript b/lib/talloc/wscript
new file mode 100644
index 0000000..8b5e02d
--- /dev/null
+++ b/lib/talloc/wscript
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+
+APPNAME = 'talloc'
+VERSION = '2.4.2'
+
+import os
+import sys
+
+# find the buildtools directory
+top = '.'
+while not os.path.exists(top+'/buildtools') and len(top.split('/')) < 5:
+ top = top + '/..'
+sys.path.insert(0, top + '/buildtools/wafsamba')
+
+out = 'bin'
+
+import wafsamba
+from wafsamba import samba_dist, samba_utils
+from waflib import Logs, Options, Context
+
+# setup what directories to put in a tarball
+samba_dist.DIST_DIRS("""lib/talloc:. lib/replace:lib/replace
+buildtools:buildtools third_party/waf:third_party/waf""")
+
+
+def options(opt):
+ opt.BUILTIN_DEFAULT('replace')
+ opt.PRIVATE_EXTENSION_DEFAULT('talloc', noextension='talloc')
+ opt.RECURSE('lib/replace')
+ if opt.IN_LAUNCH_DIR():
+ opt.add_option('--enable-talloc-compat1',
+ help=("Build talloc 1.x.x compat library [False]"),
+ action="store_true", dest='TALLOC_COMPAT1', default=False)
+
+
+def configure(conf):
+ conf.RECURSE('lib/replace')
+
+ conf.env.standalone_talloc = conf.IN_LAUNCH_DIR()
+
+ conf.define('TALLOC_BUILD_VERSION_MAJOR', int(VERSION.split('.')[0]))
+ conf.define('TALLOC_BUILD_VERSION_MINOR', int(VERSION.split('.')[1]))
+ conf.define('TALLOC_BUILD_VERSION_RELEASE', int(VERSION.split('.')[2]))
+
+ conf.env.TALLOC_COMPAT1 = False
+ if conf.env.standalone_talloc:
+ conf.env.TALLOC_COMPAT1 = Options.options.TALLOC_COMPAT1
+ conf.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+ conf.env.TALLOC_VERSION = VERSION
+
+ conf.CHECK_XSLTPROC_MANPAGES()
+
+ conf.CHECK_HEADERS('sys/auxv.h')
+ conf.CHECK_FUNCS('getauxval')
+
+ conf.SAMBA_CONFIG_H()
+
+ conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
+
+ conf.SAMBA_CHECK_PYTHON()
+ conf.SAMBA_CHECK_PYTHON_HEADERS()
+
+ if not conf.env.standalone_talloc:
+ if conf.CHECK_BUNDLED_SYSTEM_PKG('talloc', minversion=VERSION,
+ implied_deps='replace'):
+ conf.define('USING_SYSTEM_TALLOC', 1)
+
+ if conf.env.disable_python:
+ using_system_pytalloc_util = False
+ else:
+ using_system_pytalloc_util = True
+ name = 'pytalloc-util' + conf.all_envs['default']['PYTHON_SO_ABI_FLAG']
+ if not conf.CHECK_BUNDLED_SYSTEM_PKG(name, minversion=VERSION,
+ implied_deps='talloc replace'):
+ using_system_pytalloc_util = False
+
+ if using_system_pytalloc_util:
+ conf.define('USING_SYSTEM_PYTALLOC_UTIL', 1)
+
+
+def build(bld):
+ bld.RECURSE('lib/replace')
+
+ if bld.env.standalone_talloc:
+ private_library = False
+
+ # should we also install the symlink to libtalloc1.so here?
+ bld.SAMBA_LIBRARY('talloc-compat1-%s' % (VERSION),
+ 'compat/talloc_compat1.c',
+ public_deps='talloc',
+ soname='libtalloc.so.1',
+ pc_files=[],
+ public_headers=[],
+ enabled=bld.env.TALLOC_COMPAT1)
+
+ testsuite_deps = 'talloc'
+ if bld.CONFIG_SET('HAVE_PTHREAD'):
+ testsuite_deps += ' pthread'
+
+ bld.SAMBA_BINARY('talloc_testsuite',
+ 'testsuite_main.c testsuite.c',
+ testsuite_deps,
+ install=False)
+
+ bld.SAMBA_BINARY('talloc_test_magic_differs_helper',
+ 'test_magic_differs_helper.c',
+ 'talloc', install=False)
+
+ else:
+ private_library = True
+
+ if not bld.CONFIG_SET('USING_SYSTEM_TALLOC'):
+
+ bld.SAMBA_LIBRARY('talloc',
+ 'talloc.c',
+ deps='replace',
+ provide_builtin_linking=True,
+ abi_directory='ABI',
+ abi_match='talloc* _talloc*',
+ hide_symbols=True,
+ vnum=VERSION,
+ public_headers=('' if private_library else 'talloc.h'),
+ pc_files='talloc.pc',
+ public_headers_install=not private_library,
+ private_library=private_library,
+ manpages='man/talloc.3')
+
+ if not bld.CONFIG_SET('USING_SYSTEM_PYTALLOC_UTIL'):
+ name = bld.pyembed_libname('pytalloc-util')
+
+ bld.SAMBA_LIBRARY(name,
+ source='pytalloc_util.c',
+ public_deps='talloc',
+ pyembed=True,
+ vnum=VERSION,
+ hide_symbols=True,
+ abi_directory='ABI',
+ abi_match='pytalloc_* _pytalloc_*',
+ private_library=private_library,
+ public_headers=('' if private_library else 'pytalloc.h'),
+ pc_files='pytalloc-util.pc',
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+ bld.SAMBA_PYTHON('pytalloc',
+ 'pytalloc.c',
+ deps='talloc ' + name,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED(),
+ realname='talloc.so')
+
+ bld.SAMBA_PYTHON('test_pytalloc',
+ 'test_pytalloc.c',
+ deps=name,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED(),
+ realname='_test_pytalloc.so',
+ install=False)
+
+
+def testonly(ctx):
+ '''run talloc testsuite'''
+ import samba_utils
+
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared')
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private')
+
+ cmd = os.path.join(Context.g_module.out, 'talloc_testsuite')
+ ret = samba_utils.RUN_COMMAND(cmd)
+ print("testsuite returned %d" % ret)
+ magic_helper_cmd = os.path.join(Context.g_module.out, 'talloc_test_magic_differs_helper')
+ magic_cmd = os.path.join(Context.g_module.top, 'lib', 'talloc',
+ 'test_magic_differs.sh')
+ if not os.path.exists(magic_cmd):
+ magic_cmd = os.path.join(Context.g_module.top, 'test_magic_differs.sh')
+
+ magic_ret = samba_utils.RUN_COMMAND(magic_cmd + " " + magic_helper_cmd)
+ print("magic differs test returned %d" % magic_ret)
+ pyret = samba_utils.RUN_PYTHON_TESTS(['test_pytalloc.py'])
+ print("python testsuite returned %d" % pyret)
+ sys.exit(ret or magic_ret or pyret)
+
+# WAF doesn't build the unit tests for this, maybe because they don't link with talloc?
+# This forces it
+def test(ctx):
+ Options.commands.append('build')
+ Options.commands.append('testonly')
+
+def dist():
+ '''makes a tarball for distribution'''
+ samba_dist.dist()
+
+def reconfigure(ctx):
+ '''reconfigure if config scripts have changed'''
+ samba_utils.reconfigure(ctx)
diff --git a/lib/tdb/ABI/tdb-1.2.1.sigs b/lib/tdb/ABI/tdb-1.2.1.sigs
new file mode 100644
index 0000000..84f2007
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.1.sigs
@@ -0,0 +1,95 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_alloc_read: unsigned char *(struct tdb_context *, tdb_off_t, tdb_len_t)
+tdb_allocate: tdb_off_t (struct tdb_context *, tdb_len_t, struct tdb_record *)
+tdb_allrecord_lock: int (struct tdb_context *, int, enum tdb_lock_flags, bool)
+tdb_allrecord_unlock: int (struct tdb_context *, int, bool)
+tdb_allrecord_upgrade: int (struct tdb_context *)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_brlock: int (struct tdb_context *, int, tdb_off_t, size_t, enum tdb_lock_flags)
+tdb_brunlock: int (struct tdb_context *, int, tdb_off_t, size_t)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_convert: void *(void *, uint32_t)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_do_delete: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_expand: int (struct tdb_context *, tdb_off_t)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_find_lock_hash: tdb_off_t (struct tdb_context *, TDB_DATA, uint32_t, int, struct tdb_record *)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_free: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_have_extra_locks: bool (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_io_init: void (struct tdb_context *)
+tdb_lock: int (struct tdb_context *, int, int)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lock_record: int (struct tdb_context *, tdb_off_t)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_mmap: void (struct tdb_context *)
+tdb_munmap: int (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_needs_recovery: bool (struct tdb_context *)
+tdb_nest_lock: int (struct tdb_context *, uint32_t, int, enum tdb_lock_flags)
+tdb_nest_unlock: int (struct tdb_context *, uint32_t, int, bool)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_ofs_read: int (struct tdb_context *, tdb_off_t, tdb_off_t *)
+tdb_ofs_write: int (struct tdb_context *, tdb_off_t, tdb_off_t *)
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_data: int (struct tdb_context *, TDB_DATA, tdb_off_t, tdb_len_t, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_rec_free_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_rec_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_rec_write: int (struct tdb_context *, tdb_off_t, struct tdb_record *)
+tdb_release_transaction_locks: void (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_lock: int (struct tdb_context *, int, enum tdb_lock_flags)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_recover: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_unlock: int (struct tdb_context *, int)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlock_record: int (struct tdb_context *, tdb_off_t)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
+tdb_write_lock_record: int (struct tdb_context *, tdb_off_t)
+tdb_write_unlock_record: int (struct tdb_context *, tdb_off_t)
diff --git a/lib/tdb/ABI/tdb-1.2.10.sigs b/lib/tdb/ABI/tdb-1.2.10.sigs
new file mode 100644
index 0000000..61f6c19
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.10.sigs
@@ -0,0 +1,66 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.11.sigs b/lib/tdb/ABI/tdb-1.2.11.sigs
new file mode 100644
index 0000000..d727f21
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.11.sigs
@@ -0,0 +1,67 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.12.sigs b/lib/tdb/ABI/tdb-1.2.12.sigs
new file mode 100644
index 0000000..d727f21
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.12.sigs
@@ -0,0 +1,67 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.13.sigs b/lib/tdb/ABI/tdb-1.2.13.sigs
new file mode 100644
index 0000000..d727f21
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.13.sigs
@@ -0,0 +1,67 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.2.sigs b/lib/tdb/ABI/tdb-1.2.2.sigs
new file mode 100644
index 0000000..043790d
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.2.sigs
@@ -0,0 +1,60 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.3.sigs b/lib/tdb/ABI/tdb-1.2.3.sigs
new file mode 100644
index 0000000..043790d
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.3.sigs
@@ -0,0 +1,60 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.4.sigs b/lib/tdb/ABI/tdb-1.2.4.sigs
new file mode 100644
index 0000000..043790d
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.4.sigs
@@ -0,0 +1,60 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.5.sigs b/lib/tdb/ABI/tdb-1.2.5.sigs
new file mode 100644
index 0000000..1e01f3b
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.5.sigs
@@ -0,0 +1,61 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.6.sigs b/lib/tdb/ABI/tdb-1.2.6.sigs
new file mode 100644
index 0000000..1e01f3b
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.6.sigs
@@ -0,0 +1,61 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.7.sigs b/lib/tdb/ABI/tdb-1.2.7.sigs
new file mode 100644
index 0000000..1e01f3b
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.7.sigs
@@ -0,0 +1,61 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.8.sigs b/lib/tdb/ABI/tdb-1.2.8.sigs
new file mode 100644
index 0000000..1e01f3b
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.8.sigs
@@ -0,0 +1,61 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.2.9.sigs b/lib/tdb/ABI/tdb-1.2.9.sigs
new file mode 100644
index 0000000..9e4149b
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.2.9.sigs
@@ -0,0 +1,62 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.0.sigs b/lib/tdb/ABI/tdb-1.3.0.sigs
new file mode 100644
index 0000000..7d3e469
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.0.sigs
@@ -0,0 +1,68 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.1.sigs b/lib/tdb/ABI/tdb-1.3.1.sigs
new file mode 100644
index 0000000..7d3e469
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.1.sigs
@@ -0,0 +1,68 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.10.sigs b/lib/tdb/ABI/tdb-1.3.10.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.10.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.11.sigs b/lib/tdb/ABI/tdb-1.3.11.sigs
new file mode 100644
index 0000000..48f4278
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.11.sigs
@@ -0,0 +1,70 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.12.sigs b/lib/tdb/ABI/tdb-1.3.12.sigs
new file mode 100644
index 0000000..48f4278
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.12.sigs
@@ -0,0 +1,70 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.13.sigs b/lib/tdb/ABI/tdb-1.3.13.sigs
new file mode 100644
index 0000000..48f4278
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.13.sigs
@@ -0,0 +1,70 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.14.sigs b/lib/tdb/ABI/tdb-1.3.14.sigs
new file mode 100644
index 0000000..61ce5e6
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.14.sigs
@@ -0,0 +1,71 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.15.sigs b/lib/tdb/ABI/tdb-1.3.15.sigs
new file mode 100644
index 0000000..61ce5e6
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.15.sigs
@@ -0,0 +1,71 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.16.sigs b/lib/tdb/ABI/tdb-1.3.16.sigs
new file mode 100644
index 0000000..61ce5e6
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.16.sigs
@@ -0,0 +1,71 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.17.sigs b/lib/tdb/ABI/tdb-1.3.17.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.17.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.18.sigs b/lib/tdb/ABI/tdb-1.3.18.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.18.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.2.sigs b/lib/tdb/ABI/tdb-1.3.2.sigs
new file mode 100644
index 0000000..7d3e469
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.2.sigs
@@ -0,0 +1,68 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.3.sigs b/lib/tdb/ABI/tdb-1.3.3.sigs
new file mode 100644
index 0000000..7d3e469
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.3.sigs
@@ -0,0 +1,68 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.4.sigs b/lib/tdb/ABI/tdb-1.3.4.sigs
new file mode 100644
index 0000000..7d3e469
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.4.sigs
@@ -0,0 +1,68 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.5.sigs b/lib/tdb/ABI/tdb-1.3.5.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.5.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.6.sigs b/lib/tdb/ABI/tdb-1.3.6.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.6.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.7.sigs b/lib/tdb/ABI/tdb-1.3.7.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.7.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.8.sigs b/lib/tdb/ABI/tdb-1.3.8.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.8.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.3.9.sigs b/lib/tdb/ABI/tdb-1.3.9.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.3.9.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.0.sigs b/lib/tdb/ABI/tdb-1.4.0.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.0.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.1.sigs b/lib/tdb/ABI/tdb-1.4.1.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.1.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.10.sigs b/lib/tdb/ABI/tdb-1.4.10.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.10.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.2.sigs b/lib/tdb/ABI/tdb-1.4.2.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.2.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.3.sigs b/lib/tdb/ABI/tdb-1.4.3.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.3.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.4.sigs b/lib/tdb/ABI/tdb-1.4.4.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.4.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.5.sigs b/lib/tdb/ABI/tdb-1.4.5.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.5.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.6.sigs b/lib/tdb/ABI/tdb-1.4.6.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.6.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.7.sigs b/lib/tdb/ABI/tdb-1.4.7.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.7.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.8.sigs b/lib/tdb/ABI/tdb-1.4.8.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.8.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/ABI/tdb-1.4.9.sigs b/lib/tdb/ABI/tdb-1.4.9.sigs
new file mode 100644
index 0000000..e2b0427
--- /dev/null
+++ b/lib/tdb/ABI/tdb-1.4.9.sigs
@@ -0,0 +1,73 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_active: bool (struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *)
+tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/lib/tdb/Makefile b/lib/tdb/Makefile
new file mode 100644
index 0000000..55e229b
--- /dev/null
+++ b/lib/tdb/Makefile
@@ -0,0 +1,65 @@
+# simple makefile wrapper to run waf
+
+WAF_BIN=`PATH=buildtools/bin:../../buildtools/bin:$$PATH which waf`
+WAF_BINARY=$(PYTHON) $(WAF_BIN)
+WAF=PYTHONHASHSEED=1 WAF_MAKE=1 $(WAF_BINARY)
+
+all:
+ $(WAF) build
+
+install:
+ $(WAF) install
+
+uninstall:
+ $(WAF) uninstall
+
+test: FORCE
+ $(WAF) test $(TEST_OPTIONS)
+
+testenv:
+ $(WAF) test --testenv $(TEST_OPTIONS)
+
+quicktest:
+ $(WAF) test --quick $(TEST_OPTIONS)
+
+dist:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) dist
+
+distcheck:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) distcheck
+
+clean:
+ $(WAF) clean
+
+distclean:
+ $(WAF) distclean
+
+reconfigure: configure
+ $(WAF) reconfigure
+
+show_waf_options:
+ $(WAF) --help
+
+# some compatibility make targets
+everything: all
+
+testsuite: all
+
+check: test
+
+torture: all
+
+# this should do an install as well, once install is finished
+installcheck: test
+
+etags:
+ $(WAF) etags
+
+ctags:
+ $(WAF) ctags
+
+bin/%:: FORCE
+ $(WAF) --targets=`basename $@`
+FORCE:
diff --git a/lib/tdb/_tdb_text.py b/lib/tdb/_tdb_text.py
new file mode 100644
index 0000000..f3caa53
--- /dev/null
+++ b/lib/tdb/_tdb_text.py
@@ -0,0 +1,137 @@
+# Text wrapper for tdb bindings
+#
+# Copyright (C) 2015 Petr Viktorin <pviktori@redhat.com>
+# Published under the GNU LGPLv3 or later
+
+import sys
+
+import tdb
+
+
+class TdbTextWrapper(object):
+ """Text interface for a TDB file"""
+
+ def __init__(self, tdb):
+ self._tdb = tdb
+
+ @property
+ def raw(self):
+ return self._tdb
+
+ def get(self, key):
+ key = key.encode('utf-8')
+ result = self._tdb.get(key)
+ if result is not None:
+ return result.decode('utf-8')
+
+ def append(self, key, value):
+ key = key.encode('utf-8')
+ value = value.encode('utf-8')
+ self._tdb.append(key, value)
+
+ def firstkey(self):
+ result = self._tdb.firstkey()
+ if result:
+ return result.decode('utf-8')
+
+ def nextkey(self, key):
+ key = key.encode('utf-8')
+ result = self._tdb.nextkey(key)
+ if result is not None:
+ return result.decode('utf-8')
+
+ def delete(self, key):
+ key = key.encode('utf-8')
+ self._tdb.delete(key)
+
+ def store(self, key, value):
+ key = key.encode('utf-8')
+ value = value.encode('utf-8')
+ self._tdb.store(key, value)
+
+ def __iter__(self):
+ for key in iter(self._tdb):
+ yield key.decode('utf-8')
+
+ def __getitem__(self, key):
+ key = key.encode('utf-8')
+ result = self._tdb[key]
+ return result.decode('utf-8')
+
+ def __contains__(self, key):
+ key = key.encode('utf-8')
+ return key in self._tdb
+
+ def __repr__(self):
+ return '<TdbTextWrapper for %r>' % self._tdb
+
+ def __setitem__(self, key, value):
+ key = key.encode('utf-8')
+ value = value.encode('utf-8')
+ self._tdb[key] = value
+
+ def __delitem__(self, key):
+ key = key.encode('utf-8')
+ del self._tdb[key]
+
+ if sys.version_info > (3, 0):
+ keys = __iter__
+ else:
+ iterkeys = __iter__
+ has_key = __contains__
+
+
+## Add wrappers for functions and getters that don't deal with text
+
+def _add_wrapper(name):
+ orig = getattr(tdb.Tdb, name)
+
+ def wrapper(self, *args, **kwargs):
+ return orig(self._tdb, *args, **kwargs)
+ wrapper.__name__ = orig.__name__
+ wrapper.__doc__ = orig.__doc__
+
+ setattr(TdbTextWrapper, name, wrapper)
+
+for name in ("transaction_cancel",
+ "transaction_commit",
+ "transaction_prepare_commit",
+ "transaction_start",
+ "reopen",
+ "lock_all",
+ "unlock_all",
+ "read_lock_all",
+ "read_unlock_all",
+ "close",
+ "add_flags",
+ "remove_flags",
+ "clear",
+ "repack",
+ "enable_seqnum",
+ "increment_seqnum_nonblock",
+ ):
+ _add_wrapper(name)
+
+
+def _add_getter(name):
+ orig = getattr(tdb.Tdb, name)
+ doc = orig.__doc__
+
+ def getter(self):
+ return getattr(self._tdb, name)
+
+ def setter(self, value):
+ return setattr(self._tdb, name, value)
+
+ setattr(TdbTextWrapper, name, property(getter, setter, doc=doc))
+
+for name in ("hash_size",
+ "map_size",
+ "freelist_size",
+ "flags",
+ "max_dead",
+ "filename",
+ "seqnum",
+ "text",
+ ):
+ _add_getter(name)
diff --git a/lib/tdb/common/check.c b/lib/tdb/common/check.c
new file mode 100644
index 0000000..d7741f6
--- /dev/null
+++ b/lib/tdb/common/check.c
@@ -0,0 +1,489 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Rusty Russell 2009
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "tdb_private.h"
+
+/* Since we opened it, these shouldn't fail unless it's recent corruption. */
+static bool tdb_check_header(struct tdb_context *tdb, tdb_off_t *recovery)
+{
+ struct tdb_header hdr;
+ uint32_t h1, h2;
+
+ if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), 0) == -1)
+ return false;
+ if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0)
+ goto corrupt;
+
+ CONVERT(hdr);
+ if (hdr.version != TDB_VERSION)
+ goto corrupt;
+
+ if (hdr.rwlocks != 0 &&
+ hdr.rwlocks != TDB_FEATURE_FLAG_MAGIC &&
+ hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
+ goto corrupt;
+
+ tdb_header_hash(tdb, &h1, &h2);
+ if (hdr.magic1_hash && hdr.magic2_hash &&
+ (hdr.magic1_hash != h1 || hdr.magic2_hash != h2))
+ goto corrupt;
+
+ if (hdr.hash_size == 0)
+ goto corrupt;
+
+ if (hdr.hash_size != tdb->hash_size)
+ goto corrupt;
+
+ if (hdr.recovery_start != 0 &&
+ hdr.recovery_start < TDB_DATA_START(tdb->hash_size))
+ goto corrupt;
+
+ *recovery = hdr.recovery_start;
+ return true;
+
+corrupt:
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "Header is corrupt\n"));
+ return false;
+}
+
+/* Generic record header check. */
+static bool tdb_check_record(struct tdb_context *tdb,
+ tdb_off_t off,
+ const struct tdb_record *rec)
+{
+ tdb_off_t tailer;
+
+ /* Check rec->next: 0 or points to record offset, aligned. */
+ if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->hash_size)){
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u too small next %u\n",
+ off, rec->next));
+ goto corrupt;
+ }
+ if (rec->next + sizeof(*rec) < rec->next) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u too large next %u\n",
+ off, rec->next));
+ goto corrupt;
+ }
+ if ((rec->next % TDB_ALIGNMENT) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u misaligned next %u\n",
+ off, rec->next));
+ goto corrupt;
+ }
+ if (tdb_oob(tdb, rec->next, sizeof(*rec), 0))
+ goto corrupt;
+
+ /* Check rec_len: similar to rec->next, implies next record. */
+ if ((rec->rec_len % TDB_ALIGNMENT) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u misaligned length %u\n",
+ off, rec->rec_len));
+ goto corrupt;
+ }
+ /* Must fit tailer. */
+ if (rec->rec_len < sizeof(tailer)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u too short length %u\n",
+ off, rec->rec_len));
+ goto corrupt;
+ }
+ /* OOB allows "right at the end" access, so this works for last rec. */
+ if (tdb_oob(tdb, off, sizeof(*rec)+rec->rec_len, 0))
+ goto corrupt;
+
+ /* Check tailer. */
+ if (tdb_ofs_read(tdb, off+sizeof(*rec)+rec->rec_len-sizeof(tailer),
+ &tailer) == -1)
+ goto corrupt;
+ if (tailer != sizeof(*rec) + rec->rec_len) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u invalid tailer\n", off));
+ goto corrupt;
+ }
+
+ return true;
+
+corrupt:
+ tdb->ecode = TDB_ERR_CORRUPT;
+ return false;
+}
+
+/* Grab some bytes: may copy if can't use mmap.
+ Caller has already done bounds check. */
+static TDB_DATA get_bytes(struct tdb_context *tdb,
+ tdb_off_t off, tdb_len_t len)
+{
+ TDB_DATA d;
+
+ d.dsize = len;
+
+ if (tdb->transaction == NULL && tdb->map_ptr != NULL)
+ d.dptr = (unsigned char *)tdb->map_ptr + off;
+ else
+ d.dptr = tdb_alloc_read(tdb, off, d.dsize);
+ return d;
+}
+
+/* Frees data if we're not able to simply use mmap. */
+static void put_bytes(struct tdb_context *tdb, TDB_DATA d)
+{
+ if (tdb->transaction == NULL && tdb->map_ptr != NULL)
+ return;
+ free(d.dptr);
+}
+
+/* We use the excellent Jenkins lookup3 hash; this is based on hash_word2.
+ * See: http://burtleburtle.net/bob/c/lookup3.c
+ */
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+static void hash(uint32_t key, uint32_t *pc, uint32_t *pb)
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + *pc;
+ c += *pb;
+ a += key;
+ c ^= b; c -= rot(b,14);
+ a ^= c; a -= rot(c,11);
+ b ^= a; b -= rot(a,25);
+ c ^= b; c -= rot(b,16);
+ a ^= c; a -= rot(c,4);
+ b ^= a; b -= rot(a,14);
+ c ^= b; c -= rot(b,24);
+ *pc=c; *pb=b;
+}
+
+/*
+ We want to check that all free records are in the free list
+ (only once), and all free list entries are free records. Similarly
+ for each hash chain of used records.
+
+ Doing that naively (without walking hash chains, since we want to be
+ linear) means keeping a list of records which have been seen in each
+ hash chain, and another of records pointed to (ie. next pointers
+ from records and the initial hash chain heads). These two lists
+ should be equal. This will take 8 bytes per record, and require
+ sorting at the end.
+
+ So instead, we record each offset in a bitmap such a way that
+ recording it twice will cancel out. Since each offset should appear
+ exactly twice, the bitmap should be zero at the end.
+
+ The approach was inspired by Bloom Filters (see Wikipedia). For
+ each value, we flip K bits in a bitmap of size N. The number of
+ distinct arrangements is:
+
+ N! / (K! * (N-K)!)
+
+ Of course, not all arrangements are actually distinct, but testing
+ shows this formula to be close enough.
+
+ So, if K == 8 and N == 256, the probability of two things flipping the same
+ bits is 1 in 409,663,695,276,000.
+
+ Given that ldb uses a hash size of 10000, using 32 bytes per hash chain
+ (320k) seems reasonable.
+*/
+#define NUM_HASHES 8
+#define BITMAP_BITS 256
+
+static void bit_flip(unsigned char bits[], unsigned int idx)
+{
+ bits[idx / CHAR_BIT] ^= (1 << (idx % CHAR_BIT));
+}
+
+/* We record offsets in a bitmap for the particular chain it should be in. */
+static void record_offset(unsigned char bits[], tdb_off_t off)
+{
+ uint32_t h1 = off, h2 = 0;
+ unsigned int i;
+
+ /* We get two good hash values out of jhash2, so we use both. Then
+ * we keep going to produce further hash values. */
+ for (i = 0; i < NUM_HASHES / 2; i++) {
+ hash(off, &h1, &h2);
+ bit_flip(bits, h1 % BITMAP_BITS);
+ bit_flip(bits, h2 % BITMAP_BITS);
+ h2++;
+ }
+}
+
+/* Check that an in-use record is valid. */
+static bool tdb_check_used_record(struct tdb_context *tdb,
+ tdb_off_t off,
+ const struct tdb_record *rec,
+ unsigned char **hashes,
+ int (*check)(TDB_DATA, TDB_DATA, void *),
+ void *private_data)
+{
+ TDB_DATA key, data;
+ tdb_len_t len;
+
+ if (!tdb_check_record(tdb, off, rec))
+ return false;
+
+ /* key + data + tailer must fit in record */
+ len = rec->key_len;
+ len += rec->data_len;
+ if (len < rec->data_len) {
+ /* overflow */
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "Record lengths overflow\n"));
+ return false;
+ }
+ len += sizeof(tdb_off_t);
+ if (len < sizeof(tdb_off_t)) {
+ /* overflow */
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "Record lengths overflow\n"));
+ return false;
+ }
+
+ if (len > rec->rec_len) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u too short for contents\n", off));
+ return false;
+ }
+
+ key = get_bytes(tdb, off + sizeof(*rec), rec->key_len);
+ if (!key.dptr)
+ return false;
+
+ if (tdb->hash_fn(&key) != rec->full_hash) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Record offset %u has incorrect hash\n", off));
+ goto fail_put_key;
+ }
+
+ /* Mark this offset as a known value for this hash bucket. */
+ record_offset(hashes[BUCKET(rec->full_hash)+1], off);
+ /* And similarly if the next pointer is valid. */
+ if (rec->next)
+ record_offset(hashes[BUCKET(rec->full_hash)+1], rec->next);
+
+ /* If they supply a check function and this record isn't dead,
+ get data and feed it. */
+ if (check && rec->magic != TDB_DEAD_MAGIC) {
+ data = get_bytes(tdb, off + sizeof(*rec) + rec->key_len,
+ rec->data_len);
+ if (!data.dptr)
+ goto fail_put_key;
+
+ if (check(key, data, private_data) == -1)
+ goto fail_put_data;
+ put_bytes(tdb, data);
+ }
+
+ put_bytes(tdb, key);
+ return true;
+
+fail_put_data:
+ put_bytes(tdb, data);
+fail_put_key:
+ put_bytes(tdb, key);
+ return false;
+}
+
+/* Check that an unused record is valid. */
+static bool tdb_check_free_record(struct tdb_context *tdb,
+ tdb_off_t off,
+ const struct tdb_record *rec,
+ unsigned char **hashes)
+{
+ if (!tdb_check_record(tdb, off, rec))
+ return false;
+
+ /* Mark this offset as a known value for the free list. */
+ record_offset(hashes[0], off);
+ /* And similarly if the next pointer is valid. */
+ if (rec->next)
+ record_offset(hashes[0], rec->next);
+ return true;
+}
+
+/* Slow, but should be very rare. */
+size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off)
+{
+ size_t len;
+
+ for (len = 0; off + len < tdb->map_size; len++) {
+ char c;
+ if (tdb->methods->tdb_read(tdb, off, &c, 1, 0))
+ return 0;
+ if (c != 0 && c != 0x42)
+ break;
+ }
+ return len;
+}
+
+_PUBLIC_ int tdb_check(struct tdb_context *tdb,
+ int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
+ void *private_data)
+{
+ unsigned int h;
+ unsigned char **hashes;
+ tdb_off_t off, recovery_start;
+ struct tdb_record rec;
+ bool found_recovery = false;
+ tdb_len_t dead;
+ bool locked;
+
+ /* Read-only databases use no locking at all: it's best-effort.
+ * We may have a write lock already, so skip that case too. */
+ if (tdb->read_only || tdb->allrecord_lock.count != 0) {
+ locked = false;
+ } else {
+ if (tdb_lockall_read(tdb) == -1)
+ return -1;
+ locked = true;
+ }
+
+ /* Make sure we know true size of the underlying file. */
+ tdb_oob(tdb, tdb->map_size, 1, 1);
+
+ /* Header must be OK: also gets us the recovery ptr, if any. */
+ if (!tdb_check_header(tdb, &recovery_start))
+ goto unlock;
+
+ /* We should have the whole header, too. */
+ if (tdb->map_size < TDB_DATA_START(tdb->hash_size)) {
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n"));
+ goto unlock;
+ }
+
+ /* One big malloc: pointers then bit arrays. */
+ hashes = (unsigned char **)calloc(
+ 1, sizeof(hashes[0]) * (1+tdb->hash_size)
+ + BITMAP_BITS / CHAR_BIT * (1+tdb->hash_size));
+ if (!hashes) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto unlock;
+ }
+
+ /* Initialize pointers */
+ hashes[0] = (unsigned char *)(&hashes[1+tdb->hash_size]);
+ for (h = 1; h < 1+tdb->hash_size; h++)
+ hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT;
+
+ /* Freelist and hash headers are all in a row: read them. */
+ for (h = 0; h < 1+tdb->hash_size; h++) {
+ if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
+ &off) == -1)
+ goto free;
+ if (off)
+ record_offset(hashes[h], off);
+ }
+
+ /* For each record, read it in and check it's ok. */
+ for (off = TDB_DATA_START(tdb->hash_size);
+ off < tdb->map_size;
+ off += sizeof(rec) + rec.rec_len) {
+ if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
+ DOCONV()) == -1)
+ goto free;
+ switch (rec.magic) {
+ case TDB_MAGIC:
+ case TDB_DEAD_MAGIC:
+ if (!tdb_check_used_record(tdb, off, &rec, hashes,
+ check, private_data))
+ goto free;
+ break;
+ case TDB_FREE_MAGIC:
+ if (!tdb_check_free_record(tdb, off, &rec, hashes))
+ goto free;
+ break;
+ /* If we crash after ftruncate, we can get zeroes or fill. */
+ case TDB_RECOVERY_INVALID_MAGIC:
+ case 0x42424242:
+ if (recovery_start == off) {
+ found_recovery = true;
+ break;
+ }
+ dead = tdb_dead_space(tdb, off);
+ if (dead < sizeof(rec))
+ goto corrupt;
+
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Dead space at %u-%u (of %u)\n",
+ off, off + dead, tdb->map_size));
+ rec.rec_len = dead - sizeof(rec);
+ break;
+ case TDB_RECOVERY_MAGIC:
+ if (recovery_start != off) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Unexpected recovery record at offset %u\n",
+ off));
+ goto free;
+ }
+ found_recovery = true;
+ break;
+ default: ;
+ corrupt:
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Bad magic 0x%x at offset %u\n",
+ rec.magic, off));
+ goto free;
+ }
+ }
+
+ /* Now, hashes should all be empty: each record exists and is referred
+ * to by one other. */
+ for (h = 0; h < 1+tdb->hash_size; h++) {
+ unsigned int i;
+ for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) {
+ if (hashes[h][i] != 0) {
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Hashes do not match records\n"));
+ goto free;
+ }
+ }
+ }
+
+ /* We must have found recovery area if there was one. */
+ if (recovery_start != 0 && !found_recovery) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Expected a recovery area at %u\n",
+ recovery_start));
+ goto free;
+ }
+
+ free(hashes);
+ if (locked) {
+ tdb_unlockall_read(tdb);
+ }
+ return 0;
+
+free:
+ free(hashes);
+unlock:
+ if (locked) {
+ tdb_unlockall_read(tdb);
+ }
+ return -1;
+}
diff --git a/lib/tdb/common/dump.c b/lib/tdb/common/dump.c
new file mode 100644
index 0000000..adcf591
--- /dev/null
+++ b/lib/tdb/common/dump.c
@@ -0,0 +1,149 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash,
+ tdb_off_t offset)
+{
+ struct tdb_record rec;
+ tdb_off_t tailer_ofs, tailer;
+
+ if (tdb->methods->tdb_read(tdb, offset, (char *)&rec,
+ sizeof(rec), DOCONV()) == -1) {
+ printf("ERROR: failed to read record at %u\n", offset);
+ return 0;
+ }
+
+ printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%u "
+ "key_len=%u data_len=%u full_hash=0x%08x magic=0x%08x\n",
+ hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len,
+ rec.full_hash, rec.magic);
+
+ tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off_t);
+
+ if (tdb_ofs_read(tdb, tailer_ofs, &tailer) == -1) {
+ printf("ERROR: failed to read tailer at %u\n", tailer_ofs);
+ return rec.next;
+ }
+
+ if (tailer != rec.rec_len + sizeof(rec)) {
+ printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n",
+ (unsigned int)tailer, (unsigned int)(rec.rec_len + sizeof(rec)));
+ }
+ return rec.next;
+}
+
+static int tdb_dump_chain(struct tdb_context *tdb, int i)
+{
+ struct tdb_chainwalk_ctx chainwalk;
+ tdb_off_t rec_ptr, top;
+
+ if (i == -1) {
+ top = FREELIST_TOP;
+ } else {
+ top = TDB_HASH_TOP(i);
+ }
+
+ if (tdb_lock(tdb, i, F_WRLCK) != 0)
+ return -1;
+
+ if (tdb_ofs_read(tdb, top, &rec_ptr) == -1)
+ return tdb_unlock(tdb, i, F_WRLCK);
+
+ tdb_chainwalk_init(&chainwalk, rec_ptr);
+
+ if (rec_ptr)
+ printf("hash=%d\n", i);
+
+ while (rec_ptr) {
+ bool ok;
+ rec_ptr = tdb_dump_record(tdb, i, rec_ptr);
+ ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
+ if (!ok) {
+ printf("circular hash chain %d\n", i);
+ break;
+ }
+ }
+
+ return tdb_unlock(tdb, i, F_WRLCK);
+}
+
+_PUBLIC_ void tdb_dump_all(struct tdb_context *tdb)
+{
+ uint32_t i;
+ for (i=0;i<tdb->hash_size;i++) {
+ tdb_dump_chain(tdb, i);
+ }
+ printf("freelist:\n");
+ tdb_dump_chain(tdb, -1);
+}
+
+_PUBLIC_ int tdb_printfreelist(struct tdb_context *tdb)
+{
+ int ret;
+ long total_free = 0;
+ tdb_off_t offset, rec_ptr;
+ struct tdb_record rec;
+
+ if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)
+ return ret;
+
+ offset = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (tdb_ofs_read(tdb, offset, &rec_ptr) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ }
+
+ printf("freelist top=[0x%08x]\n", rec_ptr );
+ while (rec_ptr) {
+ if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec,
+ sizeof(rec), DOCONV()) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+ }
+
+ if (rec.magic != TDB_FREE_MAGIC) {
+ printf("bad magic 0x%08x in free list\n", rec.magic);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+ }
+
+ printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%u)] (end = 0x%08x)\n",
+ rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len);
+ total_free += rec.rec_len;
+
+ /* move to the next record */
+ rec_ptr = rec.next;
+ }
+ printf("total rec_len = [0x%08lx (%lu)]\n", total_free, total_free);
+
+ return tdb_unlock(tdb, -1, F_WRLCK);
+}
+
diff --git a/lib/tdb/common/error.c b/lib/tdb/common/error.c
new file mode 100644
index 0000000..c3ef8bd
--- /dev/null
+++ b/lib/tdb/common/error.c
@@ -0,0 +1,74 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+_PUBLIC_ enum TDB_ERROR tdb_error(struct tdb_context *tdb)
+{
+ return tdb->ecode;
+}
+
+_PUBLIC_ const char *tdb_errorstr(struct tdb_context *tdb)
+{
+ switch (tdb->ecode) {
+ case TDB_SUCCESS:
+ return "Success";
+ break;
+ case TDB_ERR_CORRUPT:
+ return "Corrupt database";
+ break;
+ case TDB_ERR_IO:
+ return "IO Error";
+ break;
+ case TDB_ERR_LOCK:
+ return "Locking error";
+ break;
+ case TDB_ERR_OOM:
+ return "Out of memory";
+ break;
+ case TDB_ERR_EXISTS:
+ return "Record exists";
+ break;
+ case TDB_ERR_NOLOCK:
+ return "Lock exists on other keys";
+ break;
+ case TDB_ERR_EINVAL:
+ return "Invalid parameter";
+ break;
+ case TDB_ERR_NOEXIST:
+ return "Record does not exist";
+ break;
+ case TDB_ERR_RDONLY:
+ return "write not permitted";
+ break;
+ default:
+ break;
+ }
+
+ return "Invalid error code";
+}
+
diff --git a/lib/tdb/common/freelist.c b/lib/tdb/common/freelist.c
new file mode 100644
index 0000000..046c747
--- /dev/null
+++ b/lib/tdb/common/freelist.c
@@ -0,0 +1,747 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* read a freelist record and check for simple errors */
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct tdb_record *rec)
+{
+ if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+
+ if (rec->magic == TDB_MAGIC) {
+ /* this happens when a app is showdown while deleting a record - we should
+ not completely fail when this happens */
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%u - fixing\n",
+ rec->magic, off));
+ rec->magic = TDB_FREE_MAGIC;
+ if (tdb_rec_write(tdb, off, rec) == -1)
+ return -1;
+ }
+
+ if (rec->magic != TDB_FREE_MAGIC) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%u\n",
+ rec->magic, off));
+ return -1;
+ }
+ if (tdb_oob(tdb, rec->next, sizeof(*rec), 0) != 0)
+ return -1;
+ return 0;
+}
+
+/* update a record tailer (must hold allocation lock) */
+static int update_tailer(struct tdb_context *tdb, tdb_off_t offset,
+ const struct tdb_record *rec)
+{
+ tdb_off_t totalsize;
+
+ /* Offset of tailer from record header */
+ totalsize = sizeof(*rec) + rec->rec_len;
+ return tdb_ofs_write(tdb, offset + totalsize - sizeof(tdb_off_t),
+ &totalsize);
+}
+
+/**
+ * Read the record directly on the left.
+ * Fail if there is no record on the left.
+ */
+static int read_record_on_left(struct tdb_context *tdb, tdb_off_t rec_ptr,
+ tdb_off_t *left_p,
+ struct tdb_record *left_r)
+{
+ tdb_off_t left_ptr;
+ tdb_off_t left_size;
+ struct tdb_record left_rec;
+ int ret;
+
+ left_ptr = rec_ptr - sizeof(tdb_off_t);
+
+ if (left_ptr <= TDB_DATA_START(tdb->hash_size)) {
+ /* no record on the left */
+ return -1;
+ }
+
+ /* Read in tailer and jump back to header */
+ ret = tdb_ofs_read(tdb, left_ptr, &left_size);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "tdb_free: left offset read failed at %u\n", left_ptr));
+ return -1;
+ }
+
+ /* it could be uninitialised data */
+ if (left_size == 0 || left_size == TDB_PAD_U32) {
+ return -1;
+ }
+
+ if (left_size > rec_ptr) {
+ return -1;
+ }
+
+ left_ptr = rec_ptr - left_size;
+
+ if (left_ptr < TDB_DATA_START(tdb->hash_size)) {
+ return -1;
+ }
+
+ /* Now read in the left record */
+ ret = tdb->methods->tdb_read(tdb, left_ptr, &left_rec,
+ sizeof(left_rec), DOCONV());
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "tdb_free: left read failed at %u (%u)\n",
+ left_ptr, left_size));
+ return -1;
+ }
+
+ *left_p = left_ptr;
+ *left_r = left_rec;
+
+ return 0;
+}
+
+/**
+ * Merge new freelist record with the direct left neighbour.
+ * This assumes that left_rec represents the record
+ * directly to the left of right_rec and that this is
+ * a freelist record.
+ */
+static int merge_with_left_record(struct tdb_context *tdb,
+ tdb_off_t left_ptr,
+ struct tdb_record *left_rec,
+ struct tdb_record *right_rec)
+{
+ int ret;
+
+ left_rec->rec_len += sizeof(*right_rec) + right_rec->rec_len;
+
+ ret = tdb_rec_write(tdb, left_ptr, left_rec);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "merge_with_left_record: update_left failed at %u\n",
+ left_ptr));
+ return -1;
+ }
+
+ ret = update_tailer(tdb, left_ptr, left_rec);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "merge_with_left_record: update_tailer failed at %u\n",
+ left_ptr));
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Check whether the record left of a given freelist record is
+ * also a freelist record, and if so, merge the two records.
+ *
+ * Return code:
+ * -1 upon error
+ * 0 if left was not a free record
+ * 1 if left was free and successfully merged.
+ *
+ * The current record is handed in with pointer and fully read record.
+ *
+ * The left record pointer and struct can be retrieved as result
+ * in lp and lr;
+ */
+static int check_merge_with_left_record(struct tdb_context *tdb,
+ tdb_off_t rec_ptr,
+ struct tdb_record *rec,
+ tdb_off_t *lp,
+ struct tdb_record *lr)
+{
+ tdb_off_t left_ptr;
+ struct tdb_record left_rec;
+ int ret;
+
+ ret = read_record_on_left(tdb, rec_ptr, &left_ptr, &left_rec);
+ if (ret != 0) {
+ return 0;
+ }
+
+ if (left_rec.magic != TDB_FREE_MAGIC) {
+ return 0;
+ }
+
+ /* It's free - expand to include it. */
+ ret = merge_with_left_record(tdb, left_ptr, &left_rec, rec);
+ if (ret != 0) {
+ return -1;
+ }
+
+ if (lp != NULL) {
+ *lp = left_ptr;
+ }
+
+ if (lr != NULL) {
+ *lr = left_rec;
+ }
+
+ return 1;
+}
+
+/**
+ * Check whether the record left of a given freelist record is
+ * also a freelist record, and if so, merge the two records.
+ *
+ * Return code:
+ * -1 upon error
+ * 0 if left was not a free record
+ * 1 if left was free and successfully merged.
+ *
+ * In this variant, the input record is specified just as the pointer
+ * and is read from the database if needed.
+ *
+ * next_ptr will contain the original record's next pointer after
+ * successful merging (which will be lost after merging), so that
+ * the caller can update the last pointer.
+ */
+static int check_merge_ptr_with_left_record(struct tdb_context *tdb,
+ tdb_off_t rec_ptr,
+ tdb_off_t *next_ptr)
+{
+ tdb_off_t left_ptr;
+ struct tdb_record rec, left_rec;
+ int ret;
+
+ ret = read_record_on_left(tdb, rec_ptr, &left_ptr, &left_rec);
+ if (ret != 0) {
+ return 0;
+ }
+
+ if (left_rec.magic != TDB_FREE_MAGIC) {
+ return 0;
+ }
+
+ /* It's free - expand to include it. */
+
+ ret = tdb->methods->tdb_read(tdb, rec_ptr, &rec,
+ sizeof(rec), DOCONV());
+ if (ret != 0) {
+ return -1;
+ }
+
+ ret = merge_with_left_record(tdb, left_ptr, &left_rec, &rec);
+ if (ret != 0) {
+ return -1;
+ }
+
+ if (next_ptr != NULL) {
+ *next_ptr = rec.next;
+ }
+
+ return 1;
+}
+
+/**
+ * Add an element into the freelist.
+ *
+ * We merge the new record into the left record if it is also a
+ * free record, but not with the right one. This makes the
+ * operation O(1) instead of O(n): merging with the right record
+ * requires a traverse of the freelist to find the previous
+ * record in the free list.
+ *
+ * This prevents db traverses from being O(n^2) after a lot of deletes.
+ */
+int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
+{
+ int ret;
+
+ /* Allocation and tailer lock */
+ if (tdb_lock(tdb, -1, F_WRLCK) != 0)
+ return -1;
+
+ /* set an initial tailer, so if we fail we don't leave a bogus record */
+ if (update_tailer(tdb, offset, rec) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n"));
+ goto fail;
+ }
+
+ ret = check_merge_with_left_record(tdb, offset, rec, NULL, NULL);
+ if (ret == -1) {
+ goto fail;
+ }
+ if (ret == 1) {
+ /* merged */
+ goto done;
+ }
+
+ /* Nothing to merge, prepend to free list */
+
+ rec->magic = TDB_FREE_MAGIC;
+
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
+ tdb_rec_write(tdb, offset, rec) == -1 ||
+ tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%u\n", offset));
+ goto fail;
+ }
+
+done:
+ /* And we're done. */
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+
+
+/*
+ the core of tdb_allocate - called when we have decided which
+ free list entry to use
+
+ Note that we try to allocate by grabbing data from the end of an existing record,
+ not the beginning. This is so the left merge in a free is more likely to be
+ able to free up the record without fragmentation
+ */
+static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb,
+ tdb_len_t length, tdb_off_t rec_ptr,
+ struct tdb_record *rec, tdb_off_t last_ptr)
+{
+#define MIN_REC_SIZE (sizeof(struct tdb_record) + sizeof(tdb_off_t) + 8)
+
+ if (rec->rec_len < length + MIN_REC_SIZE) {
+ /* we have to grab the whole record */
+
+ /* unlink it from the previous record */
+ if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
+ return 0;
+ }
+
+ /* mark it not free */
+ rec->magic = TDB_MAGIC;
+ if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+ return rec_ptr;
+ }
+
+ /* we're going to just shorten the existing record */
+ rec->rec_len -= (length + sizeof(*rec));
+ if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+ if (update_tailer(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ /* and setup the new record */
+ rec_ptr += sizeof(*rec) + rec->rec_len;
+
+ memset(rec, '\0', sizeof(*rec));
+ rec->rec_len = length;
+ rec->magic = TDB_MAGIC;
+
+ if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ if (update_tailer(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ return rec_ptr;
+}
+
+/* allocate some space from the free list. The offset returned points
+ to a unconnected tdb_record within the database with room for at
+ least length bytes of total data
+
+ 0 is returned if the space could not be allocated
+ */
+static tdb_off_t tdb_allocate_from_freelist(
+ struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
+{
+ tdb_off_t rec_ptr, last_ptr, newrec_ptr;
+ struct tdb_chainwalk_ctx chainwalk;
+ bool modified;
+ struct {
+ tdb_off_t rec_ptr, last_ptr;
+ tdb_len_t rec_len;
+ } bestfit;
+ float multiplier = 1.0;
+ bool merge_created_candidate;
+
+ /* over-allocate to reduce fragmentation */
+ length *= 1.25;
+
+ /* Extra bytes required for tailer */
+ length += sizeof(tdb_off_t);
+ length = TDB_ALIGN(length, TDB_ALIGNMENT);
+
+ again:
+ merge_created_candidate = false;
+ last_ptr = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
+ return 0;
+
+ modified = false;
+ tdb_chainwalk_init(&chainwalk, rec_ptr);
+
+ bestfit.rec_ptr = 0;
+ bestfit.last_ptr = 0;
+ bestfit.rec_len = 0;
+
+ /*
+ this is a best fit allocation strategy. Originally we used
+ a first fit strategy, but it suffered from massive fragmentation
+ issues when faced with a slowly increasing record size.
+ */
+ while (rec_ptr) {
+ int ret;
+ tdb_off_t left_ptr;
+ struct tdb_record left_rec;
+
+ if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ ret = check_merge_with_left_record(tdb, rec_ptr, rec,
+ &left_ptr, &left_rec);
+ if (ret == -1) {
+ return 0;
+ }
+ if (ret == 1) {
+ /* merged */
+ rec_ptr = rec->next;
+ ret = tdb_ofs_write(tdb, last_ptr, &rec->next);
+ if (ret == -1) {
+ return 0;
+ }
+
+ /*
+ * We have merged the current record into the left
+ * neighbour. So our traverse of the freelist will
+ * skip it and consider the next record in the chain.
+ *
+ * But the enlarged left neighbour may be a candidate.
+ * If it is, we can not directly use it, though.
+ * The only thing we can do and have to do here is to
+ * update the current best fit size in the chain if the
+ * current best fit is the left record. (By that we may
+ * worsen the best fit we already had, bit this is not a
+ * problem.)
+ *
+ * If the current best fit is not the left record,
+ * all we can do is remember the fact that a merge
+ * created a new candidate so that we can trigger
+ * a second walk of the freelist if at the end of
+ * the first walk we have not found any fit.
+ * This way we can avoid expanding the database.
+ */
+
+ if (bestfit.rec_ptr == left_ptr) {
+ bestfit.rec_len = left_rec.rec_len;
+ }
+
+ if (left_rec.rec_len > length) {
+ merge_created_candidate = true;
+ }
+
+ modified = true;
+
+ continue;
+ }
+
+ if (rec->rec_len >= length) {
+ if (bestfit.rec_ptr == 0 ||
+ rec->rec_len < bestfit.rec_len) {
+ bestfit.rec_len = rec->rec_len;
+ bestfit.rec_ptr = rec_ptr;
+ bestfit.last_ptr = last_ptr;
+ }
+ }
+
+ /* move to the next record */
+ last_ptr = rec_ptr;
+ rec_ptr = rec->next;
+
+ if (!modified) {
+ bool ok;
+ ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
+ if (!ok) {
+ return 0;
+ }
+ }
+
+ /* if we've found a record that is big enough, then
+ stop searching if its also not too big. The
+ definition of 'too big' changes as we scan
+ through */
+ if (bestfit.rec_len > 0 &&
+ bestfit.rec_len < length * multiplier) {
+ break;
+ }
+
+ /* this multiplier means we only extremely rarely
+ search more than 50 or so records. At 50 records we
+ accept records up to 11 times larger than what we
+ want */
+ multiplier *= 1.05;
+ }
+
+ if (bestfit.rec_ptr != 0) {
+ if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
+ return 0;
+ }
+
+ newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr,
+ rec, bestfit.last_ptr);
+ return newrec_ptr;
+ }
+
+ if (merge_created_candidate) {
+ goto again;
+ }
+
+ /* we didn't find enough space. See if we can expand the
+ database and if we can then try again */
+ if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
+ goto again;
+
+ return 0;
+}
+
+static bool tdb_alloc_dead(
+ struct tdb_context *tdb, int hash, tdb_len_t length,
+ tdb_off_t *rec_ptr, struct tdb_record *rec)
+{
+ tdb_off_t last_ptr;
+
+ *rec_ptr = tdb_find_dead(tdb, hash, rec, length, &last_ptr);
+ if (*rec_ptr == 0) {
+ return false;
+ }
+ /*
+ * Unlink the record from the hash chain, it's about to be moved into
+ * another one.
+ */
+ return (tdb_ofs_write(tdb, last_ptr, &rec->next) == 0);
+}
+
+static void tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
+{
+ int max_dead_records = tdb->max_dead_records;
+
+ tdb->max_dead_records = 0;
+
+ tdb_trim_dead(tdb, hash);
+
+ tdb->max_dead_records = max_dead_records;
+}
+
+/*
+ * Chain "hash" is assumed to be locked
+ */
+
+tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length,
+ struct tdb_record *rec)
+{
+ tdb_off_t ret;
+ uint32_t i;
+
+ if (tdb->max_dead_records == 0) {
+ /*
+ * No dead records to expect anywhere. Do the blocking
+ * freelist lock without trying to steal from others
+ */
+ goto blocking_freelist_allocate;
+ }
+
+ /*
+ * The following loop tries to get the freelist lock nonblocking. If
+ * it gets the lock, allocate from there. If the freelist is busy,
+ * instead of waiting we try to steal dead records from other hash
+ * chains.
+ *
+ * Be aware that we do nonblocking locks on the other hash chains as
+ * well and fail gracefully. This way we avoid deadlocks (we block two
+ * hash chains, something which is pretty bad normally)
+ */
+
+ for (i=0; i<tdb->hash_size; i++) {
+
+ int list;
+
+ list = BUCKET(hash+i);
+
+ if (tdb_lock_nonblock(tdb, list, F_WRLCK) == 0) {
+ bool got_dead;
+
+ got_dead = tdb_alloc_dead(tdb, list, length, &ret, rec);
+ tdb_unlock(tdb, list, F_WRLCK);
+
+ if (got_dead) {
+ return ret;
+ }
+ }
+
+ if (tdb_lock_nonblock(tdb, -1, F_WRLCK) == 0) {
+ /*
+ * Under the freelist lock take the chance to give
+ * back our dead records.
+ */
+ tdb_purge_dead(tdb, hash);
+
+ ret = tdb_allocate_from_freelist(tdb, length, rec);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return ret;
+ }
+ }
+
+blocking_freelist_allocate:
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ return 0;
+ }
+ /*
+ * Dead records can happen even if max_dead_records==0, they
+ * are older than the max_dead_records concept: They happen if
+ * tdb_delete happens concurrently with a traverse.
+ */
+ tdb_purge_dead(tdb, hash);
+ ret = tdb_allocate_from_freelist(tdb, length, rec);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return ret;
+}
+
+/**
+ * Merge adjacent records in the freelist.
+ */
+static int tdb_freelist_merge_adjacent(struct tdb_context *tdb,
+ int *count_records, int *count_merged)
+{
+ tdb_off_t cur, next;
+ int count = 0;
+ int merged = 0;
+ int ret;
+
+ ret = tdb_lock(tdb, -1, F_RDLCK);
+ if (ret == -1) {
+ return -1;
+ }
+
+ cur = FREELIST_TOP;
+ while (tdb_ofs_read(tdb, cur, &next) == 0 && next != 0) {
+ tdb_off_t next2;
+
+ count++;
+
+ ret = check_merge_ptr_with_left_record(tdb, next, &next2);
+ if (ret == -1) {
+ goto done;
+ }
+ if (ret == 1) {
+ /*
+ * merged:
+ * now let cur->next point to next2 instead of next
+ */
+
+ ret = tdb_ofs_write(tdb, cur, &next2);
+ if (ret != 0) {
+ goto done;
+ }
+
+ next = next2;
+ merged++;
+ }
+
+ cur = next;
+ }
+
+ if (count_records != NULL) {
+ *count_records = count;
+ }
+
+ if (count_merged != NULL) {
+ *count_merged = merged;
+ }
+
+ ret = 0;
+
+done:
+ tdb_unlock(tdb, -1, F_RDLCK);
+ return ret;
+}
+
+/**
+ * return the size of the freelist - no merging done
+ */
+static int tdb_freelist_size_no_merge(struct tdb_context *tdb)
+{
+ tdb_off_t ptr;
+ int count=0;
+
+ if (tdb_lock(tdb, -1, F_RDLCK) == -1) {
+ return -1;
+ }
+
+ ptr = FREELIST_TOP;
+ while (tdb_ofs_read(tdb, ptr, &ptr) == 0 && ptr != 0) {
+ count++;
+ }
+
+ tdb_unlock(tdb, -1, F_RDLCK);
+ return count;
+}
+
+/**
+ * return the size of the freelist - used to decide if we should repack
+ *
+ * As a side effect, adjacent records are merged unless the
+ * database is read-only, in order to reduce the fragmentation
+ * without repacking.
+ */
+_PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb)
+{
+
+ int count = 0;
+
+ if (tdb->read_only) {
+ count = tdb_freelist_size_no_merge(tdb);
+ } else {
+ int ret;
+ ret = tdb_freelist_merge_adjacent(tdb, &count, NULL);
+ if (ret != 0) {
+ return -1;
+ }
+ }
+
+ return count;
+}
diff --git a/lib/tdb/common/freelistcheck.c b/lib/tdb/common/freelistcheck.c
new file mode 100644
index 0000000..2f1e6eb
--- /dev/null
+++ b/lib/tdb/common/freelistcheck.c
@@ -0,0 +1,107 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Jeremy Allison 2006
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* Check the freelist is good and contains no loops.
+ Very memory intensive - only do this as a consistency
+ checker. Heh heh - uses an in memory tdb as the storage
+ for the "seen" record list. For some reason this strikes
+ me as extremely clever as I don't have to write another tree
+ data structure implementation :-).
+ */
+
+static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr)
+{
+ TDB_DATA key;
+
+ key.dptr = (unsigned char *)&rec_ptr;
+ key.dsize = sizeof(rec_ptr);
+ return tdb_store(mem_tdb, key, tdb_null, TDB_INSERT);
+}
+
+_PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
+{
+ struct tdb_context *mem_tdb = NULL;
+ struct tdb_record rec;
+ tdb_off_t rec_ptr, last_ptr;
+ int ret = -1;
+
+ *pnum_entries = 0;
+
+ mem_tdb = tdb_open("flval", tdb->hash_size,
+ TDB_INTERNAL, O_RDWR, 0600);
+ if (!mem_tdb) {
+ return -1;
+ }
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ tdb_close(mem_tdb);
+ return 0;
+ }
+
+ last_ptr = FREELIST_TOP;
+
+ /* Store the FREELIST_TOP record. */
+ if (seen_insert(mem_tdb, last_ptr) == -1) {
+ tdb->ecode = TDB_ERR_CORRUPT;
+ ret = -1;
+ goto fail;
+ }
+
+ /* read in the freelist top */
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) {
+ goto fail;
+ }
+
+ while (rec_ptr) {
+
+ /* If we can't store this record (we've seen it
+ before) then the free list has a loop and must
+ be corrupt. */
+
+ if (seen_insert(mem_tdb, rec_ptr)) {
+ tdb->ecode = TDB_ERR_CORRUPT;
+ ret = -1;
+ goto fail;
+ }
+
+ if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+
+ /* move to the next record */
+ rec_ptr = rec.next;
+ *pnum_entries += 1;
+ }
+
+ ret = 0;
+
+ fail:
+
+ tdb_close(mem_tdb);
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return ret;
+}
diff --git a/lib/tdb/common/hash.c b/lib/tdb/common/hash.c
new file mode 100644
index 0000000..ca4cac3
--- /dev/null
+++ b/lib/tdb/common/hash.c
@@ -0,0 +1,345 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Rusty Russell 2010
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "tdb_private.h"
+
+/* This is based on the hash algorithm from gdbm */
+unsigned int tdb_old_hash(TDB_DATA *key)
+{
+ uint32_t value; /* Used to compute the hash value. */
+ uint32_t i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
+ value = (value + (key->dptr[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+#ifndef WORDS_BIGENDIAN
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#endif
+
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions. Routines to test the hash are included
+if SELF_TEST is defined. You can use this free for any purpose. It's in
+the public domain. It has no warranty.
+
+You probably want to use hashlittle(). hashlittle() and hashbig()
+hash byte arrays. hashlittle() is faster than hashbig() on
+little-endian machines. Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+ a = i1; b = i2; c = i3;
+ mix(a,b,c);
+ a += i4; b += i5; c += i6;
+ mix(a,b,c);
+ a += i7;
+ final(a,b,c);
+then use c as the hash value. If you have a variable length array of
+4-byte integers to hash, use hash_word(). If you have a byte array (like
+a character string), use hashlittle(). If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers. This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+*/
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ val2 : IN: can be any 4-byte value OUT: second 32 bit hash.
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values. Note that the return value is better
+mixed than val2, so use that first.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+static uint32_t hashlittle( const void *key, size_t length )
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length);
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; FALL_THROUGH;
+ case 10: c+=((uint32_t)k8[9])<<8; FALL_THROUGH;
+ case 9 : c+=k8[8]; FALL_THROUGH;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; FALL_THROUGH;
+ case 6 : b+=((uint32_t)k8[5])<<8; FALL_THROUGH;
+ case 5 : b+=k8[4]; FALL_THROUGH;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; FALL_THROUGH;
+ case 2 : a+=((uint32_t)k8[1])<<8; FALL_THROUGH;
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; FALL_THROUGH;
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; FALL_THROUGH;
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; FALL_THROUGH;
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; FALL_THROUGH;
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; FALL_THROUGH;
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length)
+ {
+ case 12: c+=((uint32_t)k[11])<<24; FALL_THROUGH;
+ case 11: c+=((uint32_t)k[10])<<16; FALL_THROUGH;
+ case 10: c+=((uint32_t)k[9])<<8; FALL_THROUGH;
+ case 9 : c+=k[8]; FALL_THROUGH;
+ case 8 : b+=((uint32_t)k[7])<<24; FALL_THROUGH;
+ case 7 : b+=((uint32_t)k[6])<<16; FALL_THROUGH;
+ case 6 : b+=((uint32_t)k[5])<<8; FALL_THROUGH;
+ case 5 : b+=k[4]; FALL_THROUGH;
+ case 4 : a+=((uint32_t)k[3])<<24; FALL_THROUGH;
+ case 3 : a+=((uint32_t)k[2])<<16; FALL_THROUGH;
+ case 2 : a+=((uint32_t)k[1])<<8; FALL_THROUGH;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+_PUBLIC_ unsigned int tdb_jenkins_hash(TDB_DATA *key)
+{
+ return hashlittle(key->dptr, key->dsize);
+}
diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c
new file mode 100644
index 0000000..0de0dab
--- /dev/null
+++ b/lib/tdb/common/io.c
@@ -0,0 +1,806 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "tdb_private.h"
+
+/*
+ * We prepend the mutex area, so fixup offsets. See mutex.c for details.
+ * tdb->hdr_ofs is 0 or header.mutex_size.
+ *
+ * Note: that we only have the 4GB limit of tdb_off_t for
+ * tdb->map_size. The file size on disk can be 4GB + tdb->hdr_ofs!
+ */
+
+static bool tdb_adjust_offset(struct tdb_context *tdb, off_t *off)
+{
+ off_t tmp = tdb->hdr_ofs + *off;
+
+ if ((tmp < tdb->hdr_ofs) || (tmp < *off)) {
+ errno = EIO;
+ return false;
+ }
+
+ *off = tmp;
+ return true;
+}
+
+static ssize_t tdb_pwrite(struct tdb_context *tdb, const void *buf,
+ size_t count, off_t offset)
+{
+ ssize_t ret;
+
+ if (!tdb_adjust_offset(tdb, &offset)) {
+ return -1;
+ }
+
+ do {
+ ret = pwrite(tdb->fd, buf, count, offset);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
+}
+
+static ssize_t tdb_pread(struct tdb_context *tdb, void *buf,
+ size_t count, off_t offset)
+{
+ ssize_t ret;
+
+ if (!tdb_adjust_offset(tdb, &offset)) {
+ return -1;
+ }
+
+ do {
+ ret = pread(tdb->fd, buf, count, offset);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
+}
+
+static int tdb_ftruncate(struct tdb_context *tdb, off_t length)
+{
+ ssize_t ret;
+
+ if (!tdb_adjust_offset(tdb, &length)) {
+ return -1;
+ }
+
+ do {
+ ret = ftruncate(tdb->fd, length);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
+}
+
+#ifdef HAVE_POSIX_FALLOCATE
+static int tdb_posix_fallocate(struct tdb_context *tdb, off_t offset,
+ off_t len)
+{
+ ssize_t ret;
+
+ if (!tdb_adjust_offset(tdb, &offset)) {
+ return -1;
+ }
+
+ do {
+ ret = posix_fallocate(tdb->fd, offset, len);
+ } while ((ret == -1) && (errno == EINTR));
+
+ return ret;
+}
+#endif
+
+static int tdb_fstat(struct tdb_context *tdb, struct stat *buf)
+{
+ int ret;
+
+ ret = fstat(tdb->fd, buf);
+ if (ret == -1) {
+ return -1;
+ }
+
+ if (buf->st_size < tdb->hdr_ofs) {
+ errno = EIO;
+ return -1;
+ }
+ buf->st_size -= tdb->hdr_ofs;
+
+ return ret;
+}
+
+/* check for an out of bounds access - if it is out of bounds then
+ see if the database has been expanded by someone else and expand
+ if necessary
+*/
+static int tdb_notrans_oob(
+ struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe)
+{
+ struct stat st;
+ if (len + off < len) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob off %u len %u wrap\n",
+ off, len));
+ }
+ return -1;
+ }
+
+ /*
+ * This duplicates functionality from tdb_oob(). Don't remove:
+ * we still have direct callers of tdb->methods->tdb_oob()
+ * inside transaction.c.
+ */
+ if (off + len <= tdb->map_size)
+ return 0;
+ if (tdb->flags & TDB_INTERNAL) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond internal malloc size %u\n",
+ (int)(off + len), (int)tdb->map_size));
+ }
+ return -1;
+ }
+
+ if (tdb_fstat(tdb, &st) == -1) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* Beware >4G files! */
+ if ((tdb_off_t)st.st_size != st.st_size) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_oob len %llu too large!\n",
+ (long long)st.st_size));
+ return -1;
+ }
+
+ /* Unmap, update size, remap. We do this unconditionally, to handle
+ * the unusual case where the db is truncated.
+ *
+ * This can happen to a child using tdb_reopen_all(true) on a
+ * TDB_CLEAR_IF_FIRST tdb whose parent crashes: the next
+ * opener will truncate the database. */
+ if (tdb_munmap(tdb) == -1) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ tdb->map_size = st.st_size;
+ if (tdb_mmap(tdb) != 0) {
+ return -1;
+ }
+
+ if (st.st_size < (size_t)off + len) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n",
+ (int)(off + len), (int)st.st_size));
+ }
+ return -1;
+ }
+ return 0;
+}
+
+/* write a lump of data at a specified offset */
+static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
+ const void *buf, tdb_len_t len)
+{
+ if (len == 0) {
+ return 0;
+ }
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ if (tdb_oob(tdb, off, len, 0) != 0)
+ return -1;
+
+ if (tdb->map_ptr) {
+ memcpy(off + (char *)tdb->map_ptr, buf, len);
+ } else {
+#ifdef HAVE_INCOHERENT_MMAP
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+#else
+ ssize_t written;
+
+ written = tdb_pwrite(tdb, buf, len, off);
+
+ if ((written != (ssize_t)len) && (written != -1)) {
+ /* try once more */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only "
+ "%zi of %u bytes at %u, trying once more\n",
+ written, len, off));
+ written = tdb_pwrite(tdb, (const char *)buf+written,
+ len-written, off+written);
+ }
+ if (written == -1) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %u "
+ "len=%u (%s)\n", off, len, strerror(errno)));
+ return -1;
+ } else if (written != (ssize_t)len) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
+ "write %u bytes at %u in two attempts\n",
+ len, off));
+ return -1;
+ }
+#endif
+ }
+ return 0;
+}
+
+/* Endian conversion: we only ever deal with 4 byte quantities */
+void *tdb_convert(void *buf, uint32_t size)
+{
+ uint32_t i, *p = (uint32_t *)buf;
+ for (i = 0; i < size / 4; i++)
+ p[i] = TDB_BYTEREV(p[i]);
+ return buf;
+}
+
+
+/* read a lump of data at a specified offset, maybe convert */
+static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
+ tdb_len_t len, int cv)
+{
+ if (tdb_oob(tdb, off, len, 0) != 0) {
+ return -1;
+ }
+
+ if (tdb->map_ptr) {
+ memcpy(buf, off + (char *)tdb->map_ptr, len);
+ } else {
+#ifdef HAVE_INCOHERENT_MMAP
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+#else
+ ssize_t ret;
+
+ ret = tdb_pread(tdb, buf, len, off);
+ if (ret != (ssize_t)len) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %u "
+ "len=%u ret=%zi (%s) map_size=%u\n",
+ off, len, ret, strerror(errno),
+ tdb->map_size));
+ return -1;
+ }
+#endif
+ }
+ if (cv) {
+ tdb_convert(buf, len);
+ }
+ return 0;
+}
+
+
+
+/*
+ do an unlocked scan of the hash table heads to find the next non-zero head. The value
+ will then be confirmed with the lock held
+*/
+static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
+{
+ uint32_t h = *chain;
+ if (tdb->map_ptr) {
+ for (;h < tdb->hash_size;h++) {
+ if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
+ break;
+ }
+ }
+ } else {
+ uint32_t off=0;
+ for (;h < tdb->hash_size;h++) {
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
+ break;
+ }
+ }
+ }
+ (*chain) = h;
+}
+
+
+int tdb_munmap(struct tdb_context *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return 0;
+
+#ifdef HAVE_MMAP
+ if (tdb->map_ptr) {
+ int ret;
+
+ ret = munmap(tdb->map_ptr, tdb->map_size);
+ if (ret != 0)
+ return ret;
+ }
+#endif
+ tdb->map_ptr = NULL;
+ return 0;
+}
+
+/* If mmap isn't coherent, *everyone* must always mmap. */
+static bool should_mmap(const struct tdb_context *tdb)
+{
+#ifdef HAVE_INCOHERENT_MMAP
+ return true;
+#else
+ return !(tdb->flags & TDB_NOMMAP);
+#endif
+}
+
+int tdb_mmap(struct tdb_context *tdb)
+{
+ if (tdb->flags & TDB_INTERNAL)
+ return 0;
+
+#ifdef HAVE_MMAP
+ if (should_mmap(tdb)) {
+ tdb->map_ptr = mmap(NULL, tdb->map_size,
+ PROT_READ|(tdb->read_only? 0:PROT_WRITE),
+ MAP_SHARED|MAP_FILE, tdb->fd,
+ tdb->hdr_ofs);
+
+ /*
+ * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
+ */
+
+ if (tdb->map_ptr == MAP_FAILED) {
+ tdb->map_ptr = NULL;
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %u (%s)\n",
+ tdb->map_size, strerror(errno)));
+#ifdef HAVE_INCOHERENT_MMAP
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+#endif
+ }
+ } else {
+ tdb->map_ptr = NULL;
+ }
+#else
+ tdb->map_ptr = NULL;
+#endif
+ return 0;
+}
+
+/* expand a file. we prefer to use ftruncate, as that is what posix
+ says to use for mmap expansion */
+static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
+{
+ char buf[8192];
+ tdb_off_t new_size;
+ int ret;
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ if (!tdb_add_off_t(size, addition, &new_size)) {
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
+ "overflow detected current size[%u] addition[%u]!\n",
+ (unsigned)size, (unsigned)addition));
+ errno = ENOSPC;
+ return -1;
+ }
+
+#ifdef HAVE_POSIX_FALLOCATE
+ ret = tdb_posix_fallocate(tdb, size, addition);
+ if (ret == 0) {
+ return 0;
+ }
+ if (ret == ENOSPC) {
+ /*
+ * The Linux glibc (at least as of 2.24) fallback if
+ * the file system does not support fallocate does not
+ * reset the file size back to where it was. Also, to
+ * me it is unclear from the posix spec of
+ * posix_fallocate whether this is allowed or
+ * not. Better be safe than sorry and "goto fail" but
+ * "return -1" here, leaving the EOF pointer too
+ * large.
+ */
+ goto fail;
+ }
+
+ /*
+ * Retry the "old" way. Possibly unnecessary, but looking at
+ * our configure script there seem to be weird failure modes
+ * for posix_fallocate. See commit 3264a98ff16de, which
+ * probably refers to
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=1083.
+ */
+#endif
+
+ ret = tdb_ftruncate(tdb, new_size);
+ if (ret == -1) {
+ char b = 0;
+ ssize_t written = tdb_pwrite(tdb, &b, 1, new_size - 1);
+ if (written == 0) {
+ /* try once more, potentially revealing errno */
+ written = tdb_pwrite(tdb, &b, 1, new_size - 1);
+ }
+ if (written == 0) {
+ /* again - give up, guessing errno */
+ errno = ENOSPC;
+ }
+ if (written != 1) {
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %u failed (%s)\n",
+ (unsigned)new_size, strerror(errno)));
+ return -1;
+ }
+ }
+
+ /* now fill the file with something. This ensures that the
+ file isn't sparse, which would be very bad if we ran out of
+ disk. This must be done with write, not via mmap */
+ memset(buf, TDB_PAD_BYTE, sizeof(buf));
+ while (addition) {
+ size_t n = addition>sizeof(buf)?sizeof(buf):addition;
+ ssize_t written = tdb_pwrite(tdb, buf, n, size);
+ if (written == 0) {
+ /* prevent infinite loops: try _once_ more */
+ written = tdb_pwrite(tdb, buf, n, size);
+ }
+ if (written == 0) {
+ /* give up, trying to provide a useful errno */
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
+ "returned 0 twice: giving up!\n"));
+ errno = ENOSPC;
+ goto fail;
+ }
+ if (written == -1) {
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
+ "%u bytes failed (%s)\n", (int)n,
+ strerror(errno)));
+ goto fail;
+ }
+ if (written != n) {
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
+ "only %zu of %zi bytes - retrying\n", written,
+ n));
+ }
+ addition -= written;
+ size += written;
+ }
+ return 0;
+
+fail:
+ {
+ int err = errno;
+
+ /*
+ * We're holding the freelist lock or are inside a
+ * transaction. Cutting the file is safe, the space we
+ * tried to allocate can't have been used anywhere in
+ * the meantime.
+ */
+
+ ret = tdb_ftruncate(tdb, size);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: "
+ "retruncate to %ju failed\n",
+ (uintmax_t)size));
+ }
+ errno = err;
+ }
+
+ return -1;
+}
+
+
+/* You need 'size', this tells you how much you should expand by. */
+tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size)
+{
+ tdb_off_t new_size, top_size, increment;
+ tdb_off_t max_size = UINT32_MAX - map_size;
+
+ if (size > max_size) {
+ /*
+ * We can't round up anymore, just give back
+ * what we're asked for.
+ *
+ * The caller has to take care of the ENOSPC handling.
+ */
+ return size;
+ }
+
+ /* limit size in order to avoid using up huge amounts of memory for
+ * in memory tdbs if an oddball huge record creeps in */
+ if (size > 100 * 1024) {
+ increment = size * 2;
+ } else {
+ increment = size * 100;
+ }
+ if (increment < size) {
+ goto overflow;
+ }
+
+ if (!tdb_add_off_t(map_size, increment, &top_size)) {
+ goto overflow;
+ }
+
+ /* always make room for at least top_size more records, and at
+ least 25% more space. if the DB is smaller than 100MiB,
+ otherwise grow it by 10% only. */
+ if (map_size > 100 * 1024 * 1024) {
+ new_size = map_size * 1.10;
+ } else {
+ new_size = map_size * 1.25;
+ }
+ if (new_size < map_size) {
+ goto overflow;
+ }
+
+ /* Round the database up to a multiple of the page size */
+ new_size = MAX(top_size, new_size);
+
+ if (new_size + page_size < new_size) {
+ /* There's a "+" in TDB_ALIGN that might overflow... */
+ goto overflow;
+ }
+
+ return TDB_ALIGN(new_size, page_size) - map_size;
+
+overflow:
+ /*
+ * Somewhere in between we went over 4GB. Make one big jump to
+ * exactly 4GB database size.
+ */
+ return max_size;
+}
+
+/* expand the database at least size bytes by expanding the underlying
+ file and doing the mmap again if necessary */
+int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
+{
+ struct tdb_record rec;
+ tdb_off_t offset;
+ tdb_off_t new_size;
+
+ if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
+ return -1;
+ }
+
+ /* must know about any previous expansions by another process */
+ tdb_oob(tdb, tdb->map_size, 1, 1);
+
+ /*
+ * Note: that we don't care about tdb->hdr_ofs != 0 here
+ *
+ * The 4GB limitation is just related to tdb->map_size
+ * and the offset calculation in the records.
+ *
+ * The file on disk can be up to 4GB + tdb->hdr_ofs
+ */
+ size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size);
+
+ if (!tdb_add_off_t(tdb->map_size, size, &new_size)) {
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_expand "
+ "overflow detected current map_size[%u] size[%u]!\n",
+ (unsigned)tdb->map_size, (unsigned)size));
+ goto fail;
+ }
+
+ /* form a new freelist record */
+ offset = tdb->map_size;
+ memset(&rec,'\0',sizeof(rec));
+ rec.rec_len = size - sizeof(rec);
+
+ if (tdb->flags & TDB_INTERNAL) {
+ char *new_map_ptr;
+
+ new_map_ptr = (char *)realloc(tdb->map_ptr, new_size);
+ if (!new_map_ptr) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+ tdb->map_ptr = new_map_ptr;
+ tdb->map_size = new_size;
+ } else {
+ int ret;
+
+ /*
+ * expand the file itself
+ */
+ ret = tdb->methods->tdb_expand_file(tdb, tdb->map_size, size);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ /* Explicitly remap: if we're in a transaction, this won't
+ * happen automatically! */
+ tdb_munmap(tdb);
+ tdb->map_size = new_size;
+ if (tdb_mmap(tdb) != 0) {
+ goto fail;
+ }
+ }
+
+ /* link it into the free list */
+ if (tdb_free(tdb, offset, &rec) == -1)
+ goto fail;
+
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return 0;
+ fail:
+ tdb_unlock(tdb, -1, F_WRLCK);
+ return -1;
+}
+
+int _tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe)
+{
+ int ret = tdb->methods->tdb_oob(tdb, off, len, probe);
+ return ret;
+}
+
+/* read/write a tdb_off_t */
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
+{
+ return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
+}
+
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
+{
+ tdb_off_t off = *d;
+ return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
+}
+
+
+/* read a lump of data, allocating the space for it */
+unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
+{
+ unsigned char *buf;
+
+ /* some systems don't like zero length malloc */
+
+ if (!(buf = (unsigned char *)malloc(len ? len : 1))) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%u (%s)\n",
+ len, strerror(errno)));
+ return NULL;
+ }
+ if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+/* Give a piece of tdb data to a parser */
+
+int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
+ tdb_off_t offset, tdb_len_t len,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ TDB_DATA data;
+ int result;
+
+ data.dsize = len;
+
+ if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) {
+ /*
+ * Optimize by avoiding the malloc/memcpy/free, point the
+ * parser directly at the mmap area.
+ */
+ if (tdb_oob(tdb, offset, len, 0) != 0) {
+ return -1;
+ }
+ data.dptr = offset + (unsigned char *)tdb->map_ptr;
+ return parser(key, data, private_data);
+ }
+
+ if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) {
+ return -1;
+ }
+
+ result = parser(key, data, private_data);
+ free(data.dptr);
+ return result;
+}
+
+/* read/write a record */
+int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
+{
+ int ret;
+ tdb_len_t overall_len;
+
+ if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
+ return -1;
+ if (TDB_BAD_MAGIC(rec)) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%u\n", rec->magic, offset));
+ return -1;
+ }
+
+ overall_len = rec->key_len + rec->data_len;
+ if (overall_len < rec->data_len) {
+ /* overflow */
+ return -1;
+ }
+
+ if (overall_len > rec->rec_len) {
+ /* invalid record */
+ return -1;
+ }
+
+ ret = tdb_oob(tdb, offset, rec->key_len, 1);
+ if (ret == -1) {
+ return -1;
+ }
+ ret = tdb_oob(tdb, offset, rec->data_len, 1);
+ if (ret == -1) {
+ return -1;
+ }
+ ret = tdb_oob(tdb, offset, rec->rec_len, 1);
+ if (ret == -1) {
+ return -1;
+ }
+
+ return tdb_oob(tdb, rec->next, sizeof(*rec), 0);
+}
+
+int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
+{
+ struct tdb_record r = *rec;
+ return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r));
+}
+
+static const struct tdb_methods io_methods = {
+ tdb_read,
+ tdb_write,
+ tdb_next_hash_chain,
+ tdb_notrans_oob,
+ tdb_expand_file,
+};
+
+/*
+ initialise the default methods table
+*/
+void tdb_io_init(struct tdb_context *tdb)
+{
+ tdb->methods = &io_methods;
+}
diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
new file mode 100644
index 0000000..045ded9
--- /dev/null
+++ b/lib/tdb/common/lock.c
@@ -0,0 +1,1033 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+_PUBLIC_ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr)
+{
+ tdb->interrupt_sig_ptr = ptr;
+}
+
+static int fcntl_lock(struct tdb_context *tdb,
+ int rw, off_t off, off_t len, bool waitflag)
+{
+ struct flock fl;
+ int cmd;
+
+#ifdef USE_TDB_MUTEX_LOCKING
+ {
+ int ret;
+ if (tdb_mutex_lock(tdb, rw, off, len, waitflag, &ret)) {
+ return ret;
+ }
+ }
+#endif
+
+ fl.l_type = rw;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ cmd = waitflag ? F_SETLKW : F_SETLK;
+
+ return fcntl(tdb->fd, cmd, &fl);
+}
+
+static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len)
+{
+ struct flock fl;
+#if 0 /* Check they matched up locks and unlocks correctly. */
+ char line[80];
+ FILE *locks;
+ bool found = false;
+
+ locks = fopen("/proc/locks", "r");
+
+ while (fgets(line, 80, locks)) {
+ char *p;
+ int type, start, l;
+
+ /* eg. 1: FLOCK ADVISORY WRITE 2440 08:01:2180826 0 EOF */
+ p = strchr(line, ':') + 1;
+ if (strncmp(p, " POSIX ADVISORY ", strlen(" POSIX ADVISORY ")))
+ continue;
+ p += strlen(" FLOCK ADVISORY ");
+ if (strncmp(p, "READ ", strlen("READ ")) == 0)
+ type = F_RDLCK;
+ else if (strncmp(p, "WRITE ", strlen("WRITE ")) == 0)
+ type = F_WRLCK;
+ else
+ abort();
+ p += 6;
+ if (atoi(p) != getpid())
+ continue;
+ p = strchr(strchr(p, ' ') + 1, ' ') + 1;
+ start = atoi(p);
+ p = strchr(p, ' ') + 1;
+ if (strncmp(p, "EOF", 3) == 0)
+ l = 0;
+ else
+ l = atoi(p) - start + 1;
+
+ if (off == start) {
+ if (len != l) {
+ fprintf(stderr, "Len %u should be %u: %s",
+ (int)len, l, line);
+ abort();
+ }
+ if (type != rw) {
+ fprintf(stderr, "Type %s wrong: %s",
+ rw == F_RDLCK ? "READ" : "WRITE", line);
+ abort();
+ }
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ fprintf(stderr, "Unlock on %u@%u not found!\n",
+ (int)off, (int)len);
+ abort();
+ }
+
+ fclose(locks);
+#endif
+
+#ifdef USE_TDB_MUTEX_LOCKING
+ {
+ int ret;
+ if (tdb_mutex_unlock(tdb, rw, off, len, &ret)) {
+ return ret;
+ }
+ }
+#endif
+
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ return fcntl(tdb->fd, F_SETLKW, &fl);
+}
+
+/*
+ * Calculate the lock offset for a list
+ *
+ * list -1 is the freelist, otherwise a hash chain.
+ *
+ * Note that we consistently (but without real reason) lock hash chains at an
+ * offset that is 4 bytes below the real offset of the corresponding list head
+ * in the db.
+ *
+ * This is the memory layout of the hashchain array:
+ *
+ * FREELIST_TOP + 0 = freelist
+ * FREELIST_TOP + 4 = hashtable list 0
+ * FREELIST_TOP + 8 = hashtable list 1
+ * ...
+ *
+ * Otoh lock_offset computes:
+ *
+ * freelist = FREELIST_TOP - 4
+ * list 0 = FREELIST_TOP + 0
+ * list 1 = FREELIST_TOP + 4
+ * ...
+ *
+ * Unfortunately we can't change this calculation in order to align the locking
+ * offset with the memory layout, as that would make the locking incompatible
+ * between different tdb versions.
+ */
+static tdb_off_t lock_offset(int list)
+{
+ return FREELIST_TOP + 4*list;
+}
+
+/* a byte range locking function - return 0 on success
+ this functions locks/unlocks "len" byte at the specified offset.
+
+ On error, errno is also set so that errors are passed back properly
+ through tdb_open().
+
+ note that a len of zero means lock to end of file
+*/
+int tdb_brlock(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len,
+ enum tdb_lock_flags flags)
+{
+ int ret;
+
+ if (tdb->flags & TDB_NOLOCK) {
+ return 0;
+ }
+
+ if (flags & TDB_LOCK_MARK_ONLY) {
+ return 0;
+ }
+
+ if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ do {
+ ret = fcntl_lock(tdb, rw_type, offset, len,
+ flags & TDB_LOCK_WAIT);
+ /* Check for a sigalarm break. */
+ if (ret == -1 && errno == EINTR &&
+ tdb->interrupt_sig_ptr &&
+ *tdb->interrupt_sig_ptr) {
+ break;
+ }
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ tdb->ecode = TDB_ERR_LOCK;
+ /* Generic lock error. errno set by fcntl.
+ * EAGAIN is an expected return from non-blocking
+ * locks. */
+ if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) {
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %u rw_type=%d flags=%d len=%zu\n",
+ tdb->fd, offset, rw_type, flags, len));
+ }
+ return -1;
+ }
+ return 0;
+}
+
+int tdb_brunlock(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len)
+{
+ int ret;
+
+ if (tdb->flags & TDB_NOLOCK) {
+ return 0;
+ }
+
+ do {
+ ret = fcntl_unlock(tdb, rw_type, offset, len);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %u rw_type=%u len=%zu\n",
+ tdb->fd, offset, rw_type, len));
+ }
+ return ret;
+}
+
+/*
+ * Do a tdb_brlock in a loop. Some OSes (such as solaris) have too
+ * conservative deadlock detection and claim a deadlock when progress can be
+ * made. For those OSes we may loop for a while.
+ */
+
+static int tdb_brlock_retry(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len,
+ enum tdb_lock_flags flags)
+{
+ int count = 1000;
+
+ while (count--) {
+ struct timeval tv;
+ int ret;
+
+ ret = tdb_brlock(tdb, rw_type, offset, len, flags);
+ if (ret == 0) {
+ return 0;
+ }
+ if (errno != EDEADLK) {
+ break;
+ }
+ /* sleep for as short a time as we can - more portable than usleep() */
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ select(0, NULL, NULL, NULL, &tv);
+ }
+ return -1;
+}
+
+/*
+ upgrade a read lock to a write lock.
+*/
+int tdb_allrecord_upgrade(struct tdb_context *tdb)
+{
+ int ret;
+
+ if (tdb->allrecord_lock.count != 1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_allrecord_upgrade failed: count %u too high\n",
+ tdb->allrecord_lock.count));
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb->allrecord_lock.off != 1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_allrecord_upgrade failed: already upgraded?\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb_have_mutexes(tdb)) {
+ ret = tdb_mutex_allrecord_upgrade(tdb);
+ if (ret == -1) {
+ goto fail;
+ }
+ ret = tdb_brlock_retry(tdb, F_WRLCK, lock_offset(tdb->hash_size),
+ 0, TDB_LOCK_WAIT|TDB_LOCK_PROBE);
+ if (ret == -1) {
+ tdb_mutex_allrecord_downgrade(tdb);
+ }
+ } else {
+ ret = tdb_brlock_retry(tdb, F_WRLCK, FREELIST_TOP, 0,
+ TDB_LOCK_WAIT|TDB_LOCK_PROBE);
+ }
+
+ if (ret == 0) {
+ tdb->allrecord_lock.ltype = F_WRLCK;
+ tdb->allrecord_lock.off = 0;
+ return 0;
+ }
+fail:
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n"));
+ return -1;
+}
+
+static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb,
+ tdb_off_t offset)
+{
+ int i;
+
+ for (i=0; i<tdb->num_lockrecs; i++) {
+ if (tdb->lockrecs[i].off == offset) {
+ return &tdb->lockrecs[i];
+ }
+ }
+ return NULL;
+}
+
+/* lock an offset in the database. */
+int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
+ enum tdb_lock_flags flags)
+{
+ struct tdb_lock_type *new_lck;
+
+ if (offset >= lock_offset(tdb->hash_size)) {
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n",
+ offset, ltype));
+ return -1;
+ }
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+
+ new_lck = find_nestlock(tdb, offset);
+ if (new_lck) {
+ if ((new_lck->ltype == F_RDLCK) && (ltype == F_WRLCK)) {
+ if (!tdb_have_mutexes(tdb)) {
+ int ret;
+ /*
+ * Upgrade the underlying fcntl
+ * lock. Mutexes don't do readlocks,
+ * so this only applies to fcntl
+ * locking.
+ */
+ ret = tdb_brlock(tdb, ltype, offset, 1, flags);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ new_lck->ltype = F_WRLCK;
+ }
+ /*
+ * Just increment the in-memory struct, posix locks
+ * don't stack.
+ */
+ new_lck->count++;
+ return 0;
+ }
+
+ if (tdb->num_lockrecs == tdb->lockrecs_array_length) {
+ new_lck = (struct tdb_lock_type *)realloc(
+ tdb->lockrecs,
+ sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
+ if (new_lck == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ tdb->lockrecs_array_length = tdb->num_lockrecs+1;
+ tdb->lockrecs = new_lck;
+ }
+
+ /* Since fcntl locks don't nest, we do a lock for the first one,
+ and simply bump the count for future ones */
+ if (tdb_brlock(tdb, ltype, offset, 1, flags)) {
+ return -1;
+ }
+
+ new_lck = &tdb->lockrecs[tdb->num_lockrecs];
+
+ new_lck->off = offset;
+ new_lck->count = 1;
+ new_lck->ltype = ltype;
+ tdb->num_lockrecs++;
+
+ return 0;
+}
+
+static int tdb_lock_and_recover(struct tdb_context *tdb)
+{
+ int ret;
+
+ /* We need to match locking order in transaction commit. */
+ if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT)) {
+ return -1;
+ }
+
+ if (tdb_brlock(tdb, F_WRLCK, OPEN_LOCK, 1, TDB_LOCK_WAIT)) {
+ tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
+ return -1;
+ }
+
+ ret = tdb_transaction_recover(tdb);
+
+ tdb_brunlock(tdb, F_WRLCK, OPEN_LOCK, 1);
+ tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
+
+ return ret;
+}
+
+static bool have_data_locks(const struct tdb_context *tdb)
+{
+ int i;
+
+ for (i = 0; i < tdb->num_lockrecs; i++) {
+ if (tdb->lockrecs[i].off >= lock_offset(-1))
+ return true;
+ }
+ return false;
+}
+
+/*
+ * A allrecord lock allows us to avoid per chain locks. Check if the allrecord
+ * lock is strong enough.
+ */
+static int tdb_lock_covered_by_allrecord_lock(struct tdb_context *tdb,
+ int ltype)
+{
+ if (ltype == F_RDLCK) {
+ /*
+ * The allrecord_lock is equal (F_RDLCK) or stronger
+ * (F_WRLCK). Pass.
+ */
+ return 0;
+ }
+
+ if (tdb->allrecord_lock.ltype == F_RDLCK) {
+ /*
+ * We ask for ltype==F_WRLCK, but the allrecord_lock
+ * is too weak. We can't upgrade here, so fail.
+ */
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ /*
+ * Asking for F_WRLCK, allrecord is F_WRLCK as well. Pass.
+ */
+ return 0;
+}
+
+static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype,
+ enum tdb_lock_flags waitflag)
+{
+ int ret;
+ bool check = false;
+
+ if (tdb->allrecord_lock.count) {
+ return tdb_lock_covered_by_allrecord_lock(tdb, ltype);
+ }
+
+ /*
+ * Check for recoveries: Someone might have kill -9'ed a process
+ * during a commit.
+ */
+ check = !have_data_locks(tdb);
+ ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag);
+
+ if (ret == 0 && check && tdb_needs_recovery(tdb)) {
+ tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
+
+ if (tdb_lock_and_recover(tdb) == -1) {
+ return -1;
+ }
+ return tdb_lock_list(tdb, list, ltype, waitflag);
+ }
+ return ret;
+}
+
+/* lock a list in the database. list -1 is the alloc list */
+int tdb_lock(struct tdb_context *tdb, int list, int ltype)
+{
+ int ret;
+
+ ret = tdb_lock_list(tdb, list, ltype, TDB_LOCK_WAIT);
+ if (ret) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
+ "ltype=%d (%s)\n", list, ltype, strerror(errno)));
+ }
+ return ret;
+}
+
+/* lock a list in the database. list -1 is the alloc list. non-blocking lock */
+_PUBLIC_ int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
+_PUBLIC_ int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype)
+{
+ return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT);
+}
+
+
+int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
+ bool mark_lock)
+{
+ int ret = -1;
+ struct tdb_lock_type *lck;
+
+ if (tdb->flags & TDB_NOLOCK)
+ return 0;
+
+ /* Sanity checks */
+ if (offset >= lock_offset(tdb->hash_size)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->hash_size));
+ return ret;
+ }
+
+ lck = find_nestlock(tdb, offset);
+ if ((lck == NULL) || (lck->count == 0)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
+ return -1;
+ }
+
+ if (lck->count > 1) {
+ lck->count--;
+ return 0;
+ }
+
+ /*
+ * This lock has count==1 left, so we need to unlock it in the
+ * kernel. We don't bother with decrementing the in-memory array
+ * element, we're about to overwrite it with the last array element
+ * anyway.
+ */
+
+ if (mark_lock) {
+ ret = 0;
+ } else {
+ ret = tdb_brunlock(tdb, ltype, offset, 1);
+ }
+
+ /*
+ * Shrink the array by overwriting the element just unlocked with the
+ * last array element.
+ */
+ *lck = tdb->lockrecs[--tdb->num_lockrecs];
+
+ /*
+ * We don't bother with realloc when the array shrinks, but if we have
+ * a completely idle tdb we should get rid of the locked array.
+ */
+
+ if (ret)
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));
+ return ret;
+}
+
+_PUBLIC_ int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
+_PUBLIC_ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
+{
+ /* a global lock allows us to avoid per chain locks */
+ if (tdb->allrecord_lock.count) {
+ return tdb_lock_covered_by_allrecord_lock(tdb, ltype);
+ }
+
+ return tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
+}
+
+/*
+ get the transaction lock
+ */
+int tdb_transaction_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags lockflags)
+{
+ return tdb_nest_lock(tdb, TRANSACTION_LOCK, ltype, lockflags);
+}
+
+/*
+ release the transaction lock
+ */
+int tdb_transaction_unlock(struct tdb_context *tdb, int ltype)
+{
+ return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false);
+}
+
+/* Returns 0 if all done, -1 if error, 1 if ok. */
+static int tdb_allrecord_check(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags flags, bool upgradable)
+{
+ /* There are no locks on read-only dbs */
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb->allrecord_lock.count &&
+ tdb->allrecord_lock.ltype == (uint32_t)ltype) {
+ tdb->allrecord_lock.count++;
+ return 0;
+ }
+
+ if (tdb->allrecord_lock.count) {
+ /* a global lock of a different type exists */
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb_have_extra_locks(tdb)) {
+ /* can't combine global and chain locks */
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (upgradable && ltype != F_RDLCK) {
+ /* tdb error: you can't upgrade a write lock! */
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+ return 1;
+}
+
+/* We only need to lock individual bytes, but Linux merges consecutive locks
+ * so we lock in contiguous ranges. */
+static int tdb_chainlock_gradual(struct tdb_context *tdb,
+ int ltype, enum tdb_lock_flags flags,
+ size_t off, size_t len)
+{
+ int ret;
+ enum tdb_lock_flags nb_flags = (flags & ~TDB_LOCK_WAIT);
+
+ if (len <= 4) {
+ /* Single record. Just do blocking lock. */
+ return tdb_brlock(tdb, ltype, off, len, flags);
+ }
+
+ /* First we try non-blocking. */
+ ret = tdb_brlock(tdb, ltype, off, len, nb_flags);
+ if (ret == 0) {
+ return 0;
+ }
+
+ /* Try locking first half, then second. */
+ ret = tdb_chainlock_gradual(tdb, ltype, flags, off, len / 2);
+ if (ret == -1)
+ return -1;
+
+ ret = tdb_chainlock_gradual(tdb, ltype, flags,
+ off + len / 2, len - len / 2);
+ if (ret == -1) {
+ tdb_brunlock(tdb, ltype, off, len / 2);
+ return -1;
+ }
+ return 0;
+}
+
+/* lock/unlock entire database. It can only be upgradable if you have some
+ * other way of guaranteeing exclusivity (ie. transaction write lock).
+ * We do the locking gradually to avoid being starved by smaller locks. */
+int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags flags, bool upgradable)
+{
+ int ret;
+
+ switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) {
+ case -1:
+ return -1;
+ case 0:
+ return 0;
+ }
+
+ /* We cover two kinds of locks:
+ * 1) Normal chain locks. Taken for almost all operations.
+ * 2) Individual records locks. Taken after normal or free
+ * chain locks.
+ *
+ * It is (1) which cause the starvation problem, so we're only
+ * gradual for that. */
+
+ if (tdb_have_mutexes(tdb)) {
+ ret = tdb_mutex_allrecord_lock(tdb, ltype, flags);
+ } else {
+ ret = tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP,
+ tdb->hash_size * 4);
+ }
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* Grab individual record locks. */
+ if (tdb_brlock(tdb, ltype, lock_offset(tdb->hash_size), 0,
+ flags) == -1) {
+ if (tdb_have_mutexes(tdb)) {
+ tdb_mutex_allrecord_unlock(tdb);
+ } else {
+ tdb_brunlock(tdb, ltype, FREELIST_TOP,
+ tdb->hash_size * 4);
+ }
+ return -1;
+ }
+
+ tdb->allrecord_lock.count = 1;
+ /* If it's upgradable, it's actually exclusive so we can treat
+ * it as a write lock. */
+ tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype;
+ tdb->allrecord_lock.off = upgradable;
+
+ if (tdb_needs_recovery(tdb)) {
+ bool mark = flags & TDB_LOCK_MARK_ONLY;
+ tdb_allrecord_unlock(tdb, ltype, mark);
+ if (mark) {
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_lockall_mark cannot do recovery\n"));
+ return -1;
+ }
+ if (tdb_lock_and_recover(tdb) == -1) {
+ return -1;
+ }
+ return tdb_allrecord_lock(tdb, ltype, flags, upgradable);
+ }
+
+ return 0;
+}
+
+
+
+/* unlock entire db */
+int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock)
+{
+ /* There are no locks on read-only dbs */
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb->allrecord_lock.count == 0) {
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ /* Upgradable locks are marked as write locks. */
+ if (tdb->allrecord_lock.ltype != (uint32_t)ltype
+ && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) {
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb->allrecord_lock.count > 1) {
+ tdb->allrecord_lock.count--;
+ return 0;
+ }
+
+ if (!mark_lock) {
+ int ret;
+
+ if (tdb_have_mutexes(tdb)) {
+ ret = tdb_mutex_allrecord_unlock(tdb);
+ if (ret == 0) {
+ ret = tdb_brunlock(tdb, ltype,
+ lock_offset(tdb->hash_size),
+ 0);
+ }
+ } else {
+ ret = tdb_brunlock(tdb, ltype, FREELIST_TOP, 0);
+ }
+
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed "
+ "(%s)\n", strerror(errno)));
+ return -1;
+ }
+ }
+
+ tdb->allrecord_lock.count = 0;
+ tdb->allrecord_lock.ltype = 0;
+
+ return 0;
+}
+
+/* lock entire database with write lock */
+_PUBLIC_ int tdb_lockall(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_lockall");
+ return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
+}
+
+/* lock entire database with write lock - mark only */
+_PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_lockall_mark");
+ return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false);
+}
+
+/* unlock entire database with write lock - unmark only */
+_PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_lockall_unmark");
+ return tdb_allrecord_unlock(tdb, F_WRLCK, true);
+}
+
+/* lock entire database with write lock - nonblocking variant */
+_PUBLIC_ int tdb_lockall_nonblock(struct tdb_context *tdb)
+{
+ int ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false);
+ tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret);
+ return ret;
+}
+
+/* unlock entire database with write lock */
+_PUBLIC_ int tdb_unlockall(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_unlockall");
+ return tdb_allrecord_unlock(tdb, F_WRLCK, false);
+}
+
+/* lock entire database with read lock */
+_PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_lockall_read");
+ return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
+}
+
+/* lock entire database with read lock - nonblock variant */
+_PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb)
+{
+ int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false);
+ tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret);
+ return ret;
+}
+
+/* unlock entire database with read lock */
+_PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_unlockall_read");
+ return tdb_allrecord_unlock(tdb, F_RDLCK, false);
+}
+
+/* lock/unlock one hash chain. This is meant to be used to reduce
+ contention - it cannot guarantee how many records will be locked */
+_PUBLIC_ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
+{
+ int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+ tdb_trace_1rec(tdb, "tdb_chainlock", key);
+ return ret;
+}
+
+/* lock/unlock one hash chain, non-blocking. This is meant to be used
+ to reduce contention - it cannot guarantee how many records will be
+ locked */
+_PUBLIC_ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
+{
+ int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+ tdb_trace_1rec_ret(tdb, "tdb_chainlock_nonblock", key, ret);
+ return ret;
+}
+
+/* mark a chain as locked without actually locking it. Warning! use with great caution! */
+_PUBLIC_ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key)
+{
+ int ret = tdb_nest_lock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
+ F_WRLCK, TDB_LOCK_MARK_ONLY);
+ tdb_trace_1rec(tdb, "tdb_chainlock_mark", key);
+ return ret;
+}
+
+/* unmark a chain as locked without actually locking it. Warning! use with great caution! */
+_PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)
+{
+ tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key);
+ return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
+ F_WRLCK, true);
+}
+
+_PUBLIC_ int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
+{
+ tdb_trace_1rec(tdb, "tdb_chainunlock", key);
+ return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+}
+
+_PUBLIC_ int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
+{
+ int ret;
+ ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+ tdb_trace_1rec(tdb, "tdb_chainlock_read", key);
+ return ret;
+}
+
+_PUBLIC_ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
+{
+ tdb_trace_1rec(tdb, "tdb_chainunlock_read", key);
+ return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+}
+
+_PUBLIC_ int tdb_chainlock_read_nonblock(struct tdb_context *tdb, TDB_DATA key)
+{
+ int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+ tdb_trace_1rec_ret(tdb, "tdb_chainlock_read_nonblock", key, ret);
+ return ret;
+}
+
+/* record lock stops delete underneath */
+int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ if (tdb->allrecord_lock.count) {
+ return 0;
+ }
+ return off ? tdb_brlock(tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT) : 0;
+}
+
+/*
+ Write locks override our own fcntl readlocks, so check it here.
+ Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
+ an error to fail to get the lock here.
+*/
+int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ struct tdb_traverse_lock *i;
+ if (tdb == NULL) {
+ return -1;
+ }
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ return -1;
+ if (tdb->allrecord_lock.count) {
+ if (tdb->allrecord_lock.ltype == F_WRLCK) {
+ return 0;
+ }
+ return -1;
+ }
+ return tdb_brlock(tdb, F_WRLCK, off, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+}
+
+int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ if (tdb->allrecord_lock.count) {
+ return 0;
+ }
+ return tdb_brunlock(tdb, F_WRLCK, off, 1);
+}
+
+/* fcntl locks don't stack: avoid unlocking someone else's */
+int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off)
+{
+ struct tdb_traverse_lock *i;
+ uint32_t count = 0;
+
+ if (tdb->allrecord_lock.count) {
+ return 0;
+ }
+
+ if (off == 0)
+ return 0;
+ for (i = &tdb->travlocks; i; i = i->next)
+ if (i->off == off)
+ count++;
+ return (count == 1 ? tdb_brunlock(tdb, F_RDLCK, off, 1) : 0);
+}
+
+bool tdb_have_extra_locks(struct tdb_context *tdb)
+{
+ unsigned int extra = tdb->num_lockrecs;
+
+ /* A transaction holds the lock for all records. */
+ if (!tdb->transaction && tdb->allrecord_lock.count) {
+ return true;
+ }
+
+ /* We always hold the active lock if CLEAR_IF_FIRST. */
+ if (find_nestlock(tdb, ACTIVE_LOCK)) {
+ extra--;
+ }
+
+ /* In a transaction, we expect to hold the transaction lock */
+ if (tdb->transaction && find_nestlock(tdb, TRANSACTION_LOCK)) {
+ extra--;
+ }
+
+ return extra;
+}
+
+/* The transaction code uses this to remove all locks. */
+void tdb_release_transaction_locks(struct tdb_context *tdb)
+{
+ int i;
+ unsigned int active = 0;
+
+ if (tdb->allrecord_lock.count != 0) {
+ tdb_allrecord_unlock(tdb, tdb->allrecord_lock.ltype, false);
+ tdb->allrecord_lock.count = 0;
+ }
+
+ for (i=0;i<tdb->num_lockrecs;i++) {
+ struct tdb_lock_type *lck = &tdb->lockrecs[i];
+
+ /* Don't release the active lock! Copy it to first entry. */
+ if (lck->off == ACTIVE_LOCK) {
+ tdb->lockrecs[active++] = *lck;
+ } else {
+ tdb_brunlock(tdb, lck->ltype, lck->off, 1);
+ }
+ }
+ tdb->num_lockrecs = active;
+}
+
+/* Following functions are added specifically to support CTDB. */
+
+/* Don't do actual fcntl locking, just mark tdb locked */
+_PUBLIC_ int tdb_transaction_write_lock_mark(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_write_lock_mark(struct tdb_context *tdb)
+{
+ return tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY);
+}
+
+/* Don't do actual fcntl unlocking, just mark tdb unlocked */
+_PUBLIC_ int tdb_transaction_write_lock_unmark(struct tdb_context *tdb);
+_PUBLIC_ int tdb_transaction_write_lock_unmark(struct tdb_context *tdb)
+{
+ return tdb_nest_unlock(tdb, TRANSACTION_LOCK, F_WRLCK, true);
+}
diff --git a/lib/tdb/common/mutex.c b/lib/tdb/common/mutex.c
new file mode 100644
index 0000000..a710616
--- /dev/null
+++ b/lib/tdb/common/mutex.c
@@ -0,0 +1,1078 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Volker Lendecke 2012,2013
+ Copyright (C) Stefan Metzmacher 2013,2014
+ Copyright (C) Michael Adam 2014
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "tdb_private.h"
+#include "system/threads.h"
+
+#ifdef USE_TDB_MUTEX_LOCKING
+
+/*
+ * If we run with mutexes, we store the "struct tdb_mutexes" at the
+ * beginning of the file. We store an additional tdb_header right
+ * beyond the mutex area, page aligned. All the offsets within the tdb
+ * are relative to the area behind the mutex area. tdb->map_ptr points
+ * behind the mmap area as well, so the read and write path in the
+ * mutex case can remain unchanged.
+ *
+ * Early in the mutex development the mutexes were placed between the hash
+ * chain pointers and the real tdb data. This had two drawbacks: First, it
+ * made pointer calculations more complex. Second, we had to mmap the mutex
+ * area twice. One was the normal map_ptr in the tdb. This frequently changed
+ * from within tdb_oob. At least the Linux glibc robust mutex code assumes
+ * constant pointers in memory, so a constantly changing mmap area destroys
+ * the mutex list. So we had to mmap the first bytes of the file with a second
+ * mmap call. With that scheme, very weird errors happened that could be
+ * easily fixed by doing the mutex mmap in a second file. It seemed that
+ * mapping the same memory area twice does not end up in accessing the same
+ * physical page, looking at the mutexes in gdb it seemed that old data showed
+ * up after some re-mapping. To avoid a separate mutex file, the code now puts
+ * the real content of the tdb file after the mutex area. This way we do not
+ * have overlapping mmap areas, the mutex area is mmapped once and not
+ * changed, the tdb data area's mmap is constantly changed but does not
+ * overlap.
+ */
+
+struct tdb_mutexes {
+ struct tdb_header hdr;
+
+ /* protect allrecord_lock */
+ pthread_mutex_t allrecord_mutex;
+
+ /*
+ * F_UNLCK: free,
+ * F_RDLCK: shared,
+ * F_WRLCK: exclusive
+ */
+ short int allrecord_lock;
+
+ /*
+ * Index 0 is the freelist mutex, followed by
+ * one mutex per hashchain.
+ */
+ pthread_mutex_t hashchains[1];
+};
+
+bool tdb_have_mutexes(struct tdb_context *tdb)
+{
+ return ((tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) != 0);
+}
+
+size_t tdb_mutex_size(struct tdb_context *tdb)
+{
+ size_t mutex_size;
+
+ if (!tdb_have_mutexes(tdb)) {
+ return 0;
+ }
+
+ mutex_size = sizeof(struct tdb_mutexes);
+ mutex_size += tdb->hash_size * sizeof(pthread_mutex_t);
+
+ return TDB_ALIGN(mutex_size, tdb->page_size);
+}
+
+/*
+ * Get the index for a chain mutex
+ */
+static bool tdb_mutex_index(struct tdb_context *tdb, off_t off, off_t len,
+ unsigned *idx)
+{
+ /*
+ * Weird but true: We fcntl lock 1 byte at an offset 4 bytes before
+ * the 4 bytes of the freelist start and the hash chain that is about
+ * to be locked. See lock_offset() where the freelist is -1 vs the
+ * "+1" in TDB_HASH_TOP(). Because the mutex array is represented in
+ * the tdb file itself as data, we need to adjust the offset here.
+ */
+ const off_t freelist_lock_ofs = FREELIST_TOP - sizeof(tdb_off_t);
+
+ if (!tdb_have_mutexes(tdb)) {
+ return false;
+ }
+ if (len != 1) {
+ /* Possibly the allrecord lock */
+ return false;
+ }
+ if (off < freelist_lock_ofs) {
+ /* One of the special locks */
+ return false;
+ }
+ if (tdb->hash_size == 0) {
+ /* tdb not initialized yet, called from tdb_open_ex() */
+ return false;
+ }
+ if (off >= TDB_DATA_START(tdb->hash_size)) {
+ /* Single record lock from traverses */
+ return false;
+ }
+
+ /*
+ * Now we know it's a freelist or hash chain lock. Those are always 4
+ * byte aligned. Paranoia check.
+ */
+ if ((off % sizeof(tdb_off_t)) != 0) {
+ abort();
+ }
+
+ /*
+ * Re-index the fcntl offset into an offset into the mutex array
+ */
+ off -= freelist_lock_ofs; /* rebase to index 0 */
+ off /= sizeof(tdb_off_t); /* 0 for freelist 1-n for hashchain */
+
+ *idx = off;
+ return true;
+}
+
+static bool tdb_have_mutex_chainlocks(struct tdb_context *tdb)
+{
+ int i;
+
+ for (i=0; i < tdb->num_lockrecs; i++) {
+ bool ret;
+ unsigned idx;
+
+ ret = tdb_mutex_index(tdb,
+ tdb->lockrecs[i].off,
+ tdb->lockrecs[i].count,
+ &idx);
+ if (!ret) {
+ continue;
+ }
+
+ if (idx == 0) {
+ /* this is the freelist mutex */
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+static int chain_mutex_lock(pthread_mutex_t *m, bool waitflag)
+{
+ int ret;
+
+ if (waitflag) {
+ ret = pthread_mutex_lock(m);
+ } else {
+ ret = pthread_mutex_trylock(m);
+ }
+ if (ret != EOWNERDEAD) {
+ return ret;
+ }
+
+ /*
+ * For chainlocks, we don't do any cleanup (yet?)
+ */
+ return pthread_mutex_consistent(m);
+}
+
+static int allrecord_mutex_lock(struct tdb_mutexes *m, bool waitflag)
+{
+ int ret;
+
+ if (waitflag) {
+ ret = pthread_mutex_lock(&m->allrecord_mutex);
+ } else {
+ ret = pthread_mutex_trylock(&m->allrecord_mutex);
+ }
+ if (ret != EOWNERDEAD) {
+ return ret;
+ }
+
+ /*
+ * The allrecord lock holder died. We need to reset the allrecord_lock
+ * to F_UNLCK. This should also be the indication for
+ * tdb_needs_recovery.
+ */
+ m->allrecord_lock = F_UNLCK;
+
+ return pthread_mutex_consistent(&m->allrecord_mutex);
+}
+
+bool tdb_mutex_lock(struct tdb_context *tdb, int rw, off_t off, off_t len,
+ bool waitflag, int *pret)
+{
+ struct tdb_mutexes *m = tdb->mutexes;
+ pthread_mutex_t *chain;
+ int ret;
+ unsigned idx;
+ bool allrecord_ok;
+
+ if (!tdb_mutex_index(tdb, off, len, &idx)) {
+ return false;
+ }
+ chain = &m->hashchains[idx];
+
+again:
+ ret = chain_mutex_lock(chain, waitflag);
+ if (ret == EBUSY) {
+ ret = EAGAIN;
+ }
+ if (ret != 0) {
+ errno = ret;
+ goto fail;
+ }
+
+ if (idx == 0) {
+ /*
+ * This is a freelist lock, which is independent to
+ * the allrecord lock. So we're done once we got the
+ * freelist mutex.
+ */
+ *pret = 0;
+ return true;
+ }
+
+ if (tdb_have_mutex_chainlocks(tdb)) {
+ /*
+ * We can only check the allrecord lock once. If we do it with
+ * one chain mutex locked, we will deadlock with the allrecord
+ * locker process in the following way: We lock the first hash
+ * chain, we check for the allrecord lock. We keep the hash
+ * chain locked. Then the allrecord locker locks the
+ * allrecord_mutex. It walks the list of chain mutexes,
+ * locking them all in sequence. Meanwhile, we have the chain
+ * mutex locked, so the allrecord locker blocks trying to lock
+ * our chain mutex. Then we come in and try to lock the second
+ * chain lock, which in most cases will be the freelist. We
+ * see that the allrecord lock is locked and put ourselves on
+ * the allrecord_mutex. This will never be signalled though
+ * because the allrecord locker waits for us to give up the
+ * chain lock.
+ */
+
+ *pret = 0;
+ return true;
+ }
+
+ /*
+ * Check if someone is has the allrecord lock: queue if so.
+ */
+
+ allrecord_ok = false;
+
+ if (m->allrecord_lock == F_UNLCK) {
+ /*
+ * allrecord lock not taken
+ */
+ allrecord_ok = true;
+ }
+
+ if ((m->allrecord_lock == F_RDLCK) && (rw == F_RDLCK)) {
+ /*
+ * allrecord shared lock taken, but we only want to read
+ */
+ allrecord_ok = true;
+ }
+
+ if (allrecord_ok) {
+ *pret = 0;
+ return true;
+ }
+
+ ret = pthread_mutex_unlock(chain);
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_unlock"
+ "(chain_mutex) failed: %s\n", strerror(ret)));
+ errno = ret;
+ goto fail;
+ }
+ ret = allrecord_mutex_lock(m, waitflag);
+ if (ret == EBUSY) {
+ ret = EAGAIN;
+ }
+ if (ret != 0) {
+ if (waitflag || (ret != EAGAIN)) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_%slock"
+ "(allrecord_mutex) failed: %s\n",
+ waitflag ? "" : "try_", strerror(ret)));
+ }
+ errno = ret;
+ goto fail;
+ }
+ ret = pthread_mutex_unlock(&m->allrecord_mutex);
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_unlock"
+ "(allrecord_mutex) failed: %s\n", strerror(ret)));
+ errno = ret;
+ goto fail;
+ }
+ goto again;
+
+fail:
+ *pret = -1;
+ return true;
+}
+
+bool tdb_mutex_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len,
+ int *pret)
+{
+ struct tdb_mutexes *m = tdb->mutexes;
+ pthread_mutex_t *chain;
+ int ret;
+ unsigned idx;
+
+ if (!tdb_mutex_index(tdb, off, len, &idx)) {
+ return false;
+ }
+ chain = &m->hashchains[idx];
+
+ ret = pthread_mutex_unlock(chain);
+ if (ret == 0) {
+ *pret = 0;
+ return true;
+ }
+ errno = ret;
+ *pret = -1;
+ return true;
+}
+
+int tdb_mutex_allrecord_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags flags)
+{
+ struct tdb_mutexes *m = tdb->mutexes;
+ int ret;
+ uint32_t i;
+ bool waitflag = (flags & TDB_LOCK_WAIT);
+ int saved_errno;
+
+ if (tdb->flags & TDB_NOLOCK) {
+ return 0;
+ }
+
+ if (flags & TDB_LOCK_MARK_ONLY) {
+ return 0;
+ }
+
+ ret = allrecord_mutex_lock(m, waitflag);
+ if (!waitflag && (ret == EBUSY)) {
+ errno = EAGAIN;
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+ if (ret != 0) {
+ if (!(flags & TDB_LOCK_PROBE)) {
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,
+ "allrecord_mutex_lock() failed: %s\n",
+ strerror(ret)));
+ }
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (m->allrecord_lock != F_UNLCK) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "allrecord_lock == %d\n",
+ (int)m->allrecord_lock));
+ goto fail_unlock_allrecord_mutex;
+ }
+ m->allrecord_lock = (ltype == F_RDLCK) ? F_RDLCK : F_WRLCK;
+
+ for (i=0; i<tdb->hash_size; i++) {
+
+ /* ignore hashchains[0], the freelist */
+ pthread_mutex_t *chain = &m->hashchains[i+1];
+
+ ret = chain_mutex_lock(chain, waitflag);
+ if (!waitflag && (ret == EBUSY)) {
+ errno = EAGAIN;
+ goto fail_unroll_allrecord_lock;
+ }
+ if (ret != 0) {
+ if (!(flags & TDB_LOCK_PROBE)) {
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,
+ "chain_mutex_lock() failed: %s\n",
+ strerror(ret)));
+ }
+ errno = ret;
+ goto fail_unroll_allrecord_lock;
+ }
+
+ ret = pthread_mutex_unlock(chain);
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_unlock"
+ "(chainlock) failed: %s\n", strerror(ret)));
+ errno = ret;
+ goto fail_unroll_allrecord_lock;
+ }
+ }
+ /*
+ * We leave this routine with m->allrecord_mutex locked
+ */
+ return 0;
+
+fail_unroll_allrecord_lock:
+ m->allrecord_lock = F_UNLCK;
+
+fail_unlock_allrecord_mutex:
+ saved_errno = errno;
+ ret = pthread_mutex_unlock(&m->allrecord_mutex);
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_unlock"
+ "(allrecord_mutex) failed: %s\n", strerror(ret)));
+ }
+ errno = saved_errno;
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+}
+
+int tdb_mutex_allrecord_upgrade(struct tdb_context *tdb)
+{
+ struct tdb_mutexes *m = tdb->mutexes;
+ int ret;
+ uint32_t i;
+
+ if (tdb->flags & TDB_NOLOCK) {
+ return 0;
+ }
+
+ /*
+ * Our only caller tdb_allrecord_upgrade()
+ * guarantees that we already own the allrecord lock.
+ *
+ * Which means m->allrecord_mutex is still locked by us.
+ */
+
+ if (m->allrecord_lock != F_RDLCK) {
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "allrecord_lock == %d\n",
+ (int)m->allrecord_lock));
+ return -1;
+ }
+
+ m->allrecord_lock = F_WRLCK;
+
+ for (i=0; i<tdb->hash_size; i++) {
+
+ /* ignore hashchains[0], the freelist */
+ pthread_mutex_t *chain = &m->hashchains[i+1];
+
+ ret = chain_mutex_lock(chain, true);
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_lock"
+ "(chainlock) failed: %s\n", strerror(ret)));
+ goto fail_unroll_allrecord_lock;
+ }
+
+ ret = pthread_mutex_unlock(chain);
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_unlock"
+ "(chainlock) failed: %s\n", strerror(ret)));
+ goto fail_unroll_allrecord_lock;
+ }
+ }
+
+ return 0;
+
+fail_unroll_allrecord_lock:
+ m->allrecord_lock = F_RDLCK;
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+}
+
+void tdb_mutex_allrecord_downgrade(struct tdb_context *tdb)
+{
+ struct tdb_mutexes *m = tdb->mutexes;
+
+ /*
+ * Our only caller tdb_allrecord_upgrade() (in the error case)
+ * guarantees that we already own the allrecord lock.
+ *
+ * Which means m->allrecord_mutex is still locked by us.
+ */
+
+ if (m->allrecord_lock != F_WRLCK) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "allrecord_lock == %d\n",
+ (int)m->allrecord_lock));
+ return;
+ }
+
+ m->allrecord_lock = F_RDLCK;
+ return;
+}
+
+
+int tdb_mutex_allrecord_unlock(struct tdb_context *tdb)
+{
+ struct tdb_mutexes *m = tdb->mutexes;
+ short old;
+ int ret;
+
+ if (tdb->flags & TDB_NOLOCK) {
+ return 0;
+ }
+
+ /*
+ * Our only callers tdb_allrecord_unlock() and
+ * tdb_allrecord_lock() (in the error path)
+ * guarantee that we already own the allrecord lock.
+ *
+ * Which means m->allrecord_mutex is still locked by us.
+ */
+
+ if ((m->allrecord_lock != F_RDLCK) && (m->allrecord_lock != F_WRLCK)) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "allrecord_lock == %d\n",
+ (int)m->allrecord_lock));
+ return -1;
+ }
+
+ old = m->allrecord_lock;
+ m->allrecord_lock = F_UNLCK;
+
+ ret = pthread_mutex_unlock(&m->allrecord_mutex);
+ if (ret != 0) {
+ m->allrecord_lock = old;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "pthread_mutex_unlock"
+ "(allrecord_mutex) failed: %s\n", strerror(ret)));
+ return -1;
+ }
+ return 0;
+}
+
+int tdb_mutex_init(struct tdb_context *tdb)
+{
+ struct tdb_mutexes *m;
+ pthread_mutexattr_t ma;
+ uint32_t i;
+ int ret;
+
+ ret = tdb_mutex_mmap(tdb);
+ if (ret == -1) {
+ return -1;
+ }
+ m = tdb->mutexes;
+
+ ret = pthread_mutexattr_init(&ma);
+ if (ret != 0) {
+ goto fail_munmap;
+ }
+ ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) {
+ goto fail;
+ }
+ ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
+ if (ret != 0) {
+ goto fail;
+ }
+ ret = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ for (i=0; i<tdb->hash_size+1; i++) {
+ pthread_mutex_t *chain = &m->hashchains[i];
+
+ ret = pthread_mutex_init(chain, &ma);
+ if (ret != 0) {
+ goto fail;
+ }
+ }
+
+ m->allrecord_lock = F_UNLCK;
+
+ ret = pthread_mutex_init(&m->allrecord_mutex, &ma);
+ if (ret != 0) {
+ goto fail;
+ }
+ ret = 0;
+fail:
+ pthread_mutexattr_destroy(&ma);
+fail_munmap:
+
+ if (ret == 0) {
+ return 0;
+ }
+
+ tdb_mutex_munmap(tdb);
+
+ errno = ret;
+ return -1;
+}
+
+int tdb_mutex_mmap(struct tdb_context *tdb)
+{
+ size_t len;
+ void *ptr;
+
+ len = tdb_mutex_size(tdb);
+ if (len == 0) {
+ return 0;
+ }
+
+ if (tdb->mutexes != NULL) {
+ return 0;
+ }
+
+ ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FILE,
+ tdb->fd, 0);
+ if (ptr == MAP_FAILED) {
+ return -1;
+ }
+ tdb->mutexes = (struct tdb_mutexes *)ptr;
+
+ return 0;
+}
+
+int tdb_mutex_munmap(struct tdb_context *tdb)
+{
+ size_t len;
+ int ret;
+
+ len = tdb_mutex_size(tdb);
+ if (len == 0) {
+ return 0;
+ }
+
+ ret = munmap(tdb->mutexes, len);
+ if (ret == -1) {
+ return -1;
+ }
+ tdb->mutexes = NULL;
+
+ return 0;
+}
+
+static bool tdb_mutex_locking_cached;
+
+static bool tdb_mutex_locking_supported(void)
+{
+ pthread_mutexattr_t ma;
+ pthread_mutex_t m;
+ int ret;
+ static bool initialized;
+
+ if (initialized) {
+ return tdb_mutex_locking_cached;
+ }
+
+ initialized = true;
+
+ ret = pthread_mutexattr_init(&ma);
+ if (ret != 0) {
+ return false;
+ }
+ ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) {
+ goto cleanup_ma;
+ }
+ ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
+ if (ret != 0) {
+ goto cleanup_ma;
+ }
+ ret = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
+ if (ret != 0) {
+ goto cleanup_ma;
+ }
+ ret = pthread_mutex_init(&m, &ma);
+ if (ret != 0) {
+ goto cleanup_ma;
+ }
+ ret = pthread_mutex_lock(&m);
+ if (ret != 0) {
+ goto cleanup_m;
+ }
+ /*
+ * This makes sure we have real mutexes
+ * from a threading library instead of just
+ * stubs from libc.
+ */
+ ret = pthread_mutex_lock(&m);
+ if (ret != EDEADLK) {
+ goto cleanup_lock;
+ }
+ ret = pthread_mutex_unlock(&m);
+ if (ret != 0) {
+ goto cleanup_m;
+ }
+
+ tdb_mutex_locking_cached = true;
+ goto cleanup_m;
+
+cleanup_lock:
+ pthread_mutex_unlock(&m);
+cleanup_m:
+ pthread_mutex_destroy(&m);
+cleanup_ma:
+ pthread_mutexattr_destroy(&ma);
+ return tdb_mutex_locking_cached;
+}
+
+static void (*tdb_robust_mutext_old_handler)(int) = SIG_ERR;
+static pid_t tdb_robust_mutex_pid = -1;
+
+static bool tdb_robust_mutex_setup_sigchild(void (*handler)(int),
+ void (**p_old_handler)(int))
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+ struct sigaction oldact;
+
+ memset(&act, '\0', sizeof(act));
+
+ act.sa_handler = handler;
+#ifdef SA_RESTART
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask, SIGCHLD);
+ sigaction(SIGCHLD, &act, &oldact);
+ if (p_old_handler) {
+ *p_old_handler = oldact.sa_handler;
+ }
+ return true;
+#else /* !HAVE_SIGACTION */
+ return false;
+#endif
+}
+
+static void tdb_robust_mutex_handler(int sig)
+{
+ pid_t child_pid = tdb_robust_mutex_pid;
+
+ if (child_pid != -1) {
+ pid_t pid;
+
+ pid = waitpid(child_pid, NULL, WNOHANG);
+ if (pid == -1) {
+ switch (errno) {
+ case ECHILD:
+ tdb_robust_mutex_pid = -1;
+ return;
+
+ default:
+ return;
+ }
+ }
+ if (pid == child_pid) {
+ tdb_robust_mutex_pid = -1;
+ return;
+ }
+ }
+
+ if (tdb_robust_mutext_old_handler == SIG_DFL) {
+ return;
+ }
+ if (tdb_robust_mutext_old_handler == SIG_IGN) {
+ return;
+ }
+ if (tdb_robust_mutext_old_handler == SIG_ERR) {
+ return;
+ }
+
+ tdb_robust_mutext_old_handler(sig);
+}
+
+static void tdb_robust_mutex_wait_for_child(pid_t *child_pid)
+{
+ int options = WNOHANG;
+
+ if (*child_pid == -1) {
+ return;
+ }
+
+ while (tdb_robust_mutex_pid > 0) {
+ pid_t pid;
+
+ /*
+ * First we try with WNOHANG, as the process might not exist
+ * anymore. Once we've sent SIGKILL we block waiting for the
+ * exit.
+ */
+ pid = waitpid(*child_pid, NULL, options);
+ if (pid == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else if (errno == ECHILD) {
+ break;
+ } else {
+ abort();
+ }
+ }
+ if (pid == *child_pid) {
+ break;
+ }
+
+ kill(*child_pid, SIGKILL);
+ options = 0;
+ }
+
+ tdb_robust_mutex_pid = -1;
+ *child_pid = -1;
+}
+
+_PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+{
+ void *ptr = NULL;
+ pthread_mutex_t *m = NULL;
+ pthread_mutexattr_t ma;
+ int ret = 1;
+ int pipe_down[2] = { -1, -1 };
+ int pipe_up[2] = { -1, -1 };
+ ssize_t nread;
+ char c = 0;
+ bool ok;
+ static bool initialized;
+ pid_t saved_child_pid = -1;
+ bool cleanup_ma = false;
+
+ if (initialized) {
+ return tdb_mutex_locking_cached;
+ }
+
+ initialized = true;
+
+ ok = tdb_mutex_locking_supported();
+ if (!ok) {
+ return false;
+ }
+
+ tdb_mutex_locking_cached = false;
+
+ ptr = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE,
+ MAP_SHARED|MAP_ANON, -1 /* fd */, 0);
+ if (ptr == MAP_FAILED) {
+ return false;
+ }
+
+ ret = pipe(pipe_down);
+ if (ret != 0) {
+ goto cleanup;
+ }
+ ret = pipe(pipe_up);
+ if (ret != 0) {
+ goto cleanup;
+ }
+
+ ret = pthread_mutexattr_init(&ma);
+ if (ret != 0) {
+ goto cleanup;
+ }
+ cleanup_ma = true;
+ ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) {
+ goto cleanup;
+ }
+ ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
+ if (ret != 0) {
+ goto cleanup;
+ }
+ ret = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
+ if (ret != 0) {
+ goto cleanup;
+ }
+ ret = pthread_mutex_init(ptr, &ma);
+ if (ret != 0) {
+ goto cleanup;
+ }
+ m = (pthread_mutex_t *)ptr;
+
+ if (tdb_robust_mutex_setup_sigchild(tdb_robust_mutex_handler,
+ &tdb_robust_mutext_old_handler) == false) {
+ goto cleanup;
+ }
+
+ tdb_robust_mutex_pid = fork();
+ saved_child_pid = tdb_robust_mutex_pid;
+ if (tdb_robust_mutex_pid == 0) {
+ size_t nwritten;
+ close(pipe_down[1]);
+ close(pipe_up[0]);
+ ret = pthread_mutex_lock(m);
+ nwritten = write(pipe_up[1], &ret, sizeof(ret));
+ if (nwritten != sizeof(ret)) {
+ _exit(1);
+ }
+ if (ret != 0) {
+ _exit(1);
+ }
+ nread = read(pipe_down[0], &c, 1);
+ if (nread != 1) {
+ _exit(1);
+ }
+ /* leave locked */
+ _exit(0);
+ }
+ if (tdb_robust_mutex_pid == -1) {
+ goto cleanup;
+ }
+ close(pipe_down[0]);
+ pipe_down[0] = -1;
+ close(pipe_up[1]);
+ pipe_up[1] = -1;
+
+ nread = read(pipe_up[0], &ret, sizeof(ret));
+ if (nread != sizeof(ret)) {
+ goto cleanup;
+ }
+
+ ret = pthread_mutex_trylock(m);
+ if (ret != EBUSY) {
+ if (ret == 0) {
+ pthread_mutex_unlock(m);
+ }
+ goto cleanup;
+ }
+
+ if (write(pipe_down[1], &c, 1) != 1) {
+ goto cleanup;
+ }
+
+ nread = read(pipe_up[0], &c, 1);
+ if (nread != 0) {
+ goto cleanup;
+ }
+
+ tdb_robust_mutex_wait_for_child(&saved_child_pid);
+
+ ret = pthread_mutex_trylock(m);
+ if (ret != EOWNERDEAD) {
+ if (ret == 0) {
+ pthread_mutex_unlock(m);
+ }
+ goto cleanup;
+ }
+
+ ret = pthread_mutex_consistent(m);
+ if (ret != 0) {
+ goto cleanup;
+ }
+
+ ret = pthread_mutex_trylock(m);
+ if (ret != EDEADLK && ret != EBUSY) {
+ pthread_mutex_unlock(m);
+ goto cleanup;
+ }
+
+ ret = pthread_mutex_unlock(m);
+ if (ret != 0) {
+ goto cleanup;
+ }
+
+ tdb_mutex_locking_cached = true;
+
+cleanup:
+ /*
+ * Note that we don't reset the signal handler we just reset
+ * tdb_robust_mutex_pid to -1. This is ok as this code path is only
+ * called once per process.
+ *
+ * Leaving our signal handler avoids races with other threads potentially
+ * setting up their SIGCHLD handlers.
+ *
+ * The worst thing that can happen is that the other newer signal
+ * handler will get the SIGCHLD signal for our child and/or reap the
+ * child with a wait() function. tdb_robust_mutex_wait_for_child()
+ * handles the case where waitpid returns ECHILD.
+ */
+ tdb_robust_mutex_wait_for_child(&saved_child_pid);
+
+ if (m != NULL) {
+ pthread_mutex_destroy(m);
+ }
+ if (cleanup_ma) {
+ pthread_mutexattr_destroy(&ma);
+ }
+ if (pipe_down[0] != -1) {
+ close(pipe_down[0]);
+ }
+ if (pipe_down[1] != -1) {
+ close(pipe_down[1]);
+ }
+ if (pipe_up[0] != -1) {
+ close(pipe_up[0]);
+ }
+ if (pipe_up[1] != -1) {
+ close(pipe_up[1]);
+ }
+ if (ptr != NULL) {
+ munmap(ptr, sizeof(pthread_mutex_t));
+ }
+
+ return tdb_mutex_locking_cached;
+}
+
+#else
+
+size_t tdb_mutex_size(struct tdb_context *tdb)
+{
+ return 0;
+}
+
+bool tdb_have_mutexes(struct tdb_context *tdb)
+{
+ return false;
+}
+
+int tdb_mutex_allrecord_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags flags)
+{
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+}
+
+int tdb_mutex_allrecord_unlock(struct tdb_context *tdb)
+{
+ return -1;
+}
+
+int tdb_mutex_allrecord_upgrade(struct tdb_context *tdb)
+{
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+}
+
+void tdb_mutex_allrecord_downgrade(struct tdb_context *tdb)
+{
+ return;
+}
+
+int tdb_mutex_mmap(struct tdb_context *tdb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int tdb_mutex_munmap(struct tdb_context *tdb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int tdb_mutex_init(struct tdb_context *tdb)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+_PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+{
+ return false;
+}
+
+#endif
diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c
new file mode 100644
index 0000000..3fa7ce1
--- /dev/null
+++ b/lib/tdb/common/open.c
@@ -0,0 +1,968 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
+static struct tdb_context *tdbs = NULL;
+
+/* We use two hashes to double-check they're using the right hash function. */
+void tdb_header_hash(struct tdb_context *tdb,
+ uint32_t *magic1_hash, uint32_t *magic2_hash)
+{
+ TDB_DATA hash_key;
+ uint32_t tdb_magic = TDB_MAGIC;
+
+ hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD);
+ hash_key.dsize = sizeof(TDB_MAGIC_FOOD);
+ *magic1_hash = tdb->hash_fn(&hash_key);
+
+ hash_key.dptr = (unsigned char *)CONVERT(tdb_magic);
+ hash_key.dsize = sizeof(tdb_magic);
+ *magic2_hash = tdb->hash_fn(&hash_key);
+
+ /* Make sure at least one hash is non-zero! */
+ if (*magic1_hash == 0 && *magic2_hash == 0)
+ *magic1_hash = 1;
+}
+
+/* initialise a new database with a specified hash size */
+static int tdb_new_database(struct tdb_context *tdb, struct tdb_header *header,
+ int hash_size)
+{
+ struct tdb_header *newdb;
+ size_t size;
+ int ret = -1;
+
+ /* We make it up in memory, then write it out if not internal */
+ size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
+ if (!(newdb = (struct tdb_header *)calloc(size, 1))) {
+ tdb->ecode = TDB_ERR_OOM;
+ return -1;
+ }
+
+ /* Fill in the header */
+ newdb->version = TDB_VERSION;
+ newdb->hash_size = hash_size;
+
+ tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash);
+
+ /* Make sure older tdbs (which don't check the magic hash fields)
+ * will refuse to open this TDB. */
+ if (tdb->flags & TDB_INCOMPATIBLE_HASH)
+ newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC;
+
+ /*
+ * We create a tdb with TDB_FEATURE_FLAG_MUTEX support,
+ * the flag combination and runtime feature checks
+ * are done by the caller already.
+ */
+ if (tdb->flags & TDB_MUTEX_LOCKING) {
+ newdb->feature_flags |= TDB_FEATURE_FLAG_MUTEX;
+ }
+
+ /*
+ * If we have any features we add the FEATURE_FLAG_MAGIC, overwriting the
+ * TDB_HASH_RWLOCK_MAGIC above.
+ */
+ if (newdb->feature_flags != 0) {
+ newdb->rwlocks = TDB_FEATURE_FLAG_MAGIC;
+ }
+
+ /*
+ * It's required for some following code paths
+ * to have the fields on 'tdb' up-to-date.
+ *
+ * E.g. tdb_mutex_size() requires it
+ */
+ tdb->feature_flags = newdb->feature_flags;
+ tdb->hash_size = newdb->hash_size;
+
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->map_size = size;
+ tdb->map_ptr = (char *)newdb;
+ memcpy(header, newdb, sizeof(*header));
+ /* Convert the `ondisk' version if asked. */
+ CONVERT(*newdb);
+ return 0;
+ }
+ if (lseek(tdb->fd, 0, SEEK_SET) == -1)
+ goto fail;
+
+ if (ftruncate(tdb->fd, 0) == -1)
+ goto fail;
+
+ if (newdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
+ newdb->mutex_size = tdb_mutex_size(tdb);
+ tdb->hdr_ofs = newdb->mutex_size;
+ }
+
+ /* This creates an endian-converted header, as if read from disk */
+ CONVERT(*newdb);
+ memcpy(header, newdb, sizeof(*header));
+ /* Don't endian-convert the magic food! */
+ memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
+
+ if (!tdb_write_all(tdb->fd, newdb, size))
+ goto fail;
+
+ if (newdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
+
+ /*
+ * Now we init the mutex area
+ * followed by a second header.
+ */
+
+ ret = ftruncate(
+ tdb->fd,
+ newdb->mutex_size + sizeof(struct tdb_header));
+ if (ret == -1) {
+ goto fail;
+ }
+ ret = tdb_mutex_init(tdb);
+ if (ret == -1) {
+ goto fail;
+ }
+
+ /*
+ * Write a second header behind the mutexes. That's the area
+ * that will be mmapp'ed.
+ */
+ ret = lseek(tdb->fd, newdb->mutex_size, SEEK_SET);
+ if (ret == -1) {
+ goto fail;
+ }
+ if (!tdb_write_all(tdb->fd, newdb, size)) {
+ goto fail;
+ }
+ }
+
+ ret = 0;
+ fail:
+ SAFE_FREE(newdb);
+ return ret;
+}
+
+
+
+static int tdb_already_open(dev_t device,
+ ino_t ino)
+{
+ struct tdb_context *i;
+
+ for (i = tdbs; i; i = i->next) {
+ if (i->device == device && i->inode == ino) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* open the database, creating it if necessary
+
+ The open_flags and mode are passed straight to the open call on the
+ database file. A flags value of O_WRONLY is invalid. The hash size
+ is advisory, use zero for a default value.
+
+ Return is NULL on error, in which case errno is also set. Don't
+ try to call tdb_error or tdb_errname, just do strerror(errno).
+
+ @param name may be NULL for internal databases. */
+_PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
+}
+
+/* a default logging function */
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+}
+
+static bool check_header_hash(struct tdb_context *tdb,
+ struct tdb_header *header,
+ bool default_hash, uint32_t *m1, uint32_t *m2)
+{
+ tdb_header_hash(tdb, m1, m2);
+ if (header->magic1_hash == *m1 &&
+ header->magic2_hash == *m2) {
+ return true;
+ }
+
+ /* If they explicitly set a hash, always respect it. */
+ if (!default_hash)
+ return false;
+
+ /* Otherwise, try the other inbuilt hash. */
+ if (tdb->hash_fn == tdb_old_hash)
+ tdb->hash_fn = tdb_jenkins_hash;
+ else
+ tdb->hash_fn = tdb_old_hash;
+ return check_header_hash(tdb, header, false, m1, m2);
+}
+
+static bool tdb_mutex_open_ok(struct tdb_context *tdb,
+ const struct tdb_header *header)
+{
+ if (tdb->flags & TDB_NOLOCK) {
+ /*
+ * We don't look at locks, so it does not matter to have a
+ * compatible mutex implementation. Allow the open.
+ */
+ return true;
+ }
+
+ if (!(tdb->flags & TDB_MUTEX_LOCKING)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok[%s]: "
+ "Can use mutexes only with "
+ "MUTEX_LOCKING or NOLOCK\n",
+ tdb->name));
+ return false;
+ }
+
+ if (tdb_mutex_size(tdb) != header->mutex_size) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok[%s]: "
+ "Mutex size changed from %"PRIu32" to %zu\n.",
+ tdb->name,
+ header->mutex_size,
+ tdb_mutex_size(tdb)));
+ return false;
+ }
+
+ return true;
+}
+
+_PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ const struct tdb_logging_context *log_ctx,
+ tdb_hash_func hash_fn)
+{
+ int orig_errno = errno;
+ struct tdb_header header = {
+ .version = 0,
+ };
+ struct tdb_context *tdb;
+ struct stat st;
+ int rev = 0;
+ bool locked = false;
+ unsigned char *vp;
+ uint32_t vertest;
+ unsigned v;
+ const char *hash_alg;
+ uint32_t magic1, magic2;
+ int ret;
+
+ if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
+ /* Can't log this */
+ errno = ENOMEM;
+ goto fail;
+ }
+ tdb_io_init(tdb);
+
+ if (tdb_flags & TDB_INTERNAL) {
+ tdb_flags |= TDB_INCOMPATIBLE_HASH;
+ }
+ if (tdb_flags & TDB_MUTEX_LOCKING) {
+ tdb_flags |= TDB_INCOMPATIBLE_HASH;
+ }
+
+ tdb->fd = -1;
+#ifdef TDB_TRACE
+ tdb->tracefd = -1;
+#endif
+ tdb->name = NULL;
+ tdb->map_ptr = NULL;
+ tdb->flags = tdb_flags;
+ tdb->open_flags = open_flags;
+ if (log_ctx) {
+ tdb->log = *log_ctx;
+ } else {
+ tdb->log.log_fn = null_log_fn;
+ tdb->log.log_private = NULL;
+ }
+
+ if (name == NULL && (tdb_flags & TDB_INTERNAL)) {
+ name = "__TDB_INTERNAL__";
+ }
+
+ if (name == NULL) {
+ tdb->name = discard_const_p(char, "__NULL__");
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n"));
+ tdb->name = NULL;
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /* now make a copy of the name, as the caller memory might go away */
+ if (!(tdb->name = (char *)strdup(name))) {
+ /*
+ * set the name as the given string, so that tdb_name() will
+ * work in case of an error.
+ */
+ tdb->name = discard_const_p(char, name);
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n",
+ name));
+ tdb->name = NULL;
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if (hash_fn) {
+ tdb->hash_fn = hash_fn;
+ hash_alg = "the user defined";
+ } else {
+ /* This controls what we use when creating a tdb. */
+ if (tdb->flags & TDB_INCOMPATIBLE_HASH) {
+ tdb->hash_fn = tdb_jenkins_hash;
+ } else {
+ tdb->hash_fn = tdb_old_hash;
+ }
+ hash_alg = "either default";
+ }
+
+ /* cache the page size */
+ tdb->page_size = getpagesize();
+ if (tdb->page_size <= 0) {
+ tdb->page_size = 0x2000;
+ }
+
+ tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0;
+
+ if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
+ name));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (hash_size == 0)
+ hash_size = DEFAULT_HASH_SIZE;
+ if ((open_flags & O_ACCMODE) == O_RDONLY) {
+ tdb->read_only = 1;
+ /* read only databases don't do locking or clear if first */
+ tdb->flags |= TDB_NOLOCK;
+ tdb->flags &= ~(TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING);
+ }
+
+ if ((tdb->flags & TDB_ALLOW_NESTING) &&
+ (tdb->flags & TDB_DISALLOW_NESTING)) {
+ tdb->ecode = TDB_ERR_NESTING;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "allow_nesting and disallow_nesting are not allowed together!"));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (tdb->flags & TDB_MUTEX_LOCKING) {
+ /*
+ * Here we catch bugs in the callers,
+ * the runtime check for existing tdb's comes later.
+ */
+
+ if (tdb->flags & TDB_INTERNAL) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "invalid flags for %s - TDB_MUTEX_LOCKING and "
+ "TDB_INTERNAL are not allowed together\n", name));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (tdb->flags & TDB_NOMMAP) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "invalid flags for %s - TDB_MUTEX_LOCKING and "
+ "TDB_NOMMAP are not allowed together\n", name));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (tdb->read_only) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "invalid flags for %s - TDB_MUTEX_LOCKING "
+ "not allowed read only\n", name));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /*
+ * The callers should have called
+ * tdb_runtime_check_for_robust_mutexes()
+ * before using TDB_MUTEX_LOCKING!
+ *
+ * This makes sure the caller understands
+ * that the locking may behave a bit differently
+ * than with pure fcntl locking. E.g. multiple
+ * read locks are not supported.
+ */
+ if (!tdb_runtime_check_for_robust_mutexes()) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "invalid flags for %s - TDB_MUTEX_LOCKING "
+ "requires support for robust_mutexes\n",
+ name));
+ errno = ENOSYS;
+ goto fail;
+ }
+ }
+
+ if (getenv("TDB_NO_FSYNC")) {
+ tdb->flags |= TDB_NOSYNC;
+ }
+
+ /*
+ * TDB_ALLOW_NESTING is the default behavior.
+ * Note: this may change in future versions!
+ */
+ if (!(tdb->flags & TDB_DISALLOW_NESTING)) {
+ tdb->flags |= TDB_ALLOW_NESTING;
+ }
+
+ /* internal databases don't mmap or lock, and start off cleared */
+ if (tdb->flags & TDB_INTERNAL) {
+ tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
+ tdb->flags &= ~TDB_CLEAR_IF_FIRST;
+ if (tdb_new_database(tdb, &header, hash_size) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
+ goto fail;
+ }
+ tdb->hash_size = hash_size;
+ goto internal;
+ }
+
+ if ((tdb->fd = open(name, open_flags, mode)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by open(2) */
+ }
+
+ /* on exec, don't inherit the fd */
+ v = fcntl(tdb->fd, F_GETFD, 0);
+ fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
+
+ /* ensure there is only one process initialising at once */
+ if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n",
+ name, strerror(errno)));
+ goto fail; /* errno set by tdb_brlock */
+ }
+
+ /* we need to zero database if we are the only one with it open */
+ if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
+ (!tdb->read_only)) {
+ ret = tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK,
+ TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+ locked = (ret == 0);
+
+ if (locked) {
+ ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
+ TDB_LOCK_WAIT);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_brlock failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ ret = tdb_new_database(tdb, &header, hash_size);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_new_database failed for "
+ "%s: %s\n", name, strerror(errno)));
+ tdb_unlockall(tdb);
+ goto fail;
+ }
+ ret = tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "tdb_unlockall failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ ret = lseek(tdb->fd, 0, SEEK_SET);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "lseek failed for %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ }
+ }
+
+ errno = 0;
+ if (read(tdb->fd, &header, sizeof(header)) != sizeof(header)
+ /*
+ * Call strncmp() rather than strcmp() in case header.magic_food is
+ * not zero‐terminated. We’re still checking the full string for
+ * equality, as tdb_header::magic_food is larger than
+ * TDB_MAGIC_FOOD.
+ */
+ || strncmp(header.magic_food, TDB_MAGIC_FOOD, sizeof(header.magic_food)) != 0) {
+ if (!(open_flags & O_CREAT) ||
+ tdb_new_database(tdb, &header, hash_size) == -1) {
+ if (errno == 0) {
+ errno = EIO; /* ie bad format or something */
+ }
+ goto fail;
+ }
+ rev = (tdb->flags & TDB_CONVERT);
+ } else if (header.version != TDB_VERSION
+ && !(rev = (header.version==TDB_BYTEREV(TDB_VERSION)))) {
+ /* wrong version */
+ errno = EIO;
+ goto fail;
+ }
+ vp = (unsigned char *)&header.version;
+ vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) |
+ (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3];
+ tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
+ if (!rev)
+ tdb->flags &= ~TDB_CONVERT;
+ else {
+ tdb->flags |= TDB_CONVERT;
+ tdb_convert(&header, sizeof(header));
+ }
+
+ /*
+ * We only use st.st_dev and st.st_ino from the raw fstat()
+ * call, everything else needs to use tdb_fstat() in order
+ * to skip tdb->hdr_ofs!
+ */
+ if (fstat(tdb->fd, &st) == -1) {
+ goto fail;
+ }
+ tdb->device = st.st_dev;
+ tdb->inode = st.st_ino;
+ ZERO_STRUCT(st);
+
+ if (header.rwlocks != 0 &&
+ header.rwlocks != TDB_FEATURE_FLAG_MAGIC &&
+ header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
+ errno = ENOSYS;
+ goto fail;
+ }
+
+ if (header.hash_size == 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: invalid database: 0 hash_size\n"));
+ errno = ENOSYS;
+ goto fail;
+ }
+
+ tdb->hash_size = header.hash_size;
+
+ if (header.rwlocks == TDB_FEATURE_FLAG_MAGIC) {
+ tdb->feature_flags = header.feature_flags;
+ }
+
+ if (tdb->feature_flags & ~TDB_SUPPORTED_FEATURE_FLAGS) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: unsupported "
+ "features in tdb %s: 0x%08x (supported: 0x%08x)\n",
+ name, (unsigned)tdb->feature_flags,
+ (unsigned)TDB_SUPPORTED_FEATURE_FLAGS));
+ errno = ENOSYS;
+ goto fail;
+ }
+
+ if (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
+ if (!tdb_mutex_open_ok(tdb, &header)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /*
+ * We need to remember the hdr_ofs
+ * also for the TDB_NOLOCK case
+ * if the current library doesn't support
+ * mutex locking.
+ */
+ tdb->hdr_ofs = header.mutex_size;
+
+ if ((!(tdb_flags & TDB_CLEAR_IF_FIRST)) && (!tdb->read_only)) {
+ /*
+ * Open an existing mutexed tdb, but without
+ * CLEAR_IF_FIRST. We need to initialize the
+ * mutex array and keep the CLEAR_IF_FIRST
+ * lock locked.
+ */
+ ret = tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK,
+ TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+ locked = (ret == 0);
+
+ if (locked) {
+ ret = tdb_mutex_init(tdb);
+ if (ret == -1) {
+ TDB_LOG((tdb,
+ TDB_DEBUG_FATAL,
+ "tdb_open_ex: tdb_mutex_init "
+ "failed for ""%s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+ }
+ }
+ }
+
+ if ((header.magic1_hash == 0) && (header.magic2_hash == 0)) {
+ /* older TDB without magic hash references */
+ tdb->hash_fn = tdb_old_hash;
+ } else if (!check_header_hash(tdb, &header, !hash_fn,
+ &magic1, &magic2)) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "%s was not created with %s hash function we are using\n"
+ "magic1_hash[0x%08X %s 0x%08X] "
+ "magic2_hash[0x%08X %s 0x%08X]\n",
+ name, hash_alg,
+ header.magic1_hash,
+ (header.magic1_hash == magic1) ? "==" : "!=",
+ magic1,
+ header.magic2_hash,
+ (header.magic2_hash == magic2) ? "==" : "!=",
+ magic2));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /* Is it already in the open list? If so, fail. */
+ if (tdb_already_open(tdb->device, tdb->inode)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "%s (%d,%d) is already open in this process\n",
+ name, (int)tdb->device, (int)tdb->inode));
+ errno = EBUSY;
+ goto fail;
+ }
+
+ /*
+ * We had tdb_mmap(tdb) here before,
+ * but we need to use tdb_fstat(),
+ * which is triggered from tdb_oob() before calling tdb_mmap().
+ * As this skips tdb->hdr_ofs.
+ */
+ tdb->map_size = 0;
+ ret = tdb_oob(tdb, 0, 1, 0);
+ if (ret == -1) {
+ errno = EIO;
+ goto fail;
+ }
+
+ if (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
+ if (!(tdb->flags & TDB_NOLOCK)) {
+ ret = tdb_mutex_mmap(tdb);
+ if (ret != 0) {
+ goto fail;
+ }
+ }
+ }
+
+ if (tdb->hash_size > UINT32_MAX/4) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "hash size %"PRIu32" too large\n", tdb->hash_size));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ ret = tdb_oob(tdb, FREELIST_TOP, 4*tdb->hash_size, 1);
+ if (ret == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
+ "hash size %"PRIu32" does not fit\n", tdb->hash_size));
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (locked) {
+ if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
+ "failed to release ACTIVE_LOCK on %s: %s\n",
+ name, strerror(errno)));
+ goto fail;
+ }
+
+
+ }
+
+ if (locked || (tdb_flags & TDB_CLEAR_IF_FIRST)) {
+ /*
+ * We always need to do this if the CLEAR_IF_FIRST
+ * flag is set, even if we didn't get the initial
+ * exclusive lock as we need to let all other users
+ * know we're using it.
+ */
+
+ ret = tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT);
+ if (ret == -1) {
+ goto fail;
+ }
+ }
+
+ /* if needed, run recovery */
+ if (tdb_transaction_recover(tdb) == -1) {
+ goto fail;
+ }
+
+#ifdef TDB_TRACE
+ {
+ char tracefile[strlen(name) + 32];
+
+ snprintf(tracefile, sizeof(tracefile),
+ "%s.trace.%li", name, (long)getpid());
+ tdb->tracefd = open(tracefile, O_WRONLY|O_CREAT|O_EXCL, 0600);
+ if (tdb->tracefd >= 0) {
+ tdb_enable_seqnum(tdb);
+ tdb_trace_open(tdb, "tdb_open", hash_size, tdb_flags,
+ open_flags);
+ } else
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to open trace file %s!\n", tracefile));
+ }
+#endif
+
+ internal:
+ /* Internal (memory-only) databases skip all the code above to
+ * do with disk files, and resume here by releasing their
+ * open lock and hooking into the active list. */
+ if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) {
+ goto fail;
+ }
+ tdb->next = tdbs;
+ tdbs = tdb;
+ errno = orig_errno;
+ return tdb;
+
+ fail:
+ { int save_errno = errno;
+
+ if (!tdb)
+ return NULL;
+
+#ifdef TDB_TRACE
+ close(tdb->tracefd);
+#endif
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ SAFE_FREE(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+ if (tdb->fd != -1)
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
+ SAFE_FREE(tdb->lockrecs);
+ SAFE_FREE(tdb->name);
+ SAFE_FREE(tdb);
+ errno = save_errno;
+ return NULL;
+ }
+}
+
+/*
+ * Set the maximum number of dead records per hash chain
+ */
+
+_PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
+{
+ tdb->max_dead_records = max_dead;
+}
+
+/**
+ * Close a database.
+ *
+ * @returns -1 for error; 0 for success.
+ **/
+_PUBLIC_ int tdb_close(struct tdb_context *tdb)
+{
+ struct tdb_context **i;
+ int ret = 0;
+
+ if (tdb->transaction) {
+ tdb_transaction_cancel(tdb);
+ }
+ tdb_trace(tdb, "tdb_close");
+
+ if (tdb->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL)
+ SAFE_FREE(tdb->map_ptr);
+ else
+ tdb_munmap(tdb);
+ }
+
+ tdb_mutex_munmap(tdb);
+
+ SAFE_FREE(tdb->name);
+ if (tdb->fd != -1) {
+ ret = close(tdb->fd);
+ tdb->fd = -1;
+ }
+ SAFE_FREE(tdb->lockrecs);
+
+ /* Remove from contexts list */
+ for (i = &tdbs; *i; i = &(*i)->next) {
+ if (*i == tdb) {
+ *i = tdb->next;
+ break;
+ }
+ }
+
+#ifdef TDB_TRACE
+ close(tdb->tracefd);
+#endif
+ memset(tdb, 0, sizeof(*tdb));
+ SAFE_FREE(tdb);
+
+ return ret;
+}
+
+/* register a logging function */
+_PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb,
+ const struct tdb_logging_context *log_ctx)
+{
+ tdb->log = *log_ctx;
+}
+
+_PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb)
+{
+ return tdb->log.log_private;
+}
+
+static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock)
+{
+#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
+ !defined(LIBREPLACE_PWRITE_NOT_REPLACED)
+ struct stat st;
+#endif
+
+ if (tdb->flags & TDB_INTERNAL) {
+ return 0; /* Nothing to do. */
+ }
+
+ if (tdb_have_extra_locks(tdb)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
+ goto fail;
+ }
+
+ if (tdb->transaction != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n"));
+ goto fail;
+ }
+
+/* If we have real pread & pwrite, we can skip reopen. */
+#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
+ !defined(LIBREPLACE_PWRITE_NOT_REPLACED)
+ if (tdb_munmap(tdb) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
+ tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
+ if (tdb->fd == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ /*
+ * We only use st.st_dev and st.st_ino from the raw fstat()
+ * call, everything else needs to use tdb_fstat() in order
+ * to skip tdb->hdr_ofs!
+ */
+ if (fstat(tdb->fd, &st) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n"));
+ goto fail;
+ }
+ ZERO_STRUCT(st);
+
+ /*
+ * We had tdb_mmap(tdb) here before,
+ * but we need to use tdb_fstat(),
+ * which is triggered from tdb_oob() before calling tdb_mmap().
+ * As this skips tdb->hdr_ofs.
+ */
+ tdb->map_size = 0;
+ if (tdb_oob(tdb, 0, 1, 0) != 0) {
+ goto fail;
+ }
+#endif /* fake pread or pwrite */
+
+ /* We may still think we hold the active lock. */
+ tdb->num_lockrecs = 0;
+ SAFE_FREE(tdb->lockrecs);
+ tdb->lockrecs_array_length = 0;
+
+ if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ tdb_close(tdb);
+ return -1;
+}
+
+/* reopen a tdb - this can be used after a fork to ensure that we have an independent
+ seek pointer from our parent and to re-establish locks */
+_PUBLIC_ int tdb_reopen(struct tdb_context *tdb)
+{
+ bool active_lock;
+ active_lock = (tdb->flags & (TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING));
+
+ return tdb_reopen_internal(tdb, active_lock);
+}
+
+/* reopen all tdb's */
+_PUBLIC_ int tdb_reopen_all(int parent_longlived)
+{
+ struct tdb_context *tdb;
+
+ for (tdb=tdbs; tdb; tdb = tdb->next) {
+ bool active_lock;
+
+ active_lock =
+ (tdb->flags & (TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING));
+
+ /*
+ * If the parent is longlived (ie. a
+ * parent daemon architecture), we know
+ * it will keep it's active lock on a
+ * tdb opened with CLEAR_IF_FIRST. Thus
+ * for child processes we don't have to
+ * add an active lock. This is essential
+ * to improve performance on systems that
+ * keep POSIX locks as a non-scalable data
+ * structure in the kernel.
+ */
+ if (parent_longlived) {
+ /* Ensure no clear-if-first. */
+ active_lock = false;
+ }
+
+ if (tdb_reopen_internal(tdb, active_lock) != 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/lib/tdb/common/rescue.c b/lib/tdb/common/rescue.c
new file mode 100644
index 0000000..7a85ebc
--- /dev/null
+++ b/lib/tdb/common/rescue.c
@@ -0,0 +1,351 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library, rescue attempt code.
+
+ Copyright (C) Rusty Russell 2012
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "tdb_private.h"
+#include <assert.h>
+
+
+struct found {
+ tdb_off_t head; /* 0 -> invalid. */
+ struct tdb_record rec;
+ TDB_DATA key;
+ bool in_hash;
+ bool in_free;
+};
+
+struct found_table {
+ /* As an ordered array (by head offset). */
+ struct found *arr;
+ unsigned int num, max;
+};
+
+static bool looks_like_valid_record(struct tdb_context *tdb,
+ tdb_off_t off,
+ const struct tdb_record *rec,
+ TDB_DATA *key)
+{
+ unsigned int hval;
+
+ if (rec->magic != TDB_MAGIC)
+ return false;
+
+ if (rec->key_len + rec->data_len > rec->rec_len)
+ return false;
+
+ if (rec->rec_len % TDB_ALIGNMENT)
+ return false;
+
+ /* Next pointer must make some sense. */
+ if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->hash_size))
+ return false;
+
+ if (tdb_oob(tdb, rec->next, sizeof(*rec), 1))
+ return false;
+
+ key->dsize = rec->key_len;
+ key->dptr = tdb_alloc_read(tdb, off + sizeof(*rec), key->dsize);
+ if (!key->dptr)
+ return false;
+
+ hval = tdb->hash_fn(key);
+ if (hval != rec->full_hash) {
+ free(key->dptr);
+ return false;
+ }
+
+ /* Caller frees up key->dptr */
+ return true;
+}
+
+static bool add_to_table(struct found_table *found,
+ tdb_off_t off,
+ struct tdb_record *rec,
+ TDB_DATA key)
+{
+ if (found->num + 1 > found->max) {
+ struct found *new;
+ found->max = (found->max ? found->max * 2 : 128);
+ new = realloc(found->arr, found->max * sizeof(found->arr[0]));
+ if (!new)
+ return false;
+ found->arr = new;
+ }
+
+ found->arr[found->num].head = off;
+ found->arr[found->num].rec = *rec;
+ found->arr[found->num].key = key;
+ found->arr[found->num].in_hash = false;
+ found->arr[found->num].in_free = false;
+
+ found->num++;
+ return true;
+}
+
+static bool walk_record(struct tdb_context *tdb,
+ const struct found *f,
+ void (*walk)(TDB_DATA, TDB_DATA, void *private_data),
+ void *private_data)
+{
+ TDB_DATA data;
+
+ data.dsize = f->rec.data_len;
+ data.dptr = tdb_alloc_read(tdb,
+ f->head + sizeof(f->rec) + f->rec.key_len,
+ data.dsize);
+ if (!data.dptr) {
+ if (tdb->ecode == TDB_ERR_OOM)
+ return false;
+ /* I/O errors are expected. */
+ return true;
+ }
+
+ walk(f->key, data, private_data);
+ free(data.dptr);
+ return true;
+}
+
+/* First entry which has offset >= this one. */
+static unsigned int find_entry(struct found_table *found, tdb_off_t off)
+{
+ unsigned int start = 0, end = found->num;
+
+ while (start < end) {
+ /* We can't overflow here. */
+ unsigned int mid = (start + end) / 2;
+
+ if (off < found->arr[mid].head) {
+ end = mid;
+ } else if (off > found->arr[mid].head) {
+ start = mid + 1;
+ } else {
+ return mid;
+ }
+ }
+
+ assert(start == end);
+ return end;
+}
+
+static void found_in_hashchain(struct found_table *found, tdb_off_t head)
+{
+ unsigned int match;
+
+ match = find_entry(found, head);
+ if (match < found->num && found->arr[match].head == head) {
+ found->arr[match].in_hash = true;
+ }
+}
+
+static void mark_free_area(struct found_table *found, tdb_off_t head,
+ tdb_len_t len)
+{
+ unsigned int match;
+
+ match = find_entry(found, head);
+ /* Mark everything within this free entry. */
+ while (match < found->num) {
+ if (found->arr[match].head >= head + len) {
+ break;
+ }
+ found->arr[match].in_free = true;
+ match++;
+ }
+}
+
+static int cmp_key(const void *a, const void *b)
+{
+ const struct found *fa = a, *fb = b;
+
+ if (fa->key.dsize < fb->key.dsize) {
+ return -1;
+ } else if (fa->key.dsize > fb->key.dsize) {
+ return 1;
+ }
+ return memcmp(fa->key.dptr, fb->key.dptr, fa->key.dsize);
+}
+
+static bool key_eq(TDB_DATA a, TDB_DATA b)
+{
+ return a.dsize == b.dsize
+ && memcmp(a.dptr, b.dptr, a.dsize) == 0;
+}
+
+static void free_table(struct found_table *found)
+{
+ unsigned int i;
+
+ for (i = 0; i < found->num; i++) {
+ free(found->arr[i].key.dptr);
+ }
+ free(found->arr);
+}
+
+static void logging_suppressed(struct tdb_context *tdb,
+ enum tdb_debug_level level, const char *fmt, ...)
+{
+}
+
+_PUBLIC_ int tdb_rescue(struct tdb_context *tdb,
+ void (*walk)(TDB_DATA, TDB_DATA, void *private_data),
+ void *private_data)
+{
+ struct found_table found = { NULL, 0, 0 };
+ tdb_off_t h, off, i;
+ tdb_log_func oldlog = tdb->log.log_fn;
+ struct tdb_record rec;
+ TDB_DATA key;
+ bool locked;
+
+ /* Read-only databases use no locking at all: it's best-effort.
+ * We may have a write lock already, so skip that case too. */
+ if (tdb->read_only || tdb->allrecord_lock.count != 0) {
+ locked = false;
+ } else {
+ if (tdb_lockall_read(tdb) == -1)
+ return -1;
+ locked = true;
+ }
+
+ /* Make sure we know true size of the underlying file. */
+ tdb_oob(tdb, tdb->map_size, 1, 1);
+
+ /* Suppress logging, since we anticipate errors. */
+ tdb->log.log_fn = logging_suppressed;
+
+ /* Now walk entire db looking for records. */
+ for (off = TDB_DATA_START(tdb->hash_size);
+ off < tdb->map_size;
+ off += TDB_ALIGNMENT) {
+ if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
+ DOCONV()) == -1)
+ continue;
+
+ if (looks_like_valid_record(tdb, off, &rec, &key)) {
+ if (!add_to_table(&found, off, &rec, key)) {
+ goto oom;
+ }
+ }
+ }
+
+ /* Walk hash chains to positive vet. */
+ for (h = 0; h < 1+tdb->hash_size; h++) {
+ bool slow_chase = false;
+ tdb_off_t slow_off = FREELIST_TOP + h*sizeof(tdb_off_t);
+
+ if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
+ &off) == -1)
+ continue;
+
+ while (off && off != slow_off) {
+ if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
+ DOCONV()) != 0) {
+ break;
+ }
+
+ /* 0 is the free list, rest are hash chains. */
+ if (h == 0) {
+ /* Don't mark garbage as free. */
+ if (rec.magic != TDB_FREE_MAGIC) {
+ break;
+ }
+ mark_free_area(&found, off,
+ sizeof(rec) + rec.rec_len);
+ } else {
+ found_in_hashchain(&found, off);
+ }
+
+ off = rec.next;
+
+ /* Loop detection using second pointer at half-speed */
+ if (slow_chase) {
+ /* First entry happens to be next ptr */
+ tdb_ofs_read(tdb, slow_off, &slow_off);
+ }
+ slow_chase = !slow_chase;
+ }
+ }
+
+ /* Recovery area: must be marked as free, since it often has old
+ * records in there! */
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off) == 0 && off != 0) {
+ if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
+ DOCONV()) == 0) {
+ mark_free_area(&found, off, sizeof(rec) + rec.rec_len);
+ }
+ }
+
+ /* Now sort by key! */
+ if (found.arr != NULL) {
+ qsort(found.arr, found.num, sizeof(found.arr[0]), cmp_key);
+ }
+
+ for (i = 0; (found.arr != NULL) && i < found.num; ) {
+ unsigned int num, num_in_hash = 0;
+
+ /* How many are identical? */
+ for (num = 0; num < found.num - i; num++) {
+ if (!key_eq(found.arr[i].key, found.arr[i+num].key)) {
+ break;
+ }
+ if (found.arr[i+num].in_hash) {
+ if (!walk_record(tdb, &found.arr[i+num],
+ walk, private_data))
+ goto oom;
+ num_in_hash++;
+ }
+ }
+ assert(num);
+
+ /* If none were in the hash, we print any not in free list. */
+ if (num_in_hash == 0) {
+ unsigned int j;
+
+ for (j = i; j < i + num; j++) {
+ if (!found.arr[j].in_free) {
+ if (!walk_record(tdb, &found.arr[j],
+ walk, private_data))
+ goto oom;
+ }
+ }
+ }
+
+ i += num;
+ }
+
+ tdb->log.log_fn = oldlog;
+ if (locked) {
+ tdb_unlockall_read(tdb);
+ }
+ return 0;
+
+oom:
+ tdb->log.log_fn = oldlog;
+ tdb->ecode = TDB_ERR_OOM;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_rescue: failed allocating\n"));
+ free_table(&found);
+ if (locked) {
+ tdb_unlockall_read(tdb);
+ }
+ return -1;
+}
diff --git a/lib/tdb/common/summary.c b/lib/tdb/common/summary.c
new file mode 100644
index 0000000..a93eb93
--- /dev/null
+++ b/lib/tdb/common/summary.c
@@ -0,0 +1,219 @@
+ /*
+ Trivial Database: human-readable summary code
+ Copyright (C) Rusty Russell 2010
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "tdb_private.h"
+
+#define SUMMARY_FORMAT \
+ "Size of file/data: %llu/%zu\n" \
+ "Header offset/logical size: %zu/%zu\n" \
+ "Number of records: %zu\n" \
+ "Incompatible hash: %s\n" \
+ "Active/supported feature flags: 0x%08x/0x%08x\n" \
+ "Robust mutexes locking: %s\n" \
+ "Smallest/average/largest keys: %zu/%zu/%zu\n" \
+ "Smallest/average/largest data: %zu/%zu/%zu\n" \
+ "Smallest/average/largest padding: %zu/%zu/%zu\n" \
+ "Number of dead records: %zu\n" \
+ "Smallest/average/largest dead records: %zu/%zu/%zu\n" \
+ "Number of free records: %zu\n" \
+ "Smallest/average/largest free records: %zu/%zu/%zu\n" \
+ "Number of hash chains: %zu\n" \
+ "Smallest/average/largest hash chains: %zu/%zu/%zu\n" \
+ "Number of uncoalesced records: %zu\n" \
+ "Smallest/average/largest uncoalesced runs: %zu/%zu/%zu\n" \
+ "Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: %.0f/%.0f/%.0f/%.0f/%.0f/%.0f/%.0f\n"
+
+/* We don't use tally module, to keep upstream happy. */
+struct tally {
+ size_t min, max, total;
+ size_t num;
+};
+
+static void tally_init(struct tally *tally)
+{
+ tally->total = 0;
+ tally->num = 0;
+ tally->min = tally->max = 0;
+}
+
+static void tally_add(struct tally *tally, size_t len)
+{
+ if (tally->num == 0)
+ tally->max = tally->min = len;
+ else if (len > tally->max)
+ tally->max = len;
+ else if (len < tally->min)
+ tally->min = len;
+ tally->num++;
+ tally->total += len;
+}
+
+static size_t tally_mean(const struct tally *tally)
+{
+ if (!tally->num)
+ return 0;
+ return tally->total / tally->num;
+}
+
+static size_t get_hash_length(struct tdb_context *tdb, unsigned int i)
+{
+ tdb_off_t rec_ptr;
+ struct tdb_chainwalk_ctx chainwalk;
+ size_t count = 0;
+
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(i), &rec_ptr) == -1)
+ return 0;
+
+ tdb_chainwalk_init(&chainwalk, rec_ptr);
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ struct tdb_record r;
+ bool ok;
+ ++count;
+ if (tdb_rec_read(tdb, rec_ptr, &r) == -1)
+ return 0;
+ rec_ptr = r.next;
+ ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
+ if (!ok) {
+ return SIZE_MAX;
+ }
+ }
+ return count;
+}
+
+_PUBLIC_ char *tdb_summary(struct tdb_context *tdb)
+{
+ off_t file_size;
+ tdb_off_t off, rec_off;
+ struct tally freet, keys, data, dead, extra, hashval, uncoal;
+ struct tdb_record rec;
+ char *ret = NULL;
+ bool locked;
+ size_t unc = 0;
+ int len;
+ struct tdb_record recovery;
+
+ /* Read-only databases use no locking at all: it's best-effort.
+ * We may have a write lock already, so skip that case too. */
+ if (tdb->read_only || tdb->allrecord_lock.count != 0) {
+ locked = false;
+ } else {
+ if (tdb_lockall_read(tdb) == -1)
+ return NULL;
+ locked = true;
+ }
+
+ if (tdb_recovery_area(tdb, tdb->methods, &rec_off, &recovery) != 0) {
+ goto unlock;
+ }
+
+ tally_init(&freet);
+ tally_init(&keys);
+ tally_init(&data);
+ tally_init(&dead);
+ tally_init(&extra);
+ tally_init(&hashval);
+ tally_init(&uncoal);
+
+ for (off = TDB_DATA_START(tdb->hash_size);
+ off < tdb->map_size - 1;
+ off += sizeof(rec) + rec.rec_len) {
+ if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
+ DOCONV()) == -1)
+ goto unlock;
+ switch (rec.magic) {
+ case TDB_MAGIC:
+ tally_add(&keys, rec.key_len);
+ tally_add(&data, rec.data_len);
+ tally_add(&extra, rec.rec_len - (rec.key_len
+ + rec.data_len));
+ if (unc > 1)
+ tally_add(&uncoal, unc - 1);
+ unc = 0;
+ break;
+ case TDB_FREE_MAGIC:
+ tally_add(&freet, rec.rec_len);
+ unc++;
+ break;
+ /* If we crash after ftruncate, we can get zeroes or fill. */
+ case TDB_RECOVERY_INVALID_MAGIC:
+ case 0x42424242:
+ unc++;
+ /* If it's a valid recovery, we can trust rec_len. */
+ if (off != rec_off) {
+ rec.rec_len = tdb_dead_space(tdb, off)
+ - sizeof(rec);
+ }
+
+ FALL_THROUGH;
+ case TDB_DEAD_MAGIC:
+ tally_add(&dead, rec.rec_len);
+ break;
+ default:
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "Unexpected record magic 0x%x at offset %u\n",
+ rec.magic, off));
+ goto unlock;
+ }
+ }
+ if (unc > 1)
+ tally_add(&uncoal, unc - 1);
+
+ for (off = 0; off < tdb->hash_size; off++)
+ tally_add(&hashval, get_hash_length(tdb, off));
+
+ file_size = tdb->hdr_ofs + tdb->map_size;
+
+ len = asprintf(&ret, SUMMARY_FORMAT,
+ (unsigned long long)file_size, keys.total+data.total,
+ (size_t)tdb->hdr_ofs, (size_t)tdb->map_size,
+ keys.num,
+ (tdb->hash_fn == tdb_jenkins_hash)?"yes":"no",
+ (unsigned)tdb->feature_flags, TDB_SUPPORTED_FEATURE_FLAGS,
+ (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX)?"yes":"no",
+ keys.min, tally_mean(&keys), keys.max,
+ data.min, tally_mean(&data), data.max,
+ extra.min, tally_mean(&extra), extra.max,
+ dead.num,
+ dead.min, tally_mean(&dead), dead.max,
+ freet.num,
+ freet.min, tally_mean(&freet), freet.max,
+ hashval.num,
+ hashval.min, tally_mean(&hashval), hashval.max,
+ uncoal.total,
+ uncoal.min, tally_mean(&uncoal), uncoal.max,
+ keys.total * 100.0 / file_size,
+ data.total * 100.0 / file_size,
+ extra.total * 100.0 / file_size,
+ freet.total * 100.0 / file_size,
+ dead.total * 100.0 / file_size,
+ (keys.num + freet.num + dead.num)
+ * (sizeof(struct tdb_record) + sizeof(uint32_t))
+ * 100.0 / file_size,
+ tdb->hash_size * sizeof(tdb_off_t)
+ * 100.0 / file_size);
+ if (len == -1) {
+ goto unlock;
+ }
+
+unlock:
+ if (locked) {
+ tdb_unlockall_read(tdb);
+ }
+ return ret;
+}
diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
new file mode 100644
index 0000000..de829bb
--- /dev/null
+++ b/lib/tdb/common/tdb.c
@@ -0,0 +1,1348 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+_PUBLIC_ TDB_DATA tdb_null;
+
+/*
+ non-blocking increment of the tdb sequence number if the tdb has been opened using
+ the TDB_SEQNUM flag
+*/
+_PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
+{
+ tdb_off_t seqnum=0;
+
+ if (!(tdb->flags & TDB_SEQNUM)) {
+ return;
+ }
+
+ /* we ignore errors from this, as we have no sane way of
+ dealing with them.
+ */
+ tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+ seqnum++;
+ tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
+}
+
+/*
+ increment the tdb sequence number if the tdb has been opened using
+ the TDB_SEQNUM flag
+*/
+static void tdb_increment_seqnum(struct tdb_context *tdb)
+{
+ if (!(tdb->flags & TDB_SEQNUM)) {
+ return;
+ }
+
+ if (tdb->transaction != NULL) {
+ tdb_increment_seqnum_nonblock(tdb);
+ return;
+ }
+
+#if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
+ if (tdb->map_ptr != NULL) {
+ uint32_t *pseqnum = (uint32_t *)(
+ TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
+ __atomic_add_fetch(pseqnum, 1, __ATOMIC_SEQ_CST);
+ return;
+ }
+#endif
+
+ if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK,
+ TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
+ return;
+ }
+
+ tdb_increment_seqnum_nonblock(tdb);
+
+ tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false);
+}
+
+static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ return memcmp(data.dptr, key.dptr, data.dsize);
+}
+
+void tdb_chainwalk_init(struct tdb_chainwalk_ctx *ctx, tdb_off_t ptr)
+{
+ *ctx = (struct tdb_chainwalk_ctx) { .slow_ptr = ptr };
+}
+
+bool tdb_chainwalk_check(struct tdb_context *tdb,
+ struct tdb_chainwalk_ctx *ctx,
+ tdb_off_t next_ptr)
+{
+ int ret;
+
+ if (ctx->slow_chase) {
+ ret = tdb_ofs_read(tdb, ctx->slow_ptr, &ctx->slow_ptr);
+ if (ret == -1) {
+ return false;
+ }
+ }
+ ctx->slow_chase = !ctx->slow_chase;
+
+ if (next_ptr == ctx->slow_ptr) {
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_chainwalk_check: circular chain\n"));
+ return false;
+ }
+
+ return true;
+}
+
+/* Returns 0 on fail. On success, return offset of record, and fills
+ in rec */
+static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
+ struct tdb_record *r)
+{
+ tdb_off_t rec_ptr;
+ struct tdb_chainwalk_ctx chainwalk;
+
+ /* read in the hash top */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+ return 0;
+
+ tdb_chainwalk_init(&chainwalk, rec_ptr);
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ bool ok;
+
+ if (tdb_rec_read(tdb, rec_ptr, r) == -1)
+ return 0;
+
+ if (!TDB_DEAD(r) && hash==r->full_hash
+ && key.dsize==r->key_len
+ && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
+ r->key_len, tdb_key_compare,
+ NULL) == 0) {
+ return rec_ptr;
+ }
+ rec_ptr = r->next;
+
+ ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
+ if (!ok) {
+ return 0;
+ }
+ }
+ tdb->ecode = TDB_ERR_NOEXIST;
+ return 0;
+}
+
+/* As tdb_find, but if you succeed, keep the lock */
+tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
+ struct tdb_record *rec)
+{
+ uint32_t rec_ptr;
+
+ if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
+ return 0;
+ if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
+ tdb_unlock(tdb, BUCKET(hash), locktype);
+ return rec_ptr;
+}
+
+static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
+
+struct tdb_update_hash_state {
+ const TDB_DATA *dbufs;
+ int num_dbufs;
+ tdb_len_t dbufs_len;
+};
+
+static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ struct tdb_update_hash_state *state = private_data;
+ unsigned char *dptr = data.dptr;
+ int i;
+
+ if (state->dbufs_len != data.dsize) {
+ return -1;
+ }
+
+ for (i=0; i<state->num_dbufs; i++) {
+ TDB_DATA dbuf = state->dbufs[i];
+ if( dbuf.dsize > 0) {
+ int ret;
+ ret = memcmp(dptr, dbuf.dptr, dbuf.dsize);
+ if (ret != 0) {
+ return -1;
+ }
+ dptr += dbuf.dsize;
+ }
+ }
+
+ return 0;
+}
+
+/* update an entry in place - this only works if the new data size
+ is <= the old data size and the key exists.
+ on failure return -1.
+*/
+static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key,
+ uint32_t hash,
+ const TDB_DATA *dbufs, int num_dbufs,
+ tdb_len_t dbufs_len)
+{
+ struct tdb_record rec;
+ tdb_off_t rec_ptr, ofs;
+ int i;
+
+ /* find entry */
+ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
+ return -1;
+
+ /* it could be an exact duplicate of what is there - this is
+ * surprisingly common (eg. with a ldb re-index). */
+ if (rec.data_len == dbufs_len) {
+ struct tdb_update_hash_state state = {
+ .dbufs = dbufs, .num_dbufs = num_dbufs,
+ .dbufs_len = dbufs_len
+ };
+ int ret;
+
+ ret = tdb_parse_record(tdb, key, tdb_update_hash_cmp, &state);
+ if (ret == 0) {
+ return 0;
+ }
+ }
+
+ /* must be long enough key, data and tailer */
+ if (rec.rec_len < key.dsize + dbufs_len + sizeof(tdb_off_t)) {
+ tdb->ecode = TDB_SUCCESS; /* Not really an error */
+ return -1;
+ }
+
+ ofs = rec_ptr + sizeof(rec) + rec.key_len;
+
+ for (i=0; i<num_dbufs; i++) {
+ TDB_DATA dbuf = dbufs[i];
+ int ret;
+
+ ret = tdb->methods->tdb_write(tdb, ofs, dbuf.dptr, dbuf.dsize);
+ if (ret == -1) {
+ return -1;
+ }
+ ofs += dbuf.dsize;
+ }
+
+ if (dbufs_len != rec.data_len) {
+ /* update size */
+ rec.data_len = dbufs_len;
+ return tdb_rec_write(tdb, rec_ptr, &rec);
+ }
+
+ return 0;
+}
+
+/* find an entry in the database given a key */
+/* If an entry doesn't exist tdb_err will be set to
+ * TDB_ERR_NOEXIST. If a key has no data attached
+ * then the TDB_DATA will have zero length but
+ * a non-zero pointer
+ */
+static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+{
+ tdb_off_t rec_ptr;
+ struct tdb_record rec;
+ TDB_DATA ret;
+ uint32_t hash;
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
+ return tdb_null;
+
+ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len);
+ ret.dsize = rec.data_len;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return ret;
+}
+
+_PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+{
+ TDB_DATA ret = _tdb_fetch(tdb, key);
+
+ tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
+ return ret;
+}
+
+/*
+ * Find an entry in the database and hand the record's data to a parsing
+ * function. The parsing function is executed under the chain read lock, so it
+ * should be fast and should not block on other syscalls.
+ *
+ * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
+ *
+ * For mmapped tdb's that do not have a transaction open it points the parsing
+ * function directly at the mmap area, it avoids the malloc/memcpy in this
+ * case. If a transaction is open or no mmap is available, it has to do
+ * malloc/read/parse/free.
+ *
+ * This is interesting for all readers of potentially large data structures in
+ * the tdb records, ldb indexes being one example.
+ *
+ * Return -1 if the record was not found.
+ */
+
+_PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data)
+{
+ tdb_off_t rec_ptr;
+ struct tdb_record rec;
+ int ret;
+ uint32_t hash;
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+
+ if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
+ /* record not found */
+ tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
+ tdb->ecode = TDB_ERR_NOEXIST;
+ return -1;
+ }
+ tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
+
+ ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len, parser, private_data);
+
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+
+ return ret;
+}
+
+/* check if an entry in the database exists
+
+ note that 1 is returned if the key is found and 0 is returned if not found
+ this doesn't match the conventions in the rest of this module, but is
+ compatible with gdbm
+*/
+static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
+{
+ struct tdb_record rec;
+
+ if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
+ return 0;
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+ return 1;
+}
+
+_PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
+{
+ uint32_t hash = tdb->hash_fn(&key);
+ int ret;
+
+ ret = tdb_exists_hash(tdb, key, hash);
+ tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
+ return ret;
+}
+
+/*
+ * Move a dead record to the freelist. The hash chain and freelist
+ * must be locked.
+ */
+static int tdb_del_dead(struct tdb_context *tdb,
+ uint32_t last_ptr,
+ uint32_t rec_ptr,
+ struct tdb_record *rec,
+ bool *deleted)
+{
+ int ret;
+
+ ret = tdb_write_lock_record(tdb, rec_ptr);
+ if (ret == -1) {
+ /* Someone traversing here: Just leave it dead */
+ return 0;
+ }
+ ret = tdb_write_unlock_record(tdb, rec_ptr);
+ if (ret == -1) {
+ return -1;
+ }
+ ret = tdb_ofs_write(tdb, last_ptr, &rec->next);
+ if (ret == -1) {
+ return -1;
+ }
+
+ *deleted = true;
+
+ ret = tdb_free(tdb, rec_ptr, rec);
+ return ret;
+}
+
+/*
+ * Walk the hash chain and leave tdb->max_dead_records around. Move
+ * the rest of dead records to the freelist.
+ */
+int tdb_trim_dead(struct tdb_context *tdb, uint32_t hash)
+{
+ struct tdb_chainwalk_ctx chainwalk;
+ struct tdb_record rec;
+ tdb_off_t last_ptr, rec_ptr;
+ bool locked_freelist = false;
+ int num_dead = 0;
+ int ret;
+
+ last_ptr = TDB_HASH_TOP(hash);
+
+ /*
+ * Init chainwalk with the pointer to the hash top. It might
+ * be that the very first record in the chain is a dead one
+ * that we have to delete.
+ */
+ tdb_chainwalk_init(&chainwalk, last_ptr);
+
+ ret = tdb_ofs_read(tdb, last_ptr, &rec_ptr);
+ if (ret == -1) {
+ return -1;
+ }
+
+ while (rec_ptr != 0) {
+ bool deleted = false;
+ uint32_t next;
+
+ ret = tdb_rec_read(tdb, rec_ptr, &rec);
+ if (ret == -1) {
+ goto fail;
+ }
+
+ /*
+ * Make a copy of rec.next: Further down we might
+ * delete and put the record on the freelist. Make
+ * sure that modifications in that code path can't
+ * break the chainwalk here.
+ */
+ next = rec.next;
+
+ if (rec.magic == TDB_DEAD_MAGIC) {
+ num_dead += 1;
+
+ if (num_dead > tdb->max_dead_records) {
+
+ if (!locked_freelist) {
+ /*
+ * Lock the freelist only if
+ * it's really required.
+ */
+ ret = tdb_lock(tdb, -1, F_WRLCK);
+ if (ret == -1) {
+ goto fail;
+ };
+ locked_freelist = true;
+ }
+
+ ret = tdb_del_dead(
+ tdb,
+ last_ptr,
+ rec_ptr,
+ &rec,
+ &deleted);
+
+ if (ret == -1) {
+ goto fail;
+ }
+ }
+ }
+
+ /*
+ * Don't do the chainwalk check if "rec_ptr" was
+ * deleted. We reduced the chain, and the chainwalk
+ * check might catch up early. Imagine a valid chain
+ * with just dead records: We never can bump the
+ * "slow" pointer in chainwalk_check, as there isn't
+ * anything left to jump to and compare.
+ */
+ if (!deleted) {
+ bool ok;
+
+ last_ptr = rec_ptr;
+
+ ok = tdb_chainwalk_check(tdb, &chainwalk, next);
+ if (!ok) {
+ ret = -1;
+ goto fail;
+ }
+ }
+ rec_ptr = next;
+ }
+ ret = 0;
+fail:
+ if (locked_freelist) {
+ tdb_unlock(tdb, -1, F_WRLCK);
+ }
+ return ret;
+}
+
+/* delete an entry in the database given a key */
+static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
+{
+ tdb_off_t rec_ptr;
+ struct tdb_record rec;
+ int ret;
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec);
+ if (rec_ptr == 0) {
+ return -1;
+ }
+
+ /*
+ * Mark the record dead
+ */
+ rec.magic = TDB_DEAD_MAGIC;
+ ret = tdb_rec_write(tdb, rec_ptr, &rec);
+ if (ret == -1) {
+ goto done;
+ }
+
+ tdb_increment_seqnum(tdb);
+
+ ret = tdb_trim_dead(tdb, hash);
+done:
+ if (tdb_unlock(tdb, BUCKET(hash), F_WRLCK) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
+ return ret;
+}
+
+_PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
+{
+ uint32_t hash = tdb->hash_fn(&key);
+ int ret;
+
+ ret = tdb_delete_hash(tdb, key, hash);
+ tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
+ return ret;
+}
+
+/*
+ * See if we have a dead record around with enough space
+ */
+tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
+ struct tdb_record *r, tdb_len_t length,
+ tdb_off_t *p_last_ptr)
+{
+ tdb_off_t rec_ptr, last_ptr;
+ struct tdb_chainwalk_ctx chainwalk;
+ tdb_off_t best_rec_ptr = 0;
+ tdb_off_t best_last_ptr = 0;
+ struct tdb_record best = { .rec_len = UINT32_MAX };
+
+ length += sizeof(tdb_off_t); /* tailer */
+
+ last_ptr = TDB_HASH_TOP(hash);
+
+ /* read in the hash top */
+ if (tdb_ofs_read(tdb, last_ptr, &rec_ptr) == -1)
+ return 0;
+
+ tdb_chainwalk_init(&chainwalk, rec_ptr);
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ bool ok;
+
+ if (tdb_rec_read(tdb, rec_ptr, r) == -1)
+ return 0;
+
+ if (TDB_DEAD(r) && (r->rec_len >= length) &&
+ (r->rec_len < best.rec_len)) {
+ best_rec_ptr = rec_ptr;
+ best_last_ptr = last_ptr;
+ best = *r;
+ }
+ last_ptr = rec_ptr;
+ rec_ptr = r->next;
+
+ ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
+ if (!ok) {
+ return 0;
+ }
+ }
+
+ if (best.rec_len == UINT32_MAX) {
+ return 0;
+ }
+
+ *r = best;
+ *p_last_ptr = best_last_ptr;
+ return best_rec_ptr;
+}
+
+static int _tdb_storev(struct tdb_context *tdb, TDB_DATA key,
+ const TDB_DATA *dbufs, int num_dbufs,
+ int flag, uint32_t hash)
+{
+ struct tdb_record rec;
+ tdb_off_t rec_ptr, ofs;
+ tdb_len_t rec_len, dbufs_len;
+ int i;
+ int ret = -1;
+
+ dbufs_len = 0;
+
+ for (i=0; i<num_dbufs; i++) {
+ size_t dsize = dbufs[i].dsize;
+
+ if ((dsize != 0) && (dbufs[i].dptr == NULL)) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ goto fail;
+ }
+
+ dbufs_len += dsize;
+ if (dbufs_len < dsize) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+ }
+
+ rec_len = key.dsize + dbufs_len;
+ if ((rec_len < key.dsize) || (rec_len < dbufs_len)) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+
+ /* check for it existing, on insert. */
+ if (flag == TDB_INSERT) {
+ if (tdb_exists_hash(tdb, key, hash)) {
+ tdb->ecode = TDB_ERR_EXISTS;
+ goto fail;
+ }
+ } else {
+ /* first try in-place update, on modify or replace. */
+ if (tdb_update_hash(tdb, key, hash, dbufs, num_dbufs,
+ dbufs_len) == 0) {
+ goto done;
+ }
+ if (tdb->ecode == TDB_ERR_NOEXIST &&
+ flag == TDB_MODIFY) {
+ /* if the record doesn't exist and we are in TDB_MODIFY mode then
+ we should fail the store */
+ goto fail;
+ }
+ }
+ /* reset the error code potentially set by the tdb_update_hash() */
+ tdb->ecode = TDB_SUCCESS;
+
+ /* delete any existing record - if it doesn't exist we don't
+ care. Doing this first reduces fragmentation, and avoids
+ coalescing with `allocated' block before it's updated. */
+ if (flag != TDB_INSERT)
+ tdb_delete_hash(tdb, key, hash);
+
+ /* we have to allocate some space */
+ rec_ptr = tdb_allocate(tdb, hash, rec_len, &rec);
+
+ if (rec_ptr == 0) {
+ goto fail;
+ }
+
+ /* Read hash top into next ptr */
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
+ goto fail;
+
+ rec.key_len = key.dsize;
+ rec.data_len = dbufs_len;
+ rec.full_hash = hash;
+ rec.magic = TDB_MAGIC;
+
+ ofs = rec_ptr;
+
+ /* write out and point the top of the hash chain at it */
+ ret = tdb_rec_write(tdb, ofs, &rec);
+ if (ret == -1) {
+ goto fail;
+ }
+ ofs += sizeof(rec);
+
+ ret = tdb->methods->tdb_write(tdb, ofs, key.dptr, key.dsize);
+ if (ret == -1) {
+ goto fail;
+ }
+ ofs += key.dsize;
+
+ for (i=0; i<num_dbufs; i++) {
+ if (dbufs[i].dsize == 0) {
+ continue;
+ }
+
+ ret = tdb->methods->tdb_write(tdb, ofs, dbufs[i].dptr,
+ dbufs[i].dsize);
+ if (ret == -1) {
+ goto fail;
+ }
+ ofs += dbufs[i].dsize;
+ }
+
+ ret = tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr);
+ if (ret == -1) {
+ /* Need to tdb_unallocate() here */
+ goto fail;
+ }
+
+ done:
+ ret = 0;
+ fail:
+ if (ret == 0) {
+ tdb_increment_seqnum(tdb);
+ }
+ return ret;
+}
+
+static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
+ TDB_DATA dbuf, int flag, uint32_t hash)
+{
+ return _tdb_storev(tdb, key, &dbuf, 1, flag, hash);
+}
+
+/* store an element in the database, replacing any existing element
+ with the same key
+
+ return 0 on success, -1 on failure
+*/
+_PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+ uint32_t hash;
+ int ret;
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1);
+ return -1;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ ret = _tdb_store(tdb, key, dbuf, flag, hash);
+ tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return ret;
+}
+
+_PUBLIC_ int tdb_storev(struct tdb_context *tdb, TDB_DATA key,
+ const TDB_DATA *dbufs, int num_dbufs, int flag)
+{
+ uint32_t hash;
+ int ret;
+
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
+ dbufs, num_dbufs, flag, -1);
+ return -1;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ ret = _tdb_storev(tdb, key, dbufs, num_dbufs, flag, hash);
+ tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
+ dbufs, num_dbufs, flag, -1);
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ return ret;
+}
+
+/* Append to an entry. Create if not exist. */
+_PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
+{
+ uint32_t hash;
+ TDB_DATA dbufs[2];
+ int ret = -1;
+
+ /* find which hash bucket it is in */
+ hash = tdb->hash_fn(&key);
+ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+ return -1;
+
+ dbufs[0] = _tdb_fetch(tdb, key);
+ dbufs[1] = new_dbuf;
+
+ ret = _tdb_storev(tdb, key, dbufs, 2, 0, hash);
+ tdb_trace_2rec_retrec(tdb, "tdb_append", key, dbufs[0], dbufs[1]);
+
+ tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+ SAFE_FREE(dbufs[0].dptr);
+ return ret;
+}
+
+
+/*
+ return the name of the current tdb file
+ useful for external logging functions
+*/
+_PUBLIC_ const char *tdb_name(struct tdb_context *tdb)
+{
+ return tdb->name;
+}
+
+/*
+ return the underlying file descriptor being used by tdb, or -1
+ useful for external routines that want to check the device/inode
+ of the fd
+*/
+_PUBLIC_ int tdb_fd(struct tdb_context *tdb)
+{
+ return tdb->fd;
+}
+
+/*
+ return the current logging function
+ useful for external tdb routines that wish to log tdb errors
+*/
+_PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb)
+{
+ return tdb->log.log_fn;
+}
+
+
+/*
+ get the tdb sequence number. Only makes sense if the writers opened
+ with TDB_SEQNUM set. Note that this sequence number will wrap quite
+ quickly, so it should only be used for a 'has something changed'
+ test, not for code that relies on the count of the number of changes
+ made. If you want a counter then use a tdb record.
+
+ The aim of this sequence number is to allow for a very lightweight
+ test of a possible tdb change.
+*/
+_PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb)
+{
+ tdb_off_t seqnum=0;
+
+ if (tdb->transaction != NULL) {
+ tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+ return seqnum;
+ }
+
+#if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
+ if (tdb->map_ptr != NULL) {
+ uint32_t *pseqnum = (uint32_t *)(
+ TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
+ uint32_t ret;
+ __atomic_load(pseqnum, &ret,__ATOMIC_SEQ_CST);
+ return ret;
+ }
+#endif
+
+ tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+ return seqnum;
+}
+
+_PUBLIC_ int tdb_hash_size(struct tdb_context *tdb)
+{
+ return tdb->hash_size;
+}
+
+_PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb)
+{
+ return tdb->map_size;
+}
+
+_PUBLIC_ int tdb_get_flags(struct tdb_context *tdb)
+{
+ return tdb->flags;
+}
+
+_PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
+{
+ if ((flags & TDB_ALLOW_NESTING) &&
+ (flags & TDB_DISALLOW_NESTING)) {
+ tdb->ecode = TDB_ERR_NESTING;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_add_flags: "
+ "allow_nesting and disallow_nesting are not allowed together!"));
+ return;
+ }
+
+ if (flags & TDB_ALLOW_NESTING) {
+ tdb->flags &= ~TDB_DISALLOW_NESTING;
+ }
+ if (flags & TDB_DISALLOW_NESTING) {
+ tdb->flags &= ~TDB_ALLOW_NESTING;
+ }
+
+ tdb->flags |= flags;
+}
+
+_PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
+{
+ if ((flags & TDB_ALLOW_NESTING) &&
+ (flags & TDB_DISALLOW_NESTING)) {
+ tdb->ecode = TDB_ERR_NESTING;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
+ "allow_nesting and disallow_nesting are not allowed together!"));
+ return;
+ }
+
+ if ((flags & TDB_NOLOCK) &&
+ (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) &&
+ (tdb->mutexes == NULL)) {
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
+ "Can not remove NOLOCK flag on mutexed databases"));
+ return;
+ }
+
+ if (flags & TDB_ALLOW_NESTING) {
+ tdb->flags |= TDB_DISALLOW_NESTING;
+ }
+ if (flags & TDB_DISALLOW_NESTING) {
+ tdb->flags |= TDB_ALLOW_NESTING;
+ }
+
+ tdb->flags &= ~flags;
+}
+
+
+/*
+ enable sequence number handling on an open tdb
+*/
+_PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb)
+{
+ tdb->flags |= TDB_SEQNUM;
+}
+
+
+/*
+ add a region of the file to the freelist. Length is the size of the region in bytes,
+ which includes the free list header that needs to be added
+ */
+static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
+{
+ struct tdb_record rec;
+ if (length <= sizeof(rec)) {
+ /* the region is not worth adding */
+ return 0;
+ }
+ if (length + offset > tdb->map_size) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
+ return -1;
+ }
+ memset(&rec,'\0',sizeof(rec));
+ rec.rec_len = length - sizeof(rec);
+ if (tdb_free(tdb, offset, &rec) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ wipe the entire database, deleting all records. This can be done
+ very fast by using a allrecord lock. The entire data portion of the
+ file becomes a single entry in the freelist.
+
+ This code carefully steps around the recovery area, leaving it alone
+ */
+_PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb)
+{
+ uint32_t i;
+ tdb_off_t offset = 0;
+ ssize_t data_len;
+ tdb_off_t recovery_head;
+ tdb_len_t recovery_size = 0;
+
+ if (tdb_lockall(tdb) != 0) {
+ return -1;
+ }
+
+ tdb_trace(tdb, "tdb_wipe_all");
+
+ /* see if the tdb has a recovery area, and remember its size
+ if so. We don't want to lose this as otherwise each
+ tdb_wipe_all() in a transaction will increase the size of
+ the tdb by the size of the recovery area */
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
+ goto failed;
+ }
+
+ if (recovery_head != 0) {
+ struct tdb_record rec;
+ if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
+ return -1;
+ }
+ recovery_size = rec.rec_len + sizeof(rec);
+ }
+
+ /* wipe the hashes */
+ for (i=0;i<tdb->hash_size;i++) {
+ if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
+ goto failed;
+ }
+ }
+
+ /* wipe the freelist */
+ if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
+ goto failed;
+ }
+
+ /* add all the rest of the file to the freelist, possibly leaving a gap
+ for the recovery area */
+ if (recovery_size == 0) {
+ /* the simple case - the whole file can be used as a freelist */
+ data_len = (tdb->map_size - TDB_DATA_START(tdb->hash_size));
+ if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
+ goto failed;
+ }
+ } else {
+ /* we need to add two freelist entries - one on either
+ side of the recovery area
+
+ Note that we cannot shift the recovery area during
+ this operation. Only the transaction.c code may
+ move the recovery area or we risk subtle data
+ corruption
+ */
+ data_len = (recovery_head - TDB_DATA_START(tdb->hash_size));
+ if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
+ goto failed;
+ }
+ /* and the 2nd free list entry after the recovery area - if any */
+ data_len = tdb->map_size - (recovery_head+recovery_size);
+ if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
+ goto failed;
+ }
+ }
+
+ tdb_increment_seqnum_nonblock(tdb);
+
+ if (tdb_unlockall(tdb) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ tdb_unlockall(tdb);
+ return -1;
+}
+
+struct traverse_state {
+ bool error;
+ struct tdb_context *dest_db;
+};
+
+/*
+ traverse function for repacking
+ */
+static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ struct traverse_state *state = (struct traverse_state *)private_data;
+ if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
+ state->error = true;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ repack a tdb
+ */
+_PUBLIC_ int tdb_repack(struct tdb_context *tdb)
+{
+ struct tdb_context *tmp_db;
+ struct traverse_state state;
+
+ tdb_trace(tdb, "tdb_repack");
+
+ if (tdb_transaction_start(tdb) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n"));
+ return -1;
+ }
+
+ tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0);
+ if (tmp_db == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n"));
+ tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ state.error = false;
+ state.dest_db = tmp_db;
+
+ if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n"));
+ tdb_transaction_cancel(tdb);
+ tdb_close(tmp_db);
+ return -1;
+ }
+
+ if (state.error) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n"));
+ tdb_transaction_cancel(tdb);
+ tdb_close(tmp_db);
+ return -1;
+ }
+
+ if (tdb_wipe_all(tdb) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n"));
+ tdb_transaction_cancel(tdb);
+ tdb_close(tmp_db);
+ return -1;
+ }
+
+ state.error = false;
+ state.dest_db = tdb;
+
+ if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n"));
+ tdb_transaction_cancel(tdb);
+ tdb_close(tmp_db);
+ return -1;
+ }
+
+ if (state.error) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n"));
+ tdb_transaction_cancel(tdb);
+ tdb_close(tmp_db);
+ return -1;
+ }
+
+ tdb_close(tmp_db);
+
+ if (tdb_transaction_commit(tdb) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Even on files, we can get partial writes due to signals. */
+bool tdb_write_all(int fd, const void *buf, size_t count)
+{
+ while (count) {
+ ssize_t ret;
+ ret = write(fd, buf, count);
+ if (ret < 0)
+ return false;
+ buf = (const char *)buf + ret;
+ count -= ret;
+ }
+ return true;
+}
+
+bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret)
+{
+ tdb_off_t ret = a + b;
+
+ if ((ret < a) || (ret < b)) {
+ return false;
+ }
+ *pret = ret;
+ return true;
+}
+
+#ifdef TDB_TRACE
+static void tdb_trace_write(struct tdb_context *tdb, const char *str)
+{
+ if (!tdb_write_all(tdb->tracefd, str, strlen(str))) {
+ close(tdb->tracefd);
+ tdb->tracefd = -1;
+ }
+}
+
+static void tdb_trace_start(struct tdb_context *tdb)
+{
+ tdb_off_t seqnum=0;
+ char msg[sizeof(tdb_off_t) * 4 + 1];
+
+ tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+ snprintf(msg, sizeof(msg), "%u ", seqnum);
+ tdb_trace_write(tdb, msg);
+}
+
+static void tdb_trace_end(struct tdb_context *tdb)
+{
+ tdb_trace_write(tdb, "\n");
+}
+
+static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
+{
+ char msg[sizeof(ret) * 4 + 4];
+ snprintf(msg, sizeof(msg), " = %i\n", ret);
+ tdb_trace_write(tdb, msg);
+}
+
+static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
+{
+ char msg[20 + rec.dsize*2], *p;
+ unsigned int i;
+
+ /* We differentiate zero-length records from non-existent ones. */
+ if (rec.dptr == NULL) {
+ tdb_trace_write(tdb, " NULL");
+ return;
+ }
+
+ /* snprintf here is purely cargo-cult programming. */
+ p = msg;
+ p += snprintf(p, sizeof(msg), " %zu:", rec.dsize);
+ for (i = 0; i < rec.dsize; i++)
+ p += snprintf(p, 2, "%02x", rec.dptr[i]);
+
+ tdb_trace_write(tdb, msg);
+}
+
+void tdb_trace(struct tdb_context *tdb, const char *op)
+{
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_end(tdb);
+}
+
+void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op)
+{
+ char msg[sizeof(tdb_off_t) * 4 + 1];
+
+ snprintf(msg, sizeof(msg), "%u ", seqnum);
+ tdb_trace_write(tdb, msg);
+ tdb_trace_write(tdb, op);
+ tdb_trace_end(tdb);
+}
+
+void tdb_trace_open(struct tdb_context *tdb, const char *op,
+ unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
+{
+ char msg[128];
+
+ snprintf(msg, sizeof(msg),
+ "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags);
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, msg);
+ tdb_trace_end(tdb);
+}
+
+void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
+{
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
+{
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_write(tdb, " =");
+ tdb_trace_record(tdb, ret);
+ tdb_trace_end(tdb);
+}
+
+void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec)
+{
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_record(tdb, rec);
+ tdb_trace_end(tdb);
+}
+
+void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec, int ret)
+{
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_record(tdb, rec);
+ tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec, TDB_DATA ret)
+{
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_record(tdb, rec);
+ tdb_trace_write(tdb, " =");
+ tdb_trace_record(tdb, ret);
+ tdb_trace_end(tdb);
+}
+
+void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
+ int ret)
+{
+ char msg[1 + sizeof(ret) * 4];
+
+ snprintf(msg, sizeof(msg), " %#x", flag);
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_record(tdb, rec1);
+ tdb_trace_record(tdb, rec2);
+ tdb_trace_write(tdb, msg);
+ tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_1plusn_rec_flag_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec,
+ const TDB_DATA *recs, int num_recs,
+ unsigned flag, int ret)
+{
+ char msg[1 + sizeof(ret) * 4];
+ int i;
+
+ snprintf(msg, sizeof(msg), " %#x", flag);
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_record(tdb, rec);
+ for (i=0; i<num_recs; i++) {
+ tdb_trace_record(tdb, recs[i]);
+ }
+ tdb_trace_write(tdb, msg);
+ tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
+{
+ tdb_trace_start(tdb);
+ tdb_trace_write(tdb, op);
+ tdb_trace_record(tdb, rec1);
+ tdb_trace_record(tdb, rec2);
+ tdb_trace_write(tdb, " =");
+ tdb_trace_record(tdb, ret);
+ tdb_trace_end(tdb);
+}
+#endif
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h
new file mode 100644
index 0000000..2979043
--- /dev/null
+++ b/lib/tdb/common/tdb_private.h
@@ -0,0 +1,370 @@
+#ifndef TDB_PRIVATE_H
+#define TDB_PRIVATE_H
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library - private includes
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/shmem.h"
+#include "system/select.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+/* #define TDB_TRACE 1 */
+#ifndef HAVE_GETPAGESIZE
+#define getpagesize() 0x2000
+#endif
+
+typedef uint32_t tdb_len_t;
+typedef uint32_t tdb_off_t;
+
+#ifndef offsetof
+#define offsetof(t,f) ((unsigned int)&((t *)0)->f)
+#endif
+
+#define TDB_MAGIC_FOOD "TDB file\n"
+#define TDB_VERSION (0x26011967 + 6)
+#define TDB_MAGIC (0x26011999U)
+#define TDB_FREE_MAGIC (~TDB_MAGIC)
+#define TDB_DEAD_MAGIC (0xFEE1DEAD)
+#define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
+#define TDB_RECOVERY_INVALID_MAGIC (0x0)
+#define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U)
+#define TDB_FEATURE_FLAG_MAGIC (0xbad1a52U)
+#define TDB_ALIGNMENT 4
+#define DEFAULT_HASH_SIZE 131
+#define FREELIST_TOP (sizeof(struct tdb_header))
+#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
+#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24))
+#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC)
+#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
+#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t))
+#define TDB_HASHTABLE_SIZE(tdb) ((tdb->hash_size+1)*sizeof(tdb_off_t))
+#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t))
+#define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start)
+#define TDB_SEQNUM_OFS offsetof(struct tdb_header, sequence_number)
+#define TDB_PAD_BYTE 0x42
+#define TDB_PAD_U32 0x42424242
+
+#define TDB_FEATURE_FLAG_MUTEX 0x00000001
+
+#define TDB_SUPPORTED_FEATURE_FLAGS ( \
+ TDB_FEATURE_FLAG_MUTEX | \
+ 0)
+
+/* NB assumes there is a local variable called "tdb" that is the
+ * current context, also takes doubly-parenthesized print-style
+ * argument. */
+#define TDB_LOG(x) tdb->log.log_fn x
+
+#ifdef TDB_TRACE
+void tdb_trace(struct tdb_context *tdb, const char *op);
+void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op);
+void tdb_trace_open(struct tdb_context *tdb, const char *op,
+ unsigned hash_size, unsigned tdb_flags, unsigned open_flags);
+void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret);
+void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret);
+void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec);
+void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec, int ret);
+void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec, TDB_DATA ret);
+void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
+ int ret);
+void tdb_trace_1plusn_rec_flag_ret(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec,
+ const TDB_DATA *recs, int num_recs,
+ unsigned flag, int ret);
+void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
+ TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret);
+#else
+#define tdb_trace(tdb, op)
+#define tdb_trace_seqnum(tdb, seqnum, op)
+#define tdb_trace_open(tdb, op, hash_size, tdb_flags, open_flags)
+#define tdb_trace_ret(tdb, op, ret)
+#define tdb_trace_retrec(tdb, op, ret)
+#define tdb_trace_1rec(tdb, op, rec)
+#define tdb_trace_1rec_ret(tdb, op, rec, ret)
+#define tdb_trace_1rec_retrec(tdb, op, rec, ret)
+#define tdb_trace_2rec_flag_ret(tdb, op, rec1, rec2, flag, ret)
+#define tdb_trace_1plusn_rec_flag_ret(tdb, op, rec, recs, num_recs, flag, ret);
+#define tdb_trace_2rec_retrec(tdb, op, rec1, rec2, ret)
+#endif /* !TDB_TRACE */
+
+/* lock offsets */
+#define OPEN_LOCK 0
+#define ACTIVE_LOCK 4
+#define TRANSACTION_LOCK 8
+
+/* free memory if the pointer is valid and zero the pointer */
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
+/*
+ * Note: the BUCKET macro is broken as it returns an unexpected result when
+ * called as BUCKET(-1) for the freelist:
+ *
+ * -1 is sign converted to an unsigned int 4294967295 and then the modulo
+ * tdb->hashtable_size is computed. So with a hashtable_size of 10 the result
+ * is
+ *
+ * 4294967295 % hashtable_size = 5.
+ *
+ * where it should be -1 (C uses symmetric modulo).
+ *
+ * As all callers will lock the same wrong list consistently locking is still
+ * consistent. We can not change this without an incompatible on-disk format
+ * change, otherwise different tdb versions would use incompatible locking.
+ */
+#define BUCKET(hash) ((hash) % tdb->hash_size)
+
+#define DOCONV() (tdb->flags & TDB_CONVERT)
+#define CONVERT(x) (DOCONV() ? tdb_convert(&x, sizeof(x)) : &x)
+
+
+/* the body of the database is made of one tdb_record for the free space
+ plus a separate data list for each hash value */
+struct tdb_record {
+ tdb_off_t next; /* offset of the next record in the list */
+ tdb_len_t rec_len; /* total byte length of record */
+ tdb_len_t key_len; /* byte length of key */
+ tdb_len_t data_len; /* byte length of data */
+ uint32_t full_hash; /* the full 32 bit hash of the key */
+ uint32_t magic; /* try to catch errors */
+ /* the following union is implied:
+ union {
+ char record[rec_len];
+ struct {
+ char key[key_len];
+ char data[data_len];
+ }
+ uint32_t totalsize; (tailer)
+ }
+ */
+};
+
+
+/* this is stored at the front of every database */
+struct tdb_header {
+ char magic_food[32]; /* for /etc/magic */
+ uint32_t version; /* version of the code */
+ uint32_t hash_size; /* number of hash entries */
+ tdb_off_t rwlocks; /* obsolete - kept to detect old formats */
+ tdb_off_t recovery_start; /* offset of transaction recovery region */
+ tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
+ uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */
+ uint32_t magic2_hash; /* hash of TDB_MAGIC. */
+ uint32_t feature_flags;
+ tdb_len_t mutex_size; /* set if TDB_FEATURE_FLAG_MUTEX is set */
+ tdb_off_t reserved[25];
+};
+
+struct tdb_lock_type {
+ uint32_t off;
+ uint32_t count;
+ uint32_t ltype;
+};
+
+struct tdb_chainwalk_ctx {
+ tdb_off_t slow_ptr;
+ bool slow_chase;
+};
+
+struct tdb_traverse_lock {
+ struct tdb_traverse_lock *next;
+ uint32_t off;
+ uint32_t list;
+ int lock_rw;
+};
+
+void tdb_chainwalk_init(struct tdb_chainwalk_ctx *ctx, tdb_off_t ptr);
+bool tdb_chainwalk_check(struct tdb_context *tdb,
+ struct tdb_chainwalk_ctx *ctx,
+ tdb_off_t next_ptr);
+
+enum tdb_lock_flags {
+ /* WAIT == F_SETLKW, NOWAIT == F_SETLK */
+ TDB_LOCK_NOWAIT = 0,
+ TDB_LOCK_WAIT = 1,
+ /* If set, don't log an error on failure. */
+ TDB_LOCK_PROBE = 2,
+ /* If set, don't actually lock at all. */
+ TDB_LOCK_MARK_ONLY = 4,
+};
+
+struct tdb_methods {
+ int (*tdb_read)(struct tdb_context *, tdb_off_t , void *, tdb_len_t , int );
+ int (*tdb_write)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t);
+ void (*next_hash_chain)(struct tdb_context *, uint32_t *);
+ int (*tdb_oob)(struct tdb_context *, tdb_off_t , tdb_len_t, int );
+ int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
+};
+
+struct tdb_mutexes;
+
+struct tdb_context {
+ char *name; /* the name of the database */
+ void *map_ptr; /* where it is currently mapped */
+ int fd; /* open file descriptor for the database */
+ tdb_len_t map_size; /* how much space has been mapped */
+ int read_only; /* opened read-only */
+ int traverse_read; /* read-only traversal */
+ int traverse_write; /* read-write traversal */
+ struct tdb_lock_type allrecord_lock; /* .offset == upgradable */
+ int num_lockrecs;
+ struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
+ int lockrecs_array_length;
+
+ tdb_off_t hdr_ofs; /* this is 0 or header.mutex_size */
+ struct tdb_mutexes *mutexes; /* mmap of the mutex area */
+
+ enum TDB_ERROR ecode; /* error code for last tdb error */
+ uint32_t hash_size;
+ uint32_t feature_flags;
+ uint32_t flags; /* the flags passed to tdb_open */
+ struct tdb_traverse_lock travlocks; /* current traversal locks */
+ struct tdb_context *next; /* all tdbs to avoid multiple opens */
+ dev_t device; /* uniquely identifies this tdb */
+ ino_t inode; /* uniquely identifies this tdb */
+ struct tdb_logging_context log;
+ unsigned int (*hash_fn)(TDB_DATA *key);
+ int open_flags; /* flags used in the open - needed by reopen */
+ const struct tdb_methods *methods;
+ struct tdb_transaction *transaction;
+ int page_size;
+ int max_dead_records;
+#ifdef TDB_TRACE
+ int tracefd;
+#endif
+ volatile sig_atomic_t *interrupt_sig_ptr;
+};
+
+
+/*
+ internal prototypes
+*/
+int tdb_munmap(struct tdb_context *tdb);
+int tdb_mmap(struct tdb_context *tdb);
+int tdb_lock(struct tdb_context *tdb, int list, int ltype);
+int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
+int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
+ enum tdb_lock_flags flags);
+int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
+ bool mark_lock);
+int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
+int tdb_brlock(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len,
+ enum tdb_lock_flags flags);
+int tdb_brunlock(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len);
+bool tdb_have_extra_locks(struct tdb_context *tdb);
+void tdb_release_transaction_locks(struct tdb_context *tdb);
+int tdb_transaction_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags lockflags);
+int tdb_transaction_unlock(struct tdb_context *tdb, int ltype);
+int tdb_recovery_area(struct tdb_context *tdb,
+ const struct tdb_methods *methods,
+ tdb_off_t *recovery_offset,
+ struct tdb_record *rec);
+int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags flags, bool upgradable);
+int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock);
+int tdb_allrecord_upgrade(struct tdb_context *tdb);
+int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+void *tdb_convert(void *buf, uint32_t size);
+int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length,
+ struct tdb_record *rec);
+
+int _tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe);
+
+static inline int tdb_oob(
+ struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe)
+{
+ if (likely((off + len >= off) && (off + len <= tdb->map_size))) {
+ return 0;
+ }
+ return _tdb_oob(tdb, off, len, probe);
+}
+
+
+int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
+int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off);
+int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off);
+bool tdb_needs_recovery(struct tdb_context *tdb);
+int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len);
+int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
+ tdb_off_t offset, tdb_len_t len,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
+ struct tdb_record *rec);
+tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
+ struct tdb_record *r, tdb_len_t length,
+ tdb_off_t *p_last_ptr);
+int tdb_trim_dead(struct tdb_context *tdb, uint32_t hash);
+void tdb_io_init(struct tdb_context *tdb);
+int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
+tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size);
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
+ struct tdb_record *rec);
+bool tdb_write_all(int fd, const void *buf, size_t count);
+int tdb_transaction_recover(struct tdb_context *tdb);
+void tdb_header_hash(struct tdb_context *tdb,
+ uint32_t *magic1_hash, uint32_t *magic2_hash);
+unsigned int tdb_old_hash(TDB_DATA *key);
+size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off);
+bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret);
+
+/* tdb_off_t and tdb_len_t right now are both uint32_t */
+#define tdb_add_len_t tdb_add_off_t
+
+size_t tdb_mutex_size(struct tdb_context *tdb);
+bool tdb_have_mutexes(struct tdb_context *tdb);
+int tdb_mutex_init(struct tdb_context *tdb);
+int tdb_mutex_mmap(struct tdb_context *tdb);
+int tdb_mutex_munmap(struct tdb_context *tdb);
+bool tdb_mutex_lock(struct tdb_context *tdb, int rw, off_t off, off_t len,
+ bool waitflag, int *pret);
+bool tdb_mutex_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len,
+ int *pret);
+int tdb_mutex_allrecord_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags flags);
+int tdb_mutex_allrecord_unlock(struct tdb_context *tdb);
+int tdb_mutex_allrecord_upgrade(struct tdb_context *tdb);
+void tdb_mutex_allrecord_downgrade(struct tdb_context *tdb);
+
+#endif /* TDB_PRIVATE_H */
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
new file mode 100644
index 0000000..78bbd7a
--- /dev/null
+++ b/lib/tdb/common/transaction.c
@@ -0,0 +1,1388 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+/*
+ transaction design:
+
+ - only allow a single transaction at a time per database. This makes
+ using the transaction API simpler, as otherwise the caller would
+ have to cope with temporary failures in transactions that conflict
+ with other current transactions
+
+ - keep the transaction recovery information in the same file as the
+ database, using a special 'transaction recovery' record pointed at
+ by the header. This removes the need for extra journal files as
+ used by some other databases
+
+ - dynamically allocated the transaction recover record, re-using it
+ for subsequent transactions. If a larger record is needed then
+ tdb_free() the old record to place it on the normal tdb freelist
+ before allocating the new record
+
+ - during transactions, keep a linked list of all writes that have
+ been performed by intercepting all tdb_write() calls. The hooked
+ transaction versions of tdb_read() and tdb_write() check this
+ linked list and try to use the elements of the list in preference
+ to the real database.
+
+ - don't allow any locks to be held when a transaction starts,
+ otherwise we can end up with deadlock (plus lack of lock nesting
+ in posix locks would mean the lock is lost)
+
+ - if the caller gains a lock during the transaction but doesn't
+ release it then fail the commit
+
+ - allow for nested calls to tdb_transaction_start(), re-using the
+ existing transaction record. If the inner transaction is cancelled
+ then a subsequent commit will fail
+
+ - keep a mirrored copy of the tdb hash chain heads to allow for the
+ fast hash heads scan on traverse, updating the mirrored copy in
+ the transaction version of tdb_write
+
+ - allow callers to mix transaction and non-transaction use of tdb,
+ although once a transaction is started then an exclusive lock is
+ gained until the transaction is committed or cancelled
+
+ - the commit strategy involves first saving away all modified data
+ into a linearised buffer in the transaction recovery area, then
+ marking the transaction recovery area with a magic value to
+ indicate a valid recovery record. In total 4 fsync/msync calls are
+ needed per commit to prevent race conditions. It might be possible
+ to reduce this to 3 or even 2 with some more work.
+
+ - check for a valid recovery record on open of the tdb, while the
+ open lock is held. Automatically recover from the transaction
+ recovery area if needed, then continue with the open as
+ usual. This allows for smooth crash recovery with no administrator
+ intervention.
+
+ - if TDB_NOSYNC is passed to flags in tdb_open then transactions are
+ still available, but no fsync/msync calls are made. This means we
+ are still proof against a process dying during transaction commit,
+ but not against machine reboot.
+
+ - if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using
+ tdb_add_flags() transaction nesting is enabled.
+ It resets the TDB_DISALLOW_NESTING flag, as both cannot be used together.
+ The default is that transaction nesting is allowed.
+ Note: this default may change in future versions of tdb.
+
+ Beware. when transactions are nested a transaction successfully
+ completed with tdb_transaction_commit() can be silently unrolled later.
+
+ - if TDB_DISALLOW_NESTING is passed to flags in tdb open, or added using
+ tdb_add_flags() transaction nesting is disabled.
+ It resets the TDB_ALLOW_NESTING flag, as both cannot be used together.
+ An attempt create a nested transaction will fail with TDB_ERR_NESTING.
+ The default is that transaction nesting is allowed.
+ Note: this default may change in future versions of tdb.
+*/
+
+
+/*
+ hold the context of any current transaction
+*/
+struct tdb_transaction {
+ /* we keep a mirrored copy of the tdb hash heads here so
+ tdb_next_hash_chain() can operate efficiently */
+ uint32_t *hash_heads;
+
+ /* the original io methods - used to do IOs to the real db */
+ const struct tdb_methods *io_methods;
+
+ /* the list of transaction blocks. When a block is first
+ written to, it gets created in this list */
+ uint8_t **blocks;
+ uint32_t num_blocks;
+ uint32_t block_size; /* bytes in each block */
+ uint32_t last_block_size; /* number of valid bytes in the last block */
+
+ /* non-zero when an internal transaction error has
+ occurred. All write operations will then fail until the
+ transaction is ended */
+ int transaction_error;
+
+ /* when inside a transaction we need to keep track of any
+ nested tdb_transaction_start() calls, as these are allowed,
+ but don't create a new transaction */
+ int nesting;
+
+ /* set when a prepare has already occurred */
+ bool prepared;
+ tdb_off_t magic_offset;
+
+ /* old file size before transaction */
+ tdb_len_t old_map_size;
+
+ /* did we expand in this transaction */
+ bool expanded;
+};
+
+
+/*
+ read while in a transaction. We need to check first if the data is in our list
+ of transaction elements, then if not do a real read
+*/
+static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
+ tdb_len_t len, int cv)
+{
+ uint32_t blk;
+
+ /* break it down into block sized ops */
+ while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+ if (transaction_read(tdb, off, buf, len2, cv) != 0) {
+ return -1;
+ }
+ len -= len2;
+ off += len2;
+ buf = (void *)(len2 + (char *)buf);
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ blk = off / tdb->transaction->block_size;
+
+ /* see if we have it in the block list */
+ if (tdb->transaction->num_blocks <= blk ||
+ tdb->transaction->blocks[blk] == NULL) {
+ /* nope, do a real read */
+ if (tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv) != 0) {
+ goto fail;
+ }
+ return 0;
+ }
+
+ /* it is in the block list. Now check for the last block */
+ if (blk == tdb->transaction->num_blocks-1) {
+ if (len > tdb->transaction->last_block_size) {
+ goto fail;
+ }
+ }
+
+ /* now copy it out of this block */
+ memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len);
+ if (cv) {
+ tdb_convert(buf, len);
+ }
+ return 0;
+
+fail:
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%u len=%u\n", off, len));
+ tdb->ecode = TDB_ERR_IO;
+ tdb->transaction->transaction_error = 1;
+ return -1;
+}
+
+
+/*
+ write while in a transaction
+*/
+static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
+ const void *buf, tdb_len_t len)
+{
+ uint32_t blk;
+
+ if (buf == NULL) {
+ return -1;
+ }
+
+ /* Only a commit is allowed on a prepared transaction */
+ if (tdb->transaction->prepared) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n"));
+ tdb->transaction->transaction_error = 1;
+ return -1;
+ }
+
+ /* if the write is to a hash head, then update the transaction
+ hash heads */
+ if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
+ off < FREELIST_TOP+TDB_HASHTABLE_SIZE(tdb)) {
+ uint32_t chain = (off-FREELIST_TOP) / sizeof(tdb_off_t);
+ memcpy(&tdb->transaction->hash_heads[chain], buf, len);
+ }
+
+ /* break it up into block sized chunks */
+ while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+ if (transaction_write(tdb, off, buf, len2) != 0) {
+ return -1;
+ }
+ len -= len2;
+ off += len2;
+ buf = (const void *)(len2 + (const char *)buf);
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ blk = off / tdb->transaction->block_size;
+ off = off % tdb->transaction->block_size;
+
+ if (tdb->transaction->num_blocks <= blk) {
+ uint8_t **new_blocks;
+ /* expand the blocks array */
+ new_blocks = (uint8_t **)realloc(tdb->transaction->blocks,
+ (blk+1)*sizeof(uint8_t *));
+ if (new_blocks == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+ memset(&new_blocks[tdb->transaction->num_blocks], 0,
+ (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *));
+ tdb->transaction->blocks = new_blocks;
+ tdb->transaction->num_blocks = blk+1;
+ tdb->transaction->last_block_size = 0;
+ }
+
+ /* allocate and fill a block? */
+ if (tdb->transaction->blocks[blk] == NULL) {
+ tdb->transaction->blocks[blk] = (uint8_t *)calloc(tdb->transaction->block_size, 1);
+ if (tdb->transaction->blocks[blk] == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ tdb->transaction->transaction_error = 1;
+ return -1;
+ }
+ if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size;
+ if (len2 + (blk * tdb->transaction->block_size) > tdb->transaction->old_map_size) {
+ len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size);
+ }
+ if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size,
+ tdb->transaction->blocks[blk],
+ len2, 0) != 0) {
+ SAFE_FREE(tdb->transaction->blocks[blk]);
+ tdb->ecode = TDB_ERR_IO;
+ goto fail;
+ }
+ if (blk == tdb->transaction->num_blocks-1) {
+ tdb->transaction->last_block_size = len2;
+ }
+ }
+ }
+
+ /* overwrite part of an existing block */
+ memcpy(tdb->transaction->blocks[blk] + off, buf, len);
+ if (blk == tdb->transaction->num_blocks-1) {
+ if (len + off > tdb->transaction->last_block_size) {
+ tdb->transaction->last_block_size = len + off;
+ }
+ }
+
+ return 0;
+
+fail:
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%u len=%u\n",
+ (blk*tdb->transaction->block_size) + off, len));
+ tdb->transaction->transaction_error = 1;
+ return -1;
+}
+
+
+/*
+ write while in a transaction - this variant never expands the transaction blocks, it only
+ updates existing blocks. This means it cannot change the recovery size
+*/
+static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off,
+ const void *buf, tdb_len_t len)
+{
+ uint32_t blk;
+
+ /* break it up into block sized chunks */
+ while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
+ tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
+ if (transaction_write_existing(tdb, off, buf, len2) != 0) {
+ return -1;
+ }
+ len -= len2;
+ off += len2;
+ if (buf != NULL) {
+ buf = (const void *)(len2 + (const char *)buf);
+ }
+ }
+
+ if (len == 0 || buf == NULL) {
+ return 0;
+ }
+
+ blk = off / tdb->transaction->block_size;
+ off = off % tdb->transaction->block_size;
+
+ if (tdb->transaction->num_blocks <= blk ||
+ tdb->transaction->blocks[blk] == NULL) {
+ return 0;
+ }
+
+ if (blk == tdb->transaction->num_blocks-1 &&
+ off + len > tdb->transaction->last_block_size) {
+ if (off >= tdb->transaction->last_block_size) {
+ return 0;
+ }
+ len = tdb->transaction->last_block_size - off;
+ }
+
+ /* overwrite part of an existing block */
+ memcpy(tdb->transaction->blocks[blk] + off, buf, len);
+
+ return 0;
+}
+
+
+/*
+ accelerated hash chain head search, using the cached hash heads
+*/
+static void transaction_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
+{
+ uint32_t h = *chain;
+ for (;h < tdb->hash_size;h++) {
+ /* the +1 takes account of the freelist */
+ if (0 != tdb->transaction->hash_heads[h+1]) {
+ break;
+ }
+ }
+ (*chain) = h;
+}
+
+/*
+ out of bounds check during a transaction
+*/
+static int transaction_oob(struct tdb_context *tdb, tdb_off_t off,
+ tdb_len_t len, int probe)
+{
+ /*
+ * This duplicates functionality from tdb_oob(). Don't remove:
+ * we still have direct callers of tdb->methods->tdb_oob()
+ * inside transaction.c.
+ */
+ if (off + len >= off && off + len <= tdb->map_size) {
+ return 0;
+ }
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+}
+
+/*
+ transaction version of tdb_expand().
+*/
+static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
+ tdb_off_t addition)
+{
+ const char buf_zero[8192] = {0};
+ size_t buf_len = sizeof(buf_zero);
+
+ while (addition > 0) {
+ size_t n = MIN(addition, buf_len);
+ int ret;
+
+ ret = transaction_write(tdb, size, buf_zero, n);
+ if (ret != 0) {
+ return ret;
+ }
+
+ addition -= n;
+ size += n;
+ }
+
+ tdb->transaction->expanded = true;
+
+ return 0;
+}
+
+static const struct tdb_methods transaction_methods = {
+ transaction_read,
+ transaction_write,
+ transaction_next_hash_chain,
+ transaction_oob,
+ transaction_expand_file,
+};
+
+/*
+ * Is a transaction currently active on this context?
+ *
+ */
+_PUBLIC_ bool tdb_transaction_active(struct tdb_context *tdb)
+{
+ return (tdb->transaction != NULL);
+}
+
+/*
+ start a tdb transaction. No token is returned, as only a single
+ transaction is allowed to be pending per tdb_context
+*/
+static int _tdb_transaction_start(struct tdb_context *tdb,
+ enum tdb_lock_flags lockflags)
+{
+ /* some sanity checks */
+ if (tdb->read_only || (tdb->flags & TDB_INTERNAL)
+ || tdb->traverse_read) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n"));
+ tdb->ecode = TDB_ERR_EINVAL;
+ return -1;
+ }
+
+ /* cope with nested tdb_transaction_start() calls */
+ if (tdb->transaction != NULL) {
+ if (!(tdb->flags & TDB_ALLOW_NESTING)) {
+ tdb->ecode = TDB_ERR_NESTING;
+ return -1;
+ }
+ tdb->transaction->nesting++;
+ TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n",
+ tdb->transaction->nesting));
+ return 0;
+ }
+
+ if (tdb_have_extra_locks(tdb)) {
+ /* the caller must not have any locks when starting a
+ transaction as otherwise we'll be screwed by lack
+ of nested locks in posix */
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ if (tdb->travlocks.next != NULL) {
+ /* you cannot use transactions inside a traverse (although you can use
+ traverse inside a transaction) as otherwise you can end up with
+ deadlock */
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction within a traverse\n"));
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ tdb->transaction = (struct tdb_transaction *)
+ calloc(sizeof(struct tdb_transaction), 1);
+ if (tdb->transaction == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ return -1;
+ }
+
+ /* a page at a time seems like a reasonable compromise between compactness and efficiency */
+ tdb->transaction->block_size = tdb->page_size;
+
+ /* get the transaction write lock. This is a blocking lock. As
+ discussed with Volker, there are a number of ways we could
+ make this async, which we will probably do in the future */
+ if (tdb_transaction_lock(tdb, F_WRLCK, lockflags) == -1) {
+ SAFE_FREE(tdb->transaction->blocks);
+ SAFE_FREE(tdb->transaction);
+ if ((lockflags & TDB_LOCK_WAIT) == 0) {
+ tdb->ecode = TDB_ERR_NOLOCK;
+ } else {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_start: "
+ "failed to get transaction lock\n"));
+ }
+ return -1;
+ }
+
+ /* get a read lock from the freelist to the end of file. This
+ is upgraded to a write lock during the commit */
+ if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, true) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n"));
+ goto fail_allrecord_lock;
+ }
+
+ /* setup a copy of the hash table heads so the hash scan in
+ traverse can be fast */
+ tdb->transaction->hash_heads = (uint32_t *)
+ calloc(tdb->hash_size+1, sizeof(uint32_t));
+ if (tdb->transaction->hash_heads == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+ if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
+ TDB_HASHTABLE_SIZE(tdb), 0) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to read hash heads\n"));
+ tdb->ecode = TDB_ERR_IO;
+ goto fail;
+ }
+
+ /* make sure we know about any file expansions already done by
+ anyone else */
+ tdb_oob(tdb, tdb->map_size, 1, 1);
+ tdb->transaction->old_map_size = tdb->map_size;
+
+ /* finally hook the io methods, replacing them with
+ transaction specific methods */
+ tdb->transaction->io_methods = tdb->methods;
+ tdb->methods = &transaction_methods;
+
+ /* Trace at the end, so we get sequence number correct. */
+ tdb_trace(tdb, "tdb_transaction_start");
+ return 0;
+
+fail:
+ tdb_allrecord_unlock(tdb, F_RDLCK, false);
+fail_allrecord_lock:
+ tdb_transaction_unlock(tdb, F_WRLCK);
+ SAFE_FREE(tdb->transaction->blocks);
+ SAFE_FREE(tdb->transaction->hash_heads);
+ SAFE_FREE(tdb->transaction);
+ return -1;
+}
+
+_PUBLIC_ int tdb_transaction_start(struct tdb_context *tdb)
+{
+ return _tdb_transaction_start(tdb, TDB_LOCK_WAIT);
+}
+
+_PUBLIC_ int tdb_transaction_start_nonblock(struct tdb_context *tdb)
+{
+ return _tdb_transaction_start(tdb, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
+}
+
+/*
+ sync to disk
+*/
+static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
+{
+ if (tdb->flags & TDB_NOSYNC) {
+ return 0;
+ }
+
+#ifdef HAVE_FDATASYNC
+ if (fdatasync(tdb->fd) != 0) {
+#else
+ if (fsync(tdb->fd) != 0) {
+#endif
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
+ return -1;
+ }
+#ifdef HAVE_MMAP
+ if (tdb->map_ptr) {
+ tdb_off_t moffset = offset & ~(tdb->page_size-1);
+ if (msync(moffset + (char *)tdb->map_ptr,
+ length + (offset - moffset), MS_SYNC) != 0) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
+ strerror(errno)));
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+
+static int _tdb_transaction_cancel(struct tdb_context *tdb)
+{
+ uint32_t i;
+ int ret = 0;
+
+ if (tdb->transaction == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
+ return -1;
+ }
+
+ if (tdb->transaction->nesting != 0) {
+ tdb->transaction->transaction_error = 1;
+ tdb->transaction->nesting--;
+ return 0;
+ }
+
+ tdb->map_size = tdb->transaction->old_map_size;
+
+ /* free all the transaction blocks */
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ if ((tdb->transaction->blocks != NULL) &&
+ tdb->transaction->blocks[i] != NULL) {
+ free(tdb->transaction->blocks[i]);
+ }
+ }
+ SAFE_FREE(tdb->transaction->blocks);
+
+ if (tdb->transaction->magic_offset) {
+ const struct tdb_methods *methods = tdb->transaction->io_methods;
+ const uint32_t invalid = TDB_RECOVERY_INVALID_MAGIC;
+
+ /* remove the recovery marker */
+ if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &invalid, 4) == -1 ||
+ transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n"));
+ ret = -1;
+ }
+ }
+
+ /* This also removes the OPEN_LOCK, if we have it. */
+ tdb_release_transaction_locks(tdb);
+
+ /* restore the normal io methods */
+ tdb->methods = tdb->transaction->io_methods;
+
+ SAFE_FREE(tdb->transaction->hash_heads);
+ SAFE_FREE(tdb->transaction);
+
+ return ret;
+}
+
+/*
+ cancel the current transaction
+*/
+_PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_transaction_cancel");
+ return _tdb_transaction_cancel(tdb);
+}
+
+/*
+ work out how much space the linearised recovery data will consume
+*/
+static bool tdb_recovery_size(struct tdb_context *tdb, tdb_len_t *result)
+{
+ tdb_len_t recovery_size = 0;
+ uint32_t i;
+
+ recovery_size = sizeof(uint32_t);
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ tdb_len_t block_size;
+ if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) {
+ break;
+ }
+ if (tdb->transaction->blocks[i] == NULL) {
+ continue;
+ }
+ if (!tdb_add_len_t(recovery_size, 2*sizeof(tdb_off_t),
+ &recovery_size)) {
+ return false;
+ }
+ if (i == tdb->transaction->num_blocks-1) {
+ block_size = tdb->transaction->last_block_size;
+ } else {
+ block_size = tdb->transaction->block_size;
+ }
+ if (!tdb_add_len_t(recovery_size, block_size,
+ &recovery_size)) {
+ return false;
+ }
+ }
+
+ *result = recovery_size;
+ return true;
+}
+
+int tdb_recovery_area(struct tdb_context *tdb,
+ const struct tdb_methods *methods,
+ tdb_off_t *recovery_offset,
+ struct tdb_record *rec)
+{
+ int ret;
+
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, recovery_offset) == -1) {
+ return -1;
+ }
+
+ if (*recovery_offset == 0) {
+ rec->rec_len = 0;
+ return 0;
+ }
+
+ if (methods->tdb_read(tdb, *recovery_offset, rec, sizeof(*rec),
+ DOCONV()) == -1) {
+ return -1;
+ }
+
+ /* ignore invalid recovery regions: can happen in crash */
+ if (rec->magic != TDB_RECOVERY_MAGIC &&
+ rec->magic != TDB_RECOVERY_INVALID_MAGIC) {
+ *recovery_offset = 0;
+ rec->rec_len = 0;
+ }
+
+ ret = methods->tdb_oob(tdb, *recovery_offset, rec->rec_len, 1);
+ if (ret == -1) {
+ *recovery_offset = 0;
+ rec->rec_len = 0;
+ }
+
+ return 0;
+}
+
+/*
+ allocate the recovery area, or use an existing recovery area if it is
+ large enough
+*/
+static int tdb_recovery_allocate(struct tdb_context *tdb,
+ tdb_len_t *recovery_size,
+ tdb_off_t *recovery_offset,
+ tdb_len_t *recovery_max_size)
+{
+ struct tdb_record rec;
+ const struct tdb_methods *methods = tdb->transaction->io_methods;
+ tdb_off_t recovery_head, new_end;
+
+ if (tdb_recovery_area(tdb, methods, &recovery_head, &rec) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n"));
+ return -1;
+ }
+
+ if (!tdb_recovery_size(tdb, recovery_size)) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: "
+ "overflow recovery size\n"));
+ return -1;
+ }
+
+ /* Existing recovery area? */
+ if (recovery_head != 0 && *recovery_size <= rec.rec_len) {
+ /* it fits in the existing area */
+ *recovery_max_size = rec.rec_len;
+ *recovery_offset = recovery_head;
+ return 0;
+ }
+
+ /* If recovery area in middle of file, we need a new one. */
+ if (recovery_head == 0
+ || recovery_head + sizeof(rec) + rec.rec_len != tdb->map_size) {
+ /* we need to free up the old recovery area, then allocate a
+ new one at the end of the file. Note that we cannot use
+ tdb_allocate() to allocate the new one as that might return
+ us an area that is being currently used (as of the start of
+ the transaction) */
+ if (recovery_head) {
+ if (tdb_free(tdb, recovery_head, &rec) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "tdb_recovery_allocate: failed to"
+ " free previous recovery area\n"));
+ return -1;
+ }
+
+ /* the tdb_free() call might have increased
+ * the recovery size */
+ if (!tdb_recovery_size(tdb, recovery_size)) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "tdb_recovery_allocate: "
+ "overflow recovery size\n"));
+ return -1;
+ }
+ }
+
+ /* New head will be at end of file. */
+ recovery_head = tdb->map_size;
+ }
+
+ /* Now we know where it will be. */
+ *recovery_offset = recovery_head;
+
+ /* Expand by more than we need, so we don't do it often. */
+ *recovery_max_size = tdb_expand_adjust(tdb->map_size,
+ *recovery_size,
+ tdb->page_size)
+ - sizeof(rec);
+
+ if (!tdb_add_off_t(recovery_head, sizeof(rec), &new_end) ||
+ !tdb_add_off_t(new_end, *recovery_max_size, &new_end)) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: "
+ "overflow recovery area\n"));
+ return -1;
+ }
+
+ if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
+ new_end - tdb->transaction->old_map_size)
+ == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
+ return -1;
+ }
+
+ /* remap the file (if using mmap) */
+ methods->tdb_oob(tdb, tdb->map_size, 1, 1);
+
+ /* we have to reset the old map size so that we don't try to expand the file
+ again in the transaction commit, which would destroy the recovery area */
+ tdb->transaction->old_map_size = tdb->map_size;
+
+ /* write the recovery header offset and sync - we can sync without a race here
+ as the magic ptr in the recovery record has not been set */
+ CONVERT(recovery_head);
+ if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD,
+ &recovery_head, sizeof(tdb_off_t)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
+ return -1;
+ }
+ if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ setup the recovery data that will be used on a crash during commit
+*/
+static int transaction_setup_recovery(struct tdb_context *tdb,
+ tdb_off_t *magic_offset)
+{
+ tdb_len_t recovery_size;
+ unsigned char *data, *p;
+ const struct tdb_methods *methods = tdb->transaction->io_methods;
+ struct tdb_record *rec;
+ tdb_off_t recovery_offset, recovery_max_size;
+ tdb_off_t old_map_size = tdb->transaction->old_map_size;
+ uint32_t magic, tailer;
+ uint32_t i;
+
+ /*
+ check that the recovery area has enough space
+ */
+ if (tdb_recovery_allocate(tdb, &recovery_size,
+ &recovery_offset, &recovery_max_size) == -1) {
+ return -1;
+ }
+
+ rec = malloc(recovery_size + sizeof(*rec));
+ if (rec == NULL) {
+ tdb->ecode = TDB_ERR_OOM;
+ return -1;
+ }
+
+ memset(rec, 0, sizeof(*rec));
+
+ rec->magic = TDB_RECOVERY_INVALID_MAGIC;
+ rec->data_len = recovery_size;
+ rec->rec_len = recovery_max_size;
+ rec->key_len = old_map_size;
+ CONVERT(*rec);
+
+ data = (unsigned char *)rec;
+
+ /* build the recovery data into a single blob to allow us to do a single
+ large write, which should be more efficient */
+ p = data + sizeof(*rec);
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ tdb_off_t offset;
+ tdb_len_t length;
+
+ if (tdb->transaction->blocks[i] == NULL) {
+ continue;
+ }
+
+ offset = i * tdb->transaction->block_size;
+ length = tdb->transaction->block_size;
+ if (i == tdb->transaction->num_blocks-1) {
+ length = tdb->transaction->last_block_size;
+ }
+
+ if (offset >= old_map_size) {
+ continue;
+ }
+ if (offset + length > tdb->transaction->old_map_size) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n"));
+ free(data);
+ tdb->ecode = TDB_ERR_CORRUPT;
+ return -1;
+ }
+ memcpy(p, &offset, 4);
+ memcpy(p+4, &length, 4);
+ if (DOCONV()) {
+ tdb_convert(p, 8);
+ }
+ /* the recovery area contains the old data, not the
+ new data, so we have to call the original tdb_read
+ method to get it */
+ if (methods->tdb_read(tdb, offset, p + 8, length, 0) != 0) {
+ free(data);
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ p += 8 + length;
+ }
+
+ /* and the tailer */
+ tailer = sizeof(*rec) + recovery_max_size;
+ memcpy(p, &tailer, 4);
+ if (DOCONV()) {
+ tdb_convert(p, 4);
+ }
+
+ /* write the recovery data to the recovery area */
+ if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery data\n"));
+ free(data);
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n"));
+ free(data);
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* as we don't have ordered writes, we have to sync the recovery
+ data before we update the magic to indicate that the recovery
+ data is present */
+ if (transaction_sync(tdb, recovery_offset, sizeof(*rec) + recovery_size) == -1) {
+ free(data);
+ return -1;
+ }
+
+ free(data);
+
+ magic = TDB_RECOVERY_MAGIC;
+ CONVERT(magic);
+
+ *magic_offset = recovery_offset + offsetof(struct tdb_record, magic);
+
+ if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* ensure the recovery magic marker is on disk */
+ if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _tdb_transaction_prepare_commit(struct tdb_context *tdb)
+{
+ const struct tdb_methods *methods;
+
+ if (tdb->transaction == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n"));
+ return -1;
+ }
+
+ if (tdb->transaction->prepared) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ _tdb_transaction_cancel(tdb);
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n"));
+ return -1;
+ }
+
+ if (tdb->transaction->transaction_error) {
+ tdb->ecode = TDB_ERR_IO;
+ _tdb_transaction_cancel(tdb);
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n"));
+ return -1;
+ }
+
+
+ if (tdb->transaction->nesting != 0) {
+ return 0;
+ }
+
+ /* check for a null transaction */
+ if (tdb->transaction->blocks == NULL) {
+ return 0;
+ }
+
+ methods = tdb->transaction->io_methods;
+
+ /* if there are any locks pending then the caller has not
+ nested their locks properly, so fail the transaction */
+ if (tdb_have_extra_locks(tdb)) {
+ tdb->ecode = TDB_ERR_LOCK;
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n"));
+ _tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ /* upgrade the main transaction lock region to a write lock */
+ if (tdb_allrecord_upgrade(tdb) == -1) {
+ if (tdb->ecode == TDB_ERR_RDONLY && tdb->read_only) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_prepare_commit: "
+ "failed to upgrade hash locks: "
+ "database is read only\n"));
+ } else if (tdb->ecode == TDB_ERR_RDONLY
+ && tdb->traverse_read) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_prepare_commit: "
+ "failed to upgrade hash locks: "
+ "a database traverse is in progress\n"));
+ } else {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ "tdb_transaction_prepare_commit: "
+ "failed to upgrade hash locks: %s\n",
+ tdb_errorstr(tdb)));
+ }
+ _tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ /* get the open lock - this prevents new users attaching to the database
+ during the commit */
+ if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get open lock\n"));
+ _tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ /* write the recovery data to the end of the file */
+ if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
+ _tdb_transaction_cancel(tdb);
+ return -1;
+ }
+
+ tdb->transaction->prepared = true;
+
+ /* expand the file to the new size if needed */
+ if (tdb->map_size != tdb->transaction->old_map_size) {
+ if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
+ tdb->map_size -
+ tdb->transaction->old_map_size) == -1) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n"));
+ _tdb_transaction_cancel(tdb);
+ return -1;
+ }
+ tdb->map_size = tdb->transaction->old_map_size;
+ methods->tdb_oob(tdb, tdb->map_size, 1, 1);
+ }
+
+ /* Keep the open lock until the actual commit */
+
+ return 0;
+}
+
+/*
+ prepare to commit the current transaction
+*/
+_PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb)
+{
+ tdb_trace(tdb, "tdb_transaction_prepare_commit");
+ return _tdb_transaction_prepare_commit(tdb);
+}
+
+/* A repack is worthwhile if the largest is less than half total free. */
+static bool repack_worthwhile(struct tdb_context *tdb)
+{
+ tdb_off_t ptr;
+ struct tdb_record rec;
+ tdb_len_t total = 0, largest = 0;
+
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &ptr) == -1) {
+ return false;
+ }
+
+ while (ptr != 0 && tdb_rec_free_read(tdb, ptr, &rec) == 0) {
+ total += rec.rec_len;
+ if (rec.rec_len > largest) {
+ largest = rec.rec_len;
+ }
+ ptr = rec.next;
+ }
+
+ return total > largest * 2;
+}
+
+/*
+ commit the current transaction
+*/
+_PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb)
+{
+ const struct tdb_methods *methods;
+ uint32_t i;
+ bool need_repack = false;
+
+ if (tdb->transaction == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
+ return -1;
+ }
+
+ tdb_trace(tdb, "tdb_transaction_commit");
+
+ if (tdb->transaction->transaction_error) {
+ tdb->ecode = TDB_ERR_IO;
+ _tdb_transaction_cancel(tdb);
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
+ return -1;
+ }
+
+
+ if (tdb->transaction->nesting != 0) {
+ tdb->transaction->nesting--;
+ return 0;
+ }
+
+ /* check for a null transaction */
+ if (tdb->transaction->blocks == NULL) {
+ _tdb_transaction_cancel(tdb);
+ return 0;
+ }
+
+ if (!tdb->transaction->prepared) {
+ int ret = _tdb_transaction_prepare_commit(tdb);
+ if (ret)
+ return ret;
+ }
+
+ methods = tdb->transaction->io_methods;
+
+ /* perform all the writes */
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ tdb_off_t offset;
+ tdb_len_t length;
+
+ if (tdb->transaction->blocks[i] == NULL) {
+ continue;
+ }
+
+ offset = i * tdb->transaction->block_size;
+ length = tdb->transaction->block_size;
+ if (i == tdb->transaction->num_blocks-1) {
+ length = tdb->transaction->last_block_size;
+ }
+
+ if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n"));
+
+ /* we've overwritten part of the data and
+ possibly expanded the file, so we need to
+ run the crash recovery code */
+ tdb->methods = methods;
+ tdb_transaction_recover(tdb);
+
+ _tdb_transaction_cancel(tdb);
+
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n"));
+ return -1;
+ }
+ SAFE_FREE(tdb->transaction->blocks[i]);
+ }
+
+ /* Do this before we drop lock or blocks. */
+ if (tdb->transaction->expanded) {
+ need_repack = repack_worthwhile(tdb);
+ }
+
+ SAFE_FREE(tdb->transaction->blocks);
+ tdb->transaction->num_blocks = 0;
+
+ /* ensure the new data is on disk */
+ if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
+ return -1;
+ }
+
+ /*
+ TODO: maybe write to some dummy hdr field, or write to magic
+ offset without mmap, before the last sync, instead of the
+ utime() call
+ */
+
+ /* on some systems (like Linux 2.6.x) changes via mmap/msync
+ don't change the mtime of the file, this means the file may
+ not be backed up (as tdb rounding to block sizes means that
+ file size changes are quite rare too). The following forces
+ mtime changes when a transaction completes */
+#ifdef HAVE_UTIME
+ utime(tdb->name, NULL);
+#endif
+
+ /* use a transaction cancel to free memory and remove the
+ transaction locks */
+ _tdb_transaction_cancel(tdb);
+
+ if (need_repack) {
+ int ret = tdb_repack(tdb);
+ if (ret != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ __location__ " Failed to repack database (not fatal)\n"));
+ }
+ /*
+ * Ignore the error.
+ *
+ * Why?
+ *
+ * We just committed to the DB above, so anything
+ * written during the transaction is committed, the
+ * caller needs to know that the long-term state was
+ * successfully modified.
+ *
+ * tdb_repack is an optimization that can fail for
+ * reasons like lock ordering and we cannot recover
+ * the transaction lock at this point, having released
+ * it above.
+ *
+ * If we return a failure the caller thinks the
+ * transaction was rolled back.
+ */
+ }
+
+ return 0;
+}
+
+
+/*
+ recover from an aborted transaction. Must be called with exclusive
+ database write access already established (including the open
+ lock to prevent new processes attaching)
+*/
+int tdb_transaction_recover(struct tdb_context *tdb)
+{
+ tdb_off_t recovery_head, recovery_eof;
+ unsigned char *data, *p;
+ uint32_t zero = 0;
+ struct tdb_record rec;
+
+ /* find the recovery area */
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery head\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ if (recovery_head == 0) {
+ /* we have never allocated a recovery record */
+ return 0;
+ }
+
+ /* read the recovery record */
+ if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
+ sizeof(rec), DOCONV()) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ if (rec.magic != TDB_RECOVERY_MAGIC) {
+ /* there is no valid recovery data */
+ return 0;
+ }
+
+ if (tdb->read_only) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: attempt to recover read only database\n"));
+ tdb->ecode = TDB_ERR_CORRUPT;
+ return -1;
+ }
+
+ recovery_eof = rec.key_len;
+
+ data = (unsigned char *)malloc(rec.data_len);
+ if (data == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));
+ tdb->ecode = TDB_ERR_OOM;
+ return -1;
+ }
+
+ /* read the full recovery data */
+ if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
+ rec.data_len, 0) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));
+ tdb->ecode = TDB_ERR_IO;
+ free(data);
+ return -1;
+ }
+
+ /* recover the file data */
+ p = data;
+ while (p+8 < data + rec.data_len) {
+ uint32_t ofs, len;
+ if (DOCONV()) {
+ tdb_convert(p, 8);
+ }
+ memcpy(&ofs, p, 4);
+ memcpy(&len, p+4, 4);
+
+ if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) {
+ free(data);
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %u bytes at offset %u\n", len, ofs));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ p += 8 + len;
+ }
+
+ free(data);
+
+ if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync recovery\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ /* if the recovery area is after the recovered eof then remove it */
+ if (recovery_eof <= recovery_head) {
+ if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ }
+
+ /* remove the recovery magic */
+ if (tdb_ofs_write(tdb, recovery_head + offsetof(struct tdb_record, magic),
+ &zero) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ if (transaction_sync(tdb, 0, recovery_eof) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync2 recovery\n"));
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+ TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %u byte database\n",
+ recovery_eof));
+
+ /* all done */
+ return 0;
+}
+
+/* Any I/O failures we say "needs recovery". */
+bool tdb_needs_recovery(struct tdb_context *tdb)
+{
+ tdb_off_t recovery_head;
+ struct tdb_record rec;
+
+ /* find the recovery area */
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+ return true;
+ }
+
+ if (recovery_head == 0) {
+ /* we have never allocated a recovery record */
+ return false;
+ }
+
+ /* read the recovery record */
+ if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
+ sizeof(rec), DOCONV()) == -1) {
+ return true;
+ }
+
+ return (rec.magic == TDB_RECOVERY_MAGIC);
+}
diff --git a/lib/tdb/common/traverse.c b/lib/tdb/common/traverse.c
new file mode 100644
index 0000000..fcd2e00
--- /dev/null
+++ b/lib/tdb/common/traverse.c
@@ -0,0 +1,510 @@
+ /*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2005
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000-2003
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tdb_private.h"
+
+#define TDB_NEXT_LOCK_ERR ((tdb_off_t)-1)
+
+/* Uses traverse lock: 0 = finish, TDB_NEXT_LOCK_ERR = error,
+ other = record offset */
+static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tlock,
+ struct tdb_record *rec)
+{
+ int want_next = (tlock->off != 0);
+
+ /* Lock each chain from the start one. */
+ for (; tlock->list < tdb->hash_size; tlock->list++) {
+ if (!tlock->off && tlock->list != 0) {
+ /* this is an optimisation for the common case where
+ the hash chain is empty, which is particularly
+ common for the use of tdb with ldb, where large
+ hashes are used. In that case we spend most of our
+ time in tdb_brlock(), locking empty hash chains.
+
+ To avoid this, we do an unlocked pre-check to see
+ if the hash chain is empty before starting to look
+ inside it. If it is empty then we can avoid that
+ hash chain. If it isn't empty then we can't believe
+ the value we get back, as we read it without a
+ lock, so instead we get the lock and re-fetch the
+ value below.
+
+ Notice that not doing this optimisation on the
+ first hash chain is critical. We must guarantee
+ that we have done at least one fcntl lock at the
+ start of a search to guarantee that memory is
+ coherent on SMP systems. If records are added by
+ others during the search then that's OK, and we
+ could possibly miss those with this trick, but we
+ could miss them anyway without this trick, so the
+ semantics don't change.
+
+ With a non-indexed ldb search this trick gains us a
+ factor of around 80 in speed on a linux 2.6.x
+ system (testing using ldbtest).
+ */
+ tdb->methods->next_hash_chain(tdb, &tlock->list);
+ if (tlock->list == tdb->hash_size) {
+ continue;
+ }
+ }
+
+ if (tdb_lock(tdb, tlock->list, tlock->lock_rw) == -1)
+ return TDB_NEXT_LOCK_ERR;
+
+ /* No previous record? Start at top of chain. */
+ if (!tlock->off) {
+ if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->list),
+ &tlock->off) == -1)
+ goto fail;
+ } else {
+ /* Otherwise unlock the previous record. */
+ if (tdb_unlock_record(tdb, tlock->off) != 0)
+ goto fail;
+ }
+
+ if (want_next) {
+ /* We have offset of old record: grab next */
+ if (tdb_rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+ tlock->off = rec->next;
+ }
+
+ /* Iterate through chain */
+ while( tlock->off) {
+ if (tdb_rec_read(tdb, tlock->off, rec) == -1)
+ goto fail;
+
+ /* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi@exanet.com>. */
+ if (tlock->off == rec->next) {
+ tdb->ecode = TDB_ERR_CORRUPT;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n"));
+ goto fail;
+ }
+
+ if (!TDB_DEAD(rec)) {
+ /* Woohoo: we found one! */
+ if (tdb_lock_record(tdb, tlock->off) != 0)
+ goto fail;
+ return tlock->off;
+ }
+
+ tlock->off = rec->next;
+ }
+ tdb_unlock(tdb, tlock->list, tlock->lock_rw);
+ want_next = 0;
+ }
+ /* We finished iteration without finding anything */
+ tdb->ecode = TDB_SUCCESS;
+ return 0;
+
+ fail:
+ tlock->off = 0;
+ if (tdb_unlock(tdb, tlock->list, tlock->lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n"));
+ return TDB_NEXT_LOCK_ERR;
+}
+
+/* traverse the entire database - calling fn(tdb, key, data) on each element.
+ return -1 on error or the record count traversed
+ if fn is NULL then it is not called
+ a non-zero return value from fn() indicates that the traversal should stop
+ */
+static int tdb_traverse_internal(struct tdb_context *tdb,
+ tdb_traverse_func fn, void *private_data,
+ struct tdb_traverse_lock *tl)
+{
+ TDB_DATA key, dbuf;
+ struct tdb_record rec;
+ int ret = 0, count = 0;
+ tdb_off_t off;
+ size_t recbuf_len;
+
+ recbuf_len = 4096;
+ key.dptr = malloc(recbuf_len);
+ if (key.dptr == NULL) {
+ return -1;
+ }
+
+ /* This was in the initialization, above, but the IRIX compiler
+ * did not like it. crh
+ */
+ tl->next = tdb->travlocks.next;
+
+ /* fcntl locks don't stack: beware traverse inside traverse */
+ tdb->travlocks.next = tl;
+
+ /* tdb_next_lock places locks on the record returned, and its chain */
+ while ((off = tdb_next_lock(tdb, tl, &rec)) != 0) {
+ tdb_len_t full_len;
+ int nread;
+
+ if (off == TDB_NEXT_LOCK_ERR) {
+ ret = -1;
+ goto out;
+ }
+
+ full_len = rec.key_len + rec.data_len;
+
+ if (full_len > recbuf_len) {
+ recbuf_len = full_len;
+
+ /*
+ * No realloc, we don't need the old data and thus can
+ * do without the memcpy
+ */
+ free(key.dptr);
+ key.dptr = malloc(recbuf_len);
+
+ if (key.dptr == NULL) {
+ ret = -1;
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw)
+ != 0) {
+ goto out;
+ }
+ if (tdb_unlock_record(tdb, tl->off) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "tdb_traverse: malloc "
+ "failed and unlock_record "
+ "failed!\n"));
+ }
+ goto out;
+ }
+ }
+
+ count++;
+ /* now read the full record */
+ nread = tdb->methods->tdb_read(tdb, tl->off + sizeof(rec),
+ key.dptr, full_len, 0);
+ if (nread == -1) {
+ ret = -1;
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw) != 0)
+ goto out;
+ if (tdb_unlock_record(tdb, tl->off) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
+ goto out;
+ }
+ key.dsize = rec.key_len;
+ dbuf.dptr = key.dptr + rec.key_len;
+ dbuf.dsize = rec.data_len;
+
+ tdb_trace_1rec_retrec(tdb, "traverse", key, dbuf);
+
+ /* Drop chain lock, call out */
+ if (tdb_unlock(tdb, tl->list, tl->lock_rw) != 0) {
+ ret = -1;
+ goto out;
+ }
+ if (fn && fn(tdb, key, dbuf, private_data)) {
+ /* They want us to terminate traversal */
+ tdb_trace_ret(tdb, "tdb_traverse_end", count);
+ if (tdb_unlock_record(tdb, tl->off) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));;
+ ret = -1;
+ }
+ goto out;
+ }
+ }
+ tdb_trace(tdb, "tdb_traverse_end");
+out:
+ SAFE_FREE(key.dptr);
+ tdb->travlocks.next = tl->next;
+ if (ret < 0)
+ return -1;
+ else
+ return count;
+}
+
+
+/*
+ a read style traverse - temporarily marks each record read only
+*/
+_PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb,
+ tdb_traverse_func fn, void *private_data)
+{
+ struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK };
+ int ret;
+
+ tdb->traverse_read++;
+ tdb_trace(tdb, "tdb_traverse_read_start");
+ ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
+ tdb->traverse_read--;
+
+ return ret;
+}
+
+/*
+ a write style traverse - needs to get the transaction lock to
+ prevent deadlocks
+
+ WARNING: The data buffer given to the callback fn does NOT meet the
+ alignment guarantees malloc gives you.
+*/
+_PUBLIC_ int tdb_traverse(struct tdb_context *tdb,
+ tdb_traverse_func fn, void *private_data)
+{
+ struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
+ enum tdb_lock_flags lock_flags;
+ int ret;
+
+ if (tdb->read_only || tdb->traverse_read) {
+ return tdb_traverse_read(tdb, fn, private_data);
+ }
+
+ lock_flags = TDB_LOCK_WAIT;
+
+ if (tdb->allrecord_lock.count != 0) {
+ /*
+ * This avoids a deadlock between tdb_lockall() and
+ * tdb_traverse(). See
+ * https://bugzilla.samba.org/show_bug.cgi?id=11381
+ */
+ lock_flags = TDB_LOCK_NOWAIT;
+ }
+
+ if (tdb_transaction_lock(tdb, F_WRLCK, lock_flags)) {
+ return -1;
+ }
+
+ tdb->traverse_write++;
+ tdb_trace(tdb, "tdb_traverse_start");
+ ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
+ tdb->traverse_write--;
+
+ tdb_transaction_unlock(tdb, F_WRLCK);
+
+ return ret;
+}
+
+
+/* find the first entry in the database and return its key */
+_PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
+{
+ TDB_DATA key;
+ struct tdb_record rec;
+ tdb_off_t off;
+
+ /* release any old lock */
+ if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0)
+ return tdb_null;
+ tdb->travlocks.off = tdb->travlocks.list = 0;
+ tdb->travlocks.lock_rw = F_RDLCK;
+
+ /* Grab first record: locks chain and returned record. */
+ off = tdb_next_lock(tdb, &tdb->travlocks, &rec);
+ if (off == 0 || off == TDB_NEXT_LOCK_ERR) {
+ tdb_trace_retrec(tdb, "tdb_firstkey", tdb_null);
+ return tdb_null;
+ }
+ /* now read the key */
+ key.dsize = rec.key_len;
+ key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
+
+ tdb_trace_retrec(tdb, "tdb_firstkey", key);
+
+ /* Unlock the hash chain of the record we just read. */
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
+ return key;
+}
+
+/* find the next entry in the database, returning its key */
+_PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
+{
+ uint32_t oldlist;
+ TDB_DATA key = tdb_null;
+ struct tdb_record rec;
+ unsigned char *k = NULL;
+ tdb_off_t off;
+
+ /* Is locked key the old key? If so, traverse will be reliable. */
+ if (tdb->travlocks.off) {
+ if (tdb_lock(tdb,tdb->travlocks.list,tdb->travlocks.lock_rw))
+ return tdb_null;
+ if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1
+ || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
+ rec.key_len))
+ || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
+ /* No, it wasn't: unlock it and start from scratch */
+ if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) {
+ tdb_trace_1rec_retrec(tdb, "tdb_nextkey",
+ oldkey, tdb_null);
+ SAFE_FREE(k);
+ return tdb_null;
+ }
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0) {
+ SAFE_FREE(k);
+ return tdb_null;
+ }
+ tdb->travlocks.off = 0;
+ }
+
+ SAFE_FREE(k);
+ }
+
+ if (!tdb->travlocks.off) {
+ /* No previous element: do normal find, and lock record */
+ tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), tdb->travlocks.lock_rw, &rec);
+ if (!tdb->travlocks.off) {
+ tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, tdb_null);
+ return tdb_null;
+ }
+ tdb->travlocks.list = BUCKET(rec.full_hash);
+ if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
+ return tdb_null;
+ }
+ }
+ oldlist = tdb->travlocks.list;
+
+ /* Grab next record: locks chain and returned record,
+ unlocks old record */
+ off = tdb_next_lock(tdb, &tdb->travlocks, &rec);
+ if (off != TDB_NEXT_LOCK_ERR && off != 0) {
+ key.dsize = rec.key_len;
+ key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
+ key.dsize);
+ /* Unlock the chain of this new record */
+ if (tdb_unlock(tdb, tdb->travlocks.list, tdb->travlocks.lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+ }
+ /* Unlock the chain of old record */
+ if (tdb_unlock(tdb, oldlist, tdb->travlocks.lock_rw) != 0)
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+ tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, key);
+ return key;
+}
+
+_PUBLIC_ int tdb_traverse_chain(struct tdb_context *tdb,
+ unsigned chain,
+ tdb_traverse_func fn,
+ void *private_data)
+{
+ tdb_off_t rec_ptr;
+ struct tdb_chainwalk_ctx chainwalk;
+ int count = 0;
+ int ret;
+
+ if (chain >= tdb->hash_size) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ return -1;
+ }
+
+ if (tdb->traverse_read != 0) {
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+
+ ret = tdb_lock(tdb, chain, F_RDLCK);
+ if (ret == -1) {
+ return -1;
+ }
+
+ tdb->traverse_read += 1;
+
+ ret = tdb_ofs_read(tdb, TDB_HASH_TOP(chain), &rec_ptr);
+ if (ret == -1) {
+ goto fail;
+ }
+
+ tdb_chainwalk_init(&chainwalk, rec_ptr);
+
+ while (rec_ptr != 0) {
+ struct tdb_record rec;
+ bool ok;
+
+ ret = tdb_rec_read(tdb, rec_ptr, &rec);
+ if (ret == -1) {
+ goto fail;
+ }
+
+ if (!TDB_DEAD(&rec)) {
+ /* no overflow checks, tdb_rec_read checked it */
+ tdb_off_t key_ofs = rec_ptr + sizeof(rec);
+ size_t full_len = rec.key_len + rec.data_len;
+ uint8_t *buf = NULL;
+
+ TDB_DATA key = { .dsize = rec.key_len };
+ TDB_DATA data = { .dsize = rec.data_len };
+
+ if ((tdb->transaction == NULL) &&
+ (tdb->map_ptr != NULL)) {
+ ret = tdb_oob(tdb, key_ofs, full_len, 0);
+ if (ret == -1) {
+ goto fail;
+ }
+ key.dptr = (uint8_t *)tdb->map_ptr + key_ofs;
+ } else {
+ buf = tdb_alloc_read(tdb, key_ofs, full_len);
+ if (buf == NULL) {
+ goto fail;
+ }
+ key.dptr = buf;
+ }
+ data.dptr = key.dptr + key.dsize;
+
+ ret = fn(tdb, key, data, private_data);
+ free(buf);
+
+ count += 1;
+
+ if (ret != 0) {
+ break;
+ }
+ }
+
+ rec_ptr = rec.next;
+
+ ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
+ if (!ok) {
+ goto fail;
+ }
+ }
+ tdb->traverse_read -= 1;
+ tdb_unlock(tdb, chain, F_RDLCK);
+ return count;
+
+fail:
+ tdb->traverse_read -= 1;
+ tdb_unlock(tdb, chain, F_RDLCK);
+ return -1;
+}
+
+_PUBLIC_ int tdb_traverse_key_chain(struct tdb_context *tdb,
+ TDB_DATA key,
+ tdb_traverse_func fn,
+ void *private_data)
+{
+ uint32_t hash, chain;
+ int ret;
+
+ hash = tdb->hash_fn(&key);
+ chain = BUCKET(hash);
+ ret = tdb_traverse_chain(tdb, chain, fn, private_data);
+
+ return ret;
+}
diff --git a/lib/tdb/configure b/lib/tdb/configure
new file mode 100755
index 0000000..af76185
--- /dev/null
+++ b/lib/tdb/configure
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PREVPATH=$(dirname $0)
+
+if [ -f $PREVPATH/../../buildtools/bin/waf ]; then
+ WAF=../../buildtools/bin/waf
+elif [ -f $PREVPATH/buildtools/bin/waf ]; then
+ WAF=./buildtools/bin/waf
+else
+ echo "replace: Unable to find waf"
+ exit 1
+fi
+
+# using JOBS=1 gives maximum compatibility with
+# systems like AIX which have broken threading in python
+JOBS=1
+export JOBS
+
+# Make sure we don't have any library preloaded.
+unset LD_PRELOAD
+
+# Make sure we get stable hashes
+PYTHONHASHSEED=1
+export PYTHONHASHSEED
+
+cd . || exit 1
+$PYTHON $WAF configure "$@" || exit 1
+cd $PREVPATH
diff --git a/lib/tdb/docs/README b/lib/tdb/docs/README
new file mode 100644
index 0000000..86d46a3
--- /dev/null
+++ b/lib/tdb/docs/README
@@ -0,0 +1,273 @@
+tdb - a trivial database system
+tridge@linuxcare.com December 1999
+==================================
+
+This is a simple database API. It was inspired by the realisation that
+in Samba we have several ad-hoc bits of code that essentially
+implement small databases for sharing structures between parts of
+Samba. As I was about to add another I realised that a generic
+database module was called for to replace all the ad-hoc bits.
+
+I based the interface on gdbm. I couldn't use gdbm as we need to be
+able to have multiple writers to the databases at one time.
+
+Compilation
+-----------
+
+add HAVE_MMAP=1 to use mmap instead of read/write
+add NOLOCK=1 to disable locking code
+
+Testing
+-------
+
+Compile tdbtest.c and link with gdbm for testing. tdbtest will perform
+identical operations via tdb and gdbm then make sure the result is the
+same
+
+Also included is tdbtool, which allows simple database manipulation
+on the commandline.
+
+tdbtest and tdbtool are not built as part of Samba, but are included
+for completeness.
+
+Interface
+---------
+
+The interface is very similar to gdbm except for the following:
+
+- different open interface. The tdb_open call is more similar to a
+ traditional open()
+- no tdbm_reorganise() function
+- no tdbm_sync() function. No operations are cached in the library anyway
+- added a tdb_traverse() function for traversing the whole database
+- added transactions support
+
+A general rule for using tdb is that the caller frees any returned
+TDB_DATA structures. Just call free(p.dptr) to free a TDB_DATA
+return value called p. This is the same as gdbm.
+
+here is a full list of tdb functions with brief descriptions.
+
+
+----------------------------------------------------------------------
+TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+
+ open the database, creating it if necessary
+
+ The open_flags and mode are passed straight to the open call on the database
+ file. A flags value of O_WRONLY is invalid
+
+ The hash size is advisory, use zero for a default value.
+
+ return is NULL on error
+
+ possible tdb_flags are:
+ TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
+ TDB_INTERNAL - don't use a file, instead store the data in
+ memory. The filename is ignored in this case.
+ TDB_NOLOCK - don't do any locking
+ TDB_NOMMAP - don't use mmap
+ TDB_NOSYNC - don't synchronise transactions to disk
+ TDB_SEQNUM - maintain a sequence number
+ TDB_VOLATILE - activate the per-hashchain freelist, default 5
+ TDB_ALLOW_NESTING - allow transactions to nest
+ TDB_DISALLOW_NESTING - disallow transactions to nest
+
+----------------------------------------------------------------------
+TDB_CONTEXT *tdb_open_ex(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ const struct tdb_logging_context *log_ctx,
+ tdb_hash_func hash_fn)
+
+This is like tdb_open(), but allows you to pass an initial logging and
+hash function. Be careful when passing a hash function - all users of
+the database must use the same hash function or you will get data
+corruption.
+
+
+----------------------------------------------------------------------
+char *tdb_error(TDB_CONTEXT *tdb);
+
+ return a error string for the last tdb error
+
+----------------------------------------------------------------------
+int tdb_close(TDB_CONTEXT *tdb);
+
+ close a database
+
+----------------------------------------------------------------------
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ fetch an entry in the database given a key
+ if the return value has a null dptr then a error occurred
+
+ caller must free the resulting data
+
+----------------------------------------------------------------------
+int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+
+ Hand a record to a parser function without allocating it.
+
+ This function is meant as a fast tdb_fetch alternative for large records
+ that are frequently read. The "key" and "data" arguments point directly
+ into the tdb shared memory, they are not aligned at any boundary.
+
+ WARNING: The parser is called while tdb holds a lock on the record. DO NOT
+ call other tdb routines from within the parser. Also, for good performance
+ you should make the parser fast to allow parallel operations.
+
+ tdb_parse_record returns -1 if the record was not found. If the record was
+ found, the return value of "parser" is passed up to the caller.
+
+----------------------------------------------------------------------
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ check if an entry in the database exists
+
+ note that 1 is returned if the key is found and 0 is returned if not found
+ this doesn't match the conventions in the rest of this module, but is
+ compatible with gdbm
+
+----------------------------------------------------------------------
+int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
+ TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
+
+ traverse the entire database - calling fn(tdb, key, data, state) on each
+ element.
+
+ return -1 on error or the record count traversed
+
+ if fn is NULL then it is not called
+
+ a non-zero return value from fn() indicates that the traversal
+ should stop. Traversal callbacks may not start transactions.
+
+ WARNING: The data buffer given to the callback fn does NOT meet the
+ alignment restrictions malloc gives you.
+
+----------------------------------------------------------------------
+int tdb_traverse_read(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
+ TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
+
+ traverse the entire database - calling fn(tdb, key, data, state) on
+ each element, but marking the database read only during the
+ traversal, so any write operations will fail. This allows tdb to
+ use read locks, which increases the parallelism possible during the
+ traversal.
+
+ return -1 on error or the record count traversed
+
+ if fn is NULL then it is not called
+
+ a non-zero return value from fn() indicates that the traversal
+ should stop. Traversal callbacks may not start transactions.
+
+----------------------------------------------------------------------
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+
+ find the first entry in the database and return its key
+
+ the caller must free the returned data
+
+----------------------------------------------------------------------
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ find the next entry in the database, returning its key
+
+ the caller must free the returned data
+
+----------------------------------------------------------------------
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ delete an entry in the database given a key
+
+----------------------------------------------------------------------
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+
+ store an element in the database, replacing any existing element
+ with the same key
+
+ If flag==TDB_INSERT then don't overwrite an existing entry
+ If flag==TDB_MODIFY then don't create a new entry
+
+ return 0 on success, -1 on failure
+
+----------------------------------------------------------------------
+int tdb_writelock(TDB_CONTEXT *tdb);
+
+ lock the database. If we already have it locked then don't do anything
+
+----------------------------------------------------------------------
+int tdb_writeunlock(TDB_CONTEXT *tdb);
+ unlock the database
+
+----------------------------------------------------------------------
+int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ lock one hash chain. This is meant to be used to reduce locking
+ contention - it cannot guarantee how many records will be locked
+
+----------------------------------------------------------------------
+int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
+
+ unlock one hash chain
+
+----------------------------------------------------------------------
+int tdb_transaction_start(TDB_CONTEXT *tdb)
+
+ start a transaction. All operations after the transaction start can
+ either be committed with tdb_transaction_commit() or cancelled with
+ tdb_transaction_cancel().
+
+ If you call tdb_transaction_start() again on the same tdb context
+ while a transaction is in progress, then the same transaction
+ buffer is re-used. The number of tdb_transaction_{commit,cancel}
+ operations must match the number of successful
+ tdb_transaction_start() calls.
+
+ Note that transactions are by default disk synchronous, and use a
+ recover area in the database to automatically recover the database
+ on the next open if the system crashes during a transaction. You
+ can disable the synchronous transaction recovery setup using the
+ TDB_NOSYNC flag, which will greatly speed up operations at the risk
+ of corrupting your database if the system crashes.
+
+ Operations made within a transaction are not visible to other users
+ of the database until a successful commit.
+
+----------------------------------------------------------------------
+int tdb_transaction_cancel(TDB_CONTEXT *tdb)
+
+ cancel a current transaction, discarding all write and lock
+ operations that have been made since the transaction started.
+
+
+----------------------------------------------------------------------
+int tdb_transaction_commit(TDB_CONTEXT *tdb)
+
+ commit a current transaction, updating the database and releasing
+ the transaction locks.
+
+----------------------------------------------------------------------
+int tdb_transaction_prepare_commit(TDB_CONTEXT *tdb)
+
+ prepare to commit a current transaction, for two-phase commits.
+ Once prepared for commit, the only allowed calls are
+ tdb_transaction_commit() or tdb_transaction_cancel(). Preparing
+ allocates disk space for the pending updates, so a subsequent
+ commit should succeed (barring any hardware failures).
+
+----------------------------------------------------------------------
+int tdb_check(TDB_CONTEXT *tdb,
+ int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
+ void *private_data);)
+
+ check the consistency of the database, calling back the check function
+ (if non-NULL) with each record. If some consistency check fails, or
+ the supplied check function returns -1, tdb_check returns -1, otherwise
+ 0. Note that logging function (if set) will be called with additional
+ information on the corruption found.
diff --git a/lib/tdb/docs/mainpage.dox b/lib/tdb/docs/mainpage.dox
new file mode 100644
index 0000000..d130769
--- /dev/null
+++ b/lib/tdb/docs/mainpage.dox
@@ -0,0 +1,61 @@
+/**
+
+@mainpage
+
+This is a simple database API. It was inspired by the realisation that in Samba
+we have several ad-hoc bits of code that essentially implement small databases
+for sharing structures between parts of Samba.
+
+The interface is based on gdbm. gdbm couldn't be use as we needed to be able to
+have multiple writers to the databases at one time.
+
+@section tdb_download Download
+
+You can download the latest releases of tdb from the
+<a href="http://samba.org/ftp/tdb">tdb directory</a> on the samba public source
+archive.
+
+You can download the latest code either via git or rsync.
+
+To fetch via git see the following guide:
+
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a>
+Once you have cloned the tree switch to the master branch and cd into the source/lib/tdb directory.
+
+To fetch via rsync use these commands:
+
+<pre>
+ rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/tdb .
+ rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/replace .
+</pre>
+
+and build in tdb. It will find the replace library in the directory above
+automatically.
+
+@section tdb_bugs Discussion and bug reports
+
+tdb does not currently have its own mailing list or bug tracking system. For now,
+please use the
+<a href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba bugzilla</a> bug
+tracking system.
+
+
+@section tdb_compilation Compilation
+
+add HAVE_MMAP=1 to use mmap instead of read/write
+add NOLOCK=1 to disable locking code
+
+@section tdb_testing Testing
+
+Compile tdbtest.c and link with gdbm for testing. tdbtest will perform
+identical operations via tdb and gdbm then make sure the result is the
+same
+
+Also included is tdbtool, which allows simple database manipulation
+on the commandline.
+
+tdbtest and tdbtool are not built as part of Samba, but are included
+for completeness.
+
+*/
diff --git a/lib/tdb/docs/mutex.txt b/lib/tdb/docs/mutex.txt
new file mode 100644
index 0000000..0003c7f
--- /dev/null
+++ b/lib/tdb/docs/mutex.txt
@@ -0,0 +1,136 @@
+Tdb is a hashtable database with multiple concurrent writer and external
+record lock support. For speed reasons, wherever possible tdb uses a shared
+memory mapped area for data access. In its currently released form, it uses
+fcntl byte-range locks to coordinate access to the data itself.
+
+The tdb data is organized as a hashtable. Hash collisions are dealt with by
+forming a linked list of records that share a hash value. The individual
+linked lists are protected across processes with 1-byte fcntl locks on the
+starting pointer of the linked list representing a hash value.
+
+The external locking API of tdb allows one to lock individual records. Instead of
+really locking individual records, the tdb API locks a complete linked list
+with a fcntl lock.
+
+The external locking API of tdb also allows one to lock the complete database, and
+ctdb uses this facility to freeze databases during a recovery. While the
+so-called allrecord lock is held, all linked lists and all individual records
+are frozen altogether. Tdb achieves this by locking the complete file range
+with a single fcntl lock. Individual 1-byte locks for the linked lists
+conflict with this. Access to records is prevented by the one large fnctl byte
+range lock.
+
+Fcntl locks have been chosen for tdb for two reasons: First they are portable
+across all current unixes. Secondly they provide auto-cleanup. If a process
+dies while holding a fcntl lock, the lock is given up as if it was explicitly
+unlocked. Thus fcntl locks provide a very robust locking scheme, if a process
+dies for any reason the database will not stay blocked until reboot. This
+robustness is very important for long-running services, a reboot is not an
+option for most users of tdb.
+
+Unfortunately, during stress testing, fcntl locks have turned out to be a major
+problem for performance. The particular problem that was seen happens when
+ctdb on a busy server does a recovery. A recovery means that ctdb has to
+freeze all tdb databases for some time, usually a few seconds. This is done
+with the allrecord lock. During the recovery phase on a busy server many smbd
+processes try to access the tdb file with blocking fcntl calls. The specific
+test in question easily reproduces 7,000 processes piling up waiting for
+1-byte fcntl locks. When ctdb is done with the recovery, it gives up the
+allrecord lock, covering the whole file range. All 7,000 processes waiting for
+1-byte fcntl locks are woken up, trying to acquire their lock. The special
+implementation of fcntl locks in Linux (up to 2013-02-12 at least) protects
+all fcntl lock operations with a single system-wide spinlock. If 7,000 process
+waiting for the allrecord lock to become released this leads to a thundering
+herd condition, all CPUs are spinning on that single spinlock.
+
+Functionally the kernel is fine, eventually the thundering herd slows down and
+every process correctly gets his share and locking range, but the performance
+of the system while the herd is active is worse than expected.
+
+The thundering herd is only the worst case scenario for fcntl lock use. The
+single spinlock for fcntl operations is also a performance penalty for normal
+operations. In the cluster case, every read and write SMB request has to do
+two fcntl calls to provide correct SMB mandatory locks. The single spinlock
+is one source of serialization for the SMB read/write requests, limiting the
+parallelism that can be achieved in a multi-core system.
+
+While trying to tune his servers, Ira Cooper, Samba Team member, found fcntl
+locks to be a problem on Solaris as well. Ira pointed out that there is a
+potential alternative locking mechanism that might be more scalable: Process
+shared robust mutexes, as defined by Posix 2008 for example via
+
+http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setpshared.html
+http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html
+
+Pthread mutexes provide one of the core mechanisms in posix threads to protect
+in-process data structures from concurrent access by multiple threads. In the
+Linux implementation, a pthread_mutex_t is represented by a data structure in
+user space that requires no kernel calls in the uncontended case for locking
+and unlocking. Locking and unlocking in the uncontended case is implemented
+purely in user space with atomic CPU instructions and thus are very fast.
+
+The setpshared functions indicate to the kernel that the mutex is about to be
+shared between processes in a common shared memory area.
+
+The process shared posix mutexes have the potential to replace fcntl locking
+to coordinate mmap access for tdbs. However, they are missing the critical
+auto-cleanup property that fcntl provides when a process dies. A process that
+dies hard while holding a shared mutex has no chance to clean up the protected
+data structures and unlock the shared mutex. Thus with a pure process shared
+mutex the mutex will remain locked forever until the data structures are
+re-initialized from scratch.
+
+With the robust mutexes defined by Posix the process shared mutexes have been
+extended with a limited auto-cleanup property. If a mutex has been declared
+robust, when a process exits while holding that mutex, the next process trying
+to lock the mutex will get the special error message EOWNERDEAD. This informs
+the caller that the data structures the mutex protects are potentially corrupt
+and need to be cleaned up.
+
+The error message EOWNERDEAD when trying to lock a mutex is an extension over
+the fcntl functionality. A process that does a blocking fcntl lock call is not
+informed about whether the lock was explicitly freed by a process still alive
+or due to an unplanned process exit. At the time of this writing (February
+2013), at least Linux and OpenSolaris also implement the robustness feature of
+process-shared mutexes.
+
+Converting the tdb locking mechanism from fcntl to mutexes has to take care of
+both types of locks that are used on tdb files.
+
+The easy part is to use mutexes to replace the 1-byte linked list locks
+covering the individual hashes. Those can be represented by a mutex each.
+
+Covering the allrecord lock is more difficult. The allrecord lock uses a fcntl
+lock spanning all hash list locks simultaneously. This basic functionality is
+not easily possible with mutexes. A mutex carries 1 bit of information, a
+fcntl lock can carry an arbitrary amount of information.
+
+In order to support the allrecord lock, we have an allrecord_lock variable
+protected by an allrecord_mutex. The coordination between the allrecord lock
+and the chainlocks works like this:
+
+- Getting a chain lock works like this:
+
+ 1. get chain mutex
+ 2. return success if allrecord_lock is F_UNLCK (not locked)
+ 3. return success if allrecord_lock is F_RDLCK (locked readonly)
+ and we only need a read lock.
+ 4. release chain mutex
+ 5. wait for allrecord_mutex
+ 6. unlock allrecord_mutex
+ 7. goto 1.
+
+- Getting the allrecord lock:
+
+ 1. get the allrecord mutex
+ 2. return error if allrecord_lock is not F_UNLCK (it's locked)
+ 3. set allrecord_lock to the desired value.
+ 4. in a loop: lock(blocking) / unlock each chain mutex.
+ 5. return success.
+
+- allrecord lock upgrade:
+
+ 1. check we already have the allrecord lock with F_RDLCK.
+ 3. set allrecord_lock to F_WRLCK
+ 4. in a loop: lock(blocking) / unlock each chain mutex.
+ 5. return success.
diff --git a/lib/tdb/docs/tdb.magic b/lib/tdb/docs/tdb.magic
new file mode 100644
index 0000000..f5619e7
--- /dev/null
+++ b/lib/tdb/docs/tdb.magic
@@ -0,0 +1,10 @@
+# Magic file(1) information about tdb files.
+#
+# Install this into /etc/magic or the corresponding location for your
+# system, or pass as a -m argument to file(1).
+
+# You may use and redistribute this file without restriction.
+
+0 string TDB\ file TDB database
+>32 lelong =0x2601196D version 6, little-endian
+>>36 lelong x hash size %d bytes
diff --git a/lib/tdb/docs/tracing.txt b/lib/tdb/docs/tracing.txt
new file mode 100644
index 0000000..a7657ff
--- /dev/null
+++ b/lib/tdb/docs/tracing.txt
@@ -0,0 +1,46 @@
+How And Why To Use TDB Tracing
+==============================
+
+You can trace all TDB operations, using TDB_TRACE. It is not complete
+(error conditions which expect to the logged will not always be traced
+correctly, so you should set up a logging function too), but is designed
+to collect benchmark-style traces to allow us to optimize TDB.
+
+Note: tracing is not efficient, and the trace files are huge: a
+traverse of the database is particularly large! But they compress very
+well with rzip (http://rzip.samba.org)
+
+How to gather trace files:
+--------------------------
+1) Uncomment /* #define TDB_TRACE 1 */ in tdb_private.h.
+2) Rebuild TDB, and everything that uses it.
+3) Run something.
+
+Your trace files will be called <tdbname>.trace.<pid>. These files
+will not be overwritten: if the same process reopens the same TDB, an
+error will be logged and tracing will be disabled.
+
+How to replay trace files:
+--------------------------
+1) For benchmarking, remember to rebuild tdb with #define TDB_TRACE commented
+ out again!
+2) Grab the latest "replace_trace.c" from CCAN's tdb module (tools/ dir):
+ http://ccan.ozlabs.org/tarballs/tdb.tar.bz2
+3) Compile up replay_trace, munging as necessary.
+4) Run replay_trace <scratch-tdb-name> <tracefiles>...
+
+If given more than one trace file (presumably from the same tdb)
+replay_trace will try to figure out the dependencies between the operations
+and fire off a child to run each trace. Occasionally it gets stuck, in
+which case it will add another dependency and retry. Eventually it will
+give a speed value.
+
+replay_trace can intuit the existence of previous data in the tdb (ie.
+activity prior to the trace(s) supplied) and will prepopulate as
+necessary.
+
+You can run --quiet for straight benchmark results, and -n to run multiple
+times (this saves time, since it need only calculate dependencies once).
+
+Good luck!
+Rusty Russell <rusty@rustcorp.com.au>
diff --git a/lib/tdb/doxy.config b/lib/tdb/doxy.config
new file mode 100644
index 0000000..f55e9c3
--- /dev/null
+++ b/lib/tdb/doxy.config
@@ -0,0 +1,1697 @@
+# Doxyfile 1.7.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = tdb
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 1.2.9
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description for a project that appears at the top of each page and should give viewer a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = include \
+ docs
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS = *.cpp \
+ *.cc \
+ *.c \
+ *.h \
+ *.hh \
+ *.hpp \
+ *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */.git/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [0,1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+# Note that a value of 0 will completely suppress the enum values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NONE
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN \
+ PRINTF_ATTRIBUTE(x,y)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, svg, gif or svg.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/lib/tdb/include/tdb.h b/lib/tdb/include/tdb.h
new file mode 100644
index 0000000..884171c
--- /dev/null
+++ b/lib/tdb/include/tdb.h
@@ -0,0 +1,1038 @@
+#ifndef __TDB_H__
+#define __TDB_H__
+
+/*
+ Unix SMB/CIFS implementation.
+
+ trivial database library
+
+ Copyright (C) Andrew Tridgell 1999-2004
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <signal.h>
+#include <stdbool.h>
+
+/* for old gcc releases that don't have the feature test macro __has_attribute */
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef _PUBLIC_
+#if __has_attribute(visibility)
+#define _PUBLIC_ __attribute__((visibility("default")))
+#else
+#define _PUBLIC_
+#endif
+#endif
+
+/**
+ * @defgroup tdb The tdb API
+ *
+ * tdb is a Trivial database. In concept, it is very much like GDBM, and BSD's
+ * DB except that it allows multiple simultaneous writers and uses locking
+ * internally to keep writers from trampling on each other. tdb is also
+ * extremely small.
+ *
+ * @section tdb_interface Interface
+ *
+ * The interface is very similar to gdbm except for the following:
+ *
+ * <ul>
+ * <li>different open interface. The tdb_open call is more similar to a
+ * traditional open()</li>
+ * <li>no tdbm_reorganise() function</li>
+ * <li>no tdbm_sync() function. No operations are cached in the library
+ * anyway</li>
+ * <li>added a tdb_traverse() function for traversing the whole database</li>
+ * <li>added transactions support</li>
+ * </ul>
+ *
+ * A general rule for using tdb is that the caller frees any returned TDB_DATA
+ * structures. Just call free(p.dptr) to free a TDB_DATA return value called p.
+ * This is the same as gdbm.
+ *
+ * @{
+ */
+
+/** Flags to tdb_store() */
+#define TDB_REPLACE 1 /** Unused */
+#define TDB_INSERT 2 /** Don't overwrite an existing entry */
+#define TDB_MODIFY 3 /** Don't create an existing entry */
+
+/** Flags for tdb_open() */
+#define TDB_DEFAULT 0 /** just a readability place holder */
+#define TDB_CLEAR_IF_FIRST 1 /** If this is the first open, wipe the db */
+#define TDB_INTERNAL 2 /** Don't store on disk */
+#define TDB_NOLOCK 4 /** Don't do any locking */
+#define TDB_NOMMAP 8 /** Don't use mmap */
+#define TDB_CONVERT 16 /** Convert endian (internal use) */
+#define TDB_BIGENDIAN 32 /** Header is big-endian (internal use) */
+#define TDB_NOSYNC 64 /** Don't use synchronous transactions */
+#define TDB_SEQNUM 128 /** Maintain a sequence number */
+#define TDB_VOLATILE 256 /** Activate the per-hashchain freelist, default 5 */
+#define TDB_ALLOW_NESTING 512 /** Allow transactions to nest */
+#define TDB_DISALLOW_NESTING 1024 /** Disallow transactions to nest */
+#define TDB_INCOMPATIBLE_HASH 2048 /** Better hashing: can't be opened by tdb < 1.2.6. */
+#define TDB_MUTEX_LOCKING 4096 /** optimized locking using robust mutexes if supported,
+ only with tdb >= 1.3.0 and TDB_CLEAR_IF_FIRST
+ after checking tdb_runtime_check_for_robust_mutexes() */
+
+/** The tdb error codes */
+enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
+ TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
+ TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY,
+ TDB_ERR_NESTING};
+
+/** Debugging uses one of the following levels */
+enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR,
+ TDB_DEBUG_WARNING, TDB_DEBUG_TRACE};
+
+/** The tdb data structure */
+typedef struct TDB_DATA {
+ unsigned char *dptr;
+ size_t dsize;
+} TDB_DATA;
+
+#ifndef PRINTF_ATTRIBUTE
+#if __has_attribute(format) || (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+/** This is the context structure that is returned from a db open. */
+typedef struct tdb_context TDB_CONTEXT;
+
+typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *);
+typedef void (*tdb_log_func)(struct tdb_context *, enum tdb_debug_level, const char *, ...) PRINTF_ATTRIBUTE(3, 4);
+typedef unsigned int (*tdb_hash_func)(TDB_DATA *key);
+
+struct tdb_logging_context {
+ tdb_log_func log_fn;
+ void *log_private;
+};
+
+/**
+ * @brief Open the database and creating it if necessary.
+ *
+ * @param[in] name The name of the db to open.
+ *
+ * @param[in] hash_size The hash size is advisory, use zero for a default
+ * value.
+ *
+ * @param[in] tdb_flags The flags to use to open the db:\n\n
+ * TDB_CLEAR_IF_FIRST - Clear database if we are the
+ * only one with it open\n
+ * TDB_INTERNAL - Don't use a file, instead store the
+ * data in memory. The filename is
+ * ignored in this case.\n
+ * TDB_NOLOCK - Don't do any locking\n
+ * TDB_NOMMAP - Don't use mmap\n
+ * TDB_NOSYNC - Don't synchronise transactions to disk\n
+ * TDB_SEQNUM - Maintain a sequence number\n
+ * TDB_VOLATILE - activate the per-hashchain freelist,
+ * default 5.\n
+ * TDB_ALLOW_NESTING - Allow transactions to nest.\n
+ * TDB_DISALLOW_NESTING - Disallow transactions to nest.\n
+ * TDB_INCOMPATIBLE_HASH - Better hashing: can't be opened by tdb < 1.2.6.\n
+ * TDB_MUTEX_LOCKING - Optimized locking using robust mutexes if supported,
+ * can't be opened by tdb < 1.3.0.
+ * Only valid in combination with TDB_CLEAR_IF_FIRST
+ * after checking tdb_runtime_check_for_robust_mutexes()\n
+ *
+ * @param[in] open_flags Flags for the open(2) function.
+ *
+ * @param[in] mode The mode for the open(2) function.
+ *
+ * @return A tdb context structure, NULL on error.
+ */
+_PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+
+/**
+ * @brief Open the database and creating it if necessary.
+ *
+ * This is like tdb_open(), but allows you to pass an initial logging and
+ * hash function. Be careful when passing a hash function - all users of the
+ * database must use the same hash function or you will get data corruption.
+ *
+ * @param[in] name The name of the db to open.
+ *
+ * @param[in] hash_size The hash size is advisory, use zero for a default
+ * value.
+ *
+ * @param[in] tdb_flags The flags to use to open the db:\n\n
+ * TDB_CLEAR_IF_FIRST - Clear database if we are the
+ * only one with it open\n
+ * TDB_INTERNAL - Don't use a file, instead store the
+ * data in memory. The filename is
+ * ignored in this case.\n
+ * TDB_NOLOCK - Don't do any locking\n
+ * TDB_NOMMAP - Don't use mmap\n
+ * TDB_NOSYNC - Don't synchronise transactions to disk\n
+ * TDB_SEQNUM - Maintain a sequence number\n
+ * TDB_VOLATILE - activate the per-hashchain freelist,
+ * default 5.\n
+ * TDB_ALLOW_NESTING - Allow transactions to nest.\n
+ * TDB_DISALLOW_NESTING - Disallow transactions to nest.\n
+ * TDB_INCOMPATIBLE_HASH - Better hashing: can't be opened by tdb < 1.2.6.\n
+ * TDB_MUTEX_LOCKING - Optimized locking using robust mutexes if supported,
+ * can't be opened by tdb < 1.3.0.
+ * Only valid in combination with TDB_CLEAR_IF_FIRST
+ * after checking tdb_runtime_check_for_robust_mutexes()\n
+ *
+ * @param[in] open_flags Flags for the open(2) function.
+ *
+ * @param[in] mode The mode for the open(2) function.
+ *
+ * @param[in] log_ctx The logging function to use.
+ *
+ * @param[in] hash_fn The hash function you want to use.
+ *
+ * @return A tdb context structure, NULL on error.
+ *
+ * @see tdb_open()
+ */
+_PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ const struct tdb_logging_context *log_ctx,
+ tdb_hash_func hash_fn);
+
+/**
+ * @brief Set the maximum number of dead records per hash chain.
+ *
+ * @param[in] tdb The database handle to set the maximum.
+ *
+ * @param[in] max_dead The maximum number of dead records per hash chain.
+ */
+_PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead);
+
+/**
+ * @brief Reopen a tdb.
+ *
+ * This can be used after a fork to ensure that we have an independent seek
+ * pointer from our parent and to re-establish locks.
+ *
+ * @param[in] tdb The database to reopen. It will be free'd on error!
+ *
+ * @return 0 on success, -1 on error.
+ *
+ * @note Don't call tdb_error() after this function cause the tdb context will
+ * be freed on error.
+ */
+_PUBLIC_ int tdb_reopen(struct tdb_context *tdb);
+
+/**
+ * @brief Reopen all tdb's
+ *
+ * If the parent is longlived (ie. a parent daemon architecture), we know it
+ * will keep it's active lock on a tdb opened with CLEAR_IF_FIRST. Thus for
+ * child processes we don't have to add an active lock. This is essential to
+ * improve performance on systems that keep POSIX locks as a non-scalable data
+ * structure in the kernel.
+ *
+ * @param[in] parent_longlived Whether the parent is longlived or not.
+ *
+ * @return 0 on success, -1 on error.
+ */
+_PUBLIC_ int tdb_reopen_all(int parent_longlived);
+
+/**
+ * @brief Set a different tdb logging function.
+ *
+ * @param[in] tdb The tdb to set the logging function.
+ *
+ * @param[in] log_ctx The logging function to set.
+ */
+_PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx);
+
+/**
+ * @brief Get the tdb last error code.
+ *
+ * @param[in] tdb The tdb to get the error code from.
+ *
+ * @return A TDB_ERROR code.
+ *
+ * @see TDB_ERROR
+ */
+_PUBLIC_ enum TDB_ERROR tdb_error(struct tdb_context *tdb);
+
+/**
+ * @brief Get a error string for the last tdb error
+ *
+ * @param[in] tdb The tdb to get the error code from.
+ *
+ * @return An error string.
+ */
+_PUBLIC_ const char *tdb_errorstr(struct tdb_context *tdb);
+
+/**
+ * @brief Fetch an entry in the database given a key.
+ *
+ * The caller must free the resulting data.
+ *
+ * @param[in] tdb The tdb to fetch the key.
+ *
+ * @param[in] key The key to fetch.
+ *
+ * @return The key entry found in the database, NULL on error with
+ * TDB_ERROR set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
+
+/**
+ * @brief Hand a record to a parser function without allocating it.
+ *
+ * This function is meant as a fast tdb_fetch alternative for large records
+ * that are frequently read. The "key" and "data" arguments point directly
+ * into the tdb shared memory, they are not aligned at any boundary.
+ *
+ * @warning The parser is called while tdb holds a lock on the record. DO NOT
+ * call other tdb routines from within the parser. Also, for good performance
+ * you should make the parser fast to allow parallel operations.
+ *
+ * @param[in] tdb The tdb to parse the record.
+ *
+ * @param[in] key The key to parse.
+ *
+ * @param[in] parser The parser to use to parse the data.
+ *
+ * @param[in] private_data A private data pointer which is passed to the parser
+ * function.
+ *
+ * @return -1 if the record was not found. If the record was found,
+ * the return value of "parser" is passed up to the caller.
+ */
+_PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
+ int (*parser)(TDB_DATA key, TDB_DATA data,
+ void *private_data),
+ void *private_data);
+
+/**
+ * @brief Delete an entry in the database given a key.
+ *
+ * @param[in] tdb The tdb to delete the key.
+ *
+ * @param[in] key The key to delete.
+ *
+ * @return 0 on success, -1 if the key doesn't exist.
+ */
+_PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key);
+
+/**
+ * @brief Store an element in the database.
+ *
+ * This replaces any existing element with the same key.
+ *
+ * @param[in] tdb The tdb to store the entry.
+ *
+ * @param[in] key The key to use to store the entry.
+ *
+ * @param[in] dbuf The data to store under the key.
+ *
+ * @param[in] flag The flags to store the key:\n\n
+ * TDB_INSERT: Don't overwrite an existing entry.\n
+ * TDB_MODIFY: Don't create a new entry\n
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+
+
+/**
+ * @brief Store an element in the database.
+ *
+ * This replaces any existing element with the same key.
+ *
+ * @param[in] tdb The tdb to store the entry.
+ *
+ * @param[in] key The key to use to store the entry.
+ *
+ * @param[in] dbufs A vector of memory chunks to write
+ *
+ * @param[in] num_dbufs Length of the dbufs vector
+ *
+ * @param[in] flag The flags to store the key:\n\n
+ * TDB_INSERT: Don't overwrite an existing entry.\n
+ * TDB_MODIFY: Don't create a new entry\n
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_storev(struct tdb_context *tdb, TDB_DATA key,
+ const TDB_DATA *dbufs, int num_dbufs, int flag);
+
+/**
+ * @brief Append data to an entry.
+ *
+ * If the entry doesn't exist, it will create a new one.
+ *
+ * @param[in] tdb The database to use.
+ *
+ * @param[in] key The key to append the data.
+ *
+ * @param[in] new_dbuf The data to append to the key.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf);
+
+/**
+ * @brief Close a database.
+ *
+ * @param[in] tdb The database to close. The context will be free'd.
+ *
+ * @return 0 for success, -1 on error.
+ *
+ * @note Don't call tdb_error() after this function cause the tdb context will
+ * be freed on error.
+ */
+_PUBLIC_ int tdb_close(struct tdb_context *tdb);
+
+/**
+ * @brief Find the first entry in the database and return its key.
+ *
+ * The caller must free the returned data.
+ *
+ * @param[in] tdb The database to use.
+ *
+ * @return The first entry of the database, an empty TDB_DATA entry
+ * if the database is empty.
+ */
+_PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb);
+
+/**
+ * @brief Find the next entry in the database, returning its key.
+ *
+ * The caller must free the returned data.
+ *
+ * @param[in] tdb The database to use.
+ *
+ * @param[in] key The key from which you want the next key.
+ *
+ * @return The next entry of the current key, an empty TDB_DATA
+ * entry if there is no entry.
+ */
+_PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key);
+
+/**
+ * @brief Traverse the entire database.
+ *
+ * While traversing the function fn(tdb, key, data, state) is called on each
+ * element. If fn is NULL then it is not called. A non-zero return value from
+ * fn() indicates that the traversal should stop. Traversal callbacks may not
+ * start transactions.
+ *
+ * @warning The data buffer given to the callback fn does NOT meet the alignment
+ * restrictions malloc gives you.
+ *
+ * @param[in] tdb The database to traverse.
+ *
+ * @param[in] fn The function to call on each entry.
+ *
+ * @param[in] private_data The private data which should be passed to the
+ * traversing function.
+ *
+ * @return The record count traversed, -1 on error.
+ */
+_PUBLIC_ int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *private_data);
+
+/**
+ * @brief Traverse the entire database.
+ *
+ * While traversing the database the function fn(tdb, key, data, state) is
+ * called on each element, but marking the database read only during the
+ * traversal, so any write operations will fail. This allows tdb to use read
+ * locks, which increases the parallelism possible during the traversal.
+ *
+ * @param[in] tdb The database to traverse.
+ *
+ * @param[in] fn The function to call on each entry.
+ *
+ * @param[in] private_data The private data which should be passed to the
+ * traversing function.
+ *
+ * @return The record count traversed, -1 on error.
+ */
+_PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *private_data);
+
+/**
+ * @brief Traverse a single hash chain
+ *
+ * Traverse a single hash chain under a single lock operation. No
+ * database modification is possible in the callback.
+ *
+ * This exists for background cleanup of databases. In normal
+ * operations, traversing a complete database can be much too
+ * expensive. Databases can have many chains, which will all have to
+ * be looked at before tdb_traverse finishes. Also tdb_traverse does a
+ * lot of fcntl activity to protect against concurrent record deletes.
+ *
+ * With this you can walk a fraction of the whole tdb, collect the
+ * entries you want to prune, leave the traverse, and then modify or
+ * delete the records in a subsequent step.
+ *
+ * To walk the entire database, call this function tdb_hash_size()
+ * times, with 0<=chain<tdb_hash_size(tdb).
+ *
+ * @param[in] tdb The database to traverse.
+ *
+ * @param[in] chain The hash chain number to traverse.
+ *
+ * @param[in] fn The function to call on each entry.
+ *
+ * @param[in] private_data The private data which should be passed to the
+ * traversing function.
+ *
+ * @return The record count traversed, -1 on error.
+ */
+
+_PUBLIC_ int tdb_traverse_chain(struct tdb_context *tdb,
+ unsigned chain,
+ tdb_traverse_func fn,
+ void *private_data);
+
+/**
+ * @brief Traverse a single hash chain
+ *
+ * This is like tdb_traverse_chain(), but for all records that are in
+ * the same chain as the record corresponding to the key parameter.
+ *
+ * Use it for ongoing database maintenance under a lock. Whenever you
+ * are about to modify a database, you know which record you are going
+ * to write to. For that tdb_store(), an exclusive chainlock is taken
+ * behind the scenes. To utilize this exclusive lock for incremental
+ * database cleanup as well, tdb_chainlock() the key you are about to
+ * modify, then tdb_traverse_key_chain() to do the incremental
+ * maintenance, modify your record and tdb_chainunlock() the key
+ * again.
+ *
+ * @param[in] tdb The database to traverse.
+ *
+ * @param[in] key The record key to walk the chain for.
+ *
+ * @param[in] fn The function to call on each entry.
+ *
+ * @param[in] private_data The private data which should be passed to the
+ * traversing function.
+ *
+ * @return The record count traversed, -1 on error.
+ */
+
+_PUBLIC_ int tdb_traverse_key_chain(struct tdb_context *tdb,
+ TDB_DATA key,
+ tdb_traverse_func fn,
+ void *private_data);
+/**
+ * @brief Check if an entry in the database exists.
+ *
+ * @note 1 is returned if the key is found and 0 is returned if not found this
+ * doesn't match the conventions in the rest of this module, but is compatible
+ * with gdbm.
+ *
+ * @param[in] tdb The database to check if the entry exists.
+ *
+ * @param[in] key The key to check if the entry exists.
+ *
+ * @return 1 if the key is found, 0 if not.
+ */
+_PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
+
+/**
+ * @brief Lock entire database with a write lock.
+ *
+ * @param[in] tdb The database to lock.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_lockall(struct tdb_context *tdb);
+
+/**
+ * @brief Lock entire database with a write lock.
+ *
+ * This is the non-blocking call.
+ *
+ * @param[in] tdb The database to lock.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_lockall()
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_lockall_nonblock(struct tdb_context *tdb);
+
+/**
+ * @brief Unlock entire database with write lock.
+ *
+ * @param[in] tdb The database to unlock.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_lockall()
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_unlockall(struct tdb_context *tdb);
+
+/**
+ * @brief Lock entire database with a read lock.
+ *
+ * @param[in] tdb The database to lock.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb);
+
+/**
+ * @brief Lock entire database with a read lock.
+ *
+ * This is the non-blocking call.
+ *
+ * @param[in] tdb The database to lock.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_lockall_read()
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb);
+
+/**
+ * @brief Unlock entire database with read lock.
+ *
+ * @param[in] tdb The database to unlock.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_lockall_read()
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb);
+
+/**
+ * @brief Lock entire database with write lock - mark only.
+ *
+ * @todo Add more details.
+ *
+ * @param[in] tdb The database to mark.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb);
+
+/**
+ * @brief Lock entire database with write lock - unmark only.
+ *
+ * @todo Add more details.
+ *
+ * @param[in] tdb The database to mark.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb);
+
+/**
+ * @brief Get the name of the current tdb file.
+ *
+ * This is useful for external logging functions.
+ *
+ * @param[in] tdb The database to get the name from.
+ *
+ * @return The name of the database.
+ */
+_PUBLIC_ const char *tdb_name(struct tdb_context *tdb);
+
+/**
+ * @brief Get the underlying file descriptor being used by tdb.
+ *
+ * This is useful for external routines that want to check the device/inode
+ * of the fd.
+ *
+ * @param[in] tdb The database to get the fd from.
+ *
+ * @return The file descriptor or -1.
+ */
+_PUBLIC_ int tdb_fd(struct tdb_context *tdb);
+
+/**
+ * @brief Get the current logging function.
+ *
+ * This is useful for external tdb routines that wish to log tdb errors.
+ *
+ * @param[in] tdb The database to get the logging function from.
+ *
+ * @return The logging function of the database.
+ *
+ * @see tdb_get_logging_private()
+ */
+_PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb);
+
+/**
+ * @brief Get the private data of the logging function.
+ *
+ * @param[in] tdb The database to get the data from.
+ *
+ * @return The private data pointer of the logging function.
+ *
+ * @see tdb_log_fn()
+ */
+_PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb);
+
+/**
+ * @brief Is a transaction active?
+ *
+ * It is helpful for the application to know if a transaction is
+ * active, rather than needing to maintain an application-level reference
+ * count.
+ *
+ * @param[in] tdb The database to start the transaction.
+ *
+ * @return true if there is a transaction active, false otherwise
+ *
+ * @see tdb_transaction_start()
+ * @see tdb_transaction_prepare_commit()
+ * @see tdb_transaction_commit()
+ * @see tdb_transaction_cancel()
+ */
+_PUBLIC_ bool tdb_transaction_active(struct tdb_context *tdb);
+
+/**
+ * @brief Start a transaction.
+ *
+ * All operations after the transaction start can either be committed with
+ * tdb_transaction_commit() or cancelled with tdb_transaction_cancel().
+ *
+ * If (the default) TDB_ALLOW_NESTING was specified or
+ * TDB_DISALLOW_NESTING was not specified as a flag via tdb_open() or
+ * tdb_open_ex(), you call tdb_transaction_start() again on the same
+ * tdb context while a transaction is in progress, then the same
+ * transaction buffer is re-used. The number of
+ * tdb_transaction_{commit,cancel} operations must match the number of
+ * successful tdb_transaction_start() calls.
+ *
+ * Note that transactions are by default disk synchronous, and use a recover
+ * area in the database to automatically recover the database on the next open
+ * if the system crashes during a transaction. You can disable the synchronous
+ * transaction recovery setup using the TDB_NOSYNC flag, which will greatly
+ * speed up operations at the risk of corrupting your database if the system
+ * crashes.
+ *
+ * Operations made within a transaction are not visible to other users of the
+ * database until a successful commit.
+ *
+ * @param[in] tdb The database to start the transaction.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_transaction_start(struct tdb_context *tdb);
+
+/**
+ * @brief Start a transaction, non-blocking.
+ *
+ * @param[in] tdb The database to start the transaction.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ * @see tdb_transaction_start()
+ */
+_PUBLIC_ int tdb_transaction_start_nonblock(struct tdb_context *tdb);
+
+/**
+ * @brief Prepare to commit a current transaction, for two-phase commits.
+ *
+ * Once prepared for commit, the only allowed calls are tdb_transaction_commit()
+ * or tdb_transaction_cancel(). Preparing allocates disk space for the pending
+ * updates, so a subsequent commit should succeed (barring any hardware
+ * failures).
+ *
+ * @param[in] tdb The database to prepare the commit.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb);
+
+/**
+ * @brief Commit a current transaction.
+ *
+ * This updates the database and releases the current transaction locks.
+ *
+ * @param[in] tdb The database to commit the transaction.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb);
+
+/**
+ * @brief Cancel a current transaction.
+ *
+ * This discards all write and lock operations that have been made since the
+ * transaction started.
+ *
+ * @param[in] tdb The tdb to cancel the transaction on.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb);
+
+/**
+ * @brief Get the tdb sequence number.
+ *
+ * Only makes sense if the writers opened with TDB_SEQNUM set. Note that this
+ * sequence number will wrap quite quickly, so it should only be used for a
+ * 'has something changed' test, not for code that relies on the count of the
+ * number of changes made. If you want a counter then use a tdb record.
+ *
+ * The aim of this sequence number is to allow for a very lightweight test of a
+ * possible tdb change.
+ *
+ * @param[in] tdb The database to get the sequence number from.
+ *
+ * @return The sequence number or 0.
+ *
+ * @see tdb_open()
+ * @see tdb_enable_seqnum()
+ */
+_PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb);
+
+/**
+ * @brief Get the hash size.
+ *
+ * @param[in] tdb The database to get the hash size from.
+ *
+ * @return The hash size.
+ */
+_PUBLIC_ int tdb_hash_size(struct tdb_context *tdb);
+
+/**
+ * @brief Get the map size.
+ *
+ * @param[in] tdb The database to get the map size from.
+ *
+ * @return The map size.
+ */
+_PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb);
+
+/**
+ * @brief Get the tdb flags set during open.
+ *
+ * @param[in] tdb The database to get the flags form.
+ *
+ * @return The flags set to on the database.
+ */
+_PUBLIC_ int tdb_get_flags(struct tdb_context *tdb);
+
+/**
+ * @brief Add flags to the database.
+ *
+ * @param[in] tdb The database to add the flags.
+ *
+ * @param[in] flag The tdb flags to add.
+ */
+_PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flag);
+
+/**
+ * @brief Remove flags from the database.
+ *
+ * @param[in] tdb The database to remove the flags.
+ *
+ * @param[in] flag The tdb flags to remove.
+ */
+_PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flag);
+
+/**
+ * @brief Enable sequence number handling on an open tdb.
+ *
+ * @param[in] tdb The database to enable sequence number handling.
+ *
+ * @see tdb_get_seqnum()
+ */
+_PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb);
+
+/**
+ * @brief Increment the tdb sequence number.
+ *
+ * This only works if the tdb has been opened using the TDB_SEQNUM flag or
+ * enabled using tdb_enable_seqnum().
+ *
+ * @param[in] tdb The database to increment the sequence number.
+ *
+ * @see tdb_enable_seqnum()
+ * @see tdb_get_seqnum()
+ */
+_PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb);
+
+/**
+ * @brief Create a hash of the key.
+ *
+ * @param[in] key The key to hash
+ *
+ * @return The hash.
+ */
+_PUBLIC_ unsigned int tdb_jenkins_hash(TDB_DATA *key);
+
+/**
+ * @brief Check the consistency of the database.
+ *
+ * This check the consistency of the database calling back the check function
+ * (if non-NULL) on each record. If some consistency check fails, or the
+ * supplied check function returns -1, tdb_check returns -1, otherwise 0.
+ *
+ * @note The logging function (if set) will be called with additional
+ * information on the corruption found.
+ *
+ * @param[in] tdb The database to check.
+ *
+ * @param[in] check The check function to use.
+ *
+ * @param[in] private_data the private data to pass to the check function.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_check(struct tdb_context *tdb,
+ int (*check) (TDB_DATA key, TDB_DATA data, void *private_data),
+ void *private_data);
+
+/**
+ * @brief Dump all possible records in a corrupt database.
+ *
+ * This is the only way to get data out of a database where tdb_check() fails.
+ * It will call walk() with anything which looks like a database record; this
+ * may well include invalid, incomplete or duplicate records.
+ *
+ * @param[in] tdb The database to check.
+ *
+ * @param[in] walk The walk function to use.
+ *
+ * @param[in] private_data the private data to pass to the walk function.
+ *
+ * @return 0 on success, -1 on error with error code set.
+ *
+ * @see tdb_error()
+ * @see tdb_errorstr()
+ */
+_PUBLIC_ int tdb_rescue(struct tdb_context *tdb,
+ void (*walk) (TDB_DATA key, TDB_DATA data, void *private_data),
+ void *private_data);
+
+/**
+ * @brief Check if support for TDB_MUTEX_LOCKING is available at runtime.
+ *
+ * On some systems the API for pthread_mutexattr_setrobust() is not available.
+ * On other systems there are some bugs in the interaction between glibc and
+ * the linux kernel.
+ *
+ * This function provides a runtime check if robust mutexes are really
+ * available.
+ *
+ * This needs to be called and return true before TDB_MUTEX_LOCKING
+ * can be used at runtime.
+ *
+ * @note This calls fork(), but the SIGCHILD handling should be transparent.
+ *
+ * @return true if supported, false otherwise.
+ *
+ * @see TDB_MUTEX_LOCKING
+ */
+_PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void);
+
+/* @} ******************************************************************/
+
+/* Low level locking functions: use with care */
+_PUBLIC_ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_read_nonblock(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key);
+_PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key);
+
+_PUBLIC_ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr);
+
+/* wipe and repack */
+_PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb);
+_PUBLIC_ int tdb_repack(struct tdb_context *tdb);
+
+/* Debug functions. Not used in production. */
+_PUBLIC_ void tdb_dump_all(struct tdb_context *tdb);
+_PUBLIC_ int tdb_printfreelist(struct tdb_context *tdb);
+_PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries);
+_PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb);
+_PUBLIC_ char *tdb_summary(struct tdb_context *tdb);
+
+_PUBLIC_ extern TDB_DATA tdb_null;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* tdb.h */
diff --git a/lib/tdb/man/tdbbackup.8.xml b/lib/tdb/man/tdbbackup.8.xml
new file mode 100644
index 0000000..a73fb56
--- /dev/null
+++ b/lib/tdb/man/tdbbackup.8.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="tdbbackup.8">
+<refentryinfo><date>2015-04-25</date></refentryinfo>
+
+<refmeta>
+ <refentrytitle>tdbbackup</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">3.6</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>tdbbackup</refname>
+ <refpurpose>tool for backing up and for validating the integrity of samba .tdb files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>tdbbackup</command>
+ <arg choice="opt">-s suffix</arg>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-n hashsize</arg>
+ <arg choice="opt">-l</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para><command>tdbbackup</command> is a tool that may be used to backup samba .tdb
+ files. This tool may also be used to verify the integrity of the .tdb files prior
+ to samba startup or during normal operation. If it finds file damage and it finds
+ a prior backup the backup file will be restored.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Get help information.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s suffix</term>
+ <listitem><para>
+ The <command>-s</command> option allows the administrator to specify a file
+ backup extension. This way it is possible to keep a history of tdb backup
+ files by using a new suffix for each backup.
+ </para> </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem><para>
+ The <command>-v</command> will check the database for damages (corrupt data)
+ which if detected causes the backup to be restored.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-n hashsize</term>
+ <listitem><para>
+ The <command>-n</command> option sets the hash size for the new backup tdb.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-l</term>
+ <listitem><para>
+ This options disables any locking, by passing TDB_NOLOCK
+ to tdb_open_ex(). Only use this for database files which
+ are not used by any other process! And also only if it is otherwise not
+ possible to open the database, e.g. databases which were created with
+ mutex locking.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>COMMANDS</title>
+
+ <para><emphasis>GENERAL INFORMATION</emphasis></para>
+
+ <para>
+ The <command>tdbbackup</command> utility can safely be run at any time. It was designed so
+ that it can be used at any time to validate the integrity of tdb files, even during Samba
+ operation. Typical usage for the command will be:
+ </para>
+
+ <para>tdbbackup [-s suffix] *.tdb</para>
+
+ <para>
+ Before restarting samba the following command may be run to validate .tdb files:
+ </para>
+
+ <para>tdbbackup -v [-s suffix] *.tdb</para>
+
+ <para>
+ Samba .tdb files are stored in various locations, be sure to run backup all
+ .tdb file on the system. Important files includes:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <command>secrets.tdb</command> - usual location is in the /usr/local/samba/private
+ directory, or on some systems in /etc/samba.
+ </para></listitem>
+
+ <listitem><para>
+ <command>passdb.tdb</command> - usual location is in the /usr/local/samba/private
+ directory, or on some systems in /etc/samba.
+ </para></listitem>
+
+ <listitem><para>
+ <command>*.tdb</command> located in the /usr/local/samba/var directory or on some
+ systems in the /var/cache or /var/lib/samba directories.
+ </para></listitem>
+ </itemizedlist>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 3 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ The original Samba software and related utilities were created by Andrew Tridgell.
+ Samba is now developed by the Samba Team as an Open Source project similar to the way
+ the Linux kernel is developed.
+ </para>
+
+ <para>The tdbbackup man page was written by John H Terpstra.</para>
+</refsect1>
+
+</refentry>
diff --git a/lib/tdb/man/tdbdump.8.xml b/lib/tdb/man/tdbdump.8.xml
new file mode 100644
index 0000000..31e6888
--- /dev/null
+++ b/lib/tdb/man/tdbdump.8.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="tdbdump.8">
+<refentryinfo><date>2015-04-25</date></refentryinfo>
+
+<refmeta>
+ <refentrytitle>tdbdump</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">3.6</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>tdbdump</refname>
+ <refpurpose>tool for printing the contents of a TDB file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>tdbdump</command>
+ <arg choice="opt">-k <replaceable>keyname</replaceable></arg>
+ <arg choice="opt">-e</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="req">filename</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para><command>tdbdump</command> is a very simple utility that 'dumps' the
+ contents of a TDB (Trivial DataBase) file to standard output in a
+ human-readable format.
+ </para>
+
+ <para>This tool can be used when debugging problems with TDB files. It is
+ intended for those who are somewhat familiar with Samba internals.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>
+ Get help information.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-k <replaceable>keyname</replaceable></term>
+ <listitem><para>
+ The <command>-k</command> option restricts dumping to a single key, if found.
+ </para> </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-e</term>
+ <listitem><para>
+ The <command>-e</command> tries to dump out from a corrupt database. Naturally, such a dump is unreliable, at best.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 3 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ The original Samba software and related utilities were created by Andrew Tridgell.
+ Samba is now developed by the Samba Team as an Open Source project similar to the way
+ the Linux kernel is developed.
+ </para>
+
+ <para>The tdbdump man page was written by Jelmer Vernooij.</para>
+</refsect1>
+
+</refentry>
diff --git a/lib/tdb/man/tdbrestore.8.xml b/lib/tdb/man/tdbrestore.8.xml
new file mode 100644
index 0000000..034db53
--- /dev/null
+++ b/lib/tdb/man/tdbrestore.8.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="tdbrestore.8">
+<refentryinfo><date>2015-04-25</date></refentryinfo>
+
+<refmeta>
+ <refentrytitle>tdbrestore</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">3.6</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>tdbrestore</refname>
+ <refpurpose>tool for creating a TDB file out of a tdbdump output</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>tdbrestore</command>
+ <arg choice="req">tdbfilename</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para><command>tdbrestore</command> is a very simple utility that 'restores' the
+ contents of dump file into TDB (Trivial DataBase) file. The dump file is obtained from the tdbdump
+ command.
+ </para>
+
+ <para>This tool wait on the standard input for the content of the dump and will write the tdb in the tdbfilename
+ parameter.
+ </para>
+ <para>This tool can be used for unpacking the content of tdb as backup mean.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 3 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ The original Samba software and related utilities were created by Andrew Tridgell.
+ Samba is now developed by the Samba Team as an Open Source project similar to the way
+ the Linux kernel is developed.
+
+ This tool was initially written by Volker Lendecke based on an
+ idea by Simon McVittie.
+ </para>
+
+ <para>The tdbrestore man page was written by Matthieu Patou.</para>
+</refsect1>
+
+</refentry>
diff --git a/lib/tdb/man/tdbtool.8.xml b/lib/tdb/man/tdbtool.8.xml
new file mode 100644
index 0000000..045cbde
--- /dev/null
+++ b/lib/tdb/man/tdbtool.8.xml
@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="tdbtool.8">
+<refentryinfo><date>2015-04-25</date></refentryinfo>
+
+<refmeta>
+ <refentrytitle>tdbtool</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>tdbtool</refname>
+ <refpurpose>manipulate the contents TDB files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+
+ <cmdsynopsis>
+ <command>tdbtool</command>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>tdbtool</command>
+ <arg choice="opt">-l</arg>
+ <arg choice="plain">
+ <replaceable>TDBFILE</replaceable>
+ </arg>
+ <arg rep="repeat" choice="opt">
+ <replaceable>COMMANDS</replaceable>
+ </arg>
+ </cmdsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the
+ <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para><command>tdbtool</command> a tool for displaying and
+ altering the contents of Samba TDB (Trivial DataBase) files. Each
+ of the commands listed below can be entered interactively or
+ provided on the command line.</para>
+
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>-l</term>
+ <listitem><para>
+ This options disables any locking, by passing TDB_NOLOCK
+ to tdb_open_ex(). Only use this for database files which
+ are not used by any other process! And also only if it is otherwise not
+ possible to open the database, e.g. databases which were created with
+ mutex locking.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+
+
+<refsect1>
+ <title>COMMANDS</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><option>create</option>
+ <replaceable>TDBFILE</replaceable></term>
+ <listitem><para>Create a new database named
+ <replaceable>TDBFILE</replaceable>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>open</option>
+ <replaceable>TDBFILE</replaceable></term>
+ <listitem><para>Open an existing database named
+ <replaceable>TDBFILE</replaceable>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>erase</option></term>
+ <listitem><para>Erase the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>dump</option></term>
+ <listitem><para>Dump the current database as strings.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>cdump</option></term>
+ <listitem><para>Dump the current database as connection records.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>keys</option></term>
+ <listitem><para>Dump the current database keys as strings.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>hexkeys</option></term>
+ <listitem><para>Dump the current database keys as hex values.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>info</option></term>
+ <listitem><para>Print summary information about the
+ current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>insert</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>DATA</replaceable>
+ </term>
+ <listitem><para>Insert a record into the
+ current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>move</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>TDBFILE</replaceable>
+ </term>
+ <listitem><para>Move a record from the
+ current database into <replaceable>TDBFILE</replaceable>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>store</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>DATA</replaceable>
+ </term>
+ <listitem><para>Store (replace) a record in the
+ current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>storehex</option>
+ <replaceable>KEY</replaceable>
+ <replaceable>DATA</replaceable>
+ </term>
+ <listitem><para>Store (replace) a record in the
+ current database where key and data are in hex format.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>show</option>
+ <replaceable>KEY</replaceable>
+ </term>
+ <listitem><para>Show a record by key.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>delete</option>
+ <replaceable>KEY</replaceable>
+ </term>
+ <listitem><para>Delete a record by key.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>list</option>
+ </term>
+ <listitem><para>Print the current database hash table and free list.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>free</option>
+ </term>
+ <listitem><para>Print the current database and free list.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>!</option>
+ <replaceable>COMMAND</replaceable>
+ </term>
+ <listitem><para>Execute the given system command.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>first</option>
+ </term>
+ <listitem><para>Print the first record in the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>next</option>
+ </term>
+ <listitem><para>Print the next record in the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>check</option>
+ </term>
+ <listitem><para>Check the integrity of the current database.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>repack</option>
+ </term>
+ <listitem><para>Repack a database using a temporary file to remove fragmentation.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>quit</option>
+ </term>
+ <listitem><para>Exit <command>tdbtool</command>.
+ </para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>CAVEATS</title>
+ <para>The contents of the Samba TDB files are private
+ to the implementation and should not be altered with
+ <command>tdbtool</command>.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+ <para>This man page is correct for version 3.6 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para> The original Samba software and related utilities were
+ created by Andrew Tridgell. Samba is now developed by the
+ Samba Team as an Open Source project similar to the way the
+ Linux kernel is developed.</para>
+</refsect1>
+
+</refentry>
diff --git a/lib/tdb/pytdb.c b/lib/tdb/pytdb.c
new file mode 100644
index 0000000..4d75d7a
--- /dev/null
+++ b/lib/tdb/pytdb.c
@@ -0,0 +1,830 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Python interface to tdb.
+
+ Copyright (C) 2004-2006 Tim Potter <tpot@samba.org>
+ Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
+
+ ** NOTE! The following LGPL license applies to the tdb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include "replace.h"
+#include "system/filesys.h"
+
+/* Include tdb headers */
+#include <tdb.h>
+
+/* discard signature of 'func' in favour of 'target_sig' */
+#define PY_DISCARD_FUNC_SIG(target_sig, func) (target_sig)(void(*)(void))func
+
+typedef struct {
+ PyObject_HEAD
+ TDB_CONTEXT *ctx;
+ bool closed;
+} PyTdbObject;
+
+static PyTypeObject PyTdb;
+
+static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
+{
+ PyErr_SetObject(PyExc_RuntimeError,
+ Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb)));
+}
+
+static TDB_DATA PyBytes_AsTDB_DATA(PyObject *data)
+{
+ TDB_DATA ret;
+ ret.dptr = (unsigned char *)PyBytes_AsString(data);
+ ret.dsize = PyBytes_Size(data);
+ return ret;
+}
+
+static PyObject *PyBytes_FromTDB_DATA(TDB_DATA data)
+{
+ if (data.dptr == NULL && data.dsize == 0) {
+ Py_RETURN_NONE;
+ } else {
+ PyObject *ret = PyBytes_FromStringAndSize((const char *)data.dptr,
+ data.dsize);
+ free(data.dptr);
+ return ret;
+ }
+}
+
+#define PyErr_TDB_ERROR_IS_ERR_RAISE(ret, tdb) \
+ if (ret != 0) { \
+ PyErr_SetTDBError(tdb); \
+ return NULL; \
+ }
+
+#define PyErr_TDB_RAISE_IF_CLOSED(self) \
+ if (self->closed) { \
+ PyErr_SetObject(PyExc_RuntimeError, \
+ Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
+ return NULL; \
+ }
+
+#define PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self) \
+ if (self->closed) { \
+ PyErr_SetObject(PyExc_RuntimeError, \
+ Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
+ return -1; \
+ }
+
+static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ char *name = NULL;
+ int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600;
+ TDB_CONTEXT *ctx;
+ PyTdbObject *ret;
+ const char *_kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
+ char **kwnames = discard_const_p(char *, _kwnames);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
+ return NULL;
+
+ if (name == NULL) {
+ tdb_flags |= TDB_INTERNAL;
+ }
+
+ ctx = tdb_open(name, hash_size, tdb_flags, flags, mode);
+ if (ctx == NULL) {
+ PyErr_SetFromErrno(PyExc_IOError);
+ return NULL;
+ }
+
+ ret = PyObject_New(PyTdbObject, &PyTdb);
+ if (!ret) {
+ tdb_close(ctx);
+ return NULL;
+ }
+
+ ret->ctx = ctx;
+ ret->closed = false;
+ return (PyObject *)ret;
+}
+
+static PyObject *obj_transaction_cancel(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ ret = tdb_transaction_cancel(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_commit(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_transaction_commit(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_prepare_commit(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_transaction_prepare_commit(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_start(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_transaction_start(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_reopen(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_reopen(self->ctx);
+ if (ret != 0) {
+ self->closed = true;
+ PyErr_SetObject(PyExc_RuntimeError,
+ Py_BuildValue("(i,s)",
+ TDB_ERR_IO,
+ "Failed to reopen database"));
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_lockall(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_lockall(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_unlockall(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_unlockall(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_lockall_read(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_lockall_read(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_unlockall_read(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret = tdb_unlockall_read(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_close(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ if (self->closed)
+ Py_RETURN_NONE;
+ ret = tdb_close(self->ctx);
+ self->closed = true;
+ if (ret != 0) {
+ PyErr_SetObject(PyExc_RuntimeError,
+ Py_BuildValue("(i,s)",
+ TDB_ERR_IO,
+ "Failed to close database"));
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_get(PyTdbObject *self, PyObject *args)
+{
+ TDB_DATA key;
+ PyObject *py_key;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(args, "O", &py_key))
+ return NULL;
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (!key.dptr)
+ return NULL;
+
+ return PyBytes_FromTDB_DATA(tdb_fetch(self->ctx, key));
+}
+
+static PyObject *obj_append(PyTdbObject *self, PyObject *args)
+{
+ TDB_DATA key, data;
+ PyObject *py_key, *py_data;
+ int ret;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
+ return NULL;
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (!key.dptr)
+ return NULL;
+ data = PyBytes_AsTDB_DATA(py_data);
+ if (!data.dptr)
+ return NULL;
+
+ ret = tdb_append(self->ctx, key, data);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_firstkey(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ return PyBytes_FromTDB_DATA(tdb_firstkey(self->ctx));
+}
+
+static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args)
+{
+ TDB_DATA key;
+ PyObject *py_key;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(args, "O", &py_key))
+ return NULL;
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (!key.dptr)
+ return NULL;
+
+ return PyBytes_FromTDB_DATA(tdb_nextkey(self->ctx, key));
+}
+
+static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
+{
+ TDB_DATA key;
+ PyObject *py_key;
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(args, "O", &py_key))
+ return NULL;
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (!key.dptr)
+ return NULL;
+ ret = tdb_delete(self->ctx, key);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static int obj_contains(PyTdbObject *self, PyObject *py_key)
+{
+ TDB_DATA key;
+ int ret;
+ PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (!key.dptr) {
+ PyErr_BadArgument();
+ return -1;
+ }
+ ret = tdb_exists(self->ctx, key);
+ if (ret)
+ return 1;
+ return 0;
+}
+
+static PyObject *obj_store(PyTdbObject *self, PyObject *args)
+{
+ TDB_DATA key, value;
+ int ret;
+ int flag = TDB_REPLACE;
+ PyObject *py_key, *py_value;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
+ return NULL;
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (!key.dptr)
+ return NULL;
+ value = PyBytes_AsTDB_DATA(py_value);
+ if (!value.dptr)
+ return NULL;
+
+ ret = tdb_store(self->ctx, key, value, flag);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_storev(PyTdbObject *self, PyObject *args)
+{
+ TDB_DATA key, *values, value;
+ int ret;
+ int flag = TDB_REPLACE;
+ Py_ssize_t num_values, i;
+ PyObject *py_key, *py_values, *py_value;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(
+ args, "OO!|i", &py_key, &PyList_Type, &py_values, &flag)) {
+ return NULL;
+ }
+
+ num_values = PyList_Size(py_values);
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (key.dptr == NULL) {
+ return NULL;
+ }
+
+ if (SSIZE_MAX/sizeof(TDB_DATA) < num_values) {
+ PyErr_SetFromErrno(PyExc_OverflowError);
+ return NULL;
+ }
+ values = malloc(sizeof(TDB_DATA) * num_values);
+ if (values == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (i=0; i<num_values; i++) {
+ py_value = PyList_GetItem(py_values, i);
+ value = PyBytes_AsTDB_DATA(py_value);
+ if (!value.dptr) {
+ free(values);
+ return NULL;
+ }
+ values[i] = value;
+ }
+
+ ret = tdb_storev(self->ctx, key, values, num_values, flag);
+ free(values);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args)
+{
+ unsigned flags;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(args, "I", &flags))
+ return NULL;
+
+ tdb_add_flags(self->ctx, flags);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args)
+{
+ unsigned flags;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ if (!PyArg_ParseTuple(args, "I", &flags))
+ return NULL;
+
+ tdb_remove_flags(self->ctx, flags);
+ Py_RETURN_NONE;
+}
+
+typedef struct {
+ PyObject_HEAD
+ TDB_DATA current;
+ PyTdbObject *iteratee;
+} PyTdbIteratorObject;
+
+static PyObject *tdb_iter_next(PyTdbIteratorObject *self)
+{
+ TDB_DATA current;
+ PyObject *ret;
+ if (self->current.dptr == NULL && self->current.dsize == 0)
+ return NULL;
+ current = self->current;
+ self->current = tdb_nextkey(self->iteratee->ctx, self->current);
+ ret = PyBytes_FromTDB_DATA(current);
+ return ret;
+}
+
+static void tdb_iter_dealloc(PyTdbIteratorObject *self)
+{
+ Py_CLEAR(self->iteratee);
+ PyObject_Del(self);
+}
+
+PyTypeObject PyTdbIterator = {
+ .tp_name = "Iterator",
+ .tp_basicsize = sizeof(PyTdbIteratorObject),
+ .tp_iternext = (iternextfunc)tdb_iter_next,
+ .tp_dealloc = (destructor)tdb_iter_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_iter = PyObject_SelfIter,
+};
+
+static PyObject *tdb_object_iter(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ PyTdbIteratorObject *ret;
+
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+
+ ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
+ if (!ret)
+ return NULL;
+ ret->current = tdb_firstkey(self->ctx);
+ ret->iteratee = self;
+ Py_INCREF(self);
+ return (PyObject *)ret;
+}
+
+static PyObject *obj_clear(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_wipe_all(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_repack(PyTdbObject *self, PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ ret = tdb_repack(self->ctx);
+ PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_enable_seqnum(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ tdb_enable_seqnum(self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ tdb_increment_seqnum_nonblock(self->ctx);
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef tdb_object_methods[] = {
+ { "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS,
+ "S.transaction_cancel() -> None\n"
+ "Cancel the currently active transaction." },
+ { "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS,
+ "S.transaction_commit() -> None\n"
+ "Commit the currently active transaction." },
+ { "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS,
+ "S.transaction_prepare_commit() -> None\n"
+ "Prepare to commit the currently active transaction" },
+ { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS,
+ "S.transaction_start() -> None\n"
+ "Start a new transaction." },
+ { "reopen", (PyCFunction)obj_reopen, METH_NOARGS, "Reopen this file." },
+ { "lock_all", (PyCFunction)obj_lockall, METH_NOARGS, NULL },
+ { "unlock_all", (PyCFunction)obj_unlockall, METH_NOARGS, NULL },
+ { "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL },
+ { "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL },
+ { "close", (PyCFunction)obj_close, METH_NOARGS, NULL },
+ { "get", (PyCFunction)obj_get, METH_VARARGS, "S.get(key) -> value\n"
+ "Fetch a value." },
+ { "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n"
+ "Append data to an existing key." },
+ { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n"
+ "Return the first key in this database." },
+ { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> data\n"
+ "Return the next key in this database." },
+ { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n"
+ "Delete an entry." },
+ { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None"
+ "Store data." },
+ { "storev", (PyCFunction)obj_storev, METH_VARARGS, "S.storev(key, data, flag=REPLACE) -> None"
+ "Store several data." },
+ { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
+ { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
+ { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.keys() -> iterator" },
+ { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
+ "Wipe the entire database." },
+ { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
+ "Repack the entire database." },
+ { "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
+ "S.enable_seqnum() -> None" },
+ { "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
+ "S.increment_seqnum_nonblock() -> None" },
+ {0}
+};
+
+static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure)
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ return PyLong_FromLong(tdb_hash_size(self->ctx));
+}
+
+static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure)
+{
+ PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
+ if (!PyLong_Check(max_dead))
+ return -1;
+ tdb_set_max_dead(self->ctx, PyLong_AsLong(max_dead));
+ return 0;
+}
+
+static PyObject *obj_get_map_size(PyTdbObject *self, void *closure)
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ return PyLong_FromLong(tdb_map_size(self->ctx));
+}
+
+static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ return PyLong_FromLong(tdb_freelist_size(self->ctx));
+}
+
+static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ return PyLong_FromLong(tdb_get_flags(self->ctx));
+}
+
+static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ return PyBytes_FromString(tdb_name(self->ctx));
+}
+
+static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ return PyLong_FromLong(tdb_get_seqnum(self->ctx));
+}
+
+static PyObject *obj_get_text(PyTdbObject *self, void *closure)
+{
+ PyObject *mod, *cls, *inst;
+ mod = PyImport_ImportModule("_tdb_text");
+ if (mod == NULL)
+ return NULL;
+ cls = PyObject_GetAttrString(mod, "TdbTextWrapper");
+ if (cls == NULL) {
+ Py_DECREF(mod);
+ return NULL;
+ }
+ inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self);
+ Py_DECREF(mod);
+ Py_DECREF(cls);
+ return inst;
+}
+
+static PyGetSetDef tdb_object_getsetters[] = {
+ {
+ .name = discard_const_p(char, "hash_size"),
+ .get = (getter)obj_get_hash_size,
+ },
+ {
+ .name = discard_const_p(char, "map_size"),
+ .get = (getter)obj_get_map_size,
+ },
+ {
+ .name = discard_const_p(char, "freelist_size"),
+ .get = (getter)obj_get_freelist_size,
+ },
+ {
+ .name = discard_const_p(char, "flags"),
+ .get = (getter)obj_get_flags,
+ },
+ {
+ .name = discard_const_p(char, "max_dead"),
+ .set = (setter)obj_set_max_dead,
+ },
+ {
+ .name = discard_const_p(char, "filename"),
+ .get = (getter)obj_get_filename,
+ .doc = discard_const_p(char, "The filename of this TDB file."),
+ },
+ {
+ .name = discard_const_p(char, "seqnum"),
+ .get = (getter)obj_get_seqnum,
+ },
+ {
+ .name = discard_const_p(char, "text"),
+ .get = (getter)obj_get_text,
+ },
+ { .name = NULL }
+};
+
+static PyObject *tdb_object_repr(PyTdbObject *self)
+{
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
+ return PyUnicode_FromString("Tdb(<internal>)");
+ } else {
+ return PyUnicode_FromFormat("Tdb('%s')", tdb_name(self->ctx));
+ }
+}
+
+static void tdb_object_dealloc(PyTdbObject *self)
+{
+ if (!self->closed)
+ tdb_close(self->ctx);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *obj_getitem(PyTdbObject *self, PyObject *key)
+{
+ TDB_DATA tkey, val;
+ PyErr_TDB_RAISE_IF_CLOSED(self);
+ if (!PyBytes_Check(key)) {
+ PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
+ return NULL;
+ }
+
+ tkey.dptr = (unsigned char *)PyBytes_AsString(key);
+ tkey.dsize = PyBytes_Size(key);
+
+ val = tdb_fetch(self->ctx, tkey);
+ if (val.dptr == NULL) {
+ /*
+ * if the key doesn't exist raise KeyError(key) to be
+ * consistent with python dict
+ */
+ PyErr_SetObject(PyExc_KeyError, key);
+ return NULL;
+ } else {
+ return PyBytes_FromTDB_DATA(val);
+ }
+}
+
+static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value)
+{
+ TDB_DATA tkey, tval;
+ int ret;
+ PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
+ if (!PyBytes_Check(key)) {
+ PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
+ return -1;
+ }
+
+ tkey = PyBytes_AsTDB_DATA(key);
+
+ if (value == NULL) {
+ ret = tdb_delete(self->ctx, tkey);
+ } else {
+ if (!PyBytes_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "Expected string as value");
+ return -1;
+ }
+
+ tval = PyBytes_AsTDB_DATA(value);
+
+ ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
+ }
+
+ if (ret != 0) {
+ PyErr_SetTDBError(self->ctx);
+ return -1;
+ }
+
+ return ret;
+}
+
+static PyMappingMethods tdb_object_mapping = {
+ .mp_subscript = (binaryfunc)obj_getitem,
+ .mp_ass_subscript = (objobjargproc)obj_setitem,
+};
+static PySequenceMethods tdb_object_seq = {
+ .sq_contains = (objobjproc)obj_contains,
+};
+static PyTypeObject PyTdb = {
+ .tp_name = "tdb.Tdb",
+ .tp_basicsize = sizeof(PyTdbObject),
+ .tp_methods = tdb_object_methods,
+ .tp_getset = tdb_object_getsetters,
+ .tp_new = py_tdb_open,
+ .tp_doc = "A TDB file",
+ .tp_repr = (reprfunc)tdb_object_repr,
+ .tp_dealloc = (destructor)tdb_object_dealloc,
+ .tp_as_mapping = &tdb_object_mapping,
+ .tp_as_sequence = &tdb_object_seq,
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ .tp_iter = PY_DISCARD_FUNC_SIG(getiterfunc,tdb_object_iter),
+};
+
+static PyMethodDef tdb_methods[] = {
+ {
+ .ml_name = "open",
+ .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, py_tdb_open),
+ .ml_flags = METH_VARARGS|METH_KEYWORDS,
+ .ml_doc = "open(name, hash_size=0, tdb_flags=TDB_DEFAULT, "
+ "flags=O_RDWR, mode=0600)\nOpen a TDB file."
+ },
+ { .ml_name = NULL }
+};
+
+#define MODULE_DOC "simple key-value database that supports multiple writers."
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "tdb",
+ .m_doc = MODULE_DOC,
+ .m_size = -1,
+ .m_methods = tdb_methods,
+};
+
+PyObject* module_init(void);
+PyObject* module_init(void)
+{
+ PyObject *m;
+
+ if (PyType_Ready(&PyTdb) < 0)
+ return NULL;
+
+ if (PyType_Ready(&PyTdbIterator) < 0)
+ return NULL;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE);
+ PyModule_AddIntConstant(m, "INSERT", TDB_INSERT);
+ PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY);
+
+ PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT);
+ PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST);
+ PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL);
+ PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK);
+ PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP);
+ PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT);
+ PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN);
+ PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC);
+ PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM);
+ PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE);
+ PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING);
+ PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING);
+ PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH);
+
+ PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
+
+ PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
+
+ Py_INCREF(&PyTdb);
+ PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
+
+ Py_INCREF(&PyTdbIterator);
+
+ return m;
+}
+
+
+PyMODINIT_FUNC PyInit_tdb(void);
+PyMODINIT_FUNC PyInit_tdb(void)
+{
+ return module_init();
+}
diff --git a/lib/tdb/python/tdbdump.py b/lib/tdb/python/tdbdump.py
new file mode 100644
index 0000000..988e293
--- /dev/null
+++ b/lib/tdb/python/tdbdump.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+# Trivial reimplementation of tdbdump in Python
+
+import sys
+
+sys.path.insert(0, "bin/python")
+
+import tdb
+
+if len(sys.argv) < 2:
+ print("Usage: tdbdump.py <tdb-file>")
+ sys.exit(1)
+
+db = tdb.Tdb(sys.argv[1])
+for k in db.keys():
+ v = db.get(k)
+ print("{\nkey(%d) = %r\ndata(%d) = %r\n}" % (len(k), k, len(v), v))
diff --git a/lib/tdb/python/tests/simple.py b/lib/tdb/python/tests/simple.py
new file mode 100644
index 0000000..f7ab024
--- /dev/null
+++ b/lib/tdb/python/tests/simple.py
@@ -0,0 +1,315 @@
+#!/usr/bin/env python3
+# Some simple tests for the Python bindings for TDB
+# Note that this tests the interface of the Python bindings
+# It does not test tdb itself.
+#
+# Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
+# Published under the GNU LGPLv3 or later
+
+import sys
+import os
+import tempfile
+from unittest import TestCase
+
+import tdb
+
+
+class OpenTdbTests(TestCase):
+
+ def test_nonexistent_read(self):
+ self.assertRaises(IOError, tdb.Tdb, "/some/nonexistent/file", 0,
+ tdb.DEFAULT, os.O_RDWR)
+
+class CloseTdbTests(TestCase):
+
+ def test_double_close(self):
+ self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+ os.O_CREAT|os.O_RDWR)
+ self.assertNotEqual(None, self.tdb)
+
+ # ensure that double close does not crash python
+ self.tdb.close()
+ self.tdb.close()
+
+ # Check that further operations do not crash python
+ self.assertRaises(RuntimeError, lambda: self.tdb.transaction_start())
+
+ self.assertRaises(RuntimeError, lambda: self.tdb["bar"])
+
+
+class InternalTdbTests(TestCase):
+
+ def test_repr(self):
+ self.tdb = tdb.Tdb()
+
+ # repr used to crash on internal db
+ self.assertEqual(repr(self.tdb), "Tdb(<internal>)")
+
+
+class CommonTdbTests(TestCase):
+ """Tests common to both the text & bytes interfaces"""
+
+ use_text = False
+
+ def setUp(self):
+ super(CommonTdbTests, self).setUp()
+ self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+ os.O_CREAT|os.O_RDWR)
+ self.assertNotEqual(None, self.tdb)
+ if self.use_text:
+ self.tdb = self.tdb.text
+
+ def test_lockall(self):
+ self.tdb.lock_all()
+
+ def test_max_dead(self):
+ self.tdb.max_dead = 20
+
+ def test_unlockall(self):
+ self.tdb.lock_all()
+ self.tdb.unlock_all()
+
+ def test_lockall_read(self):
+ self.tdb.read_lock_all()
+ self.tdb.read_unlock_all()
+
+ def test_reopen(self):
+ self.tdb.reopen()
+
+ def test_hash_size(self):
+ self.tdb.hash_size
+
+ def test_map_size(self):
+ self.tdb.map_size
+
+ def test_freelist_size(self):
+ self.tdb.freelist_size
+
+ def test_name(self):
+ self.tdb.filename
+
+ def test_add_flags(self):
+ self.tdb.add_flags(tdb.NOMMAP)
+ self.tdb.remove_flags(tdb.NOMMAP)
+
+
+class TextCommonTdbTests(CommonTdbTests):
+
+ use_text = True
+
+
+class SimpleTdbTests(TestCase):
+
+ def setUp(self):
+ super(SimpleTdbTests, self).setUp()
+ self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+ os.O_CREAT|os.O_RDWR)
+ self.assertNotEqual(None, self.tdb)
+
+ def test_repr(self):
+ self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+ def test_store(self):
+ self.tdb.store(b"bar", b"bla")
+ self.assertEqual(b"bla", self.tdb.get(b"bar"))
+
+ def test_storev(self):
+ self.tdb.storev(b"bar", [b"first", b"second", b"third"])
+ self.assertEqual(b"firstsecondthird", self.tdb.get(b"bar"))
+
+ def test_getitem(self):
+ self.tdb[b"bar"] = b"foo"
+ self.tdb.reopen()
+ self.assertEqual(b"foo", self.tdb[b"bar"])
+
+ def test_delete(self):
+ self.tdb[b"bar"] = b"foo"
+ del self.tdb[b"bar"]
+ self.assertRaises(KeyError, lambda: self.tdb[b"bar"])
+
+ def test_contains(self):
+ self.tdb[b"bla"] = b"bloe"
+ self.assertTrue(b"bla" in self.tdb)
+ self.assertFalse(b"qwertyuiop" in self.tdb)
+ if sys.version_info < (3, 0):
+ self.assertTrue(self.tdb.has_key(b"bla"))
+ self.assertFalse(self.tdb.has_key(b"qwertyuiop"))
+
+ def test_keyerror(self):
+ self.assertRaises(KeyError, lambda: self.tdb[b"bla"])
+
+ def test_iterator(self):
+ self.tdb[b"bla"] = b"1"
+ self.tdb[b"brainslug"] = b"2"
+ l = list(self.tdb)
+ l.sort()
+ self.assertEqual([b"bla", b"brainslug"], l)
+
+ def test_transaction_cancel(self):
+ self.tdb[b"bloe"] = b"2"
+ self.tdb.transaction_start()
+ self.tdb[b"bloe"] = b"1"
+ self.tdb.transaction_cancel()
+ self.assertEqual(b"2", self.tdb[b"bloe"])
+
+ def test_transaction_commit(self):
+ self.tdb[b"bloe"] = b"2"
+ self.tdb.transaction_start()
+ self.tdb[b"bloe"] = b"1"
+ self.tdb.transaction_commit()
+ self.assertEqual(b"1", self.tdb[b"bloe"])
+
+ def test_transaction_prepare_commit(self):
+ self.tdb[b"bloe"] = b"2"
+ self.tdb.transaction_start()
+ self.tdb[b"bloe"] = b"1"
+ self.tdb.transaction_prepare_commit()
+ self.tdb.transaction_commit()
+ self.assertEqual(b"1", self.tdb[b"bloe"])
+
+ def test_iterkeys(self):
+ self.tdb[b"bloe"] = b"2"
+ self.tdb[b"bla"] = b"25"
+ if sys.version_info >= (3, 0):
+ i = self.tdb.keys()
+ else:
+ i = self.tdb.iterkeys()
+ self.assertEqual(set([b"bloe", b"bla"]), set([next(i), next(i)]))
+
+ def test_clear(self):
+ self.tdb[b"bloe"] = b"2"
+ self.tdb[b"bla"] = b"25"
+ self.assertEqual(2, len(list(self.tdb)))
+ self.tdb.clear()
+ self.assertEqual(0, len(list(self.tdb)))
+
+ def test_repack(self):
+ self.tdb[b"foo"] = b"abc"
+ self.tdb[b"bar"] = b"def"
+ del self.tdb[b"foo"]
+ self.tdb.repack()
+
+ def test_seqnum(self):
+ self.tdb.enable_seqnum()
+ seq1 = self.tdb.seqnum
+ self.tdb.increment_seqnum_nonblock()
+ seq2 = self.tdb.seqnum
+ self.assertEqual(seq2-seq1, 1)
+
+ def test_len(self):
+ self.assertEqual(0, len(list(self.tdb)))
+ self.tdb[b"entry"] = b"value"
+ self.assertEqual(1, len(list(self.tdb)))
+
+
+class TdbTextTests(TestCase):
+
+ def setUp(self):
+ super(TdbTextTests, self).setUp()
+ self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+ os.O_CREAT|os.O_RDWR)
+ self.assertNotEqual(None, self.tdb)
+
+ def test_repr(self):
+ self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+ def test_store(self):
+ self.tdb.text.store("bar", "bla")
+ self.assertEqual("bla", self.tdb.text.get("bar"))
+
+ def test_getitem(self):
+ self.tdb.text["bar"] = "foo"
+ self.tdb.reopen()
+ self.assertEqual("foo", self.tdb.text["bar"])
+
+ def test_delete(self):
+ self.tdb.text["bar"] = "foo"
+ del self.tdb.text["bar"]
+ self.assertRaises(KeyError, lambda: self.tdb.text["bar"])
+
+ def test_contains(self):
+ self.tdb.text["bla"] = "bloe"
+ self.assertTrue("bla" in self.tdb.text)
+ self.assertFalse("qwertyuiop" in self.tdb.text)
+ if sys.version_info < (3, 0):
+ self.assertTrue(self.tdb.text.has_key("bla"))
+ self.assertFalse(self.tdb.text.has_key("qwertyuiop"))
+
+ def test_keyerror(self):
+ self.assertRaises(KeyError, lambda: self.tdb.text["bla"])
+
+ def test_iterator(self):
+ self.tdb.text["bla"] = "1"
+ self.tdb.text["brainslug"] = "2"
+ l = list(self.tdb.text)
+ l.sort()
+ self.assertEqual(["bla", "brainslug"], l)
+
+ def test_transaction_cancel(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb.text["bloe"] = "1"
+ self.tdb.transaction_cancel()
+ self.assertEqual("2", self.tdb.text["bloe"])
+
+ def test_transaction_commit(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb.text["bloe"] = "1"
+ self.tdb.transaction_commit()
+ self.assertEqual("1", self.tdb.text["bloe"])
+
+ def test_transaction_prepare_commit(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb.text["bloe"] = "1"
+ self.tdb.transaction_prepare_commit()
+ self.tdb.transaction_commit()
+ self.assertEqual("1", self.tdb.text["bloe"])
+
+ def test_iterkeys(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.text["bla"] = "25"
+ if sys.version_info >= (3, 0):
+ i = self.tdb.text.keys()
+ else:
+ i = self.tdb.text.iterkeys()
+ self.assertEqual(set(["bloe", "bla"]), set([next(i), next(i)]))
+
+ def test_clear(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.text["bla"] = "25"
+ self.assertEqual(2, len(list(self.tdb)))
+ self.tdb.clear()
+ self.assertEqual(0, len(list(self.tdb)))
+
+ def test_repack(self):
+ self.tdb.text["foo"] = "abc"
+ self.tdb.text["bar"] = "def"
+ del self.tdb.text["foo"]
+ self.tdb.repack()
+
+ def test_len(self):
+ self.assertEqual(0, len(list(self.tdb.text)))
+ self.tdb.text["entry"] = "value"
+ self.assertEqual(1, len(list(self.tdb.text)))
+
+ def test_text_and_binary(self):
+ text = u'\xfa\u0148\xef\xe7\xf8\xf0\xea'
+ bytestr = text.encode('utf-8')
+ self.tdb[b"entry"] = bytestr
+ self.tdb.text[u"entry2"] = text
+ self.assertEqual(self.tdb.text["entry"], text)
+ self.assertEqual(self.tdb[b"entry2"], bytestr)
+ assert self.tdb.text.raw == self.tdb
+
+
+class VersionTests(TestCase):
+
+ def test_present(self):
+ self.assertTrue(isinstance(tdb.__version__, str))
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.TestProgram()
diff --git a/lib/tdb/tdb.pc.in b/lib/tdb/tdb.pc.in
new file mode 100644
index 0000000..b78419e
--- /dev/null
+++ b/lib/tdb/tdb.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: tdb
+Description: A trivial database
+Version: @PACKAGE_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -ltdb
+Cflags: -I${includedir}
+URL: http://tdb.samba.org/
diff --git a/lib/tdb/test/circular_chain.tdb b/lib/tdb/test/circular_chain.tdb
new file mode 100644
index 0000000..1e143d3
--- /dev/null
+++ b/lib/tdb/test/circular_chain.tdb
Binary files differ
diff --git a/lib/tdb/test/circular_freelist.tdb b/lib/tdb/test/circular_freelist.tdb
new file mode 100644
index 0000000..f1c85e5
--- /dev/null
+++ b/lib/tdb/test/circular_freelist.tdb
Binary files differ
diff --git a/lib/tdb/test/external-agent.c b/lib/tdb/test/external-agent.c
new file mode 100644
index 0000000..3c59c06
--- /dev/null
+++ b/lib/tdb/test/external-agent.c
@@ -0,0 +1,224 @@
+#include "external-agent.h"
+#include "lock-tracking.h"
+#include "logging.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include "../common/tdb_private.h"
+#include "tap-interface.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+static struct tdb_context *tdb;
+
+static enum agent_return do_operation(enum operation op, const char *name)
+{
+ TDB_DATA k;
+ enum agent_return ret;
+ TDB_DATA data;
+
+ if (op != OPEN && op != OPEN_WITH_CLEAR_IF_FIRST && !tdb) {
+ diag("external: No tdb open!");
+ return OTHER_FAILURE;
+ }
+
+ k.dptr = discard_const_p(uint8_t, name);
+ k.dsize = strlen(name);
+
+ locking_would_block = 0;
+ switch (op) {
+ case OPEN:
+ if (tdb) {
+ diag("Already have tdb %s open", tdb_name(tdb));
+ return OTHER_FAILURE;
+ }
+ tdb = tdb_open_ex(name, 0, TDB_DEFAULT, O_RDWR, 0,
+ &taplogctx, NULL);
+ if (!tdb) {
+ if (!locking_would_block)
+ diag("Opening tdb gave %s", strerror(errno));
+ ret = OTHER_FAILURE;
+ } else
+ ret = SUCCESS;
+ break;
+ case OPEN_WITH_CLEAR_IF_FIRST:
+ if (tdb)
+ return OTHER_FAILURE;
+ tdb = tdb_open_ex(name, 0, TDB_CLEAR_IF_FIRST, O_RDWR, 0,
+ &taplogctx, NULL);
+ ret = tdb ? SUCCESS : OTHER_FAILURE;
+ break;
+ case TRANSACTION_START:
+ ret = tdb_transaction_start(tdb) == 0 ? SUCCESS : OTHER_FAILURE;
+ break;
+ case FETCH:
+ data = tdb_fetch(tdb, k);
+ if (data.dptr == NULL) {
+ if (tdb_error(tdb) == TDB_ERR_NOEXIST)
+ ret = FAILED;
+ else
+ ret = OTHER_FAILURE;
+ } else if (data.dsize != k.dsize
+ || memcmp(data.dptr, k.dptr, k.dsize) != 0) {
+ ret = OTHER_FAILURE;
+ } else {
+ ret = SUCCESS;
+ }
+ free(data.dptr);
+ break;
+ case STORE:
+ ret = tdb_store(tdb, k, k, 0) == 0 ? SUCCESS : OTHER_FAILURE;
+ break;
+ case TRANSACTION_COMMIT:
+ ret = tdb_transaction_commit(tdb)==0 ? SUCCESS : OTHER_FAILURE;
+ break;
+ case CHECK:
+ ret = tdb_check(tdb, NULL, NULL) == 0 ? SUCCESS : OTHER_FAILURE;
+ break;
+ case NEEDS_RECOVERY:
+ ret = tdb_needs_recovery(tdb) ? SUCCESS : FAILED;
+ break;
+ case CLOSE:
+ ret = tdb_close(tdb) == 0 ? SUCCESS : OTHER_FAILURE;
+ tdb = NULL;
+ break;
+ case PING:
+ ret = SUCCESS;
+ break;
+ case UNMAP:
+ ret = tdb_munmap(tdb) == 0 ? SUCCESS : OTHER_FAILURE;
+ if (ret == SUCCESS) {
+ tdb->flags |= TDB_NOMMAP;
+ }
+ break;
+ default:
+ ret = OTHER_FAILURE;
+ }
+
+ if (locking_would_block)
+ ret = WOULD_HAVE_BLOCKED;
+
+ return ret;
+}
+
+struct agent {
+ int cmdfd, responsefd;
+ pid_t pid;
+};
+
+/* Do this before doing any tdb stuff. Return handle, or NULL. */
+struct agent *prepare_external_agent(void)
+{
+ int ret;
+ int command[2], response[2];
+ char name[1+PATH_MAX];
+ struct agent *agent = malloc(sizeof(*agent));
+
+ if (pipe(command) != 0 || pipe(response) != 0) {
+ fprintf(stderr, "pipe failed: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ agent->pid = fork();
+ if (agent->pid < 0) {
+ fprintf(stderr, "fork failed: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (agent->pid != 0) {
+ close(command[0]);
+ close(response[1]);
+ agent->cmdfd = command[1];
+ agent->responsefd = response[0];
+ return agent;
+ }
+
+ close(command[1]);
+ close(response[0]);
+
+ /* We want to fail, not block. */
+ nonblocking_locks = true;
+ log_prefix = "external: ";
+ while ((ret = read(command[0], name, sizeof(name))) > 0) {
+ enum agent_return result;
+
+ result = do_operation(name[0], name+1);
+ if (write(response[1], &result, sizeof(result))
+ != sizeof(result))
+ abort();
+ }
+ exit(0);
+}
+
+void shutdown_agent(struct agent *agent)
+{
+ pid_t p;
+
+ close(agent->cmdfd);
+ close(agent->responsefd);
+ p = waitpid(agent->pid, NULL, WNOHANG);
+ if (p == 0) {
+ kill(agent->pid, SIGKILL);
+ }
+ waitpid(agent->pid, NULL, 0);
+ free(agent);
+}
+
+/* Ask the external agent to try to do an operation. */
+enum agent_return external_agent_operation(struct agent *agent,
+ enum operation op,
+ const char *name)
+{
+ enum agent_return res;
+ unsigned int len;
+ char *string;
+
+ if (!name)
+ name = "";
+ len = 1 + strlen(name) + 1;
+ string = malloc(len);
+
+ string[0] = op;
+ strncpy(string+1, name, len - 1);
+ string[len-1] = '\0';
+
+ if (write(agent->cmdfd, string, len) != len
+ || read(agent->responsefd, &res, sizeof(res)) != sizeof(res))
+ res = AGENT_DIED;
+
+ free(string);
+ return res;
+}
+
+const char *agent_return_name(enum agent_return ret)
+{
+ return ret == SUCCESS ? "SUCCESS"
+ : ret == WOULD_HAVE_BLOCKED ? "WOULD_HAVE_BLOCKED"
+ : ret == AGENT_DIED ? "AGENT_DIED"
+ : ret == FAILED ? "FAILED"
+ : ret == OTHER_FAILURE ? "OTHER_FAILURE"
+ : "**INVALID**";
+}
+
+const char *operation_name(enum operation op)
+{
+ switch (op) {
+ case OPEN: return "OPEN";
+ case OPEN_WITH_CLEAR_IF_FIRST: return "OPEN_WITH_CLEAR_IF_FIRST";
+ case TRANSACTION_START: return "TRANSACTION_START";
+ case FETCH: return "FETCH";
+ case STORE: return "STORE";
+ case TRANSACTION_COMMIT: return "TRANSACTION_COMMIT";
+ case CHECK: return "CHECK";
+ case NEEDS_RECOVERY: return "NEEDS_RECOVERY";
+ case CLOSE: return "CLOSE";
+ case PING: return "PING";
+ case UNMAP: return "UNMAP";
+ }
+ return "**INVALID**";
+}
diff --git a/lib/tdb/test/external-agent.h b/lib/tdb/test/external-agent.h
new file mode 100644
index 0000000..de9d0ac
--- /dev/null
+++ b/lib/tdb/test/external-agent.h
@@ -0,0 +1,44 @@
+#ifndef TDB_TEST_EXTERNAL_AGENT_H
+#define TDB_TEST_EXTERNAL_AGENT_H
+
+/* For locking tests, we need a different process to try things at
+ * various times. */
+enum operation {
+ OPEN,
+ OPEN_WITH_CLEAR_IF_FIRST,
+ TRANSACTION_START,
+ FETCH,
+ STORE,
+ TRANSACTION_COMMIT,
+ CHECK,
+ NEEDS_RECOVERY,
+ CLOSE,
+ PING,
+ UNMAP,
+};
+
+/* Do this before doing any tdb stuff. Return handle, or -1. */
+struct agent *prepare_external_agent(void);
+void shutdown_agent(struct agent *agent);
+
+enum agent_return {
+ SUCCESS,
+ WOULD_HAVE_BLOCKED,
+ AGENT_DIED,
+ FAILED, /* For fetch, or NEEDS_RECOVERY */
+ OTHER_FAILURE,
+};
+
+/* Ask the external agent to try to do an operation.
+ * name == tdb name for OPEN/OPEN_WITH_CLEAR_IF_FIRST,
+ * record name for FETCH/STORE (store stores name as data too)
+ */
+enum agent_return external_agent_operation(struct agent *handle,
+ enum operation op,
+ const char *name);
+
+/* Mapping enum -> string. */
+const char *agent_return_name(enum agent_return ret);
+const char *operation_name(enum operation op);
+
+#endif /* TDB_TEST_EXTERNAL_AGENT_H */
diff --git a/lib/tdb/test/jenkins-be-hash.tdb b/lib/tdb/test/jenkins-be-hash.tdb
new file mode 100644
index 0000000..b652840
--- /dev/null
+++ b/lib/tdb/test/jenkins-be-hash.tdb
Binary files differ
diff --git a/lib/tdb/test/jenkins-le-hash.tdb b/lib/tdb/test/jenkins-le-hash.tdb
new file mode 100644
index 0000000..007e0a3
--- /dev/null
+++ b/lib/tdb/test/jenkins-le-hash.tdb
Binary files differ
diff --git a/lib/tdb/test/lock-tracking.c b/lib/tdb/test/lock-tracking.c
new file mode 100644
index 0000000..fb7706e
--- /dev/null
+++ b/lib/tdb/test/lock-tracking.c
@@ -0,0 +1,157 @@
+/* We save the locks so we can reacquire them. */
+#include "../common/tdb_private.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "tap-interface.h"
+#include "lock-tracking.h"
+
+struct testlock {
+ struct testlock *next;
+ unsigned int off;
+ unsigned int len;
+ int type;
+};
+static struct testlock *testlocks;
+int locking_errors = 0;
+bool suppress_lockcheck = false;
+bool nonblocking_locks;
+int locking_would_block = 0;
+void (*unlock_callback)(int fd);
+
+int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ )
+{
+ va_list ap;
+ int ret, arg3;
+ struct flock *fl;
+ bool may_block = false;
+
+ if (cmd != F_SETLK && cmd != F_SETLKW) {
+ /* This may be totally bogus, but we don't know in general. */
+ va_start(ap, cmd);
+ arg3 = va_arg(ap, int);
+ va_end(ap);
+
+ return fcntl(fd, cmd, arg3);
+ }
+
+ va_start(ap, cmd);
+ fl = va_arg(ap, struct flock *);
+ va_end(ap);
+
+ if (cmd == F_SETLKW && nonblocking_locks) {
+ cmd = F_SETLK;
+ may_block = true;
+ }
+ ret = fcntl(fd, cmd, fl);
+
+ /* Detect when we failed, but might have been OK if we waited. */
+ if (may_block && ret == -1 && (errno == EAGAIN || errno == EACCES)) {
+ locking_would_block++;
+ }
+
+ if (fl->l_type == F_UNLCK) {
+ struct testlock **l;
+ struct testlock *old = NULL;
+
+ for (l = &testlocks; *l; l = &(*l)->next) {
+ if ((*l)->off == fl->l_start
+ && (*l)->len == fl->l_len) {
+ if (ret == 0) {
+ old = *l;
+ *l = (*l)->next;
+ free(old);
+ }
+ break;
+ }
+ if (((*l)->off == fl->l_start)
+ && ((*l)->len == 0)
+ && (ret == 0)) {
+ /*
+ * Remove a piece from the start of the
+ * allrecord_lock
+ */
+ old = *l;
+ (*l)->off += fl->l_len;
+ break;
+ }
+ }
+ if (!old && !suppress_lockcheck) {
+ diag("Unknown unlock %u@%u - %i",
+ (int)fl->l_len, (int)fl->l_start, ret);
+ locking_errors++;
+ }
+ } else {
+ struct testlock *new, *i;
+ unsigned int fl_end = fl->l_start + fl->l_len;
+ if (fl->l_len == 0)
+ fl_end = (unsigned int)-1;
+
+ /* Check for overlaps: we shouldn't do this. */
+ for (i = testlocks; i; i = i->next) {
+ unsigned int i_end = i->off + i->len;
+ if (i->len == 0)
+ i_end = (unsigned int)-1;
+
+ if (fl->l_start >= i->off && fl->l_start < i_end)
+ break;
+ if (fl_end >= i->off && fl_end < i_end)
+ break;
+
+ /* tdb_allrecord_lock does this, handle adjacent: */
+ if (fl->l_start == i_end && fl->l_type == i->type) {
+ if (ret == 0) {
+ i->len = fl->l_len
+ ? i->len + fl->l_len
+ : 0;
+ }
+ goto done;
+ }
+ }
+ if (i) {
+ /* Special case: upgrade of allrecord lock. */
+ if (i->type == F_RDLCK && fl->l_type == F_WRLCK
+ && i->off == FREELIST_TOP
+ && fl->l_start == FREELIST_TOP
+ && i->len == 0
+ && fl->l_len == 0) {
+ if (ret == 0)
+ i->type = F_WRLCK;
+ goto done;
+ }
+ if (!suppress_lockcheck) {
+ diag("%s testlock %u@%u overlaps %u@%u",
+ fl->l_type == F_WRLCK ? "write" : "read",
+ (int)fl->l_len, (int)fl->l_start,
+ i->len, (int)i->off);
+ locking_errors++;
+ }
+ }
+
+ if (ret == 0) {
+ new = malloc(sizeof *new);
+ new->off = fl->l_start;
+ new->len = fl->l_len;
+ new->type = fl->l_type;
+ new->next = testlocks;
+ testlocks = new;
+ }
+ }
+done:
+ if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback)
+ unlock_callback(fd);
+ return ret;
+}
+
+unsigned int forget_locking(void)
+{
+ unsigned int num = 0;
+ while (testlocks) {
+ struct testlock *next = testlocks->next;
+ free(testlocks);
+ testlocks = next;
+ num++;
+ }
+ return num;
+}
diff --git a/lib/tdb/test/lock-tracking.h b/lib/tdb/test/lock-tracking.h
new file mode 100644
index 0000000..f2c9c44
--- /dev/null
+++ b/lib/tdb/test/lock-tracking.h
@@ -0,0 +1,25 @@
+#ifndef LOCK_TRACKING_H
+#define LOCK_TRACKING_H
+#include <stdbool.h>
+
+/* Set this if you want a callback after fnctl unlock. */
+extern void (*unlock_callback)(int fd);
+
+/* Replacement fcntl. */
+int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ );
+
+/* Discard locking info: returns number of locks outstanding. */
+unsigned int forget_locking(void);
+
+/* Number of errors in locking. */
+extern int locking_errors;
+
+/* Suppress lock checking. */
+extern bool suppress_lockcheck;
+
+/* Make all locks non-blocking. */
+extern bool nonblocking_locks;
+
+/* Number of times we failed a lock because we made it non-blocking. */
+extern int locking_would_block;
+#endif /* LOCK_TRACKING_H */
diff --git a/lib/tdb/test/logging.c b/lib/tdb/test/logging.c
new file mode 100644
index 0000000..dfab486
--- /dev/null
+++ b/lib/tdb/test/logging.c
@@ -0,0 +1,33 @@
+#include "logging.h"
+#include "tap-interface.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+bool suppress_logging = false;
+const char *log_prefix = "";
+
+/* Turn log messages into tap diag messages. */
+static void taplog(struct tdb_context *tdb,
+ enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char line[200];
+
+ if (suppress_logging)
+ return;
+
+ va_start(ap, fmt);
+ vsprintf(line, fmt, ap);
+ va_end(ap);
+
+ /* Strip trailing \n: diag adds it. */
+ if (line[0] && line[strlen(line)-1] == '\n')
+ diag("%s%.*s", log_prefix, (unsigned)strlen(line)-1, line);
+ else
+ diag("%s%s", log_prefix, line);
+}
+
+struct tdb_logging_context taplogctx = { taplog, NULL };
diff --git a/lib/tdb/test/logging.h b/lib/tdb/test/logging.h
new file mode 100644
index 0000000..89e77b2
--- /dev/null
+++ b/lib/tdb/test/logging.h
@@ -0,0 +1,11 @@
+#ifndef TDB_TEST_LOGGING_H
+#define TDB_TEST_LOGGING_H
+#include "replace.h"
+#include "../include/tdb.h"
+#include <stdbool.h>
+
+extern bool suppress_logging;
+extern const char *log_prefix;
+extern struct tdb_logging_context taplogctx;
+
+#endif /* TDB_TEST_LOGGING_H */
diff --git a/lib/tdb/test/old-nohash-be.tdb b/lib/tdb/test/old-nohash-be.tdb
new file mode 100644
index 0000000..1c49116
--- /dev/null
+++ b/lib/tdb/test/old-nohash-be.tdb
Binary files differ
diff --git a/lib/tdb/test/old-nohash-le.tdb b/lib/tdb/test/old-nohash-le.tdb
new file mode 100644
index 0000000..0655072
--- /dev/null
+++ b/lib/tdb/test/old-nohash-le.tdb
Binary files differ
diff --git a/lib/tdb/test/run-3G-file.c b/lib/tdb/test/run-3G-file.c
new file mode 100644
index 0000000..79e291b
--- /dev/null
+++ b/lib/tdb/test/run-3G-file.c
@@ -0,0 +1,145 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+static int tdb_expand_file_sparse(struct tdb_context *tdb,
+ tdb_off_t size,
+ tdb_off_t addition)
+{
+ if (tdb->read_only || tdb->traverse_read) {
+ tdb->ecode = TDB_ERR_RDONLY;
+ return -1;
+ }
+
+ if (tdb_ftruncate(tdb, size+addition) == -1) {
+ char b = 0;
+ ssize_t written = tdb_pwrite(tdb, &b, 1, (size+addition) - 1);
+ if (written == 0) {
+ /* try once more, potentially revealing errno */
+ written = tdb_pwrite(tdb, &b, 1, (size+addition) - 1);
+ }
+ if (written == 0) {
+ /* again - give up, guessing errno */
+ errno = ENOSPC;
+ }
+ if (written != 1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n",
+ size+addition, strerror(errno)));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static const struct tdb_methods large_io_methods = {
+ tdb_read,
+ tdb_write,
+ tdb_next_hash_chain,
+ tdb_notrans_oob,
+ tdb_expand_file_sparse
+};
+
+static int test_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *_data)
+{
+ TDB_DATA *expect = _data;
+ ok1(key.dsize == strlen("hi"));
+ ok1(memcmp(key.dptr, "hi", strlen("hi")) == 0);
+ ok1(data.dsize == expect->dsize);
+ ok1(memcmp(data.dptr, expect->dptr, data.dsize) == 0);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, orig_data, data;
+ uint32_t hashval;
+ tdb_off_t rec_ptr;
+ struct tdb_record rec;
+ int ret;
+
+ plan_tests(24);
+ tdb = tdb_open_ex("run-36-file.tdb", 1024, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ ok1(tdb);
+ tdb->methods = &large_io_methods;
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ orig_data.dsize = strlen("world");
+ orig_data.dptr = discard_const_p(uint8_t, "world");
+
+ /* Enlarge the file (internally multiplies by 2). */
+ ret = tdb_expand(tdb, 1500000000);
+#ifdef HAVE_INCOHERENT_MMAP
+ /* This can fail due to mmap failure on 32 bit systems. */
+ if (ret == -1) {
+ /* These should now fail. */
+ ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == -1);
+ data = tdb_fetch(tdb, key);
+ ok1(data.dptr == NULL);
+ ok1(tdb_traverse(tdb, test_traverse, &orig_data) == -1);
+ ok1(tdb_delete(tdb, key) == -1);
+ ok1(tdb_traverse(tdb, test_traverse, NULL) == -1);
+ /* Skip the rest... */
+ for (ret = 0; ret < 24 - 6; ret++)
+ ok1(1);
+ tdb_close(tdb);
+ return exit_status();
+ }
+#endif
+ ok1(ret == 0);
+
+ /* Put an entry in, and check it. */
+ ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == 0);
+
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+
+ /* That currently fills at the end, make sure that's true. */
+ hashval = tdb->hash_fn(&key);
+ rec_ptr = tdb_find_lock_hash(tdb, key, hashval, F_RDLCK, &rec);
+ ok1(rec_ptr);
+ ok1(rec_ptr > 2U*1024*1024*1024);
+ tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
+
+ /* Traverse must work. */
+ ok1(tdb_traverse(tdb, test_traverse, &orig_data) == 1);
+
+ /* Delete should work. */
+ ok1(tdb_delete(tdb, key) == 0);
+
+ ok1(tdb_traverse(tdb, test_traverse, NULL) == 0);
+
+ /* Transactions should work. */
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == 0);
+
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+ ok1(tdb_transaction_commit(tdb) == 0);
+
+ ok1(tdb_traverse(tdb, test_traverse, &orig_data) == 1);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-allrecord-traverse-deadlock.c b/lib/tdb/test/run-allrecord-traverse-deadlock.c
new file mode 100644
index 0000000..2c58206
--- /dev/null
+++ b/lib/tdb/test/run-allrecord-traverse-deadlock.c
@@ -0,0 +1,203 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+#include "logging.h"
+
+static void do_allrecord_lock(const char *name, int tdb_flags, int up,
+ int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_lockall(tdb);
+ ok(ret == 0, "tdb_lockall should succeed");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ ret = tdb_traverse(tdb, NULL, NULL);
+ ok(ret == -1, "do_allrecord_lock: traverse should fail");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ exit(0);
+}
+
+static void do_traverse(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_traverse(tdb, NULL, NULL);
+ ok(ret == 1, "do_traverse: tdb_traverse should return 1 record");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ exit(0);
+}
+
+/*
+ * Process 1: get the allrecord_lock on a tdb.
+ * Process 2: start a traverse, this will stall waiting for the
+ * first chainlock: That is taken by the allrecord_lock
+ * Process 1: start a traverse: This will get EDEADLK in trying to
+ * get the TRANSACTION_LOCK. It will deadlock for mutexes,
+ * which don't have built-in deadlock detection.
+ */
+
+static int do_tests(const char *name, int tdb_flags)
+{
+ struct tdb_context *tdb;
+ int ret;
+ pid_t traverse_child, allrecord_child;
+ int traverse_down[2];
+ int traverse_up[2];
+ int allrecord_down[2];
+ int allrecord_up[2];
+ char c;
+ ssize_t nread, nwritten;
+ TDB_DATA key, data;
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_store(tdb, key, data, TDB_INSERT);
+ ok(ret == 0, "tdb_store should succeed");
+
+ ret = pipe(traverse_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(traverse_up);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(allrecord_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(allrecord_up);
+ ok(ret == 0, "pipe should succeed");
+
+ allrecord_child = fork();
+ ok(allrecord_child != -1, "fork should succeed");
+
+ if (allrecord_child == 0) {
+ tdb_close(tdb);
+ close(traverse_up[0]);
+ close(traverse_up[1]);
+ close(traverse_down[0]);
+ close(traverse_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ do_allrecord_lock(name, tdb_flags,
+ allrecord_up[1], allrecord_down[0]);
+ exit(0);
+ }
+ close(allrecord_up[1]);
+ close(allrecord_down[0]);
+
+ nread = read(allrecord_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ traverse_child = fork();
+ ok(traverse_child != -1, "fork should succeed");
+
+ if (traverse_child == 0) {
+ tdb_close(tdb);
+ close(traverse_up[0]);
+ close(traverse_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ do_traverse(name, tdb_flags,
+ traverse_up[1], traverse_down[0]);
+ exit(0);
+ }
+ close(traverse_up[1]);
+ close(traverse_down[0]);
+
+ poll(NULL, 0, 1000);
+
+ nwritten = write(allrecord_down[1], &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(traverse_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ nwritten = write(traverse_down[1], &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(allrecord_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "ret should succeed");
+
+ close(traverse_up[0]);
+ close(traverse_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ diag("%s tests done", name);
+ return exit_status();
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ bool mutex_support;
+
+ mutex_support = tdb_runtime_check_for_robust_mutexes();
+
+ ret = do_tests("marklock-deadlock-fcntl.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "marklock-deadlock-fcntl.tdb tests should succeed");
+
+ if (!mutex_support) {
+ skip(1, "No robust mutex support, "
+ "skipping marklock-deadlock-mutex.tdb tests");
+ return exit_status();
+ }
+
+ ret = do_tests("marklock-deadlock-mutex.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_MUTEX_LOCKING |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "marklock-deadlock-mutex.tdb tests should succeed");
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-bad-tdb-header.c b/lib/tdb/test/run-bad-tdb-header.c
new file mode 100644
index 0000000..9d29fdf
--- /dev/null
+++ b/lib/tdb/test/run-bad-tdb-header.c
@@ -0,0 +1,59 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ struct tdb_header hdr;
+ int fd;
+
+ plan_tests(11);
+ /* Can open fine if complete crap, as long as O_CREAT. */
+ fd = open("run-bad-tdb-header.tdb", O_RDWR|O_CREAT|O_TRUNC, 0600);
+ ok1(fd >= 0);
+ ok1(write(fd, "hello world", 11) == 11);
+ close(fd);
+ tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(!tdb);
+ tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_CREAT|O_RDWR,
+ 0600, &taplogctx, NULL);
+ ok1(tdb);
+ tdb_close(tdb);
+
+ /* Now, with wrong version it should *not* overwrite. */
+ fd = open("run-bad-tdb-header.tdb", O_RDWR);
+ ok1(fd >= 0);
+ ok1(read(fd, &hdr, sizeof(hdr)) == sizeof(hdr));
+ ok1(hdr.version == TDB_VERSION);
+ hdr.version++;
+ lseek(fd, 0, SEEK_SET);
+ ok1(write(fd, &hdr, sizeof(hdr)) == sizeof(hdr));
+ close(fd);
+
+ tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_RDWR|O_CREAT,
+ 0600, &taplogctx, NULL);
+ ok1(errno == EIO);
+ ok1(!tdb);
+
+ /* With truncate, will be fine. */
+ tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0,
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &taplogctx, NULL);
+ ok1(tdb);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-check.c b/lib/tdb/test/run-check.c
new file mode 100644
index 0000000..ce389a2
--- /dev/null
+++ b/lib/tdb/test/run-check.c
@@ -0,0 +1,65 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(13);
+ tdb = tdb_open_ex("run-check.tdb", 1, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("run-check.tdb", 1024, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("test/tdb.corrupt", 1024, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == -1);
+ ok1(tdb_error(tdb) == TDB_ERR_CORRUPT);
+ tdb_close(tdb);
+
+ /* Big and little endian should work! */
+ tdb = tdb_open_ex("test/old-nohash-le.tdb", 1024, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("test/old-nohash-be.tdb", 1024, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-circular-chain.c b/lib/tdb/test/run-circular-chain.c
new file mode 100644
index 0000000..4fb32a2
--- /dev/null
+++ b/lib/tdb/test/run-circular-chain.c
@@ -0,0 +1,42 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key;
+
+ plan_tests(3);
+ tdb = tdb_open_ex(
+ "test/circular_chain.tdb",
+ 0,
+ TDB_DEFAULT,
+ O_RDONLY,
+ 0600,
+ &taplogctx,
+ NULL);
+
+ ok1(tdb);
+ key.dsize = strlen("x");
+ key.dptr = discard_const_p(uint8_t, "x");
+
+ ok1(tdb_exists(tdb, key) == 0);
+ ok1(tdb_error(tdb) == TDB_ERR_CORRUPT);
+
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-circular-freelist.c b/lib/tdb/test/run-circular-freelist.c
new file mode 100644
index 0000000..f1bec87
--- /dev/null
+++ b/lib/tdb/test/run-circular-freelist.c
@@ -0,0 +1,50 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(3);
+ tdb = tdb_open_ex(
+ "test/circular_freelist.tdb",
+ 0,
+ TDB_DEFAULT,
+ O_RDWR,
+ 0600,
+ &taplogctx,
+ NULL);
+
+ ok1(tdb);
+
+ /*
+ * All freelist records are just 1 byte key and value. Insert
+ * something that will walk the whole freelist and hit the
+ * circle.
+ */
+ key.dsize = strlen("x");
+ key.dptr = discard_const_p(uint8_t, "x");
+ data.dsize = strlen("too long");
+ data.dptr = discard_const_p(uint8_t, "too long");
+
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == -1);
+ ok1(tdb_error(tdb) == TDB_ERR_CORRUPT);
+
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-corrupt.c b/lib/tdb/test/run-corrupt.c
new file mode 100644
index 0000000..e6fc751
--- /dev/null
+++ b/lib/tdb/test/run-corrupt.c
@@ -0,0 +1,132 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+static int check(TDB_DATA key, TDB_DATA data, void *private)
+{
+ unsigned int *sizes = private;
+
+ if (key.dsize > strlen("hello"))
+ return -1;
+ if (memcmp(key.dptr, "hello", key.dsize) != 0)
+ return -1;
+
+ if (data.dsize != strlen("world"))
+ return -1;
+ if (memcmp(data.dptr, "world", data.dsize) != 0)
+ return -1;
+
+ sizes[0] += key.dsize;
+ sizes[1] += data.dsize;
+ return 0;
+}
+
+static void tdb_flip_bit(struct tdb_context *tdb, unsigned int bit)
+{
+ unsigned int off = bit / CHAR_BIT;
+ unsigned char mask = (1 << (bit % CHAR_BIT));
+
+ if (tdb->map_ptr)
+ ((unsigned char *)tdb->map_ptr)[off] ^= mask;
+ else {
+ unsigned char c;
+ if (pread(tdb->fd, &c, 1, off) != 1) {
+ fprintf(stderr, "pread: %s\n", strerror(errno));
+ exit(1);
+ }
+ c ^= mask;
+ if (pwrite(tdb->fd, &c, 1, off) != 1) {
+ fprintf(stderr, "pwrite: %s\n", strerror(errno));
+ exit(1);
+ }
+ }
+}
+
+static void check_test(struct tdb_context *tdb)
+{
+ TDB_DATA key, data;
+ unsigned int i, verifiable, corrupt, sizes[2], dsize, ksize;
+
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ key.dptr = discard_const_p(uint8_t, "hello");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ /* Key and data size respectively. */
+ dsize = ksize = 0;
+
+ /* 5 keys in hash size 2 means we'll have multichains. */
+ for (key.dsize = 1; key.dsize <= 5; key.dsize++) {
+ ksize += key.dsize;
+ dsize += data.dsize;
+ if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
+ abort();
+ }
+
+ /* This is how many bytes we expect to be verifiable. */
+ /* From the file header. */
+ verifiable = strlen(TDB_MAGIC_FOOD) + 1
+ + 2 * sizeof(uint32_t) + 2 * sizeof(tdb_off_t)
+ + 2 * sizeof(uint32_t);
+ /* From the free list chain and hash chains. */
+ verifiable += 3 * sizeof(tdb_off_t);
+ /* From the record headers & tailer */
+ verifiable += 5 * (sizeof(struct tdb_record) + sizeof(uint32_t));
+ /* The free block: we ignore datalen, keylen, full_hash. */
+ verifiable += sizeof(struct tdb_record) - 3*sizeof(uint32_t) +
+ sizeof(uint32_t);
+ /* Our check function verifies the key and data. */
+ verifiable += ksize + dsize;
+
+ /* Flip one bit at a time, make sure it detects verifiable bytes. */
+ for (i = 0, corrupt = 0; i < tdb->map_size * CHAR_BIT; i++) {
+ tdb_flip_bit(tdb, i);
+ memset(sizes, 0, sizeof(sizes));
+ if (tdb_check(tdb, check, sizes) != 0)
+ corrupt++;
+ else if (sizes[0] != ksize || sizes[1] != dsize)
+ corrupt++;
+ tdb_flip_bit(tdb, i);
+ }
+ ok(corrupt == verifiable * CHAR_BIT, "corrupt %u should be %u",
+ corrupt, verifiable * CHAR_BIT);
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+
+ plan_tests(4);
+ /* This should use mmap. */
+ tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ if (!tdb)
+ abort();
+ check_test(tdb);
+ tdb_close(tdb);
+
+ /* This should not. */
+ tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST|TDB_NOMMAP,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ if (!tdb)
+ abort();
+ check_test(tdb);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-die-during-transaction.c b/lib/tdb/test/run-die-during-transaction.c
new file mode 100644
index 0000000..c636d87
--- /dev/null
+++ b/lib/tdb/test/run-die-during-transaction.c
@@ -0,0 +1,232 @@
+#include "../common/tdb_private.h"
+#include "lock-tracking.h"
+static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
+static ssize_t write_check(int fd, const void *buf, size_t count);
+static int ftruncate_check(int fd, off_t length);
+
+#define pwrite pwrite_check
+#define write write_check
+#define fcntl fcntl_with_lockcheck
+#define ftruncate ftruncate_check
+
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include "external-agent.h"
+#include "logging.h"
+
+#undef write
+#undef pwrite
+#undef fcntl
+#undef ftruncate
+
+static bool in_transaction;
+static int target, current;
+static jmp_buf jmpbuf;
+#define TEST_DBNAME "run-die-during-transaction.tdb"
+#define KEY_STRING "helloworld"
+
+static void maybe_die(int fd)
+{
+ if (in_transaction && current++ == target) {
+ longjmp(jmpbuf, 1);
+ }
+}
+
+static ssize_t pwrite_check(int fd,
+ const void *buf, size_t count, off_t offset)
+{
+ ssize_t ret;
+
+ maybe_die(fd);
+
+ ret = pwrite(fd, buf, count, offset);
+ if (ret != count)
+ return ret;
+
+ maybe_die(fd);
+ return ret;
+}
+
+static ssize_t write_check(int fd, const void *buf, size_t count)
+{
+ ssize_t ret;
+
+ maybe_die(fd);
+
+ ret = write(fd, buf, count);
+ if (ret != count)
+ return ret;
+
+ maybe_die(fd);
+ return ret;
+}
+
+static int ftruncate_check(int fd, off_t length)
+{
+ int ret;
+
+ maybe_die(fd);
+
+ ret = ftruncate(fd, length);
+
+ maybe_die(fd);
+ return ret;
+}
+
+static bool test_death(enum operation op, struct agent *agent)
+{
+ struct tdb_context *tdb = NULL;
+ TDB_DATA key;
+ enum agent_return ret;
+ int needed_recovery = 0;
+
+ current = target = 0;
+reset:
+ unlink(TEST_DBNAME);
+ tdb = tdb_open_ex(TEST_DBNAME, 1024, TDB_NOMMAP,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ if (setjmp(jmpbuf) != 0) {
+ /* We're partway through. Simulate our death. */
+ close(tdb->fd);
+ forget_locking();
+ in_transaction = false;
+
+ ret = external_agent_operation(agent, NEEDS_RECOVERY, "");
+ if (ret == SUCCESS)
+ needed_recovery++;
+ else if (ret != FAILED) {
+ diag("Step %u agent NEEDS_RECOVERY = %s", current,
+ agent_return_name(ret));
+ return false;
+ }
+
+ ret = external_agent_operation(agent, op, KEY_STRING);
+ if (ret != SUCCESS) {
+ diag("Step %u op %s failed = %s", current,
+ operation_name(op),
+ agent_return_name(ret));
+ return false;
+ }
+
+ ret = external_agent_operation(agent, NEEDS_RECOVERY, "");
+ if (ret != FAILED) {
+ diag("Still needs recovery after step %u = %s",
+ current, agent_return_name(ret));
+ return false;
+ }
+
+ ret = external_agent_operation(agent, CHECK, "");
+ if (ret != SUCCESS) {
+ diag("Step %u check failed = %s", current,
+ agent_return_name(ret));
+ return false;
+ }
+
+ ret = external_agent_operation(agent, CLOSE, "");
+ if (ret != SUCCESS) {
+ diag("Step %u close failed = %s", current,
+ agent_return_name(ret));
+ return false;
+ }
+
+ /* Suppress logging as this tries to use closed fd. */
+ suppress_logging = true;
+ suppress_lockcheck = true;
+ tdb_close(tdb);
+ suppress_logging = false;
+ suppress_lockcheck = false;
+ target++;
+ current = 0;
+ goto reset;
+ }
+
+ /* Put key for agent to fetch. */
+ key.dsize = strlen(KEY_STRING);
+ key.dptr = discard_const_p(uint8_t, KEY_STRING);
+ if (tdb_store(tdb, key, key, TDB_INSERT) != 0)
+ return false;
+
+ /* This is the key we insert in transaction. */
+ key.dsize--;
+
+ ret = external_agent_operation(agent, OPEN, TEST_DBNAME);
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed to open: %s\n",
+ agent_return_name(ret));
+ exit(1);
+ }
+
+ ret = external_agent_operation(agent, FETCH, KEY_STRING);
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed find key: %s\n",
+ agent_return_name(ret));
+ exit(1);
+ }
+
+ in_transaction = true;
+ if (tdb_transaction_start(tdb) != 0)
+ return false;
+
+ if (tdb_store(tdb, key, key, TDB_INSERT) != 0)
+ return false;
+
+ if (tdb_transaction_commit(tdb) != 0)
+ return false;
+
+ in_transaction = false;
+
+ /* We made it! */
+ diag("Completed %u runs", current);
+ tdb_close(tdb);
+ ret = external_agent_operation(agent, CLOSE, "");
+ if (ret != SUCCESS) {
+ diag("Step %u close failed = %s", current,
+ agent_return_name(ret));
+ return false;
+ }
+
+#ifdef HAVE_INCOHERENT_MMAP
+ /* This means we always mmap, which makes this test a noop. */
+ ok1(1);
+#else
+ ok1(needed_recovery);
+#endif
+ ok1(locking_errors == 0);
+ ok1(forget_locking() == 0);
+ locking_errors = 0;
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ enum operation ops[] = { FETCH, STORE, TRANSACTION_START };
+ struct agent *agent;
+ int i;
+
+ plan_tests(12);
+ unlock_callback = maybe_die;
+
+ agent = prepare_external_agent();
+
+ for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
+ diag("Testing %s after death", operation_name(ops[i]));
+ ok1(test_death(ops[i], agent));
+ }
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-endian.c b/lib/tdb/test/run-endian.c
new file mode 100644
index 0000000..9d4d5f5
--- /dev/null
+++ b/lib/tdb/test/run-endian.c
@@ -0,0 +1,64 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(13);
+ tdb = tdb_open_ex("run-endian.tdb", 1024,
+ TDB_CLEAR_IF_FIRST|TDB_CONVERT,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ ok1(tdb);
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) < 0);
+ ok1(tdb_error(tdb) == TDB_ERR_NOEXIST);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) < 0);
+ ok1(tdb_error(tdb) == TDB_ERR_EXISTS);
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0);
+
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+
+ key.dsize++;
+ data = tdb_fetch(tdb, key);
+ ok1(data.dptr == NULL);
+ tdb_close(tdb);
+
+ /* Reopen: should read it */
+ tdb = tdb_open_ex("run-endian.tdb", 1024, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(tdb);
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-fcntl-deadlock.c b/lib/tdb/test/run-fcntl-deadlock.c
new file mode 100644
index 0000000..0a328af
--- /dev/null
+++ b/lib/tdb/test/run-fcntl-deadlock.c
@@ -0,0 +1,202 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include <errno.h>
+#include "tap-interface.h"
+
+/*
+ * This tests the low level locking requirement
+ * for the allrecord lock/prepare_commit and traverse_read interaction.
+ *
+ * The pattern with the traverse_read and prepare_commit interaction is
+ * the following:
+ *
+ * 1. transaction_start got the allrecord lock with F_RDLCK.
+ *
+ * 2. the traverse_read code walks the database in a sequence like this
+ * (per chain):
+ * 2.1 chainlock(chainX, F_RDLCK)
+ * 2.2 recordlock(chainX.record1, F_RDLCK)
+ * 2.3 chainunlock(chainX, F_RDLCK)
+ * 2.4 callback(chainX.record1)
+ * 2.5 chainlock(chainX, F_RDLCK)
+ * 2.6 recordunlock(chainX.record1, F_RDLCK)
+ * 2.7 recordlock(chainX.record2, F_RDLCK)
+ * 2.8 chainunlock(chainX, F_RDLCK)
+ * 2.9 callback(chainX.record2)
+ * 2.10 chainlock(chainX, F_RDLCK)
+ * 2.11 recordunlock(chainX.record2, F_RDLCK)
+ * 2.12 chainunlock(chainX, F_RDLCK)
+ * 2.13 goto next chain
+ *
+ * So it has always one record locked in F_RDLCK mode and tries to
+ * get the 2nd one before it releases the first one.
+ *
+ * 3. prepare_commit tries to upgrade the allrecord lock to F_RWLCK
+ * If that happens at the time of 2.4, the operation of
+ * 2.5 may deadlock with the allrecord lock upgrade.
+ * On Linux step 2.5 works in order to make some progress with the
+ * locking, but on solaris it might fail because the kernel
+ * wants to satisfy the 1st lock requester before the 2nd one.
+ *
+ * I think the first step is a standalone test that does this:
+ *
+ * process1: F_RDLCK for ofs=0 len=2
+ * process2: F_RDLCK for ofs=0 len=1
+ * process1: upgrade ofs=0 len=2 to F_RWLCK (in blocking mode)
+ * process2: F_RDLCK for ofs=1 len=1
+ * process2: unlock ofs=0 len=2
+ * process1: should continue at that point
+ *
+ * Such a test follows here...
+ */
+
+static int raw_fcntl_lock(int fd, int rw, off_t off, off_t len, bool waitflag)
+{
+ struct flock fl;
+ int cmd;
+ fl.l_type = rw;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ cmd = waitflag ? F_SETLKW : F_SETLK;
+
+ return fcntl(fd, cmd, &fl);
+}
+
+static int raw_fcntl_unlock(int fd, off_t off, off_t len)
+{
+ struct flock fl;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = len;
+ fl.l_pid = 0;
+
+ return fcntl(fd, F_SETLKW, &fl);
+}
+
+
+int pipe_r;
+int pipe_w;
+char buf[2];
+
+static void expect_char(char c)
+{
+ read(pipe_r, buf, 1);
+ if (*buf != c) {
+ fail("We were expecting %c, but got %c", c, buf[0]);
+ }
+}
+
+static void send_char(char c)
+{
+ write(pipe_w, &c, 1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int process;
+ int fd;
+ const char *filename = "run-fcntl-deadlock.lck";
+ int pid;
+ int pipes_1_2[2];
+ int pipes_2_1[2];
+ int ret;
+
+ pipe(pipes_1_2);
+ pipe(pipes_2_1);
+ fd = open(filename, O_RDWR | O_CREAT, 0755);
+
+ pid = fork();
+ if (pid == 0) {
+ pipe_r = pipes_1_2[0];
+ pipe_w = pipes_2_1[1];
+ process = 2;
+ alarm(15);
+ } else {
+ pipe_r = pipes_2_1[0];
+ pipe_w = pipes_1_2[1];
+ process = 1;
+ alarm(15);
+ }
+
+ /* a: process1: F_RDLCK for ofs=0 len=2 */
+ if (process == 1) {
+ ret = raw_fcntl_lock(fd, F_RDLCK, 0, 2, true);
+ ok(ret == 0,
+ "process 1 lock ofs=0 len=2: %d - %s",
+ ret, strerror(errno));
+ diag("process 1 took read lock on range 0,2");
+ send_char('a');
+ }
+
+ /* process2: F_RDLCK for ofs=0 len=1 */
+ if (process == 2) {
+ expect_char('a');
+ ret = raw_fcntl_lock(fd, F_RDLCK, 0, 1, true);
+ ok(ret == 0,
+ "process 2 lock ofs=0 len=1: %d - %s",
+ ret, strerror(errno));;
+ diag("process 2 took read lock on range 0,1");
+ send_char('b');
+ }
+
+ /* process1: upgrade ofs=0 len=2 to F_RWLCK (in blocking mode) */
+ if (process == 1) {
+ expect_char('b');
+ send_char('c');
+ diag("process 1 starts upgrade on range 0,2");
+ ret = raw_fcntl_lock(fd, F_WRLCK, 0, 2, true);
+ ok(ret == 0,
+ "process 1 RW lock ofs=0 len=2: %d - %s",
+ ret, strerror(errno));
+ diag("process 1 got read upgrade done");
+ /* at this point process 1 is blocked on 2 releasing the
+ read lock */
+ }
+
+ /*
+ * process2: F_RDLCK for ofs=1 len=1
+ * process2: unlock ofs=0 len=2
+ */
+ if (process == 2) {
+ expect_char('c'); /* we know process 1 is *about* to lock */
+ sleep(1);
+ ret = raw_fcntl_lock(fd, F_RDLCK, 1, 1, true);
+ ok(ret == 0,
+ "process 2 lock ofs=1 len=1: %d - %s",
+ ret, strerror(errno));
+ diag("process 2 got read lock on 1,1\n");
+ ret = raw_fcntl_unlock(fd, 0, 2);
+ ok(ret == 0,
+ "process 2 unlock ofs=0 len=2: %d - %s",
+ ret, strerror(errno));
+ diag("process 2 released read lock on 0,2\n");
+ sleep(1);
+ send_char('d');
+ }
+
+ if (process == 1) {
+ expect_char('d');
+ }
+
+ diag("process %d has got to the end\n", process);
+
+ return 0;
+}
diff --git a/lib/tdb/test/run-incompatible.c b/lib/tdb/test/run-incompatible.c
new file mode 100644
index 0000000..5f1b586
--- /dev/null
+++ b/lib/tdb/test/run-incompatible.c
@@ -0,0 +1,188 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+
+static unsigned int tdb_dumb_hash(TDB_DATA *key)
+{
+ return key->dsize;
+}
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+ unsigned int *count = tdb_get_logging_private(tdb);
+ if (strstr(fmt, "hash"))
+ (*count)++;
+}
+
+static unsigned int hdr_rwlocks(const char *fname)
+{
+ struct tdb_header hdr;
+ ssize_t nread;
+
+ int fd = open(fname, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ nread = read(fd, &hdr, sizeof(hdr));
+ close(fd);
+ if (nread != sizeof(hdr)) {
+ return -1;
+ }
+ return hdr.rwlocks;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count, flags;
+ TDB_DATA d, r;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+
+ plan_tests(38 * 2);
+
+ for (flags = 0; flags <= TDB_CONVERT; flags += TDB_CONVERT) {
+ unsigned int rwmagic = TDB_HASH_RWLOCK_MAGIC;
+
+ if (flags & TDB_CONVERT)
+ tdb_convert(&rwmagic, sizeof(rwmagic));
+
+ /* Create an old-style hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0, flags,
+ O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
+ NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ d.dptr = discard_const_p(uint8_t, "Hello");
+ d.dsize = 5;
+ ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
+ tdb_close(tdb);
+
+ /* Should not have marked rwlocks field. */
+ ok1(hdr_rwlocks("run-incompatible.tdb") == 0);
+
+ /* We can still open any old-style with incompat flag. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0,
+ TDB_INCOMPATIBLE_HASH,
+ O_RDWR, 0600, &log_ctx, NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ r = tdb_fetch(tdb, d);
+ ok1(r.dsize == 5);
+ free(r.dptr);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY,
+ 0, &log_ctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY,
+ 0, &log_ctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ /* OK, now create with incompatible flag, default hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0,
+ flags|TDB_INCOMPATIBLE_HASH,
+ O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
+ NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ d.dptr = discard_const_p(uint8_t, "Hello");
+ d.dsize = 5;
+ ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
+ tdb_close(tdb);
+
+ /* Should have marked rwlocks field. */
+ ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic);
+
+ /* Cannot open with old hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
+ O_RDWR, 0600, &log_ctx, tdb_old_hash);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ /* Can open with jenkins hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
+ O_RDWR, 0600, &log_ctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ r = tdb_fetch(tdb, d);
+ ok1(r.dsize == 5);
+ free(r.dptr);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ /* Can open by letting it figure it out itself. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
+ O_RDWR, 0600, &log_ctx, NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ r = tdb_fetch(tdb, d);
+ ok1(r.dsize == 5);
+ free(r.dptr);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ /* We can also use incompatible hash with other hashes. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0,
+ flags|TDB_INCOMPATIBLE_HASH,
+ O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
+ tdb_dumb_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ d.dptr = discard_const_p(uint8_t, "Hello");
+ d.dsize = 5;
+ ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
+ tdb_close(tdb);
+
+ /* Should have marked rwlocks field. */
+ ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic);
+
+ /* It should not open if we don't specify. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ /* Should reopen with correct hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, tdb_dumb_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ r = tdb_fetch(tdb, d);
+ ok1(r.dsize == 5);
+ free(r.dptr);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+ }
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-marklock-deadlock.c b/lib/tdb/test/run-marklock-deadlock.c
new file mode 100644
index 0000000..37e959f
--- /dev/null
+++ b/lib/tdb/test/run-marklock-deadlock.c
@@ -0,0 +1,278 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+#include "logging.h"
+
+static TDB_DATA key, data;
+
+static void do_chainlock(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock(tdb, key);
+ ok(ret == 0, "tdb_chainlock should succeed");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ exit(0);
+}
+
+static void do_allrecord_lock(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
+ ok(ret == 0, "tdb_allrecord_lock should succeed");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ exit(0);
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+static int do_tests(const char *name, int tdb_flags)
+{
+ struct tdb_context *tdb;
+ int ret;
+ pid_t chainlock_child, allrecord_child;
+ int chainlock_down[2];
+ int chainlock_up[2];
+ int allrecord_down[2];
+ int allrecord_up[2];
+ char c;
+ ssize_t nread, nwritten;
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ ret = pipe(chainlock_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(chainlock_up);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(allrecord_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(allrecord_up);
+ ok(ret == 0, "pipe should succeed");
+
+ chainlock_child = fork();
+ ok(chainlock_child != -1, "fork should succeed");
+
+ if (chainlock_child == 0) {
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_up[1]);
+ close(allrecord_down[0]);
+ close(allrecord_down[1]);
+ do_chainlock(name, tdb_flags,
+ chainlock_up[1], chainlock_down[0]);
+ exit(0);
+ }
+ close(chainlock_up[1]);
+ close(chainlock_down[0]);
+
+ nread = read(chainlock_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ /*
+ * Now we have a process holding a chainlock. Start another process
+ * trying the allrecord lock. This will block.
+ */
+
+ allrecord_child = fork();
+ ok(allrecord_child != -1, "fork should succeed");
+
+ if (allrecord_child == 0) {
+ close(chainlock_up[0]);
+ close(chainlock_up[1]);
+ close(chainlock_down[0]);
+ close(chainlock_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ do_allrecord_lock(name, tdb_flags,
+ allrecord_up[1], allrecord_down[0]);
+ exit(0);
+ }
+ close(allrecord_up[1]);
+ close(allrecord_down[0]);
+
+ poll(NULL, 0, 500);
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ /*
+ * Someone already holds a chainlock, but we're able to get the
+ * freelist lock.
+ *
+ * The freelist lock/mutex is independent from the allrecord lock/mutex.
+ */
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == -1, "tdb_chainlock_nonblock should not succeed");
+
+ ret = tdb_lock_nonblock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_lock_nonblock should succeed");
+
+ ret = tdb_unlock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_unlock should succeed");
+
+ /*
+ * We have someone else having done the lock for us. Just mark it.
+ */
+
+ ret = tdb_chainlock_mark(tdb, key);
+ ok(ret == 0, "tdb_chainlock_mark should succeed");
+
+ /*
+ * The tdb_store below will block the freelist. In one version of the
+ * mutex patches, the freelist was already blocked here by the
+ * allrecord child, which was waiting for the chainlock child to give
+ * up its chainlock. Make sure that we don't run into this
+ * deadlock. To exercise the deadlock, just comment out the "ok"
+ * line.
+ *
+ * The freelist lock/mutex is independent from the allrecord lock/mutex.
+ */
+
+ ret = tdb_lock_nonblock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_lock_nonblock should succeed");
+
+ ret = tdb_unlock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_unlock should succeed");
+
+ ret = tdb_store(tdb, key, data, TDB_INSERT);
+ ok(ret == 0, "tdb_store should succeed");
+
+ ret = tdb_chainlock_unmark(tdb, key);
+ ok(ret == 0, "tdb_chainlock_unmark should succeed");
+
+ nwritten = write(chainlock_down[1], &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(chainlock_up[0], &c, sizeof(c));
+ ok(nread == 0, "read should succeed");
+
+ nread = read(allrecord_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ /*
+ * Someone already holds the allrecord lock, but we're able to get the
+ * freelist lock.
+ *
+ * The freelist lock/mutex is independent from the allrecord lock/mutex.
+ */
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == -1, "tdb_chainlock_nonblock should not succeed");
+
+ ret = tdb_lockall_nonblock(tdb);
+ ok(ret == -1, "tdb_lockall_nonblock should not succeed");
+
+ ret = tdb_lock_nonblock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_lock_nonblock should succeed");
+
+ ret = tdb_unlock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_unlock should succeed");
+
+ /*
+ * We have someone else having done the lock for us. Just mark it.
+ */
+
+ ret = tdb_lockall_mark(tdb);
+ ok(ret == 0, "tdb_lockall_mark should succeed");
+
+ ret = tdb_lock_nonblock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_lock_nonblock should succeed");
+
+ ret = tdb_unlock(tdb, -1, F_WRLCK);
+ ok(ret == 0, "tdb_unlock should succeed");
+
+ ret = tdb_store(tdb, key, data, TDB_REPLACE);
+ ok(ret == 0, "tdb_store should succeed");
+
+ ret = tdb_lockall_unmark(tdb);
+ ok(ret == 0, "tdb_lockall_unmark should succeed");
+
+ nwritten = write(allrecord_down[1], &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(allrecord_up[0], &c, sizeof(c));
+ ok(nread == 0, "read should succeed");
+
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ diag("%s tests done", name);
+ return exit_status();
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ bool mutex_support;
+
+ mutex_support = tdb_runtime_check_for_robust_mutexes();
+
+ ret = do_tests("marklock-deadlock-fcntl.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "marklock-deadlock-fcntl.tdb tests should succeed");
+
+ if (!mutex_support) {
+ skip(1, "No robust mutex support, "
+ "skipping marklock-deadlock-mutex.tdb tests");
+ return exit_status();
+ }
+
+ ret = do_tests("marklock-deadlock-mutex.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_MUTEX_LOCKING |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "marklock-deadlock-mutex.tdb tests should succeed");
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex-allrecord-bench.c b/lib/tdb/test/run-mutex-allrecord-bench.c
new file mode 100644
index 0000000..b81e597
--- /dev/null
+++ b/lib/tdb/test/run-mutex-allrecord-bench.c
@@ -0,0 +1,82 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+
+static TDB_DATA key, data;
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return (tv2->tv_sec - tv1->tv_sec) +
+ (tv2->tv_usec - tv1->tv_usec)*1.0e-6;
+}
+
+static double timeval_elapsed(const struct timeval *tv)
+{
+ struct timeval tv2;
+ gettimeofday(&tv2, NULL);
+ return timeval_elapsed2(tv, &tv2);
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret;
+ struct timeval start;
+ double elapsed;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ if (!runtime_support) {
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ tdb = tdb_open_ex("mutex-allrecord-bench.tdb", 1000000,
+ TDB_INCOMPATIBLE_HASH|
+ TDB_MUTEX_LOCKING|
+ TDB_CLEAR_IF_FIRST,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ gettimeofday(&start, NULL);
+ ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
+ elapsed = timeval_elapsed(&start);
+
+ ok(ret == 0, "tdb_allrecord_lock should succeed");
+
+ diag("allrecord_lock took %f seconds", elapsed);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex-allrecord-block.c b/lib/tdb/test/run-mutex-allrecord-block.c
new file mode 100644
index 0000000..fcd3b4f
--- /dev/null
+++ b/lib/tdb/test/run-mutex-allrecord-block.c
@@ -0,0 +1,120 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+
+static TDB_DATA key, data;
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static int do_child(int tdb_flags, int to, int from)
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret;
+ char c = 0;
+
+ tdb = tdb_open_ex("mutex-allrecord-block.tdb", 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
+ ok(ret == 0, "tdb_allrecord_lock should succeed");
+
+ write(to, &c, sizeof(c));
+
+ read(from, &c, sizeof(c));
+
+ ret = tdb_allrecord_unlock(tdb, F_WRLCK, false);
+ ok(ret == 0, "tdb_allrecord_unlock should succeed");
+
+ return 0;
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret, status;
+ pid_t child, wait_ret;
+ int fromchild[2];
+ int tochild[2];
+ char c;
+ int tdb_flags;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ if (!runtime_support) {
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ pipe(fromchild);
+ pipe(tochild);
+
+ tdb_flags = TDB_INCOMPATIBLE_HASH|
+ TDB_MUTEX_LOCKING|
+ TDB_CLEAR_IF_FIRST;
+
+ child = fork();
+ if (child == 0) {
+ close(fromchild[0]);
+ close(tochild[1]);
+ return do_child(tdb_flags, fromchild[1], tochild[0]);
+ }
+ close(fromchild[1]);
+ close(tochild[0]);
+
+ read(fromchild[0], &c, sizeof(c));
+
+ tdb = tdb_open_ex("mutex-allrecord-block.tdb", 0,
+ tdb_flags, O_RDWR|O_CREAT, 0755,
+ &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == -1, "tdb_chainlock_nonblock should not succeed");
+
+ write(tochild[1], &c, sizeof(c));
+
+ ret = tdb_chainlock(tdb, key);
+ ok(ret == 0, "tdb_chainlock should not succeed");
+
+ ret = tdb_chainunlock(tdb, key);
+ ok(ret == 0, "tdb_chainunlock should succeed");
+
+ wait_ret = wait(&status);
+ ok(wait_ret == child, "child should have exited correctly");
+
+ diag("done");
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex-allrecord-trylock.c b/lib/tdb/test/run-mutex-allrecord-trylock.c
new file mode 100644
index 0000000..4b683db
--- /dev/null
+++ b/lib/tdb/test/run-mutex-allrecord-trylock.c
@@ -0,0 +1,113 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+
+static TDB_DATA key, data;
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static int do_child(int tdb_flags, int to, int from)
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret;
+ char c = 0;
+
+ tdb = tdb_open_ex("mutex-allrecord-trylock.tdb", 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock(tdb, key);
+ ok(ret == 0, "tdb_chainlock should succeed");
+
+ write(to, &c, sizeof(c));
+
+ read(from, &c, sizeof(c));
+
+ ret = tdb_chainunlock(tdb, key);
+ ok(ret == 0, "tdb_chainunlock should succeed");
+
+ return 0;
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret, status;
+ pid_t child, wait_ret;
+ int fromchild[2];
+ int tochild[2];
+ char c;
+ int tdb_flags;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ if (!runtime_support) {
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ pipe(fromchild);
+ pipe(tochild);
+
+ tdb_flags = TDB_INCOMPATIBLE_HASH|
+ TDB_MUTEX_LOCKING|
+ TDB_CLEAR_IF_FIRST;
+
+ child = fork();
+ if (child == 0) {
+ close(fromchild[0]);
+ close(tochild[1]);
+ return do_child(tdb_flags, fromchild[1], tochild[0]);
+ }
+ close(fromchild[1]);
+ close(tochild[0]);
+
+ read(fromchild[0], &c, sizeof(c));
+
+ tdb = tdb_open_ex("mutex-allrecord-trylock.tdb", 0, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false);
+ ok(ret == -1, "tdb_allrecord_lock (nowait) should not succeed");
+
+ write(tochild[1], &c, sizeof(c));
+
+ wait_ret = wait(&status);
+ ok(wait_ret == child, "child should have exited correctly");
+
+ diag("done");
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex-die.c b/lib/tdb/test/run-mutex-die.c
new file mode 100644
index 0000000..4b8eac1
--- /dev/null
+++ b/lib/tdb/test/run-mutex-die.c
@@ -0,0 +1,269 @@
+#include "../common/tdb_private.h"
+#include "lock-tracking.h"
+static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
+static ssize_t write_check(int fd, const void *buf, size_t count);
+static int ftruncate_check(int fd, off_t length);
+
+#define pwrite pwrite_check
+#define write write_check
+#define fcntl fcntl_with_lockcheck
+#define ftruncate ftruncate_check
+
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include "external-agent.h"
+#include "logging.h"
+
+#undef write
+#undef pwrite
+#undef fcntl
+#undef ftruncate
+
+static int target, current;
+#define TEST_DBNAME "run-mutex-die.tdb"
+#define KEY_STRING "helloworld"
+
+static void maybe_die(int fd)
+{
+ if (target == 0) {
+ return;
+ }
+ current += 1;
+ if (current == target) {
+ _exit(1);
+ }
+}
+
+static ssize_t pwrite_check(int fd,
+ const void *buf, size_t count, off_t offset)
+{
+ ssize_t ret;
+
+ maybe_die(fd);
+
+ ret = pwrite(fd, buf, count, offset);
+ if (ret != count)
+ return ret;
+
+ maybe_die(fd);
+ return ret;
+}
+
+static ssize_t write_check(int fd, const void *buf, size_t count)
+{
+ ssize_t ret;
+
+ maybe_die(fd);
+
+ ret = write(fd, buf, count);
+ if (ret != count)
+ return ret;
+
+ maybe_die(fd);
+ return ret;
+}
+
+static int ftruncate_check(int fd, off_t length)
+{
+ int ret;
+
+ maybe_die(fd);
+
+ ret = ftruncate(fd, length);
+
+ maybe_die(fd);
+ return ret;
+}
+
+static enum agent_return flakey_ops(struct agent *a)
+{
+ enum agent_return ret;
+
+ /*
+ * Run in the external agent child
+ */
+
+ ret = external_agent_operation(a, OPEN_WITH_CLEAR_IF_FIRST, TEST_DBNAME);
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed to open: %s\n",
+ agent_return_name(ret));
+ return ret;
+ }
+ ret = external_agent_operation(a, UNMAP, "");
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed to unmap: %s\n",
+ agent_return_name(ret));
+ return ret;
+ }
+ ret = external_agent_operation(a, STORE, "xyz");
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed to store: %s\n",
+ agent_return_name(ret));
+ return ret;
+ }
+ ret = external_agent_operation(a, STORE, KEY_STRING);
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed store: %s\n",
+ agent_return_name(ret));
+ return ret;
+ }
+ ret = external_agent_operation(a, FETCH, KEY_STRING);
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed find key: %s\n",
+ agent_return_name(ret));
+ return ret;
+ }
+ ret = external_agent_operation(a, PING, "");
+ if (ret != SUCCESS) {
+ fprintf(stderr, "Agent failed ping: %s\n",
+ agent_return_name(ret));
+ return ret;
+ }
+ return ret;
+}
+
+static bool prep_db(void) {
+ struct tdb_context *tdb;
+ TDB_DATA key;
+ TDB_DATA data;
+
+ key.dptr = discard_const_p(uint8_t, KEY_STRING);
+ key.dsize = strlen((char *)key.dptr);
+ data.dptr = discard_const_p(uint8_t, "foo");
+ data.dsize = strlen((char *)data.dptr);
+
+ unlink(TEST_DBNAME);
+
+ tdb = tdb_open_ex(
+ TEST_DBNAME, 2,
+ TDB_INCOMPATIBLE_HASH|TDB_MUTEX_LOCKING|TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+ if (tdb == NULL) {
+ return false;
+ }
+
+ if (tdb_store(tdb, key, data, TDB_INSERT) != 0) {
+ return false;
+ }
+
+ tdb_close(tdb);
+ tdb = NULL;
+
+ forget_locking();
+
+ return true;
+}
+
+static bool test_db(void) {
+ struct tdb_context *tdb;
+ int ret;
+
+ tdb = tdb_open_ex(
+ TEST_DBNAME, 1024, TDB_INCOMPATIBLE_HASH,
+ O_RDWR, 0600, &taplogctx, NULL);
+
+ if (tdb == NULL) {
+ perror("tdb_open_ex failed");
+ return false;
+ }
+
+ ret = tdb_traverse(tdb, NULL, NULL);
+ if (ret == -1) {
+ perror("traverse failed");
+ goto fail;
+ }
+
+ tdb_close(tdb);
+
+ forget_locking();
+
+ return true;
+
+fail:
+ tdb_close(tdb);
+ return false;
+}
+
+static bool test_one(void)
+{
+ enum agent_return ret;
+
+ ret = AGENT_DIED;
+ target = 19;
+
+ while (ret != SUCCESS) {
+ struct agent *agent;
+
+ {
+ int child_target = target;
+ bool pret;
+ target = 0;
+ pret = prep_db();
+ ok1(pret);
+ target = child_target;
+ }
+
+ agent = prepare_external_agent();
+
+ ret = flakey_ops(agent);
+
+ diag("Agent (target=%d) returns %s",
+ target, agent_return_name(ret));
+
+ if (ret == SUCCESS) {
+ ok((target > 19), "At least one AGENT_DIED expected");
+ } else {
+ ok(ret == AGENT_DIED, "AGENT_DIED expected");
+ }
+
+ shutdown_agent(agent);
+
+ {
+ int child_target = target;
+ bool tret;
+ target = 0;
+ tret = test_db();
+ ok1(tret);
+ target = child_target;
+ }
+
+ target += 1;
+ }
+
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ bool ret;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ if (!runtime_support) {
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ plan_tests(12);
+ unlock_callback = maybe_die;
+
+ ret = test_one();
+ ok1(ret);
+
+ diag("done");
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex-openflags2.c b/lib/tdb/test/run-mutex-openflags2.c
new file mode 100644
index 0000000..89603e6
--- /dev/null
+++ b/lib/tdb/test/run-mutex-openflags2.c
@@ -0,0 +1,146 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <poll.h>
+#include <stdarg.h>
+
+static TDB_DATA key, data;
+
+static void log_void(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+}
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static int do_child(int fd)
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ struct tdb_logging_context nolog_ctx = { log_void, NULL };
+ char c;
+
+ read(fd, &c, 1);
+
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_DEFAULT,
+ O_RDWR|O_CREAT, 0755, &nolog_ctx, NULL);
+ ok((tdb == NULL) && (errno == EINVAL), "TDB_DEFAULT without "
+ "TDB_MUTEX_LOCKING should fail with EINVAL - %d", errno);
+
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_CLEAR_IF_FIRST,
+ O_RDWR|O_CREAT, 0755, &nolog_ctx, NULL);
+ ok((tdb == NULL) && (errno == EINVAL), "TDB_CLEAR_IF_FIRST without "
+ "TDB_MUTEX_LOCKING should fail with EINVAL - %d", errno);
+
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_CLEAR_IF_FIRST |
+ TDB_MUTEX_LOCKING |
+ TDB_INTERNAL,
+ O_RDWR|O_CREAT, 0755, &nolog_ctx, NULL);
+ ok((tdb == NULL) && (errno == EINVAL), "TDB_MUTEX_LOCKING with "
+ "TDB_INTERNAL should fail with EINVAL - %d", errno);
+
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_CLEAR_IF_FIRST |
+ TDB_MUTEX_LOCKING |
+ TDB_NOMMAP,
+ O_RDWR|O_CREAT, 0755, &nolog_ctx, NULL);
+ ok((tdb == NULL) && (errno == EINVAL), "TDB_MUTEX_LOCKING with "
+ "TDB_NOMMAP should fail with EINVAL - %d", errno);
+
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_CLEAR_IF_FIRST |
+ TDB_MUTEX_LOCKING,
+ O_RDONLY, 0755, &nolog_ctx, NULL);
+ ok((tdb != NULL), "TDB_MUTEX_LOCKING with "
+ "O_RDONLY should work - %d", errno);
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_CLEAR_IF_FIRST |
+ TDB_MUTEX_LOCKING,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok((tdb != NULL), "TDB_MUTEX_LOCKING with TDB_CLEAR_IF_FIRST"
+ "TDB_NOMMAP should work - %d", errno);
+
+ return 0;
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ struct tdb_logging_context nolog_ctx = { log_void, NULL };
+ int ret, status;
+ pid_t child, wait_ret;
+ int pipefd[2];
+ char c = 0;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ ret = pipe(pipefd);
+ ok1(ret == 0);
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ if (!runtime_support) {
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_CLEAR_IF_FIRST|
+ TDB_MUTEX_LOCKING,
+ O_RDWR|O_CREAT, 0755, &nolog_ctx, NULL);
+ ok((tdb == NULL) && (errno == ENOSYS), "TDB_MUTEX_LOCKING without "
+ "runtime support should fail with ENOSYS - %d", errno);
+
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ child = fork();
+ if (child == 0) {
+ return do_child(pipefd[0]);
+ }
+
+ tdb = tdb_open_ex("mutex-openflags2.tdb", 0,
+ TDB_CLEAR_IF_FIRST|
+ TDB_MUTEX_LOCKING,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok((tdb != NULL), "tdb_open_ex with mutexes should succeed");
+
+ write(pipefd[1], &c, 1);
+
+ wait_ret = wait(&status);
+ ok((wait_ret == child) && (status == 0),
+ "child should have exited correctly");
+
+ diag("done");
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex-transaction1.c b/lib/tdb/test/run-mutex-transaction1.c
new file mode 100644
index 0000000..7b9f7b1
--- /dev/null
+++ b/lib/tdb/test/run-mutex-transaction1.c
@@ -0,0 +1,236 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+
+static TDB_DATA key, data;
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static int do_child(int tdb_flags, int to, int from)
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret;
+ char c = 0;
+
+ tdb = tdb_open_ex("mutex-transaction1.tdb", 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_transaction_start(tdb);
+ ok(ret == 0, "tdb_transaction_start should succeed");
+
+ ret = tdb_store(tdb, key, data, TDB_INSERT);
+ ok(ret == 0, "tdb_store(tdb, key, data, TDB_INSERT) should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_transaction_cancel(tdb);
+ ok(ret == 0, "tdb_transaction_cancel should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_transaction_start(tdb);
+ ok(ret == 0, "tdb_transaction_start should succeed");
+
+ ret = tdb_store(tdb, key, data, TDB_INSERT);
+ ok(ret == 0, "tdb_store(tdb, key, data, TDB_INSERT) should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_transaction_commit(tdb);
+ ok(ret == 0, "tdb_transaction_commit should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_transaction_start(tdb);
+ ok(ret == 0, "tdb_transaction_start should succeed");
+
+ ret = tdb_store(tdb, key, key, TDB_REPLACE);
+ ok(ret == 0, "tdb_store(tdb, key, data, TDB_REPLACE) should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_transaction_commit(tdb);
+ ok(ret == 0, "tdb_transaction_commit should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ return 0;
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret, status;
+ pid_t child, wait_ret;
+ int fromchild[2];
+ int tochild[2];
+ TDB_DATA val;
+ char c;
+ int tdb_flags;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ if (!runtime_support) {
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ pipe(fromchild);
+ pipe(tochild);
+
+ tdb_flags = TDB_INCOMPATIBLE_HASH|
+ TDB_MUTEX_LOCKING|
+ TDB_CLEAR_IF_FIRST;
+
+ child = fork();
+ if (child == 0) {
+ close(fromchild[0]);
+ close(tochild[1]);
+ return do_child(tdb_flags, fromchild[1], tochild[0]);
+ }
+ close(fromchild[1]);
+ close(tochild[0]);
+
+ read(fromchild[0], &c, sizeof(c));
+
+ tdb = tdb_open_ex("mutex-transaction1.tdb", 0,
+ tdb_flags, O_RDWR|O_CREAT, 0755,
+ &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ /*
+ * The child has the transaction running
+ */
+ ret = tdb_transaction_start_nonblock(tdb);
+ ok(ret == -1, "tdb_transaction_start_nonblock not succeed");
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == -1, "tdb_chainlock_nonblock should not succeed");
+
+ /*
+ * We can still read
+ */
+ ret = tdb_exists(tdb, key);
+ ok(ret == 0, "tdb_exists(tdb, key) should return 0");
+
+ val = tdb_fetch(tdb, key);
+ ok(val.dsize == 0, "tdb_fetch(tdb, key) should return an empty value");
+
+ write(tochild[1], &c, sizeof(c));
+
+ /*
+ * When the child canceled we can start...
+ */
+ ret = tdb_transaction_start(tdb);
+ ok(ret == 0, "tdb_transaction_start should succeed");
+
+ read(fromchild[0], &c, sizeof(c));
+ write(tochild[1], &c, sizeof(c));
+
+ ret = tdb_transaction_cancel(tdb);
+ ok(ret == 0, "tdb_transaction_cancel should succeed");
+
+ /*
+ * When we canceled the child can start and store...
+ */
+ read(fromchild[0], &c, sizeof(c));
+
+ /*
+ * We still see the old values before the child commits...
+ */
+ ret = tdb_exists(tdb, key);
+ ok(ret == 0, "tdb_exists(tdb, key) should return 0");
+
+ val = tdb_fetch(tdb, key);
+ ok(val.dsize == 0, "tdb_fetch(tdb, key) should return an empty value");
+
+ write(tochild[1], &c, sizeof(c));
+ read(fromchild[0], &c, sizeof(c));
+
+ /*
+ * We see the new values after the commit...
+ */
+ ret = tdb_exists(tdb, key);
+ ok(ret == 1, "tdb_exists(tdb, key) should return 1");
+
+ val = tdb_fetch(tdb, key);
+ ok(val.dsize != 0, "tdb_fetch(tdb, key) should return a value");
+ ok(val.dsize == data.dsize, "tdb_fetch(tdb, key) should return a value");
+ ok(memcmp(val.dptr, data.dptr, data.dsize) == 0, "tdb_fetch(tdb, key) should return a value");
+
+ write(tochild[1], &c, sizeof(c));
+ read(fromchild[0], &c, sizeof(c));
+
+ /*
+ * The child started a new transaction and replaces the value,
+ * but we still see the old values before the child commits...
+ */
+ ret = tdb_exists(tdb, key);
+ ok(ret == 1, "tdb_exists(tdb, key) should return 1");
+
+ val = tdb_fetch(tdb, key);
+ ok(val.dsize != 0, "tdb_fetch(tdb, key) should return a value");
+ ok(val.dsize == data.dsize, "tdb_fetch(tdb, key) should return a value");
+ ok(memcmp(val.dptr, data.dptr, data.dsize) == 0, "tdb_fetch(tdb, key) should return a value");
+
+ write(tochild[1], &c, sizeof(c));
+ read(fromchild[0], &c, sizeof(c));
+
+ /*
+ * We see the new values after the commit...
+ */
+ ret = tdb_exists(tdb, key);
+ ok(ret == 1, "tdb_exists(tdb, key) should return 1");
+
+ val = tdb_fetch(tdb, key);
+ ok(val.dsize != 0, "tdb_fetch(tdb, key) should return a value");
+ ok(val.dsize == key.dsize, "tdb_fetch(tdb, key) should return a value");
+ ok(memcmp(val.dptr, key.dptr, key.dsize) == 0, "tdb_fetch(tdb, key) should return a value");
+
+ write(tochild[1], &c, sizeof(c));
+
+ wait_ret = wait(&status);
+ ok(wait_ret == child, "child should have exited correctly");
+
+ diag("done");
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex-trylock.c b/lib/tdb/test/run-mutex-trylock.c
new file mode 100644
index 0000000..c96b635
--- /dev/null
+++ b/lib/tdb/test/run-mutex-trylock.c
@@ -0,0 +1,122 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+
+static TDB_DATA key, data;
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static int do_child(int tdb_flags, int to, int from)
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret;
+ char c = 0;
+
+ tdb = tdb_open_ex("mutex-trylock.tdb", 0, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock(tdb, key);
+ ok(ret == 0, "tdb_chainlock should succeed");
+
+ write(to, &c, sizeof(c));
+
+ read(from, &c, sizeof(c));
+
+ ret = tdb_chainunlock(tdb, key);
+ ok(ret == 0, "tdb_chainunlock should succeed");
+
+ write(to, &c, sizeof(c));
+
+ return 0;
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret, status;
+ pid_t child, wait_ret;
+ int fromchild[2];
+ int tochild[2];
+ char c;
+ int tdb_flags;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ if (!runtime_support) {
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ pipe(fromchild);
+ pipe(tochild);
+
+ tdb_flags = TDB_INCOMPATIBLE_HASH|
+ TDB_MUTEX_LOCKING|
+ TDB_CLEAR_IF_FIRST;
+
+ child = fork();
+ if (child == 0) {
+ close(fromchild[0]);
+ close(tochild[1]);
+ return do_child(tdb_flags, fromchild[1], tochild[0]);
+ }
+ close(fromchild[1]);
+ close(tochild[0]);
+
+ read(fromchild[0], &c, sizeof(c));
+
+ tdb = tdb_open_ex("mutex-trylock.tdb", 0, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == -1, "tdb_chainlock_nonblock should not succeed");
+
+ write(tochild[1], &c, sizeof(c));
+
+ read(fromchild[0], &c, sizeof(c));
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == 0, "tdb_chainlock_nonblock should succeed");
+ ret = tdb_chainunlock(tdb, key);
+ ok(ret == 0, "tdb_chainunlock should succeed");
+
+ wait_ret = wait(&status);
+ ok(wait_ret == child, "child should have exited correctly");
+
+ diag("done");
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-mutex1.c b/lib/tdb/test/run-mutex1.c
new file mode 100644
index 0000000..eb75946
--- /dev/null
+++ b/lib/tdb/test/run-mutex1.c
@@ -0,0 +1,138 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+
+static TDB_DATA key, data;
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static int do_child(int tdb_flags, int to, int from)
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret;
+ char c = 0;
+
+ tdb = tdb_open_ex("mutex1.tdb", 0, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock(tdb, key);
+ ok(ret == 0, "tdb_chainlock should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_chainunlock(tdb, key);
+ ok(ret == 0, "tdb_chainunlock should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
+ ok(ret == 0, "tdb_allrecord_lock should succeed");
+
+ write(to, &c, sizeof(c));
+ read(from, &c, sizeof(c));
+
+ ret = tdb_allrecord_unlock(tdb, F_WRLCK, false);
+ ok(ret == 0, "tdb_allrecord_lock should succeed");
+
+ return 0;
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+ int ret, status;
+ pid_t child, wait_ret;
+ int fromchild[2];
+ int tochild[2];
+ char c;
+ int tdb_flags;
+ bool runtime_support;
+
+ runtime_support = tdb_runtime_check_for_robust_mutexes();
+
+ if (!runtime_support) {
+ skip(1, "No robust mutex support");
+ return exit_status();
+ }
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ pipe(fromchild);
+ pipe(tochild);
+
+ tdb_flags = TDB_INCOMPATIBLE_HASH|
+ TDB_MUTEX_LOCKING|
+ TDB_CLEAR_IF_FIRST;
+
+ child = fork();
+ if (child == 0) {
+ close(fromchild[0]);
+ close(tochild[1]);
+ return do_child(tdb_flags, fromchild[1], tochild[0]);
+ }
+ close(fromchild[1]);
+ close(tochild[0]);
+
+ read(fromchild[0], &c, sizeof(c));
+
+ tdb = tdb_open_ex("mutex1.tdb", 0, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ write(tochild[1], &c, sizeof(c));
+ read(fromchild[0], &c, sizeof(c));
+
+ ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
+ ok(ret == 0, "tdb_allrecord_lock should succeed");
+
+ ret = tdb_store(tdb, key, data, 0);
+ ok(ret == 0, "tdb_store should succeed");
+
+ ret = tdb_allrecord_unlock(tdb, F_WRLCK, false);
+ ok(ret == 0, "tdb_allrecord_unlock should succeed");
+
+ write(tochild[1], &c, sizeof(c));
+ read(fromchild[0], &c, sizeof(c));
+ write(tochild[1], &c, sizeof(c));
+
+ ret = tdb_delete(tdb, key);
+ ok(ret == 0, "tdb_delete should succeed");
+
+ wait_ret = wait(&status);
+ ok(wait_ret == child, "child should have exited correctly");
+
+ diag("done");
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-nested-transactions.c b/lib/tdb/test/run-nested-transactions.c
new file mode 100644
index 0000000..864adf2
--- /dev/null
+++ b/lib/tdb/test/run-nested-transactions.c
@@ -0,0 +1,79 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(27);
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+
+ tdb = tdb_open_ex("run-nested-transactions.tdb",
+ 1024, TDB_CLEAR_IF_FIRST|TDB_DISALLOW_NESTING,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+ ok1(tdb);
+
+ /* Nesting disallowed. */
+ ok1(tdb_transaction_start(tdb) == 0);
+ data.dptr = discard_const_p(uint8_t, "world");
+ data.dsize = strlen("world");
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+ ok1(tdb_transaction_start(tdb) != 0);
+ ok1(tdb_error(tdb) == TDB_ERR_NESTING);
+
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+ ok1(tdb_transaction_commit(tdb) == 0);
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+ tdb_close(tdb);
+
+ /* Nesting allowed by default */
+ tdb = tdb_open_ex("run-nested-transactions.tdb",
+ 1024, TDB_DEFAULT, O_RDWR, 0, &taplogctx, NULL);
+ ok1(tdb);
+
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_delete(tdb, key) == 0);
+ ok1(tdb_transaction_commit(tdb) == 0);
+ ok1(!tdb_exists(tdb, key));
+ ok1(tdb_transaction_cancel(tdb) == 0);
+ /* Surprise! Kills inner "committed" transaction. */
+ ok1(tdb_exists(tdb, key));
+
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_delete(tdb, key) == 0);
+ ok1(tdb_transaction_commit(tdb) == 0);
+ ok1(!tdb_exists(tdb, key));
+ ok1(tdb_transaction_commit(tdb) == 0);
+ ok1(!tdb_exists(tdb, key));
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-nested-traverse.c b/lib/tdb/test/run-nested-traverse.c
new file mode 100644
index 0000000..aeaa085
--- /dev/null
+++ b/lib/tdb/test/run-nested-traverse.c
@@ -0,0 +1,111 @@
+#include "../common/tdb_private.h"
+#include "lock-tracking.h"
+#define fcntl fcntl_with_lockcheck
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#undef fcntl
+#include <stdlib.h>
+#include <stdbool.h>
+#include "external-agent.h"
+#include "logging.h"
+
+static struct agent *agent;
+
+static bool correct_key(TDB_DATA key)
+{
+ return key.dsize == strlen("hi")
+ && memcmp(key.dptr, "hi", key.dsize) == 0;
+}
+
+static bool correct_data(TDB_DATA data)
+{
+ return data.dsize == strlen("world")
+ && memcmp(data.dptr, "world", data.dsize) == 0;
+}
+
+static int traverse2(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *p)
+{
+ ok1(correct_key(key));
+ ok1(correct_data(data));
+ return 0;
+}
+
+static int traverse1r(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *p)
+{
+ ok1(correct_key(key));
+ ok1(correct_data(data));
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, STORE, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, TRANSACTION_COMMIT, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ tdb_traverse(tdb, traverse2, NULL);
+
+ /* That should *not* release the all-records lock! */
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, STORE, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, TRANSACTION_COMMIT, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ return 0;
+}
+
+static int traverse1w(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *p)
+{
+ ok1(correct_key(key));
+ ok1(correct_data(data));
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ tdb_traverse(tdb, traverse2, NULL);
+
+ /* That should *not* release the all-records lock! */
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(17);
+ agent = prepare_external_agent();
+
+ tdb = tdb_open_ex("run-nested-traverse.tdb", 1024, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+ ok1(tdb);
+
+ ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS);
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == SUCCESS);
+ ok1(external_agent_operation(agent, TRANSACTION_COMMIT, tdb_name(tdb))
+ == SUCCESS);
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dptr = discard_const_p(uint8_t, "world");
+ data.dsize = strlen("world");
+
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ tdb_traverse(tdb, traverse1w, NULL);
+ tdb_traverse_read(tdb, traverse1r, NULL);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-no-lock-during-traverse.c b/lib/tdb/test/run-no-lock-during-traverse.c
new file mode 100644
index 0000000..737a32f
--- /dev/null
+++ b/lib/tdb/test/run-no-lock-during-traverse.c
@@ -0,0 +1,114 @@
+#include "../common/tdb_private.h"
+#include "lock-tracking.h"
+
+#define fcntl fcntl_with_lockcheck
+
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+#undef fcntl
+
+#define NUM_ENTRIES 10
+
+static bool prepare_entries(struct tdb_context *tdb)
+{
+ unsigned int i;
+ TDB_DATA key, data;
+
+ for (i = 0; i < NUM_ENTRIES; i++) {
+ key.dsize = sizeof(i);
+ key.dptr = (void *)&i;
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ if (tdb_store(tdb, key, data, 0) != 0)
+ return false;
+ }
+ return true;
+}
+
+static void delete_entries(struct tdb_context *tdb)
+{
+ unsigned int i;
+ TDB_DATA key;
+
+ for (i = 0; i < NUM_ENTRIES; i++) {
+ key.dsize = sizeof(i);
+ key.dptr = (void *)&i;
+
+ ok1(tdb_delete(tdb, key) == 0);
+ }
+}
+
+/* We don't know how many times this will run. */
+static int delete_other(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ unsigned int i;
+ memcpy(&i, key.dptr, 4);
+ i = (i + 1) % NUM_ENTRIES;
+ key.dptr = (void *)&i;
+ if (tdb_delete(tdb, key) != 0)
+ (*(int *)private_data)++;
+ return 0;
+}
+
+static int delete_self(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ ok1(tdb_delete(tdb, key) == 0);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ int errors = 0;
+
+ plan_tests(41);
+ tdb = tdb_open_ex("run-no-lock-during-traverse.tdb",
+ 1024, TDB_CLEAR_IF_FIRST, O_CREAT|O_TRUNC|O_RDWR,
+ 0600, &taplogctx, NULL);
+
+ ok1(tdb);
+ ok1(prepare_entries(tdb));
+ ok1(locking_errors == 0);
+ ok1(tdb_lockall(tdb) == 0);
+ ok1(locking_errors == 0);
+ tdb_traverse(tdb, delete_other, &errors);
+ ok1(errors == 0);
+ ok1(locking_errors == 0);
+ ok1(tdb_unlockall(tdb) == 0);
+
+ ok1(prepare_entries(tdb));
+ ok1(locking_errors == 0);
+ ok1(tdb_lockall(tdb) == 0);
+ ok1(locking_errors == 0);
+ tdb_traverse(tdb, delete_self, NULL);
+ ok1(locking_errors == 0);
+ ok1(tdb_unlockall(tdb) == 0);
+
+ ok1(prepare_entries(tdb));
+ ok1(locking_errors == 0);
+ ok1(tdb_lockall(tdb) == 0);
+ ok1(locking_errors == 0);
+ delete_entries(tdb);
+ ok1(locking_errors == 0);
+ ok1(tdb_unlockall(tdb) == 0);
+
+ ok1(tdb_close(tdb) == 0);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-oldhash.c b/lib/tdb/test/run-oldhash.c
new file mode 100644
index 0000000..aaee6f6
--- /dev/null
+++ b/lib/tdb/test/run-oldhash.c
@@ -0,0 +1,50 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+
+ plan_tests(8);
+
+ /* Old format (with zeroes in the hash magic fields) should
+ * open with any hash (since we don't know what hash they used). */
+ tdb = tdb_open_ex("test/old-nohash-le.tdb", 0, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("test/old-nohash-be.tdb", 0, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("test/old-nohash-le.tdb", 0, 0, O_RDWR, 0,
+ &taplogctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("test/old-nohash-be.tdb", 0, 0, O_RDWR, 0,
+ &taplogctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-open-during-transaction.c b/lib/tdb/test/run-open-during-transaction.c
new file mode 100644
index 0000000..9a6c6c1
--- /dev/null
+++ b/lib/tdb/test/run-open-during-transaction.c
@@ -0,0 +1,183 @@
+#include "../common/tdb_private.h"
+#include "lock-tracking.h"
+
+static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
+static ssize_t write_check(int fd, const void *buf, size_t count);
+static int ftruncate_check(int fd, off_t length);
+
+#define pwrite pwrite_check
+#define write write_check
+#define fcntl fcntl_with_lockcheck
+#define ftruncate ftruncate_check
+
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include "external-agent.h"
+#include "logging.h"
+
+static struct agent *agent;
+static bool opened;
+static int errors = 0;
+static bool clear_if_first;
+#define TEST_DBNAME "run-open-during-transaction.tdb"
+
+#undef write
+#undef pwrite
+#undef fcntl
+#undef ftruncate
+
+static bool is_same(const char *snapshot, const char *latest, off_t len)
+{
+ unsigned i;
+
+ for (i = 0; i < len; i++) {
+ if (snapshot[i] != latest[i])
+ return false;
+ }
+ return true;
+}
+
+static bool compare_file(int fd, const char *snapshot, off_t snapshot_len)
+{
+ char *contents;
+ bool same;
+
+ /* over-length read serves as length check. */
+ contents = malloc(snapshot_len+1);
+ same = pread(fd, contents, snapshot_len+1, 0) == snapshot_len
+ && is_same(snapshot, contents, snapshot_len);
+ free(contents);
+ return same;
+}
+
+static void check_file_intact(int fd)
+{
+ enum agent_return ret;
+ struct stat st;
+ char *contents;
+
+ fstat(fd, &st);
+ contents = malloc(st.st_size);
+ if (pread(fd, contents, st.st_size, 0) != st.st_size) {
+ diag("Read fail");
+ errors++;
+ free(contents);
+ return;
+ }
+
+ /* Ask agent to open file. */
+ ret = external_agent_operation(agent, clear_if_first ?
+ OPEN_WITH_CLEAR_IF_FIRST :
+ OPEN,
+ TEST_DBNAME);
+
+ /* It's OK to open it, but it must not have changed! */
+ if (!compare_file(fd, contents, st.st_size)) {
+ diag("Agent changed file after opening %s",
+ agent_return_name(ret));
+ errors++;
+ }
+
+ if (ret == SUCCESS) {
+ ret = external_agent_operation(agent, CLOSE, NULL);
+ if (ret != SUCCESS) {
+ diag("Agent failed to close tdb: %s",
+ agent_return_name(ret));
+ errors++;
+ }
+ } else if (ret != WOULD_HAVE_BLOCKED) {
+ diag("Agent opening file gave %s",
+ agent_return_name(ret));
+ errors++;
+ }
+
+ free(contents);
+}
+
+static void after_unlock(int fd)
+{
+ if (opened)
+ check_file_intact(fd);
+}
+
+static ssize_t pwrite_check(int fd,
+ const void *buf, size_t count, off_t offset)
+{
+ if (opened)
+ check_file_intact(fd);
+
+ return pwrite(fd, buf, count, offset);
+}
+
+static ssize_t write_check(int fd, const void *buf, size_t count)
+{
+ if (opened)
+ check_file_intact(fd);
+
+ return write(fd, buf, count);
+}
+
+static int ftruncate_check(int fd, off_t length)
+{
+ if (opened)
+ check_file_intact(fd);
+
+ return ftruncate(fd, length);
+
+}
+
+int main(int argc, char *argv[])
+{
+ const int flags[] = { TDB_DEFAULT,
+ TDB_CLEAR_IF_FIRST,
+ TDB_NOMMAP,
+ TDB_CLEAR_IF_FIRST | TDB_NOMMAP };
+ int i;
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(20);
+ agent = prepare_external_agent();
+
+ unlock_callback = after_unlock;
+ for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i++) {
+ clear_if_first = (flags[i] & TDB_CLEAR_IF_FIRST);
+ diag("Test with %s and %s",
+ clear_if_first ? "CLEAR" : "DEFAULT",
+ (flags[i] & TDB_NOMMAP) ? "no mmap" : "mmap");
+ unlink(TEST_DBNAME);
+ tdb = tdb_open_ex(TEST_DBNAME, 1024, flags[i],
+ O_CREAT|O_TRUNC|O_RDWR, 0600,
+ &taplogctx, NULL);
+ ok1(tdb);
+
+ opened = true;
+ ok1(tdb_transaction_start(tdb) == 0);
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dptr = discard_const_p(uint8_t, "world");
+ data.dsize = strlen("world");
+
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_transaction_commit(tdb) == 0);
+ ok(!errors, "We had %u open errors", errors);
+
+ opened = false;
+ tdb_close(tdb);
+ }
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-rdlock-upgrade.c b/lib/tdb/test/run-rdlock-upgrade.c
new file mode 100644
index 0000000..042001b
--- /dev/null
+++ b/lib/tdb/test/run-rdlock-upgrade.c
@@ -0,0 +1,166 @@
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+#include "logging.h"
+
+static TDB_DATA key, data;
+
+static void do_chainlock(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_chainlock_read(tdb, key);
+ ok(ret == 0, "tdb_chainlock_read should succeed");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == 0, "read should succeed");
+
+ exit(0);
+}
+
+static void do_trylock(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ /*
+ * tdb used to have a bug where with fcntl locks an upgrade
+ * from a readlock to writelock did not check for the
+ * underlying fcntl lock. Mutexes don't distinguish between
+ * readlocks and writelocks, so that bug does not apply here.
+ */
+
+ ret = tdb_chainlock_read(tdb, key);
+ ok(ret == 0, "tdb_chainlock_read should succeed");
+
+ ret = tdb_chainlock_nonblock(tdb, key);
+ ok(ret == -1, "tdb_chainlock_nonblock should fail");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == 0, "read should succeed");
+
+ exit(0);
+}
+
+static int do_tests(const char *name, int tdb_flags)
+{
+ int ret;
+ pid_t chainlock_child, store_child;
+ int chainlock_down[2];
+ int chainlock_up[2];
+ int store_down[2];
+ int store_up[2];
+ char c;
+ ssize_t nread;
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ ret = pipe(chainlock_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(chainlock_up);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(store_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(store_up);
+ ok(ret == 0, "pipe should succeed");
+
+ chainlock_child = fork();
+ ok(chainlock_child != -1, "fork should succeed");
+
+ if (chainlock_child == 0) {
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(store_up[0]);
+ close(store_up[1]);
+ close(store_down[0]);
+ close(store_down[1]);
+ do_chainlock(name, tdb_flags,
+ chainlock_up[1], chainlock_down[0]);
+ exit(0);
+ }
+ close(chainlock_up[1]);
+ close(chainlock_down[0]);
+
+ nread = read(chainlock_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ /*
+ * Now we have a process holding a chain read lock. Start
+ * another process trying to write lock. This should fail.
+ */
+
+ store_child = fork();
+ ok(store_child != -1, "fork should succeed");
+
+ if (store_child == 0) {
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(store_up[0]);
+ close(store_down[1]);
+ do_trylock(name, tdb_flags,
+ store_up[1], store_down[0]);
+ exit(0);
+ }
+ close(store_up[1]);
+ close(store_down[0]);
+
+ nread = read(store_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ close(chainlock_up[0]);
+ close(chainlock_down[1]);
+ close(store_up[0]);
+ close(store_down[1]);
+ diag("%s tests done", name);
+ return exit_status();
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ ret = do_tests("rdlock-upgrade.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "rdlock-upgrade.tdb tests should succeed");
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-readonly-check.c b/lib/tdb/test/run-readonly-check.c
new file mode 100644
index 0000000..c5e0f7d
--- /dev/null
+++ b/lib/tdb/test/run-readonly-check.c
@@ -0,0 +1,53 @@
+/* We should be able to tdb_check a O_RDONLY tdb, and we were previously allowed
+ * to tdb_check() inside a transaction (though that's paranoia!). */
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(11);
+ tdb = tdb_open_ex("run-readonly-check.tdb", 1024,
+ TDB_DEFAULT,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ ok1(tdb);
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ /* We are also allowed to do a check inside a transaction. */
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ ok1(tdb_close(tdb) == 0);
+
+ tdb = tdb_open_ex("run-readonly-check.tdb", 1024,
+ TDB_DEFAULT, O_RDONLY, 0, &taplogctx, NULL);
+
+ ok1(tdb);
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) == -1);
+ ok1(tdb_error(tdb) == TDB_ERR_RDONLY);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ ok1(tdb_close(tdb) == 0);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-rescue-find_entry.c b/lib/tdb/test/run-rescue-find_entry.c
new file mode 100644
index 0000000..5d6f8f7
--- /dev/null
+++ b/lib/tdb/test/run-rescue-find_entry.c
@@ -0,0 +1,51 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/rescue.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+#define NUM 20
+
+/* Binary searches are deceptively simple: easy to screw up! */
+int main(int argc, char *argv[])
+{
+ unsigned int i, j, n;
+ struct found f[NUM+1];
+ struct found_table table;
+
+ /* Set up array for searching. */
+ for (i = 0; i < NUM+1; i++) {
+ f[i].head = i * 3;
+ }
+ table.arr = f;
+
+ for (i = 0; i < NUM; i++) {
+ table.num = i;
+ for (j = 0; j < (i + 2) * 3; j++) {
+ n = find_entry(&table, j);
+ ok1(n <= i);
+
+ /* If we were searching for something too large... */
+ if (j > i*3)
+ ok1(n == i);
+ else {
+ /* It must give us something after j */
+ ok1(f[n].head >= j);
+ ok1(n == 0 || f[n-1].head < j);
+ }
+ }
+ }
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-rescue.c b/lib/tdb/test/run-rescue.c
new file mode 100644
index 0000000..e43f53b
--- /dev/null
+++ b/lib/tdb/test/run-rescue.c
@@ -0,0 +1,127 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/rescue.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+struct walk_data {
+ TDB_DATA key;
+ TDB_DATA data;
+ bool fail;
+ unsigned count;
+};
+
+static inline bool tdb_deq(TDB_DATA a, TDB_DATA b)
+{
+ return a.dsize == b.dsize && memcmp(a.dptr, b.dptr, a.dsize) == 0;
+}
+
+static inline TDB_DATA tdb_mkdata(const void *p, size_t len)
+{
+ TDB_DATA d;
+ d.dptr = discard_const_p(uint8_t, p);
+ d.dsize = len;
+ return d;
+}
+
+static void walk(TDB_DATA key, TDB_DATA data, void *_wd)
+{
+ struct walk_data *wd = _wd;
+
+ if (!tdb_deq(key, wd->key)) {
+ wd->fail = true;
+ }
+
+ if (!tdb_deq(data, wd->data)) {
+ wd->fail = true;
+ }
+ wd->count++;
+}
+
+static void count_records(TDB_DATA key, TDB_DATA data, void *_wd)
+{
+ struct walk_data *wd = _wd;
+
+ if (!tdb_deq(key, wd->key) || !tdb_deq(data, wd->data))
+ diag("%.*s::%.*s",
+ (int)key.dsize, key.dptr, (int)data.dsize, data.dptr);
+ wd->count++;
+}
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+ unsigned int *count = tdb_get_logging_private(tdb);
+ (*count)++;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ struct walk_data wd;
+ unsigned int i, size, log_count = 0;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+
+ plan_tests(8);
+ tdb = tdb_open_ex("run-rescue.tdb", 1, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &log_ctx, NULL);
+
+ wd.key.dsize = strlen("hi");
+ wd.key.dptr = discard_const_p(uint8_t, "hi");
+ wd.data.dsize = strlen("world");
+ wd.data.dptr = discard_const_p(uint8_t, "world");
+ wd.count = 0;
+ wd.fail = false;
+
+ ok1(tdb_store(tdb, wd.key, wd.data, TDB_INSERT) == 0);
+
+ ok1(tdb_rescue(tdb, walk, &wd) == 0);
+ ok1(!wd.fail);
+ ok1(wd.count == 1);
+
+ /* Corrupt the database, walk should either get it or not. */
+ size = tdb->map_size;
+ for (i = sizeof(struct tdb_header); i < size; i++) {
+ char c;
+ if (tdb->methods->tdb_read(tdb, i, &c, 1, false) != 0)
+ fail("Reading offset %i", i);
+ if (tdb->methods->tdb_write(tdb, i, "X", 1) != 0)
+ fail("Writing X at offset %i", i);
+
+ wd.count = 0;
+ if (tdb_rescue(tdb, count_records, &wd) != 0) {
+ wd.fail = true;
+ break;
+ }
+ /* Could be 0 or 1. */
+ if (wd.count > 1) {
+ wd.fail = true;
+ break;
+ }
+ if (tdb->methods->tdb_write(tdb, i, &c, 1) != 0)
+ fail("Restoring offset %i", i);
+ }
+ ok1(log_count == 0);
+ ok1(!wd.fail);
+ tdb_close(tdb);
+
+ /* Now try our known-corrupt db. */
+ tdb = tdb_open_ex("test/tdb.corrupt", 1024, 0, O_RDWR, 0,
+ &taplogctx, NULL);
+ wd.count = 0;
+ ok1(tdb_rescue(tdb, count_records, &wd) == 0);
+ ok1(wd.count == 1627);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-rwlock-check.c b/lib/tdb/test/run-rwlock-check.c
new file mode 100644
index 0000000..2ac9dc3
--- /dev/null
+++ b/lib/tdb/test/run-rwlock-check.c
@@ -0,0 +1,46 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+ unsigned int *count = tdb_get_logging_private(tdb);
+ if (strstr(fmt, "spinlocks"))
+ (*count)++;
+}
+
+/* The code should barf on TDBs created with rwlocks. */
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+
+ plan_tests(4);
+
+ /* We should fail to open rwlock-using tdbs of either endian. */
+ log_count = 0;
+ tdb = tdb_open_ex("test/rwlock-le.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/rwlock-be.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-summary.c b/lib/tdb/test/run-summary.c
new file mode 100644
index 0000000..8b9a1a0
--- /dev/null
+++ b/lib/tdb/test/run-summary.c
@@ -0,0 +1,65 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/summary.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT };
+ TDB_DATA key = { (unsigned char *)&j, sizeof(j) };
+ TDB_DATA data = { (unsigned char *)&j, sizeof(j) };
+ char *summary;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-summary.tdb", 131, flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ /* Put some stuff in there. */
+ for (j = 0; j < 500; j++) {
+ /* Make sure padding varies to we get some graphs! */
+ data.dsize = j % (sizeof(j) + 1);
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ fail("Storing in tdb");
+ }
+
+ summary = tdb_summary(tdb);
+ diag("%s", summary);
+ ok1(strstr(summary, "Size of file/data: "));
+ ok1(strstr(summary, "Number of records: 500\n"));
+ ok1(strstr(summary, "Smallest/average/largest keys: 4/4/4\n"));
+ ok1(strstr(summary, "Smallest/average/largest data: 0/2/4\n"));
+ ok1(strstr(summary, "Smallest/average/largest padding: "));
+ ok1(strstr(summary, "Number of dead records: 0\n"));
+ ok1(strstr(summary, "Number of free records: 1\n"));
+ ok1(strstr(summary, "Smallest/average/largest free records: "));
+ ok1(strstr(summary, "Number of hash chains: 131\n"));
+ ok1(strstr(summary, "Smallest/average/largest hash chains: "));
+ ok1(strstr(summary, "Number of uncoalesced records: 0\n"));
+ ok1(strstr(summary, "Smallest/average/largest uncoalesced runs: 0/0/0\n"));
+ ok1(strstr(summary, "Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: "));
+
+ free(summary);
+ tdb_close(tdb);
+ }
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-transaction-expand.c b/lib/tdb/test/run-transaction-expand.c
new file mode 100644
index 0000000..d36b894
--- /dev/null
+++ b/lib/tdb/test/run-transaction-expand.c
@@ -0,0 +1,125 @@
+#include "../common/tdb_private.h"
+
+/* Speed up the tests, but do the actual sync tests. */
+static unsigned int sync_counts = 0;
+static inline int fake_fsync(int fd)
+{
+ sync_counts++;
+ return 0;
+}
+#define fsync fake_fsync
+
+#ifdef MS_SYNC
+static inline int fake_msync(void *addr, size_t length, int flags)
+{
+ sync_counts++;
+ return 0;
+}
+#define msync fake_msync
+#endif
+
+#ifdef HAVE_FDATASYNC
+static inline int fake_fdatasync(int fd)
+{
+ sync_counts++;
+ return 0;
+}
+#define fdatasync fake_fdatasync
+#endif
+
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+static void write_record(struct tdb_context *tdb, size_t extra_len,
+ TDB_DATA *data)
+{
+ TDB_DATA key;
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+
+ data->dsize += extra_len;
+ tdb_transaction_start(tdb);
+ tdb_store(tdb, key, *data, TDB_REPLACE);
+ tdb_transaction_commit(tdb);
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ size_t i;
+ TDB_DATA data;
+ struct tdb_record rec;
+ tdb_off_t off;
+
+ /* Do *not* suppress sync for this test; we do it ourselves. */
+ unsetenv("TDB_NO_FSYNC");
+
+ plan_tests(5);
+ tdb = tdb_open_ex("run-transaction-expand.tdb",
+ 1024, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+ ok1(tdb);
+
+ data.dsize = 0;
+ data.dptr = calloc(1000, getpagesize());
+ if (data.dptr == NULL) {
+ diag("Unable to allocate memory for data.dptr");
+ tdb_close(tdb);
+ exit(1);
+ }
+
+ /* Simulate a slowly growing record. */
+ for (i = 0; i < 1000; i++)
+ write_record(tdb, getpagesize(), &data);
+
+ tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off);
+ tdb_read(tdb, off, &rec, sizeof(rec), DOCONV());
+ diag("TDB size = %zu, recovery = %llu-%llu",
+ (size_t)tdb->map_size, (unsigned long long)off, (unsigned long long)(off + sizeof(rec) + rec.rec_len));
+
+ /* We should only be about 5 times larger than largest record. */
+ ok1(tdb->map_size < 6 * i * getpagesize());
+ tdb_close(tdb);
+
+ tdb = tdb_open_ex("run-transaction-expand.tdb",
+ 1024, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+ ok1(tdb);
+
+ data.dsize = 0;
+
+ /* Simulate a slowly growing record, repacking to keep
+ * recovery area at end. */
+ for (i = 0; i < 1000; i++) {
+ write_record(tdb, getpagesize(), &data);
+ if (i % 10 == 0)
+ tdb_repack(tdb);
+ }
+
+ tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off);
+ tdb_read(tdb, off, &rec, sizeof(rec), DOCONV());
+ diag("TDB size = %zu, recovery = %llu-%llu",
+ (size_t)tdb->map_size, (unsigned long long)off, (unsigned long long)(off + sizeof(rec) + rec.rec_len));
+
+ /* We should only be about 4 times larger than largest record. */
+ ok1(tdb->map_size < 5 * i * getpagesize());
+
+ /* We should have synchronized multiple times. */
+ ok1(sync_counts);
+ tdb_close(tdb);
+ free(data.dptr);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-traverse-chain.c b/lib/tdb/test/run-traverse-chain.c
new file mode 100644
index 0000000..2a25bec
--- /dev/null
+++ b/lib/tdb/test/run-traverse-chain.c
@@ -0,0 +1,94 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+static char keystr0[] = "x";
+static TDB_DATA key0 = { .dptr = (uint8_t *)keystr0,
+ .dsize = sizeof(keystr0) };
+static char valuestr0[] = "y";
+static TDB_DATA value0 = { .dptr = (uint8_t *)valuestr0,
+ .dsize = sizeof(valuestr0) };
+
+static char keystr1[] = "aaa";
+static TDB_DATA key1 = { .dptr = (uint8_t *)keystr1,
+ .dsize = sizeof(keystr1) };
+static char valuestr1[] = "bbbbb";
+static TDB_DATA value1 = { .dptr = (uint8_t *)valuestr1,
+ .dsize = sizeof(valuestr1) };
+
+static TDB_DATA *keys[] = { &key0, &key1 };
+static TDB_DATA *values[] = { &value0, &value1 };
+
+static bool tdb_data_same(TDB_DATA d1, TDB_DATA d2)
+{
+ if (d1.dsize != d2.dsize) {
+ return false;
+ }
+ return (memcmp(d1.dptr, d2.dptr, d1.dsize) == 0);
+}
+
+struct traverse_chain_state {
+ size_t idx;
+ bool ok;
+};
+
+static int traverse_chain_fn(struct tdb_context *tdb,
+ TDB_DATA key,
+ TDB_DATA data,
+ void *private_data)
+{
+ struct traverse_chain_state *state = private_data;
+
+ state->ok &= tdb_data_same(key, *keys[state->idx]);
+ state->ok &= tdb_data_same(data, *values[state->idx]);
+ state->idx += 1;
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ struct traverse_chain_state state = { .ok = true };
+ int ret;
+
+ plan_tests(4);
+
+ tdb = tdb_open_ex(
+ "traverse_chain.tdb",
+ 1,
+ TDB_CLEAR_IF_FIRST,
+ O_RDWR|O_CREAT,
+ 0600,
+ &taplogctx,
+ NULL);
+ ok1(tdb);
+
+ /* add in reverse order, tdb_store adds to the front of the list */
+ ret = tdb_store(tdb, key1, value1, TDB_INSERT);
+ ok1(ret == 0);
+ ret = tdb_store(tdb, key0, value0, TDB_INSERT);
+ ok1(ret == 0);
+
+ ret = tdb_traverse_key_chain(tdb, key0, traverse_chain_fn, &state);
+ ok1(ret == 2);
+ ok1(state.ok);
+
+ unlink(tdb_name(tdb));
+
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-traverse-in-transaction.c b/lib/tdb/test/run-traverse-in-transaction.c
new file mode 100644
index 0000000..d187b9b
--- /dev/null
+++ b/lib/tdb/test/run-traverse-in-transaction.c
@@ -0,0 +1,90 @@
+#include "lock-tracking.h"
+#include "../common/tdb_private.h"
+#define fcntl fcntl_with_lockcheck
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#undef fcntl_with_lockcheck
+#include <stdlib.h>
+#include <stdbool.h>
+#include "external-agent.h"
+#include "logging.h"
+
+static struct agent *agent;
+
+static bool correct_key(TDB_DATA key)
+{
+ return key.dsize == strlen("hi")
+ && memcmp(key.dptr, "hi", key.dsize) == 0;
+}
+
+static bool correct_data(TDB_DATA data)
+{
+ return data.dsize == strlen("world")
+ && memcmp(data.dptr, "world", data.dsize) == 0;
+}
+
+static int traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
+ void *p)
+{
+ ok1(correct_key(key));
+ ok1(correct_data(data));
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(13);
+ agent = prepare_external_agent();
+
+ tdb = tdb_open_ex("run-traverse-in-transaction.tdb",
+ 1024, TDB_CLEAR_IF_FIRST, O_CREAT|O_TRUNC|O_RDWR,
+ 0600, &taplogctx, NULL);
+ ok1(tdb);
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dptr = discard_const_p(uint8_t, "world");
+ data.dsize = strlen("world");
+
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+
+ ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS);
+
+ ok1(tdb_transaction_active(tdb) == 0);
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_transaction_active(tdb) == 1);
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ tdb_traverse(tdb, traverse, NULL);
+
+ /* That should *not* release the transaction lock! */
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ tdb_traverse_read(tdb, traverse, NULL);
+
+ /* That should *not* release the transaction lock! */
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == WOULD_HAVE_BLOCKED);
+ ok1(tdb_transaction_commit(tdb) == 0);
+ ok1(tdb_transaction_active(tdb) == 0);
+ /* Now we should be fine. */
+ ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
+ == SUCCESS);
+
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-wronghash-fail.c b/lib/tdb/test/run-wronghash-fail.c
new file mode 100644
index 0000000..c44b0f5
--- /dev/null
+++ b/lib/tdb/test/run-wronghash-fail.c
@@ -0,0 +1,121 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+ unsigned int *count = tdb_get_logging_private(tdb);
+ if (strstr(fmt, "hash"))
+ (*count)++;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ TDB_DATA d;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+
+ plan_tests(28);
+
+ /* Create with default hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0,
+ O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx, NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ d.dptr = discard_const_p(uint8_t, "Hello");
+ d.dsize = 5;
+ ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
+ tdb_close(tdb);
+
+ /* Fail to open with different hash. */
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, tdb_jenkins_hash);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ /* Create with different hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0,
+ O_CREAT|O_RDWR|O_TRUNC,
+ 0600, &log_ctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ tdb_close(tdb);
+
+ /* Endian should be no problem. */
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, tdb_old_hash);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, tdb_old_hash);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ log_count = 0;
+ /* Fail to open with old default hash. */
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, tdb_old_hash);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY,
+ 0, &log_ctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY,
+ 0, &log_ctx, tdb_jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ /* It should open with jenkins hash if we don't specify. */
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+ log_count = 0;
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDONLY,
+ 0, &log_ctx, NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run-zero-append.c b/lib/tdb/test/run-zero-append.c
new file mode 100644
index 0000000..f9eba1b
--- /dev/null
+++ b/lib/tdb/test/run-zero-append.c
@@ -0,0 +1,41 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(4);
+ tdb = tdb_open_ex(NULL, 1024, TDB_INTERNAL, O_CREAT|O_TRUNC|O_RDWR,
+ 0600, &taplogctx, NULL);
+ ok1(tdb);
+
+ /* Tickle bug on appending zero length buffer to zero length buffer. */
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dptr = discard_const_p(uint8_t, "world");
+ data.dsize = 0;
+
+ ok1(tdb_append(tdb, key, data) == 0);
+ ok1(tdb_append(tdb, key, data) == 0);
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == 0);
+ tdb_close(tdb);
+ free(data.dptr);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/run.c b/lib/tdb/test/run.c
new file mode 100644
index 0000000..c744c4d
--- /dev/null
+++ b/lib/tdb/test/run.c
@@ -0,0 +1,50 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ TDB_DATA key, data;
+
+ plan_tests(10);
+ tdb = tdb_open_ex("run.tdb", 1024, TDB_CLEAR_IF_FIRST,
+ O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
+
+ ok1(tdb);
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) < 0);
+ ok1(tdb_error(tdb) == TDB_ERR_NOEXIST);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) < 0);
+ ok1(tdb_error(tdb) == TDB_ERR_EXISTS);
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0);
+
+ data = tdb_fetch(tdb, key);
+ ok1(data.dsize == strlen("world"));
+ ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
+ free(data.dptr);
+
+ key.dsize++;
+ data = tdb_fetch(tdb, key);
+ ok1(data.dptr == NULL);
+ tdb_close(tdb);
+
+ return exit_status();
+}
diff --git a/lib/tdb/test/rwlock-be.tdb b/lib/tdb/test/rwlock-be.tdb
new file mode 100644
index 0000000..45b5f09
--- /dev/null
+++ b/lib/tdb/test/rwlock-be.tdb
Binary files differ
diff --git a/lib/tdb/test/rwlock-le.tdb b/lib/tdb/test/rwlock-le.tdb
new file mode 100644
index 0000000..45b5f09
--- /dev/null
+++ b/lib/tdb/test/rwlock-le.tdb
Binary files differ
diff --git a/lib/tdb/test/sample_tdb.tdb b/lib/tdb/test/sample_tdb.tdb
new file mode 100644
index 0000000..a40e50c
--- /dev/null
+++ b/lib/tdb/test/sample_tdb.tdb
Binary files differ
diff --git a/lib/tdb/test/tap-interface.h b/lib/tdb/test/tap-interface.h
new file mode 100644
index 0000000..8f742d8
--- /dev/null
+++ b/lib/tdb/test/tap-interface.h
@@ -0,0 +1,58 @@
+/*
+ Unix SMB/CIFS implementation.
+ Simplistic implementation of tap interface.
+
+ Copyright (C) Rusty Russell 2012
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+
+#ifndef __location__
+#define __TAP_STRING_LINE1__(s) #s
+#define __TAP_STRING_LINE2__(s) __TAP_STRING_LINE1__(s)
+#define __TAP_STRING_LINE3__ __TAP_STRING_LINE2__(__LINE__)
+#define __location__ __FILE__ ":" __TAP_STRING_LINE3__
+#endif
+
+#define plan_tests(num)
+#define fail(...) do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ fflush(stderr); \
+ exit(1); \
+} while(0)
+#define diag(...) do { \
+ fprintf(stdout, __VA_ARGS__); \
+ fprintf(stdout, "\n"); \
+ fflush(stdout); \
+} while(0)
+#define pass(...) do { \
+ fprintf(stdout, "."); \
+ fflush(stdout); \
+} while(0)
+#define ok(e, ...) do { \
+ if (e) { \
+ pass(); \
+ } else { \
+ fail(__VA_ARGS__); \
+ } \
+} while(0)
+#define ok1(e) ok((e), "%s:%s", __location__, #e)
+#define skip(n, ...) diag(__VA_ARGS__)
+#define exit_status() 0
diff --git a/lib/tdb/test/tap-to-subunit.h b/lib/tdb/test/tap-to-subunit.h
new file mode 100644
index 0000000..a5cf74f
--- /dev/null
+++ b/lib/tdb/test/tap-to-subunit.h
@@ -0,0 +1,155 @@
+#ifndef TAP_TO_SUBUNIT_H
+#define TAP_TO_SUBUNIT_H
+/*
+ * tap-style wrapper for subunit.
+ *
+ * Copyright (c) 2011 Rusty Russell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 AUTHOR OR CONTRIBUTORS 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.
+ */
+#include "replace.h"
+
+/**
+ * plan_tests - announce the number of tests you plan to run
+ * @tests: the number of tests
+ *
+ * This should be the first call in your test program: it allows tracing
+ * of failures which mean that not all tests are run.
+ *
+ * If you don't know how many tests will actually be run, assume all of them
+ * and use skip() if you don't actually run some tests.
+ *
+ * Example:
+ * plan_tests(13);
+ */
+void plan_tests(unsigned int tests);
+
+/**
+ * ok1 - Simple conditional test
+ * @e: the expression which we expect to be true.
+ *
+ * This is the simplest kind of test: if the expression is true, the
+ * test passes. The name of the test which is printed will simply be
+ * file name, line number, and the expression itself.
+ *
+ * Example:
+ * ok1(somefunc() == 1);
+ */
+# define ok1(e) ((e) ? \
+ _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
+ _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
+
+/**
+ * ok - Conditional test with a name
+ * @e: the expression which we expect to be true.
+ * @...: the printf-style name of the test.
+ *
+ * If the expression is true, the test passes. The name of the test will be
+ * the filename, line number, and the printf-style string. This can be clearer
+ * than simply the expression itself.
+ *
+ * Example:
+ * ok1(somefunc() == 1);
+ * ok(somefunc() == 0, "Second somefunc() should fail");
+ */
+# define ok(e, ...) ((e) ? \
+ _gen_result(1, __func__, __FILE__, __LINE__, \
+ __VA_ARGS__) : \
+ _gen_result(0, __func__, __FILE__, __LINE__, \
+ __VA_ARGS__))
+
+/**
+ * pass - Note that a test passed
+ * @...: the printf-style name of the test.
+ *
+ * For complicated code paths, it can be easiest to simply call pass() in one
+ * branch and fail() in another.
+ *
+ * Example:
+ * int x = somefunc();
+ * if (x > 0)
+ * pass("somefunc() returned a valid value");
+ * else
+ * fail("somefunc() returned an invalid value");
+ */
+# define pass(...) ok(1, __VA_ARGS__)
+
+/**
+ * fail - Note that a test failed
+ * @...: the printf-style name of the test.
+ *
+ * For complicated code paths, it can be easiest to simply call pass() in one
+ * branch and fail() in another.
+ */
+# define fail(...) ok(0, __VA_ARGS__)
+
+unsigned int _gen_result(int, const char *, const char *, unsigned int,
+ const char *, ...) PRINTF_ATTRIBUTE(5, 6);
+
+/**
+ * diag - print a diagnostic message (use instead of printf/fprintf)
+ * @fmt: the format of the printf-style message
+ *
+ * diag ensures that the output will not be considered to be a test
+ * result by the TAP test harness. It will append '\n' for you.
+ *
+ * Example:
+ * diag("Now running complex tests");
+ */
+void diag(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/**
+ * skip - print a diagnostic message (use instead of printf/fprintf)
+ * @n: number of tests you're skipping.
+ * @fmt: the format of the reason you're skipping the tests.
+ *
+ * Sometimes tests cannot be run because the test system lacks some feature:
+ * you should explicitly document that you're skipping tests using skip().
+ *
+ * From the Test::More documentation:
+ * If it's something the user might not be able to do, use SKIP. This
+ * includes optional modules that aren't installed, running under an OS that
+ * doesn't have some feature (like fork() or symlinks), or maybe you need an
+ * Internet connection and one isn't available.
+ *
+ * Example:
+ * #ifdef HAVE_SOME_FEATURE
+ * ok1(somefunc());
+ * #else
+ * skip(1, "Don't have SOME_FEATURE");
+ * #endif
+ */
+void skip(unsigned int n, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+
+/**
+ * exit_status - the value that main should return.
+ *
+ * For maximum compatibility your test program should return a particular exit
+ * code (ie. 0 if all tests were run, and every test which was expected to
+ * succeed succeeded).
+ *
+ * Example:
+ * exit(exit_status());
+ */
+int exit_status(void);
+#endif /* CCAN_TAP_H */
diff --git a/lib/tdb/test/tdb.corrupt b/lib/tdb/test/tdb.corrupt
new file mode 100644
index 0000000..83d6677
--- /dev/null
+++ b/lib/tdb/test/tdb.corrupt
Binary files differ
diff --git a/lib/tdb/test/test_tdbbackup.sh b/lib/tdb/test/test_tdbbackup.sh
new file mode 100755
index 0000000..8552ea1
--- /dev/null
+++ b/lib/tdb/test/test_tdbbackup.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Blackbox test for tdbbackup of given ldb or tdb database
+# Copyright (C) 2018 Andrew Bartlett <abartlet@samba.org>
+
+if [ $# -lt 1 ]; then
+ echo "Usage: $0 LDBFILE"
+ exit 1
+fi
+
+LDBFILE=$1
+
+timestamp()
+{
+ date -u +'time: %Y-%m-%d %H:%M:%S.%6NZ' | sed 's/\..*NZ$/.000000Z/'
+}
+
+subunit_fail_test()
+{
+ timestamp
+ printf 'failure: %s [\n' "$1"
+ cat -
+ echo "]"
+}
+
+testit()
+{
+ name="$1"
+ shift
+ cmdline="$@"
+ timestamp
+ printf 'test: %s\n' "$1"
+ output=$($cmdline 2>&1)
+ status=$?
+ if [ x$status = x0 ]; then
+ timestamp
+ printf 'success: %s\n' "$name"
+ else
+ echo "$output" | subunit_fail_test "$name"
+ fi
+ return $status
+}
+
+$BINDIR/tdbdump $LDBFILE | sort >orig_dump
+
+testit "normal tdbbackup on tdb file" $BINDIR/tdbbackup $LDBFILE -s .bak
+$BINDIR/tdbdump $LDBFILE.bak | sort >bak_dump
+testit "cmp between tdbdumps of original and backup" cmp orig_dump bak_dump
+rm $LDBFILE.bak
+rm bak_dump
+
+testit "readonly tdbbackup on tdb file" $BINDIR/tdbbackup $LDBFILE -s .bak -r
+$BINDIR/tdbdump $LDBFILE.bak | sort >bak_dump
+testit "cmp between tdbdumps of original and back dbs" cmp orig_dump bak_dump
+rm $LDBFILE.bak
+rm bak_dump
+
+rm orig_dump
diff --git a/lib/tdb/tools/tdbbackup.c b/lib/tdb/tools/tdbbackup.c
new file mode 100644
index 0000000..1125987
--- /dev/null
+++ b/lib/tdb/tools/tdbbackup.c
@@ -0,0 +1,370 @@
+/*
+ Unix SMB/CIFS implementation.
+ low level tdb backup and restore utility
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+
+ This program is meant for backup/restore of tdb databases. Typical usage would be:
+ tdbbackup *.tdb
+ when Samba shuts down cleanly, which will make a backup of all the local databases
+ to *.bak files. Then on Samba startup you would use:
+ tdbbackup -v *.tdb
+ and this will check the databases for corruption and if corruption is detected then
+ the backup will be restored.
+
+ You may also like to do a backup on a regular basis while Samba is
+ running, perhaps using cron.
+
+ The reason this program is needed is to cope with power failures
+ while Samba is running. A power failure could lead to database
+ corruption and Samba will then not start correctly.
+
+ Note that many of the databases in Samba are transient and thus
+ don't need to be backed up, so you can optimise the above a little
+ by only running the backup on the critical databases.
+
+ */
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+static int failed;
+
+static struct tdb_logging_context log_ctx;
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+}
+
+static char *add_suffix(const char *name, const char *suffix)
+{
+ char *ret;
+ int len = strlen(name) + strlen(suffix) + 1;
+ ret = (char *)malloc(len);
+ if (!ret) {
+ fprintf(stderr,"Out of memory!\n");
+ exit(1);
+ }
+ snprintf(ret, len, "%s%s", name, suffix);
+ return ret;
+}
+
+static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
+
+ if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
+ fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb_new));
+ failed = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
+static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ return 0;
+}
+
+/*
+ carefully backup a tdb, validating the contents and
+ only doing the backup if its OK
+ this function is also used for restore
+*/
+static int backup_tdb(const char *old_name, const char *new_name,
+ int hash_size, int nolock, bool readonly)
+{
+ TDB_CONTEXT *tdb;
+ TDB_CONTEXT *tdb_new;
+ char *tmp_name;
+ struct stat st;
+ int count1, count2;
+
+ tmp_name = add_suffix(new_name, ".tmp");
+
+ /* stat the old tdb to find its permissions */
+ if (stat(old_name, &st) != 0) {
+ perror(old_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* open the old tdb */
+ tdb = tdb_open_ex(old_name, 0,
+ TDB_DEFAULT | (nolock ? TDB_NOLOCK : 0),
+ O_RDWR, 0, &log_ctx, NULL);
+ if (!tdb) {
+ printf("Failed to open %s\n", old_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* create the new tdb */
+ unlink(tmp_name);
+ tdb_new = tdb_open_ex(tmp_name,
+ hash_size ? hash_size : tdb_hash_size(tdb),
+ TDB_DEFAULT,
+ O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777,
+ &log_ctx, NULL);
+ if (!tdb_new) {
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ if (readonly) {
+ if (tdb_lockall_read(tdb) != 0) {
+ printf("Failed to obtain read only lock on old tdb\n");
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+ } else if (tdb_transaction_start(tdb) != 0) {
+ printf("Failed to start transaction on db\n");
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* lock the backup tdb so that nobody else can change it */
+ if (tdb_lockall(tdb_new) != 0) {
+ printf("Failed to lock backup tdb\n");
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ failed = 0;
+
+ /* traverse and copy */
+ if (readonly) {
+ count1 = tdb_traverse_read(tdb,
+ copy_fn,
+ (void *)tdb_new);
+ } else {
+ count1 = tdb_traverse(tdb,
+ copy_fn,
+ (void *)tdb_new);
+ }
+ if (count1 < 0 || failed) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* close the old tdb */
+ tdb_close(tdb);
+
+ /* copy done, unlock the backup tdb */
+ tdb_unlockall(tdb_new);
+
+#ifdef HAVE_FDATASYNC
+ if (fdatasync(tdb_fd(tdb_new)) != 0) {
+#else
+ if (fsync(tdb_fd(tdb_new)) != 0) {
+#endif
+ /* not fatal */
+ fprintf(stderr, "failed to fsync backup file\n");
+ }
+
+ /* close the new tdb and re-open read-only */
+ tdb_close(tdb_new);
+ tdb_new = tdb_open_ex(tmp_name,
+ 0,
+ TDB_DEFAULT,
+ O_RDONLY, 0,
+ &log_ctx, NULL);
+ if (!tdb_new) {
+ fprintf(stderr,"failed to reopen %s\n", tmp_name);
+ unlink(tmp_name);
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* traverse the new tdb to confirm */
+ count2 = tdb_traverse(tdb_new, test_fn, NULL);
+ if (count2 != count1) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* close the new tdb and rename it to .bak */
+ tdb_close(tdb_new);
+ if (rename(tmp_name, new_name) != 0) {
+ perror(new_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ free(tmp_name);
+
+ return 0;
+}
+
+/*
+ verify a tdb and if it is corrupt then restore from *.bak
+*/
+static int verify_tdb(const char *fname, const char *bak_name)
+{
+ TDB_CONTEXT *tdb;
+ int count = -1;
+
+ /* open the tdb */
+ tdb = tdb_open_ex(fname, 0, 0,
+ O_RDONLY, 0, &log_ctx, NULL);
+
+ /* traverse the tdb, then close it */
+ if (tdb) {
+ count = tdb_traverse(tdb, test_fn, NULL);
+ tdb_close(tdb);
+ }
+
+ /* count is < 0 means an error */
+ if (count < 0) {
+ printf("restoring %s\n", fname);
+ return backup_tdb(bak_name, fname, 0, 0, 0);
+ }
+
+ printf("%s : %d records\n", fname, count);
+
+ return 0;
+}
+
+/*
+ see if one file is newer than another
+*/
+static int file_newer(const char *fname1, const char *fname2)
+{
+ struct stat st1, st2;
+ if (stat(fname1, &st1) != 0) {
+ return 0;
+ }
+ if (stat(fname2, &st2) != 0) {
+ return 1;
+ }
+ return (st1.st_mtime > st2.st_mtime);
+}
+
+static void usage(void)
+{
+ printf("Usage: tdbbackup [options] <fname...>\n\n");
+ printf(" -h this help message\n");
+ printf(" -s suffix set the backup suffix\n");
+ printf(" -v verify mode (restore if corrupt)\n");
+ printf(" -n hashsize set the new hash size for the backup\n");
+ printf(" -l open without locking to back up mutex dbs\n");
+ printf(" -r open with read only locking\n");
+}
+
+ int main(int argc, char *argv[])
+{
+ int i;
+ int ret = 0;
+ int c;
+ int verify = 0;
+ int hashsize = 0;
+ int nolock = 0;
+ bool readonly = false;
+ const char *suffix = ".bak";
+
+ log_ctx.log_fn = tdb_log;
+
+ while ((c = getopt(argc, argv, "vhs:n:lr")) != -1) {
+ switch (c) {
+ case 'h':
+ usage();
+ exit(0);
+ case 'v':
+ verify = 1;
+ break;
+ case 's':
+ suffix = optarg;
+ break;
+ case 'n':
+ hashsize = atoi(optarg);
+ break;
+ case 'l':
+ nolock = 1;
+ break;
+ case 'r':
+ readonly = true;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ for (i=0; i<argc; i++) {
+ const char *fname = argv[i];
+ char *bak_name;
+
+ bak_name = add_suffix(fname, suffix);
+
+ if (verify) {
+ if (verify_tdb(fname, bak_name) != 0) {
+ ret = 1;
+ }
+ } else {
+ if (file_newer(fname, bak_name) &&
+ backup_tdb(fname, bak_name, hashsize,
+ nolock, readonly) != 0) {
+ ret = 1;
+ }
+ }
+
+ free(bak_name);
+ }
+
+ return ret;
+}
diff --git a/lib/tdb/tools/tdbdump.c b/lib/tdb/tools/tdbdump.c
new file mode 100644
index 0000000..9f1ab91
--- /dev/null
+++ b/lib/tdb/tools/tdbdump.c
@@ -0,0 +1,181 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple tdb dump util
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+static void print_data(TDB_DATA d)
+{
+ unsigned char *p = (unsigned char *)d.dptr;
+ int len = d.dsize;
+ while (len--) {
+ if (isprint(*p) && !strchr("\"\\", *p)) {
+ fputc(*p, stdout);
+ } else {
+ printf("\\%02X", *p);
+ }
+ p++;
+ }
+}
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("{\n");
+ printf("key(%zu) = \"", key.dsize);
+ print_data(key);
+ printf("\"\n");
+ printf("data(%zu) = \"", dbuf.dsize);
+ print_data(dbuf);
+ printf("\"\n");
+ printf("}\n");
+ return 0;
+}
+
+static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ const char *name = tdb_name(tdb);
+ const char *prefix = "";
+
+ if (!name)
+ name = "unnamed";
+
+ switch (level) {
+ case TDB_DEBUG_ERROR:
+ prefix = "ERROR: ";
+ break;
+ case TDB_DEBUG_WARNING:
+ prefix = "WARNING: ";
+ break;
+ case TDB_DEBUG_TRACE:
+ return;
+
+ default:
+ case TDB_DEBUG_FATAL:
+ prefix = "FATAL: ";
+ break;
+ }
+
+ va_start(ap, fmt);
+ fprintf(stderr, "tdb(%s): %s", name, prefix);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname)
+{
+ if (keyname) {
+ if (key.dsize != strlen(keyname))
+ return;
+ if (memcmp(key.dptr, keyname, key.dsize) != 0)
+ return;
+ }
+ traverse_fn(NULL, key, dbuf, NULL);
+}
+
+static int dump_tdb(const char *fname, const char *keyname, bool emergency)
+{
+ TDB_CONTEXT *tdb;
+ TDB_DATA key, value;
+ struct tdb_logging_context logfn = {
+ .log_fn = log_stderr,
+ };
+ int tdb_flags = TDB_DEFAULT;
+
+ /*
+ * Note: that O_RDONLY implies TDB_NOLOCK, but we want to make it
+ * explicit as it's important when working on databases which were
+ * created with mutex locking.
+ */
+ tdb_flags |= TDB_NOLOCK;
+
+ tdb = tdb_open_ex(fname, 0, tdb_flags, O_RDONLY, 0, &logfn, NULL);
+ if (!tdb) {
+ printf("Failed to open %s\n", fname);
+ return 1;
+ }
+
+ if (emergency) {
+ return tdb_rescue(tdb, emergency_walk, discard_const(keyname)) == 0;
+ }
+ if (!keyname) {
+ return tdb_traverse(tdb, traverse_fn, NULL) == -1 ? 1 : 0;
+ } else {
+ key.dptr = discard_const_p(uint8_t, keyname);
+ key.dsize = strlen(keyname);
+ value = tdb_fetch(tdb, key);
+ if (!value.dptr) {
+ return 1;
+ } else {
+ print_data(value);
+ free(value.dptr);
+ }
+ }
+
+ return 0;
+}
+
+static void usage( void)
+{
+ printf( "Usage: tdbdump [options] <filename>\n\n");
+ printf( " -h this help message\n");
+ printf( " -k keyname dumps value of keyname\n");
+ printf( " -e emergency dump, for corrupt databases\n");
+}
+
+ int main(int argc, char *argv[])
+{
+ char *fname, *keyname=NULL;
+ bool emergency = false;
+ int c;
+
+ if (argc < 2) {
+ printf("Usage: tdbdump <fname>\n");
+ exit(1);
+ }
+
+ while ((c = getopt( argc, argv, "hk:e")) != -1) {
+ switch (c) {
+ case 'h':
+ usage();
+ exit( 0);
+ case 'k':
+ keyname = optarg;
+ break;
+ case 'e':
+ emergency = true;
+ break;
+ default:
+ usage();
+ exit( 1);
+ }
+ }
+
+ fname = argv[optind];
+
+ return dump_tdb(fname, keyname, emergency);
+}
diff --git a/lib/tdb/tools/tdbrestore.c b/lib/tdb/tools/tdbrestore.c
new file mode 100644
index 0000000..1435758
--- /dev/null
+++ b/lib/tdb/tools/tdbrestore.c
@@ -0,0 +1,202 @@
+/*
+ tdbrestore -- construct a tdb from tdbdump output.
+ Copyright (C) Volker Lendecke 2010
+ Copyright (C) Simon McVittie 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <assert.h>
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+static int read_linehead(FILE *f)
+{
+ size_t i;
+ int c;
+ int num_bytes;
+ char prefix[128];
+
+ while (1) {
+ c = getc(f);
+ if (c == EOF) {
+ return -1;
+ }
+ if (c == '(') {
+ break;
+ }
+ }
+ for (i=0; i<sizeof(prefix); i++) {
+ c = getc(f);
+ if (c == EOF) {
+ return -1;
+ }
+ prefix[i] = c;
+ if (c == '"') {
+ break;
+ }
+ }
+ if (i == sizeof(prefix)) {
+ return -1;
+ }
+ prefix[i] = '\0';
+
+ if (sscanf(prefix, "%d) = ", &num_bytes) != 1) {
+ return -1;
+ }
+ return num_bytes;
+}
+
+static int read_data(FILE *f, TDB_DATA *d, size_t size) {
+ size_t i;
+
+ d->dptr = (unsigned char *)malloc(size);
+ if (d->dptr == NULL) {
+ return -1;
+ }
+ d->dsize = size;
+
+ for (i=0; i<size; i++) {
+ int c = getc(f);
+ if (c == EOF) {
+ fprintf(stderr, "Unexpected EOF in data\n");
+ return 1;
+ } else if (c == '"') {
+ return 0;
+ } else if (c == '\\') {
+ char in[3] = {0};
+ size_t n;
+ bool ok;
+
+ n = fread(in, 1, 2, stdin);
+ if (n != 2) {
+ return -1;
+ }
+ ok = hex_byte(in, &d->dptr[i]);
+ if (!ok) {
+ fprintf(stderr, "Invalid hex: .2%s\n", in);
+ return -1;
+ }
+ } else {
+ d->dptr[i] = c;
+ }
+ }
+ return 0;
+}
+
+static int swallow(FILE *f, const char *s, int *eof)
+{
+ char line[128];
+
+ if (fgets(line, sizeof(line), f) == NULL) {
+ if (eof != NULL) {
+ *eof = 1;
+ }
+ return -1;
+ }
+ if (strcmp(line, s) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static int read_rec(FILE *f, TDB_CONTEXT *tdb, int *eof)
+{
+ int length;
+ TDB_DATA key, data;
+ int ret = -1;
+
+ key.dptr = NULL;
+ data.dptr = NULL;
+
+ if (swallow(f, "{\n", eof) == -1) {
+ goto fail;
+ }
+ length = read_linehead(f);
+ if (length == -1) {
+ goto fail;
+ }
+ if (read_data(f, &key, length) == -1) {
+ goto fail;
+ }
+ if (swallow(f, "\"\n", NULL) == -1) {
+ goto fail;
+ }
+ length = read_linehead(f);
+ if (length == -1) {
+ goto fail;
+ }
+ if (read_data(f, &data, length) == -1) {
+ goto fail;
+ }
+ if ((swallow(f, "\"\n", NULL) == -1)
+ || (swallow(f, "}\n", NULL) == -1)) {
+ goto fail;
+ }
+ if (tdb_store(tdb, key, data, TDB_INSERT) != 0) {
+ fprintf(stderr, "TDB error: %s\n", tdb_errorstr(tdb));
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ free(key.dptr);
+ free(data.dptr);
+ return ret;
+}
+
+static int restore_tdb(const char *fname)
+{
+ TDB_CONTEXT *tdb;
+
+ tdb = tdb_open(fname, 0, 0, O_RDWR|O_CREAT|O_EXCL, 0666);
+ if (!tdb) {
+ perror("tdb_open");
+ fprintf(stderr, "Failed to open %s\n", fname);
+ return 1;
+ }
+
+ while (1) {
+ int eof = 0;
+ if (read_rec(stdin, tdb, &eof) == -1) {
+ if (eof) {
+ break;
+ }
+ return 1;
+ }
+ }
+ if (tdb_close(tdb)) {
+ fprintf(stderr, "Error closing tdb\n");
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char *fname;
+
+ if (argc < 2) {
+ printf("Usage: %s dbname < tdbdump_output\n", argv[0]);
+ exit(1);
+ }
+
+ fname = argv[1];
+
+ return restore_tdb(fname);
+}
diff --git a/lib/tdb/tools/tdbtest.c b/lib/tdb/tools/tdbtest.c
new file mode 100644
index 0000000..0be35dc
--- /dev/null
+++ b/lib/tdb/tools/tdbtest.c
@@ -0,0 +1,290 @@
+/* a test program for tdb - the trivial database */
+
+#include "replace.h"
+#include "tdb.h"
+#include "system/filesys.h"
+#include "system/time.h"
+
+#include <gdbm.h>
+
+
+#define DELETE_PROB 7
+#define STORE_PROB 5
+
+static struct tdb_context *db;
+static GDBM_FILE gdbm;
+
+struct timeval tp1,tp2;
+
+static void _start_timer(void)
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double _end_timer(void)
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+static void fatal(const char *why)
+{
+ perror(why);
+ exit(1);
+}
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+}
+
+static void compare_db(void)
+{
+ TDB_DATA d, key, nextkey;
+ datum gd, gkey, gnextkey;
+
+ key = tdb_firstkey(db);
+ while (key.dptr) {
+ d = tdb_fetch(db, key);
+ gkey.dptr = key.dptr;
+ gkey.dsize = key.dsize;
+
+ gd = gdbm_fetch(gdbm, gkey);
+
+ if (!gd.dptr) fatal("key not in gdbm");
+ if (gd.dsize != d.dsize) fatal("data sizes differ");
+ if (memcmp(gd.dptr, d.dptr, d.dsize)) {
+ fatal("data differs");
+ }
+
+ nextkey = tdb_nextkey(db, key);
+ free(key.dptr);
+ free(d.dptr);
+ free(gd.dptr);
+ key = nextkey;
+ }
+
+ gkey = gdbm_firstkey(gdbm);
+ while (gkey.dptr) {
+ gd = gdbm_fetch(gdbm, gkey);
+ key.dptr = gkey.dptr;
+ key.dsize = gkey.dsize;
+
+ d = tdb_fetch(db, key);
+
+ if (!d.dptr) fatal("key not in db");
+ if (d.dsize != gd.dsize) fatal("data sizes differ");
+ if (memcmp(d.dptr, gd.dptr, gd.dsize)) {
+ fatal("data differs");
+ }
+
+ gnextkey = gdbm_nextkey(gdbm, gkey);
+ free(gkey.dptr);
+ free(gd.dptr);
+ free(d.dptr);
+ gkey = gnextkey;
+ }
+}
+
+static char *randbuf(int len)
+{
+ char *buf;
+ int i;
+ buf = (char *)malloc(len+1);
+
+ for (i=0;i<len;i++) {
+ buf[i] = 'a' + (rand() % 26);
+ }
+ buf[i] = 0;
+ return buf;
+}
+
+static void addrec_db(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ TDB_DATA key, data;
+
+ klen = 1 + (rand() % 4);
+ dlen = 1 + (rand() % 100);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = k;
+ key.dsize = klen+1;
+
+ data.dptr = d;
+ data.dsize = dlen+1;
+
+ if (rand() % DELETE_PROB == 0) {
+ tdb_delete(db, key);
+ } else if (rand() % STORE_PROB == 0) {
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ } else {
+ data = tdb_fetch(db, key);
+ if (data.dptr) free(data.dptr);
+ }
+
+ free(k);
+ free(d);
+}
+
+static void addrec_gdbm(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ datum key, data;
+
+ klen = 1 + (rand() % 4);
+ dlen = 1 + (rand() % 100);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = k;
+ key.dsize = klen+1;
+
+ data.dptr = d;
+ data.dsize = dlen+1;
+
+ if (rand() % DELETE_PROB == 0) {
+ gdbm_delete(gdbm, key);
+ } else if (rand() % STORE_PROB == 0) {
+ if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) {
+ fatal("gdbm_store failed");
+ }
+ } else {
+ data = gdbm_fetch(gdbm, key);
+ if (data.dptr) free(data.dptr);
+ }
+
+ free(k);
+ free(d);
+}
+
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+#if 0
+ printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
+#endif
+ tdb_delete(tdb, key);
+ return 0;
+}
+
+static void merge_test(void)
+{
+ int i;
+ char keys[5][2];
+ char tdata[] = "test";
+ TDB_DATA key, data;
+
+ for (i = 0; i < 5; i++) {
+ snprintf(keys[i],2, "%d", i);
+ key.dptr = keys[i];
+ key.dsize = 2;
+
+ data.dptr = tdata;
+ data.dsize = 4;
+
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ }
+
+ key.dptr = keys[0];
+ tdb_delete(db, key);
+ key.dptr = keys[4];
+ tdb_delete(db, key);
+ key.dptr = keys[2];
+ tdb_delete(db, key);
+ key.dptr = keys[1];
+ tdb_delete(db, key);
+ key.dptr = keys[3];
+ tdb_delete(db, key);
+}
+
+static char *test_path(const char *filename)
+{
+ const char *prefix = getenv("TEST_DATA_PREFIX");
+
+ if (prefix) {
+ char *path = NULL;
+ int ret;
+
+ ret = asprintf(&path, "%s/%s", prefix, filename);
+ if (ret == -1) {
+ return NULL;
+ }
+ return path;
+ }
+
+ return strdup(filename);
+}
+
+ int main(int argc, const char *argv[])
+{
+ int i, seed=0;
+ int loops = 10000;
+ int num_entries;
+ char test_gdbm[1] = "test.gdbm";
+ char *test_tdb;
+
+ test_gdbm[0] = test_path("test.gdbm");
+ test_tdb = test_path("test.tdb");
+
+ unlink(test_gdbm[0]);
+
+ db = tdb_open(test_tdb, 0, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
+ gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST,
+ 0600, NULL);
+
+ if (!db || !gdbm) {
+ fatal("db open failed");
+ }
+
+#if 1
+ srand(seed);
+ _start_timer();
+ for (i=0;i<loops;i++) addrec_gdbm();
+ printf("gdbm got %.2f ops/sec\n", i/_end_timer());
+#endif
+
+ merge_test();
+
+ srand(seed);
+ _start_timer();
+ for (i=0;i<loops;i++) addrec_db();
+ printf("tdb got %.2f ops/sec\n", i/_end_timer());
+
+ if (tdb_validate_freelist(db, &num_entries) == -1) {
+ printf("tdb freelist is corrupt\n");
+ } else {
+ printf("tdb freelist is good (%d entries)\n", num_entries);
+ }
+
+ compare_db();
+
+ printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+ printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
+
+ tdb_close(db);
+ gdbm_close(gdbm);
+
+ free(test_gdbm[0]);
+ free(test_tdb);
+
+ return 0;
+}
diff --git a/lib/tdb/tools/tdbtool.c b/lib/tdb/tools/tdbtool.c
new file mode 100644
index 0000000..fca28a1
--- /dev/null
+++ b/lib/tdb/tools/tdbtool.c
@@ -0,0 +1,924 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba database functions
+ Copyright (C) Andrew Tridgell 1999-2000
+ Copyright (C) Paul `Rusty' Russell 2000
+ Copyright (C) Jeremy Allison 2000
+ Copyright (C) Andrew Esh 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "tdb.h"
+
+static int do_command(void);
+const char *cmdname;
+char *arg1, *arg2;
+size_t arg1len, arg2len;
+int bIterate = 0;
+char *line;
+TDB_DATA iterate_kbuf;
+char cmdline[1024];
+static int disable_mmap;
+static int _disable_lock;
+
+enum commands {
+ CMD_CREATE_TDB,
+ CMD_OPEN_TDB,
+ CMD_TRANSACTION_START,
+ CMD_TRANSACTION_COMMIT,
+ CMD_TRANSACTION_CANCEL,
+ CMD_ERASE,
+ CMD_DUMP,
+ CMD_INSERT,
+ CMD_MOVE,
+ CMD_STOREHEX,
+ CMD_STORE,
+ CMD_SHOW,
+ CMD_KEYS,
+ CMD_HEXKEYS,
+ CMD_DELETE,
+ CMD_LIST_HASH_FREE,
+ CMD_LIST_FREE,
+ CMD_FREELIST_SIZE,
+ CMD_INFO,
+ CMD_MMAP,
+ CMD_SPEED,
+ CMD_FIRST,
+ CMD_NEXT,
+ CMD_SYSTEM,
+ CMD_CHECK,
+ CMD_REPACK,
+ CMD_QUIT,
+ CMD_HELP
+};
+
+typedef struct {
+ const char *name;
+ enum commands cmd;
+} COMMAND_TABLE;
+
+COMMAND_TABLE cmd_table[] = {
+ {"create", CMD_CREATE_TDB},
+ {"open", CMD_OPEN_TDB},
+ {"transaction_start", CMD_TRANSACTION_START},
+ {"transaction_commit", CMD_TRANSACTION_COMMIT},
+ {"transaction_cancel", CMD_TRANSACTION_CANCEL},
+ {"erase", CMD_ERASE},
+ {"dump", CMD_DUMP},
+ {"insert", CMD_INSERT},
+ {"move", CMD_MOVE},
+ {"storehex", CMD_STOREHEX},
+ {"store", CMD_STORE},
+ {"show", CMD_SHOW},
+ {"keys", CMD_KEYS},
+ {"hexkeys", CMD_HEXKEYS},
+ {"delete", CMD_DELETE},
+ {"list", CMD_LIST_HASH_FREE},
+ {"free", CMD_LIST_FREE},
+ {"freelist_size", CMD_FREELIST_SIZE},
+ {"info", CMD_INFO},
+ {"speed", CMD_SPEED},
+ {"mmap", CMD_MMAP},
+ {"first", CMD_FIRST},
+ {"1", CMD_FIRST},
+ {"next", CMD_NEXT},
+ {"n", CMD_NEXT},
+ {"check", CMD_CHECK},
+ {"quit", CMD_QUIT},
+ {"q", CMD_QUIT},
+ {"!", CMD_SYSTEM},
+ {"repack", CMD_REPACK},
+ {NULL, CMD_HELP}
+};
+
+struct timeval tp1,tp2;
+
+static void _start_timer(void)
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double _end_timer(void)
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log_open(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log_open(struct tdb_context *tdb, enum tdb_debug_level level,
+ const char *format, ...)
+{
+ const char *mutex_msg =
+ "Can use mutexes only with MUTEX_LOCKING or NOLOCK\n";
+ char *p;
+ va_list ap;
+
+ p = strstr(format, mutex_msg);
+ if (p != NULL) {
+ /*
+ * Yes, this is a hack, but we don't want to see this
+ * message on first open, but we want to see
+ * everything else.
+ */
+ return;
+ }
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+/* a tdb tool for manipulating a tdb database */
+
+static TDB_CONTEXT *tdb;
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+
+static void print_asc(const char *buf,int len)
+{
+ int i;
+
+ /* We're probably printing ASCII strings so don't try to display
+ the trailing NULL character. */
+
+ if (buf[len - 1] == 0)
+ len--;
+
+ for (i=0;i<len;i++)
+ printf("%c",isprint(buf[i])?buf[i]:'.');
+}
+
+static void print_data(const char *buf,int len)
+{
+ int i=0;
+ if (len<=0) return;
+ printf("[%03X] ",i);
+ for (i=0;i<len;) {
+ printf("%02X ",(int)((unsigned char)buf[i]));
+ i++;
+ if (i%8 == 0) printf(" ");
+ if (i%16 == 0) {
+ print_asc(&buf[i-16],8); printf(" ");
+ print_asc(&buf[i-8],8); printf("\n");
+ if (i<len) printf("[%03X] ",i);
+ }
+ }
+ if (i%16) {
+ int n;
+
+ n = 16 - (i%16);
+ printf(" ");
+ if (n>8) printf(" ");
+ while (n--) printf(" ");
+
+ n = i%16;
+ if (n > 8) n = 8;
+ print_asc(&buf[i-(i%16)],n); printf(" ");
+ n = (i%16) - n;
+ if (n>0) print_asc(&buf[i-n],n);
+ printf("\n");
+ }
+}
+
+static void help(void)
+{
+ printf("\n"
+"tdbtool: \n"
+" create dbname : create a database\n"
+" open dbname : open an existing database\n"
+" transaction_start : start a transaction\n"
+" transaction_commit : commit a transaction\n"
+" transaction_cancel : cancel a transaction\n"
+" erase : erase the database\n"
+" dump : dump the database as strings\n"
+" keys : dump the database keys as strings\n"
+" hexkeys : dump the database keys as hex values\n"
+" info : print summary info about the database\n"
+" insert key data : insert a record\n"
+" move key file : move a record to a destination tdb\n"
+" storehex key data : store a record (replace), key/value in hex format\n"
+" store key data : store a record (replace)\n"
+" show key : show a record by key\n"
+" delete key : delete a record by key\n"
+" list : print the database hash table and freelist\n"
+" free : print the database freelist\n"
+" freelist_size : print the number of records in the freelist\n"
+" check : check the integrity of an opened database\n"
+" repack : repack the database\n"
+" speed : perform speed tests on the database\n"
+" ! command : execute system command\n"
+" 1 | first : print the first record\n"
+" n | next : print the next record\n"
+" q | quit : terminate\n"
+" \\n : repeat 'next' command\n"
+"\n");
+}
+
+static void terror(const char *why)
+{
+ printf("%s\n", why);
+}
+
+static void create_tdb(const char *tdbname)
+{
+ struct tdb_logging_context log_ctx = { NULL, NULL};
+ log_ctx.log_fn = tdb_log;
+
+ if (tdb) tdb_close(tdb);
+ tdb = tdb_open_ex(tdbname, 0,
+ TDB_CLEAR_IF_FIRST |
+ (disable_mmap?TDB_NOMMAP:0) |
+ (_disable_lock?TDB_NOLOCK:0),
+ O_RDWR | O_CREAT | O_TRUNC, 0600, &log_ctx, NULL);
+ if (!tdb) {
+ printf("Could not create %s: %s\n", tdbname, strerror(errno));
+ }
+}
+
+static void open_tdb(const char *tdbname)
+{
+ struct tdb_logging_context log_ctx = { NULL, NULL };
+ log_ctx.log_fn = tdb_log_open;
+
+ if (tdb) tdb_close(tdb);
+ tdb = tdb_open_ex(tdbname, 0,
+ (disable_mmap?TDB_NOMMAP:0) |
+ (_disable_lock?TDB_NOLOCK:0),
+ O_RDWR, 0600,
+ &log_ctx, NULL);
+
+ log_ctx.log_fn = tdb_log;
+ if (tdb != NULL) {
+ tdb_set_logging_function(tdb, &log_ctx);
+ }
+
+ if ((tdb == NULL) && (errno == EINVAL)) {
+ /*
+ * Retry NOLOCK and readonly. There we want to see all
+ * error messages.
+ */
+ tdb = tdb_open_ex(tdbname, 0,
+ (disable_mmap?TDB_NOMMAP:0) |TDB_NOLOCK,
+ O_RDONLY, 0600,
+ &log_ctx, NULL);
+ }
+
+ if (!tdb) {
+ printf("Could not open %s: %s\n", tdbname, strerror(errno));
+ }
+}
+
+static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+ TDB_DATA key, dbuf;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+ dbuf.dptr = (unsigned char *)data;
+ dbuf.dsize = datalen;
+
+ if (tdb_store(tdb, key, dbuf, TDB_INSERT) != 0) {
+ terror("insert failed");
+ }
+}
+
+static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+ TDB_DATA key, dbuf;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ if ((data == NULL) || (datalen == 0)) {
+ terror("need data");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+ dbuf.dptr = (unsigned char *)data;
+ dbuf.dsize = datalen;
+
+ printf("Storing key:\n");
+ print_rec(tdb, key, dbuf, NULL);
+
+ if (tdb_store(tdb, key, dbuf, TDB_REPLACE) != 0) {
+ terror("store failed");
+ }
+}
+
+static bool parse_hex(const char *src, size_t srclen, uint8_t *dst)
+{
+ size_t i=0;
+
+ if ((srclen % 2) != 0) {
+ return false;
+ }
+
+ while (i<srclen) {
+ bool ok = hex_byte(src, dst);
+ if (!ok) {
+ return false;
+ }
+ src += 2;
+ dst += 1;
+ }
+
+ return true;
+}
+
+static void store_hex_tdb(char *keystr, size_t keylen,
+ char *datastr, size_t datalen)
+{
+ if ((keystr == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+ if ((datastr == NULL) || (datalen == 0)) {
+ terror("need data");
+ return;
+ }
+
+ {
+ uint8_t keybuf[keylen/2];
+ TDB_DATA key = { .dptr = keybuf, .dsize = sizeof(keybuf) };
+ uint8_t databuf[datalen/2];
+ TDB_DATA data = { .dptr = databuf, .dsize = sizeof(databuf) };
+ bool ok;
+
+ ok = parse_hex(keystr, keylen, keybuf);
+ if (!ok) {
+ terror("need hex key");
+ return;
+ }
+ ok = parse_hex(datastr, datalen, databuf);
+ if (!ok) {
+ terror("need hex data");
+ return;
+ }
+
+ printf("storing key/data:\n");
+ print_data((char *)key.dptr, key.dsize);
+ print_data((char *)data.dptr, data.dsize);
+
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) {
+ terror("store failed");
+ }
+ }
+}
+
+static void show_tdb(char *keyname, size_t keylen)
+{
+ TDB_DATA key, dbuf;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr) {
+ terror("fetch failed");
+ return;
+ }
+
+ print_rec(tdb, key, dbuf, NULL);
+
+ free( dbuf.dptr );
+
+ return;
+}
+
+static void delete_tdb(char *keyname, size_t keylen)
+{
+ TDB_DATA key;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+
+ if (tdb_delete(tdb, key) != 0) {
+ terror("delete failed");
+ }
+}
+
+static void move_rec(char *keyname, size_t keylen, char* tdbname)
+{
+ TDB_DATA key, dbuf;
+ TDB_CONTEXT *dst_tdb;
+
+ if ((keyname == NULL) || (keylen == 0)) {
+ terror("need key");
+ return;
+ }
+
+ if ( !tdbname ) {
+ terror("need destination tdb name");
+ return;
+ }
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+
+ dbuf = tdb_fetch(tdb, key);
+ if (!dbuf.dptr) {
+ terror("fetch failed");
+ return;
+ }
+
+ print_rec(tdb, key, dbuf, NULL);
+
+ dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600);
+ if ( !dst_tdb ) {
+ terror("unable to open destination tdb");
+ return;
+ }
+
+ if (tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) != 0) {
+ terror("failed to move record");
+ }
+ else
+ printf("record moved\n");
+
+ tdb_close( dst_tdb );
+
+ return;
+}
+
+static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("\nkey %d bytes\n", (int)key.dsize);
+ print_asc((const char *)key.dptr, key.dsize);
+ printf("\ndata %d bytes\n", (int)dbuf.dsize);
+ print_data((const char *)dbuf.dptr, dbuf.dsize);
+ return 0;
+}
+
+static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("key %d bytes: ", (int)key.dsize);
+ print_asc((const char *)key.dptr, key.dsize);
+ printf("\n");
+ return 0;
+}
+
+static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ printf("key %d bytes\n", (int)key.dsize);
+ print_data((const char *)key.dptr, key.dsize);
+ printf("\n");
+ return 0;
+}
+
+static int total_bytes;
+
+static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ total_bytes += dbuf.dsize;
+ return 0;
+}
+
+static void info_tdb(void)
+{
+ char *summary = tdb_summary(tdb);
+
+ if (!summary) {
+ printf("Error = %s\n", tdb_errorstr(tdb));
+ } else {
+ printf("%s", summary);
+ free(summary);
+ }
+}
+
+static void speed_tdb(const char *tlimit)
+{
+ const char *str = "store test", *str2 = "transaction test";
+ unsigned timelimit = tlimit?atoi(tlimit):0;
+ double t;
+ int ops;
+ if (timelimit == 0) timelimit = 5;
+
+ ops = 0;
+ printf("Testing store speed for %u seconds\n", timelimit);
+ _start_timer();
+ do {
+ long int r = random();
+ TDB_DATA key, dbuf;
+ key.dptr = discard_const_p(uint8_t, str);
+ key.dsize = strlen((char *)key.dptr);
+ dbuf.dptr = (uint8_t *) &r;
+ dbuf.dsize = sizeof(r);
+ tdb_store(tdb, key, dbuf, TDB_REPLACE);
+ t = _end_timer();
+ ops++;
+ } while (t < timelimit);
+ printf("%10.3f ops/sec\n", ops/t);
+
+ ops = 0;
+ printf("Testing fetch speed for %u seconds\n", timelimit);
+ _start_timer();
+ do {
+ TDB_DATA key;
+ key.dptr = discard_const_p(uint8_t, str);
+ key.dsize = strlen((char *)key.dptr);
+ tdb_fetch(tdb, key);
+ t = _end_timer();
+ ops++;
+ } while (t < timelimit);
+ printf("%10.3f ops/sec\n", ops/t);
+
+ ops = 0;
+ printf("Testing transaction speed for %u seconds\n", timelimit);
+ _start_timer();
+ do {
+ long int r = random();
+ TDB_DATA key, dbuf;
+ key.dptr = discard_const_p(uint8_t, str2);
+ key.dsize = strlen((char *)key.dptr);
+ dbuf.dptr = (uint8_t *) &r;
+ dbuf.dsize = sizeof(r);
+ tdb_transaction_start(tdb);
+ tdb_store(tdb, key, dbuf, TDB_REPLACE);
+ tdb_transaction_commit(tdb);
+ t = _end_timer();
+ ops++;
+ } while (t < timelimit);
+ printf("%10.3f ops/sec\n", ops/t);
+
+ ops = 0;
+ printf("Testing traverse speed for %u seconds\n", timelimit);
+ _start_timer();
+ do {
+ tdb_traverse(tdb, traverse_fn, NULL);
+ t = _end_timer();
+ ops++;
+ } while (t < timelimit);
+ printf("%10.3f ops/sec\n", ops/t);
+}
+
+static void toggle_mmap(void)
+{
+ disable_mmap = !disable_mmap;
+ if (disable_mmap) {
+ printf("mmap is disabled\n");
+ } else {
+ printf("mmap is enabled\n");
+ }
+}
+
+static char *tdb_getline(const char *prompt)
+{
+ static char thisline[1024];
+ char *p;
+ fputs(prompt, stdout);
+ thisline[0] = 0;
+ p = fgets(thisline, sizeof(thisline)-1, stdin);
+ if (p) p = strchr(p, '\n');
+ if (p) *p = 0;
+ return p?thisline:NULL;
+}
+
+static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+ TDB_DATA dbuf;
+ *pkey = tdb_firstkey(the_tdb);
+
+ dbuf = tdb_fetch(the_tdb, *pkey);
+ if (!dbuf.dptr) terror("fetch failed");
+ else {
+ print_rec(the_tdb, *pkey, dbuf, NULL);
+ }
+}
+
+static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
+{
+ TDB_DATA dbuf;
+ *pkey = tdb_nextkey(the_tdb, *pkey);
+
+ dbuf = tdb_fetch(the_tdb, *pkey);
+ if (!dbuf.dptr)
+ terror("fetch failed");
+ else
+ print_rec(the_tdb, *pkey, dbuf, NULL);
+}
+
+static int count(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ (*(unsigned int *)private_data)++;
+ return 0;
+}
+
+static void check_db(TDB_CONTEXT *the_tdb)
+{
+ int tdbcount = 0;
+ if (!the_tdb)
+ printf("Error: No database opened!\n");
+ else if (tdb_check(the_tdb, count, &tdbcount) == -1)
+ printf("Integrity check for the opened database failed.\n");
+ else
+ printf("Database integrity is OK and has %d records.\n",
+ tdbcount);
+}
+
+static int do_command(void)
+{
+ COMMAND_TABLE *ctp = cmd_table;
+ enum commands mycmd = CMD_HELP;
+ int cmd_len;
+
+ if (cmdname != NULL) {
+ if (strlen(cmdname) == 0) {
+ mycmd = CMD_NEXT;
+ } else {
+ while (ctp->name) {
+ cmd_len = strlen(ctp->name);
+ if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
+ mycmd = ctp->cmd;
+ break;
+ }
+ ctp++;
+ }
+ }
+ }
+
+ switch (mycmd) {
+ case CMD_CREATE_TDB:
+ bIterate = 0;
+ create_tdb(arg1);
+ return 0;
+ case CMD_OPEN_TDB:
+ bIterate = 0;
+ open_tdb(arg1);
+ return 0;
+ case CMD_SYSTEM:
+ /* Shell command */
+ if (system(arg1) == -1) {
+ terror("system() call failed\n");
+ }
+ return 0;
+ case CMD_QUIT:
+ return 1;
+ default:
+ /* all the rest require a open database */
+ if (!tdb) {
+ bIterate = 0;
+ terror("database not open");
+ help();
+ return 0;
+ }
+ switch (mycmd) {
+ case CMD_TRANSACTION_START:
+ bIterate = 0;
+ tdb_transaction_start(tdb);
+ return 0;
+ case CMD_TRANSACTION_COMMIT:
+ bIterate = 0;
+ tdb_transaction_commit(tdb);
+ return 0;
+ case CMD_REPACK:
+ bIterate = 0;
+ tdb_repack(tdb);
+ return 0;
+ case CMD_TRANSACTION_CANCEL:
+ bIterate = 0;
+ tdb_transaction_cancel(tdb);
+ return 0;
+ case CMD_ERASE:
+ bIterate = 0;
+ tdb_wipe_all(tdb);
+ return 0;
+ case CMD_DUMP:
+ bIterate = 0;
+ tdb_traverse(tdb, print_rec, NULL);
+ return 0;
+ case CMD_INSERT:
+ bIterate = 0;
+ insert_tdb(arg1, arg1len,arg2,arg2len);
+ return 0;
+ case CMD_MOVE:
+ bIterate = 0;
+ move_rec(arg1,arg1len,arg2);
+ return 0;
+ case CMD_STORE:
+ bIterate = 0;
+ store_tdb(arg1,arg1len,arg2,arg2len);
+ return 0;
+ case CMD_STOREHEX:
+ bIterate = 0;
+ store_hex_tdb(arg1,arg1len,arg2,arg2len);
+ return 0;
+ case CMD_SHOW:
+ bIterate = 0;
+ show_tdb(arg1, arg1len);
+ return 0;
+ case CMD_KEYS:
+ tdb_traverse(tdb, print_key, NULL);
+ return 0;
+ case CMD_HEXKEYS:
+ tdb_traverse(tdb, print_hexkey, NULL);
+ return 0;
+ case CMD_DELETE:
+ bIterate = 0;
+ delete_tdb(arg1,arg1len);
+ return 0;
+ case CMD_LIST_HASH_FREE:
+ tdb_dump_all(tdb);
+ return 0;
+ case CMD_LIST_FREE:
+ tdb_printfreelist(tdb);
+ return 0;
+ case CMD_FREELIST_SIZE: {
+ int size;
+
+ size = tdb_freelist_size(tdb);
+ if (size < 0) {
+ printf("Error getting freelist size.\n");
+ } else {
+ printf("freelist size: %d\n", size);
+ }
+
+ return 0;
+ }
+ case CMD_INFO:
+ info_tdb();
+ return 0;
+ case CMD_SPEED:
+ speed_tdb(arg1);
+ return 0;
+ case CMD_MMAP:
+ toggle_mmap();
+ return 0;
+ case CMD_FIRST:
+ bIterate = 1;
+ first_record(tdb, &iterate_kbuf);
+ return 0;
+ case CMD_NEXT:
+ if (bIterate)
+ next_record(tdb, &iterate_kbuf);
+ return 0;
+ case CMD_CHECK:
+ check_db(tdb);
+ return 0;
+ case CMD_HELP:
+ help();
+ return 0;
+ case CMD_CREATE_TDB:
+ case CMD_OPEN_TDB:
+ case CMD_SYSTEM:
+ case CMD_QUIT:
+ /*
+ * unhandled commands. cases included here to avoid compiler
+ * warnings.
+ */
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static char *tdb_convert_string(char *instring, size_t *sizep)
+{
+ size_t length = 0;
+ char *outp, *inp;
+ char temp[3];
+
+ outp = inp = instring;
+
+ while (*inp) {
+ if (*inp == '\\') {
+ inp++;
+ if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+ temp[0] = *inp++;
+ temp[1] = '\0';
+ if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+ temp[1] = *inp++;
+ temp[2] = '\0';
+ }
+ *outp++ = (char)strtol((const char *)temp,NULL,16);
+ } else {
+ *outp++ = *inp++;
+ }
+ } else {
+ *outp++ = *inp++;
+ }
+ length++;
+ }
+ *sizep = length;
+ return instring;
+}
+
+int main(int argc, char *argv[])
+{
+ cmdname = "";
+ arg1 = NULL;
+ arg1len = 0;
+ arg2 = NULL;
+ arg2len = 0;
+
+ if (argv[1] && (strcmp(argv[1], "-l") == 0)) {
+ _disable_lock = 1;
+ argv[1] = argv[0];
+ argv += 1;
+ argc -= 1;
+ }
+
+ if (argv[1]) {
+ cmdname = "open";
+ arg1 = argv[1];
+ do_command();
+ cmdname = "";
+ arg1 = NULL;
+ }
+
+ switch (argc) {
+ case 1:
+ case 2:
+ /* Interactive mode */
+ while ((cmdname = tdb_getline("tdb> "))) {
+ arg2 = arg1 = NULL;
+ if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
+ arg1++;
+ arg2 = arg1;
+ while (*arg2) {
+ if (*arg2 == ' ') {
+ *arg2++ = '\0';
+ break;
+ }
+ if ((*arg2++ == '\\') && (*arg2 == ' ')) {
+ arg2++;
+ }
+ }
+ }
+ if (arg1) arg1 = tdb_convert_string(arg1,&arg1len);
+ if (arg2) arg2 = tdb_convert_string(arg2,&arg2len);
+ if (do_command()) break;
+ }
+ break;
+ case 5:
+ arg2 = tdb_convert_string(argv[4],&arg2len);
+ FALL_THROUGH;
+ case 4:
+ arg1 = tdb_convert_string(argv[3],&arg1len);
+ FALL_THROUGH;
+ case 3:
+ cmdname = argv[2];
+ FALL_THROUGH;
+ default:
+ do_command();
+ break;
+ }
+
+ if (tdb) tdb_close(tdb);
+
+ return 0;
+}
diff --git a/lib/tdb/tools/tdbtortseq.c b/lib/tdb/tools/tdbtortseq.c
new file mode 100644
index 0000000..9423b46
--- /dev/null
+++ b/lib/tdb/tools/tdbtortseq.c
@@ -0,0 +1,123 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include <tdb.h>
+#include <stdio.h>
+#include <errno.h>
+#include "system/wait.h"
+
+#define NPROCS 500
+#define NUMOPS 1000000
+
+int main(void)
+{
+ pid_t pids[NPROCS];
+ struct tdb_context *tdb = NULL;
+ int i;
+ uint32_t seqnum_before, seqnum_after;
+
+ tdb = tdb_open("seqnum_test.tdb",
+ 10000,
+ TDB_CLEAR_IF_FIRST|
+ TDB_SEQNUM|
+ TDB_INCOMPATIBLE_HASH|
+ TDB_MUTEX_LOCKING,
+ O_CREAT|O_RDWR,
+ 0644);
+ if (tdb == NULL) {
+ perror("tdb_open failed");
+ return 1;
+ }
+ seqnum_before = tdb_get_seqnum(tdb);
+
+ for (i=0; i<NPROCS; i++) {
+ pids[i] = fork();
+ if (pids[i] == -1) {
+ perror("fork failed");
+ return 1;
+ }
+ if (pids[i] == 0) {
+ pid_t mypid = getpid();
+ int ret;
+ int j;
+
+ ret = tdb_reopen(tdb);
+ if (ret != 0) {
+ perror("tdb_reopen failed");
+ return 1;
+ }
+
+ for (j=0; j<NUMOPS; j++) {
+ TDB_DATA key = {
+ .dptr = (uint8_t *)&mypid,
+ .dsize = sizeof(mypid),
+ };
+ TDB_DATA value = {
+ .dptr = (uint8_t *)&j,
+ .dsize = sizeof(j),
+ };
+ ret = tdb_store(tdb, key, value, 0);
+ if (ret == -1) {
+ perror("tdb_store failed");
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+ }
+
+ for (i=0; i<NPROCS; i++) {
+ int wstatus;
+ pid_t ret = waitpid(pids[i], &wstatus, 0);
+
+ if (ret == -1) {
+ perror("waitpid failed");
+ return 1;
+ }
+
+ if (!WIFEXITED(wstatus)) {
+ fprintf(stderr,
+ "pid %d did not exit properly\n",
+ (int)pids[i]);
+ return 1;
+ }
+
+ if (WEXITSTATUS(wstatus) != 0) {
+ fprintf(stderr,
+ "pid %d returned %d\n",
+ (int)pids[i],
+ WEXITSTATUS(wstatus));
+ return 1;
+ }
+ }
+
+ seqnum_after = tdb_get_seqnum(tdb);
+
+ printf("seqnum_before=%"PRIu32", seqnum_after=%"PRIu32"\n",
+ seqnum_before,
+ seqnum_after);
+
+ if ((seqnum_after - seqnum_before) != (NPROCS*NUMOPS)) {
+ perror("incrementing seqnum failed");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/lib/tdb/tools/tdbtorture.c b/lib/tdb/tools/tdbtorture.c
new file mode 100644
index 0000000..1063f14
--- /dev/null
+++ b/lib/tdb/tools/tdbtorture.c
@@ -0,0 +1,500 @@
+/* this tests tdb by doing lots of ops from several simultaneous
+ writers - that stresses the locking code.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+#include "tdb.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+
+#define REOPEN_PROB 30
+#define DELETE_PROB 8
+#define STORE_PROB 4
+#define APPEND_PROB 6
+#define TRANSACTION_PROB 10
+#define TRANSACTION_PREPARE_PROB 2
+#define LOCKSTORE_PROB 5
+#define TRAVERSE_PROB 20
+#define TRAVERSE_READ_PROB 20
+#define CULL_PROB 100
+#define KEYLEN 3
+#define DATALEN 100
+
+static struct tdb_context *db;
+static int in_transaction;
+static int error_count;
+static int always_transaction = 0;
+static int hash_size = 2;
+static unsigned loopnum;
+static int count_pipe;
+static bool mutex = false;
+static struct tdb_logging_context log_ctx;
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+ va_list ap;
+
+ /* trace level messages do not indicate an error */
+ if (level != TDB_DEBUG_TRACE) {
+ error_count++;
+ }
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+#if 0
+ if (level != TDB_DEBUG_TRACE) {
+ char *ptr;
+ signal(SIGUSR1, SIG_IGN);
+ asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
+ system(ptr);
+ free(ptr);
+ }
+#endif
+}
+
+static void fatal(const char *why)
+{
+ perror(why);
+ error_count++;
+}
+
+static char *randbuf(int len)
+{
+ char *buf;
+ int i;
+ buf = (char *)malloc(len+1);
+
+ for (i=0;i<len;i++) {
+ buf[i] = 'a' + (rand() % 26);
+ }
+ buf[i] = 0;
+ return buf;
+}
+
+static int cull_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+#if CULL_PROB
+ if (random() % CULL_PROB == 0) {
+ tdb_delete(tdb, key);
+ }
+#endif
+ return 0;
+}
+
+static bool do_transaction(void)
+{
+#if TRANSACTION_PROB
+ if (mutex) {
+ return false;
+ }
+ if (random() % TRANSACTION_PROB == 0) {
+ return true;
+ }
+#endif
+ return false;
+}
+
+static void addrec_db(void)
+{
+ int klen, dlen;
+ char *k, *d;
+ TDB_DATA key, data;
+
+ klen = 1 + (rand() % KEYLEN);
+ dlen = 1 + (rand() % DATALEN);
+
+ k = randbuf(klen);
+ d = randbuf(dlen);
+
+ key.dptr = (unsigned char *)k;
+ key.dsize = klen+1;
+
+ data.dptr = (unsigned char *)d;
+ data.dsize = dlen+1;
+
+#if REOPEN_PROB
+ if (in_transaction == 0 && random() % REOPEN_PROB == 0) {
+ tdb_reopen_all(0);
+ goto next;
+ }
+#endif
+
+ if (in_transaction == 0 &&
+ (always_transaction || do_transaction())) {
+ if (tdb_transaction_start(db) != 0) {
+ fatal("tdb_transaction_start failed");
+ }
+ in_transaction++;
+ goto next;
+ }
+ if (in_transaction && do_transaction()) {
+ if (random() % TRANSACTION_PREPARE_PROB == 0) {
+ if (tdb_transaction_prepare_commit(db) != 0) {
+ fatal("tdb_transaction_prepare_commit failed");
+ }
+ }
+ if (tdb_transaction_commit(db) != 0) {
+ fatal("tdb_transaction_commit failed");
+ }
+ in_transaction--;
+ goto next;
+ }
+ if (in_transaction && do_transaction()) {
+ if (tdb_transaction_cancel(db) != 0) {
+ fatal("tdb_transaction_cancel failed");
+ }
+ in_transaction--;
+ goto next;
+ }
+
+#if DELETE_PROB
+ if (random() % DELETE_PROB == 0) {
+ tdb_delete(db, key);
+ goto next;
+ }
+#endif
+
+#if STORE_PROB
+ if (random() % STORE_PROB == 0) {
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ goto next;
+ }
+#endif
+
+#if APPEND_PROB
+ if (random() % APPEND_PROB == 0) {
+ if (tdb_append(db, key, data) != 0) {
+ fatal("tdb_append failed");
+ }
+ goto next;
+ }
+#endif
+
+#if LOCKSTORE_PROB
+ if (random() % LOCKSTORE_PROB == 0) {
+ tdb_chainlock(db, key);
+ data = tdb_fetch(db, key);
+ if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+ fatal("tdb_store failed");
+ }
+ if (data.dptr) free(data.dptr);
+ tdb_chainunlock(db, key);
+ goto next;
+ }
+#endif
+
+#if TRAVERSE_PROB
+ if (random() % TRAVERSE_PROB == 0) {
+ tdb_traverse(db, cull_traverse, NULL);
+ goto next;
+ }
+#endif
+
+#if TRAVERSE_READ_PROB
+ if (random() % TRAVERSE_READ_PROB == 0) {
+ tdb_traverse_read(db, NULL, NULL);
+ goto next;
+ }
+#endif
+
+ data = tdb_fetch(db, key);
+ if (data.dptr) free(data.dptr);
+
+next:
+ free(k);
+ free(d);
+}
+
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+ void *state)
+{
+ tdb_delete(tdb, key);
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Usage: tdbtorture [-t] [-k] [-m] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
+ exit(0);
+}
+
+static void send_count_and_suicide(int sig)
+{
+ ssize_t ret;
+
+ /* This ensures our successor can continue where we left off. */
+ do {
+ ret = write(count_pipe, &loopnum, sizeof(loopnum));
+ } while (ret == -1 && errno == EINTR);
+ /* This gives a unique signature. */
+ kill(getpid(), SIGUSR2);
+}
+
+static int run_child(const char *filename, int i, int seed, unsigned num_loops, unsigned start)
+{
+ int tdb_flags = TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH;
+
+ if (mutex) {
+ tdb_flags |= TDB_MUTEX_LOCKING;
+ }
+
+ db = tdb_open_ex(filename, hash_size, tdb_flags,
+ O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
+ if (!db) {
+ fatal("db open failed");
+ }
+
+ srand(seed + i);
+ srandom(seed + i);
+
+ /* Set global, then we're ready to handle being killed. */
+ loopnum = start;
+ signal(SIGUSR1, send_count_and_suicide);
+
+ for (;loopnum<num_loops && error_count == 0;loopnum++) {
+ addrec_db();
+ }
+
+ if (error_count == 0) {
+ tdb_traverse_read(db, NULL, NULL);
+ if (always_transaction) {
+ while (in_transaction) {
+ tdb_transaction_cancel(db);
+ in_transaction--;
+ }
+ if (tdb_transaction_start(db) != 0)
+ fatal("tdb_transaction_start failed");
+ }
+ tdb_traverse(db, traverse_fn, NULL);
+ tdb_traverse(db, traverse_fn, NULL);
+ if (always_transaction) {
+ if (tdb_transaction_commit(db) != 0)
+ fatal("tdb_transaction_commit failed");
+ }
+ }
+
+ tdb_close(db);
+
+ return (error_count < 100 ? error_count : 100);
+}
+
+static char *test_path(const char *filename)
+{
+ const char *prefix = getenv("TEST_DATA_PREFIX");
+
+ if (prefix) {
+ char *path = NULL;
+ int ret;
+
+ ret = asprintf(&path, "%s/%s", prefix, filename);
+ if (ret == -1) {
+ return NULL;
+ }
+ return path;
+ }
+
+ return strdup(filename);
+}
+
+int main(int argc, char * const *argv)
+{
+ int i, seed = -1;
+ int num_loops = 5000;
+ int num_procs = 3;
+ int c, pfds[2];
+ extern char *optarg;
+ pid_t *pids;
+ int kill_random = 0;
+ int *done;
+ char *test_tdb;
+
+ log_ctx.log_fn = tdb_log;
+
+ while ((c = getopt(argc, argv, "n:l:s:H:thkm")) != -1) {
+ switch (c) {
+ case 'n':
+ num_procs = strtol(optarg, NULL, 0);
+ break;
+ case 'l':
+ num_loops = strtol(optarg, NULL, 0);
+ break;
+ case 'H':
+ hash_size = strtol(optarg, NULL, 0);
+ break;
+ case 's':
+ seed = strtol(optarg, NULL, 0);
+ break;
+ case 't':
+ always_transaction = 1;
+ break;
+ case 'k':
+ kill_random = 1;
+ break;
+ case 'm':
+ mutex = tdb_runtime_check_for_robust_mutexes();
+ if (!mutex) {
+ printf("tdb_runtime_check_for_robust_mutexes() returned false\n");
+ exit(1);
+ }
+ break;
+ default:
+ usage();
+ }
+ }
+
+ test_tdb = test_path("torture.tdb");
+
+ unlink(test_tdb);
+
+ if (seed == -1) {
+ seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
+ }
+
+ printf("Testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
+ num_procs, num_loops, hash_size, seed,
+ (always_transaction ? " (all within transactions)" : ""));
+
+ if (num_procs == 1 && !kill_random) {
+ /* Don't fork for this case, makes debugging easier. */
+ error_count = run_child(test_tdb, 0, seed, num_loops, 0);
+ goto done;
+ }
+
+ pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
+ if (pids == NULL) {
+ perror("Unable to allocate memory for pids");
+ exit(1);
+ }
+ done = (int *)calloc(sizeof(int), num_procs);
+ if (done == NULL) {
+ perror("Unable to allocate memory for done");
+ exit(1);
+ }
+
+ if (pipe(pfds) != 0) {
+ perror("Creating pipe");
+ exit(1);
+ }
+ count_pipe = pfds[1];
+
+ for (i=0;i<num_procs;i++) {
+ if ((pids[i]=fork()) == 0) {
+ close(pfds[0]);
+ exit(run_child(test_tdb, i, seed, num_loops, 0));
+ }
+ }
+
+ while (num_procs) {
+ int status, j;
+ pid_t pid;
+
+ if (error_count != 0) {
+ /* try and stop the test on any failure */
+ for (j=0;j<num_procs;j++) {
+ if (pids[j] != 0) {
+ kill(pids[j], SIGTERM);
+ }
+ }
+ }
+
+ pid = waitpid(-1, &status, kill_random ? WNOHANG : 0);
+ if (pid == 0) {
+ struct timeval tv;
+
+ /* Sleep for 1/10 second. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ select(0, NULL, NULL, NULL, &tv);
+
+ /* Kill someone. */
+ kill(pids[random() % num_procs], SIGUSR1);
+ continue;
+ }
+
+ if (pid == -1) {
+ perror("failed to wait for child\n");
+ exit(1);
+ }
+
+ for (j=0;j<num_procs;j++) {
+ if (pids[j] == pid) break;
+ }
+ if (j == num_procs) {
+ printf("unknown child %d exited!?\n", (int)pid);
+ exit(1);
+ }
+ if (WIFSIGNALED(status)) {
+ if (WTERMSIG(status) == SIGUSR2
+ || WTERMSIG(status) == SIGUSR1) {
+ /* SIGUSR2 means they wrote to pipe. */
+ if (WTERMSIG(status) == SIGUSR2) {
+ ssize_t ret;
+
+ do {
+ ret = read(pfds[0], &done[j],
+ sizeof(done[j]));
+ } while (ret == -1 && errno == EINTR);
+ }
+ pids[j] = fork();
+ if (pids[j] == 0)
+ exit(run_child(test_tdb, j, seed,
+ num_loops, done[j]));
+ printf("Restarting child %i for %u-%u\n",
+ j, done[j], num_loops);
+ continue;
+ }
+ printf("child %d exited with signal %d\n",
+ (int)pid, WTERMSIG(status));
+ error_count++;
+ } else {
+ if (WEXITSTATUS(status) != 0) {
+ printf("child %d exited with status %d\n",
+ (int)pid, WEXITSTATUS(status));
+ error_count++;
+ }
+ }
+ ARRAY_DEL_ELEMENT(pids, j, num_procs);
+ num_procs--;
+ }
+
+ free(pids);
+
+done:
+ if (error_count == 0) {
+ int tdb_flags = TDB_DEFAULT;
+
+ if (mutex) {
+ tdb_flags |= TDB_NOLOCK;
+ }
+
+ db = tdb_open_ex(test_tdb, hash_size, tdb_flags,
+ O_RDWR, 0, &log_ctx, NULL);
+ if (!db) {
+ fatal("db open failed\n");
+ exit(1);
+ }
+ if (tdb_check(db, NULL, NULL) == -1) {
+ printf("db check failed\n");
+ exit(1);
+ }
+ tdb_close(db);
+ printf("OK\n");
+ }
+
+ free(test_tdb);
+ return error_count;
+}
diff --git a/lib/tdb/web/index.html b/lib/tdb/web/index.html
new file mode 100644
index 0000000..99e8a2f
--- /dev/null
+++ b/lib/tdb/web/index.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>ldb</TITLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033">
+
+<h1>tdb</h1>
+
+TDB is a Trivial Database. In concept, it is very much like GDBM, and BSD's DB
+except that it allows multiple simultaneous writers and uses locking
+internally to keep writers from trampling on each other. TDB is also extremely
+small.
+
+<h2>Download</h2>
+You can download the latest releases of tdb from the <a
+href="http://samba.org/ftp/tdb">tdb directory</a> on the samba public
+source archive.
+
+
+<h2>Discussion and bug reports</h2>
+
+tdb does not currently have its own mailing list or bug tracking
+system. For now, please use the <a
+href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba
+bugzilla</a> bug tracking system.
+
+<h2>Download</h2>
+
+You can download the latest code either via git or rsync.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the master branch and cd into the source/lib/tdb directory.<br>
+<br>
+To fetch via rsync use these commands:
+
+<pre>
+ rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/tdb .
+ rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/replace .
+</pre>
+
+and build in tdb. It will find the replace library in the directory
+above automatically.
+
+</BODY>
+</HTML>
diff --git a/lib/tdb/wscript b/lib/tdb/wscript
new file mode 100644
index 0000000..2c587fb
--- /dev/null
+++ b/lib/tdb/wscript
@@ -0,0 +1,264 @@
+#!/usr/bin/env python
+
+APPNAME = 'tdb'
+VERSION = '1.4.10'
+
+import sys, os
+
+# find the buildtools directory
+top = '.'
+while not os.path.exists(top+'/buildtools') and len(top.split('/')) < 5:
+ top = top + '/..'
+sys.path.insert(0, top + '/buildtools/wafsamba')
+
+out = 'bin'
+
+import wafsamba
+from wafsamba import samba_dist, samba_utils
+from waflib import Options, Logs, Context
+import shutil
+
+samba_dist.DIST_DIRS('lib/tdb:. lib/replace:lib/replace buildtools:buildtools third_party/waf:third_party/waf')
+
+tdb1_unit_tests = [
+ 'run-3G-file',
+ 'run-bad-tdb-header',
+ 'run',
+ 'run-check',
+ 'run-corrupt',
+ 'run-die-during-transaction',
+ 'run-endian',
+ 'run-incompatible',
+ 'run-nested-transactions',
+ 'run-nested-traverse',
+ 'run-no-lock-during-traverse',
+ 'run-oldhash',
+ 'run-open-during-transaction',
+ 'run-readonly-check',
+ 'run-rescue',
+ 'run-rescue-find_entry',
+ 'run-rdlock-upgrade',
+ 'run-rwlock-check',
+ 'run-summary',
+ 'run-transaction-expand',
+ 'run-traverse-in-transaction',
+ 'run-wronghash-fail',
+ 'run-zero-append',
+ 'run-fcntl-deadlock',
+ 'run-marklock-deadlock',
+ 'run-allrecord-traverse-deadlock',
+ 'run-mutex-openflags2',
+ 'run-mutex-trylock',
+ 'run-mutex-allrecord-bench',
+ 'run-mutex-allrecord-trylock',
+ 'run-mutex-allrecord-block',
+ 'run-mutex-transaction1',
+ 'run-mutex-die',
+ 'run-mutex1',
+ 'run-circular-chain',
+ 'run-circular-freelist',
+ 'run-traverse-chain',
+]
+
+def options(opt):
+ opt.BUILTIN_DEFAULT('replace')
+ opt.PRIVATE_EXTENSION_DEFAULT('tdb', noextension='tdb')
+ opt.RECURSE('lib/replace')
+ opt.add_option('--disable-tdb-mutex-locking',
+ help=("Disable the use of pthread robust mutexes"),
+ action="store_true", dest='disable_tdb_mutex_locking',
+ default=False)
+
+
+def configure(conf):
+ conf.env.disable_tdb_mutex_locking = getattr(Options.options,
+ 'disable_tdb_mutex_locking',
+ False)
+ if not conf.env.disable_tdb_mutex_locking:
+ conf.env.replace_add_global_pthread = True
+ conf.RECURSE('lib/replace')
+
+ conf.env.standalone_tdb = conf.IN_LAUNCH_DIR()
+ conf.env.building_tdb = True
+
+ if not conf.env.standalone_tdb:
+ if conf.CHECK_BUNDLED_SYSTEM_PKG('tdb', minversion=VERSION,
+ implied_deps='replace'):
+ conf.define('USING_SYSTEM_TDB', 1)
+ conf.env.building_tdb = False
+ if not conf.env.disable_python and \
+ conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION):
+ conf.define('USING_SYSTEM_PYTDB', 1)
+
+ if (conf.CONFIG_SET('HAVE_ROBUST_MUTEXES') and
+ conf.env.building_tdb and
+ not conf.env.disable_tdb_mutex_locking):
+ conf.define('USE_TDB_MUTEX_LOCKING', 1)
+
+ conf.CHECK_XSLTPROC_MANPAGES()
+
+ conf.SAMBA_CHECK_PYTHON()
+ conf.SAMBA_CHECK_PYTHON_HEADERS()
+
+ conf.SAMBA_CONFIG_H()
+
+ conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
+
+def build(bld):
+ bld.RECURSE('lib/replace')
+
+ COMMON_FILES='''check.c error.c tdb.c traverse.c
+ freelistcheck.c lock.c dump.c freelist.c
+ io.c open.c transaction.c hash.c summary.c rescue.c
+ mutex.c'''
+
+ COMMON_SRC = bld.SUBDIR('common', COMMON_FILES)
+
+ if bld.env.standalone_tdb:
+ bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+ private_library = False
+ else:
+ private_library = True
+
+ if not bld.CONFIG_SET('USING_SYSTEM_TDB'):
+
+ tdb_deps = 'replace'
+
+ if bld.CONFIG_SET('USE_TDB_MUTEX_LOCKING'):
+ tdb_deps += ' pthread'
+
+ bld.SAMBA_LIBRARY('tdb',
+ COMMON_SRC,
+ deps=tdb_deps,
+ includes='include',
+ abi_directory='ABI',
+ abi_match='tdb_*',
+ hide_symbols=True,
+ vnum=VERSION,
+ public_headers=('' if private_library else 'include/tdb.h'),
+ public_headers_install=not private_library,
+ pc_files='tdb.pc',
+ private_library=private_library)
+
+ bld.SAMBA_BINARY('tdbtorture',
+ 'tools/tdbtorture.c',
+ 'tdb',
+ install=False)
+
+ bld.SAMBA_BINARY('tdbtortseq',
+ 'tools/tdbtortseq.c',
+ 'tdb',
+ install=False)
+
+ bld.SAMBA_BINARY('tdbrestore',
+ 'tools/tdbrestore.c',
+ 'tdb', manpages='man/tdbrestore.8')
+
+ bld.SAMBA_BINARY('tdbdump',
+ 'tools/tdbdump.c',
+ 'tdb', manpages='man/tdbdump.8')
+
+ bld.SAMBA_BINARY('tdbbackup',
+ 'tools/tdbbackup.c',
+ 'tdb',
+ manpages='man/tdbbackup.8')
+
+ bld.SAMBA_BINARY('tdbtool',
+ 'tools/tdbtool.c',
+ 'tdb', manpages='man/tdbtool.8')
+
+ if bld.env.standalone_tdb:
+ # FIXME: This hardcoded list is stupid, stupid, stupid.
+ bld.SAMBA_SUBSYSTEM('tdb-test-helpers',
+ 'test/external-agent.c test/lock-tracking.c test/logging.c',
+ tdb_deps,
+ includes='include')
+
+ for t in tdb1_unit_tests:
+ b = "tdb1-" + t
+ s = "test/" + t + ".c"
+ bld.SAMBA_BINARY(b, s, 'replace tdb-test-helpers',
+ includes='include', install=False)
+
+ if not bld.CONFIG_SET('USING_SYSTEM_PYTDB'):
+ bld.SAMBA_PYTHON('pytdb',
+ 'pytdb.c',
+ deps='tdb',
+ enabled=not bld.env.disable_python,
+ realname='tdb.so',
+ cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+
+ if not bld.env.disable_python:
+ bld.SAMBA_SCRIPT('_tdb_text.py',
+ pattern='_tdb_text.py',
+ installdir='python')
+
+ bld.INSTALL_FILES('${PYTHONARCHDIR}', '_tdb_text.py')
+
+def testonly(ctx):
+ '''run tdb testsuite'''
+ ecode = 0
+
+ blddir = Context.g_module.out
+ test_prefix = "%s/st" % (blddir)
+ shutil.rmtree(test_prefix, ignore_errors=True)
+ os.makedirs(test_prefix)
+ os.environ['TEST_DATA_PREFIX'] = test_prefix
+
+ env = samba_utils.LOAD_ENVIRONMENT()
+ # FIXME: This is horrible :(
+ if env.building_tdb:
+ # Create scratch directory for tests.
+ testdir = os.path.join(test_prefix, 'tdb-tests')
+ samba_utils.mkdir_p(testdir)
+ # Symlink back to source dir so it can find tests in test/
+ link = os.path.join(testdir, 'test')
+ if not os.path.exists(link):
+ os.symlink(ctx.path.make_node('test').abspath(), link)
+
+ sh_tests = ["test/test_tdbbackup.sh test/jenkins-be-hash.tdb"]
+
+ for sh_test in sh_tests:
+ cmd = "BINDIR=%s %s" % (blddir, sh_test)
+ print("shell test: " + cmd)
+ ret = samba_utils.RUN_COMMAND(cmd)
+ if ret != 0:
+ print("%s sh test failed" % cmd)
+ ecode = ret
+ break
+
+ for t in tdb1_unit_tests:
+ f = "tdb1-" + t
+ cmd = "cd " + testdir + " && " + os.path.abspath(os.path.join(blddir, f)) + " > test-output 2>&1"
+ print("..." + f)
+ ret = samba_utils.RUN_COMMAND(cmd)
+ if ret != 0:
+ print("%s failed:" % f)
+ samba_utils.RUN_COMMAND("cat " + os.path.join(testdir, 'test-output'))
+ ecode = ret
+ break
+
+ if ecode == 0:
+ cmd = os.path.join(blddir, 'tdbtorture')
+ ret = samba_utils.RUN_COMMAND(cmd)
+ print("testsuite returned %d" % ret)
+ if ret != 0:
+ ecode = ret
+
+ pyret = samba_utils.RUN_PYTHON_TESTS(['python/tests/simple.py'])
+ print("python testsuite returned %d" % pyret)
+ sys.exit(ecode or pyret)
+
+# WAF doesn't build the unit tests for this, maybe because they don't link with tdb?
+# This forces it
+def test(ctx):
+ Options.commands.append('build')
+ Options.commands.append('testonly')
+
+def dist():
+ '''makes a tarball for distribution'''
+ samba_dist.dist()
+
+def reconfigure(ctx):
+ '''reconfigure if config scripts have changed'''
+ samba_utils.reconfigure(ctx)
diff --git a/lib/tdb_wrap/tdb_wrap.c b/lib/tdb_wrap/tdb_wrap.c
new file mode 100644
index 0000000..49585aa
--- /dev/null
+++ b/lib/tdb_wrap/tdb_wrap.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+ TDB wrap functions
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/debug.h"
+#include "tdb_wrap.h"
+
+/*
+ Log tdb messages via DEBUG().
+*/
+static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
+ const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+
+static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
+ const char *format, ...)
+{
+ va_list ap;
+ char *ptr = NULL;
+ int debuglevel = 0;
+ int ret;
+
+ switch (level) {
+ case TDB_DEBUG_FATAL:
+ debuglevel = 0;
+ break;
+ case TDB_DEBUG_ERROR:
+ debuglevel = 1;
+ break;
+ case TDB_DEBUG_WARNING:
+ debuglevel = 2;
+ break;
+ case TDB_DEBUG_TRACE:
+ debuglevel = 5;
+ break;
+ default:
+ debuglevel = 0;
+ }
+
+ va_start(ap, format);
+ ret = vasprintf(&ptr, format, ap);
+ va_end(ap);
+
+ if (ret != -1) {
+ const char *name = tdb_name(tdb);
+ DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
+ free(ptr);
+ }
+}
+
+struct tdb_wrap_private {
+ struct tdb_context *tdb;
+ const char *name;
+ struct tdb_wrap_private *next, *prev;
+};
+
+static struct tdb_wrap_private *tdb_list;
+
+/* destroy the last connection to a tdb */
+static int tdb_wrap_private_destructor(struct tdb_wrap_private *w)
+{
+ tdb_close(w->tdb);
+ DLIST_REMOVE(tdb_list, w);
+ return 0;
+}
+
+static struct tdb_wrap_private *tdb_wrap_private_open(TALLOC_CTX *mem_ctx,
+ const char *name,
+ int hash_size,
+ int tdb_flags,
+ int open_flags,
+ mode_t mode)
+{
+ struct tdb_wrap_private *result;
+ struct tdb_logging_context lctx = { .log_fn = tdb_wrap_log };
+
+ result = talloc_pooled_object(mem_ctx, struct tdb_wrap_private,
+ 1, strlen(name)+1);
+ if (result == NULL) {
+ return NULL;
+ }
+ /* Doesn't fail, see talloc_pooled_object */
+ result->name = talloc_strdup(result, name);
+
+ /*
+ * TDB files don't make sense after execve()
+ */
+ open_flags |= O_CLOEXEC;
+
+ result->tdb = tdb_open_ex(name, hash_size, tdb_flags,
+ open_flags, mode, &lctx, NULL);
+ if (result->tdb == NULL) {
+ goto fail;
+ }
+ talloc_set_destructor(result, tdb_wrap_private_destructor);
+ DLIST_ADD(tdb_list, result);
+ return result;
+
+fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+/*
+ wrapped connection to a tdb database
+ to close just talloc_free() the tdb_wrap pointer
+ */
+struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ struct tdb_wrap *result;
+ struct tdb_wrap_private *w;
+
+ if (name == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ result = talloc(mem_ctx, struct tdb_wrap);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ for (w=tdb_list;w;w=w->next) {
+ if (strcmp(name, w->name) == 0) {
+ break;
+ }
+ }
+
+ if (w == NULL) {
+
+ if (tdb_flags & TDB_MUTEX_LOCKING) {
+ if (!tdb_runtime_check_for_robust_mutexes()) {
+ tdb_flags &= ~TDB_MUTEX_LOCKING;
+ }
+ }
+
+ w = tdb_wrap_private_open(result, name, hash_size, tdb_flags,
+ open_flags, mode);
+ } else {
+ /*
+ * Correctly use talloc_reference: The tdb will be
+ * closed when "w" is being freed. The caller never
+ * sees "w", so an incorrect use of talloc_free(w)
+ * instead of calling talloc_unlink is not possible.
+ * To avoid having to refcount ourselves, "w" will
+ * have multiple parents that hang off all the
+ * tdb_wrap's being returned from here. Those parents
+ * can be freed without problem.
+ */
+ if (talloc_reference(result, w) == NULL) {
+ goto fail;
+ }
+ }
+ if (w == NULL) {
+ goto fail;
+ }
+ result->tdb = w->tdb;
+ return result;
+fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
diff --git a/lib/tdb_wrap/tdb_wrap.h b/lib/tdb_wrap/tdb_wrap.h
new file mode 100644
index 0000000..de7e332
--- /dev/null
+++ b/lib/tdb_wrap/tdb_wrap.h
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ database wrap headers
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* IMPORTANT: tdb_wrap should be always preferred over tdb_context for end consumer functions
+ it's because if the code will be running inside smbd, then we must use the linked list
+ of open tdb files, to determine if the tdb we desire is already open
+ as otherwise, when you close the tdb (even on a different file descriptor),
+ ALL LOCKS are lost (due to a real screwup in the POSIX specification that nobody has been able to get fixed)
+*/
+
+#ifndef _TDB_WRAP_H_
+#define _TDB_WRAP_H_
+
+#include <talloc.h>
+#include <tdb.h>
+
+struct tdb_wrap {
+ struct tdb_context *tdb;
+};
+
+struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
+ const char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+
+#endif /* _TDB_WRAP_H_ */
diff --git a/lib/tdb_wrap/wscript_build b/lib/tdb_wrap/wscript_build
new file mode 100644
index 0000000..7e113c3
--- /dev/null
+++ b/lib/tdb_wrap/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+
+bld.SAMBA_LIBRARY('tdb-wrap',
+ source='tdb_wrap.c',
+ deps='tdb talloc samba-debug',
+ private_library=True,
+ local_include=False
+ )
diff --git a/lib/tdr/TODO b/lib/tdr/TODO
new file mode 100644
index 0000000..5093afd
--- /dev/null
+++ b/lib/tdr/TODO
@@ -0,0 +1 @@
+- Support read/write (to fd) as well as push/pull (to DATA_BLOB)
diff --git a/lib/tdr/tdr.c b/lib/tdr/tdr.c
new file mode 100644
index 0000000..cff1fc6
--- /dev/null
+++ b/lib/tdr/tdr.c
@@ -0,0 +1,409 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ TDR (Trivial Data Representation) helper functions
+ Based loosely on ndr.c by Andrew Tridgell.
+
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "lib/tdr/tdr.h"
+
+#define TDR_BASE_MARSHALL_SIZE 1024
+
+#define TDR_PUSH_NEED_BYTES(tdr, n) TDR_CHECK(tdr_push_expand(tdr, tdr->data.length+(n)))
+
+#define TDR_PULL_NEED_BYTES(tdr, n) do { \
+ if ((n) > tdr->data.length || tdr->offset + (n) > tdr->data.length) { \
+ return NT_STATUS_BUFFER_TOO_SMALL; \
+ } \
+} while(0)
+
+#define TDR_BE(tdr) ((tdr)->flags & TDR_BIG_ENDIAN)
+
+#define TDR_CVAL(tdr, ofs) CVAL(tdr->data.data,ofs)
+#define TDR_SVAL(tdr, ofs) (TDR_BE(tdr)?RSVAL(tdr->data.data,ofs):SVAL(tdr->data.data,ofs))
+#define TDR_IVAL(tdr, ofs) (TDR_BE(tdr)?RIVAL(tdr->data.data,ofs):IVAL(tdr->data.data,ofs))
+#define TDR_SCVAL(tdr, ofs, v) SCVAL(tdr->data.data,ofs,v)
+#define TDR_SSVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSSVAL(tdr->data.data,ofs,v); } else SSVAL(tdr->data.data,ofs,v); } while (0)
+#define TDR_SIVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSIVAL(tdr->data.data,ofs,v); } else SIVAL(tdr->data.data,ofs,v); } while (0)
+
+/**
+ expand the available space in the buffer to 'size'
+*/
+NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size)
+{
+ if (talloc_get_size(tdr->data.data) >= size) {
+ return NT_STATUS_OK;
+ }
+
+ tdr->data.data = talloc_realloc(tdr, tdr->data.data, uint8_t, tdr->data.length + TDR_BASE_MARSHALL_SIZE);
+
+ if (tdr->data.data == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint8_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 1);
+ *v = TDR_CVAL(tdr, tdr->offset);
+ tdr->offset += 1;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_uint8(struct tdr_push *tdr, const uint8_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 1);
+ TDR_SCVAL(tdr, tdr->data.length, *v);
+ tdr->data.length += 1;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_uint8(struct tdr_print *tdr, const char *name, uint8_t *v)
+{
+ tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 2);
+ *v = TDR_SVAL(tdr, tdr->offset);
+ tdr->offset += 2;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_pull_uint1632(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v)
+{
+ return tdr_pull_uint16(tdr, ctx, v);
+}
+
+NTSTATUS tdr_push_uint16(struct tdr_push *tdr, const uint16_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 2);
+ TDR_SSVAL(tdr, tdr->data.length, *v);
+ tdr->data.length += 2;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_uint1632(struct tdr_push *tdr, const uint16_t *v)
+{
+ return tdr_push_uint16(tdr, v);
+}
+
+NTSTATUS tdr_print_uint16(struct tdr_print *tdr, const char *name, uint16_t *v)
+{
+ tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint32_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 4);
+ *v = TDR_IVAL(tdr, tdr->offset);
+ tdr->offset += 4;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_uint32(struct tdr_push *tdr, const uint32_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 4);
+ TDR_SIVAL(tdr, tdr->data.length, *v);
+ tdr->data.length += 4;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_uint32(struct tdr_print *tdr, const char *name, uint32_t *v)
+{
+ tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, TALLOC_CTX *ctx, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
+{
+ size_t ret;
+
+ if (length == -1) {
+ switch (chset) {
+ case CH_DOS:
+ length = ascii_len_n((const char*)tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
+ break;
+ case CH_UTF16:
+ length = utf16_null_terminated_len_n(tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (length == 0) {
+ *v = talloc_strdup(ctx, "");
+ return NT_STATUS_OK;
+ }
+
+ TDR_PULL_NEED_BYTES(tdr, el_size*length);
+
+ if (!convert_string_talloc(ctx, chset, CH_UNIX, tdr->data.data+tdr->offset, el_size*length, v, &ret)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tdr->offset += length * el_size;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
+{
+ size_t required, size = 0;
+ bool ret;
+
+ if (length == -1) {
+ length = strlen(*v) + 1; /* Extra element for null character */
+ }
+
+ required = el_size * length;
+ TDR_PUSH_NEED_BYTES(tdr, required);
+
+ ret = convert_string(CH_UNIX, chset, *v, strlen(*v), tdr->data.data+tdr->data.length, required, &size);
+ if (ret == false) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Make sure the remaining part of the string is filled with zeroes */
+ if (size < required) {
+ memset(tdr->data.data+tdr->data.length+size, 0, required-size);
+ }
+
+ tdr->data.length += required;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
+{
+ tdr->print(tdr, "%-25s: %s", name, *v);
+ return NT_STATUS_OK;
+}
+
+/**
+ parse a hyper
+*/
+NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint64_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 8);
+ *v = TDR_IVAL(tdr, tdr->offset);
+ *v |= (uint64_t)(TDR_IVAL(tdr, tdr->offset+4)) << 32;
+ tdr->offset += 8;
+ return NT_STATUS_OK;
+}
+
+/**
+ push a hyper
+*/
+NTSTATUS tdr_push_hyper(struct tdr_push *tdr, uint64_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 8);
+ TDR_SIVAL(tdr, tdr->data.length, ((*v) & 0xFFFFFFFF));
+ TDR_SIVAL(tdr, tdr->data.length+4, ((*v)>>32));
+ tdr->data.length += 8;
+ return NT_STATUS_OK;
+}
+
+/**
+ push a NTTIME
+*/
+NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t)
+{
+ TDR_CHECK(tdr_push_hyper(tdr, t));
+ return NT_STATUS_OK;
+}
+
+/**
+ pull a NTTIME
+*/
+NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, TALLOC_CTX *ctx, NTTIME *t)
+{
+ TDR_CHECK(tdr_pull_hyper(tdr, ctx, t));
+ return NT_STATUS_OK;
+}
+
+/**
+ push a time_t
+*/
+NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t)
+{
+ return tdr_push_uint32(tdr, (uint32_t *)t);
+}
+
+/**
+ pull a time_t
+*/
+NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, TALLOC_CTX *ctx, time_t *t)
+{
+ uint32_t tt;
+ TDR_CHECK(tdr_pull_uint32(tdr, ctx, &tt));
+ *t = tt;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_time_t(struct tdr_print *tdr, const char *name, time_t *t)
+{
+ if (*t == (time_t)-1 || *t == 0) {
+ tdr->print(tdr, "%-25s: (time_t)%d", name, (int)*t);
+ } else {
+ tdr->print(tdr, "%-25s: %s", name, timestring(tdr, *t));
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_NTTIME(struct tdr_print *tdr, const char *name, NTTIME *t)
+{
+ tdr->print(tdr, "%-25s: %s", name, nt_time_string(tdr, *t));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB *r)
+{
+ tdr->print(tdr, "%-25s: DATA_BLOB length=%u", name, r->length);
+ if (r->length) {
+ dump_data(10, r->data, r->length);
+ }
+
+ return NT_STATUS_OK;
+}
+
+#define TDR_ALIGN(l,n) (((l) & ((n)-1)) == 0?0:((n)-((l)&((n)-1))))
+
+/*
+ push a DATA_BLOB onto the wire.
+*/
+NTSTATUS tdr_push_DATA_BLOB(struct tdr_push *tdr, DATA_BLOB *blob)
+{
+ if (tdr->flags & TDR_ALIGN2) {
+ blob->length = TDR_ALIGN(tdr->data.length, 2);
+ } else if (tdr->flags & TDR_ALIGN4) {
+ blob->length = TDR_ALIGN(tdr->data.length, 4);
+ } else if (tdr->flags & TDR_ALIGN8) {
+ blob->length = TDR_ALIGN(tdr->data.length, 8);
+ }
+
+ TDR_PUSH_NEED_BYTES(tdr, blob->length);
+
+ memcpy(tdr->data.data+tdr->data.length, blob->data, blob->length);
+ return NT_STATUS_OK;
+}
+
+/*
+ pull a DATA_BLOB from the wire.
+*/
+NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, TALLOC_CTX *ctx, DATA_BLOB *blob)
+{
+ uint32_t length;
+
+ if (tdr->flags & TDR_ALIGN2) {
+ length = TDR_ALIGN(tdr->offset, 2);
+ } else if (tdr->flags & TDR_ALIGN4) {
+ length = TDR_ALIGN(tdr->offset, 4);
+ } else if (tdr->flags & TDR_ALIGN8) {
+ length = TDR_ALIGN(tdr->offset, 8);
+ } else if (tdr->flags & TDR_REMAINING) {
+ length = tdr->data.length - tdr->offset;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (tdr->data.length - tdr->offset < length) {
+ length = tdr->data.length - tdr->offset;
+ }
+
+ TDR_PULL_NEED_BYTES(tdr, length);
+
+ *blob = data_blob_talloc(tdr, tdr->data.data+tdr->offset, length);
+ tdr->offset += length;
+ return NT_STATUS_OK;
+}
+
+struct tdr_push *tdr_push_init(TALLOC_CTX *mem_ctx)
+{
+ struct tdr_push *push = talloc_zero(mem_ctx, struct tdr_push);
+
+ if (push == NULL)
+ return NULL;
+
+ return push;
+}
+
+struct tdr_pull *tdr_pull_init(TALLOC_CTX *mem_ctx)
+{
+ struct tdr_pull *pull = talloc_zero(mem_ctx, struct tdr_pull);
+
+ if (pull == NULL)
+ return NULL;
+
+ return pull;
+}
+
+NTSTATUS tdr_push_to_fd(int fd, tdr_push_fn_t push_fn, const void *p)
+{
+ struct tdr_push *push = tdr_push_init(NULL);
+
+ if (push == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (NT_STATUS_IS_ERR(push_fn(push, p))) {
+ DEBUG(1, ("Error pushing data\n"));
+ talloc_free(push);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (write(fd, push->data.data, push->data.length) < push->data.length) {
+ DEBUG(1, ("Error writing all data\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ talloc_free(push);
+
+ return NT_STATUS_OK;
+}
+
+void tdr_print_debug_helper(struct tdr_print *tdr, const char *format, ...)
+{
+ va_list ap;
+ char *s = NULL;
+ int i, ret;
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return;
+ }
+
+ for (i=0;i<tdr->level;i++) { DEBUG(0,(" ")); }
+
+ DEBUG(0,("%s\n", s));
+ free(s);
+}
diff --git a/lib/tdr/tdr.h b/lib/tdr/tdr.h
new file mode 100644
index 0000000..fa0a4d7
--- /dev/null
+++ b/lib/tdr/tdr.h
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/CIFS implementation.
+ TDR definitions
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TDR_H__
+#define __TDR_H__
+
+#include <talloc.h>
+#include "../lib/util/charset/charset.h"
+
+#define TDR_BIG_ENDIAN 0x01
+#define TDR_ALIGN2 0x02
+#define TDR_ALIGN4 0x04
+#define TDR_ALIGN8 0x08
+#define TDR_REMAINING 0x10
+
+struct tdr_pull {
+ DATA_BLOB data;
+ uint32_t offset;
+ int flags;
+};
+
+struct tdr_push {
+ DATA_BLOB data;
+ int flags;
+};
+
+struct tdr_print {
+ int level;
+ void (*print)(struct tdr_print *, const char *, ...);
+ int flags;
+};
+
+#define TDR_CHECK(call) do { NTSTATUS _status; \
+ _status = call; \
+ if (!NT_STATUS_IS_OK(_status)) \
+ return _status; \
+ } while (0)
+
+#define TDR_ALLOC(ctx, s, n) do { \
+ (s) = talloc_array_ptrtype(ctx, (s), n); \
+ if ((n) && !(s)) return NT_STATUS_NO_MEMORY; \
+ } while (0)
+
+typedef NTSTATUS (*tdr_push_fn_t) (struct tdr_push *, const void *);
+typedef NTSTATUS (*tdr_pull_fn_t) (struct tdr_pull *, TALLOC_CTX *, void *);
+
+NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size);
+NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint8_t *v);
+NTSTATUS tdr_push_uint8(struct tdr_push *tdr, const uint8_t *v);
+NTSTATUS tdr_print_uint8(struct tdr_print *tdr, const char *name, uint8_t *v);
+NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v);
+NTSTATUS tdr_pull_uint1632(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v);
+NTSTATUS tdr_push_uint16(struct tdr_push *tdr, const uint16_t *v);
+NTSTATUS tdr_push_uint1632(struct tdr_push *tdr, const uint16_t *v);
+NTSTATUS tdr_print_uint16(struct tdr_print *tdr, const char *name, uint16_t *v);
+NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint32_t *v);
+NTSTATUS tdr_push_uint32(struct tdr_push *tdr, const uint32_t *v);
+NTSTATUS tdr_print_uint32(struct tdr_print *tdr, const char *name, uint32_t *v);
+NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, TALLOC_CTX *ctx, const char **v, uint32_t length, uint32_t el_size, charset_t chset);
+NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, charset_t chset);
+NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, charset_t chset);
+
+NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint64_t *v);
+NTSTATUS tdr_push_hyper(struct tdr_push *tdr, uint64_t *v);
+
+NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t);
+NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, TALLOC_CTX *ctx, NTTIME *t);
+NTSTATUS tdr_print_NTTIME(struct tdr_print *tdr, const char *name, NTTIME *t);
+
+NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t);
+NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, TALLOC_CTX *ctx, time_t *t);
+NTSTATUS tdr_print_time_t(struct tdr_print *tdr, const char *name, time_t *t);
+
+NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB *r);
+NTSTATUS tdr_push_DATA_BLOB(struct tdr_push *tdr, DATA_BLOB *blob);
+NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, TALLOC_CTX *ctx, DATA_BLOB *blob);
+
+struct tdr_push *tdr_push_init(TALLOC_CTX *mem_ctx);
+struct tdr_pull *tdr_pull_init(TALLOC_CTX *mem_ctx);
+
+NTSTATUS tdr_push_to_fd(int fd, tdr_push_fn_t push_fn, const void *p);
+void tdr_print_debug_helper(struct tdr_print *tdr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+
+#endif /* __TDR_H__ */
diff --git a/lib/tdr/testsuite.c b/lib/tdr/testsuite.c
new file mode 100644
index 0000000..e784e07
--- /dev/null
+++ b/lib/tdr/testsuite.c
@@ -0,0 +1,186 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for basic tdr functions
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/tdr/tdr.h"
+
+static bool test_push_uint8(struct torture_context *tctx)
+{
+ uint8_t v = 4;
+ struct tdr_push *tdr = tdr_push_init(tctx);
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_uint8(tdr, &v), "push failed");
+ torture_assert_int_equal(tctx, tdr->data.length, 1, "length incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[0], 4, "data incorrect");
+ return true;
+}
+
+static bool test_pull_uint8(struct torture_context *tctx)
+{
+ uint8_t d = 2;
+ uint8_t l;
+ struct tdr_pull *tdr = tdr_pull_init(tctx);
+ tdr->data.data = &d;
+ tdr->data.length = 1;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_uint8(tdr, tctx, &l),
+ "pull failed");
+ torture_assert_int_equal(tctx, 1, tdr->offset,
+ "offset invalid");
+ return true;
+}
+
+static bool test_push_uint16(struct torture_context *tctx)
+{
+ uint16_t v = 0xF32;
+ struct tdr_push *tdr = tdr_push_init(tctx);
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_uint16(tdr, &v), "push failed");
+ torture_assert_int_equal(tctx, tdr->data.length, 2, "length incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[0], 0x32, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[1], 0x0F, "data incorrect");
+ return true;
+}
+
+static bool test_pull_uint16(struct torture_context *tctx)
+{
+ uint8_t d[2] = { 782 & 0xFF, (782 & 0xFF00) / 0x100 };
+ uint16_t l;
+ struct tdr_pull *tdr = tdr_pull_init(tctx);
+ tdr->data.data = d;
+ tdr->data.length = 2;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_uint16(tdr, tctx, &l),
+ "pull failed");
+ torture_assert_int_equal(tctx, 2, tdr->offset, "offset invalid");
+ torture_assert_int_equal(tctx, 782, l, "right int read");
+ return true;
+}
+
+static bool test_push_uint32(struct torture_context *tctx)
+{
+ uint32_t v = 0x100F32;
+ struct tdr_push *tdr = tdr_push_init(tctx);
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_uint32(tdr, &v), "push failed");
+ torture_assert_int_equal(tctx, tdr->data.length, 4, "length incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[0], 0x32, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[1], 0x0F, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[2], 0x10, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[3], 0x00, "data incorrect");
+ return true;
+}
+
+static bool test_pull_uint32(struct torture_context *tctx)
+{
+ uint8_t d[4] = { 782 & 0xFF, (782 & 0xFF00) / 0x100, 0, 0 };
+ uint32_t l;
+ struct tdr_pull *tdr = tdr_pull_init(tctx);
+ tdr->data.data = d;
+ tdr->data.length = 4;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_uint32(tdr, tctx, &l),
+ "pull failed");
+ torture_assert_int_equal(tctx, 4, tdr->offset, "offset invalid");
+ torture_assert_int_equal(tctx, 782, l, "right int read");
+ return true;
+}
+
+static bool test_pull_charset(struct torture_context *tctx)
+{
+ struct tdr_pull *tdr = tdr_pull_init(tctx);
+ const char *l = NULL;
+ tdr->data.data = (uint8_t *)talloc_strdup(tctx, "bla");
+ tdr->data.length = 4;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_charset(tdr, tctx, &l, -1, 1, CH_DOS),
+ "pull failed");
+ torture_assert_int_equal(tctx, 4, tdr->offset, "offset invalid");
+ torture_assert_str_equal(tctx, "bla", l, "right int read");
+
+ tdr->offset = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_charset(tdr, tctx, &l, 2, 1, CH_UNIX),
+ "pull failed");
+ torture_assert_int_equal(tctx, 2, tdr->offset, "offset invalid");
+ torture_assert_str_equal(tctx, "bl", l, "right int read");
+
+ return true;
+}
+
+static bool test_pull_charset_empty(struct torture_context *tctx)
+{
+ struct tdr_pull *tdr = tdr_pull_init(tctx);
+ const char *l = NULL;
+ tdr->data.data = (uint8_t *)talloc_strdup(tctx, "bla");
+ tdr->data.length = 4;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_charset(tdr, tctx, &l, 0, 1, CH_DOS),
+ "pull failed");
+ torture_assert_int_equal(tctx, 0, tdr->offset, "offset invalid");
+ torture_assert_str_equal(tctx, "", l, "right string read");
+
+ return true;
+}
+
+
+
+static bool test_push_charset(struct torture_context *tctx)
+{
+ const char *l = "bloe";
+ struct tdr_push *tdr = tdr_push_init(tctx);
+ torture_assert_ntstatus_ok(tctx, tdr_push_charset(tdr, &l, 4, 1, CH_UTF8),
+ "push failed");
+ torture_assert_int_equal(tctx, 4, tdr->data.length, "offset invalid");
+ torture_assert(tctx, strncmp("bloe", (const char *)tdr->data.data, 4) == 0, "right string push");
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_charset(tdr, &l, -1, 1, CH_UTF8),
+ "push failed");
+ torture_assert_int_equal(tctx, 9, tdr->data.length, "offset invalid");
+ torture_assert_str_equal(tctx, "bloe", (const char *)tdr->data.data+4, "right string read");
+
+ return true;
+}
+
+struct torture_suite *torture_local_tdr(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "tdr");
+
+ torture_suite_add_simple_test(suite, "pull_uint8", test_pull_uint8);
+ torture_suite_add_simple_test(suite, "push_uint8", test_push_uint8);
+
+ torture_suite_add_simple_test(suite, "pull_uint16", test_pull_uint16);
+ torture_suite_add_simple_test(suite, "push_uint16", test_push_uint16);
+
+ torture_suite_add_simple_test(suite, "pull_uint32", test_pull_uint32);
+ torture_suite_add_simple_test(suite, "push_uint32", test_push_uint32);
+
+ torture_suite_add_simple_test(suite, "pull_charset", test_pull_charset);
+ torture_suite_add_simple_test(suite, "pull_charset", test_pull_charset_empty);
+ torture_suite_add_simple_test(suite, "push_charset", test_push_charset);
+
+ return suite;
+}
diff --git a/lib/tdr/wscript_build b/lib/tdr/wscript_build
new file mode 100644
index 0000000..67fdfeb
--- /dev/null
+++ b/lib/tdr/wscript_build
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_SUBSYSTEM('TDR',
+ source='tdr.c',
+ public_deps='talloc samba-util',
+ public_headers='tdr.h'
+ )
+
diff --git a/lib/tevent/ABI/tevent-0.10.0.sigs b/lib/tevent/ABI/tevent-0.10.0.sigs
new file mode 100644
index 0000000..f6227db
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.10.0.sigs
@@ -0,0 +1,126 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.10.1.sigs b/lib/tevent/ABI/tevent-0.10.1.sigs
new file mode 100644
index 0000000..f6227db
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.10.1.sigs
@@ -0,0 +1,126 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.10.2.sigs b/lib/tevent/ABI/tevent-0.10.2.sigs
new file mode 100644
index 0000000..f6227db
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.10.2.sigs
@@ -0,0 +1,126 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.11.0.sigs b/lib/tevent/ABI/tevent-0.11.0.sigs
new file mode 100644
index 0000000..e64007e
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.11.0.sigs
@@ -0,0 +1,146 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.12.0.sigs b/lib/tevent/ABI/tevent-0.12.0.sigs
new file mode 100644
index 0000000..22a8ce3
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.12.0.sigs
@@ -0,0 +1,151 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.12.1.sigs b/lib/tevent/ABI/tevent-0.12.1.sigs
new file mode 100644
index 0000000..0e4d1e1
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.12.1.sigs
@@ -0,0 +1,151 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.13.0.sigs b/lib/tevent/ABI/tevent-0.13.0.sigs
new file mode 100644
index 0000000..68722a0
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.13.0.sigs
@@ -0,0 +1,152 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cached_getpid: pid_t (void)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.14.0.sigs b/lib/tevent/ABI/tevent-0.14.0.sigs
new file mode 100644
index 0000000..f2a1190
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.14.0.sigs
@@ -0,0 +1,157 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cached_getpid: pid_t (void)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_find_ops_byname: const struct tevent_ops *(const char *)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_call_depth_activate: void (size_t *)
+tevent_thread_call_depth_deactivate: void (void)
+tevent_thread_call_depth_reset_from_req: void (struct tevent_req *)
+tevent_thread_call_depth_start: void (struct tevent_req *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.14.1.sigs b/lib/tevent/ABI/tevent-0.14.1.sigs
new file mode 100644
index 0000000..f2a1190
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.14.1.sigs
@@ -0,0 +1,157 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cached_getpid: pid_t (void)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_find_ops_byname: const struct tevent_ops *(const char *)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_call_depth_activate: void (size_t *)
+tevent_thread_call_depth_deactivate: void (void)
+tevent_thread_call_depth_reset_from_req: void (struct tevent_req *)
+tevent_thread_call_depth_start: void (struct tevent_req *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.15.0.sigs b/lib/tevent/ABI/tevent-0.15.0.sigs
new file mode 100644
index 0000000..f7eba57
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.15.0.sigs
@@ -0,0 +1,167 @@
+__tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *, const char *)
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, const char *, void *)
+_tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn, const char *)
+_tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_thread_call_depth_reset_from_req: void (struct tevent_req *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cached_getpid: pid_t (void)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_find_ops_byname: const struct tevent_ops *(const char *)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_max_debug_level: enum tevent_debug_level (struct tevent_context *, enum tevent_debug_level)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_call_depth_activate: void (size_t *)
+tevent_thread_call_depth_deactivate: void (void)
+tevent_thread_call_depth_reset_from_req: void (struct tevent_req *)
+tevent_thread_call_depth_set_callback: void (tevent_call_depth_callback_t, void *)
+tevent_thread_call_depth_start: void (struct tevent_req *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.16.0.sigs b/lib/tevent/ABI/tevent-0.16.0.sigs
new file mode 100644
index 0000000..f7eba57
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.16.0.sigs
@@ -0,0 +1,167 @@
+__tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *, const char *)
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, const char *, void *)
+_tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn, const char *)
+_tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_thread_call_depth_reset_from_req: void (struct tevent_req *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cached_getpid: pid_t (void)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_find_ops_byname: const struct tevent_ops *(const char *)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_max_debug_level: enum tevent_debug_level (struct tevent_context *, enum tevent_debug_level)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_call_depth_activate: void (size_t *)
+tevent_thread_call_depth_deactivate: void (void)
+tevent_thread_call_depth_reset_from_req: void (struct tevent_req *)
+tevent_thread_call_depth_set_callback: void (tevent_call_depth_callback_t, void *)
+tevent_thread_call_depth_start: void (struct tevent_req *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.16.1.sigs b/lib/tevent/ABI/tevent-0.16.1.sigs
new file mode 100644
index 0000000..f7eba57
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.16.1.sigs
@@ -0,0 +1,167 @@
+__tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *, const char *)
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, const char *, void *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, const char *, void *)
+_tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn, const char *)
+_tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_thread_call_depth_reset_from_req: void (struct tevent_req *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cached_getpid: pid_t (void)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_get_tag: uint64_t (const struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_fd_set_tag: void (struct tevent_fd *, uint64_t)
+tevent_find_ops_byname: const struct tevent_ops *(const char *)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_get_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t *, void *)
+tevent_get_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t *, void *)
+tevent_get_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t *, void *)
+tevent_get_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t *, void *)
+tevent_get_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t *, void *)
+tevent_immediate_get_tag: uint64_t (const struct tevent_immediate *)
+tevent_immediate_set_tag: void (struct tevent_immediate *, uint64_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_get_tag: uint64_t (const struct tevent_queue_entry *)
+tevent_queue_entry_set_tag: void (struct tevent_queue_entry *, uint64_t)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_max_debug_level: enum tevent_debug_level (struct tevent_context *, enum tevent_debug_level)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_set_trace_fd_callback: void (struct tevent_context *, tevent_trace_fd_callback_t, void *)
+tevent_set_trace_immediate_callback: void (struct tevent_context *, tevent_trace_immediate_callback_t, void *)
+tevent_set_trace_queue_callback: void (struct tevent_context *, tevent_trace_queue_callback_t, void *)
+tevent_set_trace_signal_callback: void (struct tevent_context *, tevent_trace_signal_callback_t, void *)
+tevent_set_trace_timer_callback: void (struct tevent_context *, tevent_trace_timer_callback_t, void *)
+tevent_signal_get_tag: uint64_t (const struct tevent_signal *)
+tevent_signal_set_tag: void (struct tevent_signal *, uint64_t)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_call_depth_activate: void (size_t *)
+tevent_thread_call_depth_deactivate: void (void)
+tevent_thread_call_depth_reset_from_req: void (struct tevent_req *)
+tevent_thread_call_depth_set_callback: void (tevent_call_depth_callback_t, void *)
+tevent_thread_call_depth_start: void (struct tevent_req *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timer_get_tag: uint64_t (const struct tevent_timer *)
+tevent_timer_set_tag: void (struct tevent_timer *, uint64_t)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_fd_callback: void (struct tevent_context *, struct tevent_fd *, enum tevent_event_trace_point)
+tevent_trace_immediate_callback: void (struct tevent_context *, struct tevent_immediate *, enum tevent_event_trace_point)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_trace_queue_callback: void (struct tevent_context *, struct tevent_queue_entry *, enum tevent_event_trace_point)
+tevent_trace_signal_callback: void (struct tevent_context *, struct tevent_signal *, enum tevent_event_trace_point)
+tevent_trace_timer_callback: void (struct tevent_context *, struct tevent_timer *, enum tevent_event_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.10.sigs b/lib/tevent/ABI/tevent-0.9.10.sigs
new file mode 100644
index 0000000..9adaba5
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.10.sigs
@@ -0,0 +1,73 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.11.sigs b/lib/tevent/ABI/tevent-0.9.11.sigs
new file mode 100644
index 0000000..9adaba5
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.11.sigs
@@ -0,0 +1,73 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.12.sigs b/lib/tevent/ABI/tevent-0.9.12.sigs
new file mode 100644
index 0000000..df9b08d
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.12.sigs
@@ -0,0 +1,74 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.13.sigs b/lib/tevent/ABI/tevent-0.9.13.sigs
new file mode 100644
index 0000000..888ca0e
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.13.sigs
@@ -0,0 +1,75 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.14.sigs b/lib/tevent/ABI/tevent-0.9.14.sigs
new file mode 100644
index 0000000..13c461c
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.14.sigs
@@ -0,0 +1,78 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.15.sigs b/lib/tevent/ABI/tevent-0.9.15.sigs
new file mode 100644
index 0000000..13c461c
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.15.sigs
@@ -0,0 +1,78 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.16.sigs b/lib/tevent/ABI/tevent-0.9.16.sigs
new file mode 100644
index 0000000..ea7f944
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.16.sigs
@@ -0,0 +1,82 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.17.sigs b/lib/tevent/ABI/tevent-0.9.17.sigs
new file mode 100644
index 0000000..ea7f944
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.17.sigs
@@ -0,0 +1,82 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.18.sigs b/lib/tevent/ABI/tevent-0.9.18.sigs
new file mode 100644
index 0000000..70d20b6
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.18.sigs
@@ -0,0 +1,83 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.19.sigs b/lib/tevent/ABI/tevent-0.9.19.sigs
new file mode 100644
index 0000000..70d20b6
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.19.sigs
@@ -0,0 +1,83 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.20.sigs b/lib/tevent/ABI/tevent-0.9.20.sigs
new file mode 100644
index 0000000..7b9c77d
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.20.sigs
@@ -0,0 +1,87 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.21.sigs b/lib/tevent/ABI/tevent-0.9.21.sigs
new file mode 100644
index 0000000..d8b9f4b
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.21.sigs
@@ -0,0 +1,88 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.22.sigs b/lib/tevent/ABI/tevent-0.9.22.sigs
new file mode 100644
index 0000000..d8b9f4b
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.22.sigs
@@ -0,0 +1,88 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.23.sigs b/lib/tevent/ABI/tevent-0.9.23.sigs
new file mode 100644
index 0000000..d8b9f4b
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.23.sigs
@@ -0,0 +1,88 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.24.sigs b/lib/tevent/ABI/tevent-0.9.24.sigs
new file mode 100644
index 0000000..d8b9f4b
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.24.sigs
@@ -0,0 +1,88 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.25.sigs b/lib/tevent/ABI/tevent-0.9.25.sigs
new file mode 100644
index 0000000..d8b9f4b
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.25.sigs
@@ -0,0 +1,88 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.26.sigs b/lib/tevent/ABI/tevent-0.9.26.sigs
new file mode 100644
index 0000000..1357751
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.26.sigs
@@ -0,0 +1,90 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.27.sigs b/lib/tevent/ABI/tevent-0.9.27.sigs
new file mode 100644
index 0000000..1357751
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.27.sigs
@@ -0,0 +1,90 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.28.sigs b/lib/tevent/ABI/tevent-0.9.28.sigs
new file mode 100644
index 0000000..1357751
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.28.sigs
@@ -0,0 +1,90 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.29.sigs b/lib/tevent/ABI/tevent-0.9.29.sigs
new file mode 100644
index 0000000..1357751
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.29.sigs
@@ -0,0 +1,90 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.30.sigs b/lib/tevent/ABI/tevent-0.9.30.sigs
new file mode 100644
index 0000000..9b8bfa1
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.30.sigs
@@ -0,0 +1,96 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.31.sigs b/lib/tevent/ABI/tevent-0.9.31.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.31.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.32.sigs b/lib/tevent/ABI/tevent-0.9.32.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.32.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.33.sigs b/lib/tevent/ABI/tevent-0.9.33.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.33.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.34.sigs b/lib/tevent/ABI/tevent-0.9.34.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.34.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.35.sigs b/lib/tevent/ABI/tevent-0.9.35.sigs
new file mode 100644
index 0000000..7a6a236
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.35.sigs
@@ -0,0 +1,99 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
new file mode 100644
index 0000000..8a579c8
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -0,0 +1,100 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.37.sigs b/lib/tevent/ABI/tevent-0.9.37.sigs
new file mode 100644
index 0000000..f6227db
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.37.sigs
@@ -0,0 +1,126 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.38.sigs b/lib/tevent/ABI/tevent-0.9.38.sigs
new file mode 100644
index 0000000..f6227db
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.38.sigs
@@ -0,0 +1,126 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.39.sigs b/lib/tevent/ABI/tevent-0.9.39.sigs
new file mode 100644
index 0000000..f6227db
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.39.sigs
@@ -0,0 +1,126 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/ABI/tevent-0.9.9.sigs b/lib/tevent/ABI/tevent-0.9.9.sigs
new file mode 100644
index 0000000..9adaba5
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.9.sigs
@@ -0,0 +1,73 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/Makefile b/lib/tevent/Makefile
new file mode 100644
index 0000000..6a3aab0
--- /dev/null
+++ b/lib/tevent/Makefile
@@ -0,0 +1,52 @@
+# simple makefile wrapper to run waf
+WAF_BIN=`PATH=buildtools/bin:../../buildtools/bin:$$PATH which waf`
+WAF_BINARY=$(PYTHON) $(WAF_BIN)
+WAF=PYTHONHASHSEED=1 WAF_MAKE=1 $(WAF_BINARY)
+
+all:
+ $(WAF) build
+
+install:
+ $(WAF) install
+
+uninstall:
+ $(WAF) uninstall
+
+test:
+ $(WAF) test $(TEST_OPTIONS)
+
+dist:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) dist
+
+distcheck:
+ touch .tmplock
+ WAFLOCK=.tmplock $(WAF) distcheck
+
+clean:
+ $(WAF) clean
+
+distclean:
+ $(WAF) distclean
+
+reconfigure: configure
+ $(WAF) reconfigure
+
+show_waf_options:
+ $(WAF) --help
+
+# some compatibility make targets
+everything: all
+
+testsuite: all
+
+check: test
+
+# this should do an install as well, once install is finished
+installcheck: test
+
+etags:
+ $(WAF) etags
+
+ctags:
+ $(WAF) ctags
diff --git a/lib/tevent/bindings.py b/lib/tevent/bindings.py
new file mode 100644
index 0000000..f5e1499
--- /dev/null
+++ b/lib/tevent/bindings.py
@@ -0,0 +1,116 @@
+#!/usr/bin/python
+#
+# Python integration for tevent - tests
+#
+# Copyright (C) Jelmer Vernooij 2010
+#
+# ** NOTE! The following LGPL license applies to the tevent
+# ** library. This does NOT imply that all of Samba is released
+# ** under the LGPL
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+import signal
+from unittest import TestCase, TestProgram
+import gc
+
+import _tevent
+
+
+class BackendListTests(TestCase):
+
+ def test_backend_list(self):
+ self.assertTrue(isinstance(_tevent.backend_list(), list))
+
+
+class CreateContextTests(TestCase):
+
+ def test_by_name(self):
+ ctx = _tevent.Context(_tevent.backend_list()[0])
+ self.assertTrue(ctx is not None)
+
+ def test_no_name(self):
+ ctx = _tevent.Context()
+ self.assertTrue(ctx is not None)
+
+
+class ContextTests(TestCase):
+
+ def setUp(self):
+ super(ContextTests, self).setUp()
+ self.ctx = _tevent.Context()
+
+ def test_signal_support(self):
+ self.assertTrue(type(self.ctx.signal_support) is bool)
+
+ def test_reinitialise(self):
+ self.ctx.reinitialise()
+
+ def test_loop_wait(self):
+ self.ctx.loop_wait()
+
+ def test_add_signal(self):
+ sig = self.ctx.add_signal(signal.SIGINT, 0, lambda callback: None)
+ self.assertTrue(isinstance(sig, _tevent.Signal))
+
+ def test_timer(self):
+ """Test a timer is can be scheduled"""
+ collecting_list = []
+ # time "0" has already passed, callback will be scheduled immediately
+ timer = self.ctx.add_timer(0, lambda t: collecting_list.append(True))
+ self.assertTrue(timer.active)
+ self.assertEqual(collecting_list, [])
+ self.ctx.loop_once()
+ self.assertFalse(timer.active)
+ self.assertEqual(collecting_list, [True])
+
+ def test_timer_deallocate_timer(self):
+ """Test timer is scheduled even if reference to it isn't held"""
+ collecting_list = []
+
+ def callback(t):
+ collecting_list.append(True)
+ timer = self.ctx.add_timer(0, lambda t: collecting_list.append(True))
+ gc.collect()
+ self.assertEqual(collecting_list, [])
+ self.ctx.loop_once()
+ self.assertEqual(collecting_list, [True])
+
+ def test_timer_deallocate_context(self):
+ """Test timer is unscheduled when context is freed"""
+ collecting_list = []
+
+ def callback(t):
+ collecting_list.append(True)
+ timer = self.ctx.add_timer(0, lambda t: collecting_list.append(True))
+ self.assertTrue(timer.active)
+ del self.ctx
+ gc.collect()
+ self.assertEqual(collecting_list, [])
+ self.assertFalse(timer.active)
+
+ def test_timer_offset(self):
+ """Test scheduling timer with an offset"""
+ collecting_list = []
+ self.ctx.add_timer_offset(0.2, lambda t: collecting_list.append(2))
+ self.ctx.add_timer_offset(0.1, lambda t: collecting_list.append(1))
+ self.assertEqual(collecting_list, [])
+ self.ctx.loop_once()
+ self.assertEqual(collecting_list, [1])
+ self.ctx.loop_once()
+ self.assertEqual(collecting_list, [1, 2])
+
+
+if __name__ == '__main__':
+ TestProgram()
diff --git a/lib/tevent/configure b/lib/tevent/configure
new file mode 100755
index 0000000..7b972bd
--- /dev/null
+++ b/lib/tevent/configure
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PREVPATH=$(dirname $0)
+
+if [ -f $PREVPATH/../../buildtools/bin/waf ]; then
+ WAF=../../buildtools/bin/waf
+elif [ -f $PREVPATH/buildtools/bin/waf ]; then
+ WAF=./buildtools/bin/waf
+else
+ echo "tevent: Unable to find waf"
+ exit 1
+fi
+
+# using JOBS=1 gives maximum compatibility with
+# systems like AIX which have broken threading in python
+JOBS=1
+export JOBS
+
+# Make sure we don't have any library preloaded.
+unset LD_PRELOAD
+
+# Make sure we get stable hashes
+PYTHONHASHSEED=1
+export PYTHONHASHSEED
+
+cd . || exit 1
+$PYTHON $WAF configure "$@" || exit 1
+cd $PREVPATH
diff --git a/lib/tevent/doc/img/tevent_context_stucture.png b/lib/tevent/doc/img/tevent_context_stucture.png
new file mode 100644
index 0000000..fba8161
--- /dev/null
+++ b/lib/tevent/doc/img/tevent_context_stucture.png
Binary files differ
diff --git a/lib/tevent/doc/img/tevent_subrequest.png b/lib/tevent/doc/img/tevent_subrequest.png
new file mode 100644
index 0000000..ea79223
--- /dev/null
+++ b/lib/tevent/doc/img/tevent_subrequest.png
Binary files differ
diff --git a/lib/tevent/doc/mainpage.dox b/lib/tevent/doc/mainpage.dox
new file mode 100644
index 0000000..5b76013
--- /dev/null
+++ b/lib/tevent/doc/mainpage.dox
@@ -0,0 +1,47 @@
+/**
+ * @mainpage
+ *
+ * Tevent is an event system based on the talloc memory management library. It
+ * is the core event system used in Samba.
+ *
+ * The low level tevent has support for many event types, including timers,
+ * signals, and the classic file descriptor events.
+ *
+ * Tevent also provide helpers to deal with asynchronous code providing the
+ * tevent_req (tevent request) functions.
+ *
+ * @section main_tevent_tutorial Tutorial
+ *
+ * You should start by reading @subpage tevent_tutorial, then reading the
+ * documentation of the interesting functions as you go.
+ *
+ * @section main_tevent_download Download
+ *
+ * You can download the latest releases of tevent from the
+ * <a href="http://samba.org/ftp/tevent" target="_blank">tevent directory</a>
+ * on the samba public source archive.
+ *
+ * @section main_tevent_bugs Discussion and bug reports
+ *
+ * tevent does not currently have its own mailing list or bug tracking system.
+ * For now, please use the
+ * <a href="https://lists.samba.org/mailman/listinfo/samba-technical" target="_blank">samba-technical</a>
+ * mailing list, and the
+ * <a href="http://bugzilla.samba.org/" target="_blank">Samba bugzilla</a>
+ * bug tracking system.
+ *
+ * @section main_tevent_devel Development
+ * You can download the latest code either via git or rsync.
+ *
+ * To fetch via git see the following guide:
+ *
+ * <a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development" target="_blank">Using Git for Samba Development</a>
+ *
+ * Once you have cloned the tree switch to the master branch and cd into the
+ * lib/tevent directory.
+ *
+ * To fetch via rsync use this command:
+ *
+ * rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/tevent .
+ *
+ */
diff --git a/lib/tevent/doc/tevent_context.dox b/lib/tevent/doc/tevent_context.dox
new file mode 100644
index 0000000..39eb85e
--- /dev/null
+++ b/lib/tevent/doc/tevent_context.dox
@@ -0,0 +1,75 @@
+/**
+@page tevent_context Chapter 1: Tevent context
+
+@section context Tevent context
+
+Tevent context is an essential logical unit of tevent library. For working with
+events at least one such context has to be created - allocated, initialized.
+Then, events which are meant to be caught and handled have to be registered
+within this specific context. Reason for subordinating events to a tevent
+context structure rises from the fact that several context can be created and
+each of them is processed at different time. So, there can be 1 context
+containing just file descriptor events, another one taking care of signal and
+time events and the third one which keeps information about the rest.
+
+Tevent loops are the part of the library which represents the mechanism where
+noticing events and triggering handlers actually happens. They accept just one
+argument - tevent context structure. Therefore if theoretically an infinity
+loop (tevent_loop_wait) was called, only those arguments which belong to the
+passed tevent context structure can be caught and invoked within this call.
+Although some more signal events were registered (but within some other
+context) they will not be noticed.
+
+@subsection Example
+
+First lines which handle <code>mem_ctx</code> belong to talloc library
+knowledge but because of the fact that tevent uses the talloc library for its
+mechanisms it is necessary to understand a bit talloc as well. For more
+information about working with talloc, please visit <a
+href="http://talloc.samba.org/">talloc website</a> where tutorial and
+documentation are located.
+
+Tevent context structure <code>*event_ctx</code> represents the unit which will
+further contain information about registered events. It is created via calling
+tevent_context_init().
+
+@code
+TALLOC_CTX *mem_ctx = talloc_new(NULL);
+if (mem_ctx == NULL) {
+ // error handling
+}
+
+struct tevent_context *ev_ctx = tevent_context_init(mem_ctx);
+if(ev_ctx == NULL) {
+ // error handling
+}
+@endcode
+
+Tevent context has a structure containing lots of information. It include lists
+of all events which are divided according their type and are in order showing
+the sequence as they came.
+
+@image html tevent_context_stucture.png
+
+In addition to the lists shown in the diagram, the tevent context also contains
+many other data (e.g. information about the available system mechanism for
+triggering callbacks).
+
+@section tevent_loops Tevent loops
+
+Tevent loops are the dispatcher for events. They catch them and trigger the
+handlers. In the case of longer processes, the program spends most of its time
+at this point waiting for events, invoking handlers and waiting for another
+event again. There are 2 types of loop available for use in tevent library:
+
+<ul>
+<li>int tevent_loop_wait()</li>
+<li>int tevent_loop_once()</li>
+</ul>
+
+Both of functions accept just one parameter (tevent context) and the only
+difference lies in the fact that the first loop can theoretically last for ever
+but the second one will wait just for a single one event to catch and then the
+loop breaks and the program continue.
+
+*/
diff --git a/lib/tevent/doc/tevent_data.dox b/lib/tevent/doc/tevent_data.dox
new file mode 100644
index 0000000..dbe7a04
--- /dev/null
+++ b/lib/tevent/doc/tevent_data.dox
@@ -0,0 +1,137 @@
+/**
+@page tevent_data Chapter 3: Accessing data
+@section data Accessing data with tevent
+
+A tevent request is (usually) created together with a structure for storing the
+data necessary for an asynchronous computation. For these private data, tevent
+library uses void (generic) pointers, therefore any data type can be very
+simply pointed at. However, this attitude requires clear and guaranteed
+knowledge of the data type that will be handled, in advance. Private data can
+be of 2 types: connected with a request itself or given as an individual
+argument to a callback. It is necessary to differentiate these types, because
+there is a slightly different method of data access for each. There are two
+possibilities how to access data that is given as an argument directly to a
+callback. The difference lies in the pointer that is returned. In one case it
+is the data type specified in the function’s argument, in another void* is
+returned.
+
+@code
+void tevent_req_callback_data (struct tevent_req *req, #type)
+void tevent_req_callback_data_void (struct tevent_req *req)
+@endcode
+
+
+To obtain data that are strictly bound to a request, this function is the only
+direct procedure.
+
+@code
+void *tevent_req_data (struct tevent_req *req, #type)
+@endcode
+
+Example with both calls which differs between private data within tevent
+request and data handed over as an argument.
+
+@code
+#include <stdio.h>
+#include <unistd.h>
+#include <tevent.h>
+
+struct foo_state {
+ int x;
+};
+
+struct testA {
+ int y;
+};
+
+
+static void foo_done(struct tevent_req *req) {
+ // a->x contains 10 since it came from foo_send
+ struct foo_state *a = tevent_req_data(req, struct foo_state);
+
+ // b->y contains 9 since it came from run
+ struct testA *b = tevent_req_callback_data(req, struct testA);
+
+ // c->y contains 9 since it came from run we just used a different way
+ // of getting it.
+ struct testA *c = (struct testA *)tevent_req_callback_data_void(req);
+
+ printf("a->x: %d\n", a->x);
+ printf("b->y: %d\n", b->y);
+ printf("c->y: %d\n", c->y);
+}
+
+
+struct tevent_req * foo_send(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx) {
+
+printf("_send\n");
+struct tevent_req *req;
+struct foo_state *state;
+
+req = tevent_req_create(event_ctx, &state, struct foo_state);
+state->x = 10;
+
+return req;
+}
+
+static void run(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval current_time, void *private_data) {
+ struct tevent_req *req;
+ struct testA *tmp = talloc(ev, struct testA);
+
+ // Note that we did not use the private data passed in
+
+ tmp->y = 9;
+ req = foo_send(ev, ev);
+
+ tevent_req_set_callback(req, foo_done, tmp);
+ tevent_req_done(req);
+
+}
+
+int main (int argc, char **argv) {
+
+ struct tevent_context *event_ctx;
+ struct testA *data;
+ TALLOC_CTX *mem_ctx;
+ struct tevent_timer *time_event;
+
+ mem_ctx = talloc_new(NULL); //parent
+ if (mem_ctx == NULL)
+ return EXIT_FAILURE;
+
+ event_ctx = tevent_context_init(mem_ctx);
+ if (event_ctx == NULL)
+ return EXIT_FAILURE;
+
+ data = talloc(mem_ctx, struct testA);
+ data->y = 11;
+
+ time_event = tevent_add_timer(event_ctx,
+ mem_ctx,
+ tevent_timeval_current(),
+ run,
+ data);
+ if (time_event == NULL) {
+ fprintf(stderr, " FAILED\n");
+ return EXIT_FAILURE;
+ }
+
+ tevent_loop_once(event_ctx);
+
+ talloc_free(mem_ctx);
+
+ printf("Quit\n");
+ return EXIT_SUCCESS;
+}
+@endcode
+
+Output of this example is:
+
+@code
+a->x: 10
+b->y: 9
+c->y: 9
+@endcode
+
+*/
diff --git a/lib/tevent/doc/tevent_events.dox b/lib/tevent/doc/tevent_events.dox
new file mode 100644
index 0000000..94fed9c
--- /dev/null
+++ b/lib/tevent/doc/tevent_events.dox
@@ -0,0 +1,341 @@
+/**
+@page tevent_events Chapter 2: Tevent events
+@section pools Tevent events
+
+Ok, after reading previous chapter we can start doing something useful. So, the
+way of creating events is similar for all types - signals, file descriptors,
+time or immediate events. At the beginning it is good to know about some
+typedefs which are set in tevent library and which specify the arguments for
+each callback. These callbacks are:
+
+- tevent_timer_handler_t()
+
+- tevent_immediate_handler_t()
+
+- tevent_signal_handler_t()
+
+- tevent_fd_handler_t()
+
+According their names it is obvious that for creating callback for e.g. time
+event, tevent_timer_handler_t will be used.
+
+The best way how to introduce registering an event and setting up a callback
+would be example, so examples describing all the types of events follow.
+
+@subsection Time Time event
+
+This example shows how to set up an event which will be repeated for a minute
+with interval of 2 seconds (will be triggered 30 times). After exceeding this
+limit, the event loop will finish and all the memory resources will be freed.
+This is just example describing repeated activity, nothing useful is done
+within foo function
+
+@code
+#include <stdio.h>
+#include <unistd.h>
+#include <tevent.h>
+#include <sys/time.h>
+
+struct state {
+ struct timeval endtime;
+ int counter;
+ TALLOC_CTX *ctx;
+};
+
+static void callback(struct tevent_context *ev, struct tevent_timer *tim,
+ struct timeval current_time, void *private_data)
+{
+ struct state *data = talloc_get_type_abort(private_data, struct state);
+ struct tevent_timer *time_event;
+ struct timeval schedule;
+
+ printf("Data value: %d\n", data->counter);
+ data->counter += 1; // increase counter
+
+ // if time has not reached its limit, set another event
+ if (tevent_timeval_compare(&current_time, &(data->endtime)) < 0) {
+ // do something
+ // set repeat with delay 2 seconds
+ schedule = tevent_timeval_current_ofs(2, 0);
+ time_event = tevent_add_timer(ev, data->ctx, schedule, callback, data);
+ if (time_event == NULL) { // error ...
+ fprintf(stderr, "MEMORY PROBLEM\n");
+ return;
+ }
+ } else {
+ // time limit exceeded
+ }
+}
+
+int main(void) {
+ struct tevent_context *event_ctx;
+ TALLOC_CTX *mem_ctx;
+ struct tevent_timer *time_event;
+ struct timeval schedule;
+
+ mem_ctx = talloc_new(NULL); // parent
+ event_ctx = tevent_context_init(mem_ctx);
+
+ struct state *data = talloc(mem_ctx, struct state);
+
+ schedule = tevent_timeval_current_ofs(2, 0); // +2 second time value
+ data->endtime = tevent_timeval_add(&schedule, 60, 0); // one minute time limit
+ data->ctx = mem_ctx;
+ data->counter = 0;
+
+ // add time event
+ time_event = tevent_add_timer(event_ctx, mem_ctx, schedule, callback, data);
+ if (time_event == NULL) {
+ fprintf(stderr, "FAILED\n");
+ return EXIT_FAILURE;
+ }
+
+ tevent_loop_wait(event_ctx);
+ talloc_free(mem_ctx);
+ return EXIT_SUCCESS;
+}
+@endcode
+
+Variable <code>counter</code> is only used for counting the number of triggered
+functions. List of all available functions which tevent offers for working with
+time are listed
+<a href="http://tevent.samba.org/group__tevent__helpers.html">here</a> together
+with their description. More detailed view at these functions is unnecessary
+because their purpose and usage is quite simple and clear.
+
+@subsection Immediate Immediate event
+
+These events are, as their name indicates, activated and performed immediately.
+It means that this kind of events have priority over others (except signal
+events). So if there is a bulk of events registered and after that a
+tevent loop is launched, then all the immediate events will be triggered before
+the other events. Except other immediate events (and signal events) because
+they are also processed sequentially - according the order they were scheduled.
+Signals have the highest priority and therefore they are processed
+preferentially. Therefore the expression immediate may not correspond exactly
+to the dictionary definition of "something without delay" but rather "as soon
+as possible" after all preceding immediate events.
+
+For creating an immediate event there is a small different which lies in the
+fact that the creation of such event is done in 2 steps. One represents the
+creation (memory allocation), the second one represents registering as the
+event within some tevent context.
+
+@code
+struct tevent_immediate *run(TALLOC_CTX* mem_ctx,
+ struct tevent_context event_ctx,
+ void * data)
+{
+ struct tevent_immediate *im;
+
+ im = tevent_create_immediate(mem_ctx);
+ if (im == NULL) {
+ return NULL;
+ }
+ tevent_schedule_immediate(im, event_ctx, foo, data);
+
+ return im;
+}
+@endcode
+
+Example which may be compiled and run representing the creation of immediate event.
+
+@code
+
+#include <stdio.h>
+#include <unistd.h>
+#include <tevent.h>
+
+struct info_struct {
+ int counter;
+};
+
+static void foo(struct tevent_context *ev, struct tevent_immediate *im,
+ void *private_data)
+{
+ struct info_struct *data = talloc_get_type_abort(private_data, struct info_struct);
+ printf("Data value: %d\n", data->counter);
+}
+
+int main (void) {
+ struct tevent_context *event_ctx;
+ TALLOC_CTX *mem_ctx;
+ struct tevent_immediate *im;
+
+ printf("INIT\n");
+
+ mem_ctx = talloc_new(NULL);
+ event_ctx = tevent_context_init(mem_ctx);
+
+ struct info_struct *data = talloc(mem_ctx, struct info_struct);
+
+ // setting up private data
+ data->counter = 1;
+
+ // first immediate event
+ im = tevent_create_immediate(mem_ctx);
+ if (im == NULL) {
+ fprintf(stderr, "FAILED\n");
+ return EXIT_FAILURE;
+ }
+ tevent_schedule_immediate(im, event_ctx, foo, data);
+
+ tevent_loop_wait(event_ctx);
+ talloc_free(mem_ctx);
+
+ return 0;
+}
+@endcode
+
+@subsection Signal Signal event
+
+This is an alternative to standard C library functions signal() or sigaction().
+The main difference that distinguishes these ways of treating signals is their
+setting up of handlers for different time intervals of the running program.
+
+While standard C library methods for dealing with signals offer sufficient
+tools for most cases, they are inadequate for handling signals within the
+tevent loop. It could be necessary to finish certain tevent requests within the
+tevent loop without interruption. If a signal was sent to a program at a moment
+when the tevent loop is in progress, a standard signal handler would not return
+processing to the application at the very same place and it would quit the
+tevent loop for ever. In such cases, tevent signal handlers offer the
+possibility of dealing with these signals by masking them from the rest of
+application and not quitting the loop, so the other events can still be
+processed.
+
+Tevent offers also a control function, which enables us to verify whether it is
+possible to handle signals via tevent, is defined within tevent library and it
+returns a boolean value revealing the result of the verification.
+
+@code
+bool tevent_signal_support (struct tevent_context *ev)
+@endcode
+
+Checking for signal support is not necessary, but if it is not guaranteed, this
+is a good and easy control to prevent unexpected behaviour or failure of the
+program occurring. Such a test of course does not have to be run every single
+time you wish to create a signal handler, but simply at the beginning - during
+the initialization procedures of the program. Afterthat, simply adapt to each
+situation that arises.
+
+@code
+
+#include <stdio.h>
+#include <tevent.h>
+#include <signal.h>
+
+static void handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+
+ // Do something useful
+
+ printf("handling signal...\n");
+ exit(EXIT_SUCCESS);
+}
+
+int main (void)
+{
+ struct tevent_context *event_ctx;
+ TALLOC_CTX *mem_ctx;
+ struct tevent_signal *sig;
+
+ mem_ctx = talloc_new(NULL); //parent
+ if (mem_ctx == NULL) {
+ fprintf(stderr, "FAILED\n");
+ return EXIT_FAILURE;
+ }
+
+ event_ctx = tevent_context_init(mem_ctx);
+ if (event_ctx == NULL) {
+ fprintf(stderr, "FAILED\n");
+ return EXIT_FAILURE;
+ }
+
+ if (tevent_signal_support(event_ctx)) {
+ // create signal event
+ sig = tevent_add_signal(event_ctx, mem_ctx, SIGINT, 0, handler, NULL);
+ if (sig == NULL) {
+ fprintf(stderr, "FAILED\n");
+ return EXIT_FAILURE;
+ }
+ tevent_loop_wait(event_ctx);
+ }
+
+ talloc_free(mem_ctx);
+ return EXIT_SUCCESS;
+}
+@endcode
+
+
+@subsection File File descriptor event
+
+Support of events on file descriptors is mainly useful for socket communication
+but it certainly works flawlessly with standard streams (stdin, stdout, stderr)
+ as well. Working asynchronously with file descriptors enables switching
+ within processing I/O operations. This ability may rise with a greater
+ number of I/O operations and such overlapping leads to enhancement of the
+ throughput.
+
+There are several other functions included in tevent API related to handling
+file descriptors (there are too many functions defined within tevent therefore
+just some of them are fully described within this thesis. The
+declaration of the rest can be easily found on the library’s website or
+directly from the source code):
+
+<ul>
+<li>tevent_fd_set_close_fn() - can add another function to be called at the
+ moment when a structure tevent fd is freed.</li>
+<li>tevent_fd_set_auto_close() - calling this function can simplify the
+ maintenance of file descriptors, because it instructs tevent to close the
+ appropriate file descriptor when the tevent fd structure is about to be
+ freed.</li>
+<li>tevent_fd_get_flags() - returns flags which are set on the file descriptor
+ connected with this tevent fd structure.</li>
+<li>tevent_fd_set_flags() - sets specified flags on the event’s file
+ descriptor.</li>
+</ul>
+
+@code
+
+static void close_fd(struct tevent_context *ev, struct tevent_fd *fd_event,
+ int fd, void *private_data)
+{
+ // processing when fd_event is freed
+}
+
+struct static void handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ // handling event; reading from a file descriptor
+ tevent_fd_set_close_fn (fd_event, close_fd);
+}
+
+int run(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx,
+ int fd, uint16_t flags, char *buffer)
+{
+ struct tevent_fd* fd_event = NULL;
+
+ if (flags & TEVENT_FD_READ) {
+ fd_event = tevent_add_fd(event_ctx,
+ mem_ctx,
+ fd,
+ flags,
+ handler,
+ buffer);
+ }
+ if (fd_event == NULL) {
+ // error handling
+ }
+ return tevent_loop_once();
+}
+@endcode
+
+*/
diff --git a/lib/tevent/doc/tevent_queue.dox b/lib/tevent/doc/tevent_queue.dox
new file mode 100644
index 0000000..c1d629c
--- /dev/null
+++ b/lib/tevent/doc/tevent_queue.dox
@@ -0,0 +1,275 @@
+/**
+@page tevent_queue Chapter 5: Tevent queue
+@section queue Tevent queue
+
+There is a possibility that the dispatcher and its handlers may not be able to
+handle all the incoming events as quickly as they arrive. One way to deal with
+this situation is to buffer the received events by introducing an event queue
+into the events stream, between the events generator and the dispatcher. Events
+are added to the queue as they arrive, and the dispatcher pops them off the
+beginning of the queue as fast as possible. In tevent library it is
+similar, but the queue is not automatically set for any event. The queue has to
+be created on purpose, and events which should follow the order of the FIFO
+queue have to be explicitly pinpointed. Creating such a queue is crucial in
+situations when sequential processing is absolutely essential for the
+successful
+completion of a task, e.g. for a large quantity of data that are about to be
+written from a buffer into a socket. The tevent library has its own queue
+structure that is ready to use after it has been initialized and started up
+once.
+
+@subsection cr_queue Creation of Queues
+
+The first and most important step is the creation of the tevent queue
+(represented by struct tevent_queue), which will then be in running mode.
+
+@code
+struct tevent_queue* tevent_queue_create (TALLOC_CTX *mem_ctx, const char *name)
+@endcode
+
+When the program returns from this function, the allocated memory, set
+destructor and labeled queue as running has been done and the structure is
+ready to be filled with entries. Stopping and starting queues on the run. If
+you need to stop a queue from processing its entries, and then turn it on
+again, a couple of functions which serve this purpose are:
+
+- bool tevent_queue_stop()
+- bool tevent_queue_start()
+
+These functions actually only provide for the simple setting of a variable,
+which indicates that the queue has been stopped/started. Returned value
+indicates result.
+
+@subsection add_queue Adding Requests to a Queue
+
+Tevent in fact offers 3 possible ways of inserting a request into a queue.
+There are no vast differences between them, but still there might be situations
+where one of them is more suitable and desired than another.
+
+@code
+bool tevent_queue_add(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data)
+@endcode
+
+This call is the simplest of all three. It offers only boolean verification of
+whether the operation of adding the request into a queue was successful or not.
+No additional deletion of an item from the queue is possible, i.e. it is only
+possible to deallocate the whole tevent request, which would cause triggering
+of destructor handling and also dropping the request from the queue.
+
+<strong>Extended Options</strong>
+
+Both of the following functions have a feature in common - they return tevent
+queue entry structure representing the item in a queue. There is no further
+possible handling with this structure except the use of the structure’s pointer
+for its deallocation (which leads also its removal from the queue). The
+difference lies in the possibility that with the following functions it is
+possible to remove the tevent request from a queue without its deallocation.
+The previous function can only deallocate the tevent request as it was from
+memory, and thereby logically cause its removal from the queue as well. There
+is no other utilization of this structure via API at this stage of tevent
+library. The possibility of easier debugging while developing with tevent could
+be considered to be an advantage of this returned pointer.
+
+@code
+struct tevent_queue_entry *tevent_queue_add_entry(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data)
+@endcode
+
+The feature that allows for the optimized addition of entries to a queue is
+that a check for an empty queue with no items is first of all carried out. If
+it is found that the queue is empty, then the request for inserting the entry
+into a queue will be omitted and directly triggered.
+
+@code
+struct tevent_queue_entry *tevent_queue_add_optimize_empty(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data)
+@endcode
+
+When calling any of the functions serving for inserting an item into a queue,
+it is possible to leave out the fourth argument (trigger) and instead of a
+function pass a NULL pointer. This usage sets so-called blocking entries.
+These entries, since they do not have any trigger operation to be activated,
+just sit in their position until they are labeled as a done by another
+function. Their purpose is to block other items in the queue from being
+triggered.
+
+@subsection example_q Example of tevent queue
+
+@code
+#include <stdio.h>
+#include <unistd.h>
+#include <tevent.h>
+
+struct foo_state {
+ int local_var;
+ int x;
+};
+
+struct juststruct {
+ TALLOC_CTX * ctx;
+ struct tevent_context *ev;
+ int y;
+};
+
+int created = 0;
+
+static void timer_handler(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval current_time, void *private_data)
+{
+ // time event which after all sets request as done. Following item from
+ // the queue may be invoked.
+ struct tevent_req *req = private_data;
+ struct foo_state *stateX = tevent_req_data(req, struct foo_state);
+
+ // processing some stuff
+
+ printf("time_handler\n");
+
+ tevent_req_done(req);
+ talloc_free(req);
+
+ printf("Request #%d set as done.\n", stateX->x);
+}
+
+static void trigger(struct tevent_req *req, void *private_data)
+{
+ struct juststruct *priv = tevent_req_callback_data (req, struct juststruct);
+ struct foo_state *in = tevent_req_data(req, struct foo_state);
+ struct timeval schedule;
+ struct tevent_timer *tim;
+ schedule = tevent_timeval_current_ofs(1, 0);
+ printf("Processing request #%d\n", in->x);
+
+ if (in->x % 3 == 0) { // just example; third request does not contain
+ // any further operation and will be finished right
+ // away.
+ tim = NULL;
+ } else {
+ tim = tevent_add_timer(priv->ev, req, schedule, timer_handler, req);
+ }
+
+ if (tim == NULL) {
+ tevent_req_done(req);
+ talloc_free(req);
+ printf("Request #%d set as done.\n", in->x);
+ }
+}
+
+struct tevent_req *foo_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ const char *name, int num)
+{
+ struct tevent_req *req;
+ struct foo_state *state;
+ struct foo_state *in;
+ struct tevent_timer *tim;
+
+ printf("foo_send\n");
+ req = tevent_req_create(mem_ctx, &state, struct foo_state);
+ if (req == NULL) { // check for appropriate allocation
+ tevent_req_error(req, 1);
+ return NULL;
+ }
+
+ // exemplary filling of variables
+ state->local_var = 1;
+ state->x = num;
+
+ return req;
+}
+
+static void foo_done(struct tevent_req *req) {
+
+ enum tevent_req_state state;
+ uint64_t err;
+
+ if (tevent_req_is_error(req, &state, &err)) {
+ printf("ERROR WAS SET %d\n", state);
+ return;
+ } else {
+ // processing some stuff
+ printf("Callback is done...\n");
+ }
+}
+
+int main (int argc, char **argv)
+{
+ TALLOC_CTX *mem_ctx;
+ struct tevent_req* req[6];
+ struct tevent_req* tmp;
+ struct tevent_context *ev;
+ struct tevent_queue *fronta = NULL;
+ struct juststruct *data;
+ int ret;
+ int i = 0;
+
+ const char * const names[] = {
+ "first", "second", "third", "fourth", "fifth"
+ };
+
+ printf("INIT\n");
+
+ mem_ctx = talloc_new(NULL); //parent
+ talloc_parent(mem_ctx);
+ ev = tevent_context_init(mem_ctx);
+ if (ev == NULL) {
+ fprintf(stderr, "MEMORY ERROR\n");
+ return EXIT_FAILURE;
+ }
+
+ // setting up queue
+ fronta = tevent_queue_create(mem_ctx, "test_queue");
+ tevent_queue_stop(fronta);
+ tevent_queue_start(fronta);
+ if (tevent_queue_running(fronta)) {
+ printf ("Queue is running (length: %d)\n", tevent_queue_length(fronta));
+ } else {
+ printf ("Queue is not running\n");
+ }
+
+ data = talloc(ev, struct juststruct);
+ data->ctx = mem_ctx;
+ data->ev = ev;
+
+
+ // create 4 requests
+ for (i = 1; i < 5; i++) {
+ req[i] = foo_send(mem_ctx, ev, names[i], i);
+ tmp = req[i];
+ if (req[i] == NULL) {
+ fprintf(stderr, "Request error! %d \n", ret);
+ break;
+ }
+ tevent_req_set_callback(req[i], foo_done, data);
+ created++;
+ }
+
+ // add item to a queue
+ tevent_queue_add(fronta, ev, req[1], trigger, data);
+ tevent_queue_add(fronta, ev, req[2], trigger, data);
+ tevent_queue_add(fronta, ev, req[3], trigger, data);
+ tevent_queue_add(fronta, ev, req[4], trigger, data);
+
+ printf("Queue length: %d\n", tevent_queue_length(fronta));
+ while(tevent_queue_length(fronta) > 0) {
+ tevent_loop_once(ev);
+ printf("Queue: %d items left\n", tevent_queue_length(fronta));
+ }
+
+ talloc_free(mem_ctx);
+ printf("FINISH\n");
+
+ return EXIT_SUCCESS;
+}
+@endcode
+
+*/
diff --git a/lib/tevent/doc/tevent_request.dox b/lib/tevent/doc/tevent_request.dox
new file mode 100644
index 0000000..bda6f76
--- /dev/null
+++ b/lib/tevent/doc/tevent_request.dox
@@ -0,0 +1,189 @@
+/**
+@page tevent_request Chapter 4: Tevent request
+@section request Tevent request
+
+A specific feature of the library is the tevent request API that provides for
+asynchronous computation and allows much more interconnected working and
+cooperation among functions and events. When working with tevent request it
+is possible to nest one event under another and handle them bit by bit. This
+enables the creation of sequences of steps, and provides an opportunity to
+prepare for all problems which may unexpectedly happen within the different
+phases. One way or another, subrequests split bigger tasks into smaller ones
+which allow a clearer view of each task as a whole.
+
+@subsection name Naming conventions
+
+There is a naming convention which is not obligatory but it is followed in this
+tutorial:
+
+- Functions triggered before the event happens. These establish a request.
+- \b foo_send(...) - this function is called first and it includes the
+ creation of tevent request - tevent req structure. It does not block
+ anything, it simply creates a request, sets a callback (foo done) and lets
+ the program continue
+- Functions as a result of event.
+- \b foo_done(...) - this function contains code providing for handling itself
+ and based upon its results, the request is set either as a done or, if an
+ error occurs, the request is set as a failure.
+- \b foo_recv(...) - this function contains code which should, if demanded,
+ access the result data and make them further visible. The foo state should
+ be deallocated from memory when the request’s processing is over and
+ therefore all computed data up to this point would be lost.
+
+As was already mentioned, specific naming subsumes not only functions but also
+the data themselves:
+
+- \b foo_state - this is a structure. It contains all the data necessary for
+ the asynchronous task.
+
+@subsection cr_req Creating a New Asynchronous Request
+
+The first step for working asynchronously is the allocation of memory
+requirements. As in previous cases, the talloc context is required, upon which
+the asynchronous request will be tied. The next step is the creation of the
+request itself.
+
+@code
+struct tevent_req* tevent_req_create (TALLOC_CTX *mem_ctx, void **pstate, #type)
+@endcode
+
+The pstate is the pointer to the private data. The necessary amount of memory
+(based on data type) is allocated during this call. Within this same memory
+area all the data from the asynchronous request that need to be preserved for
+some time should be kept.
+
+<b>Dealing with a lack of memory</b>
+
+The verification of the returned pointer against NULL is necessary in order to
+identify a potential lack of memory. There is a special function which helps
+with this check tevent_req_nomem().
+
+It handles verification both of the talloc memory allocation and of the
+associated tevent request, and is therefore a very useful function for avoiding
+unexpected situations. It can easily be used when checking the availability of
+further memory resources that are required for a tevent request. Imagine an
+example where additional memory needs arise although no memory resources are
+currently available.
+
+@code
+bar = talloc(mem_ctx, struct foo);
+if(tevent_req_nomem (bar, req)) {
+ // handling a problem
+}
+@endcode
+
+This code ensures that the variable bar, which contains NULL as a result of the
+unsuccessful satisfaction of its memory requirements, is noticed, and also that
+the tevent request req declares it exceeds memory capacity, which implies the
+impossibility of finishing the request as originally programmed.
+
+
+@subsection fini_req Finishing a Request
+
+Marking each request as finished is an essential principle of the tevent
+library. Without marking the request as completed - either successfully or with
+an error - the tevent loop could not let the appropriate callback be triggered.
+It is important to understand that this would be a significant threat, because
+it is not usually a question of one single function which prints some text on a
+screen, but rather the request is itself probably just a link in a series of
+other requests. Stopping one request would stop the others, memory resources
+would not be freed, file descriptors might remain open, communication via
+socket could be interrupted, and so on. Therefore it is important to think
+about finishing requests, either successfully or not, and also to prepare
+functions for all possible scenarios, so that the the callbacks do not process
+data that are actually invalid or, even worse, in fact non-existent meaning
+that a segmentation fault may arise.
+
+<ul>
+<li>\b Manually - This is the most common type of finishing request. Calling
+this function sets the request as a TEVENT_REQ_DONE. This is the only purpose
+of this function and it should be used when everything went well. Typically it
+is used within the done functions.
+
+@code
+void tevent_req_done (struct tevent_req *req)
+@endcode
+Alternatively, the request can end up being unsuccessful.
+@code
+bool tevent_req_error (struct tevent_req *req, uint64_t error)
+@endcode
+
+The second argument takes the number of an error (declared by the programmer,
+for example in an enumerated variable). The function tevent_req_error() sets
+the status of the request as a TEVENT_REQ_USER_ERROR and also stores the code
+of error within the structure so it can be used, for example for debugging. The
+function returns true, if marking the request as an error was processed with no
+problem - value error passed to this function is not equal to 1.</li>
+
+<li>
+<b>Setting up a timeout for request</b> - A request can be finished virtually,
+or if the process takes too much time, it can be timed out. This is considered
+as an error of the request and it leads to calling callback. In the
+background, this timeout is set through a time event (described in
+@subpage tevent_events ) which eventually triggers an operation marking the
+request as a TEVENT_REQ_TIMED_OUT (can not be considered as successfully
+finished). In case a time out was already set, this operation will overwrite it
+with a new time value (so the timeout may be lengthened) and if everything is
+set properly, it returns true.
+
+@code
+bool tevent_req_set_endtime(struct tevent_req *req,
+ struct tevent_context *ev,
+ struct timeval endtime);
+@endcode
+</li>
+
+
+<li><b>Premature Triggering</b> - Imagine a situation in which some part of a
+nested subrequest ended up with a failure and it is still required to trigger a
+callback. Such as example might result from lack of memory leading to the
+impossibility of allocating enough memory requirements for the event to start
+processing another subrequest, or from a clear intention to skip other
+procedures and trigger the callback regardless of other progress. In these
+cases, the function tevent_req_post() is very handy and offers this option.
+
+@code
+struct tevent_req* tevent_req_post (struct tevent_req *req,
+ struct tevent_context *ev);
+@endcode
+
+A request finished in this way does not behave as a time event nor as a file
+descriptor event but as a immediately scheduled event, and therefore it will be
+treated according the description laid down in @subpage tevent_events .
+</li>
+</ul>
+
+
+@section nested Subrequests - Nested Requests
+
+To create more complex and interconnected asynchronous operations, it is
+possible to submerge a request into another and thus create a so-called
+subrequest. Subrequests are not represented by any other special structure but
+they are created from tevent_req_create(). This diagram shows the nesting and
+life time of each request. The table below describes the same in words, and
+shows the triggering of functions during the application run.
+
+<i>Wrapper</i> represents the trigger of the whole cascade of (sub)requests. It
+may be e.g. a time or file descriptor event, or another request that was
+created at a specific time by the function tevent_wakeup_send() which is a
+slightly exceptional method of creating
+
+@code
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval wakeup_time);
+@endcode
+
+By calling this function, it is possible to create a tevent request which is
+actually the return value of this function. In summary, it sets the time value
+of the tevent request’s creation. While using this function it is necessary to
+use another function in the subrequest’s callback to check for any problems
+tevent_wakeup_recv() )
+
+@image html tevent_subrequest.png
+
+A comprehensive example of nested subrequests can be found in the file
+echo_server.c. It implements a complete, self-contained echo server with no
+dependencies but libtevent and libtalloc.
+
+*/
diff --git a/lib/tevent/doc/tevent_thread.dox b/lib/tevent/doc/tevent_thread.dox
new file mode 100644
index 0000000..875dae8
--- /dev/null
+++ b/lib/tevent/doc/tevent_thread.dox
@@ -0,0 +1,322 @@
+/**
+@page tevent_thread Chapter 6: Tevent with threads
+
+@section threads Tevent with threads
+
+In order to use tevent with threads, you must first understand
+how to use the talloc library in threaded programs. For more
+information about working with talloc, please visit <a
+href="https://talloc.samba.org/">talloc website</a> where tutorial and
+documentation are located.
+
+If a tevent context structure is talloced from a NULL, thread-safe talloc
+context, then it can be safe to use in a threaded program. The function
+<code>talloc_disable_null_tracking()</code> <b>must</b> be called from the initial
+program thread before any talloc calls are made to ensure talloc is thread-safe.
+
+Each thread must create it's own tevent context structure as follows
+<code>tevent_context_init(NULL)</code> and no talloc memory contexts
+can be shared between threads.
+
+Separate threads using tevent in this way can communicate
+by writing data into file descriptors that are being monitored
+by a tevent context on another thread. For example (simplified
+with no error handling):
+
+@code
+Main thread:
+
+main()
+{
+ talloc_disable_null_tracking();
+
+ struct tevent_context *master_ev = tevent_context_init(NULL);
+ void *mem_ctx = talloc_new(master_ev);
+
+ // Create file descriptor to monitor.
+ int pipefds[2];
+
+ pipe(pipefds);
+
+ struct tevent_fd *fde = tevent_add_fd(master_ev,
+ mem_ctx,
+ pipefds[0], // read side of pipe
+ TEVENT_FD_READ,
+ pipe_read_handler, // callback function
+ private_data_pointer);
+
+ // Create sub thread, pass pipefds[1] write side of pipe to it.
+ // The above code not shown here..
+
+ // Process events.
+ tevent_loop_wait(master_ev);
+
+ // Cleanup if loop exits.
+ talloc_free(master_ev);
+}
+
+@endcode
+
+When the subthread writes to pipefds[1], the function
+<code>pipe_read_handler()</code> will be called in the main thread.
+
+@subsection More sophisticated use
+
+A popular way to use an event library within threaded programs
+is to allow a sub-thread to asynchronously schedule a tevent_immediate
+function call from the event loop of another thread. This can be built
+out of the basic functions and isolation mechanisms of tevent,
+but tevent also comes with some utility functions that make
+this easier, so long as you understand the limitations that
+using threads with talloc and tevent impose.
+
+To allow a tevent context to receive an asynchronous tevent_immediate
+function callback from another thread, create a struct tevent_thread_proxy *
+by calling @code
+
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+ struct tevent_context *dest_ev_ctx);
+
+@endcode
+
+This function allocates the internal data structures to
+allow asynchronous callbacks as a talloc child of the
+struct tevent_context *, and returns a struct tevent_thread_proxy *
+that can be passed to another thread.
+
+When you have finished receiving asynchronous callbacks, simply
+talloc_free the struct tevent_thread_proxy *, or talloc_free
+the struct tevent_context *, which will deallocate the resources
+used.
+
+To schedule an asynchronous tevent_immediate function call from one
+thread on the tevent loop of another thread, use
+@code
+
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+ struct tevent_immediate **pp_im,
+ tevent_immediate_handler_t handler,
+ void **pp_private_data);
+
+@endcode
+
+This function causes the function <code>handler()</code>
+to be invoked as a tevent_immediate callback from the event loop
+of the thread that created the struct tevent_thread_proxy *
+(so the owning <code>struct tevent_context *</code> should be
+long-lived and not in the process of being torn down).
+
+The <code>struct tevent_thread_proxy</code> object being
+used here is a child of the event context of the target
+thread. So external synchronization mechanisms must be
+used to ensure that the target object is still in use
+at the time of the <code>tevent_thread_proxy_schedule()</code>
+call. In the example below, the request/response nature
+of the communication ensures this.
+
+The <code>struct tevent_immediate **pp_im</code> passed into this function
+should be a struct tevent_immediate * allocated on a talloc context
+local to this thread, and will be reparented via talloc_move
+to be owned by <code>struct tevent_thread_proxy *tp</code>.
+<code>*pp_im</code> will be set to NULL on successful scheduling
+of the tevent_immediate call.
+
+<code>handler()</code> will be called as a normal tevent_immediate
+callback from the <code>struct tevent_context *</code> of the destination
+event loop that created the <code>struct tevent_thread_proxy *</code>
+
+Returning from this functions does not mean that the <code>handler</code>
+has been invoked, merely that it has been scheduled to be called in the
+destination event loop.
+
+Because the calling thread does not wait for the
+callback to be scheduled and run on the destination
+thread, this is a fire-and-forget call. If you wish
+confirmation of the <code>handler()</code> being
+successfully invoked, you must ensure it replies to the
+caller in some way.
+
+Because of asynchronous nature of this call, the nature
+of the parameter passed to the destination thread has some
+restructions. If you don't need parameters, merely pass
+<code>NULL</code> as the value of
+<code>void **pp_private_data</code>.
+
+If you wish to pass a pointer to data between the threads,
+it <b>MUST</b> be a pointer to a talloced pointer, which is
+not part of a talloc-pool, and it must not have a destructor
+attached. The ownership of the memory pointed to will
+be passed from the calling thread to the tevent library,
+and if the receiving thread does not talloc-reparent
+it to its own contexts, it will be freed once the
+<code>handler</code> is called.
+
+On success, <code>*pp_private</code> will be <code>NULL</code>
+to signify the talloc memory ownership has been moved.
+
+In practice for message passing between threads in
+event loops these restrictions are not very onerous.
+
+The easiest way to to a request-reply pair between
+tevent loops on different threads is to pass the
+parameter block of memory back and forth using
+a reply <code>tevent_thread_proxy_schedule()</code>
+call.
+
+Here is an example (without error checking for
+simplicity):
+
+@code
+------------------------------------------------
+// Master thread.
+
+main()
+{
+ // Make talloc thread-safe.
+
+ talloc_disable_null_tracking();
+
+ // Create the master event context.
+
+ struct tevent_context *master_ev = tevent_context_init(NULL);
+
+ // Create the master thread proxy to allow it to receive
+ // async callbacks from other threads.
+
+ struct tevent_thread_proxy *master_tp =
+ tevent_thread_proxy_create(master_ev);
+
+ // Create sub-threads, passing master_tp in
+ // some way to them.
+ // This code not shown..
+
+ // Process events.
+ // Function master_callback() below
+ // will be invoked on this thread on
+ // master_ev event context.
+
+ tevent_loop_wait(master_ev);
+
+ // Cleanup if loop exits.
+
+ talloc_free(master_ev);
+}
+
+// Data passed between threads.
+struct reply_state {
+ struct tevent_thread_proxy *reply_tp;
+ pthread_t thread_id;
+ bool *p_finished;
+};
+
+// Callback Called in child thread context.
+
+static void thread_callback(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_ptr)
+{
+ // Move the ownership of what private_ptr
+ // points to from the tevent library back to this thread.
+
+ struct reply_state *rsp =
+ talloc_get_type_abort(private_ptr, struct reply_state);
+
+ talloc_steal(ev, rsp);
+
+ *rsp->p_finished = true;
+
+ // im will be talloc_freed on return from this call.
+ // but rsp will not.
+}
+
+// Callback Called in master thread context.
+
+static void master_callback(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_ptr)
+{
+ // Move the ownership of what private_ptr
+ // points to from the tevent library to this thread.
+
+ struct reply_state *rsp =
+ talloc_get_type_abort(private_ptr, struct reply_state);
+
+ talloc_steal(ev, rsp);
+
+ printf("Callback from thread %s\n", thread_id_to_string(rsp->thread_id));
+
+ /* Now reply to the thread ! */
+ tevent_thread_proxy_schedule(rsp->reply_tp,
+ &im,
+ thread_callback,
+ &rsp);
+
+ // Note - rsp and im are now NULL as the tevent library
+ // owns the memory.
+}
+
+// Child thread.
+
+static void *thread_fn(void *private_ptr)
+{
+ struct tevent_thread_proxy *master_tp =
+ talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+ bool finished = false;
+ int ret;
+
+ // Create our own event context.
+
+ struct tevent_context *ev = tevent_context_init(NULL);
+
+ // Create the local thread proxy to allow us to receive
+ // async callbacks from other threads.
+
+ struct tevent_thread_proxy *local_tp =
+ tevent_thread_proxy_create(master_ev);
+
+ // Setup the data to send.
+
+ struct reply_state *rsp = talloc(ev, struct reply_state);
+
+ rsp->reply_tp = local_tp;
+ rsp->thread_id = pthread_self();
+ rsp->p_finished = &finished;
+
+ // Create the immediate event to use.
+
+ struct tevent_immediate *im = tevent_create_immediate(ev);
+
+ // Call the master thread.
+
+ tevent_thread_proxy_schedule(master_tp,
+ &im,
+ master_callback,
+ &rsp);
+
+ // Note - rsp and im are now NULL as the tevent library
+ // owns the memory.
+
+ // Wait for the reply.
+
+ while (!finished) {
+ tevent_loop_once(ev);
+ }
+
+ // Cleanup.
+
+ talloc_free(ev);
+ return NULL;
+}
+
+@endcode
+
+Note this doesn't have to be a master-subthread communication.
+Any thread that has access to the <code>struct tevent_thread_proxy *</code>
+pointer of another thread that has called <code>tevent_thread_proxy_create()
+</code> can send an async tevent_immediate request.
+
+But remember the caveat that external synchronization must be used
+to ensure the target <code>struct tevent_thread_proxy *</code> object
+exists at the time of the <code>tevent_thread_proxy_schedule()</code>
+call or unreproducible crashes will result.
+*/
diff --git a/lib/tevent/doc/tevent_tutorial.dox b/lib/tevent/doc/tevent_tutorial.dox
new file mode 100644
index 0000000..207a244
--- /dev/null
+++ b/lib/tevent/doc/tevent_tutorial.dox
@@ -0,0 +1,22 @@
+/**
+@page tevent_tutorial The Tutorial
+
+@section tevent_tutorial_introduction Introduction
+
+Tutorial describing working with tevent library.
+
+@section tevent_tutorial_toc Table of contents
+
+@subpage tevent_context
+
+@subpage tevent_events
+
+@subpage tevent_data
+
+@subpage tevent_request
+
+@subpage tevent_queue
+
+@subpage tevent_thread
+
+*/
diff --git a/lib/tevent/doc/tutorials.dox b/lib/tevent/doc/tutorials.dox
new file mode 100644
index 0000000..e8beed7
--- /dev/null
+++ b/lib/tevent/doc/tutorials.dox
@@ -0,0 +1,43 @@
+/**
+ * @page tevent_queue_tutorial The tevent_queue tutorial
+ *
+ * @section Introduction
+ *
+ * A tevent_queue is used to queue up async requests that must be
+ * serialized. For example writing buffers into a socket must be
+ * serialized. Writing a large lump of data into a socket can require
+ * multiple write(2) or send(2) system calls. If more than one async
+ * request is outstanding to write large buffers into a socket, every
+ * request must individually be completed before the next one begins,
+ * even if multiple syscalls are required.
+ *
+ * To do this, every socket gets assigned a tevent_queue struct.
+ *
+ * Creating a serialized async request follows the usual convention to
+ * return a tevent_req structure with an embedded state structure. To
+ * serialize the work the requests is about to so, instead of directly
+ * starting or doing that work, tevent_queue_add must be called. When it
+ * is time for the serialized async request to do its work, the trigger
+ * callback function tevent_queue_add was given is called. In the example
+ * of writing to a socket, the trigger is called when the write request
+ * can begin accessing the socket.
+ *
+ * How does this engine work behind the scenes? When the queue is empty,
+ * tevent_queue_add schedules an immediate call to the trigger
+ * callback. The trigger callback starts its work, likely by starting
+ * other async subrequests. While these async subrequests are working,
+ * more requests can accumulate in the queue by tevent_queue_add. While
+ * there is no function to explicitly trigger the next waiter in line, it
+ * still works: When the active request in the queue is done, it will be
+ * destroyed by talloc_free. Talloc_free of an serialized async request
+ * that had been added to a queue will trigger the next request in the
+ * queue via a talloc destructor attached to a child of the serialized
+ * request. This way the queue will be kept busy when an async request
+ * finishes.
+ *
+ * @section Example
+ *
+ * @code
+ * Metze: Please add a code example here.
+ * @endcode
+ */
diff --git a/lib/tevent/doxy.config b/lib/tevent/doxy.config
new file mode 100644
index 0000000..dbb40c5
--- /dev/null
+++ b/lib/tevent/doxy.config
@@ -0,0 +1,1908 @@
+# Doxyfile 1.8.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed
+# in front of the TAG it is preceding .
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = tevent
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.9.8
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian,
+# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic,
+# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields or simple typedef fields will be shown
+# inline in the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO (the default), structs, classes, and unions are shown on a separate
+# page (for HTML and Man pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can
+# be an expensive process and often the same symbol appear multiple times in
+# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too
+# small doxygen will become slower. If the cache is too large, memory is wasted.
+# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid
+# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536
+# symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = . \
+ doc
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS = *.cpp \
+ *.cc \
+ *.c \
+ *.h \
+ *.hh \
+ *.hpp \
+ *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */.git/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = doc/img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be ignored.
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefore more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
+# pieces of code that will be used on startup of the MathJax code.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search
+# engine library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4 will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images
+# or other source files which should be copied to the LaTeX output directory.
+# Note that the files will be copied as-is; there are no commands or markers
+# available.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files
+# that can be used to generate PDF.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it. If left blank docbook will be used as the default path.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN \
+ PRINTF_ATTRIBUTE(x,y)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed
+# in the related pages index. If set to NO, only the current project's
+# pages will be listed.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# manageable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/lib/tevent/echo_server.c b/lib/tevent/echo_server.c
new file mode 100644
index 0000000..f93d8bc
--- /dev/null
+++ b/lib/tevent/echo_server.c
@@ -0,0 +1,667 @@
+/**
+ ** NOTE! The following liberal license applies to this sample file only.
+ ** This does NOT imply that all of Samba is released under this license.
+ **
+ ** This file is meant as a starting point for libtevent users to be used
+ ** in any program linking against the LGPL licensed libtevent.
+ **/
+
+/*
+ * This file is being made available by the Samba Team under the following
+ * license:
+ *
+ * Permission to use, copy, modify, and distribute this sample file for any
+ * purpose is hereby granted without fee.
+ *
+ * This work is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+#include "tevent.h"
+#include "talloc.h"
+
+/**
+ * @brief Helper function to get a useful unix error from tevent_req
+ */
+
+static bool tevent_req_is_unix_error(struct tevent_req *req, int *perrno)
+{
+ enum tevent_req_state state;
+ uint64_t err;
+
+ if (!tevent_req_is_error(req, &state, &err)) {
+ return false;
+ }
+ switch (state) {
+ case TEVENT_REQ_TIMED_OUT:
+ *perrno = ETIMEDOUT;
+ break;
+ case TEVENT_REQ_NO_MEMORY:
+ *perrno = ENOMEM;
+ break;
+ case TEVENT_REQ_USER_ERROR:
+ *perrno = err;
+ break;
+ default:
+ *perrno = EINVAL;
+ break;
+ }
+ return true;
+}
+
+/**
+ * @brief Wrapper around accept(2)
+ */
+
+struct accept_state {
+ struct tevent_fd *fde;
+ int listen_sock;
+ socklen_t addrlen;
+ struct sockaddr_storage addr;
+ int sock;
+};
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data);
+
+static struct tevent_req *accept_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int listen_sock)
+{
+ struct tevent_req *req;
+ struct accept_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct accept_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->listen_sock = listen_sock;
+
+ state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
+ accept_handler, req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ private_data, struct tevent_req);
+ struct accept_state *state = tevent_req_data(req, struct accept_state);
+ int ret;
+
+ TALLOC_FREE(state->fde);
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+ state->addrlen = sizeof(state->addr);
+
+ ret = accept(state->listen_sock,
+ (struct sockaddr *)&state->addr,
+ &state->addrlen);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ smb_set_close_on_exec(ret);
+ state->sock = ret;
+ tevent_req_done(req);
+}
+
+static int accept_recv(struct tevent_req *req, struct sockaddr *paddr,
+ socklen_t *paddrlen, int *perr)
+{
+ struct accept_state *state = tevent_req_data(req, struct accept_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ if (perr != NULL) {
+ *perr = err;
+ }
+ return -1;
+ }
+ if (paddr != NULL) {
+ memcpy(paddr, &state->addr, state->addrlen);
+ }
+ if (paddrlen != NULL) {
+ *paddrlen = state->addrlen;
+ }
+ return state->sock;
+}
+
+/**
+ * @brief Wrapper around read(2)
+ */
+
+struct read_state {
+ struct tevent_fd *fde;
+ int fd;
+ void *buf;
+ size_t count;
+
+ ssize_t nread;
+};
+
+static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data);
+
+static struct tevent_req *read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd, void *buf, size_t count)
+{
+ struct tevent_req *req;
+ struct read_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->fd = fd;
+ state->buf = buf;
+ state->count = count;
+
+ state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
+ read_handler, req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void read_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ private_data, struct tevent_req);
+ struct read_state *state = tevent_req_data(req, struct read_state);
+ ssize_t ret;
+
+ TALLOC_FREE(state->fde);
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ ret = read(state->fd, state->buf, state->count);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ state->nread = ret;
+ tevent_req_done(req);
+}
+
+static ssize_t read_recv(struct tevent_req *req, int *perr)
+{
+ struct read_state *state = tevent_req_data(req, struct read_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ if (perr != NULL) {
+ *perr = err;
+ }
+ return -1;
+ }
+ return state->nread;
+}
+
+/**
+ * @brief Wrapper around write(2)
+ */
+
+struct write_state {
+ struct tevent_fd *fde;
+ int fd;
+ const void *buf;
+ size_t count;
+
+ ssize_t nwritten;
+};
+
+static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data);
+
+static struct tevent_req *write_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd, const void *buf, size_t count)
+{
+ struct tevent_req *req;
+ struct write_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct write_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->fd = fd;
+ state->buf = buf;
+ state->count = count;
+
+ state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE,
+ write_handler, req);
+ if (tevent_req_nomem(state->fde, req)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void write_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ private_data, struct tevent_req);
+ struct write_state *state = tevent_req_data(req, struct write_state);
+ ssize_t ret;
+
+ TALLOC_FREE(state->fde);
+
+ if ((flags & TEVENT_FD_WRITE) == 0) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ ret = write(state->fd, state->buf, state->count);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ state->nwritten = ret;
+ tevent_req_done(req);
+}
+
+static ssize_t write_recv(struct tevent_req *req, int *perr)
+{
+ struct write_state *state = tevent_req_data(req, struct write_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ if (perr != NULL) {
+ *perr = err;
+ }
+ return -1;
+ }
+ return state->nwritten;
+}
+
+/**
+ * @brief Wrapper function that deals with short writes
+ */
+
+struct writeall_state {
+ struct tevent_context *ev;
+ int fd;
+ const void *buf;
+ size_t count;
+ size_t nwritten;
+};
+
+static void writeall_done(struct tevent_req *subreq);
+
+static struct tevent_req *writeall_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd, const void *buf, size_t count)
+{
+ struct tevent_req *req, *subreq;
+ struct writeall_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct writeall_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->fd = fd;
+ state->buf = buf;
+ state->count = count;
+ state->nwritten = 0;
+
+ subreq = write_send(state, state->ev, state->fd,
+ ((char *)state->buf)+state->nwritten,
+ state->count - state->nwritten);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, writeall_done, req);
+ return req;
+}
+
+static void writeall_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct writeall_state *state = tevent_req_data(
+ req, struct writeall_state);
+ ssize_t nwritten;
+ int err = 0;
+
+ nwritten = write_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ state->nwritten += nwritten;
+
+ if (state->nwritten < state->count) {
+ subreq = write_send(state, state->ev, state->fd,
+ ((char *)state->buf)+state->nwritten,
+ state->count - state->nwritten);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, writeall_done, req);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static ssize_t writeall_recv(struct tevent_req *req, int *perr)
+{
+ struct writeall_state *state = tevent_req_data(
+ req, struct writeall_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ if (perr != NULL) {
+ *perr = err;
+ }
+ return -1;
+ }
+ return state->nwritten;
+}
+
+/**
+ * @brief Async echo handler code dealing with one client
+ */
+
+struct echo_state {
+ struct tevent_context *ev;
+ int fd;
+ uint8_t *buf;
+};
+
+static int echo_state_destructor(struct echo_state *s);
+static void echo_read_done(struct tevent_req *subreq);
+static void echo_writeall_done(struct tevent_req *subreq);
+
+static struct tevent_req *echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd, size_t bufsize)
+{
+ struct tevent_req *req, *subreq;
+ struct echo_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct echo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->fd = fd;
+
+ talloc_set_destructor(state, echo_state_destructor);
+
+ state->buf = talloc_array(state, uint8_t, bufsize);
+ if (tevent_req_nomem(state->buf, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = read_send(state, state->ev, state->fd,
+ state->buf, talloc_get_size(state->buf));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, echo_read_done, req);
+ return req;
+}
+
+static int echo_state_destructor(struct echo_state *s)
+{
+ if (s->fd != -1) {
+ printf("Closing client fd %d\n", s->fd);
+ close(s->fd);
+ s->fd = -1;
+ }
+ return 0;
+}
+
+static void echo_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct echo_state *state = tevent_req_data(
+ req, struct echo_state);
+ ssize_t nread;
+ int err;
+
+ nread = read_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nread == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+ if (nread == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ subreq = writeall_send(state, state->ev, state->fd, state->buf, nread);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, echo_writeall_done, req);
+}
+
+static void echo_writeall_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct echo_state *state = tevent_req_data(
+ req, struct echo_state);
+ ssize_t nwritten;
+ int err;
+
+ nwritten = writeall_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ if (err == EPIPE) {
+ tevent_req_done(req);
+ return;
+ }
+ tevent_req_error(req, err);
+ return;
+ }
+
+ subreq = read_send(state, state->ev, state->fd,
+ state->buf, talloc_get_size(state->buf));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, echo_read_done, req);
+}
+
+static bool echo_recv(struct tevent_req *req, int *perr)
+{
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ *perr = err;
+ return false;
+ }
+ return true;
+}
+
+/**
+ * @brief Full echo handler code accepting and handling clients
+ */
+
+struct echo_server_state {
+ struct tevent_context *ev;
+ int listen_sock;
+};
+
+static void echo_server_accepted(struct tevent_req *subreq);
+static void echo_server_client_done(struct tevent_req *subreq);
+
+static struct tevent_req *echo_server_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int listen_sock)
+{
+ struct tevent_req *req, *subreq;
+ struct echo_server_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct echo_server_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->listen_sock = listen_sock;
+
+ subreq = accept_send(state, state->ev, state->listen_sock);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, echo_server_accepted, req);
+ return req;
+}
+
+static void echo_server_accepted(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct echo_server_state *state = tevent_req_data(
+ req, struct echo_server_state);
+ int sock, err;
+
+ sock = accept_recv(subreq, NULL, NULL, &err);
+ TALLOC_FREE(subreq);
+ if (sock == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ printf("new client fd %d\n", sock);
+
+ subreq = echo_send(state, state->ev, sock, 100);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, echo_server_client_done, req);
+
+ subreq = accept_send(state, state->ev, state->listen_sock);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, echo_server_accepted, req);
+}
+
+static void echo_server_client_done(struct tevent_req *subreq)
+{
+ bool ret;
+ int err;
+
+ ret = echo_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+
+ if (ret) {
+ printf("Client done\n");
+ } else {
+ printf("Client failed: %s\n", strerror(err));
+ }
+}
+
+static bool echo_server_recv(struct tevent_req *req, int *perr)
+{
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ *perr = err;
+ return false;
+ }
+ return true;
+}
+
+int main(int argc, const char **argv)
+{
+ int ret, port, listen_sock, err;
+ struct tevent_context *ev;
+ struct sockaddr_in addr;
+ struct tevent_req *req;
+ bool result;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <port>\n", argv[0]);
+ exit(1);
+ }
+
+ port = atoi(argv[1]);
+
+ printf("listening on port %d\n", port);
+
+ listen_sock = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (listen_sock == -1) {
+ perror("socket() failed");
+ exit(1);
+ }
+
+ addr = (struct sockaddr_in) {
+ .sin_family = AF_INET,
+ .sin_port = htons(port)
+ };
+
+ ret = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret == -1) {
+ perror("bind() failed");
+ exit(1);
+ }
+
+ ret = listen(listen_sock, 5);
+ if (ret == -1) {
+ perror("listen() failed");
+ exit(1);
+ }
+
+ ev = tevent_context_init(NULL);
+ if (ev == NULL) {
+ fprintf(stderr, "tevent_context_init failed\n");
+ exit(1);
+ }
+
+ req = echo_server_send(ev, ev, listen_sock);
+ if (req == NULL) {
+ fprintf(stderr, "echo_server_send failed\n");
+ exit(1);
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ perror("tevent_req_poll() failed");
+ exit(1);
+ }
+
+ result = echo_server_recv(req, &err);
+ TALLOC_FREE(req);
+ if (!result) {
+ fprintf(stderr, "echo_server failed: %s\n", strerror(err));
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/lib/tevent/pytevent.c b/lib/tevent/pytevent.c
new file mode 100644
index 0000000..bbe29f6
--- /dev/null
+++ b/lib/tevent/pytevent.c
@@ -0,0 +1,798 @@
+/*
+ Unix SMB/CIFS implementation.
+ Python bindings for tevent
+
+ Copyright (C) Jelmer Vernooij 2010
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "lib/replace/system/python.h"
+#include "replace.h"
+#include <tevent.h>
+
+
+/* discard signature of 'func' in favour of 'target_sig' */
+#define PY_DISCARD_FUNC_SIG(target_sig, func) (target_sig)(void(*)(void))func
+
+void init_tevent(void);
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_context *ev;
+} TeventContext_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_queue *queue;
+} TeventQueue_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_req *req;
+} TeventReq_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_signal *signal;
+} TeventSignal_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_timer *timer;
+ PyObject *callback;
+} TeventTimer_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_fd *fd;
+} TeventFd_Object;
+
+static PyTypeObject TeventContext_Type;
+static PyTypeObject TeventReq_Type;
+static PyTypeObject TeventQueue_Type;
+static PyTypeObject TeventSignal_Type;
+static PyTypeObject TeventTimer_Type;
+static PyTypeObject TeventFd_Type;
+
+static PyObject *py_tevent_context_reinitialise(TeventContext_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret = tevent_re_initialise(self->ev);
+ if (ret != 0) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_queue_stop(TeventQueue_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ tevent_queue_stop(self->queue);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_queue_start(TeventQueue_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ tevent_queue_start(self->queue);
+ Py_RETURN_NONE;
+}
+
+static void py_queue_trigger(struct tevent_req *req, void *private_data)
+{
+ PyObject *callback = private_data, *ret;
+
+ ret = PyObject_CallFunction(callback, discard_const_p(char, ""));
+ Py_XDECREF(ret);
+}
+
+static PyObject *py_tevent_queue_add(TeventQueue_Object *self, PyObject *args)
+{
+ TeventContext_Object *py_ev;
+ TeventReq_Object *py_req;
+ PyObject *trigger;
+ bool ret;
+
+ if (!PyArg_ParseTuple(args, "O!O!O",
+ &TeventContext_Type, &py_ev,
+ &TeventReq_Type, &py_req,
+ &trigger))
+ return NULL;
+
+ Py_INCREF(trigger);
+
+ ret = tevent_queue_add(self->queue, py_ev->ev, py_req->req,
+ py_queue_trigger, trigger);
+ if (!ret) {
+ PyErr_SetString(PyExc_RuntimeError, "queue add failed");
+ Py_DECREF(trigger);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_tevent_queue_methods[] = {
+ { "stop", (PyCFunction)py_tevent_queue_stop,
+ METH_NOARGS,
+ "S.stop()" },
+ { "start", (PyCFunction)py_tevent_queue_start,
+ METH_NOARGS,
+ "S.start()" },
+ { "add", (PyCFunction)py_tevent_queue_add, METH_VARARGS,
+ "S.add(ctx, req, trigger, baton)" },
+ {0},
+};
+
+static PyObject *py_tevent_context_wakeup_send(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_context_loop_wait(TeventContext_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ if (tevent_loop_wait(self->ev) != 0) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_context_loop_once(TeventContext_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ if (tevent_loop_once(self->ev) != 0) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static void py_tevent_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ PyObject *callback = (PyObject *)private_data, *ret;
+
+ ret = PyObject_CallFunction(callback, discard_const_p(char, "ii"), signum, count);
+ Py_XDECREF(ret);
+}
+
+static void py_tevent_signal_dealloc(TeventSignal_Object *self)
+{
+ talloc_free(self->signal);
+ PyObject_Del(self);
+}
+
+static PyTypeObject TeventSignal_Type = {
+ .tp_name = "tevent.Signal",
+ .tp_basicsize = sizeof(TeventSignal_Object),
+ .tp_dealloc = (destructor)py_tevent_signal_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
+static PyObject *py_tevent_context_add_signal(TeventContext_Object *self, PyObject *args)
+{
+ int signum, sa_flags;
+ PyObject *handler;
+ struct tevent_signal *sig;
+ TeventSignal_Object *ret;
+
+ if (!PyArg_ParseTuple(args, "iiO", &signum, &sa_flags, &handler))
+ return NULL;
+
+ Py_INCREF(handler);
+ sig = tevent_add_signal(self->ev, NULL, signum, sa_flags,
+ py_tevent_signal_handler, handler);
+
+ ret = PyObject_New(TeventSignal_Object, &TeventSignal_Type);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(sig);
+ return NULL;
+ }
+
+ ret->signal = sig;
+
+ return (PyObject *)ret;
+}
+
+static void py_timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ TeventTimer_Object *self = private_data;
+ PyObject *ret;
+
+ ret = PyObject_CallFunction(self->callback, discard_const_p(char, "l"), te);
+ if (ret == NULL) {
+ /* No Python stack to propagate exception to; just print traceback */
+ PyErr_PrintEx(0);
+ }
+ Py_XDECREF(ret);
+}
+
+static void py_tevent_timer_dealloc(TeventTimer_Object *self)
+{
+ if (self->timer) {
+ talloc_free(self->timer);
+ }
+ Py_CLEAR(self->callback);
+ PyObject_Del(self);
+}
+
+static int py_tevent_timer_traverse(TeventTimer_Object *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->callback);
+ return 0;
+}
+
+static PyObject* py_tevent_timer_get_active(TeventTimer_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyBool_FromLong(self->timer != NULL);
+}
+
+struct PyGetSetDef py_tevent_timer_getset[] = {
+ {
+ .name = discard_const_p(char, "active"),
+ .get = (getter)py_tevent_timer_get_active,
+ .doc = discard_const_p(char, "true if the timer is scheduled to run"),
+ },
+ {0},
+};
+
+static PyTypeObject TeventTimer_Type = {
+ .tp_name = "tevent.Timer",
+ .tp_basicsize = sizeof(TeventTimer_Object),
+ .tp_dealloc = (destructor)py_tevent_timer_dealloc,
+ .tp_traverse = (traverseproc)py_tevent_timer_traverse,
+ .tp_getset = py_tevent_timer_getset,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
+struct TeventTimer_Object_ref {
+ TeventTimer_Object *obj;
+};
+
+static int TeventTimer_Object_ref_destructor(struct TeventTimer_Object_ref *ref)
+{
+ ref->obj->timer = NULL;
+ Py_CLEAR(ref->obj);
+ return 0;
+}
+
+static PyObject *py_tevent_context_add_timer_internal(TeventContext_Object *self,
+ struct timeval next_event,
+ PyObject *callback)
+{
+ /* Ownership notes:
+ *
+ * There are 5 pieces in play; two tevent contexts and 3 Python objects:
+ * - The tevent timer
+ * - The tevent context
+ * - The Python context -- "self"
+ * - The Python timer (TeventTimer_Object) -- "ret"
+ * - The Python callback function -- "callback"
+ *
+ * We only use the Python context for getting the tevent context,
+ * afterwards it can be destroyed.
+ *
+ * The tevent context owns the tevent timer.
+ *
+ * The tevent timer holds a reference to the Python timer, so the Python
+ * timer must always outlive the tevent timer.
+ * The Python timer has a pointer to the tevent timer; a destructor is
+ * used to set this to NULL when the tevent timer is deallocated.
+ *
+ * The tevent timer can be deallocated in these cases:
+ * 1) when the context is destroyed
+ * 2) after the event fires
+ * Posssibly, API might be added to cancel (free the tevent timer).
+ *
+ * The Python timer holds a reference to the callback.
+ */
+ TeventTimer_Object *ret;
+ struct TeventTimer_Object_ref *ref;
+
+ ret = PyObject_New(TeventTimer_Object, &TeventTimer_Type);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ Py_INCREF(callback);
+ ret->callback = callback;
+ ret->timer = tevent_add_timer(self->ev, NULL, next_event, py_timer_handler,
+ ret);
+ if (ret->timer == NULL) {
+ Py_DECREF(ret);
+ PyErr_SetString(PyExc_RuntimeError, "Could not initialize timer");
+ return NULL;
+ }
+ ref = talloc(ret->timer, struct TeventTimer_Object_ref);
+ if (ref == NULL) {
+ talloc_free(ret->timer);
+ Py_DECREF(ret);
+ PyErr_SetString(PyExc_RuntimeError, "Could not initialize timer");
+ return NULL;
+ }
+ Py_INCREF(ret);
+ ref->obj = ret;
+
+ talloc_set_destructor(ref, TeventTimer_Object_ref_destructor);
+
+ return (PyObject *)ret;
+}
+
+static PyObject *py_tevent_context_add_timer(TeventContext_Object *self, PyObject *args)
+{
+ struct timeval next_event;
+ PyObject *callback;
+ double secs, usecs;
+ if (!PyArg_ParseTuple(args, "dO", &secs, &callback)){
+ return NULL;
+ }
+ next_event.tv_sec = secs;
+ usecs = (secs - next_event.tv_sec) * 1000000.0;
+ next_event.tv_usec = usecs;
+ return py_tevent_context_add_timer_internal(self, next_event, callback);
+}
+
+static PyObject *py_tevent_context_add_timer_offset(TeventContext_Object *self, PyObject *args)
+{
+ struct timeval next_event;
+ double offset;
+ int seconds;
+ PyObject *callback;
+ if (!PyArg_ParseTuple(args, "dO", &offset, &callback))
+ return NULL;
+
+ seconds = offset;
+ offset -= seconds;
+ next_event = tevent_timeval_current_ofs(seconds, (int)(offset*1000000));
+ return py_tevent_context_add_timer_internal(self, next_event, callback);
+}
+
+static void py_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ PyObject *callback = private_data, *ret;
+
+ ret = PyObject_CallFunction(callback, discard_const_p(char, "i"), flags);
+ Py_XDECREF(ret);
+}
+
+static void py_tevent_fp_dealloc(TeventFd_Object *self)
+{
+ talloc_free(self->fd);
+ PyObject_Del(self);
+}
+
+static PyTypeObject TeventFd_Type = {
+ .tp_name = "tevent.Fd",
+ .tp_basicsize = sizeof(TeventFd_Object),
+ .tp_dealloc = (destructor)py_tevent_fp_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
+static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args)
+{
+ int fd, flags;
+ PyObject *handler;
+ struct tevent_fd *tfd;
+ TeventFd_Object *ret;
+
+ if (!PyArg_ParseTuple(args, "iiO", &fd, &flags, &handler))
+ return NULL;
+
+ tfd = tevent_add_fd(self->ev, NULL, fd, flags, py_fd_handler, handler);
+ if (tfd == NULL) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ ret = PyObject_New(TeventFd_Object, &TeventFd_Type);
+ if (ret == NULL) {
+ talloc_free(tfd);
+ return NULL;
+ }
+ ret->fd = tfd;
+
+ return (PyObject *)ret;
+}
+
+static PyMethodDef py_tevent_context_methods[] = {
+ { "reinitialise", (PyCFunction)py_tevent_context_reinitialise,
+ METH_NOARGS,
+ "S.reinitialise()" },
+ { "wakeup_send", (PyCFunction)py_tevent_context_wakeup_send,
+ METH_VARARGS, "S.wakeup_send(wakeup_time) -> req" },
+ { "loop_wait", (PyCFunction)py_tevent_context_loop_wait,
+ METH_NOARGS, "S.loop_wait()" },
+ { "loop_once", (PyCFunction)py_tevent_context_loop_once,
+ METH_NOARGS, "S.loop_once()" },
+ { "add_signal", (PyCFunction)py_tevent_context_add_signal,
+ METH_VARARGS, "S.add_signal(signum, sa_flags, handler) -> signal" },
+ { "add_timer", (PyCFunction)py_tevent_context_add_timer,
+ METH_VARARGS, "S.add_timer(next_event, handler) -> timer" },
+ { "add_timer_offset", (PyCFunction)py_tevent_context_add_timer_offset,
+ METH_VARARGS, "S.add_timer_offset(offset_seconds, handler) -> timer" },
+ { "add_fd", (PyCFunction)py_tevent_context_add_fd,
+ METH_VARARGS, "S.add_fd(fd, flags, handler) -> fd" },
+ {0},
+};
+
+static PyObject *py_tevent_req_wakeup_recv(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_received(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_is_error(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_poll(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_is_in_progress(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyGetSetDef py_tevent_req_getsetters[] = {
+ {
+ .name = discard_const_p(char, "in_progress"),
+ .get = (getter)py_tevent_req_is_in_progress,
+ .doc = discard_const_p(char, "Whether the request is in progress"),
+ },
+ {0}
+};
+
+static PyObject *py_tevent_req_post(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_set_error(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_done(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_notify_callback(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_set_endtime(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_cancel(TeventReq_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ if (!tevent_req_cancel(self->req)) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_tevent_req_methods[] = {
+ { "wakeup_recv", (PyCFunction)py_tevent_req_wakeup_recv,
+ METH_NOARGS,
+ "Wakeup received" },
+ { "received", (PyCFunction)py_tevent_req_received,
+ METH_NOARGS,
+ "Receive finished" },
+ { "is_error", (PyCFunction)py_tevent_req_is_error, METH_NOARGS,
+ "is_error() -> (error, state)" },
+ { "poll", (PyCFunction)py_tevent_req_poll, METH_VARARGS,
+ "poll(ctx)" },
+ { "post", (PyCFunction)py_tevent_req_post, METH_VARARGS,
+ "post(ctx) -> req" },
+ { "set_error", (PyCFunction)py_tevent_req_set_error, METH_VARARGS,
+ "set_error(error)" },
+ { "done", (PyCFunction)py_tevent_req_done, METH_NOARGS,
+ "done()" },
+ { "notify_callback", (PyCFunction)py_tevent_req_notify_callback,
+ METH_NOARGS, "notify_callback()" },
+ { "set_endtime", (PyCFunction)py_tevent_req_set_endtime,
+ METH_VARARGS, "set_endtime(ctx, endtime)" },
+ { "cancel", (PyCFunction)py_tevent_req_cancel,
+ METH_NOARGS, "cancel()" },
+ {0}
+};
+
+static void py_tevent_req_dealloc(TeventReq_Object *self)
+{
+ talloc_free(self->req);
+ PyObject_DEL(self);
+}
+
+static PyTypeObject TeventReq_Type = {
+ .tp_name = "tevent.Request",
+ .tp_basicsize = sizeof(TeventReq_Object),
+ .tp_methods = py_tevent_req_methods,
+ .tp_dealloc = (destructor)py_tevent_req_dealloc,
+ .tp_getset = py_tevent_req_getsetters,
+ /* FIXME: .tp_new = py_tevent_req_new, */
+};
+
+static PyObject *py_tevent_queue_get_length(TeventQueue_Object *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ return PyLong_FromLong(tevent_queue_length(self->queue));
+}
+
+static PyGetSetDef py_tevent_queue_getsetters[] = {
+ {
+ .name = discard_const_p(char, "length"),
+ .get = (getter)py_tevent_queue_get_length,
+ .doc = discard_const_p(char, "The number of elements in the queue."),
+ },
+ {0},
+};
+
+static void py_tevent_queue_dealloc(TeventQueue_Object *self)
+{
+ talloc_free(self->queue);
+ PyObject_Del(self);
+}
+
+static PyTypeObject TeventQueue_Type = {
+ .tp_name = "tevent.Queue",
+ .tp_basicsize = sizeof(TeventQueue_Object),
+ .tp_dealloc = (destructor)py_tevent_queue_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_getset = py_tevent_queue_getsetters,
+ .tp_methods = py_tevent_queue_methods,
+};
+
+static PyObject *py_tevent_context_signal_support(PyObject *_self,
+ PyObject *Py_UNUSED(ignored))
+{
+ TeventContext_Object *self = (TeventContext_Object *)_self;
+ return PyBool_FromLong(tevent_signal_support(self->ev));
+}
+
+static PyGetSetDef py_tevent_context_getsetters[] = {
+ {
+ .name = discard_const_p(char, "signal_support"),
+ .get = PY_DISCARD_FUNC_SIG(getter,
+ py_tevent_context_signal_support),
+ .doc = discard_const_p(char, "if this platform and tevent context support signal handling"),
+ },
+ {0}
+};
+
+static void py_tevent_context_dealloc(TeventContext_Object *self)
+{
+ talloc_free(self->ev);
+ PyObject_Del(self);
+}
+
+static PyObject *py_tevent_context_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ const char * const kwnames[] = { "name", NULL };
+ char *name = NULL;
+ struct tevent_context *ev;
+ TeventContext_Object *ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", discard_const_p(char *, kwnames), &name))
+ return NULL;
+
+ if (name == NULL) {
+ ev = tevent_context_init(NULL);
+ } else {
+ ev = tevent_context_init_byname(NULL, name);
+ }
+
+ if (ev == NULL) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ ret = PyObject_New(TeventContext_Object, type);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(ev);
+ return NULL;
+ }
+
+ ret->ev = ev;
+ return (PyObject *)ret;
+}
+
+static PyTypeObject TeventContext_Type = {
+ .tp_name = "tevent.Context",
+ .tp_new = py_tevent_context_new,
+ .tp_basicsize = sizeof(TeventContext_Object),
+ .tp_dealloc = (destructor)py_tevent_context_dealloc,
+ .tp_methods = py_tevent_context_methods,
+ .tp_getset = py_tevent_context_getsetters,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
+static PyObject *py_set_default_backend(PyObject *self, PyObject *args)
+{
+ char *backend_name;
+ if (!PyArg_ParseTuple(args, "s", &backend_name))
+ return NULL;
+
+ tevent_set_default_backend(backend_name);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_backend_list(PyObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ PyObject *ret = NULL;
+ PyObject *string = NULL;
+ int i, result;
+ const char **backends = NULL;
+
+ ret = PyList_New(0);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ backends = tevent_backend_list(NULL);
+ if (backends == NULL) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ goto err;
+ }
+ for (i = 0; backends[i]; i++) {
+ string = PyUnicode_FromString(backends[i]);
+ if (!string) {
+ goto err;
+ }
+ result = PyList_Append(ret, string);
+ if (result) {
+ goto err;
+ }
+ Py_DECREF(string);
+ string = NULL;
+ }
+
+ talloc_free(backends);
+
+ return ret;
+
+err:
+ Py_XDECREF(ret);
+ Py_XDECREF(string);
+ talloc_free(backends);
+ return NULL;
+}
+
+static PyMethodDef tevent_methods[] = {
+ { "set_default_backend", (PyCFunction)py_set_default_backend,
+ METH_VARARGS, "set_default_backend(backend)" },
+ { "backend_list", (PyCFunction)py_backend_list,
+ METH_NOARGS, "backend_list() -> list" },
+ {0},
+};
+
+#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "_tevent",
+ .m_doc = MODULE_DOC,
+ .m_size = -1,
+ .m_methods = tevent_methods,
+};
+
+PyObject * module_init(void);
+PyObject * module_init(void)
+{
+ PyObject *m;
+
+ if (PyType_Ready(&TeventContext_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&TeventQueue_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&TeventReq_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&TeventSignal_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&TeventTimer_Type) < 0)
+ return NULL;
+
+ if (PyType_Ready(&TeventFd_Type) < 0)
+ return NULL;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ Py_INCREF(&TeventContext_Type);
+ PyModule_AddObject(m, "Context", (PyObject *)&TeventContext_Type);
+
+ Py_INCREF(&TeventQueue_Type);
+ PyModule_AddObject(m, "Queue", (PyObject *)&TeventQueue_Type);
+
+ Py_INCREF(&TeventReq_Type);
+ PyModule_AddObject(m, "Request", (PyObject *)&TeventReq_Type);
+
+ Py_INCREF(&TeventSignal_Type);
+ PyModule_AddObject(m, "Signal", (PyObject *)&TeventSignal_Type);
+
+ Py_INCREF(&TeventTimer_Type);
+ PyModule_AddObject(m, "Timer", (PyObject *)&TeventTimer_Type);
+
+ Py_INCREF(&TeventFd_Type);
+ PyModule_AddObject(m, "Fd", (PyObject *)&TeventFd_Type);
+
+ PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
+
+ return m;
+}
+
+PyMODINIT_FUNC PyInit__tevent(void);
+PyMODINIT_FUNC PyInit__tevent(void)
+{
+ return module_init();
+}
diff --git a/lib/tevent/test_req.c b/lib/tevent/test_req.c
new file mode 100644
index 0000000..2274a8c
--- /dev/null
+++ b/lib/tevent/test_req.c
@@ -0,0 +1,288 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * testing of some tevent_req aspects
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "tevent.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_req_profile.h"
+#include "lib/util/time_basic.h"
+
+struct tevent_req_create_state {
+ uint8_t val;
+};
+
+static bool test_tevent_req_create(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct tevent_req *req;
+ struct tevent_req_create_state *state;
+
+ req = tevent_req_create(tctx, &state,
+ struct tevent_req_create_state);
+ torture_assert_not_null(tctx, req, "tevent_req_create failed\n");
+ torture_assert_int_equal(tctx, state->val, 0, "state not initialized\n");
+
+ TALLOC_FREE(req);
+
+ return true;
+}
+
+struct profile1_state {
+ uint8_t dummy;
+};
+
+static bool test_tevent_req_profile1(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct tevent_req *req;
+ struct profile1_state *state;
+ const struct tevent_req_profile *p1;
+ struct tevent_req_profile *p2;
+ struct timeval start, stop;
+ bool ok;
+ int cmp;
+
+ req = tevent_req_create(tctx, &state, struct profile1_state);
+ torture_assert_not_null(tctx, req, "tevent_req_create failed\n");
+
+ p1 = tevent_req_get_profile(req);
+ torture_assert(tctx, p1 == NULL, "profile not initialized to NULL\n");
+
+ ok = tevent_req_set_profile(req);
+ torture_assert(tctx, ok, "set_profile failed\n");
+
+ tevent_req_done(req);
+
+ p2 = tevent_req_move_profile(req, tctx);
+ torture_assert_not_null(tctx, p2, "get_profile failed\n");
+
+ /* Demonstrate sure "p2" outlives req */
+ TALLOC_FREE(req);
+
+ tevent_req_profile_get_start(p2, NULL, &start);
+ tevent_req_profile_get_stop(p2, NULL, &stop);
+
+ cmp = tevent_timeval_compare(&start, &stop);
+ torture_assert(tctx, cmp <= 0, "stop before start\n");
+
+ TALLOC_FREE(p2);
+
+ return true;
+}
+
+struct profile2_state {
+ uint8_t dummy;
+};
+
+static void profile2_done(struct tevent_req *subreq);
+
+static struct tevent_req *profile2_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev)
+{
+ struct tevent_req *req, *subreq;
+ struct profile2_state *state;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state, struct profile2_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ok = tevent_req_set_profile(req);
+ if (!ok) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tevent_wakeup_send(
+ state,
+ ev,
+ tevent_timeval_current_ofs(0, 1));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, profile2_done, req);
+
+ return req;
+}
+
+static void profile2_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ if (!ok) {
+ tevent_req_oom(req);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static int profile2_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **profile)
+{
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+
+ *profile = tevent_req_move_profile(req, mem_ctx);
+
+ return 0;
+}
+
+static bool test_tevent_req_profile2(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ struct tevent_req_profile *p1 = NULL;
+ struct tevent_req_profile *p2 = NULL;
+ const char *str1, *str2;
+ struct timeval tv1, tv2;
+ pid_t pid1, pid2;
+ enum tevent_req_state state1, state2;
+ uint64_t err1, err2;
+ char *printstring;
+ ssize_t pack_len;
+ int err;
+ bool ok;
+
+ ev = samba_tevent_context_init(tctx);
+ torture_assert_not_null(tctx, ev, "samba_tevent_context_init failed\n");
+
+ req = profile2_send(tctx, ev);
+ torture_assert_not_null(tctx, req, "profile2_send failed\n");
+
+ ok = tevent_req_poll_unix(req, ev, &err);
+ torture_assert(tctx, ok, "tevent_req_poll_unix failed\n");
+
+ err = profile2_recv(req, tctx, &p1);
+ torture_assert_int_equal(tctx, err, 0, "profile2_recv failed\n");
+
+ TALLOC_FREE(req);
+ TALLOC_FREE(ev);
+
+ printstring = tevent_req_profile_string(tctx, p1, 0, UINT_MAX);
+ torture_assert_not_null(
+ tctx,
+ printstring,
+ "tevent_req_profile_string failed\n");
+ printf("%s\n", printstring);
+
+ pack_len = tevent_req_profile_pack(p1, NULL, 0);
+ torture_assert(tctx, pack_len>0, "profile_pack failed\n");
+
+ {
+ uint8_t buf[pack_len];
+ ssize_t unpack_len;
+
+ tevent_req_profile_pack(p1, buf, sizeof(buf));
+ dump_data(10, buf, sizeof(buf));
+
+ unpack_len = tevent_req_profile_unpack(
+ buf,
+ pack_len,
+ tctx,
+ &p2);
+ torture_assert_int_equal(tctx,
+ pack_len,
+ unpack_len,
+ "profile_unpack failed\n");
+ }
+
+ printstring = tevent_req_profile_string(tctx, p2, 0, UINT_MAX);
+ torture_assert_not_null(
+ tctx,
+ printstring,
+ "tevent_req_profile_string failed\n");
+ printf("%s\n", printstring);
+
+ tevent_req_profile_get_name(p1, &str1);
+ tevent_req_profile_get_name(p2, &str2);
+ torture_assert_str_equal(tctx, str1, str2, "names differ\n");
+
+ tevent_req_profile_get_start(p1, &str1, &tv1);
+ tevent_req_profile_get_start(p2, &str2, &tv2);
+ torture_assert_str_equal(tctx, str1, str2, "start strings differ\n");
+ torture_assert(tctx,
+ tevent_timeval_compare(&tv1, &tv2) == 0,
+ "start times differ\n");
+
+ tevent_req_profile_get_stop(p1, &str1, &tv1);
+ tevent_req_profile_get_stop(p2, &str2, &tv2);
+ torture_assert_str_equal(tctx, str1, str2, "stop strings differ\n");
+ torture_assert(tctx,
+ tevent_timeval_compare(&tv1, &tv2) == 0,
+ "stop times differ\n");
+
+ tevent_req_profile_get_status(p1, &pid1, &state1, &err1);
+ tevent_req_profile_get_status(p2, &pid2, &state2, &err2);
+ torture_assert_int_equal(tctx, pid1, pid2, "pids differ\n");
+ torture_assert_int_equal(tctx, state1, state2, "states differ\n");
+ torture_assert_int_equal(tctx, err1, err2, "user errors differ\n");
+
+ str1 = tevent_req_profile_string(p1, p1, 0, UINT_MAX);
+ torture_assert_not_null(tctx, str1, "profile_string failed\n");
+ str2 = tevent_req_profile_string(p2, p2, 0, UINT_MAX);
+ torture_assert_not_null(tctx, str2, "profile_string failed\n");
+
+ torture_assert_str_equal(tctx, str1, str2, "result strings differ\n");
+
+ TALLOC_FREE(p1);
+ TALLOC_FREE(p2);
+
+ return true;
+}
+
+struct torture_suite *torture_local_tevent_req(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(mem_ctx, "tevent_req");
+
+ torture_suite_add_simple_tcase_const(
+ suite,
+ "create",
+ test_tevent_req_create,
+ NULL);
+ torture_suite_add_simple_tcase_const(
+ suite,
+ "profile1",
+ test_tevent_req_profile1,
+ NULL);
+ torture_suite_add_simple_tcase_const(
+ suite,
+ "profile2",
+ test_tevent_req_profile2,
+ NULL);
+
+ return suite;
+}
diff --git a/lib/tevent/tests/test_tevent_tag.c b/lib/tevent/tests/test_tevent_tag.c
new file mode 100644
index 0000000..2ae0e38
--- /dev/null
+++ b/lib/tevent/tests/test_tevent_tag.c
@@ -0,0 +1,253 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * testing of some tevent_req aspects
+ *
+ * Copyright (C) Pavel Březina <pbrezina@redhat.com> 2021
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+
+#include <talloc.h>
+#include <tevent.h>
+#include <cmocka.h>
+
+static void queue_trigger(struct tevent_req *req, void *private_data)
+{
+ /* Dummy handler. Just return. */
+ return;
+}
+
+static void fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ /* Dummy handler. Just return. */
+ return;
+}
+
+static void timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ /* Dummy handler. Just return. */
+ return;
+}
+
+static void signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ /* Dummy handler. Just return. */
+ return;
+}
+
+static void immediate_handler(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ /* Dummy handler. Just return. */
+ return;
+}
+
+static int test_setup(void **state)
+{
+ struct tevent_context *ev;
+
+ ev = tevent_context_init(NULL);
+ assert_non_null(ev);
+
+ *state = ev;
+ return 0;
+}
+
+static int test_teardown(void **state)
+{
+ struct tevent_context *ev = (struct tevent_context *)(*state);
+ talloc_free(ev);
+ return 0;
+}
+
+static void test_fd_tag(void **state)
+{
+ struct tevent_context *ev = (struct tevent_context *)(*state);
+ struct tevent_fd *fde;
+ uint64_t tag;
+
+ fde = tevent_add_fd(ev, ev, 0, TEVENT_FD_READ, fd_handler, NULL);
+ assert_non_null(fde);
+
+ tag = tevent_fd_get_tag(fde);
+ assert_int_equal(0, tag);
+
+ tevent_fd_set_tag(fde, 1);
+ tag = tevent_fd_get_tag(fde);
+ assert_int_equal(1, tag);
+
+ tevent_re_initialise(ev);
+
+ tag = tevent_fd_get_tag(fde);
+ assert_int_equal(1, tag);
+
+ TALLOC_FREE(fde);
+}
+
+static void test_timer_tag(void **state)
+{
+ struct tevent_context *ev = (struct tevent_context *)(*state);
+ struct tevent_timer *te;
+ struct timeval next;
+ uint64_t tag;
+
+ next = tevent_timeval_current();
+ te = tevent_add_timer(ev, ev, next, timer_handler, NULL);
+ assert_non_null(te);
+
+ tag = tevent_timer_get_tag(te);
+ assert_int_equal(0, tag);
+
+ tevent_timer_set_tag(te, 1);
+ tag = tevent_timer_get_tag(te);
+ assert_int_equal(1, tag);
+
+ next = tevent_timeval_current();
+ tevent_update_timer(te, next);
+
+ tag = tevent_timer_get_tag(te);
+ assert_int_equal(1, tag);
+
+ tevent_re_initialise(ev);
+
+ tag = tevent_timer_get_tag(te);
+ assert_int_equal(1, tag);
+
+ TALLOC_FREE(te);
+}
+
+static void test_signal_tag(void **state)
+{
+ struct tevent_context *ev = (struct tevent_context *)(*state);
+ struct tevent_signal *se;
+ uint64_t tag;
+
+ se = tevent_add_signal(ev, ev, SIGUSR1, 0, signal_handler, NULL);
+ assert_non_null(se);
+
+ tag = tevent_signal_get_tag(se);
+ assert_int_equal(0, tag);
+
+ tevent_signal_set_tag(se, 1);
+ tag = tevent_signal_get_tag(se);
+ assert_int_equal(1, tag);
+
+ tevent_re_initialise(ev);
+
+ tag = tevent_signal_get_tag(se);
+ assert_int_equal(1, tag);
+
+ TALLOC_FREE(se);
+}
+
+static void test_immediate_tag(void **state)
+{
+ struct tevent_context *ev = (struct tevent_context *)(*state);
+ struct tevent_immediate *im;
+ uint64_t tag;
+
+ im = tevent_create_immediate(ev);
+ assert_non_null(im);
+
+ tag = tevent_immediate_get_tag(im);
+ assert_int_equal(0, tag);
+
+ tevent_immediate_set_tag(im, 1);
+ tag = tevent_immediate_get_tag(im);
+ assert_int_equal(1, tag);
+
+ tevent_schedule_immediate(im, ev, immediate_handler, NULL);
+
+ tag = tevent_immediate_get_tag(im);
+ assert_int_equal(1, tag);
+
+ tevent_re_initialise(ev);
+
+ tag = tevent_immediate_get_tag(im);
+ assert_int_equal(1, tag);
+
+ TALLOC_FREE(im);
+}
+
+static void test_queue_entry_tag(void **state)
+{
+ struct tevent_context *ev = (struct tevent_context *)(*state);
+ struct tevent_queue *q;
+ struct tevent_queue_entry *e1, *e2;
+ struct tevent_req *r1, *r2;
+ int *s1, *s2;
+ uint64_t tag;
+
+ q = tevent_queue_create(ev, "test_queue");
+ assert_non_null(q);
+
+ r1 = tevent_req_create(ev, &s1, int);
+ r2 = tevent_req_create(ev, &s2, int);
+ e1 = tevent_queue_add_entry(q, ev, r1, queue_trigger, NULL);
+ e2 = tevent_queue_add_entry(q, ev, r2, queue_trigger, NULL);
+
+ tag = tevent_queue_entry_get_tag(e1);
+ assert_int_equal(0, tag);
+ tag = tevent_queue_entry_get_tag(e2);
+ assert_int_equal(0, tag);
+
+ tevent_queue_entry_set_tag(e1, 1);
+ tevent_queue_entry_set_tag(e2, 2);
+
+ tag = tevent_queue_entry_get_tag(e1);
+ assert_int_equal(1, tag);
+
+ tag = tevent_queue_entry_get_tag(e2);
+ assert_int_equal(2, tag);
+
+ TALLOC_FREE(q);
+}
+
+int main(int argc, char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_fd_tag, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_timer_tag, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_signal_tag, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_immediate_tag, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_queue_entry_tag, test_setup, test_teardown),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/tevent/tests/test_tevent_trace.c b/lib/tevent/tests/test_tevent_trace.c
new file mode 100644
index 0000000..10e1ee0
--- /dev/null
+++ b/lib/tevent/tests/test_tevent_trace.c
@@ -0,0 +1,1324 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * testing of some tevent_req aspects
+ *
+ * Copyright (C) Pavel Březina <pbrezina@redhat.com> 2021
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <talloc.h>
+#include <tevent.h>
+#include <cmocka.h>
+
+struct test_ctx {
+ struct tevent_context *ev;
+
+ bool handler_skipped;
+ bool reattach_reset;
+
+ uint64_t (*get_tag)(const void *event);
+ void (*set_tag)(void *event, uint64_t tag);
+ uint64_t current_tag;
+
+ bool attach;
+ bool before_handler;
+ bool handler_called;
+ bool detach;
+};
+
+static void fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_fd_get_tag(fde);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ return;
+}
+
+static void timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_timer_get_tag(te);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ return;
+}
+
+static void signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_signal_get_tag(se);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ return;
+}
+
+static void immediate_handler(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_immediate_get_tag(im);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ return;
+}
+
+static void immediate_handler_reschedule(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_immediate_get_tag(im);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+
+ assert_false(tctx->reattach_reset);
+ tctx->reattach_reset = true;
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler, tctx);
+ assert_false(tctx->reattach_reset);
+ assert_false(tctx->handler_skipped);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ assert_int_not_equal(tag, tctx->current_tag);
+ tag = tevent_immediate_get_tag(im);
+ assert_int_equal(tag, tctx->current_tag);
+
+ tctx->handler_skipped = true;
+ tctx->reattach_reset = true;
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler, tctx);
+ assert_false(tctx->reattach_reset);
+ assert_false(tctx->handler_skipped);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ assert_int_not_equal(tag, tctx->current_tag);
+ tag = tevent_immediate_get_tag(im);
+ assert_int_equal(tag, tctx->current_tag);
+}
+
+static void fd_handler_free(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_fd_get_tag(fde);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ TALLOC_FREE(fde);
+ assert_true(tctx->detach);
+ return;
+}
+
+static void timer_handler_free(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_timer_get_tag(te);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ TALLOC_FREE(te);
+ assert_true(tctx->detach);
+ return;
+}
+
+static void signal_handler_free(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_signal_get_tag(se);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ TALLOC_FREE(se);
+ assert_true(tctx->detach);
+ return;
+}
+
+static void immediate_handler_free(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tevent_immediate_get_tag(im);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->handler_called = true;
+ assert_int_equal(tag, tctx->current_tag);
+ TALLOC_FREE(im);
+ assert_true(tctx->detach);
+ return;
+}
+
+static void trace_event_cb(void *event,
+ enum tevent_event_trace_point point,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag = tctx->get_tag(event);
+
+ switch (point) {
+ case TEVENT_EVENT_TRACE_ATTACH:
+ if (tctx->reattach_reset) {
+ assert_true(tctx->attach);
+ assert_true(tctx->detach);
+ tctx->attach = false;
+ tctx->before_handler = false;
+ tctx->handler_called = false;
+ tctx->detach = false;
+ tctx->handler_skipped = false;
+ tctx->reattach_reset = false;
+ }
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->attach = true;
+ assert_int_equal(tag, tctx->current_tag);
+ tag = ++tctx->current_tag;
+ tctx->set_tag(event, tag);
+ break;
+ case TEVENT_EVENT_TRACE_BEFORE_HANDLER:
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ tctx->before_handler = true;
+ assert_int_equal(tag, tctx->current_tag);
+ break;
+ case TEVENT_EVENT_TRACE_DETACH:
+ assert_true(tctx->attach);
+ if (tctx->handler_skipped) {
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ } else {
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ }
+ assert_false(tctx->detach);
+ tctx->detach = true;
+ assert_int_equal(tag, tctx->current_tag);
+ break;
+ }
+}
+
+static void trace_event_cb1(void *event,
+ enum tevent_event_trace_point point,
+ void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ uint64_t tag;
+
+ switch (point) {
+ case TEVENT_EVENT_TRACE_ATTACH:
+ tctx->attach = true;
+ tag = ++tctx->current_tag;
+ tctx->set_tag(event, tag);
+ break;
+ case TEVENT_EVENT_TRACE_BEFORE_HANDLER:
+ tctx->before_handler = true;
+ break;
+ case TEVENT_EVENT_TRACE_DETACH:
+ tctx->detach = true;
+ break;
+ }
+}
+
+static int test_setup(void **state)
+{
+ struct test_ctx *tctx;
+
+ tctx = talloc_zero(NULL, struct test_ctx);
+ assert_non_null(tctx);
+
+ tctx->ev = tevent_context_init(tctx);
+ assert_non_null(tctx->ev);
+
+ *state = tctx;
+ return 0;
+}
+
+static int test_teardown(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ tctx->get_tag = NULL;
+ tctx->set_tag = NULL;
+ tevent_set_trace_fd_callback(tctx->ev, NULL, NULL);
+ tevent_set_trace_timer_callback(tctx->ev, NULL, NULL);
+ tevent_set_trace_signal_callback(tctx->ev, NULL, NULL);
+ tevent_set_trace_immediate_callback(tctx->ev, NULL, NULL);
+ TALLOC_FREE(tctx);
+ return 0;
+}
+
+static uint64_t fd_get_tag(const void *_event)
+{
+ const struct tevent_fd *event =
+ (const struct tevent_fd *)_event;
+
+ return tevent_fd_get_tag(event);
+}
+
+static void fd_set_tag(void *_event, uint64_t tag)
+{
+ struct tevent_fd *event =
+ (struct tevent_fd *)_event;
+
+ tevent_fd_set_tag(event, tag);
+}
+
+static uint64_t timer_get_tag(const void *_event)
+{
+ const struct tevent_timer *event =
+ (const struct tevent_timer *)_event;
+
+ return tevent_timer_get_tag(event);
+}
+
+static void timer_set_tag(void *_event, uint64_t tag)
+{
+ struct tevent_timer *event =
+ (struct tevent_timer *)_event;
+
+ tevent_timer_set_tag(event, tag);
+}
+
+static uint64_t signal_get_tag(const void *_event)
+{
+ const struct tevent_signal *event =
+ (const struct tevent_signal *)_event;
+
+ return tevent_signal_get_tag(event);
+}
+
+static void signal_set_tag(void *_event, uint64_t tag)
+{
+ struct tevent_signal *event =
+ (struct tevent_signal *)_event;
+
+ tevent_signal_set_tag(event, tag);
+}
+
+static uint64_t immediate_get_tag(const void *_event)
+{
+ const struct tevent_immediate *event =
+ (const struct tevent_immediate *)_event;
+
+ return tevent_immediate_get_tag(event);
+}
+
+static void immediate_set_tag(void *_event, uint64_t tag)
+{
+ struct tevent_immediate *event =
+ (struct tevent_immediate *)_event;
+
+ tevent_immediate_set_tag(event, tag);
+}
+
+static uint64_t queue_entry_get_tag(const void *_event)
+{
+ const struct tevent_queue_entry *event =
+ (const struct tevent_queue_entry *)_event;
+
+ return tevent_queue_entry_get_tag(event);
+}
+
+static void queue_entry_set_tag(void *_event, uint64_t tag)
+{
+ struct tevent_queue_entry *event =
+ (struct tevent_queue_entry *)_event;
+
+ tevent_queue_entry_set_tag(event, tag);
+}
+
+static void test_trace_event_fd__loop(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_fd *fde;
+
+ tctx->get_tag = fd_get_tag;
+ tctx->set_tag = fd_set_tag;
+ tevent_set_trace_fd_callback(tctx->ev, (tevent_trace_fd_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ fde = tevent_add_fd(tctx->ev, tctx, 0, TEVENT_FD_WRITE, fd_handler, tctx);
+ assert_non_null(fde);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ TEVENT_FD_WRITEABLE(fde);
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ TALLOC_FREE(fde);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_fd__reset(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_fd *fde;
+
+ tctx->get_tag = fd_get_tag;
+ tctx->set_tag = fd_set_tag;
+ tevent_set_trace_fd_callback(tctx->ev, (tevent_trace_fd_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ fde = tevent_add_fd(tctx->ev, tctx, 0, TEVENT_FD_WRITE, fd_handler, tctx);
+ assert_non_null(fde);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tctx->handler_skipped = true;
+ tevent_re_initialise(tctx->ev);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_fd__free(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_fd *fde;
+
+ tctx->get_tag = fd_get_tag;
+ tctx->set_tag = fd_set_tag;
+ tevent_set_trace_fd_callback(tctx->ev, (tevent_trace_fd_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ fde = tevent_add_fd(tctx->ev, tctx, 0, TEVENT_FD_WRITE, fd_handler, tctx);
+ assert_non_null(fde);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tctx->handler_skipped = true;
+ TALLOC_FREE(fde);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_fd__free_in_handler(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_fd *fde;
+
+ tctx->get_tag = fd_get_tag;
+ tctx->set_tag = fd_set_tag;
+ tevent_set_trace_fd_callback(tctx->ev, (tevent_trace_fd_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ fde = tevent_add_fd(tctx->ev, tctx, 0, TEVENT_FD_WRITE, fd_handler_free, tctx);
+ assert_non_null(fde);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ TEVENT_FD_WRITEABLE(fde);
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_timer__loop(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_timer *te;
+ struct timeval next;
+
+ tctx->get_tag = timer_get_tag;
+ tctx->set_tag = timer_set_tag;
+ tevent_set_trace_timer_callback(tctx->ev, (tevent_trace_timer_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ next = tevent_timeval_current();
+ te = tevent_add_timer(tctx->ev, tctx, next, timer_handler, tctx);
+ assert_non_null(te);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ /* timer events are self destructing after calling the handler */
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_timer__reset(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_timer *te;
+ struct timeval next;
+
+ tctx->get_tag = timer_get_tag;
+ tctx->set_tag = timer_set_tag;
+ tevent_set_trace_timer_callback(tctx->ev, (tevent_trace_timer_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ next = tevent_timeval_current();
+ te = tevent_add_timer(tctx->ev, tctx, next, timer_handler, tctx);
+ assert_non_null(te);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ assert_true(tctx->attach);
+
+ assert_false(tctx->reattach_reset);
+ tctx->handler_skipped = true;
+ tctx->reattach_reset = true;
+ next = tevent_timeval_current();
+ tevent_update_timer(te, next);
+ assert_false(tctx->reattach_reset);
+ assert_false(tctx->handler_skipped);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tctx->handler_skipped = true;
+ tevent_re_initialise(tctx->ev);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_timer__free(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_timer *te;
+ struct timeval next;
+
+ tctx->get_tag = timer_get_tag;
+ tctx->set_tag = timer_set_tag;
+ tevent_set_trace_timer_callback(tctx->ev, (tevent_trace_timer_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ next = tevent_timeval_current();
+ te = tevent_add_timer(tctx->ev, tctx, next, timer_handler, tctx);
+ assert_non_null(te);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ assert_true(tctx->attach);
+
+ tctx->handler_skipped = true;
+ TALLOC_FREE(te);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_timer__free_in_handler(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_timer *te;
+ struct timeval next;
+
+ tctx->get_tag = timer_get_tag;
+ tctx->set_tag = timer_set_tag;
+ tevent_set_trace_timer_callback(tctx->ev, (tevent_trace_timer_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ next = tevent_timeval_current();
+ te = tevent_add_timer(tctx->ev, tctx, next, timer_handler_free, tctx);
+ assert_non_null(te);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_signal__loop(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_signal *se;
+
+ tctx->get_tag = signal_get_tag;
+ tctx->set_tag = signal_set_tag;
+ tevent_set_trace_signal_callback(tctx->ev, (tevent_trace_signal_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ se = tevent_add_signal(tctx->ev, tctx, SIGUSR1, 0, signal_handler, tctx);
+ assert_non_null(se);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ kill(getpid(), SIGUSR1);
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ TALLOC_FREE(se);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_signal__reset(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_signal *se;
+
+ tctx->get_tag = signal_get_tag;
+ tctx->set_tag = signal_set_tag;
+ tevent_set_trace_signal_callback(tctx->ev, (tevent_trace_signal_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ se = tevent_add_signal(tctx->ev, tctx, SIGUSR1, 0, signal_handler, tctx);
+ assert_non_null(se);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tctx->handler_skipped = true;
+ TALLOC_FREE(se);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_signal__free(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_signal *se;
+
+ tctx->get_tag = signal_get_tag;
+ tctx->set_tag = signal_set_tag;
+ tevent_set_trace_signal_callback(tctx->ev, (tevent_trace_signal_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ se = tevent_add_signal(tctx->ev, tctx, SIGUSR1, 0, signal_handler, tctx);
+ assert_non_null(se);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tctx->handler_skipped = true;
+ TALLOC_FREE(se);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_signal__free_in_handler(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_signal *se;
+
+ tctx->get_tag = signal_get_tag;
+ tctx->set_tag = signal_set_tag;
+ tevent_set_trace_signal_callback(tctx->ev, (tevent_trace_signal_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ se = tevent_add_signal(tctx->ev, tctx, SIGUSR1, 0, signal_handler_free, tctx);
+ assert_non_null(se);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ kill(getpid(), SIGUSR1);
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_immediate__loop(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_immediate *im;
+
+ tctx->get_tag = immediate_get_tag;
+ tctx->set_tag = immediate_set_tag;
+ tevent_set_trace_immediate_callback(tctx->ev, (tevent_trace_immediate_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ im = tevent_create_immediate(tctx);
+ assert_non_null(im);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler, tctx);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ /* immediate events are self detaching */
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_immediate__reset(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_immediate *im;
+
+ tctx->get_tag = immediate_get_tag;
+ tctx->set_tag = immediate_set_tag;
+ tevent_set_trace_immediate_callback(tctx->ev, (tevent_trace_immediate_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ im = tevent_create_immediate(tctx);
+ assert_non_null(im);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler, tctx);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tctx->handler_skipped = true;
+ tevent_re_initialise(tctx->ev);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_immediate__free(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_immediate *im;
+
+ tctx->get_tag = immediate_get_tag;
+ tctx->set_tag = immediate_set_tag;
+ tevent_set_trace_immediate_callback(tctx->ev, (tevent_trace_immediate_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ im = tevent_create_immediate(tctx);
+ assert_non_null(im);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler, tctx);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tctx->handler_skipped = true;
+ TALLOC_FREE(im);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_immediate__free_in_handler(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_immediate *im;
+
+ tctx->get_tag = immediate_get_tag;
+ tctx->set_tag = immediate_set_tag;
+ tevent_set_trace_immediate_callback(tctx->ev, (tevent_trace_immediate_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ im = tevent_create_immediate(tctx);
+ assert_non_null(im);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler_free, tctx);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_trace_event_immediate__reschedule(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_immediate *im;
+
+ tctx->get_tag = immediate_get_tag;
+ tctx->set_tag = immediate_set_tag;
+ tevent_set_trace_immediate_callback(tctx->ev, (tevent_trace_immediate_callback_t)trace_event_cb, tctx);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ im = tevent_create_immediate(tctx);
+ assert_non_null(im);
+
+ assert_false(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler, tctx);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ assert_false(tctx->reattach_reset);
+ tctx->handler_skipped = true;
+ tctx->reattach_reset = true;
+ tevent_schedule_immediate(im, tctx->ev, immediate_handler_reschedule, tctx);
+ assert_false(tctx->reattach_reset);
+ assert_false(tctx->handler_skipped);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_loop_once(tctx->ev);
+ assert_false(tctx->reattach_reset);
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+
+ tevent_loop_once(tctx->ev);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ /* immediate events are self detaching */
+ assert_true(tctx->detach);
+}
+
+struct dummy_request_state
+{
+ int i;
+ struct tevent_queue_entry *e;
+};
+
+static void queue_trigger(struct tevent_req *req, void *private_data)
+{
+ struct test_ctx *tctx = (struct test_ctx *)private_data;
+ struct dummy_request_state *state = tevent_req_data(
+ req, struct dummy_request_state);
+
+ tctx->handler_called = true;
+ assert_int_equal(tevent_queue_entry_get_tag(state->e), state->i);
+ TALLOC_FREE(req);
+
+ return;
+}
+
+static void test_trace_queue__loop(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_queue *qa, *qb;
+ struct tevent_req *r1, *r2, *r3, *r4, *r5;
+ struct dummy_request_state *ds1, *ds2, *ds3, *ds4, *ds5;
+
+ tevent_set_trace_queue_callback(
+ tctx->ev,
+ (tevent_trace_queue_callback_t)trace_event_cb1,
+ tctx);
+ tctx->get_tag = queue_entry_get_tag;
+ tctx->set_tag = queue_entry_set_tag;
+
+ qa = tevent_queue_create(tctx->ev, "test_queue A");
+ assert_non_null(qa);
+ qb = tevent_queue_create(tctx->ev, "test_queue B");
+ assert_non_null(qb);
+
+ r1 = tevent_req_create(tctx->ev, &ds1, struct dummy_request_state);
+ ds1->e = tevent_queue_add_entry(qa,
+ tctx->ev,
+ r1,
+ queue_trigger,
+ *state);
+ ds1->i = tctx->current_tag;
+ assert_int_equal(ds1->i, 1);
+
+ r2 = tevent_req_create(tctx->ev, &ds2, struct dummy_request_state);
+ ds2->e = tevent_queue_add_entry(qa,
+ tctx->ev,
+ r2,
+ queue_trigger,
+ *state);
+ ds2->i = tctx->current_tag;
+ assert_int_equal(ds2->i, 2);
+
+ r3 = tevent_req_create(tctx->ev, &ds3, struct dummy_request_state);
+ ds3->e = tevent_queue_add_entry(qb,
+ tctx->ev,
+ r3,
+ queue_trigger,
+ *state);
+ ds3->i = tctx->current_tag;
+ assert_int_equal(ds3->i, 3);
+
+ r4 = tevent_req_create(tctx->ev, &ds4, struct dummy_request_state);
+ ds4->e = tevent_queue_add_entry(qb,
+ tctx->ev,
+ r4,
+ queue_trigger,
+ *state);
+ ds4->i = tctx->current_tag;
+ assert_int_equal(ds4->i, 4);
+
+ r5 = tevent_req_create(tctx->ev, &ds5, struct dummy_request_state);
+ ds5->e = tevent_queue_add_entry(qa,
+ tctx->ev,
+ r5,
+ queue_trigger,
+ *state);
+ ds5->i = tctx->current_tag;
+ assert_int_equal(ds5->i, 5);
+
+ tevent_loop_once(tctx->ev);
+ tevent_loop_once(tctx->ev);
+ tevent_loop_once(tctx->ev);
+ tevent_loop_once(tctx->ev);
+ tevent_loop_once(tctx->ev);
+}
+
+static void reset_tctx(struct test_ctx *tctx)
+{
+ tctx->attach = false;
+ tctx->before_handler = false;
+ tctx->handler_called = false;
+ tctx->detach = false;
+}
+
+static void test_trace_queue__extra(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ struct tevent_queue *qa;
+ struct tevent_req *r1, *r2, *r3;
+ struct dummy_request_state *ds1, *ds2, *ds3;
+
+ tevent_set_trace_queue_callback(
+ tctx->ev,
+ (tevent_trace_queue_callback_t)trace_event_cb1,
+ tctx);
+ tctx->get_tag = queue_entry_get_tag;
+ tctx->set_tag = queue_entry_set_tag;
+
+ qa = tevent_queue_create(tctx->ev, "test_queue A");
+ assert_non_null(qa);
+
+ /*
+ * r1 - this tests optimize_empty - request is triggered immediately,
+ * (and not even scheduled to tevent_context). The TALLOC_FREE() called
+ * from queue_trigger removes the request/queue_entry from the queue qa.
+ * So qa is empty
+ */
+ r1 = tevent_req_create(tctx->ev, &ds1, struct dummy_request_state);
+ ds1->e = tevent_queue_add_optimize_empty(qa,
+ tctx->ev,
+ r1,
+ queue_trigger,
+ *state);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+ assert_int_equal(tevent_queue_length(qa), 0);
+
+ reset_tctx(tctx);
+
+ /*
+ * Test a blocker request r2 - the trigger function is NULL.
+ */
+ r2 = tevent_req_create(tctx->ev, &ds2, struct dummy_request_state);
+ ds2->e = tevent_queue_add_entry(qa, tctx->ev, r2, NULL, *state);
+ ds2->i = tctx->current_tag;
+ assert_true(tctx->attach);
+ assert_false(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ assert_int_equal(tevent_queue_length(qa), 1);
+
+ /*
+ * This runs the tevent_queue_noop_trigger().
+ * A blocker r2 is still on the queue head, with triggered==true
+ */
+ tevent_loop_once(tctx->ev);
+
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ /* tevent_queue_noop_trigger() is a noop. Does not set handler_called */
+ assert_false(tctx->detach);
+ assert_int_equal(tevent_queue_length(qa), 1);
+
+ /*
+ * Add a normal request r3. It will be blocked by r2.
+ */
+ r3 = tevent_req_create(tctx->ev, &ds3, struct dummy_request_state);
+ ds3->e = tevent_queue_add_entry(qa,
+ tctx->ev,
+ r3,
+ queue_trigger,
+ *state);
+ ds3->i = tctx->current_tag;
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_false(tctx->detach);
+ assert_int_equal(tevent_queue_length(qa), 2);
+
+ /*
+ * Remove the blocker r2.
+ */
+ TALLOC_FREE(r2);
+ assert_true(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_false(tctx->handler_called);
+ assert_true(tctx->detach);
+ assert_int_equal(tevent_queue_length(qa), 1);
+
+ reset_tctx(tctx);
+
+ /* Process r3 */
+ tevent_loop_once(tctx->ev);
+
+ assert_false(tctx->attach);
+ assert_true(tctx->before_handler);
+ assert_true(tctx->handler_called);
+ assert_true(tctx->detach);
+}
+
+static void test_get_set_trace_fd_callback(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ tevent_trace_fd_callback_t cb;
+ void *pvt;
+
+ tevent_get_trace_fd_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+
+ tevent_set_trace_fd_callback(tctx->ev, (tevent_trace_fd_callback_t)trace_event_cb, tctx);
+ tevent_get_trace_fd_callback(tctx->ev, &cb, &pvt);
+ assert_ptr_equal(cb, trace_event_cb);
+ assert_ptr_equal(pvt, tctx);
+
+ tevent_set_trace_fd_callback(tctx->ev, NULL, NULL);
+ tevent_get_trace_fd_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+}
+
+static void test_get_set_trace_timer_callback(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ tevent_trace_timer_callback_t cb;
+ void *pvt;
+
+ tevent_get_trace_timer_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+
+ tevent_set_trace_timer_callback(tctx->ev, (tevent_trace_timer_callback_t)trace_event_cb, tctx);
+ tevent_get_trace_timer_callback(tctx->ev, &cb, &pvt);
+ assert_ptr_equal(cb, trace_event_cb);
+ assert_ptr_equal(pvt, tctx);
+
+ tevent_set_trace_timer_callback(tctx->ev, NULL, NULL);
+ tevent_get_trace_timer_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+}
+
+static void test_get_set_trace_signal_callback(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ tevent_trace_signal_callback_t cb;
+ void *pvt;
+
+ tevent_get_trace_signal_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+
+ tevent_set_trace_signal_callback(tctx->ev, (tevent_trace_signal_callback_t)trace_event_cb, tctx);
+ tevent_get_trace_signal_callback(tctx->ev, &cb, &pvt);
+ assert_ptr_equal(cb, trace_event_cb);
+ assert_ptr_equal(pvt, tctx);
+
+ tevent_set_trace_signal_callback(tctx->ev, NULL, NULL);
+ tevent_get_trace_signal_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+}
+
+static void test_get_set_trace_immediate_callback(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ tevent_trace_immediate_callback_t cb;
+ void *pvt;
+
+ tevent_get_trace_immediate_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+
+ tevent_set_trace_immediate_callback(tctx->ev, (tevent_trace_immediate_callback_t)trace_event_cb, tctx);
+ tevent_get_trace_immediate_callback(tctx->ev, &cb, &pvt);
+ assert_ptr_equal(cb, trace_event_cb);
+ assert_ptr_equal(pvt, tctx);
+
+ tevent_set_trace_immediate_callback(tctx->ev, NULL, NULL);
+ tevent_get_trace_immediate_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+}
+
+static void test_get_set_trace_queue_callback(void **state)
+{
+ struct test_ctx *tctx = (struct test_ctx *)(*state);
+ tevent_trace_queue_callback_t cb;
+ void *pvt;
+
+ tevent_get_trace_queue_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+
+ tevent_set_trace_queue_callback(tctx->ev, (tevent_trace_queue_callback_t)trace_event_cb, tctx);
+ tevent_get_trace_queue_callback(tctx->ev, &cb, &pvt);
+ assert_ptr_equal(cb, trace_event_cb);
+ assert_ptr_equal(pvt, tctx);
+
+ tevent_set_trace_queue_callback(tctx->ev, NULL, NULL);
+ tevent_get_trace_queue_callback(tctx->ev, &cb, &pvt);
+ assert_null(cb);
+ assert_null(pvt);
+}
+
+int main(int argc, char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_trace_event_fd__loop, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_fd__reset, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_fd__free, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_fd__free_in_handler, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_timer__loop, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_timer__reset, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_timer__free, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_timer__free_in_handler, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_signal__loop, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_signal__reset, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_signal__free, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_signal__free_in_handler, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_immediate__loop, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_immediate__reset, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_immediate__free, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_immediate__free_in_handler, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_event_immediate__reschedule, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_queue__loop, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_trace_queue__extra, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_get_set_trace_fd_callback, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_get_set_trace_timer_callback, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_get_set_trace_signal_callback, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_get_set_trace_immediate_callback, test_setup, test_teardown),
+ cmocka_unit_test_setup_teardown(test_get_set_trace_queue_callback, test_setup, test_teardown),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
new file mode 100644
index 0000000..e088166
--- /dev/null
+++ b/lib/tevent/testsuite.c
@@ -0,0 +1,2651 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ testing of the events subsystem
+
+ Copyright (C) Stefan Metzmacher 2006-2009
+ Copyright (C) Jeremy Allison 2013
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "system/network.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/util/blocking.h"
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+#include <assert.h>
+#endif
+
+static struct tevent_context *
+test_tevent_context_init(TALLOC_CTX *mem_ctx)
+{
+ struct tevent_context *ev = NULL;
+
+ ev = tevent_context_init(mem_ctx);
+ if (ev != NULL) {
+ samba_tevent_set_debug(ev, "<default>");
+ }
+
+ return ev;
+}
+
+static struct tevent_context *
+test_tevent_context_init_byname(TALLOC_CTX *mem_ctx, const char *name)
+{
+ struct tevent_context *ev = NULL;
+
+ ev = tevent_context_init_byname(mem_ctx, name);
+ if (ev != NULL) {
+ samba_tevent_set_debug(ev, name);
+ }
+
+ return ev;
+}
+
+static int fde_count;
+
+static void do_read(int fd, void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = read(fd, buf, count);
+ } while (ret == -1 && errno == EINTR);
+}
+
+static void fde_handler_read(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ int *fd = (int *)private_data;
+ char c;
+#ifdef SA_SIGINFO
+ kill(getpid(), SIGUSR1);
+#endif
+ kill(getpid(), SIGALRM);
+
+ do_read(fd[0], &c, 1);
+ fde_count++;
+}
+
+static void do_write(int fd, void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = write(fd, buf, count);
+ } while (ret == -1 && errno == EINTR);
+}
+
+static void do_fill(int fd)
+{
+ uint8_t buf[1024] = {0, };
+ ssize_t ret;
+
+ set_blocking(fd, false);
+
+ do {
+ do {
+ ret = write(fd, buf, ARRAY_SIZE(buf));
+ } while (ret == -1 && errno == EINTR);
+ } while (ret == ARRAY_SIZE(buf));
+
+ set_blocking(fd, true);
+}
+
+static void fde_handler_write(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ int *fd = (int *)private_data;
+ char c = 0;
+
+ do_write(fd[1], &c, 1);
+}
+
+
+/* This will only fire if the fd's returned from pipe() are bi-directional. */
+static void fde_handler_read_1(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ int *fd = (int *)private_data;
+ char c;
+#ifdef SA_SIGINFO
+ kill(getpid(), SIGUSR1);
+#endif
+ kill(getpid(), SIGALRM);
+
+ do_read(fd[1], &c, 1);
+ fde_count++;
+}
+
+/* This will only fire if the fd's returned from pipe() are bi-directional. */
+static void fde_handler_write_1(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ int *fd = (int *)private_data;
+ char c = 0;
+ do_write(fd[0], &c, 1);
+}
+
+static void finished_handler(struct tevent_context *ev_ctx, struct tevent_timer *te,
+ struct timeval tval, void *private_data)
+{
+ int *finished = (int *)private_data;
+ (*finished) = 1;
+}
+
+static void count_handler(struct tevent_context *ev_ctx, struct tevent_signal *te,
+ int signum, int count, void *info, void *private_data)
+{
+ int *countp = (int *)private_data;
+ (*countp) += count;
+}
+
+static bool test_event_context(struct torture_context *test,
+ const void *test_data)
+{
+ struct tevent_context *ev_ctx;
+ int fd[2] = { -1, -1 };
+ const char *backend = (const char *)test_data;
+ int alarm_count=0, info_count=0;
+ struct tevent_fd *fde_read;
+ struct tevent_fd *fde_read_1;
+ struct tevent_fd *fde_write;
+ struct tevent_fd *fde_write_1;
+#ifdef SA_RESTART
+ struct tevent_signal *se1 = NULL;
+#endif
+#ifdef SA_RESETHAND
+ struct tevent_signal *se2 = NULL;
+#endif
+#ifdef SA_SIGINFO
+ struct tevent_signal *se3 = NULL;
+#endif
+ int finished=0;
+ struct timeval t;
+ int ret;
+
+ ev_ctx = test_tevent_context_init_byname(test, backend);
+ if (ev_ctx == NULL) {
+ torture_comment(test, "event backend '%s' not supported\n", backend);
+ return true;
+ }
+
+ torture_comment(test, "backend '%s' - %s\n",
+ backend, __FUNCTION__);
+
+ /* reset globals */
+ fde_count = 0;
+
+ /* create a pipe */
+ ret = pipe(fd);
+ torture_assert_int_equal(test, ret, 0, "pipe failed");
+
+ fde_read = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
+ fde_handler_read, fd);
+ fde_write_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_WRITE,
+ fde_handler_write_1, fd);
+
+ fde_write = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_WRITE,
+ fde_handler_write, fd);
+ fde_read_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_READ,
+ fde_handler_read_1, fd);
+
+ tevent_fd_set_auto_close(fde_read);
+ tevent_fd_set_auto_close(fde_write);
+
+ tevent_add_timer(ev_ctx, ev_ctx, timeval_current_ofs(2,0),
+ finished_handler, &finished);
+
+#ifdef SA_RESTART
+ se1 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count);
+ torture_assert(test, se1 != NULL, "failed to setup se1");
+#endif
+#ifdef SA_RESETHAND
+ se2 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count);
+ torture_assert(test, se2 != NULL, "failed to setup se2");
+#endif
+#ifdef SA_SIGINFO
+ se3 = tevent_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count);
+ torture_assert(test, se3 != NULL, "failed to setup se3");
+#endif
+
+ t = timeval_current();
+ while (!finished) {
+ errno = 0;
+ if (tevent_loop_once(ev_ctx) == -1) {
+ TALLOC_FREE(ev_ctx);
+ torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
+ return false;
+ }
+ }
+
+ talloc_free(fde_read_1);
+ talloc_free(fde_write_1);
+ talloc_free(fde_read);
+ talloc_free(fde_write);
+
+ while (alarm_count < fde_count+1) {
+ if (tevent_loop_once(ev_ctx) == -1) {
+ break;
+ }
+ }
+
+ torture_comment(test, "Got %.2f pipe events/sec\n", fde_count/timeval_elapsed(&t));
+
+#ifdef SA_RESTART
+ talloc_free(se1);
+#endif
+
+ torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch");
+
+#ifdef SA_RESETHAND
+ /*
+ * we do not call talloc_free(se2)
+ * because it is already gone,
+ * after triggering the event handler.
+ */
+#endif
+
+#ifdef SA_SIGINFO
+ talloc_free(se3);
+ torture_assert_int_equal(test, info_count, fde_count, "info count mismatch");
+#endif
+
+ talloc_free(ev_ctx);
+
+ return true;
+}
+
+static void fde_handler_do_read(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ int *fd = (int *)private_data;
+ char c = 0;
+
+ do_read(fd[0], &c, 1);
+ fde_count++;
+}
+
+static void fde_handler_do_write(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ int *fd = (int *)private_data;
+ char c = 0;
+
+ do_write(fd[1], &c, 1);
+}
+
+static void fde_handler_ignore(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+}
+
+static bool test_fd_speedX(struct torture_context *test,
+ const void *test_data,
+ size_t additional_fdes)
+{
+ struct tevent_context *ev_ctx = NULL;
+ int fd[2] = { -1, -1 };
+ const char *backend = (const char *)test_data;
+ struct tevent_fd *fde_read = NULL;
+ struct tevent_fd *fde_write = NULL;
+ int finished=0;
+ struct timeval t;
+ size_t i;
+ int ret;
+
+ ev_ctx = test_tevent_context_init_byname(test, backend);
+ if (ev_ctx == NULL) {
+ torture_comment(test, "event backend '%s' not supported\n", backend);
+ return true;
+ }
+
+ torture_comment(test, "backend '%s' - test_fd_speed%zu\n",
+ backend, 1 + additional_fdes);
+
+ /* reset globals */
+ fde_count = 0;
+
+ /* create a pipe */
+ ret = pipe(fd);
+ torture_assert_int_equal(test, ret, 0, "pipe failed");
+
+ fde_read = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
+ fde_handler_do_read, fd);
+
+ fde_write = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_WRITE,
+ fde_handler_do_write, fd);
+
+ for (i = 0; i < additional_fdes; i++) {
+ tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_WRITE,
+ fde_handler_ignore, fd);
+ tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_READ,
+ fde_handler_ignore, fd);
+ }
+
+ tevent_fd_set_auto_close(fde_read);
+ tevent_fd_set_auto_close(fde_write);
+
+ tevent_add_timer(ev_ctx, ev_ctx, timeval_current_ofs(600,0),
+ finished_handler, &finished);
+
+ t = timeval_current();
+ while (!finished && fde_count < 1000000) {
+ errno = 0;
+ if (tevent_loop_once(ev_ctx) == -1) {
+ TALLOC_FREE(ev_ctx);
+ torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
+ return false;
+ }
+ }
+
+ talloc_free(fde_read);
+ talloc_free(fde_write);
+
+ torture_comment(test, "Got %.2f pipe events\n", (double)fde_count);
+ torture_comment(test, "Got %.2f pipe events/sec\n", fde_count/timeval_elapsed(&t));
+
+ talloc_free(ev_ctx);
+
+ return true;
+}
+
+static bool test_fd_speed1(struct torture_context *test,
+ const void *test_data)
+{
+ return test_fd_speedX(test, test_data, 0);
+}
+
+static bool test_fd_speed2(struct torture_context *test,
+ const void *test_data)
+{
+ return test_fd_speedX(test, test_data, 1);
+}
+
+static bool test_fd_speed3(struct torture_context *test,
+ const void *test_data)
+{
+ return test_fd_speedX(test, test_data, 2);
+}
+
+struct test_event_fd1_state {
+ struct torture_context *tctx;
+ const char *backend;
+ struct tevent_context *ev;
+ int sock[2];
+ struct tevent_timer *te;
+ struct tevent_fd *fde0;
+ struct tevent_fd *fde1;
+ bool got_write;
+ bool got_read;
+ bool drain;
+ bool drain_done;
+ unsigned loop_count;
+ bool finished;
+ const char *error;
+};
+
+static void test_event_fd1_fde_handler(struct tevent_context *ev_ctx,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_event_fd1_state *state =
+ (struct test_event_fd1_state *)private_data;
+
+ if (state->drain_done) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (state->drain) {
+ ssize_t ret;
+ uint8_t c = 0;
+
+ if (!(flags & TEVENT_FD_READ)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ ret = read(state->sock[0], &c, 1);
+ if (ret == 1) {
+ return;
+ }
+
+ /*
+ * end of test...
+ */
+ tevent_fd_set_flags(fde, 0);
+ state->drain_done = true;
+ return;
+ }
+
+ if (!state->got_write) {
+ uint8_t c = 0;
+
+ if (flags != TEVENT_FD_WRITE) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ state->got_write = true;
+
+ /*
+ * we write to the other socket...
+ */
+ do_write(state->sock[1], &c, 1);
+ TEVENT_FD_NOT_WRITEABLE(fde);
+ TEVENT_FD_READABLE(fde);
+ return;
+ }
+
+ if (!state->got_read) {
+ if (flags != TEVENT_FD_READ) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ state->got_read = true;
+
+ TEVENT_FD_NOT_READABLE(fde);
+ return;
+ }
+
+ state->finished = true;
+ state->error = __location__;
+ return;
+}
+
+static void test_event_fd1_finished(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd1_state *state =
+ (struct test_event_fd1_state *)private_data;
+
+ if (state->drain_done) {
+ state->finished = true;
+ return;
+ }
+
+ if (!state->got_write) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (!state->got_read) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ state->loop_count++;
+ if (state->loop_count > 3) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ state->got_write = false;
+ state->got_read = false;
+
+ tevent_fd_set_flags(state->fde0, TEVENT_FD_WRITE);
+
+ if (state->loop_count > 2) {
+ state->drain = true;
+ TALLOC_FREE(state->fde1);
+ TEVENT_FD_READABLE(state->fde0);
+ }
+
+ state->te = tevent_add_timer(state->ev, state->ev,
+ timeval_current_ofs(0,2000),
+ test_event_fd1_finished, state);
+}
+
+static bool test_event_fd1(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_event_fd1_state state;
+ int ret;
+
+ ZERO_STRUCT(state);
+ state.tctx = tctx;
+ state.backend = (const char *)test_data;
+
+ state.ev = test_tevent_context_init_byname(tctx, state.backend);
+ if (state.ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ state.backend));
+ return true;
+ }
+
+ torture_comment(tctx, "backend '%s' - %s\n",
+ state.backend, __FUNCTION__);
+
+ /*
+ * This tests the following:
+ *
+ * It monitors the state of state.sock[0]
+ * with tevent_fd, but we never read/write on state.sock[0]
+ * while state.sock[1] * is only used to write a few bytes.
+ *
+ * We have a loop:
+ * - we wait only for TEVENT_FD_WRITE on state.sock[0]
+ * - we write 1 byte to state.sock[1]
+ * - we wait only for TEVENT_FD_READ on state.sock[0]
+ * - we disable events on state.sock[0]
+ * - the timer event restarts the loop
+ * Then we close state.sock[1]
+ * We have a loop:
+ * - we wait for TEVENT_FD_READ/WRITE on state.sock[0]
+ * - we try to read 1 byte
+ * - if the read gets an error of returns 0
+ * we disable the event handler
+ * - the timer finishes the test
+ */
+ state.sock[0] = -1;
+ state.sock[1] = -1;
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, state.sock);
+ torture_assert(tctx, ret == 0, "socketpair() failed");
+
+ state.te = tevent_add_timer(state.ev, state.ev,
+ timeval_current_ofs(0,10000),
+ test_event_fd1_finished, &state);
+ state.fde0 = tevent_add_fd(state.ev, state.ev,
+ state.sock[0], TEVENT_FD_WRITE,
+ test_event_fd1_fde_handler, &state);
+ /* state.fde1 is only used to auto close */
+ state.fde1 = tevent_add_fd(state.ev, state.ev,
+ state.sock[1], 0,
+ test_event_fd1_fde_handler, &state);
+
+ tevent_fd_set_auto_close(state.fde0);
+ tevent_fd_set_auto_close(state.fde1);
+
+ while (!state.finished) {
+ errno = 0;
+ if (tevent_loop_once(state.ev) == -1) {
+ talloc_free(state.ev);
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "Failed event loop %s\n",
+ strerror(errno)));
+ }
+ }
+
+ talloc_free(state.ev);
+
+ torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx,
+ "%s", state.error));
+
+ return true;
+}
+
+struct test_event_fd2_state {
+ struct torture_context *tctx;
+ const char *backend;
+ struct tevent_context *ev;
+ struct tevent_timer *te;
+ struct test_event_fd2_sock {
+ struct test_event_fd2_state *state;
+ int fd;
+ struct tevent_fd *fde;
+ size_t num_written;
+ size_t num_read;
+ bool got_full;
+ } sock0, sock1;
+ bool finished;
+ const char *error;
+};
+
+static void test_event_fd2_sock_handler(struct tevent_context *ev_ctx,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_event_fd2_sock *cur_sock =
+ (struct test_event_fd2_sock *)private_data;
+ struct test_event_fd2_state *state = cur_sock->state;
+ struct test_event_fd2_sock *oth_sock = NULL;
+ uint8_t v = 0, c;
+ ssize_t ret;
+
+ if (cur_sock == &state->sock0) {
+ oth_sock = &state->sock1;
+ } else {
+ oth_sock = &state->sock0;
+ }
+
+ if (oth_sock->num_written == 1) {
+ if (flags != (TEVENT_FD_READ | TEVENT_FD_WRITE)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ }
+
+ if (cur_sock->num_read == oth_sock->num_written) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (!(flags & TEVENT_FD_READ)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (oth_sock->num_read >= PIPE_BUF) {
+ /*
+ * On Linux we become writable once we've read
+ * one byte. On Solaris we only become writable
+ * again once we've read 4096 bytes. PIPE_BUF
+ * is probably a safe bet to test against.
+ *
+ * There should be room to write a byte again
+ */
+ if (!(flags & TEVENT_FD_WRITE)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ }
+
+ if ((flags & TEVENT_FD_WRITE) && !cur_sock->got_full) {
+ v = (uint8_t)cur_sock->num_written;
+ ret = write(cur_sock->fd, &v, 1);
+ if (ret != 1) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ cur_sock->num_written++;
+ if (cur_sock->num_written > 0x80000000) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ return;
+ }
+
+ if (!cur_sock->got_full) {
+ cur_sock->got_full = true;
+
+ if (!oth_sock->got_full) {
+ /*
+ * cur_sock is full,
+ * lets wait for oth_sock
+ * to be filled
+ */
+ tevent_fd_set_flags(cur_sock->fde, 0);
+ return;
+ }
+
+ /*
+ * oth_sock waited for cur_sock,
+ * lets restart it
+ */
+ tevent_fd_set_flags(oth_sock->fde,
+ TEVENT_FD_READ|TEVENT_FD_WRITE);
+ }
+
+ ret = read(cur_sock->fd, &v, 1);
+ if (ret != 1) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ c = (uint8_t)cur_sock->num_read;
+ if (c != v) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ cur_sock->num_read++;
+
+ if (cur_sock->num_read < oth_sock->num_written) {
+ /* there is more to read */
+ return;
+ }
+ /*
+ * we read everything, we need to remove TEVENT_FD_WRITE
+ * to avoid spinning
+ */
+ TEVENT_FD_NOT_WRITEABLE(cur_sock->fde);
+
+ if (oth_sock->num_read == cur_sock->num_written) {
+ /*
+ * both directions are finished
+ */
+ state->finished = true;
+ }
+
+ return;
+}
+
+static void test_event_fd2_finished(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd2_state *state =
+ (struct test_event_fd2_state *)private_data;
+
+ /*
+ * this should never be triggered
+ */
+ state->finished = true;
+ state->error = __location__;
+}
+
+static bool test_event_fd2(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_event_fd2_state state;
+ int sock[2];
+ uint8_t c = 0;
+
+ ZERO_STRUCT(state);
+ state.tctx = tctx;
+ state.backend = (const char *)test_data;
+
+ state.ev = test_tevent_context_init_byname(tctx, state.backend);
+ if (state.ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ state.backend));
+ return true;
+ }
+
+ torture_comment(tctx, "backend '%s' - %s\n",
+ state.backend, __FUNCTION__);
+
+ /*
+ * This tests the following
+ *
+ * - We write 1 byte to each socket
+ * - We wait for TEVENT_FD_READ/WRITE on both sockets
+ * - When we get TEVENT_FD_WRITE we write 1 byte
+ * until both socket buffers are full, which
+ * means both sockets only get TEVENT_FD_READ.
+ * - Then we read 1 byte until we have consumed
+ * all bytes the other end has written.
+ */
+ sock[0] = -1;
+ sock[1] = -1;
+ socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+
+ /*
+ * the timer should never expire
+ */
+ state.te = tevent_add_timer(state.ev, state.ev,
+ timeval_current_ofs(600, 0),
+ test_event_fd2_finished, &state);
+ state.sock0.state = &state;
+ state.sock0.fd = sock[0];
+ state.sock0.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ TEVENT_FD_READ | TEVENT_FD_WRITE,
+ test_event_fd2_sock_handler,
+ &state.sock0);
+ state.sock1.state = &state;
+ state.sock1.fd = sock[1];
+ state.sock1.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ TEVENT_FD_READ | TEVENT_FD_WRITE,
+ test_event_fd2_sock_handler,
+ &state.sock1);
+
+ tevent_fd_set_auto_close(state.sock0.fde);
+ tevent_fd_set_auto_close(state.sock1.fde);
+
+ do_write(state.sock0.fd, &c, 1);
+ state.sock0.num_written++;
+ do_write(state.sock1.fd, &c, 1);
+ state.sock1.num_written++;
+
+ while (!state.finished) {
+ errno = 0;
+ if (tevent_loop_once(state.ev) == -1) {
+ talloc_free(state.ev);
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "Failed event loop %s\n",
+ strerror(errno)));
+ }
+ }
+
+ talloc_free(state.ev);
+
+ torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx,
+ "%s", state.error));
+
+ return true;
+}
+
+struct test_event_fd3_state {
+ struct torture_context *tctx;
+ const char *backend;
+ struct tevent_context *ev;
+ struct timeval start_time;
+ struct tevent_timer *te1, *te2, *te3, *te4, *te5;
+ struct test_event_fd3_sock {
+ struct test_event_fd3_state *state;
+ const char *sock_name;
+ int fd;
+ const char *phase_name;
+ uint64_t iteration_id;
+ uint64_t max_iterations;
+ uint16_t expected_flags;
+ uint8_t expected_count;
+ uint8_t actual_count;
+ struct test_event_fd3_fde {
+ struct test_event_fd3_sock *sock;
+ struct tevent_fd *fde;
+ uint64_t last_iteration_id;
+ } fde1, fde2, fde3, fde4, fde5, fde6, fde7, fde8, fde9;
+ void (*fde_callback)(struct test_event_fd3_fde *tfde,
+ uint16_t flags);
+ } sock0, sock1;
+ bool finished;
+ const char *error;
+};
+
+static void test_event_fd3_fde_callback(struct test_event_fd3_fde *tfde,
+ uint16_t flags)
+{
+ struct test_event_fd3_sock *sock = tfde->sock;
+ struct test_event_fd3_state *state = sock->state;
+ uint16_t fde_flags = tevent_fd_get_flags(tfde->fde);
+ uint16_t expected_flags = sock->expected_flags & fde_flags;
+
+ if (expected_flags == 0) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (flags != expected_flags) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (tfde->last_iteration_id == sock->iteration_id) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ tfde->last_iteration_id = sock->iteration_id;
+
+ sock->actual_count += 1;
+
+ if (sock->actual_count > sock->expected_count) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (sock->actual_count == sock->expected_count) {
+ sock->actual_count = 0;
+ sock->iteration_id += 1;
+ }
+
+ if (sock->iteration_id > sock->max_iterations) {
+ torture_comment(state->tctx,
+ "%s: phase[%s] finished with %"PRIu64" iterations\n",
+ sock->sock_name,
+ sock->phase_name,
+ sock->max_iterations);
+ tevent_fd_set_flags(sock->fde1.fde, 0);
+ tevent_fd_set_flags(sock->fde2.fde, 0);
+ tevent_fd_set_flags(sock->fde3.fde, 0);
+ tevent_fd_set_flags(sock->fde4.fde, 0);
+ tevent_fd_set_flags(sock->fde5.fde, 0);
+ tevent_fd_set_flags(sock->fde6.fde, 0);
+ tevent_fd_set_flags(sock->fde7.fde, 0);
+ tevent_fd_set_flags(sock->fde8.fde, 0);
+ tevent_fd_set_flags(sock->fde9.fde, 0);
+ sock->fde_callback = NULL;
+ }
+}
+
+static void test_event_fd3_prepare_phase(struct test_event_fd3_sock *sock,
+ const char *phase_name,
+ uint64_t max_iterations,
+ uint16_t expected_flags,
+ uint8_t expected_count,
+ uint16_t flags1,
+ uint16_t flags2,
+ uint16_t flags3,
+ uint16_t flags4,
+ uint16_t flags5,
+ uint16_t flags6,
+ uint16_t flags7,
+ uint16_t flags8,
+ uint16_t flags9)
+{
+ struct test_event_fd3_state *state = sock->state;
+
+ if (sock->fde_callback != NULL) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ sock->phase_name = phase_name;
+ sock->max_iterations = max_iterations;
+ sock->expected_flags = expected_flags;
+ sock->expected_count = expected_count;
+ sock->iteration_id = 1;
+ sock->actual_count = 0;
+
+ tevent_fd_set_flags(sock->fde1.fde, flags1);
+ sock->fde1.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde2.fde, flags2);
+ sock->fde2.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde3.fde, flags3);
+ sock->fde3.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde4.fde, flags4);
+ sock->fde4.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde5.fde, flags5);
+ sock->fde5.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde6.fde, flags6);
+ sock->fde6.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde7.fde, flags7);
+ sock->fde7.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde8.fde, flags8);
+ sock->fde8.last_iteration_id = 0;
+ tevent_fd_set_flags(sock->fde9.fde, flags9);
+ sock->fde9.last_iteration_id = 0;
+
+ sock->fde_callback = test_event_fd3_fde_callback;
+}
+
+static void test_event_fd3_sock_handler(struct tevent_context *ev_ctx,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_event_fd3_fde *tfde =
+ (struct test_event_fd3_fde *)private_data;
+ struct test_event_fd3_sock *sock = tfde->sock;
+ struct test_event_fd3_state *state = sock->state;
+
+ if (sock->fd == -1) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (sock->fde_callback == NULL) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ sock->fde_callback(tfde, flags);
+ return;
+}
+
+static bool test_event_fd3_assert_timeout(struct test_event_fd3_state *state,
+ double expected_elapsed,
+ const char *func)
+{
+ double e = timeval_elapsed(&state->start_time);
+ double max_latency = 0.05;
+
+ if (e < expected_elapsed) {
+ torture_comment(state->tctx,
+ "%s: elapsed=%.6f < expected_elapsed=%.6f\n",
+ func, e, expected_elapsed);
+ state->finished = true;
+ state->error = __location__;
+ return false;
+ }
+
+ if (e > (expected_elapsed + max_latency)) {
+ torture_comment(state->tctx,
+ "%s: elapsed=%.6f > "
+ "(expected_elapsed=%.6f + max_latency=%.6f)\n",
+ func, e, expected_elapsed, max_latency);
+ state->finished = true;
+ state->error = __location__;
+ return false;
+ }
+
+ torture_comment(state->tctx, "%s: elapsed=%.6f\n", __func__, e);
+ return true;
+}
+
+static void test_event_fd3_writeable(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd3_state *state =
+ (struct test_event_fd3_state *)private_data;
+
+ if (!test_event_fd3_assert_timeout(state, 1, __func__)) {
+ return;
+ }
+
+ test_event_fd3_prepare_phase(&state->sock0,
+ __func__,
+ INT8_MAX,
+ TEVENT_FD_WRITE,
+ 5,
+ TEVENT_FD_WRITE,
+ 0,
+ TEVENT_FD_READ,
+ TEVENT_FD_WRITE,
+ TEVENT_FD_READ|TEVENT_FD_WRITE,
+ TEVENT_FD_READ,
+ TEVENT_FD_WRITE,
+ TEVENT_FD_READ|TEVENT_FD_WRITE,
+ 0);
+
+ test_event_fd3_prepare_phase(&state->sock1,
+ __func__,
+ INT8_MAX,
+ TEVENT_FD_WRITE,
+ 9,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR);
+}
+
+static void test_event_fd3_readable(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd3_state *state =
+ (struct test_event_fd3_state *)private_data;
+ uint8_t c = 0;
+
+ if (!test_event_fd3_assert_timeout(state, 2, __func__)) {
+ return;
+ }
+
+ do_write(state->sock0.fd, &c, 1);
+ do_write(state->sock1.fd, &c, 1);
+
+ test_event_fd3_prepare_phase(&state->sock0,
+ __func__,
+ INT8_MAX,
+ TEVENT_FD_READ|TEVENT_FD_WRITE,
+ 9,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR);
+
+ test_event_fd3_prepare_phase(&state->sock1,
+ __func__,
+ INT8_MAX,
+ TEVENT_FD_READ|TEVENT_FD_WRITE,
+ 7,
+ TEVENT_FD_READ,
+ TEVENT_FD_READ|TEVENT_FD_WRITE,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ 0,
+ TEVENT_FD_READ,
+ TEVENT_FD_WRITE,
+ TEVENT_FD_ERROR,
+ TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE);
+}
+
+static void test_event_fd3_not_writeable(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd3_state *state =
+ (struct test_event_fd3_state *)private_data;
+
+ if (!test_event_fd3_assert_timeout(state, 3, __func__)) {
+ return;
+ }
+
+ do_fill(state->sock0.fd);
+ do_fill(state->sock1.fd);
+
+ test_event_fd3_prepare_phase(&state->sock0,
+ __func__,
+ INT8_MAX,
+ TEVENT_FD_READ,
+ 5,
+ TEVENT_FD_READ|TEVENT_FD_WRITE,
+ TEVENT_FD_WRITE,
+ TEVENT_FD_READ,
+ 0,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_ERROR,
+ TEVENT_FD_ERROR,
+ TEVENT_FD_READ);
+
+ test_event_fd3_prepare_phase(&state->sock1,
+ __func__,
+ INT8_MAX,
+ TEVENT_FD_READ,
+ 9,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR);
+}
+
+static void test_event_fd3_off(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd3_state *state =
+ (struct test_event_fd3_state *)private_data;
+
+ if (!test_event_fd3_assert_timeout(state, 4, __func__)) {
+ return;
+ }
+
+ TALLOC_FREE(state->sock0.fde1.fde);
+ state->sock0.fd = -1;
+
+ test_event_fd3_prepare_phase(&state->sock1,
+ __func__,
+ INT8_MAX,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ 7,
+ TEVENT_FD_READ|TEVENT_FD_WRITE,
+ TEVENT_FD_WRITE,
+ TEVENT_FD_READ,
+ 0,
+ TEVENT_FD_READ|TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_WRITE|TEVENT_FD_ERROR,
+ TEVENT_FD_READ|TEVENT_FD_ERROR,
+ TEVENT_FD_ERROR,
+ TEVENT_FD_READ);
+}
+
+static void test_event_fd3_finished(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd3_state *state =
+ (struct test_event_fd3_state *)private_data;
+
+ if (!test_event_fd3_assert_timeout(state, 5, __func__)) {
+ return;
+ }
+
+ /*
+ * this should never be triggered
+ */
+ if (state->sock0.fde_callback != NULL) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ if (state->sock1.fde_callback != NULL) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ state->finished = true;
+}
+
+static bool test_event_fd3(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_event_fd3_state state = {
+ .tctx = tctx,
+ .backend = (const char *)test_data,
+ };
+ int rc;
+ int sock[2];
+
+ state.ev = test_tevent_context_init_byname(tctx, state.backend);
+ if (state.ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ state.backend));
+ return true;
+ }
+
+ torture_comment(tctx, "backend '%s' - %s\n",
+ state.backend, __FUNCTION__);
+
+ sock[0] = -1;
+ sock[1] = -1;
+ rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+ torture_assert_int_equal(tctx, rc, 0, "socketpair()");
+
+ state.start_time = timeval_current();
+ state.te1 = tevent_add_timer(state.ev, state.ev,
+ timeval_add(&state.start_time, 5, 0),
+ test_event_fd3_finished, &state);
+ torture_assert(tctx, state.te1 != NULL, "tevent_add_timer()");
+ state.te2 = tevent_add_timer(state.ev, state.ev,
+ timeval_add(&state.start_time, 1, 0),
+ test_event_fd3_writeable, &state);
+ torture_assert(tctx, state.te2 != NULL, "tevent_add_timer()");
+ state.te3 = tevent_add_timer(state.ev, state.ev,
+ timeval_add(&state.start_time, 2, 0),
+ test_event_fd3_readable, &state);
+ torture_assert(tctx, state.te3 != NULL, "tevent_add_timer()");
+ state.te4 = tevent_add_timer(state.ev, state.ev,
+ timeval_add(&state.start_time, 3, 0),
+ test_event_fd3_not_writeable, &state);
+ torture_assert(tctx, state.te4 != NULL, "tevent_add_timer()");
+ state.te5 = tevent_add_timer(state.ev, state.ev,
+ timeval_add(&state.start_time, 4, 0),
+ test_event_fd3_off, &state);
+ torture_assert(tctx, state.te5 != NULL, "tevent_add_timer()");
+
+ state.sock0.state = &state;
+ state.sock0.sock_name = "sock0";
+ state.sock0.fd = sock[0];
+ state.sock0.fde1.sock = &state.sock0;
+ state.sock0.fde1.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde1);
+ torture_assert(tctx, state.sock0.fde1.fde != NULL, "tevent_add_fd()");
+ tevent_fd_set_auto_close(state.sock0.fde1.fde);
+ state.sock0.fde2.sock = &state.sock0;
+ state.sock0.fde2.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde2);
+ torture_assert(tctx, state.sock0.fde2.fde != NULL, "tevent_add_fd()");
+ state.sock0.fde3.sock = &state.sock0;
+ state.sock0.fde3.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde3);
+ torture_assert(tctx, state.sock0.fde3.fde != NULL, "tevent_add_fd()");
+ state.sock0.fde4.sock = &state.sock0;
+ state.sock0.fde4.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde4);
+ torture_assert(tctx, state.sock0.fde4.fde != NULL, "tevent_add_fd()");
+ state.sock0.fde5.sock = &state.sock0;
+ state.sock0.fde5.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde5);
+ torture_assert(tctx, state.sock0.fde5.fde != NULL, "tevent_add_fd()");
+ state.sock0.fde6.sock = &state.sock0;
+ state.sock0.fde6.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde6);
+ torture_assert(tctx, state.sock0.fde6.fde != NULL, "tevent_add_fd()");
+ state.sock0.fde7.sock = &state.sock0;
+ state.sock0.fde7.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde7);
+ torture_assert(tctx, state.sock0.fde7.fde != NULL, "tevent_add_fd()");
+ state.sock0.fde8.sock = &state.sock0;
+ state.sock0.fde8.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde8);
+ torture_assert(tctx, state.sock0.fde8.fde != NULL, "tevent_add_fd()");
+ state.sock0.fde9.sock = &state.sock0;
+ state.sock0.fde9.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock0.fde9);
+ torture_assert(tctx, state.sock0.fde9.fde != NULL, "tevent_add_fd()");
+
+ state.sock1.state = &state;
+ state.sock1.sock_name = "sock1";
+ state.sock1.fd = sock[1];
+ state.sock1.fde1.sock = &state.sock1;
+ state.sock1.fde1.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 1,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde1);
+ torture_assert(tctx, state.sock1.fde1.fde != NULL, "tevent_add_fd()");
+ tevent_fd_set_auto_close(state.sock1.fde1.fde);
+ state.sock1.fde2.sock = &state.sock1;
+ state.sock1.fde2.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde2);
+ torture_assert(tctx, state.sock1.fde2.fde != NULL, "tevent_add_fd()");
+ state.sock1.fde3.sock = &state.sock1;
+ state.sock1.fde3.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde3);
+ torture_assert(tctx, state.sock1.fde3.fde != NULL, "tevent_add_fd()");
+ state.sock1.fde4.sock = &state.sock1;
+ state.sock1.fde4.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde4);
+ torture_assert(tctx, state.sock1.fde4.fde != NULL, "tevent_add_fd()");
+ state.sock1.fde5.sock = &state.sock1;
+ state.sock1.fde5.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde5);
+ torture_assert(tctx, state.sock1.fde5.fde != NULL, "tevent_add_fd()");
+ state.sock1.fde6.sock = &state.sock1;
+ state.sock1.fde6.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde6);
+ torture_assert(tctx, state.sock1.fde6.fde != NULL, "tevent_add_fd()");
+ state.sock1.fde7.sock = &state.sock1;
+ state.sock1.fde7.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde7);
+ torture_assert(tctx, state.sock1.fde7.fde != NULL, "tevent_add_fd()");
+ state.sock1.fde8.sock = &state.sock1;
+ state.sock1.fde8.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde8);
+ torture_assert(tctx, state.sock1.fde8.fde != NULL, "tevent_add_fd()");
+ state.sock1.fde9.sock = &state.sock1;
+ state.sock1.fde9.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ 0,
+ test_event_fd3_sock_handler,
+ &state.sock1.fde9);
+ torture_assert(tctx, state.sock1.fde9.fde != NULL, "tevent_add_fd()");
+
+ while (!state.finished) {
+ errno = 0;
+ if (tevent_loop_once(state.ev) == -1) {
+ talloc_free(state.ev);
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "Failed event loop %s\n",
+ strerror(errno)));
+ }
+ }
+
+ talloc_free(state.ev);
+
+ torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx,
+ "%s", state.error));
+
+ return true;
+}
+
+struct test_wrapper_state {
+ struct torture_context *tctx;
+ int num_events;
+ int num_wrap_handlers;
+};
+
+static bool test_wrapper_before_use(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+ return true;
+}
+
+static void test_wrapper_after_use(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_fd_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_fd_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_timer_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_timer_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_immediate_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_immediate_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_signal_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_signal_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static const struct tevent_wrapper_ops test_wrapper_ops = {
+ .name = "test_wrapper",
+ .before_use = test_wrapper_before_use,
+ .after_use = test_wrapper_after_use,
+ .before_fd_handler = test_wrapper_before_fd_handler,
+ .after_fd_handler = test_wrapper_after_fd_handler,
+ .before_timer_handler = test_wrapper_before_timer_handler,
+ .after_timer_handler = test_wrapper_after_timer_handler,
+ .before_immediate_handler = test_wrapper_before_immediate_handler,
+ .after_immediate_handler = test_wrapper_after_immediate_handler,
+ .before_signal_handler = test_wrapper_before_signal_handler,
+ .after_signal_handler = test_wrapper_after_signal_handler,
+};
+
+static void test_wrapper_timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+
+ torture_comment(state->tctx, "timer handler\n");
+
+ state->num_events++;
+ talloc_free(te);
+ return;
+}
+
+static void test_wrapper_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ unsigned short fd_flags,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+ torture_comment(state->tctx, "fd handler\n");
+
+ state->num_events++;
+ talloc_free(fde);
+ return;
+}
+
+static void test_wrapper_immediate_handler(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+ state->num_events++;
+ talloc_free(im);
+
+ torture_comment(state->tctx, "immediate handler\n");
+ return;
+}
+
+static void test_wrapper_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+ torture_comment(state->tctx, "signal handler\n");
+
+ state->num_events++;
+ talloc_free(se);
+ return;
+}
+
+static bool test_wrapper(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_wrapper_state *state = NULL;
+ int sock[2] = { -1, -1};
+ uint8_t c = 0;
+ const int num_events = 4;
+ const char *backend = (const char *)test_data;
+ struct tevent_context *ev = NULL;
+ struct tevent_context *wrap_ev = NULL;
+ struct tevent_fd *fde = NULL;
+ struct tevent_timer *te = NULL;
+ struct tevent_signal *se = NULL;
+ struct tevent_immediate *im = NULL;
+ int ret;
+ bool ok = false;
+ bool ret2;
+
+ ev = test_tevent_context_init_byname(tctx, backend);
+ if (ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ backend));
+ return true;
+ }
+
+ torture_comment(tctx, "tevent backend '%s'\n", backend);
+
+ wrap_ev = tevent_context_wrapper_create(
+ ev, ev, &test_wrapper_ops, &state, struct test_wrapper_state);
+ torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
+ "tevent_context_wrapper_create failed\n");
+ *state = (struct test_wrapper_state) {
+ .tctx = tctx,
+ };
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+ torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
+
+ te = tevent_add_timer(wrap_ev, wrap_ev,
+ timeval_current_ofs(0, 0),
+ test_wrapper_timer_handler, state);
+ torture_assert_not_null_goto(tctx, te, ok, done,
+ "tevent_add_timer failed\n");
+
+ fde = tevent_add_fd(wrap_ev, wrap_ev,
+ sock[1],
+ TEVENT_FD_READ,
+ test_wrapper_fd_handler,
+ state);
+ torture_assert_not_null_goto(tctx, fde, ok, done,
+ "tevent_add_fd failed\n");
+
+ im = tevent_create_immediate(wrap_ev);
+ torture_assert_not_null_goto(tctx, im, ok, done,
+ "tevent_create_immediate failed\n");
+
+ se = tevent_add_signal(wrap_ev, wrap_ev,
+ SIGUSR1,
+ 0,
+ test_wrapper_signal_handler,
+ state);
+ torture_assert_not_null_goto(tctx, se, ok, done,
+ "tevent_add_signal failed\n");
+
+ do_write(sock[0], &c, 1);
+ kill(getpid(), SIGUSR1);
+ tevent_schedule_immediate(im,
+ wrap_ev,
+ test_wrapper_immediate_handler,
+ state);
+
+ ret2 = tevent_context_push_use(wrap_ev);
+ torture_assert_goto(tctx, ret2, ok, done, "tevent_context_push_use(wrap_ev) failed\n");
+ ret2 = tevent_context_push_use(ev);
+ torture_assert_goto(tctx, ret2, ok, pop_use, "tevent_context_push_use(ev) failed\n");
+ tevent_context_pop_use(ev);
+ tevent_context_pop_use(wrap_ev);
+
+ ret = tevent_loop_wait(ev);
+ torture_assert_int_equal_goto(tctx, ret, 0, ok, done, "tevent_loop_wait failed\n");
+
+ torture_comment(tctx, "Num events: %d\n", state->num_events);
+ torture_comment(tctx, "Num wrap handlers: %d\n",
+ state->num_wrap_handlers);
+
+ torture_assert_int_equal_goto(tctx, state->num_events, num_events, ok, done,
+ "Wrong event count\n");
+ torture_assert_int_equal_goto(tctx, state->num_wrap_handlers,
+ num_events*2+2,
+ ok, done, "Wrong wrapper count\n");
+
+ ok = true;
+
+done:
+ TALLOC_FREE(wrap_ev);
+ TALLOC_FREE(ev);
+
+ if (sock[0] != -1) {
+ close(sock[0]);
+ }
+ if (sock[1] != -1) {
+ close(sock[1]);
+ }
+ return ok;
+pop_use:
+ tevent_context_pop_use(wrap_ev);
+ goto done;
+}
+
+static void test_free_wrapper_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct torture_context *tctx =
+ talloc_get_type_abort(private_data,
+ struct torture_context);
+
+ torture_comment(tctx, "signal handler\n");
+
+ talloc_free(se);
+
+ /*
+ * signal handlers have highest priority in tevent, so this signal
+ * handler will always be started before the other handlers
+ * below. Freeing the (wrapper) event context here tests that the
+ * wrapper implementation correctly handles the wrapper ev going away
+ * with pending events.
+ */
+ talloc_free(ev);
+ return;
+}
+
+static void test_free_wrapper_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ unsigned short fd_flags,
+ void *private_data)
+{
+ /*
+ * This should never be called as
+ * test_free_wrapper_signal_handler()
+ * already destroyed the wrapper tevent_context.
+ */
+ abort();
+}
+
+static void test_free_wrapper_immediate_handler(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ /*
+ * This should never be called as
+ * test_free_wrapper_signal_handler()
+ * already destroyed the wrapper tevent_context.
+ */
+ abort();
+}
+
+static void test_free_wrapper_timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv,
+ void *private_data)
+{
+ /*
+ * This should never be called as
+ * test_free_wrapper_signal_handler()
+ * already destroyed the wrapper tevent_context.
+ */
+ abort();
+}
+
+static bool test_free_wrapper(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_wrapper_state *state = NULL;
+ int sock[2] = { -1, -1};
+ uint8_t c = 0;
+ const char *backend = (const char *)test_data;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = NULL;
+ struct tevent_context *wrap_ev = NULL;
+ struct tevent_fd *fde = NULL;
+ struct tevent_timer *te = NULL;
+ struct tevent_signal *se = NULL;
+ struct tevent_immediate *im = NULL;
+ int ret;
+ bool ok = false;
+
+ ev = test_tevent_context_init_byname(frame, backend);
+ if (ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ backend));
+ return true;
+ }
+
+ torture_comment(tctx, "tevent backend '%s'\n", backend);
+
+ wrap_ev = tevent_context_wrapper_create(
+ ev, ev, &test_wrapper_ops, &state, struct test_wrapper_state);
+ torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
+ "tevent_context_wrapper_create failed\n");
+ *state = (struct test_wrapper_state) {
+ .tctx = tctx,
+ };
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+ torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
+
+ fde = tevent_add_fd(wrap_ev, frame,
+ sock[1],
+ TEVENT_FD_READ,
+ test_free_wrapper_fd_handler,
+ NULL);
+ torture_assert_not_null_goto(tctx, fde, ok, done,
+ "tevent_add_fd failed\n");
+
+ te = tevent_add_timer(wrap_ev, frame,
+ timeval_current_ofs(0, 0),
+ test_free_wrapper_timer_handler, NULL);
+ torture_assert_not_null_goto(tctx, te, ok, done,
+ "tevent_add_timer failed\n");
+
+ im = tevent_create_immediate(frame);
+ torture_assert_not_null_goto(tctx, im, ok, done,
+ "tevent_create_immediate failed\n");
+
+ se = tevent_add_signal(wrap_ev, frame,
+ SIGUSR1,
+ 0,
+ test_free_wrapper_signal_handler,
+ tctx);
+ torture_assert_not_null_goto(tctx, se, ok, done,
+ "tevent_add_signal failed\n");
+
+ do_write(sock[0], &c, 1);
+ kill(getpid(), SIGUSR1);
+ tevent_schedule_immediate(im,
+ wrap_ev,
+ test_free_wrapper_immediate_handler,
+ NULL);
+
+ ret = tevent_loop_wait(ev);
+ torture_assert_goto(tctx, ret == 0, ok, done, "tevent_loop_wait failed\n");
+
+ ok = true;
+
+done:
+ TALLOC_FREE(frame);
+
+ if (sock[0] != -1) {
+ close(sock[0]);
+ }
+ if (sock[1] != -1) {
+ close(sock[1]);
+ }
+ return ok;
+}
+
+#ifdef HAVE_PTHREAD
+
+static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool do_shutdown = false;
+
+static void test_event_threaded_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&threaded_mutex);
+ assert(ret == 0);
+}
+
+static void test_event_threaded_unlock(void)
+{
+ int ret;
+ ret = pthread_mutex_unlock(&threaded_mutex);
+ assert(ret == 0);
+}
+
+static void test_event_threaded_trace(enum tevent_trace_point point,
+ void *private_data)
+{
+ switch (point) {
+ case TEVENT_TRACE_BEFORE_WAIT:
+ test_event_threaded_unlock();
+ break;
+ case TEVENT_TRACE_AFTER_WAIT:
+ test_event_threaded_lock();
+ break;
+ case TEVENT_TRACE_BEFORE_LOOP_ONCE:
+ case TEVENT_TRACE_AFTER_LOOP_ONCE:
+ break;
+ }
+}
+
+static void test_event_threaded_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ return;
+}
+
+static void *test_event_poll_thread(void *private_data)
+{
+ struct tevent_context *ev = (struct tevent_context *)private_data;
+
+ test_event_threaded_lock();
+
+ while (true) {
+ int ret;
+ ret = tevent_loop_once(ev);
+ assert(ret == 0);
+ if (do_shutdown) {
+ test_event_threaded_unlock();
+ return NULL;
+ }
+ }
+
+}
+
+static void test_event_threaded_read_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ int *pfd = (int *)private_data;
+ char c;
+ ssize_t nread;
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ return;
+ }
+
+ do {
+ nread = read(*pfd, &c, 1);
+ } while ((nread == -1) && (errno == EINTR));
+
+ assert(nread == 1);
+}
+
+static bool test_event_context_threaded(struct torture_context *test,
+ const void *test_data)
+{
+ struct tevent_context *ev;
+ struct tevent_timer *te;
+ struct tevent_fd *fde;
+ pthread_t poll_thread;
+ int fds[2];
+ int ret;
+ char c = 0;
+
+ ev = test_tevent_context_init_byname(test, "poll_mt");
+ torture_assert(test, ev != NULL, "poll_mt not supported");
+
+ tevent_set_trace_callback(ev, test_event_threaded_trace, NULL);
+
+ te = tevent_add_timer(ev, ev, timeval_current_ofs(5, 0),
+ test_event_threaded_timer, NULL);
+ torture_assert(test, te != NULL, "Could not add timer");
+
+ ret = pthread_create(&poll_thread, NULL, test_event_poll_thread, ev);
+ torture_assert(test, ret == 0, "Could not create poll thread");
+
+ ret = pipe(fds);
+ torture_assert(test, ret == 0, "Could not create pipe");
+
+ poll(NULL, 0, 100);
+
+ test_event_threaded_lock();
+
+ fde = tevent_add_fd(ev, ev, fds[0], TEVENT_FD_READ,
+ test_event_threaded_read_handler, &fds[0]);
+ torture_assert(test, fde != NULL, "Could not add fd event");
+
+ test_event_threaded_unlock();
+
+ poll(NULL, 0, 100);
+
+ do_write(fds[1], &c, 1);
+
+ poll(NULL, 0, 100);
+
+ test_event_threaded_lock();
+ do_shutdown = true;
+ test_event_threaded_unlock();
+
+ do_write(fds[1], &c, 1);
+
+ ret = pthread_join(poll_thread, NULL);
+ torture_assert(test, ret == 0, "pthread_join failed");
+
+ return true;
+}
+
+#define NUM_TEVENT_THREADS 100
+
+/* Ugly, but needed for torture_comment... */
+static struct torture_context *thread_test_ctx;
+static pthread_t thread_map[NUM_TEVENT_THREADS];
+static unsigned thread_counter;
+
+/* Called in master thread context */
+static void callback_nowait(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_ptr)
+{
+ pthread_t *thread_id_ptr =
+ talloc_get_type_abort(private_ptr, pthread_t);
+ unsigned i;
+
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ if (pthread_equal(*thread_id_ptr,
+ thread_map[i])) {
+ break;
+ }
+ }
+ torture_comment(thread_test_ctx,
+ "Callback %u from thread %u\n",
+ thread_counter,
+ i);
+ thread_counter++;
+}
+
+/* Blast the master tevent_context with a callback, no waiting. */
+static void *thread_fn_nowait(void *private_ptr)
+{
+ struct tevent_thread_proxy *master_tp =
+ talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+ struct tevent_immediate *im;
+ pthread_t *thread_id_ptr;
+
+ im = tevent_create_immediate(NULL);
+ if (im == NULL) {
+ return NULL;
+ }
+ thread_id_ptr = talloc(NULL, pthread_t);
+ if (thread_id_ptr == NULL) {
+ return NULL;
+ }
+ *thread_id_ptr = pthread_self();
+
+ tevent_thread_proxy_schedule(master_tp,
+ &im,
+ callback_nowait,
+ &thread_id_ptr);
+ return NULL;
+}
+
+static void timeout_fn(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *p)
+{
+ thread_counter = NUM_TEVENT_THREADS * 10;
+}
+
+static bool test_multi_tevent_threaded(struct torture_context *test,
+ const void *test_data)
+{
+ unsigned i;
+ struct tevent_context *master_ev;
+ struct tevent_thread_proxy *tp;
+
+ talloc_disable_null_tracking();
+
+ /* Ugly global stuff. */
+ thread_test_ctx = test;
+ thread_counter = 0;
+
+ master_ev = test_tevent_context_init(NULL);
+ if (master_ev == NULL) {
+ return false;
+ }
+
+ tp = tevent_thread_proxy_create(master_ev);
+ if (tp == NULL) {
+ torture_fail(test,
+ talloc_asprintf(test,
+ "tevent_thread_proxy_create failed\n"));
+ talloc_free(master_ev);
+ return false;
+ }
+
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ int ret = pthread_create(&thread_map[i],
+ NULL,
+ thread_fn_nowait,
+ tp);
+ if (ret != 0) {
+ torture_fail(test,
+ talloc_asprintf(test,
+ "Failed to create thread %i, %d\n",
+ i, ret));
+ return false;
+ }
+ }
+
+ /* Ensure we don't wait more than 10 seconds. */
+ tevent_add_timer(master_ev,
+ master_ev,
+ timeval_current_ofs(10,0),
+ timeout_fn,
+ NULL);
+
+ while (thread_counter < NUM_TEVENT_THREADS) {
+ int ret = tevent_loop_once(master_ev);
+ torture_assert(test, ret == 0, "tevent_loop_once failed");
+ }
+
+ torture_assert(test, thread_counter == NUM_TEVENT_THREADS,
+ "thread_counter fail\n");
+
+ talloc_free(master_ev);
+ return true;
+}
+
+struct reply_state {
+ struct tevent_thread_proxy *reply_tp;
+ pthread_t thread_id;
+ int *p_finished;
+};
+
+static void thread_timeout_fn(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *p)
+{
+ int *p_finished = (int *)p;
+
+ *p_finished = 2;
+}
+
+/* Called in child-thread context */
+static void thread_callback(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_ptr)
+{
+ struct reply_state *rsp =
+ talloc_get_type_abort(private_ptr, struct reply_state);
+
+ talloc_steal(ev, rsp);
+ *rsp->p_finished = 1;
+}
+
+/* Called in master thread context */
+static void master_callback(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_ptr)
+{
+ struct reply_state *rsp =
+ talloc_get_type_abort(private_ptr, struct reply_state);
+ unsigned i;
+
+ talloc_steal(ev, rsp);
+
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ if (pthread_equal(rsp->thread_id,
+ thread_map[i])) {
+ break;
+ }
+ }
+ torture_comment(thread_test_ctx,
+ "Callback %u from thread %u\n",
+ thread_counter,
+ i);
+ /* Now reply to the thread ! */
+ tevent_thread_proxy_schedule(rsp->reply_tp,
+ &im,
+ thread_callback,
+ &rsp);
+
+ thread_counter++;
+}
+
+static void *thread_fn_1(void *private_ptr)
+{
+ struct tevent_thread_proxy *master_tp =
+ talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+ struct tevent_thread_proxy *tp;
+ struct tevent_immediate *im;
+ struct tevent_context *ev;
+ struct reply_state *rsp;
+ int finished = 0;
+ int ret;
+
+ ev = tevent_context_init(NULL);
+ if (ev == NULL) {
+ return NULL;
+ }
+
+ tp = tevent_thread_proxy_create(ev);
+ if (tp == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ im = tevent_create_immediate(ev);
+ if (im == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ rsp = talloc(ev, struct reply_state);
+ if (rsp == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ rsp->thread_id = pthread_self();
+ rsp->reply_tp = tp;
+ rsp->p_finished = &finished;
+
+ /* Introduce a little randomness into the mix.. */
+ usleep(random() % 7000);
+
+ tevent_thread_proxy_schedule(master_tp,
+ &im,
+ master_callback,
+ &rsp);
+
+ /* Ensure we don't wait more than 10 seconds. */
+ tevent_add_timer(ev,
+ ev,
+ timeval_current_ofs(10,0),
+ thread_timeout_fn,
+ &finished);
+
+ while (finished == 0) {
+ ret = tevent_loop_once(ev);
+ assert(ret == 0);
+ }
+
+ if (finished > 1) {
+ /* Timeout ! */
+ abort();
+ }
+
+ /*
+ * NB. We should talloc_free(ev) here, but if we do
+ * we currently get hit by helgrind Fix #323432
+ * "When calling pthread_cond_destroy or pthread_mutex_destroy
+ * with initializers as argument Helgrind (incorrectly) reports errors."
+ *
+ * http://valgrind.10908.n7.nabble.com/Helgrind-3-9-0-false-positive-
+ * with-pthread-mutex-destroy-td47757.html
+ *
+ * Helgrind doesn't understand that the request/reply
+ * messages provide synchronization between the lock/unlock
+ * in tevent_thread_proxy_schedule(), and the pthread_destroy()
+ * when the struct tevent_thread_proxy object is talloc_free'd.
+ *
+ * As a work-around for now return ev for the parent thread to free.
+ */
+ return ev;
+}
+
+static bool test_multi_tevent_threaded_1(struct torture_context *test,
+ const void *test_data)
+{
+ unsigned i;
+ struct tevent_context *master_ev;
+ struct tevent_thread_proxy *master_tp;
+ int ret;
+
+ talloc_disable_null_tracking();
+
+ /* Ugly global stuff. */
+ thread_test_ctx = test;
+ thread_counter = 0;
+
+ master_ev = test_tevent_context_init(NULL);
+ if (master_ev == NULL) {
+ return false;
+ }
+
+ master_tp = tevent_thread_proxy_create(master_ev);
+ if (master_tp == NULL) {
+ torture_fail(test,
+ talloc_asprintf(test,
+ "tevent_thread_proxy_create failed\n"));
+ talloc_free(master_ev);
+ return false;
+ }
+
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ ret = pthread_create(&thread_map[i],
+ NULL,
+ thread_fn_1,
+ master_tp);
+ if (ret != 0) {
+ torture_fail(test,
+ talloc_asprintf(test,
+ "Failed to create thread %i, %d\n",
+ i, ret));
+ return false;
+ }
+ }
+
+ while (thread_counter < NUM_TEVENT_THREADS) {
+ ret = tevent_loop_once(master_ev);
+ torture_assert(test, ret == 0, "tevent_loop_once failed");
+ }
+
+ /* Wait for all the threads to finish - join 'em. */
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ void *retval;
+ ret = pthread_join(thread_map[i], &retval);
+ torture_assert(test, ret == 0, "pthread_join failed");
+ /* Free the child thread event context. */
+ talloc_free(retval);
+ }
+
+ talloc_free(master_ev);
+ return true;
+}
+
+struct threaded_test_2 {
+ struct tevent_threaded_context *tctx;
+ struct tevent_immediate *im;
+ pthread_t thread_id;
+};
+
+static void master_callback_2(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static void *thread_fn_2(void *private_data)
+{
+ struct threaded_test_2 *state = private_data;
+
+ state->thread_id = pthread_self();
+
+ usleep(random() % 7000);
+
+ tevent_threaded_schedule_immediate(
+ state->tctx, state->im, master_callback_2, state);
+
+ return NULL;
+}
+
+static void master_callback_2(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct threaded_test_2 *state = private_data;
+ int i;
+
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ if (pthread_equal(state->thread_id, thread_map[i])) {
+ break;
+ }
+ }
+ torture_comment(thread_test_ctx,
+ "Callback_2 %u from thread %u\n",
+ thread_counter,
+ i);
+ thread_counter++;
+}
+
+static bool test_multi_tevent_threaded_2(struct torture_context *test,
+ const void *test_data)
+{
+ unsigned i;
+
+ struct tevent_context *ev;
+ struct tevent_threaded_context *tctx;
+ int ret;
+
+ thread_test_ctx = test;
+ thread_counter = 0;
+
+ ev = test_tevent_context_init(test);
+ torture_assert(test, ev != NULL, "tevent_context_init failed");
+
+ /*
+ * tevent_re_initialise used to have a bug where it did not
+ * re-initialise the thread support after taking it
+ * down. Exercise that code path.
+ */
+ ret = tevent_re_initialise(ev);
+ torture_assert(test, ret == 0, "tevent_re_initialise failed");
+
+ tctx = tevent_threaded_context_create(ev, ev);
+ torture_assert(test, tctx != NULL,
+ "tevent_threaded_context_create failed");
+
+ for (i=0; i<NUM_TEVENT_THREADS; i++) {
+ struct threaded_test_2 *state;
+
+ state = talloc(ev, struct threaded_test_2);
+ torture_assert(test, state != NULL, "talloc failed");
+
+ state->tctx = tctx;
+ state->im = tevent_create_immediate(state);
+ torture_assert(test, state->im != NULL,
+ "tevent_create_immediate failed");
+
+ ret = pthread_create(&thread_map[i], NULL, thread_fn_2, state);
+ torture_assert(test, ret == 0, "pthread_create failed");
+ }
+
+ while (thread_counter < NUM_TEVENT_THREADS) {
+ ret = tevent_loop_once(ev);
+ torture_assert(test, ret == 0, "tevent_loop_once failed");
+ }
+
+ /* Wait for all the threads to finish - join 'em. */
+ for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+ void *retval;
+ ret = pthread_join(thread_map[i], &retval);
+ torture_assert(test, ret == 0, "pthread_join failed");
+ /* Free the child thread event context. */
+ }
+
+ talloc_free(tctx);
+ talloc_free(ev);
+ return true;
+}
+
+struct test_cached_pid_thread_state {
+ pid_t thread_cached_pid;
+ pid_t thread_pid;
+};
+
+static void *test_cached_pid_thread(void *private_data)
+{
+ struct test_cached_pid_thread_state *state =
+ (struct test_cached_pid_thread_state *)private_data;
+
+ state->thread_cached_pid = tevent_cached_getpid();
+ state->thread_pid = getpid();
+
+ return NULL;
+}
+#endif
+
+static bool test_cached_pid(struct torture_context *test,
+ const void *test_data)
+{
+ pid_t parent_pid = getpid();
+ pid_t child_pid;
+ pid_t finished_pid;
+ int child_status;
+
+ torture_assert(test, tevent_cached_getpid() == parent_pid, "tevent_cached_getpid()");
+
+#ifdef HAVE_PTHREAD
+ {
+ struct test_cached_pid_thread_state state = { .thread_cached_pid = -1, };
+ pthread_t thread;
+ void *retval = NULL;
+ int ret;
+
+ ret = pthread_create(&thread, NULL, test_cached_pid_thread, &state);
+ torture_assert(test, ret == 0, "pthread_create failed");
+
+ ret = pthread_join(thread, &retval);
+ torture_assert(test, ret == 0, "pthread_join failed");
+
+ torture_assert(test, state.thread_pid == parent_pid, "getpid() in thread");
+ torture_assert(test, state.thread_cached_pid == parent_pid, "tevent_cached_getpid() in thread");
+ }
+#endif /* HAVE_PTHREAD */
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ /* child */
+ pid_t pid = getpid();
+ pid_t cached_pid = tevent_cached_getpid();
+
+ if (parent_pid == pid) {
+ exit(1);
+ }
+ if (pid != cached_pid) {
+ exit(2);
+ }
+ exit(0);
+ }
+ torture_assert(test, child_pid > 0, "fork failed");
+
+ finished_pid = waitpid(child_pid, &child_status, 0);
+ torture_assert(test, finished_pid == child_pid, "wrong child");
+ torture_assert(test, child_status == 0, "child_status");
+
+ return true;
+}
+
+struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "event");
+ const char **list = tevent_backend_list(suite);
+ int i;
+
+ for (i=0;list && list[i];i++) {
+ struct torture_suite *backend_suite;
+
+ backend_suite = torture_suite_create(mem_ctx, list[i]);
+
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "context",
+ test_event_context,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd_speed1",
+ test_fd_speed1,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd_speed2",
+ test_fd_speed2,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd_speed3",
+ test_fd_speed3,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd1",
+ test_event_fd1,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd2",
+ test_event_fd2,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd3",
+ test_event_fd3,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "wrapper",
+ test_wrapper,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "free_wrapper",
+ test_free_wrapper,
+ (const void *)list[i]);
+
+ torture_suite_add_suite(suite, backend_suite);
+ }
+
+#ifdef HAVE_PTHREAD
+ torture_suite_add_simple_tcase_const(suite, "threaded_poll_mt",
+ test_event_context_threaded,
+ NULL);
+
+ torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded",
+ test_multi_tevent_threaded,
+ NULL);
+
+ torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded_1",
+ test_multi_tevent_threaded_1,
+ NULL);
+
+ torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded_2",
+ test_multi_tevent_threaded_2,
+ NULL);
+
+#endif
+
+ torture_suite_add_simple_tcase_const(suite, "tevent_cached_getpid",
+ test_cached_pid,
+ NULL);
+
+ return suite;
+}
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
new file mode 100644
index 0000000..9f4a919
--- /dev/null
+++ b/lib/tevent/tevent.c
@@ -0,0 +1,1091 @@
+/*
+ Unix SMB/CIFS implementation.
+ main select loop and event handling
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ PLEASE READ THIS BEFORE MODIFYING!
+
+ This module is a general abstraction for the main select loop and
+ event handling. Do not ever put any localised hacks in here, instead
+ register one of the possible event types and implement that event
+ somewhere else.
+
+ There are 2 types of event handling that are handled in this module:
+
+ 1) a file descriptor becoming readable or writeable. This is mostly
+ used for network sockets, but can be used for any type of file
+ descriptor. You may only register one handler for each file
+ descriptor/io combination or you will get unpredictable results
+ (this means that you can have a handler for read events, and a
+ separate handler for write events, but not two handlers that are
+ both handling read events)
+
+ 2) a timed event. You can register an event that happens at a
+ specific time. You can register as many of these as you
+ like. They are single shot - add a new timed event in the event
+ handler to get another event.
+
+ To setup a set of events you first need to create a event_context
+ structure using the function tevent_context_init(); This returns a
+ 'struct tevent_context' that you use in all subsequent calls.
+
+ After that you can add/remove events that you are interested in
+ using tevent_add_*() and talloc_free()
+
+ Finally, you call tevent_loop_wait_once() to block waiting for one of the
+ events to occor or tevent_loop_wait() which will loop
+ forever.
+
+*/
+#include "replace.h"
+#include "system/filesys.h"
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+#endif
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+#ifdef HAVE_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+struct tevent_ops_list {
+ struct tevent_ops_list *next, *prev;
+ const char *name;
+ const struct tevent_ops *ops;
+};
+
+/* list of registered event backends */
+static struct tevent_ops_list *tevent_backends = NULL;
+static char *tevent_default_backend = NULL;
+
+/*
+ register an events backend
+*/
+bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
+{
+ struct tevent_ops_list *e;
+
+ for (e = tevent_backends; e != NULL; e = e->next) {
+ if (0 == strcmp(e->name, name)) {
+ /* already registered, skip it */
+ return true;
+ }
+ }
+
+ e = talloc(NULL, struct tevent_ops_list);
+ if (e == NULL) return false;
+
+ e->name = name;
+ e->ops = ops;
+ DLIST_ADD(tevent_backends, e);
+
+ return true;
+}
+
+/*
+ set the default event backend
+ */
+void tevent_set_default_backend(const char *backend)
+{
+ talloc_free(tevent_default_backend);
+ tevent_default_backend = talloc_strdup(NULL, backend);
+}
+
+/*
+ initialise backends if not already done
+*/
+static void tevent_backend_init(void)
+{
+ static bool done;
+
+ if (done) {
+ return;
+ }
+
+ done = true;
+
+ tevent_poll_init();
+ tevent_poll_mt_init();
+#if defined(HAVE_EPOLL)
+ tevent_epoll_init();
+#endif
+
+ tevent_standard_init();
+}
+
+const struct tevent_ops *tevent_find_ops_byname(const char *name)
+{
+ struct tevent_ops_list *e;
+
+ tevent_backend_init();
+
+ if (name == NULL) {
+ name = tevent_default_backend;
+ }
+ if (name == NULL) {
+ name = "standard";
+ }
+
+ for (e = tevent_backends; e != NULL; e = e->next) {
+ if (0 == strcmp(e->name, name)) {
+ return e->ops;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ list available backends
+*/
+const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
+{
+ const char **list = NULL;
+ struct tevent_ops_list *e;
+ size_t idx = 0;
+
+ tevent_backend_init();
+
+ for (e=tevent_backends;e;e=e->next) {
+ idx += 1;
+ }
+
+ list = talloc_zero_array(mem_ctx, const char *, idx+1);
+ if (list == NULL) {
+ return NULL;
+ }
+
+ idx = 0;
+ for (e=tevent_backends;e;e=e->next) {
+ list[idx] = talloc_strdup(list, e->name);
+ if (list[idx] == NULL) {
+ TALLOC_FREE(list);
+ return NULL;
+ }
+ idx += 1;
+ }
+
+ return list;
+}
+
+static void tevent_common_wakeup_fini(struct tevent_context *ev);
+
+#ifdef HAVE_PTHREAD
+
+static pthread_mutex_t tevent_contexts_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct tevent_context *tevent_contexts = NULL;
+static pthread_once_t tevent_atfork_initialized = PTHREAD_ONCE_INIT;
+static pid_t tevent_cached_global_pid = 0;
+
+static void tevent_atfork_prepare(void)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ ret = pthread_mutex_lock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ for (ev = tevent_contexts; ev != NULL; ev = ev->next) {
+ struct tevent_threaded_context *tctx;
+
+ for (tctx = ev->threaded_contexts; tctx != NULL;
+ tctx = tctx->next) {
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_lock failed");
+ }
+ }
+
+ ret = pthread_mutex_lock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_lock failed");
+ }
+ }
+}
+
+static void tevent_atfork_parent(void)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
+ ev = DLIST_PREV(ev)) {
+ struct tevent_threaded_context *tctx;
+
+ ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_unlock failed");
+ }
+
+ for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
+ tctx = DLIST_PREV(tctx)) {
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ tevent_abort(
+ ev, "pthread_mutex_unlock failed");
+ }
+ }
+ }
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+}
+
+static void tevent_atfork_child(void)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ tevent_cached_global_pid = getpid();
+
+ for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
+ ev = DLIST_PREV(ev)) {
+ struct tevent_threaded_context *tctx;
+
+ for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
+ tctx = DLIST_PREV(tctx)) {
+ tctx->event_ctx = NULL;
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ tevent_abort(
+ ev, "pthread_mutex_unlock failed");
+ }
+ }
+
+ ev->threaded_contexts = NULL;
+
+ ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ tevent_abort(ev, "pthread_mutex_unlock failed");
+ }
+ }
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+}
+
+static void tevent_prep_atfork(void)
+{
+ int ret;
+
+ ret = pthread_atfork(tevent_atfork_prepare,
+ tevent_atfork_parent,
+ tevent_atfork_child);
+ if (ret != 0) {
+ abort();
+ }
+
+ tevent_cached_global_pid = getpid();
+}
+
+#endif
+
+static int tevent_init_globals(void)
+{
+#ifdef HAVE_PTHREAD
+ int ret;
+
+ ret = pthread_once(&tevent_atfork_initialized, tevent_prep_atfork);
+ if (ret != 0) {
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+_PUBLIC_ pid_t tevent_cached_getpid(void)
+{
+#ifdef HAVE_PTHREAD
+ tevent_init_globals();
+#ifdef TEVENT_VERIFY_CACHED_GETPID
+ if (tevent_cached_global_pid != getpid()) {
+ tevent_abort(NULL, "tevent_cached_global_pid invalid");
+ }
+#endif
+ if (tevent_cached_global_pid != 0) {
+ return tevent_cached_global_pid;
+ }
+#endif
+ return getpid();
+}
+
+int tevent_common_context_destructor(struct tevent_context *ev)
+{
+ struct tevent_fd *fd, *fn;
+ struct tevent_timer *te, *tn;
+ struct tevent_immediate *ie, *in;
+ struct tevent_signal *se, *sn;
+ struct tevent_wrapper_glue *gl, *gn;
+#ifdef HAVE_PTHREAD
+ int ret;
+#endif
+
+ if (ev->wrapper.glue != NULL) {
+ tevent_abort(ev,
+ "tevent_common_context_destructor() active on wrapper");
+ }
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_mutex_lock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ DLIST_REMOVE(tevent_contexts, ev);
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ while (ev->threaded_contexts != NULL) {
+ struct tevent_threaded_context *tctx = ev->threaded_contexts;
+
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ /*
+ * Indicate to the thread that the tevent_context is
+ * gone. The counterpart of this is in
+ * _tevent_threaded_schedule_immediate, there we read
+ * this under the threaded_context's mutex.
+ */
+
+ tctx->event_ctx = NULL;
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ DLIST_REMOVE(ev->threaded_contexts, tctx);
+ }
+
+ ret = pthread_mutex_destroy(&ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+#endif
+
+ for (gl = ev->wrapper.list; gl; gl = gn) {
+ gn = gl->next;
+
+ gl->main_ev = NULL;
+ DLIST_REMOVE(ev->wrapper.list, gl);
+ }
+
+ tevent_common_wakeup_fini(ev);
+
+ for (fd = ev->fd_events; fd; fd = fn) {
+ fn = fd->next;
+ tevent_common_fd_disarm(fd);
+ }
+
+ ev->last_zero_timer = NULL;
+ for (te = ev->timer_events; te; te = tn) {
+ tn = te->next;
+ tevent_trace_timer_callback(te->event_ctx, te, TEVENT_EVENT_TRACE_DETACH);
+ te->wrapper = NULL;
+ te->event_ctx = NULL;
+ DLIST_REMOVE(ev->timer_events, te);
+ }
+
+ for (ie = ev->immediate_events; ie; ie = in) {
+ in = ie->next;
+ tevent_trace_immediate_callback(ie->event_ctx, ie, TEVENT_EVENT_TRACE_DETACH);
+ ie->wrapper = NULL;
+ ie->event_ctx = NULL;
+ ie->cancel_fn = NULL;
+ DLIST_REMOVE(ev->immediate_events, ie);
+ }
+
+ for (se = ev->signal_events; se; se = sn) {
+ sn = se->next;
+ tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_DETACH);
+ se->wrapper = NULL;
+ se->event_ctx = NULL;
+ DLIST_REMOVE(ev->signal_events, se);
+ /*
+ * This is important, Otherwise signals
+ * are handled twice in child. eg, SIGHUP.
+ * one added in parent, and another one in
+ * the child. -- BoYang
+ */
+ tevent_cleanup_pending_signal_handlers(se);
+ }
+
+ /* removing nesting hook or we get an abort when nesting is
+ * not allowed. -- SSS
+ * Note that we need to leave the allowed flag at its current
+ * value, otherwise the use in tevent_re_initialise() will
+ * leave the event context with allowed forced to false, which
+ * will break users that expect nesting to be allowed
+ */
+ ev->nesting.level = 0;
+ ev->nesting.hook_fn = NULL;
+ ev->nesting.hook_private = NULL;
+
+ return 0;
+}
+
+static int tevent_common_context_constructor(struct tevent_context *ev)
+{
+ int ret;
+
+ ret = tevent_init_globals();
+ if (ret != 0) {
+ return ret;
+ }
+
+#ifdef HAVE_PTHREAD
+
+ ret = pthread_mutex_init(&ev->scheduled_mutex, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = pthread_mutex_lock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ pthread_mutex_destroy(&ev->scheduled_mutex);
+ return ret;
+ }
+
+ DLIST_ADD(tevent_contexts, ev);
+
+ ret = pthread_mutex_unlock(&tevent_contexts_mutex);
+ if (ret != 0) {
+ abort();
+ }
+#endif
+
+ talloc_set_destructor(ev, tevent_common_context_destructor);
+
+ return 0;
+}
+
+void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason)
+{
+ void *parent_ptr = talloc_parent(ptr);
+ size_t parent_blocks = talloc_total_blocks(parent_ptr);
+
+ if (parent_ptr != NULL && parent_blocks == 0) {
+ /*
+ * This is an implicit talloc free, as we still have a parent
+ * but it's already being destroyed. Note that
+ * talloc_total_blocks(ptr) also just returns 0 if a
+ * talloc_free(ptr) is still in progress of freeing all
+ * children.
+ */
+ return;
+ }
+
+ tevent_abort(NULL, reason);
+}
+
+/*
+ create a event_context structure for a specific implementation.
+ This must be the first events call, and all subsequent calls pass
+ this event_context as the first element. Event handlers also
+ receive this as their first argument.
+
+ This function is for allowing third-party-applications to hook in gluecode
+ to their own event loop code, so that they can make async usage of our client libs
+
+ NOTE: use tevent_context_init() inside of samba!
+*/
+struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
+ const struct tevent_ops *ops,
+ void *additional_data)
+{
+ struct tevent_context *ev;
+ int ret;
+
+ ev = talloc_zero(mem_ctx, struct tevent_context);
+ if (!ev) return NULL;
+
+ ret = tevent_common_context_constructor(ev);
+ if (ret != 0) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ ev->ops = ops;
+ ev->additional_data = additional_data;
+
+ ret = ev->ops->context_init(ev);
+ if (ret != 0) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ return ev;
+}
+
+/*
+ create a event_context structure. This must be the first events
+ call, and all subsequent calls pass this event_context as the first
+ element. Event handlers also receive this as their first argument.
+*/
+struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
+ const char *name)
+{
+ const struct tevent_ops *ops;
+
+ ops = tevent_find_ops_byname(name);
+ if (ops == NULL) {
+ return NULL;
+ }
+
+ return tevent_context_init_ops(mem_ctx, ops, NULL);
+}
+
+
+/*
+ create a event_context structure. This must be the first events
+ call, and all subsequent calls pass this event_context as the first
+ element. Event handlers also receive this as their first argument.
+*/
+struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
+{
+ return tevent_context_init_byname(mem_ctx, NULL);
+}
+
+/*
+ add a fd based event
+ return NULL on failure (memory allocation error)
+*/
+struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
+ handler_name, location);
+}
+
+/*
+ set a close function on the fd event
+*/
+void tevent_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn)
+{
+ if (!fde) return;
+ if (!fde->event_ctx) return;
+ fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
+}
+
+static void tevent_fd_auto_close_fn(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ int fd,
+ void *private_data)
+{
+ close(fd);
+}
+
+void tevent_fd_set_auto_close(struct tevent_fd *fde)
+{
+ tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
+}
+
+/*
+ return the fd event flags
+*/
+uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
+{
+ if (!fde) return 0;
+ if (!fde->event_ctx) return 0;
+ return fde->event_ctx->ops->get_fd_flags(fde);
+}
+
+/*
+ set the fd event flags
+*/
+void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ if (!fde) return;
+ if (!fde->event_ctx) return;
+ fde->event_ctx->ops->set_fd_flags(fde, flags);
+}
+
+bool tevent_signal_support(struct tevent_context *ev)
+{
+ if (ev->ops->add_signal) {
+ return true;
+ }
+ return false;
+}
+
+static void (*tevent_abort_fn)(const char *reason);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+ tevent_abort_fn = abort_fn;
+}
+
+void tevent_abort(struct tevent_context *ev, const char *reason)
+{
+ if (ev != NULL) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "abort: %s\n", reason);
+ }
+
+ if (!tevent_abort_fn) {
+ abort();
+ }
+
+ tevent_abort_fn(reason);
+}
+
+/*
+ add a timer event
+ return NULL on failure
+*/
+struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
+ handler_name, location);
+}
+
+/*
+ allocate an immediate event
+ return NULL on failure (memory allocation error)
+*/
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+ const char *location)
+{
+ struct tevent_immediate *im;
+
+ im = talloc(mem_ctx, struct tevent_immediate);
+ if (im == NULL) return NULL;
+
+ *im = (struct tevent_immediate) { .create_location = location };
+
+ return im;
+}
+
+/*
+ schedule an immediate event
+*/
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ ev->ops->schedule_immediate(im, ev, handler, private_data,
+ handler_name, location);
+}
+
+/*
+ add a signal event
+
+ sa_flags are flags to sigaction(2)
+
+ return NULL on failure
+*/
+struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
+ handler_name, location);
+}
+
+void tevent_loop_allow_nesting(struct tevent_context *ev)
+{
+ if (ev->wrapper.glue != NULL) {
+ tevent_abort(ev, "tevent_loop_allow_nesting() on wrapper");
+ return;
+ }
+
+ if (ev->wrapper.list != NULL) {
+ tevent_abort(ev, "tevent_loop_allow_nesting() with wrapper");
+ return;
+ }
+
+ ev->nesting.allowed = true;
+}
+
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+ tevent_nesting_hook hook,
+ void *private_data)
+{
+ if (ev->nesting.hook_fn &&
+ (ev->nesting.hook_fn != hook ||
+ ev->nesting.hook_private != private_data)) {
+ /* the way the nesting hook code is currently written
+ we cannot support two different nesting hooks at the
+ same time. */
+ tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
+ }
+ ev->nesting.hook_fn = hook;
+ ev->nesting.hook_private = private_data;
+}
+
+static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
+{
+ const char *reason;
+
+ reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
+ location);
+ if (!reason) {
+ reason = "tevent_loop_once() nesting";
+ }
+
+ tevent_abort(ev, reason);
+}
+
+/*
+ do a single event loop using the events defined in ev
+*/
+int _tevent_loop_once(struct tevent_context *ev, const char *location)
+{
+ int ret;
+ void *nesting_stack_ptr = NULL;
+
+ ev->nesting.level++;
+
+ if (ev->nesting.level > 1) {
+ if (!ev->nesting.allowed) {
+ tevent_abort_nesting(ev, location);
+ errno = ELOOP;
+ return -1;
+ }
+ }
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ true,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+ tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
+ ret = ev->ops->loop_once(ev, location);
+ tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
+
+ /* New event (and request) will always start with call depth 0. */
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_RESET,
+ NULL,
+ 0,
+ __func__);
+
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ false,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+done:
+ ev->nesting.level--;
+ return ret;
+}
+
+/*
+ this is a performance optimization for the samba4 nested event loop problems
+*/
+int _tevent_loop_until(struct tevent_context *ev,
+ bool (*finished)(void *private_data),
+ void *private_data,
+ const char *location)
+{
+ int ret = 0;
+ void *nesting_stack_ptr = NULL;
+
+ ev->nesting.level++;
+
+ if (ev->nesting.level > 1) {
+ if (!ev->nesting.allowed) {
+ tevent_abort_nesting(ev, location);
+ errno = ELOOP;
+ return -1;
+ }
+ }
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ true,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+ while (!finished(private_data)) {
+ tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
+ ret = ev->ops->loop_once(ev, location);
+ tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
+ if (ret != 0) {
+ break;
+ }
+ }
+
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ false,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+done:
+ ev->nesting.level--;
+ return ret;
+}
+
+bool tevent_common_have_events(struct tevent_context *ev)
+{
+ if (ev->fd_events != NULL) {
+ if (ev->fd_events != ev->wakeup_fde) {
+ return true;
+ }
+ if (ev->fd_events->next != NULL) {
+ return true;
+ }
+
+ /*
+ * At this point we just have the wakeup pipe event as
+ * the only fd_event. That one does not count as a
+ * regular event, so look at the other event types.
+ */
+ }
+
+ return ((ev->timer_events != NULL) ||
+ (ev->immediate_events != NULL) ||
+ (ev->signal_events != NULL));
+}
+
+/*
+ return on failure or (with 0) if all fd events are removed
+*/
+int tevent_common_loop_wait(struct tevent_context *ev,
+ const char *location)
+{
+ /*
+ * loop as long as we have events pending
+ */
+ while (tevent_common_have_events(ev)) {
+ int ret;
+ ret = _tevent_loop_once(ev, location);
+ if (ret != 0) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "_tevent_loop_once() failed: %d - %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_WARNING,
+ "tevent_common_loop_wait() out of events\n");
+ return 0;
+}
+
+/*
+ return on failure or (with 0) if all fd events are removed
+*/
+int _tevent_loop_wait(struct tevent_context *ev, const char *location)
+{
+ return ev->ops->loop_wait(ev, location);
+}
+
+
+/*
+ re-initialise a tevent context. This leaves you with the same
+ event context, but all events are wiped and the structure is
+ re-initialised. This is most useful after a fork()
+
+ zero is returned on success, non-zero on failure
+*/
+int tevent_re_initialise(struct tevent_context *ev)
+{
+ tevent_common_context_destructor(ev);
+
+ tevent_common_context_constructor(ev);
+
+ return ev->ops->context_init(ev);
+}
+
+static void wakeup_pipe_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags, void *_private)
+{
+ ssize_t ret;
+
+ do {
+ /*
+ * This is the boilerplate for eventfd, but it works
+ * for pipes too. And as we don't care about the data
+ * we read, we're fine.
+ */
+ uint64_t val;
+ ret = read(fde->fd, &val, sizeof(val));
+ } while (ret == -1 && errno == EINTR);
+}
+
+/*
+ * Initialize the wakeup pipe and pipe fde
+ */
+
+int tevent_common_wakeup_init(struct tevent_context *ev)
+{
+ int ret, read_fd;
+
+ if (ev->wakeup_fde != NULL) {
+ return 0;
+ }
+
+#ifdef HAVE_EVENTFD
+ ret = eventfd(0, EFD_NONBLOCK);
+ if (ret == -1) {
+ return errno;
+ }
+ read_fd = ev->wakeup_fd = ret;
+#else
+ {
+ int pipe_fds[2];
+ ret = pipe(pipe_fds);
+ if (ret == -1) {
+ return errno;
+ }
+ ev->wakeup_fd = pipe_fds[1];
+ ev->wakeup_read_fd = pipe_fds[0];
+
+ ev_set_blocking(ev->wakeup_fd, false);
+ ev_set_blocking(ev->wakeup_read_fd, false);
+
+ read_fd = ev->wakeup_read_fd;
+ }
+#endif
+
+ ev->wakeup_fde = tevent_add_fd(ev, ev, read_fd, TEVENT_FD_READ,
+ wakeup_pipe_handler, NULL);
+ if (ev->wakeup_fde == NULL) {
+ close(ev->wakeup_fd);
+#ifndef HAVE_EVENTFD
+ close(ev->wakeup_read_fd);
+#endif
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+int tevent_common_wakeup_fd(int fd)
+{
+ ssize_t ret;
+
+ do {
+#ifdef HAVE_EVENTFD
+ uint64_t val = 1;
+ ret = write(fd, &val, sizeof(val));
+#else
+ char c = '\0';
+ ret = write(fd, &c, 1);
+#endif
+ } while ((ret == -1) && (errno == EINTR));
+
+ return 0;
+}
+
+int tevent_common_wakeup(struct tevent_context *ev)
+{
+ if (ev->wakeup_fde == NULL) {
+ return ENOTCONN;
+ }
+
+ return tevent_common_wakeup_fd(ev->wakeup_fd);
+}
+
+static void tevent_common_wakeup_fini(struct tevent_context *ev)
+{
+ if (ev->wakeup_fde == NULL) {
+ return;
+ }
+
+ TALLOC_FREE(ev->wakeup_fde);
+
+ close(ev->wakeup_fd);
+#ifndef HAVE_EVENTFD
+ close(ev->wakeup_read_fd);
+#endif
+}
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
new file mode 100644
index 0000000..0f40b2b
--- /dev/null
+++ b/lib/tevent/tevent.h
@@ -0,0 +1,3103 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ generalised event loop handling
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2005-2009
+ Copyright (C) Volker Lendecke 2008
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TEVENT_H__
+#define __TEVENT_H__
+
+#include <stdint.h>
+#include <talloc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+/* for old gcc releases that don't have the feature test macro __has_attribute */
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifdef TEVENT_DEPRECATED
+#ifndef _DEPRECATED_
+#if __has_attribute(deprecated) || (__GNUC__ >= 3)
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+#endif
+
+struct tevent_context;
+struct tevent_ops;
+struct tevent_fd;
+struct tevent_timer;
+struct tevent_immediate;
+struct tevent_signal;
+struct tevent_thread_proxy;
+struct tevent_threaded_context;
+
+/**
+ * @defgroup tevent The tevent API
+ *
+ * The tevent low-level API
+ *
+ * This API provides the public interface to manage events in the tevent
+ * mainloop. Functions are provided for managing low-level events such
+ * as timer events, fd events and signal handling.
+ *
+ * @{
+ */
+
+/* event handler types */
+/**
+ * Called when a file descriptor monitored by tevent has
+ * data to be read or written on it.
+ */
+typedef void (*tevent_fd_handler_t)(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+/**
+ * Called when tevent is ceasing the monitoring of a file descriptor.
+ */
+typedef void (*tevent_fd_close_fn_t)(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ int fd,
+ void *private_data);
+
+/**
+ * Called when a tevent timer has fired.
+ */
+typedef void (*tevent_timer_handler_t)(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data);
+
+/**
+ * Called when a tevent immediate event is invoked.
+ */
+typedef void (*tevent_immediate_handler_t)(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
+/**
+ * Called after tevent detects the specified signal.
+ */
+typedef void (*tevent_signal_handler_t)(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data);
+
+/**
+ * @brief Create a event_context structure.
+ *
+ * This must be the first events call, and all subsequent calls pass this
+ * event_context as the first element. Event handlers also receive this as
+ * their first argument.
+ *
+ * @param[in] mem_ctx The memory context to use.
+ *
+ * @return An allocated tevent context, NULL on error.
+ *
+ * @see tevent_context_init()
+ */
+struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Create a event_context structure and select a specific backend.
+ *
+ * This must be the first events call, and all subsequent calls pass this
+ * event_context as the first element. Event handlers also receive this as
+ * their first argument.
+ *
+ * @param[in] mem_ctx The memory context to use.
+ *
+ * @param[in] name The name of the backend to use.
+ *
+ * @return An allocated tevent context, NULL on error.
+ */
+struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx, const char *name);
+
+/**
+ * @brief Create a custom event context
+ *
+ * @param[in] mem_ctx The memory context to use.
+ * @param[in] ops The function pointer table of the backend.
+ * @param[in] additional_data The additional/private data to this instance
+ *
+ * @return An allocated tevent context, NULL on error.
+ *
+ */
+struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
+ const struct tevent_ops *ops,
+ void *additional_data);
+
+/**
+ * @brief List available backends.
+ *
+ * @param[in] mem_ctx The memory context to use.
+ *
+ * @return A string vector with a terminating NULL element, NULL
+ * on error.
+ */
+const char **tevent_backend_list(TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Set the default tevent backend.
+ *
+ * @param[in] backend The name of the backend to set.
+ */
+void tevent_set_default_backend(const char *backend);
+
+#ifdef DOXYGEN
+/**
+ * @brief Add a file descriptor based event.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] fd The file descriptor to base the event on.
+ *
+ * @param[in] flags #TEVENT_FD_READ, #TEVENT_FD_WRITE or #TEVENT_FD_ERROR.
+ *
+ * @param[in] handler The callback handler for the event.
+ *
+ * @param[in] private_data The private data passed to the callback handler.
+ *
+ * @return The file descriptor based event, NULL on error.
+ *
+ * @note To cancel the monitoring of a file descriptor, call talloc_free()
+ * on the object returned by this function.
+ *
+ * @note The caller should avoid closing the file descriptor before
+ * calling talloc_free()! Otherwise the behaviour is undefined which
+ * might result in crashes. See https://bugzilla.samba.org/show_bug.cgi?id=11141
+ * for an example.
+ */
+struct tevent_fd *tevent_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data);
+#else
+struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data) \
+ _tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data, \
+ #handler, __location__)
+#endif
+
+/**
+ * @brief Associate a custom tag with the event.
+ *
+ * This tag can be then retrieved with tevent_fd_get_tag()
+ *
+ * @param[in] fde The file descriptor event.
+ *
+ * @param[in] tag Custom tag.
+ */
+void tevent_fd_set_tag(struct tevent_fd *fde, uint64_t tag);
+
+/**
+ * @brief Get custom event tag.
+ */
+uint64_t tevent_fd_get_tag(const struct tevent_fd *fde);
+
+#ifdef DOXYGEN
+/**
+ * @brief Add a timed event
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] next_event Timeval specifying the absolute time to fire this
+ * event. This is not an offset.
+ *
+ * @param[in] handler The callback handler for the event.
+ *
+ * @param[in] private_data The private data passed to the callback handler.
+ *
+ * @return The newly-created timer event, or NULL on error.
+ *
+ * @note To cancel a timer event before it fires, call talloc_free() on the
+ * event returned from this function. This event is automatically
+ * talloc_free()-ed after its event handler files, if it hasn't been freed yet.
+ *
+ * @note Unlike some mainloops, tevent timers are one-time events. To set up
+ * a recurring event, it is necessary to call tevent_add_timer() again during
+ * the handler processing.
+ *
+ * @note Due to the internal mainloop processing, a timer set to run
+ * immediately will do so after any other pending timers fire, but before
+ * any further file descriptor or signal handling events fire. Callers should
+ * not rely on this behavior!
+ */
+struct tevent_timer *tevent_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data);
+#else
+struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_add_timer(ev, mem_ctx, next_event, handler, private_data) \
+ _tevent_add_timer(ev, mem_ctx, next_event, handler, private_data, \
+ #handler, __location__)
+#endif
+
+/**
+ * @brief Set the time a tevent_timer fires
+ *
+ * @param[in] te The timer event to reset
+ *
+ * @param[in] next_event Timeval specifying the absolute time to fire this
+ * event. This is not an offset.
+ */
+void tevent_update_timer(struct tevent_timer *te, struct timeval next_event);
+
+/**
+ * @brief Associate a custom tag with the event.
+ *
+ * This tag can be then retrieved with tevent_timer_get_tag()
+ *
+ * @param[in] te The timer event.
+ *
+ * @param[in] tag Custom tag.
+ */
+void tevent_timer_set_tag(struct tevent_timer *te, uint64_t tag);
+
+/**
+ * @brief Get custom event tag.
+ */
+uint64_t tevent_timer_get_tag(const struct tevent_timer *te);
+
+#ifdef DOXYGEN
+/**
+ * Initialize an immediate event object
+ *
+ * This object can be used to trigger an event to occur immediately after
+ * returning from the current event (before any other event occurs)
+ *
+ * @param[in] mem_ctx The talloc memory context to use as the parent
+ *
+ * @return An empty tevent_immediate object. Use tevent_schedule_immediate
+ * to populate and use it.
+ *
+ * @note Available as of tevent 0.9.8
+ */
+struct tevent_immediate *tevent_create_immediate(TALLOC_CTX *mem_ctx);
+#else
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+ const char *location);
+#define tevent_create_immediate(mem_ctx) \
+ _tevent_create_immediate(mem_ctx, __location__)
+#endif
+
+#ifdef DOXYGEN
+
+/**
+ * Schedule an event for immediate execution. This event will occur
+ * immediately after returning from the current event (before any other
+ * event occurs)
+ *
+ * @param[in] im The tevent_immediate object to populate and use
+ * @param[in] ctx The tevent_context to run this event
+ * @param[in] handler The event handler to run when this event fires
+ * @param[in] private_data Data to pass to the event handler
+ */
+void tevent_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ctx,
+ tevent_immediate_handler_t handler,
+ void *private_data);
+#else
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ctx,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_schedule_immediate(im, ctx, handler, private_data) \
+ _tevent_schedule_immediate(im, ctx, handler, private_data, \
+ #handler, __location__);
+#endif
+
+/**
+ * @brief Associate a custom tag with the event.
+ *
+ * This tag can be then retrieved with tevent_immediate_get_tag()
+ *
+ * @param[in] im The immediate event.
+ *
+ * @param[in] tag Custom tag.
+ */
+void tevent_immediate_set_tag(struct tevent_immediate *im, uint64_t tag);
+
+/**
+ * @brief Get custom event tag.
+ */
+uint64_t tevent_immediate_get_tag(const struct tevent_immediate *fde);
+
+#ifdef DOXYGEN
+/**
+ * @brief Add a tevent signal handler
+ *
+ * tevent_add_signal() creates a new event for handling a signal the next
+ * time through the mainloop. It implements a very simple traditional signal
+ * handler whose only purpose is to add the handler event into the mainloop.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] signum The signal to trap
+ *
+ * @param[in] handler The callback handler for the signal.
+ *
+ * @param[in] sa_flags sigaction flags for this signal handler.
+ *
+ * @param[in] private_data The private data passed to the callback handler.
+ *
+ * @return The newly-created signal handler event, or NULL on error.
+ *
+ * @note To cancel a signal handler, call talloc_free() on the event returned
+ * from this function.
+ *
+ * @see tevent_num_signals, tevent_sa_info_queue_count
+ */
+struct tevent_signal *tevent_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data);
+#else
+struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data) \
+ _tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data, \
+ #handler, __location__)
+#endif
+
+/**
+ * @brief Associate a custom tag with the event.
+ *
+ * This tag can be then retrieved with tevent_signal_get_tag()
+ *
+ * @param[in] fde The signal event.
+ *
+ * @param[in] tag Custom tag.
+ */
+void tevent_signal_set_tag(struct tevent_signal *se, uint64_t tag);
+
+/**
+ * @brief Get custom event tag.
+ */
+uint64_t tevent_signal_get_tag(const struct tevent_signal *se);
+
+/**
+ * @brief the number of supported signals
+ *
+ * This returns value of the configure time TEVENT_NUM_SIGNALS constant.
+ *
+ * The 'signum' argument of tevent_add_signal() must be less than
+ * TEVENT_NUM_SIGNALS.
+ *
+ * @see tevent_add_signal
+ */
+size_t tevent_num_signals(void);
+
+/**
+ * @brief the number of pending realtime signals
+ *
+ * This returns value of TEVENT_SA_INFO_QUEUE_COUNT.
+ *
+ * The tevent internals remember the last TEVENT_SA_INFO_QUEUE_COUNT
+ * siginfo_t structures for SA_SIGINFO signals. If the system generates
+ * more some signals get lost.
+ *
+ * @see tevent_add_signal
+ */
+size_t tevent_sa_info_queue_count(void);
+
+#ifdef DOXYGEN
+/**
+ * @brief Pass a single time through the mainloop
+ *
+ * This will process any appropriate signal, immediate, fd and timer events
+ *
+ * @param[in] ev The event context to process
+ *
+ * @return Zero on success, nonzero if an internal error occurred
+ */
+int tevent_loop_once(struct tevent_context *ev);
+#else
+int _tevent_loop_once(struct tevent_context *ev, const char *location);
+#define tevent_loop_once(ev) \
+ _tevent_loop_once(ev, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Run the mainloop
+ *
+ * The mainloop will run until there are no events remaining to be processed
+ *
+ * @param[in] ev The event context to process
+ *
+ * @return Zero if all events have been processed. Nonzero if an internal
+ * error occurred.
+ */
+int tevent_loop_wait(struct tevent_context *ev);
+#else
+int _tevent_loop_wait(struct tevent_context *ev, const char *location);
+#define tevent_loop_wait(ev) \
+ _tevent_loop_wait(ev, __location__)
+#endif
+
+
+/**
+ * Assign a function to run when a tevent_fd is freed
+ *
+ * This function is a destructor for the tevent_fd. It does not automatically
+ * close the file descriptor. If this is the desired behavior, then it must be
+ * performed by the close_fn.
+ *
+ * @param[in] fde File descriptor event on which to set the destructor
+ * @param[in] close_fn Destructor to execute when fde is freed
+ *
+ * @note That the close_fn() on tevent_fd is *NOT* wrapped on contexts
+ * created by tevent_context_wrapper_create()!
+ *
+ * @see tevent_fd_set_close_fn
+ * @see tevent_context_wrapper_create
+ */
+void tevent_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn);
+
+/**
+ * Automatically close the file descriptor when the tevent_fd is freed
+ *
+ * This function calls close(fd) internally.
+ *
+ * @param[in] fde File descriptor event to auto-close
+ *
+ * @see tevent_fd_set_close_fn
+ */
+void tevent_fd_set_auto_close(struct tevent_fd *fde);
+
+/**
+ * Return the flags set on this file descriptor event
+ *
+ * @param[in] fde File descriptor event to query
+ *
+ * @return The flags set on the event. See #TEVENT_FD_READ,
+ * #TEVENT_FD_WRITE and #TEVENT_FD_ERROR
+ */
+uint16_t tevent_fd_get_flags(struct tevent_fd *fde);
+
+/**
+ * Set flags on a file descriptor event
+ *
+ * @param[in] fde File descriptor event to set
+ * @param[in] flags Flags to set on the event. See #TEVENT_FD_READ,
+ * #TEVENT_FD_WRITE and #TEVENT_FD_ERROR
+ */
+void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+
+/**
+ * Query whether tevent supports signal handling
+ *
+ * @param[in] ev An initialized tevent context
+ *
+ * @return True if this platform and tevent context support signal handling
+ */
+bool tevent_signal_support(struct tevent_context *ev);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason));
+
+/* bits for file descriptor event flags */
+
+/**
+ * Monitor a file descriptor for data to be read and errors
+ *
+ * Note: we map this from/to POLLIN, POLLHUP, POLLERR and
+ * where available POLLRDHUP
+ */
+#define TEVENT_FD_READ 1
+/**
+ * Monitor a file descriptor for writeability
+ *
+ * Note: we map this from/to POLLOUT
+ */
+#define TEVENT_FD_WRITE 2
+/**
+ * Monitor a file descriptor for errors
+ *
+ * Note: we map this from/to POLLHUP, POLLERR and
+ * where available POLLRDHUP
+ */
+#define TEVENT_FD_ERROR 4
+
+/**
+ * Convenience function for declaring a tevent_fd writable
+ */
+#define TEVENT_FD_WRITEABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_WRITE)
+
+/**
+ * Convenience function for declaring a tevent_fd readable
+ */
+#define TEVENT_FD_READABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_READ)
+
+/**
+ * Convenience function for declaring a tevent_fd waiting for errors
+ */
+#define TEVENT_FD_WANTERROR(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) | TEVENT_FD_ERROR)
+
+/**
+ * Convenience function for declaring a tevent_fd non-writable
+ */
+#define TEVENT_FD_NOT_WRITEABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_WRITE)
+
+/**
+ * Convenience function for declaring a tevent_fd non-readable
+ */
+#define TEVENT_FD_NOT_READABLE(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_READ)
+
+/**
+ * Convenience function for declaring a tevent_fd not waiting for errors
+ */
+#define TEVENT_FD_NOT_WANTERROR(fde) \
+ tevent_fd_set_flags(fde, tevent_fd_get_flags(fde) & ~TEVENT_FD_ERROR)
+
+/**
+ * Debug level of tevent
+ */
+enum tevent_debug_level {
+ TEVENT_DEBUG_FATAL,
+ TEVENT_DEBUG_ERROR,
+ TEVENT_DEBUG_WARNING,
+ TEVENT_DEBUG_TRACE
+};
+
+/**
+ * @brief The tevent debug callbac.
+ *
+ * @param[in] context The memory context to use.
+ *
+ * @param[in] level The debug level.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ap The arguments for the format string.
+ */
+typedef void (*tevent_debug_fn)(void *context,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(3,0);
+
+/**
+ * Set destination for tevent debug messages
+ *
+ * As of version 0.15.0 the invocation of
+ * the debug function for individual messages
+ * is limited by the current max_debug_level,
+ * which means TEVENT_DEBUG_TRACE messages
+ * are not passed by default:
+ *
+ * - tevent_set_debug() with debug == NULL implies
+ * tevent_set_max_debug_level(ev, TEVENT_DEBUG_FATAL).
+ *
+ * - tevent_set_debug() with debug != NULL implies
+ * tevent_set_max_debug_level(ev, TEVENT_DEBUG_WARNING).
+ *
+ * @param[in] ev Event context to debug
+ * @param[in] debug Function to handle output printing
+ * @param[in] context The context to pass to the debug function.
+ *
+ * @return Always returns 0 as of version 0.9.8
+ *
+ * @note Default is to emit no debug messages
+ *
+ * @see tevent_set_max_debug_level()
+ */
+int tevent_set_debug(struct tevent_context *ev,
+ tevent_debug_fn debug,
+ void *context);
+
+/**
+ * Set maximum debug level for tevent debug messages
+ *
+ * @param[in] ev Event context to debug
+ * @param[in] max_level Function to handle output printing
+ *
+ * @return The former max level is returned.
+ *
+ * @see tevent_set_debug()
+ *
+ * @note Available as of tevent 0.15.0
+ */
+enum tevent_debug_level
+tevent_set_max_debug_level(struct tevent_context *ev,
+ enum tevent_debug_level max_level);
+
+/**
+ * Designate stderr for debug message output
+ *
+ * @param[in] ev Event context to debug
+ *
+ * @note This function will only output TEVENT_DEBUG_FATAL, TEVENT_DEBUG_ERROR
+ * and TEVENT_DEBUG_WARNING messages. For TEVENT_DEBUG_TRACE, please define a
+ * function for tevent_set_debug()
+ */
+int tevent_set_debug_stderr(struct tevent_context *ev);
+
+enum tevent_trace_point {
+ /**
+ * Corresponds to a trace point just before waiting
+ */
+ TEVENT_TRACE_BEFORE_WAIT,
+ /**
+ * Corresponds to a trace point just after waiting
+ */
+ TEVENT_TRACE_AFTER_WAIT,
+#define TEVENT_HAS_LOOP_ONCE_TRACE_POINTS 1
+ /**
+ * Corresponds to a trace point just before calling
+ * the loop_once() backend function.
+ */
+ TEVENT_TRACE_BEFORE_LOOP_ONCE,
+ /**
+ * Corresponds to a trace point right after the
+ * loop_once() backend function has returned.
+ */
+ TEVENT_TRACE_AFTER_LOOP_ONCE,
+};
+
+typedef void (*tevent_trace_callback_t)(enum tevent_trace_point,
+ void *private_data);
+
+/**
+ * Register a callback to be called at certain trace points
+ *
+ * @param[in] ev Event context
+ * @param[in] cb Trace callback
+ * @param[in] private_data Data to be passed to callback
+ *
+ * @note The callback will be called at trace points defined by
+ * tevent_trace_point. Call with NULL to reset.
+ */
+void tevent_set_trace_callback(struct tevent_context *ev,
+ tevent_trace_callback_t cb,
+ void *private_data);
+
+/**
+ * Retrieve the current trace callback
+ *
+ * @param[in] ev Event context
+ * @param[out] cb Registered trace callback
+ * @param[out] private_data Registered data to be passed to callback
+ *
+ * @note This can be used to allow one component that wants to
+ * register a callback to respect the callback that another component
+ * has already registered.
+ */
+void tevent_get_trace_callback(struct tevent_context *ev,
+ tevent_trace_callback_t *cb,
+ void *private_data);
+
+enum tevent_event_trace_point {
+ /**
+ * Corresponds to a trace point just before the event is added.
+ */
+ TEVENT_EVENT_TRACE_ATTACH,
+
+ /**
+ * Corresponds to a trace point just before the event is removed.
+ */
+ TEVENT_EVENT_TRACE_DETACH,
+
+ /**
+ * Corresponds to a trace point just before the event handler is called.
+ */
+ TEVENT_EVENT_TRACE_BEFORE_HANDLER,
+};
+
+typedef void (*tevent_trace_fd_callback_t)(struct tevent_fd *fde,
+ enum tevent_event_trace_point,
+ void *private_data);
+
+typedef void (*tevent_trace_signal_callback_t)(struct tevent_signal *se,
+ enum tevent_event_trace_point,
+ void *private_data);
+
+typedef void (*tevent_trace_timer_callback_t)(struct tevent_timer *te,
+ enum tevent_event_trace_point,
+ void *private_data);
+
+typedef void (*tevent_trace_immediate_callback_t)(struct tevent_immediate *im,
+ enum tevent_event_trace_point,
+ void *private_data);
+
+/**
+ * Register a callback to be called at certain trace points of fd event.
+ *
+ * @param[in] ev Event context
+ * @param[in] cb Trace callback
+ * @param[in] private_data Data to be passed to callback
+ *
+ * @note The callback will be called at trace points defined by
+ * tevent_event_trace_point. Call with NULL to reset.
+ */
+void tevent_set_trace_fd_callback(struct tevent_context *ev,
+ tevent_trace_fd_callback_t cb,
+ void *private_data);
+
+/**
+ * Retrieve the current trace callback of file descriptor event.
+ *
+ * @param[in] ev Event context
+ * @param[out] cb Registered trace callback
+ * @param[out] p_private_data Registered data to be passed to callback
+ *
+ * @note This can be used to allow one component that wants to
+ * register a callback to respect the callback that another component
+ * has already registered.
+ */
+void tevent_get_trace_fd_callback(struct tevent_context *ev,
+ tevent_trace_fd_callback_t *cb,
+ void *p_private_data);
+
+/**
+ * Register a callback to be called at certain trace points of signal event.
+ *
+ * @param[in] ev Event context
+ * @param[in] cb Trace callback
+ * @param[in] private_data Data to be passed to callback
+ *
+ * @note The callback will be called at trace points defined by
+ * tevent_event_trace_point. Call with NULL to reset.
+ */
+void tevent_set_trace_signal_callback(struct tevent_context *ev,
+ tevent_trace_signal_callback_t cb,
+ void *private_data);
+
+/**
+ * Retrieve the current trace callback of signal event.
+ *
+ * @param[in] ev Event context
+ * @param[out] cb Registered trace callback
+ * @param[out] p_private_data Registered data to be passed to callback
+ *
+ * @note This can be used to allow one component that wants to
+ * register a callback to respect the callback that another component
+ * has already registered.
+ */
+void tevent_get_trace_signal_callback(struct tevent_context *ev,
+ tevent_trace_signal_callback_t *cb,
+ void *p_private_data);
+
+/**
+ * Register a callback to be called at certain trace points of timer event.
+ *
+ * @param[in] ev Event context
+ * @param[in] cb Trace callback
+ * @param[in] private_data Data to be passed to callback
+ *
+ * @note The callback will be called at trace points defined by
+ * tevent_event_trace_point. Call with NULL to reset.
+ */
+void tevent_set_trace_timer_callback(struct tevent_context *ev,
+ tevent_trace_timer_callback_t cb,
+ void *private_data);
+
+/**
+ * Retrieve the current trace callback of timer event.
+ *
+ * @param[in] ev Event context
+ * @param[out] cb Registered trace callback
+ * @param[out] p_private_data Registered data to be passed to callback
+ *
+ * @note This can be used to allow one component that wants to
+ * register a callback to respect the callback that another component
+ * has already registered.
+ */
+void tevent_get_trace_timer_callback(struct tevent_context *ev,
+ tevent_trace_timer_callback_t *cb,
+ void *p_private_data);
+
+/**
+ * Register a callback to be called at certain trace points of immediate event.
+ *
+ * @param[in] ev Event context
+ * @param[in] cb Trace callback
+ * @param[in] private_data Data to be passed to callback
+ *
+ * @note The callback will be called at trace points defined by
+ * tevent_event_trace_point. Call with NULL to reset.
+ */
+void tevent_set_trace_immediate_callback(struct tevent_context *ev,
+ tevent_trace_immediate_callback_t cb,
+ void *private_data);
+
+/**
+ * Retrieve the current trace callback of immediate event.
+ *
+ * @param[in] ev Event context
+ * @param[out] cb Registered trace callback
+ * @param[out] p_private_data Registered data to be passed to callback
+ *
+ * @note This can be used to allow one component that wants to
+ * register a callback to respect the callback that another component
+ * has already registered.
+ */
+void tevent_get_trace_immediate_callback(struct tevent_context *ev,
+ tevent_trace_immediate_callback_t *cb,
+ void *p_private_data);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup tevent_request The tevent request functions.
+ * @ingroup tevent
+ *
+ * A tevent_req represents an asynchronous computation.
+ *
+ * The tevent_req group of API calls is the recommended way of
+ * programming async computations within tevent. In particular the
+ * file descriptor (tevent_add_fd) and timer (tevent_add_timed) events
+ * are considered too low-level to be used in larger computations. To
+ * read and write from and to sockets, Samba provides two calls on top
+ * of tevent_add_fd: tstream_read_packet_send/recv and tstream_writev_send/recv.
+ * These requests are much easier to compose than the low-level event
+ * handlers called from tevent_add_fd.
+ *
+ * A lot of the simplicity tevent_req has brought to the notoriously
+ * hairy async programming came via a set of conventions that every
+ * async computation programmed should follow. One central piece of
+ * these conventions is the naming of routines and variables.
+ *
+ * Every async computation needs a name (sensibly called "computation"
+ * down from here). From this name quite a few naming conventions are
+ * derived.
+ *
+ * Every computation that requires local state needs a
+ * @code
+ * struct computation_state {
+ * int local_var;
+ * };
+ * @endcode
+ * Even if no local variables are required, such a state struct should
+ * be created containing a dummy variable. Quite a few helper
+ * functions and macros (for example tevent_req_create()) assume such
+ * a state struct.
+ *
+ * An async computation is started by a computation_send
+ * function. When it is finished, its result can be received by a
+ * computation_recv function. For an example how to set up an async
+ * computation, see the code example in the documentation for
+ * tevent_req_create() and tevent_req_post(). The prototypes for _send
+ * and _recv functions should follow some conventions:
+ *
+ * @code
+ * struct tevent_req *computation_send(TALLOC_CTX *mem_ctx,
+ * struct tevent_context *ev,
+ * ... further args);
+ * int computation_recv(struct tevent_req *req, ... further output args);
+ * @endcode
+ *
+ * The "int" result of computation_recv() depends on the result the
+ * sync version of the function would have, "int" is just an example
+ * here.
+ *
+ * Another important piece of the conventions is that the program flow
+ * is interrupted as little as possible. Because a blocking
+ * sub-computation requires that the flow needs to continue in a
+ * separate function that is the logical sequel of some computation,
+ * it should lexically follow sending off the blocking
+ * sub-computation. Setting the callback function via
+ * tevent_req_set_callback() requires referencing a function lexically
+ * below the call to tevent_req_set_callback(), forward declarations
+ * are required. A lot of the async computations thus begin with a
+ * sequence of declarations such as
+ *
+ * @code
+ * static void computation_step1_done(struct tevent_req *subreq);
+ * static void computation_step2_done(struct tevent_req *subreq);
+ * static void computation_step3_done(struct tevent_req *subreq);
+ * @endcode
+ *
+ * It really helps readability a lot to do these forward declarations,
+ * because the lexically sequential program flow makes the async
+ * computations almost as clear to read as a normal, sync program
+ * flow.
+ *
+ * It is up to the user of the async computation to talloc_free it
+ * after it has finished. If an async computation should be aborted,
+ * the tevent_req structure can be talloc_free'ed. After it has
+ * finished, it should talloc_free'ed by the API user.
+ *
+ * tevent_req variable naming conventions:
+ *
+ * The name of the variable pointing to the tevent_req structure
+ * returned by a _send() function SHOULD be named differently between
+ * implementation and caller.
+ *
+ * From the point of view of the implementation (of the _send() and
+ * _recv() functions) the variable returned by tevent_req_create() is
+ * always called @em req.
+ *
+ * While the caller of the _send() function should use @em subreq to
+ * hold the result.
+ *
+ * @see tevent_req_create()
+ * @see tevent_req_fn()
+ *
+ * @{
+ */
+
+/**
+ * An async request moves from TEVENT_REQ_INIT to
+ * TEVENT_REQ_IN_PROGRESS. All other states are valid after a request
+ * has finished.
+ */
+enum tevent_req_state {
+ /**
+ * We are creating the request
+ */
+ TEVENT_REQ_INIT,
+ /**
+ * We are waiting the request to complete
+ */
+ TEVENT_REQ_IN_PROGRESS,
+ /**
+ * The request is finished successfully
+ */
+ TEVENT_REQ_DONE,
+ /**
+ * A user error has occurred. The user error has been
+ * indicated by tevent_req_error(), it can be retrieved via
+ * tevent_req_is_error().
+ */
+ TEVENT_REQ_USER_ERROR,
+ /**
+ * Request timed out after the timeout set by tevent_req_set_endtime.
+ */
+ TEVENT_REQ_TIMED_OUT,
+ /**
+ * An internal allocation has failed, or tevent_req_nomem has
+ * been given a NULL pointer as the first argument.
+ */
+ TEVENT_REQ_NO_MEMORY,
+ /**
+ * The request has been received by the caller. No further
+ * action is valid.
+ */
+ TEVENT_REQ_RECEIVED
+};
+
+/**
+ * @brief An async request
+ */
+struct tevent_req;
+
+/**
+ * @brief A tevent request callback function.
+ *
+ * @param[in] subreq The tevent async request which executed this callback.
+ */
+typedef void (*tevent_req_fn)(struct tevent_req *subreq);
+
+/**
+ * @brief Set an async request callback.
+ *
+ * See the documentation of tevent_req_post() for an example how this
+ * is supposed to be used.
+ *
+ * @param[in] req The async request to set the callback.
+ *
+ * @param[in] fn The callback function to set.
+ *
+ * @param[in] pvt A pointer to private data to pass to the async request
+ * callback.
+ */
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt);
+void _tevent_req_set_callback(struct tevent_req *req,
+ tevent_req_fn fn,
+ const char *fn_name,
+ void *pvt);
+
+#define tevent_req_set_callback(req, fn, pvt) \
+ _tevent_req_set_callback(req, fn, #fn, pvt)
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the private data cast to the given type for a callback from
+ * a tevent request structure.
+ *
+ * @code
+ * static void computation_done(struct tevent_req *subreq) {
+ * struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
+ * struct computation_state *state = tevent_req_data(req, struct computation_state);
+ * .... more things, eventually maybe call tevent_req_done(req);
+ * }
+ * @endcode
+ *
+ * @param[in] req The structure to get the callback data from.
+ *
+ * @param[in] type The type of the private callback data to get.
+ *
+ * @return The type casted private data set NULL if not set.
+ */
+void *tevent_req_callback_data(struct tevent_req *req, #type);
+#else
+void *_tevent_req_callback_data(struct tevent_req *req);
+#define tevent_req_callback_data(_req, _type) \
+ talloc_get_type_abort(_tevent_req_callback_data(_req), _type)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the private data for a callback from a tevent request structure.
+ *
+ * @param[in] req The structure to get the callback data from.
+ *
+ * @return The private data or NULL if not set.
+ */
+void *tevent_req_callback_data_void(struct tevent_req *req);
+#else
+#define tevent_req_callback_data_void(_req) \
+ _tevent_req_callback_data(_req)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Get the private data from a tevent request structure.
+ *
+ * When the tevent_req has been created by tevent_req_create, the
+ * result of tevent_req_data() is the state variable created by
+ * tevent_req_create() as a child of the req.
+ *
+ * @param[in] req The structure to get the private data from.
+ *
+ * @param[in] type The type of the private data
+ *
+ * @return The private data or NULL if not set.
+ */
+void *tevent_req_data(struct tevent_req *req, #type);
+#else
+void *_tevent_req_data(struct tevent_req *req);
+#define tevent_req_data(_req, _type) \
+ talloc_get_type_abort(_tevent_req_data(_req), _type)
+#endif
+
+/**
+ * @brief The print function which can be set for a tevent async request.
+ *
+ * @param[in] req The tevent async request.
+ *
+ * @param[in] ctx A talloc memory context which can be uses to allocate
+ * memory.
+ *
+ * @return An allocated string buffer to print.
+ *
+ * Example:
+ * @code
+ * static char *my_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
+ * {
+ * struct my_data *data = tevent_req_data(req, struct my_data);
+ * char *result;
+ *
+ * result = tevent_req_default_print(mem_ctx, req);
+ * if (result == NULL) {
+ * return NULL;
+ * }
+ *
+ * return talloc_asprintf_append_buffer(result, "foo=%d, bar=%d",
+ * data->foo, data->bar);
+ * }
+ * @endcode
+ */
+typedef char *(*tevent_req_print_fn)(struct tevent_req *req, TALLOC_CTX *ctx);
+
+/**
+ * @brief This function sets a print function for the given request.
+ *
+ * This function can be used to setup a print function for the given request.
+ * This will be triggered if the tevent_req_print() function was
+ * called on the given request.
+ *
+ * @param[in] req The request to use.
+ *
+ * @param[in] fn A pointer to the print function
+ *
+ * @note This function should only be used for debugging.
+ */
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn);
+
+/**
+ * @brief The default print function for creating debug messages.
+ *
+ * The function should not be used by users of the async API,
+ * but custom print function can use it and append custom text
+ * to the string.
+ *
+ * @param[in] req The request to be printed.
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ *
+ * @return Text representation of request.
+ *
+ */
+char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Print an tevent_req structure in debug messages.
+ *
+ * This function should be used by callers of the async API.
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ *
+ * @param[in] req The request to be printed.
+ *
+ * @return Text representation of request.
+ */
+char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req);
+
+/**
+ * @brief A typedef for a cancel function for a tevent request.
+ *
+ * @param[in] req The tevent request calling this function.
+ *
+ * @return True if the request could be canceled, false if not.
+ */
+typedef bool (*tevent_req_cancel_fn)(struct tevent_req *req);
+
+/**
+ * @brief This function sets a cancel function for the given tevent request.
+ *
+ * This function can be used to setup a cancel function for the given request.
+ * This will be triggered if the tevent_req_cancel() function was
+ * called on the given request.
+ *
+ * @param[in] req The request to use.
+ *
+ * @param[in] fn A pointer to the cancel function.
+ */
+void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn);
+void _tevent_req_set_cancel_fn(struct tevent_req *req,
+ tevent_req_cancel_fn fn,
+ const char *fn_name);
+#define tevent_req_set_cancel_fn(req, fn) \
+ _tevent_req_set_cancel_fn(req, fn, #fn)
+
+#ifdef DOXYGEN
+/**
+ * @brief Try to cancel the given tevent request.
+ *
+ * This function can be used to cancel the given request.
+ *
+ * It is only possible to cancel a request when the implementation
+ * has registered a cancel function via the tevent_req_set_cancel_fn().
+ *
+ * @param[in] req The request to use.
+ *
+ * @return This function returns true if the request is
+ * cancelable, otherwise false is returned.
+ *
+ * @note Even if the function returns true, the caller need to wait
+ * for the function to complete normally.
+ * Only the _recv() function of the given request indicates
+ * if the request was really canceled.
+ */
+bool tevent_req_cancel(struct tevent_req *req);
+#else
+bool _tevent_req_cancel(struct tevent_req *req, const char *location);
+#define tevent_req_cancel(req) \
+ _tevent_req_cancel(req, __location__)
+#endif
+
+/**
+ * @brief A typedef for a cleanup function for a tevent request.
+ *
+ * @param[in] req The tevent request calling this function.
+ *
+ * @param[in] req_state The current tevent_req_state.
+ *
+ */
+typedef void (*tevent_req_cleanup_fn)(struct tevent_req *req,
+ enum tevent_req_state req_state);
+
+/**
+ * @brief This function sets a cleanup function for the given tevent request.
+ *
+ * This function can be used to setup a cleanup function for the given request.
+ * This will be triggered when the tevent_req_done() or tevent_req_error()
+ * function was called, before notifying the callers callback function,
+ * and also before scheduling the deferred trigger.
+ *
+ * This might be useful if more than one tevent_req belong together
+ * and need to finish both requests at the same time.
+ *
+ * The cleanup function is able to call tevent_req_done() or tevent_req_error()
+ * recursively, the cleanup function is only triggered the first time.
+ *
+ * The cleanup function is also called by tevent_req_received()
+ * (possibly triggered from tevent_req_destructor()) before destroying
+ * the private data of the tevent_req.
+ *
+ * @param[in] req The request to use.
+ *
+ * @param[in] fn A pointer to the cancel function.
+ */
+void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn);
+void _tevent_req_set_cleanup_fn(struct tevent_req *req,
+ tevent_req_cleanup_fn fn,
+ const char *fn_name);
+#define tevent_req_set_cleanup_fn(req, fn) \
+ _tevent_req_set_cleanup_fn(req, fn, #fn)
+
+#ifdef DOXYGEN
+/**
+ * @brief Create an async tevent request.
+ *
+ * The new async request will be initialized in state TEVENT_REQ_IN_PROGRESS.
+ *
+ * @code
+ * struct tevent_req *req;
+ * struct computation_state *state;
+ * req = tevent_req_create(mem_ctx, &state, struct computation_state);
+ * @endcode
+ *
+ * Tevent_req_create() allocates and zeros the state variable as a talloc
+ * child of its result. The state variable should be used as the talloc
+ * parent for all temporary variables that are allocated during the async
+ * computation. This way, when the user of the async computation frees
+ * the request, the state as a talloc child will be free'd along with
+ * all the temporary variables hanging off the state.
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] pstate Pointer to the private request state.
+ * @param[in] type The name of the request.
+ *
+ * @return A new async request. NULL on error.
+ */
+struct tevent_req *tevent_req_create(TALLOC_CTX *mem_ctx,
+ void **pstate, #type);
+#else
+struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
+ void *pstate,
+ size_t state_size,
+ const char *type,
+ const char *location);
+
+struct tevent_req *__tevent_req_create(TALLOC_CTX *mem_ctx,
+ void *pstate,
+ size_t state_size,
+ const char *type,
+ const char *func,
+ const char *location);
+
+#define tevent_req_create(_mem_ctx, _pstate, _type) \
+ __tevent_req_create((_mem_ctx), \
+ (_pstate), \
+ sizeof(_type), \
+ #_type, \
+ __func__, \
+ __location__)
+#endif
+
+/**
+ * @brief Set a timeout for an async request. On failure, "req" is already
+ * set to state TEVENT_REQ_NO_MEMORY.
+ *
+ * @param[in] req The request to set the timeout for.
+ *
+ * @param[in] ev The event context to use for the timer.
+ *
+ * @param[in] endtime The endtime of the request.
+ *
+ * @return True if succeeded, false if not.
+ */
+bool tevent_req_set_endtime(struct tevent_req *req,
+ struct tevent_context *ev,
+ struct timeval endtime);
+
+/**
+ * @brief Reset the timer set by tevent_req_set_endtime.
+ *
+ * @param[in] req The request to reset the timeout for
+ */
+void tevent_req_reset_endtime(struct tevent_req *req);
+
+#ifdef DOXYGEN
+/**
+ * @brief Call the notify callback of the given tevent request manually.
+ *
+ * @param[in] req The tevent request to call the notify function from.
+ *
+ * @see tevent_req_set_callback()
+ */
+void tevent_req_notify_callback(struct tevent_req *req);
+#else
+void _tevent_req_notify_callback(struct tevent_req *req, const char *location);
+#define tevent_req_notify_callback(req) \
+ _tevent_req_notify_callback(req, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief An async request has successfully finished.
+ *
+ * This function is to be used by implementors of async requests. When a
+ * request is successfully finished, this function calls the user's completion
+ * function.
+ *
+ * @param[in] req The finished request.
+ */
+void tevent_req_done(struct tevent_req *req);
+#else
+void _tevent_req_done(struct tevent_req *req,
+ const char *location);
+#define tevent_req_done(req) \
+ _tevent_req_done(req, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief An async request has seen an error.
+ *
+ * This function is to be used by implementors of async requests. When a
+ * request can not successfully completed, the implementation should call this
+ * function with the appropriate status code.
+ *
+ * If error is 0 the function returns false and does nothing more.
+ *
+ * @param[in] req The request with an error.
+ *
+ * @param[in] error The error code.
+ *
+ * @return On success true is returned, false if error is 0.
+ *
+ * @code
+ * int error = first_function();
+ * if (tevent_req_error(req, error)) {
+ * return;
+ * }
+ *
+ * error = second_function();
+ * if (tevent_req_error(req, error)) {
+ * return;
+ * }
+ *
+ * tevent_req_done(req);
+ * return;
+ * @endcode
+ */
+bool tevent_req_error(struct tevent_req *req,
+ uint64_t error);
+#else
+bool _tevent_req_error(struct tevent_req *req,
+ uint64_t error,
+ const char *location);
+#define tevent_req_error(req, error) \
+ _tevent_req_error(req, error, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Helper function for nomem check.
+ *
+ * Convenience helper to easily check alloc failure within a callback
+ * implementing the next step of an async request.
+ *
+ * @param[in] p The pointer to be checked.
+ *
+ * @param[in] req The request being processed.
+ *
+ * @code
+ * p = talloc(mem_ctx, bla);
+ * if (tevent_req_nomem(p, req)) {
+ * return;
+ * }
+ * @endcode
+ */
+bool tevent_req_nomem(const void *p,
+ struct tevent_req *req);
+#else
+bool _tevent_req_nomem(const void *p,
+ struct tevent_req *req,
+ const char *location);
+#define tevent_req_nomem(p, req) \
+ _tevent_req_nomem(p, req, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Indicate out of memory to a request
+ *
+ * @param[in] req The request being processed.
+ */
+void tevent_req_oom(struct tevent_req *req);
+#else
+void _tevent_req_oom(struct tevent_req *req,
+ const char *location);
+#define tevent_req_oom(req) \
+ _tevent_req_oom(req, __location__)
+#endif
+
+/**
+ * @brief Finish a request before the caller had a chance to set the callback.
+ *
+ * An implementation of an async request might find that it can either finish
+ * the request without waiting for an external event, or it can not even start
+ * the engine. To present the illusion of a callback to the user of the API,
+ * the implementation can call this helper function which triggers an
+ * immediate event. This way the caller can use the same calling
+ * conventions, independent of whether the request was actually deferred.
+ *
+ * @code
+ * struct tevent_req *computation_send(TALLOC_CTX *mem_ctx,
+ * struct tevent_context *ev)
+ * {
+ * struct tevent_req *req, *subreq;
+ * struct computation_state *state;
+ * req = tevent_req_create(mem_ctx, &state, struct computation_state);
+ * if (req == NULL) {
+ * return NULL;
+ * }
+ * subreq = subcomputation_send(state, ev);
+ * if (tevent_req_nomem(subreq, req)) {
+ * return tevent_req_post(req, ev);
+ * }
+ * tevent_req_set_callback(subreq, computation_done, req);
+ * return req;
+ * }
+ * @endcode
+ *
+ * @param[in] req The finished request.
+ *
+ * @param[in] ev The tevent_context for the immediate event.
+ *
+ * @return The given request will be returned.
+ */
+struct tevent_req *tevent_req_post(struct tevent_req *req,
+ struct tevent_context *ev);
+
+/**
+ * @brief Finish multiple requests within one function
+ *
+ * Normally tevent_req_notify_callback() and all wrappers
+ * (e.g. tevent_req_done() and tevent_req_error())
+ * need to be the last thing an event handler should call.
+ * This is because the callback is likely to destroy the
+ * context of the current function.
+ *
+ * If a function wants to notify more than one caller,
+ * it is dangerous if it just triggers multiple callbacks
+ * in a row. With tevent_req_defer_callback() it is possible
+ * to set an event context that will be used to defer the callback
+ * via an immediate event (similar to tevent_req_post()).
+ *
+ * @code
+ * struct complete_state {
+ * struct tevent_context *ev;
+ *
+ * struct tevent_req **reqs;
+ * };
+ *
+ * void complete(struct complete_state *state)
+ * {
+ * size_t i, c = talloc_array_length(state->reqs);
+ *
+ * for (i=0; i < c; i++) {
+ * tevent_req_defer_callback(state->reqs[i], state->ev);
+ * tevent_req_done(state->reqs[i]);
+ * }
+ * }
+ * @endcode
+ *
+ * @param[in] req The finished request.
+ *
+ * @param[in] ev The tevent_context for the immediate event.
+ *
+ * @return The given request will be returned.
+ */
+void tevent_req_defer_callback(struct tevent_req *req,
+ struct tevent_context *ev);
+
+/**
+ * @brief Check if the given request is still in progress.
+ *
+ * It is typically used by sync wrapper functions.
+ *
+ * @param[in] req The request to poll.
+ *
+ * @return The boolean form of "is in progress".
+ */
+bool tevent_req_is_in_progress(struct tevent_req *req);
+
+/**
+ * @brief Actively poll for the given request to finish.
+ *
+ * This function is typically used by sync wrapper functions.
+ *
+ * @param[in] req The request to poll.
+ *
+ * @param[in] ev The tevent_context to be used.
+ *
+ * @return On success true is returned. If a critical error has
+ * happened in the tevent loop layer false is returned.
+ * This is not the return value of the given request!
+ *
+ * @note This should only be used if the given tevent context was created by the
+ * caller, to avoid event loop nesting.
+ *
+ * @code
+ * req = tstream_writev_queue_send(mem_ctx,
+ * ev_ctx,
+ * tstream,
+ * send_queue,
+ * iov, 2);
+ * ok = tevent_req_poll(req, tctx->ev);
+ * rc = tstream_writev_queue_recv(req, &sys_errno);
+ * TALLOC_FREE(req);
+ * @endcode
+ */
+bool tevent_req_poll(struct tevent_req *req,
+ struct tevent_context *ev);
+
+/**
+ * @brief Get the tevent request state and the actual error set by
+ * tevent_req_error.
+ *
+ * @code
+ * int computation_recv(struct tevent_req *req, uint64_t *perr)
+ * {
+ * enum tevent_req_state state;
+ * uint64_t err;
+ * if (tevent_req_is_error(req, &state, &err)) {
+ * *perr = err;
+ * return -1;
+ * }
+ * return 0;
+ * }
+ * @endcode
+ *
+ * @param[in] req The tevent request to get the error from.
+ *
+ * @param[out] state A pointer to store the tevent request error state.
+ *
+ * @param[out] error A pointer to store the error set by tevent_req_error().
+ *
+ * @return True if the function could set error and state, false
+ * otherwise.
+ *
+ * @see tevent_req_error()
+ */
+bool tevent_req_is_error(struct tevent_req *req,
+ enum tevent_req_state *state,
+ uint64_t *error);
+
+/**
+ * @brief Use as the last action of a _recv() function.
+ *
+ * This function destroys the attached private data.
+ *
+ * @param[in] req The finished request.
+ */
+void tevent_req_received(struct tevent_req *req);
+
+/**
+ * @brief Mark a tevent_req for profiling
+ *
+ * This will turn on profiling for this tevent_req an all subreqs that
+ * are directly started as helper requests off this
+ * tevent_req. subreqs are chained by walking up the talloc_parent
+ * hierarchy at a subreq's tevent_req_create. This means to get the
+ * profiling chain right the subreq that needs to be profiled as part
+ * of this tevent_req's profile must be a talloc child of the requests
+ * state variable.
+ *
+ * @param[in] req The request to do tracing for
+ *
+ * @return False if the profile could not be activated
+ */
+bool tevent_req_set_profile(struct tevent_req *req);
+
+struct tevent_req_profile;
+
+/**
+ * @brief Get a request's profile for inspection
+ *
+ * @param[in] req The request to get the profile from
+ *
+ * @return The request's profile
+ */
+const struct tevent_req_profile *tevent_req_get_profile(
+ struct tevent_req *req);
+
+/**
+ * @brief Move the profile out of a request
+ *
+ * This function detaches the request's profile from the request, so
+ * that the profile can outlive the request in a _recv function.
+ *
+ * @param[in] req The request to move the profile out of
+ * @param[in] mem_ctx The new talloc context for the profile
+ *
+ * @return The moved profile
+ */
+
+struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Get a profile description
+ *
+ * @param[in] profile The profile to be queried
+ * @param[in] req_name The name of the request (state's name)
+ *
+ * "req_name" after this call is still in talloc-posession of "profile"
+ */
+void tevent_req_profile_get_name(const struct tevent_req_profile *profile,
+ const char **req_name);
+
+/**
+ * @brief Get a profile's start event data
+ *
+ * @param[in] profile The profile to be queried
+ * @param[in] start_location The location where this event started
+ * @param[in] start_time The time this event started
+ *
+ * "start_location" after this call is still in talloc-posession of "profile"
+ */
+void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
+ const char **start_location,
+ struct timeval *start_time);
+
+/**
+ * @brief Get a profile's stop event data
+ *
+ * @param[in] profile The profile to be queried
+ * @param[in] stop_location The location where this event stopped
+ * @param[in] stop_time The time this event stopped
+ *
+ * "stop_location" after this call is still in talloc-posession of "profile"
+ */
+void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
+ const char **stop_location,
+ struct timeval *stop_time);
+
+/**
+ * @brief Get a profile's result data
+ *
+ * @param[in] pid The process where this profile was taken
+ * @param[in] state The status the profile's tevent_req finished with
+ * @param[in] user_error The user error of the profile's tevent_req
+ */
+void tevent_req_profile_get_status(const struct tevent_req_profile *profile,
+ pid_t *pid,
+ enum tevent_req_state *state,
+ uint64_t *user_error);
+
+/**
+ * @brief Retrieve the first subreq's profile from a profile
+ *
+ * @param[in] profile The profile to query
+ *
+ * @return The first tevent subreq's profile
+ */
+const struct tevent_req_profile *tevent_req_profile_get_subprofiles(
+ const struct tevent_req_profile *profile);
+
+/**
+ * @brief Walk the chain of subreqs
+ *
+ * @param[in] profile The subreq's profile to walk
+ *
+ * @return The next subprofile in the list
+ */
+const struct tevent_req_profile *tevent_req_profile_next(
+ const struct tevent_req_profile *profile);
+
+/**
+ * @brief Create a fresh tevent_req_profile
+ *
+ * @param[in] mem_ctx The talloc context to hang the fresh struct off
+ *
+ * @return The fresh struct
+ */
+struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Set a profile's name
+ *
+ * @param[in] profile The profile to set the name for
+ * @param[in] name The new name for the profile
+ *
+ * @return True if the internal talloc_strdup succeeded
+ */
+bool tevent_req_profile_set_name(struct tevent_req_profile *profile,
+ const char *name);
+
+/**
+ * @brief Set a profile's start event
+ *
+ * @param[in] profile The profile to set the start data for
+ * @param[in] start_location The new start location
+ * @param[in] start_time The new start time
+ *
+ * @return True if the internal talloc_strdup succeeded
+ */
+bool tevent_req_profile_set_start(struct tevent_req_profile *profile,
+ const char *start_location,
+ struct timeval start_time);
+
+/**
+ * @brief Set a profile's stop event
+ *
+ * @param[in] profile The profile to set the stop data for
+ * @param[in] stop_location The new stop location
+ * @param[in] stop_time The new stop time
+ *
+ * @return True if the internal talloc_strdup succeeded
+ */
+bool tevent_req_profile_set_stop(struct tevent_req_profile *profile,
+ const char *stop_location,
+ struct timeval stop_time);
+
+/**
+ * @brief Set a profile's exit status
+ *
+ * @param[in] profile The profile to set the exit status for
+ * @param[in] pid The process where this profile was taken
+ * @param[in] state The status the profile's tevent_req finished with
+ * @param[in] user_error The user error of the profile's tevent_req
+ */
+void tevent_req_profile_set_status(struct tevent_req_profile *profile,
+ pid_t pid,
+ enum tevent_req_state state,
+ uint64_t user_error);
+
+/**
+ * @brief Add a subprofile to a profile
+ *
+ * @param[in] parent_profile The profile to be modified
+ * @param[in] sub_profile The subreqs profile profile to be added
+ *
+ * "subreq" is talloc_move'ed into "parent_profile", so the talloc
+ * ownership of "sub_profile" changes
+ */
+
+void tevent_req_profile_append_sub(struct tevent_req_profile *parent_profile,
+ struct tevent_req_profile **sub_profile);
+
+/**
+ * @brief Create a tevent subrequest at a given time.
+ *
+ * The idea is that always the same syntax for tevent requests.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The event handle to setup the request.
+ *
+ * @param[in] wakeup_time The time to wakeup and execute the request.
+ *
+ * @return The new subrequest, NULL on error.
+ *
+ * Example:
+ * @code
+ * static void my_callback_wakeup_done(tevent_req *subreq)
+ * {
+ * struct tevent_req *req = tevent_req_callback_data(subreq,
+ * struct tevent_req);
+ * bool ok;
+ *
+ * ok = tevent_wakeup_recv(subreq);
+ * TALLOC_FREE(subreq);
+ * if (!ok) {
+ * tevent_req_error(req, -1);
+ * return;
+ * }
+ * ...
+ * }
+ * @endcode
+ *
+ * @code
+ * subreq = tevent_wakeup_send(mem_ctx, ev, wakeup_time);
+ * if (tevent_req_nomem(subreq, req)) {
+ * return false;
+ * }
+ * tevent_set_callback(subreq, my_callback_wakeup_done, req);
+ * @endcode
+ *
+ * @see tevent_wakeup_recv()
+ */
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval wakeup_time);
+
+/**
+ * @brief Check if the wakeup has been correctly executed.
+ *
+ * This function needs to be called in the callback function set after calling
+ * tevent_wakeup_send().
+ *
+ * @param[in] req The tevent request to check.
+ *
+ * @return True on success, false otherwise.
+ *
+ * @see tevent_wakeup_recv()
+ */
+bool tevent_wakeup_recv(struct tevent_req *req);
+
+/* @} */
+
+/**
+ * @defgroup tevent_helpers The tevent helper functions
+ * @ingroup tevent
+ *
+ * @todo description
+ *
+ * @{
+ */
+
+/**
+ * @brief Compare two timeval values.
+ *
+ * @param[in] tv1 The first timeval value to compare.
+ *
+ * @param[in] tv2 The second timeval value to compare.
+ *
+ * @return 0 if they are equal.
+ * 1 if the first time is greater than the second.
+ * -1 if the first time is smaller than the second.
+ */
+int tevent_timeval_compare(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+/**
+ * @brief Get a zero timeval value.
+ *
+ * @return A zero timeval value.
+ */
+struct timeval tevent_timeval_zero(void);
+
+/**
+ * @brief Get a timeval value for the current time.
+ *
+ * @return A timeval value with the current time.
+ */
+struct timeval tevent_timeval_current(void);
+
+/**
+ * @brief Get a timeval structure with the given values.
+ *
+ * @param[in] secs The seconds to set.
+ *
+ * @param[in] usecs The microseconds to set.
+ *
+ * @return A timeval structure with the given values.
+ */
+struct timeval tevent_timeval_set(uint32_t secs, uint32_t usecs);
+
+/**
+ * @brief Get the difference between two timeval values.
+ *
+ * @param[in] tv1 The first timeval.
+ *
+ * @param[in] tv2 The second timeval.
+ *
+ * @return A timeval structure with the difference between the
+ * first and the second value.
+ */
+struct timeval tevent_timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+/**
+ * @brief Check if a given timeval structure is zero.
+ *
+ * @param[in] tv The timeval to check if it is zero.
+ *
+ * @return True if it is zero, false otherwise.
+ */
+bool tevent_timeval_is_zero(const struct timeval *tv);
+
+/**
+ * @brief Add the given amount of time to a timeval structure.
+ *
+ * @param[in] tv The timeval structure to add the time.
+ *
+ * @param[in] secs The seconds to add to the timeval.
+ *
+ * @param[in] usecs The microseconds to add to the timeval.
+ *
+ * @return The timeval structure with the new time.
+ */
+struct timeval tevent_timeval_add(const struct timeval *tv, uint32_t secs,
+ uint32_t usecs);
+
+/**
+ * @brief Get a timeval in the future with a specified offset from now.
+ *
+ * @param[in] secs The seconds of the offset from now.
+ *
+ * @param[in] usecs The microseconds of the offset from now.
+ *
+ * @return A timeval with the given offset in the future.
+ */
+struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs);
+
+/**
+ *
+ * @brief A cached version of getpid()
+ *
+ * We use getpid() in a lot a performance critical situations
+ * in order to check if caches are still valid in the current process.
+ *
+ * Calling getpid() always add the cost of an additional syscall!
+ *
+ * When tevent is build with pthread support, we already make use
+ * of pthread_atfork(), so it's trivial to use it maintain a cache for getpid().
+ *
+ * @return The pid of the current process.
+ */
+pid_t tevent_cached_getpid(void);
+
+/* @} */
+
+
+/**
+ * @defgroup tevent_thread_call_depth The tevent call depth tracking functions
+ * @ingroup tevent
+ *
+ *
+ * The call depth tracking consists of two parts.
+ *
+ * Part 1 - storing the depth inside each tevent request.
+ *
+ * Each instance of 'struct tevent_req' internally stores the value of the
+ * current depth. If a new subrequest is created via tevent_req_create(), the
+ * newly created subrequest gets the value from the parent incremented by 1.
+ *
+ * Part 2 - updating external variable with the call depth of the currently
+ * processed tevent request.
+ *
+ * The intended use of call depth is for the trace indentation. This is done
+ * by registering the address of an external size_t variable via
+ * tevent_thread_call_depth_activate(). And the tracing code just reads it's
+ * value.
+ *
+ * The updates happen during:
+ *
+ * tevent_req_create()
+ * - external variable is set to the value of the newly created request (i.e.
+ * value of the parent incremented by 1)
+ *
+ * tevent_req_notify_callback()
+ * - external variable is set to the value of the parent tevent request, which
+ * is just about to be processed
+ *
+ * tevent_queue_immediate_trigger()
+ * - external variable is set to the value of the request coming from the queue
+ *
+ *
+ * While 'Part 1' maintains the call depth value inside each teven request
+ * precisely, the value of the external variable depends on the call flow and
+ * can be changed after return from a function call, so it no longer matches
+ * the value of the request being processed in the current function.
+ *
+ * @code
+ * struct tevent_req *foo_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
+ * {
+ * struct tevent_req *req, *subreq;
+ * struct foo_state *state;
+ *
+ * // External variable has value 'X', which is the value in parent code
+ * // It is ok, since tracing starts often only after tevent_req_create()
+ * req = tevent_req_create(mem_ctx, &state, struct foo_state);
+ *
+ * // External variable has now value 'X + 1'
+ * D_DEBUG("foo_send(): the external variable has the expected value\n");
+ *
+ * subreq = bar_send(state, ev, ...);
+ * tevent_req_set_callback(subreq, foo_done, req);
+ *
+ * // External variable has value 'X + 1 + n', where n > 0 and n is the
+ * // depth reached in bar_send().
+ * // We want to reset it via tevent_thread_call_depth_reset_from_req(),
+ * // since we want the following D_DEBUG() to have the right trace
+ * //indentation.
+ *
+ * tevent_thread_call_depth_reset_from_req(req);
+ * // External variable has again value 'X + 1' taken from req.
+ * D_DEBUG("foo_send(): the external variable has the expected value\n");
+ * return req;
+ * }
+ *
+ * static void foo_done(struct tevent_req *subreq)
+ * {
+ * struct tevent_req *req =
+ * tevent_req_callback_data(subreq,
+ * struct tevent_req);
+ * struct foo_state *state =
+ * tevent_req_data(req,
+ * struct foo_state);
+ *
+ * // external variable has value 'X + 1'
+ *
+ * D_DEBUG("foo_done(): the external variable has the expected value\n");
+ * status = bar_recv(subreq, state, ...)
+ * tevent_req_done(req);
+ * }
+ *
+ * NTSTATUS foo_recv(struct tevent_req *req)
+ * {
+ * struct foo_state *state = tevent_req_data( req, struct foo_state);
+ *
+ * // external variable has value 'X' (not 'X + 1')
+ * // which is ok, if we consider _recv() to be an access function
+ * // called from the parent context
+ *
+ * D_DEBUG("foo_recv(): external variable has the value from parent\n");
+ * return NT_STATUS_OK;
+ * }
+ * @endcode
+ *
+ * Interface has 3 parts:
+ *
+ * Part 1: activation/deactivation
+ *
+ * void tevent_thread_call_depth_set_callback(f, private_data)
+ * Register a callback that can track 'call depth' and 'request flow'
+ * NULL as a function callback means deactivation.
+ *
+ * Part 2: Mark the request (and its subrequests) to be tracked
+ *
+ * tevent_thread_call_depth_start(struct tevent_req *req)
+ *
+ * By default, all newly created requests have call depth set to 0.
+ * tevent_thread_call_depth_start() should be called shortly after
+ * tevent_req_create(). It sets the call depth to 1.
+ * Subrequest will have call depth 2 and so on.
+ *
+ * Part 3: reset the external variable using value from tevent request
+ *
+ * tevent_thread_call_depth_reset_from_req(struct tevent_req *req)
+ *
+ * If the call depth is used for trace indentation, it might be useful to
+ * reset the external variable to the call depth of currently processed tevent
+ * request, since the ext. variable can be changed after return from a function
+ * call that has created subrequests.
+ *
+ * THREADING
+ *
+ * The state is thread specific, i.e. each thread can activate it and register
+ * its own external variable.
+ *
+ * @{
+ */
+
+enum tevent_thread_call_depth_cmd {
+ TEVENT_CALL_FLOW_REQ_RESET,
+ TEVENT_CALL_FLOW_REQ_CREATE,
+ TEVENT_CALL_FLOW_REQ_CANCEL,
+ TEVENT_CALL_FLOW_REQ_CLEANUP,
+ TEVENT_CALL_FLOW_REQ_NOTIFY_CB,
+ TEVENT_CALL_FLOW_REQ_QUEUE_ENTER,
+ TEVENT_CALL_FLOW_REQ_QUEUE_TRIGGER,
+ TEVENT_CALL_FLOW_REQ_QUEUE_LEAVE,
+};
+
+typedef void (*tevent_call_depth_callback_t)(
+ void *private_data,
+ enum tevent_thread_call_depth_cmd cmd,
+ struct tevent_req *req,
+ size_t depth,
+ const char *fname);
+
+struct tevent_thread_call_depth_state {
+ tevent_call_depth_callback_t cb;
+ void *cb_private;
+};
+
+extern __thread struct tevent_thread_call_depth_state
+ tevent_thread_call_depth_state_g;
+
+/**
+ * Register callback function for request/subrequest call depth / flow tracking.
+ *
+ * @param[in] f External call depth and flow handling function
+ */
+void tevent_thread_call_depth_set_callback(tevent_call_depth_callback_t f,
+ void *private_data);
+
+#ifdef TEVENT_DEPRECATED
+
+void tevent_thread_call_depth_activate(size_t *ptr) _DEPRECATED_;
+void tevent_thread_call_depth_deactivate(void) _DEPRECATED_;
+void tevent_thread_call_depth_start(struct tevent_req *req) _DEPRECATED_;
+
+#endif
+
+/**
+ * Reset the external call depth to the call depth of the request.
+ *
+ * @param[in] req Request from which the call depth is reset.
+ * variable.
+ */
+void tevent_thread_call_depth_reset_from_req(struct tevent_req *req);
+
+void _tevent_thread_call_depth_reset_from_req(struct tevent_req *req,
+ const char *fname);
+
+#define tevent_thread_call_depth_reset_from_req(req) \
+ _tevent_thread_call_depth_reset_from_req(req, __func__)
+
+/* @} */
+
+
+/**
+ * @defgroup tevent_queue The tevent queue functions
+ * @ingroup tevent
+ *
+ * A tevent_queue is used to queue up async requests that must be
+ * serialized. For example writing buffers into a socket must be
+ * serialized. Writing a large lump of data into a socket can require
+ * multiple write(2) or send(2) system calls. If more than one async
+ * request is outstanding to write large buffers into a socket, every
+ * request must individually be completed before the next one begins,
+ * even if multiple syscalls are required.
+ *
+ * Take a look at @ref tevent_queue_tutorial for more details.
+ * @{
+ */
+
+struct tevent_queue;
+struct tevent_queue_entry;
+
+/**
+ * @brief Associate a custom tag with the queue entry.
+ *
+ * This tag can be then retrieved with tevent_queue_entry_get_tag()
+ *
+ * @param[in] qe The queue entry.
+ *
+ * @param[in] tag Custom tag.
+ */
+void tevent_queue_entry_set_tag(struct tevent_queue_entry *qe, uint64_t tag);
+
+/**
+ * @brief Get custom queue entry tag.
+ */
+uint64_t tevent_queue_entry_get_tag(const struct tevent_queue_entry *qe);
+
+typedef void (*tevent_trace_queue_callback_t)(struct tevent_queue_entry *qe,
+ enum tevent_event_trace_point,
+ void *private_data);
+
+/**
+ * Register a callback to be called at certain trace points of queue.
+ *
+ * @param[in] ev Event context
+ * @param[in] cb Trace callback
+ * @param[in] private_data Data to be passed to callback
+ *
+ * @note The callback will be called at trace points defined by
+ * tevent_event_trace_point. Call with NULL to reset.
+ */
+void tevent_set_trace_queue_callback(struct tevent_context *ev,
+ tevent_trace_queue_callback_t cb,
+ void *private_data);
+
+/**
+ * Retrieve the current trace callback of queue.
+ *
+ * @param[in] ev Event context
+ * @param[out] cb Registered trace callback
+ * @param[out] p_private_data Registered data to be passed to callback
+ *
+ * @note This can be used to allow one component that wants to
+ * register a callback to respect the callback that another component
+ * has already registered.
+ */
+void tevent_get_trace_queue_callback(struct tevent_context *ev,
+ tevent_trace_queue_callback_t *cb,
+ void *p_private_data);
+
+#ifdef DOXYGEN
+/**
+ * @brief Create and start a tevent queue.
+ *
+ * @param[in] mem_ctx The talloc memory context to allocate the queue.
+ *
+ * @param[in] name The name to use to identify the queue.
+ *
+ * @return An allocated tevent queue on success, NULL on error.
+ *
+ * @see tevent_queue_start()
+ * @see tevent_queue_stop()
+ */
+struct tevent_queue *tevent_queue_create(TALLOC_CTX *mem_ctx,
+ const char *name);
+#else
+struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *location);
+
+#define tevent_queue_create(_mem_ctx, _name) \
+ _tevent_queue_create((_mem_ctx), (_name), __location__)
+#endif
+
+/**
+ * @brief A callback trigger function run by the queue.
+ *
+ * @param[in] req The tevent request the trigger function is executed on.
+ *
+ * @param[in] private_data The private data pointer specified by
+ * tevent_queue_add().
+ *
+ * @see tevent_queue_add()
+ * @see tevent_queue_add_entry()
+ * @see tevent_queue_add_optimize_empty()
+ */
+typedef void (*tevent_queue_trigger_fn_t)(struct tevent_req *req,
+ void *private_data);
+
+/**
+ * @brief Add a tevent request to the queue.
+ *
+ * @param[in] queue The queue to add the request.
+ *
+ * @param[in] ev The event handle to use for the request.
+ *
+ * @param[in] req The tevent request to add to the queue.
+ *
+ * @param[in] trigger The function triggered by the queue when the request
+ * is called. Since tevent 0.9.14 it's possible to
+ * pass NULL, in order to just add a "blocker" to the
+ * queue.
+ *
+ * @param[in] private_data The private data passed to the trigger function.
+ *
+ * @return True if the request has been successfully added, false
+ * otherwise.
+ */
+bool tevent_queue_add(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data);
+
+bool _tevent_queue_add(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ const char* trigger_name,
+ void *private_data);
+
+#define tevent_queue_add(queue, ev, req, trigger, private_data) \
+ _tevent_queue_add(queue, ev, req, trigger, #trigger, private_data)
+
+/**
+ * @brief Add a tevent request to the queue.
+ *
+ * The request can be removed from the queue by calling talloc_free()
+ * (or a similar function) on the returned queue entry. This
+ * is the only difference to tevent_queue_add().
+ *
+ * @param[in] queue The queue to add the request.
+ *
+ * @param[in] ev The event handle to use for the request.
+ *
+ * @param[in] req The tevent request to add to the queue.
+ *
+ * @param[in] trigger The function triggered by the queue when the request
+ * is called. Since tevent 0.9.14 it's possible to
+ * pass NULL, in order to just add a "blocker" to the
+ * queue.
+ *
+ * @param[in] private_data The private data passed to the trigger function.
+ *
+ * @return a pointer to the tevent_queue_entry if the request
+ * has been successfully added, NULL otherwise.
+ *
+ * @see tevent_queue_add()
+ * @see tevent_queue_add_optimize_empty()
+ */
+struct tevent_queue_entry *tevent_queue_add_entry(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data);
+
+struct tevent_queue_entry *_tevent_queue_add_entry(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ const char* trigger_name,
+ void *private_data);
+
+#define tevent_queue_add_entry(queue, ev, req, trigger, private_data) \
+ _tevent_queue_add_entry(queue, ev, req, trigger, #trigger, private_data);
+
+/**
+ * @brief Add a tevent request to the queue using a possible optimization.
+ *
+ * This tries to optimize for the empty queue case and may calls
+ * the trigger function directly. This is the only difference compared
+ * to tevent_queue_add_entry().
+ *
+ * The caller needs to be prepared that the trigger function has
+ * already called tevent_req_notify_callback(), tevent_req_error(),
+ * tevent_req_done() or a similar function.
+ *
+ * The trigger function has no chance to see the returned
+ * queue_entry in the optimized case.
+ *
+ * The request can be removed from the queue by calling talloc_free()
+ * (or a similar function) on the returned queue entry.
+ *
+ * @param[in] queue The queue to add the request.
+ *
+ * @param[in] ev The event handle to use for the request.
+ *
+ * @param[in] req The tevent request to add to the queue.
+ *
+ * @param[in] trigger The function triggered by the queue when the request
+ * is called. Since tevent 0.9.14 it's possible to
+ * pass NULL, in order to just add a "blocker" to the
+ * queue.
+ *
+ * @param[in] private_data The private data passed to the trigger function.
+ *
+ * @return a pointer to the tevent_queue_entry if the request
+ * has been successfully added, NULL otherwise.
+ *
+ * @see tevent_queue_add()
+ * @see tevent_queue_add_entry()
+ */
+struct tevent_queue_entry *tevent_queue_add_optimize_empty(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data);
+
+struct tevent_queue_entry *_tevent_queue_add_optimize_empty(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ const char* trigger_name,
+ void *private_data);
+
+#define tevent_queue_add_optimize_empty(queue, ev, req, trigger, private_data) \
+ _tevent_queue_add_optimize_empty(queue, ev, req, trigger, #trigger, private_data)
+
+/**
+ * @brief Untrigger an already triggered queue entry.
+ *
+ * If a trigger function detects that it needs to remain
+ * in the queue, it needs to call tevent_queue_stop()
+ * followed by tevent_queue_entry_untrigger().
+ *
+ * @note In order to call tevent_queue_entry_untrigger()
+ * the queue must be already stopped and the given queue_entry
+ * must be the first one in the queue! Otherwise it calls abort().
+ *
+ * @note You can't use this together with tevent_queue_add_optimize_empty()
+ * because the trigger function doesn't have access to the queue entry
+ * in the case of an empty queue.
+ *
+ * @param[in] queue_entry The queue entry to rearm.
+ *
+ * @see tevent_queue_add_entry()
+ * @see tevent_queue_stop()
+ */
+void tevent_queue_entry_untrigger(struct tevent_queue_entry *entry);
+
+/**
+ * @brief Start a tevent queue.
+ *
+ * The queue is started by default.
+ *
+ * @param[in] queue The queue to start.
+ */
+void tevent_queue_start(struct tevent_queue *queue);
+
+/**
+ * @brief Stop a tevent queue.
+ *
+ * The queue is started by default.
+ *
+ * @param[in] queue The queue to stop.
+ */
+void tevent_queue_stop(struct tevent_queue *queue);
+
+/**
+ * @brief Get the length of the queue.
+ *
+ * @param[in] queue The queue to get the length from.
+ *
+ * @return The number of elements.
+ */
+size_t tevent_queue_length(struct tevent_queue *queue);
+
+/**
+ * @brief Is the tevent queue running.
+ *
+ * The queue is started by default.
+ *
+ * @param[in] queue The queue.
+ *
+ * @return Whether the queue is running or not..
+ */
+bool tevent_queue_running(struct tevent_queue *queue);
+
+/**
+ * @brief Create a tevent subrequest that waits in a tevent_queue
+ *
+ * The idea is that always the same syntax for tevent requests.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The event handle to setup the request.
+ *
+ * @param[in] queue The queue to wait in.
+ *
+ * @return The new subrequest, NULL on error.
+ *
+ * @see tevent_queue_wait_recv()
+ */
+struct tevent_req *tevent_queue_wait_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tevent_queue *queue);
+
+/**
+ * @brief Check if we no longer need to wait in the queue.
+ *
+ * This function needs to be called in the callback function set after calling
+ * tevent_queue_wait_send().
+ *
+ * @param[in] req The tevent request to check.
+ *
+ * @return True on success, false otherwise.
+ *
+ * @see tevent_queue_wait_send()
+ */
+bool tevent_queue_wait_recv(struct tevent_req *req);
+
+typedef int (*tevent_nesting_hook)(struct tevent_context *ev,
+ void *private_data,
+ uint32_t level,
+ bool begin,
+ void *stack_ptr,
+ const char *location);
+
+/**
+ * @brief Create a tevent_thread_proxy for message passing between threads.
+ *
+ * The tevent_context must have been allocated on the NULL
+ * talloc context, and talloc_disable_null_tracking() must
+ * have been called.
+ *
+ * @param[in] dest_ev_ctx The tevent_context to receive events.
+ *
+ * @return An allocated tevent_thread_proxy, NULL on error.
+ * If tevent was compiled without PTHREAD support
+ * NULL is always returned and errno set to ENOSYS.
+ *
+ * @see tevent_thread_proxy_schedule()
+ */
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+ struct tevent_context *dest_ev_ctx);
+
+/**
+ * @brief Schedule an immediate event on an event context from another thread.
+ *
+ * Causes dest_ev_ctx, being run by another thread, to receive an
+ * immediate event calling the handler with the *pp_private parameter.
+ *
+ * *pp_im must be a pointer to an immediate event talloced on a context owned
+ * by the calling thread, or the NULL context. Ownership will
+ * be transferred to the tevent_thread_proxy and *pp_im will be returned as NULL.
+ *
+ * *pp_private_data must be a talloced area of memory with no destructors.
+ * Ownership of this memory will be transferred to the tevent library and
+ * *pp_private_data will be set to NULL on successful completion of
+ * the call. Set pp_private to NULL if no parameter transfer
+ * needed (a pure callback). This is an asynchronous request, caller
+ * does not wait for callback to be completed before returning.
+ *
+ * @param[in] tp The tevent_thread_proxy to use.
+ *
+ * @param[in] pp_im Pointer to immediate event pointer.
+ *
+ * @param[in] handler The function that will be called.
+ *
+ * @param[in] pp_private_data The talloced memory to transfer.
+ *
+ * @see tevent_thread_proxy_create()
+ */
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+ struct tevent_immediate **pp_im,
+ tevent_immediate_handler_t handler,
+ void *pp_private_data);
+
+/*
+ * @brief Create a context for threaded activation of immediates
+ *
+ * A tevent_treaded_context provides a link into an event
+ * context. Using tevent_threaded_schedule_immediate, it is possible
+ * to activate an immediate event from within a thread.
+ *
+ * It is the duty of the caller of tevent_threaded_context_create() to
+ * keep the event context around longer than any
+ * tevent_threaded_context. tevent will abort if ev is talloc_free'ed
+ * with an active tevent_threaded_context.
+ *
+ * If tevent is build without pthread support, this always returns
+ * NULL with errno=ENOSYS.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ * @param[in] ev The event context to link this to.
+ * @return The threaded context, or NULL with errno set.
+ *
+ * @see tevent_threaded_schedule_immediate()
+ *
+ * @note Available as of tevent 0.9.30
+ */
+struct tevent_threaded_context *tevent_threaded_context_create(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev);
+
+#ifdef DOXYGEN
+/*
+ * @brief Activate an immediate from a thread
+ *
+ * Activate an immediate from within a thread.
+ *
+ * This routine does not watch out for talloc hierarchies. This means
+ * that it is highly recommended to create the tevent_immediate in the
+ * thread owning tctx, allocate a threaded job description for the
+ * thread, hand over both pointers to a helper thread and not touch it
+ * in the main thread at all anymore.
+ *
+ * tevent_threaded_schedule_immediate is intended as a job completion
+ * indicator for simple threaded helpers.
+ *
+ * Please be aware that tevent_threaded_schedule_immediate is very
+ * picky about its arguments: An immediate may not already be
+ * activated and the handler must exist. With
+ * tevent_threaded_schedule_immediate memory ownership is transferred
+ * to the main thread holding the tevent context behind tctx, the
+ * helper thread can't access it anymore.
+ *
+ * @param[in] tctx The threaded context to go through
+ * @param[in] im The immediate event to activate
+ * @param[in] handler The immediate handler to call in the main thread
+ * @param[in] private_data Pointer for the immediate handler
+ *
+ * @see tevent_threaded_context_create()
+ *
+ * @note Available as of tevent 0.9.30
+ */
+void tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
+ struct tevent_immediate *im,
+ tevent_immediate_handler_t handler,
+ void *private_data);
+#else
+void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
+ struct tevent_immediate *im,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_threaded_schedule_immediate(tctx, im, handler, private_data) \
+ _tevent_threaded_schedule_immediate(tctx, im, handler, private_data, \
+ #handler, __location__);
+#endif
+
+#ifdef TEVENT_DEPRECATED
+void tevent_loop_allow_nesting(struct tevent_context *ev) _DEPRECATED_;
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+ tevent_nesting_hook hook,
+ void *private_data) _DEPRECATED_;
+int _tevent_loop_until(struct tevent_context *ev,
+ bool (*finished)(void *private_data),
+ void *private_data,
+ const char *location) _DEPRECATED_;
+#define tevent_loop_until(ev, finished, private_data) \
+ _tevent_loop_until(ev, finished, private_data, __location__)
+#endif
+
+int tevent_re_initialise(struct tevent_context *ev);
+
+/* @} */
+
+/**
+ * @defgroup tevent_ops The tevent operation functions
+ * @ingroup tevent
+ *
+ * The following structure and registration functions are exclusively
+ * needed for people writing and plugging a different event engine.
+ * There is nothing useful for normal tevent user in here.
+ * @{
+ */
+
+struct tevent_ops {
+ /* context init */
+ int (*context_init)(struct tevent_context *ev);
+
+ /* fd_event functions */
+ struct tevent_fd *(*add_fd)(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+ void (*set_fd_close_fn)(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn);
+ uint16_t (*get_fd_flags)(struct tevent_fd *fde);
+ void (*set_fd_flags)(struct tevent_fd *fde, uint16_t flags);
+
+ /* timed_event functions */
+ struct tevent_timer *(*add_timer)(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+
+ /* immediate event functions */
+ void (*schedule_immediate)(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+
+ /* signal functions */
+ struct tevent_signal *(*add_signal)(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum, int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+
+ /* loop functions */
+ int (*loop_once)(struct tevent_context *ev, const char *location);
+ int (*loop_wait)(struct tevent_context *ev, const char *location);
+};
+
+bool tevent_register_backend(const char *name, const struct tevent_ops *ops);
+const struct tevent_ops *tevent_find_ops_byname(const char *name);
+
+/* @} */
+
+#ifdef TEVENT_DEPRECATED
+/**
+ * @defgroup tevent_wrapper_ops The tevent wrapper operation functions
+ * @ingroup tevent
+ *
+ * The following structure and registration functions are exclusively
+ * needed for people writing wrapper functions for event handlers
+ * e.g. wrappers can be used for debugging/profiling or impersonation.
+ *
+ * There is nothing useful for normal tevent user in here.
+ *
+ * @note That the close_fn() on tevent_fd is *NOT* wrapped!
+ *
+ * @see tevent_context_wrapper_create
+ * @see tevent_fd_set_auto_close
+ * @{
+ */
+
+struct tevent_wrapper_ops {
+ const char *name;
+
+ bool (*before_use)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ const char *location);
+ void (*after_use)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ const char *location);
+
+ void (*before_fd_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location);
+ void (*after_fd_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location);
+
+ void (*before_timer_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location);
+ void (*after_timer_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location);
+
+ void (*before_immediate_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location);
+ void (*after_immediate_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location);
+
+ void (*before_signal_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location);
+ void (*after_signal_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location);
+};
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a wrapper tevent_context.
+ *
+ * @param[in] main_ev The main event context to work on.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ops The tevent_wrapper_ops function table.
+ *
+ * @param[out] private_state The private state use by the wrapper functions.
+ *
+ * @param[in] private_type The talloc type of the private_state.
+ *
+ * @return The wrapper event context, NULL on error.
+ *
+ * @note Available as of tevent 0.9.37
+ * @note Deprecated as of tevent 0.9.38
+ */
+struct tevent_context *tevent_context_wrapper_create(struct tevent_context *main_ev,
+ TALLOC_CTX *mem_ctx,
+ const struct tevent_wrapper_ops *ops,
+ void **private_state,
+ const char *private_type);
+#else
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+ TALLOC_CTX *mem_ctx,
+ const struct tevent_wrapper_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location) _DEPRECATED_;
+#define tevent_context_wrapper_create(main_ev, mem_ctx, ops, state, type) \
+ _tevent_context_wrapper_create(main_ev, mem_ctx, ops, \
+ state, sizeof(type), #type, __location__)
+#endif
+
+/**
+ * @brief Check if the event context is a wrapper event context.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @return Is a wrapper (true), otherwise (false).
+ *
+ * @see tevent_context_wrapper_create()
+ *
+ * @note Available as of tevent 0.9.37
+ * @note Deprecated as of tevent 0.9.38
+ */
+bool tevent_context_is_wrapper(struct tevent_context *ev) _DEPRECATED_;
+
+#ifdef DOXYGEN
+/**
+ * @brief Prepare the environment of a (wrapper) event context.
+ *
+ * A caller might call this before passing a wrapper event context
+ * to a tevent_req based *_send() function.
+ *
+ * The wrapper event context might do something like impersonation.
+ *
+ * tevent_context_push_use() must always be used in combination
+ * with tevent_context_pop_use().
+ *
+ * There is a global stack of currently active/busy wrapper event contexts.
+ * Each wrapper can only appear once on that global stack!
+ * The stack size is limited to 32 elements, which should be enough
+ * for all useful scenarios.
+ *
+ * In addition to an explicit tevent_context_push_use() also
+ * the invocation of an immediate, timer or fd handler implicitly
+ * pushes the wrapper on the stack.
+ *
+ * Therefore there are some strict constraints for the usage of
+ * tevent_context_push_use():
+ * - It must not be called from within an event handler
+ * that already acts on the wrapper.
+ * - tevent_context_pop_use() must be called before
+ * leaving the code block that called tevent_context_push_use().
+ * - The caller is responsible ensure the correct stack ordering
+ * - Any violation of these constraints results in calling
+ * the abort handler of the given tevent context.
+ *
+ * Calling tevent_context_push_use() on a raw event context
+ * still consumes an element on the stack, but it's otherwise
+ * a no-op.
+ *
+ * If tevent_context_push_use() returns false, it means
+ * that the wrapper's before_use() hook returned this failure,
+ * in that case you must not call tevent_context_pop_use() as
+ * the wrapper is not pushed onto the stack.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @return Success (true) or failure (false).
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_pop_use
+ *
+ * @note Available as of tevent 0.9.37
+ * @note Deprecated as of tevent 0.9.38
+ */
+bool tevent_context_push_use(struct tevent_context *ev);
+#else
+bool _tevent_context_push_use(struct tevent_context *ev,
+ const char *location) _DEPRECATED_;
+#define tevent_context_push_use(ev) \
+ _tevent_context_push_use(ev, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Release the environment of a (wrapper) event context.
+ *
+ * The wrapper event context might undo something like impersonation.
+ *
+ * This must be called after a successful tevent_context_push_use().
+ * Any ordering violation results in calling
+ * the abort handler of the given tevent context.
+ *
+ * This basically calls the wrapper's after_use() hook.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_push_use
+ *
+ * @note Available as of tevent 0.9.37
+ * @note Deprecated as of tevent 0.9.38
+ */
+void tevent_context_pop_use(struct tevent_context *ev);
+#else
+void _tevent_context_pop_use(struct tevent_context *ev,
+ const char *location) _DEPRECATED_;
+#define tevent_context_pop_use(ev) \
+ _tevent_context_pop_use(ev, __location__)
+#endif
+
+/**
+ * @brief Check is the two context pointers belong to the same low level loop
+ *
+ * With the introduction of wrapper contexts it's not trivial
+ * to check if two context pointers belong to the same low level
+ * event loop. Some code may need to know this in order
+ * to make some caching decisions.
+ *
+ * @param[in] ev1 The first event context.
+ * @param[in] ev2 The second event context.
+ *
+ * @return true if both contexts belong to the same (still existing) context
+ * loop, false otherwise.
+ *
+ * @see tevent_context_wrapper_create
+ *
+ * @note Available as of tevent 0.9.37
+ * @note Deprecated as of tevent 0.9.38
+ */
+bool tevent_context_same_loop(struct tevent_context *ev1,
+ struct tevent_context *ev2) _DEPRECATED_;
+
+/* @} */
+#endif /* TEVENT_DEPRECATED */
+
+/**
+ * @defgroup tevent_compat The tevent compatibility functions
+ * @ingroup tevent
+ *
+ * The following definitions are useful only for compatibility with the
+ * implementation originally developed within the samba4 code and will be
+ * soon removed. Please NEVER use in new code.
+ *
+ * @todo Ignore it?
+ *
+ * @{
+ */
+
+#ifdef TEVENT_COMPAT_DEFINES
+
+#define event_context tevent_context
+#define event_ops tevent_ops
+#define fd_event tevent_fd
+#define timed_event tevent_timer
+#define signal_event tevent_signal
+
+#define event_fd_handler_t tevent_fd_handler_t
+#define event_timed_handler_t tevent_timer_handler_t
+#define event_signal_handler_t tevent_signal_handler_t
+
+#define event_context_init(mem_ctx) \
+ tevent_context_init(mem_ctx)
+
+#define event_context_init_byname(mem_ctx, name) \
+ tevent_context_init_byname(mem_ctx, name)
+
+#define event_backend_list(mem_ctx) \
+ tevent_backend_list(mem_ctx)
+
+#define event_set_default_backend(backend) \
+ tevent_set_default_backend(backend)
+
+#define event_add_fd(ev, mem_ctx, fd, flags, handler, private_data) \
+ tevent_add_fd(ev, mem_ctx, fd, flags, handler, private_data)
+
+#define event_add_timed(ev, mem_ctx, next_event, handler, private_data) \
+ tevent_add_timer(ev, mem_ctx, next_event, handler, private_data)
+
+#define event_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data) \
+ tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data)
+
+#define event_loop_once(ev) \
+ tevent_loop_once(ev)
+
+#define event_loop_wait(ev) \
+ tevent_loop_wait(ev)
+
+#define event_get_fd_flags(fde) \
+ tevent_fd_get_flags(fde)
+
+#define event_set_fd_flags(fde, flags) \
+ tevent_fd_set_flags(fde, flags)
+
+#define EVENT_FD_READ TEVENT_FD_READ
+#define EVENT_FD_WRITE TEVENT_FD_WRITE
+
+#define EVENT_FD_WRITEABLE(fde) \
+ TEVENT_FD_WRITEABLE(fde)
+
+#define EVENT_FD_READABLE(fde) \
+ TEVENT_FD_READABLE(fde)
+
+#define EVENT_FD_NOT_WRITEABLE(fde) \
+ TEVENT_FD_NOT_WRITEABLE(fde)
+
+#define EVENT_FD_NOT_READABLE(fde) \
+ TEVENT_FD_NOT_READABLE(fde)
+
+#define ev_debug_level tevent_debug_level
+
+#define EV_DEBUG_FATAL TEVENT_DEBUG_FATAL
+#define EV_DEBUG_ERROR TEVENT_DEBUG_ERROR
+#define EV_DEBUG_WARNING TEVENT_DEBUG_WARNING
+#define EV_DEBUG_TRACE TEVENT_DEBUG_TRACE
+
+#define ev_set_debug(ev, debug, context) \
+ tevent_set_debug(ev, debug, context)
+
+#define ev_set_debug_stderr(_ev) tevent_set_debug_stderr(ev)
+
+#endif /* TEVENT_COMPAT_DEFINES */
+
+/* @} */
+
+#endif /* __TEVENT_H__ */
diff --git a/lib/tevent/tevent.pc.in b/lib/tevent/tevent.pc.in
new file mode 100644
index 0000000..eb0e564
--- /dev/null
+++ b/lib/tevent/tevent.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: tevent
+Description: An event system library
+Version: @PACKAGE_VERSION@
+Requires: talloc
+Libs: @LIB_RPATH@ -L${libdir} -ltevent
+Cflags: -I${includedir}
+URL: http://samba.org/
diff --git a/lib/tevent/tevent.py b/lib/tevent/tevent.py
new file mode 100644
index 0000000..14aa27d
--- /dev/null
+++ b/lib/tevent/tevent.py
@@ -0,0 +1,28 @@
+#
+# Python integration for tevent
+#
+# Copyright (C) Jelmer Vernooij 2011
+#
+# ** NOTE! The following LGPL license applies to the tevent
+# ** library. This does NOT imply that all of Samba is released
+# ** under the LGPL
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+from _tevent import (
+ __version__,
+ backend_list,
+ Context,
+ Signal,
+)
diff --git a/lib/tevent/tevent_debug.c b/lib/tevent/tevent_debug.c
new file mode 100644
index 0000000..c38c58a
--- /dev/null
+++ b/lib/tevent/tevent_debug.c
@@ -0,0 +1,371 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#define TEVENT_DEPRECATED
+#include "tevent.h"
+#include "tevent_internal.h"
+
+#undef tevent_thread_call_depth_reset_from_req
+
+/********************************************************************
+ * Debug wrapper functions, modeled (with lot's of code copied as is)
+ * after the ev debug wrapper functions
+ ********************************************************************/
+
+/*
+ this allows the user to choose their own debug function
+*/
+int tevent_set_debug(struct tevent_context *ev,
+ void (*debug)(void *context,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(3,0),
+ void *context)
+{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_debug() on wrapper");
+ errno = EINVAL;
+ return -1;
+ }
+ if (debug != NULL) {
+ /*
+ * tevent_set_max_debug_level(ev, TEVENT_DEBUG_TRACE)
+ * can be used to get full tracing, but we can to
+ * avoid overhead by default.
+ */
+ ev->debug_ops.max_level = TEVENT_DEBUG_WARNING;
+ } else {
+ ev->debug_ops.max_level = TEVENT_DEBUG_FATAL;
+ }
+ ev->debug_ops.debug = debug;
+ ev->debug_ops.context = context;
+ return 0;
+}
+
+enum tevent_debug_level
+tevent_set_max_debug_level(struct tevent_context *ev,
+ enum tevent_debug_level max_level)
+{
+ enum tevent_debug_level old_level;
+ old_level = ev->debug_ops.max_level;
+ ev->debug_ops.max_level = max_level;
+ return old_level;
+}
+
+/*
+ debug function for ev_set_debug_stderr
+*/
+static void tevent_debug_stderr(void *private_data,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(3,0);
+static void tevent_debug_stderr(void *private_data,
+ enum tevent_debug_level level,
+ const char *fmt, va_list ap)
+{
+ if (level <= TEVENT_DEBUG_WARNING) {
+ vfprintf(stderr, fmt, ap);
+ }
+}
+
+/*
+ convenience function to setup debug messages on stderr
+ messages of level TEVENT_DEBUG_WARNING and higher are printed
+*/
+int tevent_set_debug_stderr(struct tevent_context *ev)
+{
+ return tevent_set_debug(ev, tevent_debug_stderr, ev);
+}
+
+/*
+ * log a message
+ *
+ * The default debug action is to ignore debugging messages.
+ * This is the most appropriate action for a library.
+ * Applications using the library must decide where to
+ * redirect debugging messages
+*/
+void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ if (!ev) {
+ return;
+ }
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ }
+ if (level > ev->debug_ops.max_level) {
+ return;
+ }
+ if (ev->debug_ops.debug == NULL) {
+ return;
+ }
+ va_start(ap, fmt);
+ ev->debug_ops.debug(ev->debug_ops.context, level, fmt, ap);
+ va_end(ap);
+}
+
+void tevent_set_trace_callback(struct tevent_context *ev,
+ tevent_trace_callback_t cb,
+ void *private_data)
+{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_trace_callback() on wrapper");
+ return;
+ }
+
+ ev->tracing.point.callback = cb;
+ ev->tracing.point.private_data = private_data;
+}
+
+void tevent_get_trace_callback(struct tevent_context *ev,
+ tevent_trace_callback_t *cb,
+ void *private_data)
+{
+ *cb = ev->tracing.point.callback;
+ *(void**)private_data = ev->tracing.point.private_data;
+}
+
+void tevent_trace_point_callback(struct tevent_context *ev,
+ enum tevent_trace_point tp)
+{
+ if (ev->tracing.point.callback != NULL) {
+ ev->tracing.point.callback(tp, ev->tracing.point.private_data);
+ }
+}
+
+void tevent_set_trace_fd_callback(struct tevent_context *ev,
+ tevent_trace_fd_callback_t cb,
+ void *private_data)
+{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_trace_fd_callback() on wrapper");
+ return;
+ }
+
+ ev->tracing.fde.callback = cb;
+ ev->tracing.fde.private_data = private_data;
+}
+
+void tevent_get_trace_fd_callback(struct tevent_context *ev,
+ tevent_trace_fd_callback_t *cb,
+ void *p_private_data)
+{
+ *cb = ev->tracing.fde.callback;
+ *(void**)p_private_data = ev->tracing.fde.private_data;
+}
+
+void tevent_trace_fd_callback(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ enum tevent_event_trace_point tp)
+{
+ if (ev->tracing.fde.callback != NULL) {
+ ev->tracing.fde.callback(fde, tp, ev->tracing.fde.private_data);
+ }
+}
+
+void tevent_set_trace_signal_callback(struct tevent_context *ev,
+ tevent_trace_signal_callback_t cb,
+ void *private_data)
+{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_trace_signal_callback() "
+ "on wrapper");
+ return;
+ }
+
+ ev->tracing.se.callback = cb;
+ ev->tracing.se.private_data = private_data;
+}
+
+void tevent_get_trace_signal_callback(struct tevent_context *ev,
+ tevent_trace_signal_callback_t *cb,
+ void *p_private_data)
+{
+ *cb = ev->tracing.se.callback;
+ *(void**)p_private_data = ev->tracing.se.private_data;
+}
+
+void tevent_trace_signal_callback(struct tevent_context *ev,
+ struct tevent_signal *se,
+ enum tevent_event_trace_point tp)
+{
+ if (ev->tracing.se.callback != NULL) {
+ ev->tracing.se.callback(se, tp, ev->tracing.se.private_data);
+ }
+}
+
+void tevent_set_trace_timer_callback(struct tevent_context *ev,
+ tevent_trace_timer_callback_t cb,
+ void *private_data)
+{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_trace_timer_callback() "
+ "on wrapper");
+ return;
+ }
+
+ ev->tracing.te.callback = cb;
+ ev->tracing.te.private_data = private_data;
+}
+
+void tevent_get_trace_timer_callback(struct tevent_context *ev,
+ tevent_trace_timer_callback_t *cb,
+ void *p_private_data)
+{
+ *cb = ev->tracing.te.callback;
+ *(void**)p_private_data = ev->tracing.te.private_data;
+}
+
+void tevent_trace_timer_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ enum tevent_event_trace_point tp)
+{
+ if (ev->tracing.te.callback != NULL) {
+ ev->tracing.te.callback(te, tp, ev->tracing.te.private_data);
+ }
+}
+
+void tevent_set_trace_immediate_callback(struct tevent_context *ev,
+ tevent_trace_immediate_callback_t cb,
+ void *private_data)
+{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_trace_immediate_callback() "
+ "on wrapper");
+ return;
+ }
+
+ ev->tracing.im.callback = cb;
+ ev->tracing.im.private_data = private_data;
+}
+
+void tevent_get_trace_immediate_callback(struct tevent_context *ev,
+ tevent_trace_immediate_callback_t *cb,
+ void *p_private_data)
+{
+ *cb = ev->tracing.im.callback;
+ *(void**)p_private_data = ev->tracing.im.private_data;
+}
+
+void tevent_trace_immediate_callback(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ enum tevent_event_trace_point tp)
+{
+ if (ev->tracing.im.callback != NULL) {
+ ev->tracing.im.callback(im, tp, ev->tracing.im.private_data);
+ }
+}
+
+void tevent_set_trace_queue_callback(struct tevent_context *ev,
+ tevent_trace_queue_callback_t cb,
+ void *private_data)
+{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_trace_queue_callback() "
+ "on wrapper");
+ return;
+ }
+
+ ev->tracing.qe.callback = cb;
+ ev->tracing.qe.private_data = private_data;
+}
+
+void tevent_get_trace_queue_callback(struct tevent_context *ev,
+ tevent_trace_queue_callback_t *cb,
+ void *p_private_data)
+{
+ *cb = ev->tracing.qe.callback;
+ *(void**)p_private_data = ev->tracing.qe.private_data;
+}
+
+void tevent_trace_queue_callback(struct tevent_context *ev,
+ struct tevent_queue_entry *qe,
+ enum tevent_event_trace_point tp)
+{
+ if (ev->tracing.qe.callback != NULL) {
+ ev->tracing.qe.callback(qe, tp, ev->tracing.qe.private_data);
+ }
+}
+
+_PRIVATE_ __thread
+struct tevent_thread_call_depth_state tevent_thread_call_depth_state_g;
+
+void tevent_thread_call_depth_activate(size_t *ptr)
+{
+}
+
+void tevent_thread_call_depth_deactivate(void)
+{
+}
+
+void tevent_thread_call_depth_start(struct tevent_req *req)
+{
+}
+
+void tevent_thread_call_depth_reset_from_req(struct tevent_req *req)
+{
+ _tevent_thread_call_depth_reset_from_req(req, NULL);
+}
+
+void _tevent_thread_call_depth_reset_from_req(struct tevent_req *req,
+ const char *fname)
+{
+ if (tevent_thread_call_depth_state_g.cb != NULL) {
+ tevent_thread_call_depth_state_g.cb(
+ tevent_thread_call_depth_state_g.cb_private,
+ TEVENT_CALL_FLOW_REQ_RESET,
+ req,
+ req->internal.call_depth,
+ fname);
+ }
+}
+
+void tevent_thread_call_depth_set_callback(tevent_call_depth_callback_t f,
+ void *private_data)
+{
+ /* In case of deactivation, make sure that call depth is set to 0 */
+ if (tevent_thread_call_depth_state_g.cb != NULL) {
+ tevent_thread_call_depth_state_g.cb(
+ tevent_thread_call_depth_state_g.cb_private,
+ TEVENT_CALL_FLOW_REQ_RESET,
+ NULL,
+ 0,
+ "tevent_thread_call_depth_set_callback");
+ }
+ tevent_thread_call_depth_state_g = (struct tevent_thread_call_depth_state)
+ {
+ .cb = f,
+ .cb_private = private_data,
+ };
+}
diff --git a/lib/tevent/tevent_dlinklist.h b/lib/tevent/tevent_dlinklist.h
new file mode 100644
index 0000000..49a135a
--- /dev/null
+++ b/lib/tevent/tevent_dlinklist.h
@@ -0,0 +1,198 @@
+/*
+ Unix SMB/CIFS implementation.
+ some simple double linked list macros
+
+ Copyright (C) Andrew Tridgell 1998-2010
+
+ ** NOTE! The following LGPL license applies to this file (*dlinklist.h).
+ ** This does NOT imply that all of Samba is released under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* To use these macros you must have a structure containing a next and
+ prev pointer */
+
+#ifndef _DLINKLIST_H
+#define _DLINKLIST_H
+
+/*
+ February 2010 - changed list format to have a prev pointer from the
+ list head. This makes DLIST_ADD_END() O(1) even though we only have
+ one list pointer.
+
+ The scheme is as follows:
+
+ 1) with no entries in the list:
+ list_head == NULL
+
+ 2) with 1 entry in the list:
+ list_head->next == NULL
+ list_head->prev == list_head
+
+ 3) with 2 entries in the list:
+ list_head->next == element2
+ list_head->prev == element2
+ element2->prev == list_head
+ element2->next == NULL
+
+ 4) with N entries in the list:
+ list_head->next == element2
+ list_head->prev == elementN
+ elementN->prev == element{N-1}
+ elementN->next == NULL
+
+ This allows us to find the tail of the list by using
+ list_head->prev, which means we can add to the end of the list in
+ O(1) time
+ */
+
+
+/*
+ add an element at the front of a list
+*/
+#define DLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (p)->prev = (list) = (p); \
+ (p)->next = NULL; \
+ } else { \
+ (p)->prev = (list)->prev; \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (list) = (p); \
+ } \
+} while (0)
+
+/*
+ remove an element from a list
+ Note that the element doesn't have to be in the list. If it
+ isn't then this is a no-op
+*/
+#define DLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ (list) = (p)->next; \
+ } else if ((p)->prev && (list) && (p) == (list)->prev) { \
+ (p)->prev->next = NULL; \
+ (list)->prev = (p)->prev; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) != (list)) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+/*
+ find the head of the list given any element in it.
+ Note that this costs O(N), so you should avoid this macro
+ if at all possible!
+*/
+#define DLIST_HEAD(p, result_head) \
+do { \
+ (result_head) = (p); \
+ while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
+} while(0)
+
+/* return the last element in the list */
+#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
+
+/* return the previous element in the list. */
+#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+ this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+ if (!(list) || !(el)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ (p)->prev = (el); \
+ (p)->next = (el)->next; \
+ (el)->next = (p); \
+ if ((p)->next) (p)->next->prev = (p); \
+ if ((list)->prev == (el)) (list)->prev = (p); \
+ }\
+} while (0)
+
+
+/*
+ add to the end of a list.
+*/
+#define DLIST_ADD_END(list, p) \
+do { \
+ if (!(list)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ DLIST_ADD_AFTER(list, p, (list)->prev); \
+ } \
+} while (0)
+
+/* promote an element to the front of a list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD(list, p); \
+} while (0)
+
+/*
+ demote an element to the end of a list.
+*/
+#define DLIST_DEMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD_END(list, p); \
+} while (0)
+
+/*
+ * like DLIST_DEMOTE(), but optimized
+ * for short lists with 0, 1 or 2 elements
+ */
+#define DLIST_DEMOTE_SHORT(list, p) \
+do { \
+ if ((list) == NULL) { \
+ /* no reason to demote, just add */ \
+ DLIST_ADD(list, p); \
+ } else if ((list)->prev == (p)) { \
+ /* optimize if p is last */ \
+ } else if ((list) == (p)) { \
+ /* optimize if p is first */ \
+ (list)->prev->next = (p); \
+ (list) = (p)->next; \
+ (p)->next = NULL; \
+ } else { \
+ DLIST_DEMOTE(list, p); \
+ } \
+} while (0)
+
+/*
+ concatenate two lists - putting all elements of the 2nd list at the
+ end of the first list.
+*/
+#define DLIST_CONCATENATE(list1, list2) \
+do { \
+ if (!(list1)) { \
+ (list1) = (list2); \
+ } else { \
+ (list1)->prev->next = (list2); \
+ if (list2) { \
+ void *_tmplist = (void *)(list1)->prev; \
+ (list1)->prev = (list2)->prev; \
+ (list2)->prev = _tmplist; \
+ } \
+ } \
+} while (0)
+
+#endif /* _DLINKLIST_H */
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
new file mode 100644
index 0000000..e56bd02
--- /dev/null
+++ b/lib/tevent/tevent_epoll.c
@@ -0,0 +1,945 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ main select loop and event handling - epoll implementation
+
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Stefan Metzmacher 2005-2013
+ Copyright (C) Jeremy Allison 2013
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct epoll_event_context {
+ /* a pointer back to the generic event_context */
+ struct tevent_context *ev;
+
+ /* when using epoll this is the handle from epoll_create1(2) */
+ int epoll_fd;
+
+ pid_t pid;
+
+ bool panic_force_replay;
+ bool *panic_state;
+ bool (*panic_fallback)(struct tevent_context *ev, bool replay);
+};
+
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<1)
+
+#ifdef TEST_PANIC_FALLBACK
+
+static int epoll_create1_panic_fallback(struct epoll_event_context *epoll_ev,
+ int flags)
+{
+ if (epoll_ev->panic_fallback == NULL) {
+ return epoll_create1(flags);
+ }
+
+ /* 50% of the time, fail... */
+ if ((random() % 2) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return epoll_create1(flags);
+}
+
+static int epoll_ctl_panic_fallback(struct epoll_event_context *epoll_ev,
+ int epfd, int op, int fd,
+ struct epoll_event *event)
+{
+ if (epoll_ev->panic_fallback == NULL) {
+ return epoll_ctl(epfd, op, fd, event);
+ }
+
+ /* 50% of the time, fail... */
+ if ((random() % 2) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return epoll_ctl(epfd, op, fd, event);
+}
+
+static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev,
+ int epfd,
+ struct epoll_event *events,
+ int maxevents,
+ int timeout)
+{
+ if (epoll_ev->panic_fallback == NULL) {
+ return epoll_wait(epfd, events, maxevents, timeout);
+ }
+
+ /* 50% of the time, fail... */
+ if ((random() % 2) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return epoll_wait(epfd, events, maxevents, timeout);
+}
+
+#define epoll_create1(_flags) \
+ epoll_create1_panic_fallback(epoll_ev, _flags)
+#define epoll_ctl(_epfd, _op, _fd, _event) \
+ epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event)
+#define epoll_wait(_epfd, _events, _maxevents, _timeout) \
+ epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout)
+#endif
+
+/*
+ called to set the panic fallback function.
+*/
+_PRIVATE_ void tevent_epoll_set_panic_fallback(struct tevent_context *ev,
+ bool (*panic_fallback)(struct tevent_context *ev,
+ bool replay))
+{
+ struct epoll_event_context *epoll_ev =
+ talloc_get_type_abort(ev->additional_data,
+ struct epoll_event_context);
+
+ epoll_ev->panic_fallback = panic_fallback;
+}
+
+/*
+ called when a epoll call fails
+*/
+static void epoll_panic(struct epoll_event_context *epoll_ev,
+ const char *reason, bool replay)
+{
+ struct tevent_context *ev = epoll_ev->ev;
+ bool (*panic_fallback)(struct tevent_context *ev, bool replay);
+
+ panic_fallback = epoll_ev->panic_fallback;
+
+ if (epoll_ev->panic_state != NULL) {
+ *epoll_ev->panic_state = true;
+ }
+
+ if (epoll_ev->panic_force_replay) {
+ replay = true;
+ }
+
+ TALLOC_FREE(ev->additional_data);
+
+ if (panic_fallback == NULL) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "%s (%s) replay[%u] - calling abort()\n",
+ reason, strerror(errno), (unsigned)replay);
+ abort();
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_ERROR,
+ "%s (%s) replay[%u] - calling panic_fallback\n",
+ reason, strerror(errno), (unsigned)replay);
+
+ if (!panic_fallback(ev, replay)) {
+ /* Fallback failed. */
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "%s (%s) replay[%u] - calling abort()\n",
+ reason, strerror(errno), (unsigned)replay);
+ abort();
+ }
+}
+
+/*
+ map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
+*/
+static uint32_t epoll_map_flags(uint16_t flags)
+{
+ uint32_t ret = 0;
+
+ /*
+ * we do not need to specify EPOLLERR | EPOLLHUP
+ * they are always reported.
+ */
+
+ if (flags & TEVENT_FD_READ) {
+ /*
+ * Note that EPOLLRDHUP always
+ * returns EPOLLIN in addition,
+ * so EPOLLRDHUP is not strictly needed,
+ * but we want to make it explicit.
+ */
+ ret |= EPOLLIN | EPOLLRDHUP;
+ }
+ if (flags & TEVENT_FD_WRITE) {
+ ret |= EPOLLOUT;
+ }
+ if (flags & TEVENT_FD_ERROR) {
+ ret |= EPOLLRDHUP;
+ }
+ return ret;
+}
+
+/*
+ free the epoll fd
+*/
+static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
+{
+ close(epoll_ev->epoll_fd);
+ epoll_ev->epoll_fd = -1;
+ return 0;
+}
+
+/*
+ init the epoll fd
+*/
+static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
+{
+ epoll_ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (epoll_ev->epoll_fd == -1) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "Failed to create epoll handle (%s).\n",
+ strerror(errno));
+ return -1;
+ }
+
+ epoll_ev->pid = tevent_cached_getpid();
+ talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
+
+ return 0;
+}
+
+static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
+
+/*
+ reopen the epoll handle when our pid changes
+ see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
+ demonstration of why this is needed
+ */
+static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
+{
+ struct tevent_fd *fde;
+ bool *caller_panic_state = epoll_ev->panic_state;
+ bool panic_triggered = false;
+ pid_t pid = tevent_cached_getpid();
+
+ if (epoll_ev->pid == pid) {
+ return;
+ }
+
+ close(epoll_ev->epoll_fd);
+ epoll_ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (epoll_ev->epoll_fd == -1) {
+ epoll_panic(epoll_ev, "epoll_create() failed", false);
+ return;
+ }
+
+ epoll_ev->pid = pid;
+ epoll_ev->panic_state = &panic_triggered;
+ for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
+ /*
+ * We leave the mpx mappings alive
+ * so that we'll just re-add events for
+ * the existing primary events in the loop
+ * below.
+ */
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ }
+ for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
+ epoll_update_event(epoll_ev, fde);
+
+ if (panic_triggered) {
+ if (caller_panic_state != NULL) {
+ *caller_panic_state = true;
+ }
+ return;
+ }
+ }
+ epoll_ev->panic_state = NULL;
+}
+
+/*
+ epoll cannot add the same file descriptor twice, once
+ with read, once with write which is allowed by the
+ tevent poll backend. Multiplex the existing fde, flag it
+ as such so we can search for the correct fde on
+ event triggering.
+*/
+
+static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *add_fde)
+{
+ struct tevent_fd *primary = NULL;
+ uint16_t effective_flags;
+ struct epoll_event event;
+ uint64_t clear_flags = 0;
+ uint64_t add_flags = 0;
+ int ret;
+
+ /*
+ * Check if there is another fde we can attach to
+ */
+ primary = tevent_common_fd_mpx_add(add_fde);
+ if (primary == NULL) {
+ /* the caller calls epoll_panic() */
+ return -1;
+ }
+
+ /*
+ * First propagate the HAS_EVENT flag from
+ * the primary to all others (mainly add_fde)
+ */
+ if (primary->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
+ add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
+ }
+
+ /*
+ * Update the mpx internals and check if
+ * there is an update needed.
+ */
+ primary = tevent_common_fd_mpx_update(primary);
+ if (primary == NULL) {
+ /*
+ * It seems the primary was already
+ * watching (at least) the same flags
+ * as add_fde, so we are done.
+ */
+ return 0;
+ }
+
+ /*
+ * Before me modify the low level epoll state,
+ * we clear HAS_EVENT on all fdes.
+ */
+ clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
+
+ effective_flags = tevent_common_fd_mpx_flags(primary);
+
+ /*
+ * Modify the low level epoll state to reflect
+ * the effective flags we want to monitor.
+ */
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(effective_flags);
+ event.data.ptr = primary;
+ ret = epoll_ctl(epoll_ev->epoll_fd,
+ EPOLL_CTL_MOD,
+ primary->fd,
+ &event);
+ if (ret != 0 && errno == EBADF) {
+ struct tevent_common_fd_buf pbuf = {};
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_ERROR,
+ "EPOLL_CTL_MOD EBADF for "
+ "%s - disabling\n",
+ tevent_common_fd_str(&pbuf, "primary", primary));
+ tevent_common_fd_mpx_disarm_all(primary);
+ return 0;
+ } else if (ret != 0) {
+ struct tevent_common_fd_buf pbuf = {};
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "EPOLL_CTL_MOD for %s - failed - %s",
+ tevent_common_fd_str(&pbuf, "primary", primary),
+ strerror(errno));
+ /* the caller calls epoll_panic() */
+ return ret;
+ }
+
+ /*
+ * Finally re-add HAS_EVENT to all fdes
+ */
+ add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
+
+ return 0;
+}
+
+/*
+ add the epoll event to the given fd_event
+*/
+static void epoll_add_event(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *_primary)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
+ uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
+ struct epoll_event event;
+ uint64_t clear_flags = 0;
+ uint64_t add_flags = 0;
+ int ret;
+
+ /*
+ * Before me modify the low level epoll state,
+ * we clear HAS_EVENT on all fdes.
+ */
+ clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
+
+ /*
+ * Modify the low level epoll state to reflect
+ * the effective flags we want to monitor.
+ *
+ * Most likely we won't trigger the EEXIST
+ * case, so it's much cheaper to try and
+ * react on EEXIST if needed, than to always
+ * scan the list of all existing events.
+ */
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(effective_flags);
+ event.data.ptr = primary;
+ ret = epoll_ctl(epoll_ev->epoll_fd,
+ EPOLL_CTL_ADD,
+ primary->fd,
+ &event);
+ if (ret != 0 && errno == EBADF) {
+ struct tevent_common_fd_buf pbuf = {};
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_ERROR,
+ "EPOLL_CTL_ADD EBADF for "
+ "%s - disabling\n",
+ tevent_common_fd_str(&pbuf, "primary", primary));
+ tevent_common_fd_mpx_disarm_all(primary);
+ return;
+ } else if (ret != 0 && errno == EEXIST) {
+ ret = epoll_add_multiplex_fd(epoll_ev, primary);
+ if (ret != 0) {
+ epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed",
+ false);
+ return;
+ }
+ /*
+ * epoll_add_multiplex_fd() already
+ * added EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT
+ */
+ return;
+ } else if (ret != 0) {
+ epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
+ return;
+ }
+
+ /*
+ * Finally re-add HAS_EVENT to all fdes
+ */
+ add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
+}
+
+/*
+ delete the epoll event for given fd_event
+*/
+static void epoll_del_event(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *_primary)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
+ struct epoll_event event;
+ uint64_t clear_flags = 0;
+ int ret;
+
+ /*
+ * Before me delete the low level epoll state,
+ * we clear HAS_EVENT on all fdes.
+ */
+ clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
+
+ /*
+ * Delete the low level epoll state to reflect
+ * the effective flags we want to monitor.
+ */
+ ZERO_STRUCT(event);
+ ret = epoll_ctl(epoll_ev->epoll_fd,
+ EPOLL_CTL_DEL,
+ primary->fd,
+ &event);
+ if (ret != 0 && errno == ENOENT) {
+ struct tevent_common_fd_buf pbuf = {};
+ /*
+ * This can happen after a epoll_check_reopen
+ * within epoll_event_fd_destructor.
+ */
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_TRACE,
+ "EPOLL_CTL_DEL ignoring ENOENT for %s\n",
+ tevent_common_fd_str(&pbuf, "primary", primary));
+ return;
+ } else if (ret != 0 && errno == EBADF) {
+ struct tevent_common_fd_buf pbuf = {};
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_WARNING,
+ "EPOLL_CTL_DEL EBADF for %s - disabling\n",
+ tevent_common_fd_str(&pbuf, "primary", primary));
+ tevent_common_fd_mpx_disarm_all(primary);
+ return;
+ } else if (ret != 0) {
+ struct tevent_common_fd_buf pbuf = {};
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "EPOLL_CTL_DEL for %s - failed - %s",
+ tevent_common_fd_str(&pbuf, "primary", primary),
+ strerror(errno));
+ epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false);
+ return;
+ }
+}
+
+/*
+ change the epoll event to the given fd_event
+*/
+static void epoll_mod_event(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *_primary)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(_primary);
+ uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
+ struct epoll_event event;
+ uint64_t clear_flags = 0;
+ uint64_t add_flags = 0;
+ int ret;
+
+ /*
+ * Before me modify the low level epoll state,
+ * we clear HAS_EVENT on all fdes.
+ */
+ clear_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, clear_flags, 0);
+
+ /*
+ * Modify the low level epoll state to reflect
+ * the effective flags we want to monitor.
+ */
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(effective_flags);
+ event.data.ptr = primary;
+ ret = epoll_ctl(epoll_ev->epoll_fd,
+ EPOLL_CTL_MOD,
+ primary->fd,
+ &event);
+ if (ret != 0 && errno == EBADF) {
+ struct tevent_common_fd_buf pbuf = {};
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_ERROR,
+ "EPOLL_CTL_MOD EBADF for %s - disabling\n",
+ tevent_common_fd_str(&pbuf, "primary", primary));
+ tevent_common_fd_mpx_disarm_all(primary);
+ return;
+ } else if (ret != 0) {
+ struct tevent_common_fd_buf pbuf = {};
+ TEVENT_DEBUG(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "EPOLL_CTL_MOD for %s - failed - %s",
+ tevent_common_fd_str(&pbuf, "primary", primary),
+ strerror(errno));
+ epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
+ return;
+ }
+
+ /*
+ * Finally re-add HAS_EVENT to all fdes
+ */
+ add_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ tevent_common_fd_mpx_additional_flags(primary, 0, add_flags);
+}
+
+static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(fde);
+ uint64_t _paf = primary->additional_flags;
+ bool got_error = (_paf & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+ uint16_t effective_flags = tevent_common_fd_mpx_flags(primary);
+ bool want_read = (effective_flags & TEVENT_FD_READ);
+ bool want_write= (effective_flags & TEVENT_FD_WRITE);
+ bool want_error= (effective_flags & TEVENT_FD_ERROR);
+
+ /* there's already an event */
+ if (primary->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
+ if (want_read || want_error || (want_write && !got_error)) {
+ epoll_mod_event(epoll_ev, primary);
+ return;
+ }
+ /*
+ * if we want to match the select behavior, we need to remove the epoll_event
+ * when the caller isn't interested in events.
+ *
+ * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
+ */
+ epoll_del_event(epoll_ev, primary);
+ return;
+ }
+
+ /* there's no epoll_event attached to the fde */
+ if (want_read || want_error || (want_write && !got_error)) {
+ epoll_add_event(epoll_ev, primary);
+ return;
+ }
+}
+
+/*
+ event loop handling using epoll
+*/
+static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
+{
+ int ret, i;
+#define MAXEVENTS 1
+ struct epoll_event events[MAXEVENTS];
+ int timeout = -1;
+ int wait_errno;
+
+ if (tvalp) {
+ /* it's better to trigger timed events a bit later than too early */
+ timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
+ }
+
+ if (epoll_ev->ev->signal_events &&
+ tevent_common_check_signal(epoll_ev->ev)) {
+ return 0;
+ }
+
+ tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
+ ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
+ wait_errno = errno;
+ tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
+
+ if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
+ if (tevent_common_check_signal(epoll_ev->ev)) {
+ return 0;
+ }
+ }
+
+ if (ret == -1 && wait_errno != EINTR) {
+ epoll_panic(epoll_ev, "epoll_wait() failed", true);
+ return -1;
+ }
+
+ if (ret == 0 && tvalp) {
+ /* we don't care about a possible delay here */
+ tevent_common_loop_timer_delay(epoll_ev->ev);
+ return 0;
+ }
+
+ for (i=0;i<ret;i++) {
+ struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
+ struct tevent_fd);
+ struct tevent_fd *selected = NULL;
+ uint16_t effective_flags;
+ uint16_t flags = 0;
+ bool got_error = false;
+
+ if (fde == NULL) {
+ epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
+ return -1;
+ }
+ effective_flags = tevent_common_fd_mpx_flags(fde);
+ if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP)) {
+ uint64_t add_flags = 0;
+
+ add_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+ tevent_common_fd_mpx_additional_flags(fde,
+ 0,
+ add_flags);
+
+ if (effective_flags & TEVENT_FD_ERROR) {
+ flags |= TEVENT_FD_ERROR;
+ }
+ if (effective_flags & TEVENT_FD_READ) {
+ flags |= TEVENT_FD_READ;
+ }
+ }
+ if (events[i].events & EPOLLIN) {
+ if (effective_flags & TEVENT_FD_READ) {
+ flags |= TEVENT_FD_READ;
+ }
+ }
+ if (events[i].events & EPOLLOUT) {
+ if (effective_flags & TEVENT_FD_WRITE) {
+ flags |= TEVENT_FD_WRITE;
+ }
+ }
+
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR)
+ {
+ got_error = true;
+ }
+
+ selected = tevent_common_fd_mpx_select(fde, flags, got_error);
+ if (selected == NULL) {
+ if (got_error) {
+ /*
+ * if we only wait for TEVENT_FD_WRITE, we
+ * should not tell the event handler about it,
+ * and remove the epoll_event, as we only
+ * report errors when waiting for read events,
+ * to match the select() behavior
+ *
+ * Do the same as the poll backend and
+ * remove the writeable flag.
+ */
+ tevent_common_fd_mpx_clear_writeable(fde);
+ epoll_update_event(epoll_ev, fde);
+ }
+ continue;
+ }
+
+ /*
+ * make sure we only pass the flags
+ * the handler is expecting.
+ */
+ flags &= selected->flags;
+ return tevent_common_invoke_fd_handler(selected,
+ flags,
+ NULL);
+ }
+
+ return 0;
+}
+
+/*
+ create a epoll_event_context structure.
+*/
+static int epoll_event_context_init(struct tevent_context *ev)
+{
+ int ret;
+ struct epoll_event_context *epoll_ev;
+
+ /*
+ * We might be called during tevent_re_initialise()
+ * which means we need to free our old additional_data.
+ */
+ TALLOC_FREE(ev->additional_data);
+
+ epoll_ev = talloc_zero(ev, struct epoll_event_context);
+ if (!epoll_ev) return -1;
+ epoll_ev->ev = ev;
+ epoll_ev->epoll_fd = -1;
+
+ ret = epoll_init_ctx(epoll_ev);
+ if (ret != 0) {
+ talloc_free(epoll_ev);
+ return ret;
+ }
+
+ ev->additional_data = epoll_ev;
+ return 0;
+}
+
+/*
+ destroy an fd_event
+*/
+static int epoll_event_fd_destructor(struct tevent_fd *fde)
+{
+ struct tevent_fd *old_primary = NULL;
+ struct tevent_fd *new_primary = NULL;
+ struct tevent_fd *update_primary = NULL;
+ struct tevent_context *ev = fde->event_ctx;
+ struct epoll_event_context *epoll_ev = NULL;
+ bool panic_triggered = false;
+
+ if (ev == NULL) {
+ tevent_common_fd_mpx_reinit(fde);
+ return tevent_common_fd_destructor(fde);
+ }
+
+ epoll_ev = talloc_get_type_abort(ev->additional_data,
+ struct epoll_event_context);
+
+ /*
+ * we must remove the event from the list
+ * otherwise a panic fallback handler may
+ * reuse invalid memory
+ */
+ DLIST_REMOVE(ev->fd_events, fde);
+
+ epoll_ev->panic_state = &panic_triggered;
+ if (epoll_ev->pid != tevent_cached_getpid()) {
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ tevent_common_fd_mpx_reinit(fde);
+ return tevent_common_fd_destructor(fde);
+ }
+ }
+
+ old_primary = tevent_common_fd_mpx_primary(fde);
+
+ if (old_primary == fde) {
+ epoll_del_event(epoll_ev, fde);
+ if (panic_triggered) {
+ tevent_common_fd_mpx_reinit(fde);
+ return tevent_common_fd_destructor(fde);
+ }
+ }
+
+ new_primary = tevent_common_fd_mpx_remove(fde);
+ if (new_primary == NULL) {
+ epoll_ev->panic_state = NULL;
+ return tevent_common_fd_destructor(fde);
+ }
+ update_primary = tevent_common_fd_mpx_update(new_primary);
+ if (update_primary == NULL) {
+ epoll_ev->panic_state = NULL;
+ return tevent_common_fd_destructor(fde);
+ }
+
+ epoll_update_event(epoll_ev, update_primary);
+ if (panic_triggered) {
+ return tevent_common_fd_destructor(fde);
+ }
+ epoll_ev->panic_state = NULL;
+
+ return tevent_common_fd_destructor(fde);
+}
+
+/*
+ add a fd based event
+ return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct epoll_event_context *epoll_ev =
+ talloc_get_type_abort(ev->additional_data,
+ struct epoll_event_context);
+ struct tevent_fd *fde;
+ bool panic_triggered = false;
+ pid_t old_pid = epoll_ev->pid;
+
+ fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
+ handler, private_data,
+ handler_name, location);
+ if (!fde) return NULL;
+
+ talloc_set_destructor(fde, epoll_event_fd_destructor);
+
+ /*
+ * prepare for tevent_common_fd_mpx_flags()
+ * in epoll_update_event()
+ */
+ tevent_common_fd_mpx_update_flags(fde);
+
+ if (epoll_ev->pid != tevent_cached_getpid()) {
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return fde;
+ }
+ epoll_ev->panic_state = NULL;
+ }
+
+ if (epoll_ev->pid == old_pid) {
+ epoll_update_event(epoll_ev, fde);
+ }
+
+ return fde;
+}
+
+/*
+ set the fd event flags
+*/
+static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ struct tevent_context *ev;
+ struct epoll_event_context *epoll_ev;
+ bool panic_triggered = false;
+ pid_t old_pid;
+
+ if (fde->flags == flags) return;
+
+ ev = fde->event_ctx;
+ epoll_ev = talloc_get_type_abort(ev->additional_data,
+ struct epoll_event_context);
+ old_pid = epoll_ev->pid;
+
+ fde->flags = flags;
+ /*
+ * prepare for tevent_common_fd_mpx_flags()
+ * in epoll_update_event()
+ */
+ tevent_common_fd_mpx_update_flags(fde);
+
+ if (epoll_ev->pid != tevent_cached_getpid()) {
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return;
+ }
+ epoll_ev->panic_state = NULL;
+ }
+
+ if (epoll_ev->pid == old_pid) {
+ epoll_update_event(epoll_ev, fde);
+ }
+}
+
+/*
+ do a single event loop using the events defined in ev
+*/
+static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
+{
+ struct epoll_event_context *epoll_ev =
+ talloc_get_type_abort(ev->additional_data,
+ struct epoll_event_context);
+ struct timeval tval;
+ bool panic_triggered = false;
+
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (ev->threaded_contexts != NULL) {
+ tevent_common_threaded_activate_immediate(ev);
+ }
+
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
+
+ tval = tevent_common_loop_timer_delay(ev);
+ if (tevent_timeval_is_zero(&tval)) {
+ return 0;
+ }
+
+ if (epoll_ev->pid != tevent_cached_getpid()) {
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_ev->panic_force_replay = true;
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ errno = EINVAL;
+ return -1;
+ }
+ epoll_ev->panic_force_replay = false;
+ epoll_ev->panic_state = NULL;
+ }
+
+ return epoll_event_loop(epoll_ev, &tval);
+}
+
+static const struct tevent_ops epoll_event_ops = {
+ .context_init = epoll_event_context_init,
+ .add_fd = epoll_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = epoll_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer_v2,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = epoll_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
+};
+
+_PRIVATE_ bool tevent_epoll_init(void)
+{
+ return tevent_register_backend("epoll", &epoll_event_ops);
+}
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
new file mode 100644
index 0000000..a414f23
--- /dev/null
+++ b/lib/tevent/tevent_fd.c
@@ -0,0 +1,215 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for fd events
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+_PRIVATE_
+const char *tevent_common_fd_str(struct tevent_common_fd_buf *buf,
+ const char *description,
+ const struct tevent_fd *fde)
+{
+ snprintf(buf->buf, sizeof(buf->buf),
+ "%s[fde=%p,"
+ "fd=%d,flags=0x%x(%s%s%s),%s]",
+ description, fde, fde->fd,
+ fde->flags,
+ (fde->flags & TEVENT_FD_ERROR) ? "E" : "",
+ (fde->flags & TEVENT_FD_READ) ? "R" : "",
+ (fde->flags & TEVENT_FD_WRITE) ? "W" : "",
+ fde->handler_name);
+ return buf->buf;
+}
+
+int tevent_common_fd_destructor(struct tevent_fd *fde)
+{
+ struct tevent_fd *primary = NULL;
+
+ if (fde->destroyed) {
+ tevent_common_check_double_free(fde, "tevent_fd double free");
+ goto done;
+ }
+ fde->destroyed = true;
+
+ /*
+ * The caller should have cleared it from any mpx relationship
+ */
+ primary = tevent_common_fd_mpx_primary(fde);
+ if (primary != fde) {
+ tevent_abort(fde->event_ctx,
+ "tevent_common_fd_destructor: fde not mpx primary");
+ } else if (fde->mpx.list != NULL) {
+ tevent_abort(fde->event_ctx,
+ "tevent_common_fd_destructor: fde has mpx fdes");
+ }
+
+ if (fde->event_ctx) {
+ tevent_trace_fd_callback(fde->event_ctx, fde, TEVENT_EVENT_TRACE_DETACH);
+ DLIST_REMOVE(fde->event_ctx->fd_events, fde);
+ }
+
+ if (fde->close_fn) {
+ fde->close_fn(fde->event_ctx, fde, fde->fd, fde->private_data);
+ fde->fd = -1;
+ fde->close_fn = NULL;
+ }
+
+ fde->event_ctx = NULL;
+done:
+ if (fde->busy) {
+ return -1;
+ }
+ fde->wrapper = NULL;
+
+ return 0;
+}
+
+struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_fd *fde;
+
+ /* tevent will crash later on select() if we save
+ * a negative file descriptor. Better to fail here
+ * so that consumers will be able to debug it
+ */
+ if (fd < 0) return NULL;
+
+ fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
+ if (!fde) return NULL;
+
+ *fde = (struct tevent_fd) {
+ .event_ctx = ev,
+ .fd = fd,
+ .flags = flags,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .location = location,
+ };
+
+ tevent_trace_fd_callback(fde->event_ctx, fde, TEVENT_EVENT_TRACE_ATTACH);
+ DLIST_ADD(ev->fd_events, fde);
+ tevent_common_fd_mpx_reinit(fde);
+
+ talloc_set_destructor(fde, tevent_common_fd_destructor);
+
+
+ return fde;
+}
+uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde)
+{
+ return fde->flags;
+}
+
+void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ if (fde->flags == flags) return;
+ fde->flags = flags;
+}
+
+void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn)
+{
+ fde->close_fn = close_fn;
+}
+
+int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
+ bool *removed)
+{
+ struct tevent_context *handler_ev = fde->event_ctx;
+
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ if (fde->event_ctx == NULL) {
+ return 0;
+ }
+
+ fde->busy = true;
+ if (fde->wrapper != NULL) {
+ handler_ev = fde->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, fde->wrapper);
+ fde->wrapper->ops->before_fd_handler(
+ fde->wrapper->wrap_ev,
+ fde->wrapper->private_state,
+ fde->wrapper->main_ev,
+ fde,
+ flags,
+ fde->handler_name,
+ fde->location);
+ }
+ tevent_trace_fd_callback(fde->event_ctx, fde, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
+ fde->handler(handler_ev, fde, flags, fde->private_data);
+ if (fde->wrapper != NULL) {
+ fde->wrapper->ops->after_fd_handler(
+ fde->wrapper->wrap_ev,
+ fde->wrapper->private_state,
+ fde->wrapper->main_ev,
+ fde,
+ flags,
+ fde->handler_name,
+ fde->location);
+ tevent_wrapper_pop_use_internal(handler_ev, fde->wrapper);
+ }
+ fde->busy = false;
+
+ if (fde->destroyed) {
+ talloc_set_destructor(fde, NULL);
+ TALLOC_FREE(fde);
+ if (removed != NULL) {
+ *removed = true;
+ }
+ }
+
+ return 0;
+}
+
+void tevent_fd_set_tag(struct tevent_fd *fde, uint64_t tag)
+{
+ if (fde == NULL) {
+ return;
+ }
+
+ fde->tag = tag;
+}
+
+uint64_t tevent_fd_get_tag(const struct tevent_fd *fde)
+{
+ if (fde == NULL) {
+ return 0;
+ }
+
+ return fde->tag;
+}
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
new file mode 100644
index 0000000..82f92f1
--- /dev/null
+++ b/lib/tevent/tevent_immediate.c
@@ -0,0 +1,261 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for immediate events
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static void tevent_common_immediate_cancel(struct tevent_immediate *im)
+{
+ const char *create_location = im->create_location;
+ bool busy = im->busy;
+ uint64_t tag = im->tag;
+ struct tevent_context *detach_ev_ctx = NULL;
+
+ if (im->destroyed) {
+ tevent_abort(im->event_ctx, "tevent_immediate use after free");
+ return;
+ }
+
+ if (im->detach_ev_ctx != NULL) {
+ detach_ev_ctx = im->detach_ev_ctx;
+ im->detach_ev_ctx = NULL;
+ tevent_trace_immediate_callback(detach_ev_ctx,
+ im,
+ TEVENT_EVENT_TRACE_DETACH);
+ return;
+ }
+
+ if (!im->event_ctx) {
+ return;
+ }
+
+ if (im->handler_name != NULL) {
+ TEVENT_DEBUG(im->event_ctx, TEVENT_DEBUG_TRACE,
+ "Cancel immediate event %p \"%s\"\n",
+ im, im->handler_name);
+ }
+
+ /* let the backend free im->additional_data */
+ if (im->cancel_fn) {
+ im->cancel_fn(im);
+ }
+
+ if (busy && im->handler_name == NULL) {
+ detach_ev_ctx = im->event_ctx;
+ } else {
+ tevent_trace_immediate_callback(im->event_ctx,
+ im,
+ TEVENT_EVENT_TRACE_DETACH);
+ }
+ DLIST_REMOVE(im->event_ctx->immediate_events, im);
+
+ *im = (struct tevent_immediate) {
+ .create_location = create_location,
+ .busy = busy,
+ .tag = tag,
+ .detach_ev_ctx = detach_ev_ctx,
+ };
+
+ if (!busy) {
+ talloc_set_destructor(im, NULL);
+ }
+}
+
+/*
+ destroy an immediate event
+*/
+static int tevent_common_immediate_destructor(struct tevent_immediate *im)
+{
+ if (im->destroyed) {
+ tevent_common_check_double_free(im,
+ "tevent_immediate double free");
+ goto done;
+ }
+
+ tevent_common_immediate_cancel(im);
+
+ im->destroyed = true;
+
+done:
+ if (im->busy) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * schedule an immediate event on
+ */
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ const char *create_location = im->create_location;
+ bool busy = im->busy;
+ uint64_t tag = im->tag;
+ struct tevent_wrapper_glue *glue = im->wrapper;
+
+ tevent_common_immediate_cancel(im);
+
+ if (!handler) {
+ return;
+ }
+
+ *im = (struct tevent_immediate) {
+ .event_ctx = ev,
+ .wrapper = glue,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .create_location = create_location,
+ .schedule_location = location,
+ .busy = busy,
+ .tag = tag,
+ };
+
+ tevent_trace_immediate_callback(im->event_ctx, im, TEVENT_EVENT_TRACE_ATTACH);
+ DLIST_ADD_END(ev->immediate_events, im);
+ talloc_set_destructor(im, tevent_common_immediate_destructor);
+
+ TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
+ "Schedule immediate event \"%s\": %p\n",
+ handler_name, im);
+}
+
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+ bool *removed)
+{
+ struct tevent_context *handler_ev = im->event_ctx;
+ struct tevent_context *ev = im->event_ctx;
+ struct tevent_immediate cur = *im;
+
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
+ "Run immediate event \"%s\": %p\n",
+ im->handler_name, im);
+
+ /*
+ * remember the handler and then clear the event
+ * the handler might reschedule the event
+ */
+
+ im->busy = true;
+ im->handler_name = NULL;
+ tevent_common_immediate_cancel(im);
+ if (cur.wrapper != NULL) {
+ handler_ev = cur.wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, cur.wrapper);
+ cur.wrapper->ops->before_immediate_handler(
+ cur.wrapper->wrap_ev,
+ cur.wrapper->private_state,
+ cur.wrapper->main_ev,
+ im,
+ cur.handler_name,
+ cur.schedule_location);
+ }
+ tevent_trace_immediate_callback(cur.event_ctx, im, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
+ cur.handler(handler_ev, im, cur.private_data);
+ if (cur.wrapper != NULL) {
+ cur.wrapper->ops->after_immediate_handler(
+ cur.wrapper->wrap_ev,
+ cur.wrapper->private_state,
+ cur.wrapper->main_ev,
+ im,
+ cur.handler_name,
+ cur.schedule_location);
+ tevent_wrapper_pop_use_internal(handler_ev, cur.wrapper);
+ }
+ im->busy = false;
+
+ /* The event was removed in tevent_common_immediate_cancel(). */
+ if (im->detach_ev_ctx != NULL) {
+ struct tevent_context *detach_ev_ctx = im->detach_ev_ctx;
+ im->detach_ev_ctx = NULL;
+ tevent_trace_immediate_callback(detach_ev_ctx,
+ im,
+ TEVENT_EVENT_TRACE_DETACH);
+ }
+
+ if (im->destroyed) {
+ talloc_set_destructor(im, NULL);
+ TALLOC_FREE(im);
+ if (removed != NULL) {
+ *removed = true;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ trigger the first immediate event and return true
+ if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+ struct tevent_immediate *im = ev->immediate_events;
+ int ret;
+
+ if (!im) {
+ return false;
+ }
+
+ ret = tevent_common_invoke_immediate_handler(im, NULL);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
+ }
+
+ return true;
+}
+
+
+void tevent_immediate_set_tag(struct tevent_immediate *im, uint64_t tag)
+{
+ if (im == NULL) {
+ return;
+ }
+
+ im->tag = tag;
+}
+
+uint64_t tevent_immediate_get_tag(const struct tevent_immediate *im)
+{
+ if (im == NULL) {
+ return 0;
+ }
+
+ return im->tag;
+}
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
new file mode 100644
index 0000000..75ae114
--- /dev/null
+++ b/lib/tevent/tevent_internal.h
@@ -0,0 +1,950 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ generalised event loop handling
+
+ INTERNAL STRUCTS. THERE ARE NO API GUARANTEES.
+ External users should only ever have to include this header when
+ implementing new tevent backends.
+
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+struct tevent_req {
+ /**
+ * @brief What to do on completion
+ *
+ * This is used for the user of an async request, fn is called when
+ * the request completes, either successfully or with an error.
+ */
+ struct {
+ /**
+ * @brief Completion function
+ * Completion function, to be filled by the API user
+ */
+ tevent_req_fn fn;
+ /**
+ * @brief Private data for the completion function
+ */
+ void *private_data;
+ /**
+ * @brief The completion function name, for flow tracing.
+ */
+ const char *fn_name;
+ } async;
+
+ /**
+ * @brief Private state pointer for the actual implementation
+ *
+ * The implementation doing the work for the async request needs to
+ * keep around current data like for example a fd event. The user of
+ * an async request should not touch this.
+ */
+ void *data;
+
+ /**
+ * @brief A function to overwrite the default print function
+ *
+ * The implementation doing the work may want to implement a
+ * custom function to print the text representation of the async
+ * request.
+ */
+ tevent_req_print_fn private_print;
+
+ /**
+ * @brief A function to cancel the request
+ *
+ * The implementation might want to set a function
+ * that is called when the tevent_req_cancel() function
+ * was called.
+ */
+ struct {
+ tevent_req_cancel_fn fn;
+ const char *fn_name;
+ } private_cancel;
+
+ /**
+ * @brief A function to cleanup the request
+ *
+ * The implementation might want to set a function
+ * that is called before the tevent_req_done() and tevent_req_error()
+ * trigger the callers callback function.
+ */
+ struct {
+ tevent_req_cleanup_fn fn;
+ const char *fn_name;
+ enum tevent_req_state state;
+ } private_cleanup;
+
+ /**
+ * @brief Internal state of the request
+ *
+ * Callers should only access this via functions and never directly.
+ */
+ struct {
+ /**
+ * @brief The talloc type of the data pointer
+ *
+ * This is filled by the tevent_req_create() macro.
+ *
+ * This for debugging only.
+ */
+ const char *private_type;
+
+ /**
+ * @brief The location where the request was created
+ *
+ * This uses the __location__ macro via the tevent_req_create()
+ * macro.
+ *
+ * This for debugging only.
+ */
+ const char *create_location;
+
+ /**
+ * @brief The location where the request was finished
+ *
+ * This uses the __location__ macro via the tevent_req_done(),
+ * tevent_req_error() or tevent_req_nomem() macro.
+ *
+ * This for debugging only.
+ */
+ const char *finish_location;
+
+ /**
+ * @brief The location where the request was canceled
+ *
+ * This uses the __location__ macro via the
+ * tevent_req_cancel() macro.
+ *
+ * This for debugging only.
+ */
+ const char *cancel_location;
+
+ /**
+ * @brief The external state - will be queried by the caller
+ *
+ * While the async request is being processed, state will remain in
+ * TEVENT_REQ_IN_PROGRESS. A request is finished if
+ * req->state>=TEVENT_REQ_DONE.
+ */
+ enum tevent_req_state state;
+
+ /**
+ * @brief status code when finished
+ *
+ * This status can be queried in the async completion function. It
+ * will be set to 0 when everything went fine.
+ */
+ uint64_t error;
+
+ /**
+ * @brief the immediate event used by tevent_req_post
+ *
+ */
+ struct tevent_immediate *trigger;
+
+ /**
+ * @brief An event context which will be used to
+ * defer the _tevent_req_notify_callback().
+ */
+ struct tevent_context *defer_callback_ev;
+
+ /**
+ * @brief the timer event if tevent_req_set_endtime was used
+ *
+ */
+ struct tevent_timer *timer;
+
+ /**
+ * @brief The place where profiling data is kept
+ */
+ struct tevent_req_profile *profile;
+
+ size_t call_depth;
+ } internal;
+};
+
+struct tevent_req_profile {
+ struct tevent_req_profile *prev, *next;
+ struct tevent_req_profile *parent;
+ const char *req_name;
+ pid_t pid;
+ const char *start_location;
+ struct timeval start_time;
+ const char *stop_location;
+ struct timeval stop_time;
+ enum tevent_req_state state;
+ uint64_t user_error;
+ struct tevent_req_profile *subprofiles;
+};
+
+struct tevent_fd {
+ struct tevent_fd *prev, *next;
+ struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
+ bool busy;
+ bool destroyed;
+ int fd;
+ uint16_t flags; /* see TEVENT_FD_* flags */
+ tevent_fd_handler_t handler;
+ tevent_fd_close_fn_t close_fn;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *location;
+ /* this is private for the events_ops implementation */
+ uint64_t additional_flags;
+ void *additional_data;
+ /* custom tag that can be set by caller */
+ uint64_t tag;
+ struct tevent_fd_mpx {
+ struct tevent_fd_mpx *prev, *next;
+ struct tevent_fd *fde;
+ struct tevent_fd *primary;
+ struct tevent_fd_mpx *list;
+ uint16_t total_flags;
+ bool has_mpx;
+ } mpx;
+};
+
+struct tevent_timer {
+ struct tevent_timer *prev, *next;
+ struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
+ bool busy;
+ bool destroyed;
+ struct timeval next_event;
+ tevent_timer_handler_t handler;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *location;
+ /* this is private for the events_ops implementation */
+ void *additional_data;
+ /* custom tag that can be set by caller */
+ uint64_t tag;
+};
+
+struct tevent_immediate {
+ struct tevent_immediate *prev, *next;
+ struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
+ bool busy;
+ bool destroyed;
+ struct tevent_context *detach_ev_ctx;
+ tevent_immediate_handler_t handler;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *create_location;
+ const char *schedule_location;
+ /* this is private for the events_ops implementation */
+ void (*cancel_fn)(struct tevent_immediate *im);
+ void *additional_data;
+ /* custom tag that can be set by caller */
+ uint64_t tag;
+};
+
+struct tevent_signal {
+ struct tevent_signal *prev, *next;
+ struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
+ bool busy;
+ bool destroyed;
+ int signum;
+ int sa_flags;
+ tevent_signal_handler_t handler;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *location;
+ /* this is private for the events_ops implementation */
+ void *additional_data;
+ /* custom tag that can be set by caller */
+ uint64_t tag;
+};
+
+struct tevent_threaded_context {
+ struct tevent_threaded_context *next, *prev;
+
+#ifdef HAVE_PTHREAD
+ pthread_mutex_t event_ctx_mutex;
+#endif
+ struct tevent_context *event_ctx;
+};
+
+struct tevent_debug_ops {
+ enum tevent_debug_level max_level;
+ void (*debug)(void *context, enum tevent_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+ void *context;
+};
+
+void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+#define TEVENT_DEBUG(__ev, __level, __fmt, ...) do { \
+ if (unlikely((__ev) != NULL && \
+ (__level) <= (__ev)->debug_ops.max_level)) \
+ { \
+ tevent_debug((__ev), (__level), (__fmt), __VA_ARGS__); \
+ } \
+} while(0)
+
+void tevent_abort(struct tevent_context *ev, const char *reason);
+
+void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason);
+
+struct tevent_context {
+ /* the specific events implementation */
+ const struct tevent_ops *ops;
+
+ /*
+ * The following three pointers are queried on every loop_once
+ * in the order in which they appear here. Not measured, but
+ * hopefully putting them at the top together with "ops"
+ * should make tevent a *bit* more cache-friendly than before.
+ */
+
+ /* list of signal events - used by common code */
+ struct tevent_signal *signal_events;
+
+ /* List of threaded job indicators */
+ struct tevent_threaded_context *threaded_contexts;
+
+ /* list of immediate events - used by common code */
+ struct tevent_immediate *immediate_events;
+
+ /* list of fd events - used by common code */
+ struct tevent_fd *fd_events;
+
+ /* list of timed events - used by common code */
+ struct tevent_timer *timer_events;
+
+ /* List of scheduled immediates */
+ pthread_mutex_t scheduled_mutex;
+ struct tevent_immediate *scheduled_immediates;
+
+ /* this is private for the events_ops implementation */
+ void *additional_data;
+
+ /* pipe hack used with signal handlers */
+ struct tevent_fd *wakeup_fde;
+ int wakeup_fd; /* fd to write into */
+#ifndef HAVE_EVENT_FD
+ int wakeup_read_fd;
+#endif
+
+ /* debugging operations */
+ struct tevent_debug_ops debug_ops;
+
+ /* info about the nesting status */
+ struct {
+ bool allowed;
+ uint32_t level;
+ tevent_nesting_hook hook_fn;
+ void *hook_private;
+ } nesting;
+
+ struct {
+ struct {
+ tevent_trace_callback_t callback;
+ void *private_data;
+ } point;
+
+ struct {
+ tevent_trace_fd_callback_t callback;
+ void *private_data;
+ } fde;
+
+ struct {
+ tevent_trace_signal_callback_t callback;
+ void *private_data;
+ } se;
+
+ struct {
+ tevent_trace_timer_callback_t callback;
+ void *private_data;
+ } te;
+
+ struct {
+ tevent_trace_immediate_callback_t callback;
+ void *private_data;
+ } im;
+
+ struct {
+ tevent_trace_queue_callback_t callback;
+ void *private_data;
+ } qe;
+ } tracing;
+
+ struct {
+ /*
+ * This is used on the main event context
+ */
+ struct tevent_wrapper_glue *list;
+
+ /*
+ * This is used on the wrapper event context
+ */
+ struct tevent_wrapper_glue *glue;
+ } wrapper;
+
+ /*
+ * an optimization pointer into timer_events
+ * used by used by common code via
+ * tevent_common_add_timer_v2()
+ */
+ struct tevent_timer *last_zero_timer;
+
+#ifdef HAVE_PTHREAD
+ struct tevent_context *prev, *next;
+#endif
+};
+
+int tevent_common_context_destructor(struct tevent_context *ev);
+int tevent_common_loop_wait(struct tevent_context *ev,
+ const char *location);
+
+struct tevent_common_fd_buf {
+ char buf[128];
+};
+
+const char *tevent_common_fd_str(struct tevent_common_fd_buf *buf,
+ const char *description,
+ const struct tevent_fd *fde);
+
+int tevent_common_fd_destructor(struct tevent_fd *fde);
+struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn);
+uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde);
+void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
+ bool *removed);
+
+struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
+int tevent_common_invoke_timer_handler(struct tevent_timer *te,
+ struct timeval current_time,
+ bool *removed);
+
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+ bool *removed);
+bool tevent_common_loop_immediate(struct tevent_context *ev);
+void tevent_common_threaded_activate_immediate(struct tevent_context *ev);
+
+bool tevent_common_have_events(struct tevent_context *ev);
+int tevent_common_wakeup_init(struct tevent_context *ev);
+int tevent_common_wakeup_fd(int fd);
+int tevent_common_wakeup(struct tevent_context *ev);
+
+struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+int tevent_common_check_signal(struct tevent_context *ev);
+void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
+int tevent_common_invoke_signal_handler(struct tevent_signal *se,
+ int signum, int count, void *siginfo,
+ bool *removed);
+
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev);
+
+struct tevent_wrapper_ops;
+
+struct tevent_wrapper_glue {
+ struct tevent_wrapper_glue *prev, *next;
+ struct tevent_context *wrap_ev;
+ struct tevent_context *main_ev;
+ bool busy;
+ bool destroyed;
+ const struct tevent_wrapper_ops *ops;
+ void *private_state;
+};
+
+void tevent_wrapper_push_use_internal(struct tevent_context *ev,
+ struct tevent_wrapper_glue *wrapper);
+void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
+ struct tevent_wrapper_glue *wrapper);
+
+bool tevent_standard_init(void);
+bool tevent_poll_init(void);
+bool tevent_poll_event_add_fd_internal(struct tevent_context *ev,
+ struct tevent_fd *fde);
+bool tevent_poll_mt_init(void);
+#ifdef HAVE_EPOLL
+bool tevent_epoll_init(void);
+void tevent_epoll_set_panic_fallback(struct tevent_context *ev,
+ bool (*panic_fallback)(struct tevent_context *ev,
+ bool replay));
+#endif
+
+static inline void tevent_thread_call_depth_notify(
+ enum tevent_thread_call_depth_cmd cmd,
+ struct tevent_req *req,
+ size_t depth,
+ const char *fname)
+{
+ if (tevent_thread_call_depth_state_g.cb != NULL) {
+ tevent_thread_call_depth_state_g.cb(
+ tevent_thread_call_depth_state_g.cb_private,
+ cmd,
+ req,
+ depth,
+ fname);
+ }
+}
+
+void tevent_trace_point_callback(struct tevent_context *ev,
+ enum tevent_trace_point);
+
+void tevent_trace_fd_callback(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ enum tevent_event_trace_point);
+
+void tevent_trace_signal_callback(struct tevent_context *ev,
+ struct tevent_signal *se,
+ enum tevent_event_trace_point);
+
+void tevent_trace_timer_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
+ enum tevent_event_trace_point);
+
+void tevent_trace_immediate_callback(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ enum tevent_event_trace_point);
+
+void tevent_trace_queue_callback(struct tevent_context *ev,
+ struct tevent_queue_entry *qe,
+ enum tevent_event_trace_point);
+
+#include "tevent_dlinklist.h"
+
+static inline void tevent_common_fd_mpx_reinit(struct tevent_fd *fde)
+{
+ fde->mpx = (struct tevent_fd_mpx) { .fde = fde, };
+}
+
+static inline void tevent_common_fd_disarm(struct tevent_fd *fde)
+{
+ if (fde->event_ctx != NULL) {
+ tevent_trace_fd_callback(fde->event_ctx, fde,
+ TEVENT_EVENT_TRACE_DETACH);
+ DLIST_REMOVE(fde->event_ctx->fd_events, fde);
+ fde->event_ctx = NULL;
+ }
+ tevent_common_fd_mpx_reinit(fde);
+ fde->wrapper = NULL;
+}
+
+/*
+ * tevent_common_fd_mpx_primary() returns the fde that is responsible
+ * for the low level state.
+ *
+ * By default (when there's no multiplexing) it just returns 'any_fde'.
+ *
+ * Note it always returns a valid pointer.
+ */
+static inline
+struct tevent_fd *tevent_common_fd_mpx_primary(struct tevent_fd *any_fde)
+{
+ struct tevent_fd *primary = NULL;
+
+ if (any_fde->mpx.primary != NULL) {
+ primary = any_fde->mpx.primary;
+ } else {
+ primary = any_fde;
+ }
+
+ return primary;
+}
+
+/*
+ * tevent_common_fd_mpx_update_flags() needs to be called
+ * if update_fde->flags has changed. It is needed in
+ * order to let tevent_common_fd_mpx_flags() return a valid
+ * result.
+ */
+static inline
+void tevent_common_fd_mpx_update_flags(struct tevent_fd *update_fde)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(update_fde);
+ struct tevent_fd_mpx *mpx = NULL;
+ uint16_t new_total_flags = 0;
+
+ if (!primary->mpx.has_mpx) {
+ primary->mpx.total_flags = primary->flags;
+ return;
+ }
+
+ for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
+ struct tevent_fd *mpx_fde = mpx->fde;
+ /* we don't care that mpx_fde might be == primary */
+ new_total_flags |= mpx_fde->flags;
+ }
+
+ primary->mpx.total_flags = new_total_flags;
+}
+
+/*
+ * tevent_common_fd_mpx_flags() return the effective flags
+ * (TEVEND_FD_*) of the primary fde and all multiplexed fdes.
+ *
+ * Valid after tevent_common_fd_mpx_update_flags() was called
+ */
+static inline
+uint16_t tevent_common_fd_mpx_flags(struct tevent_fd *any_fde)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
+
+ return primary->mpx.total_flags;
+}
+
+/*
+ * tevent_common_fd_mpx_clear_writeable() clears TEVENT_FD_WRITE
+ * from all fdes belonging together.
+ */
+static inline
+void tevent_common_fd_mpx_clear_writeable(struct tevent_fd *any_fde)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
+ struct tevent_fd_mpx *mpx = NULL;
+
+ primary->flags &= ~TEVENT_FD_WRITE;
+
+ for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
+ struct tevent_fd *mpx_fde = mpx->fde;
+ /* we don't care that mpx_fde might be == primary */
+ mpx_fde->flags &= ~TEVENT_FD_WRITE;
+ }
+
+ primary->mpx.total_flags &= ~TEVENT_FD_WRITE;
+}
+
+/*
+ * tevent_common_fd_mpx_additional_flags() modifies
+ * fde->additional_flags for all fdes belonging together.
+ */
+static inline
+void tevent_common_fd_mpx_additional_flags(struct tevent_fd *any_fde,
+ uint64_t clear_flags,
+ uint64_t add_flags)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
+ struct tevent_fd_mpx *mpx = NULL;
+
+ primary->additional_flags &= ~clear_flags;
+ primary->additional_flags |= add_flags;
+
+ for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
+ struct tevent_fd *mpx_fde = mpx->fde;
+ /* we don't care that mpx_fde might be == primary */
+ mpx_fde->additional_flags &= ~clear_flags;
+ mpx_fde->additional_flags |= add_flags;
+ }
+}
+
+/*
+ * tevent_common_fd_mpx_disarm_all() detaches
+ * all fdes currently belonging together from each other
+ * and also from the tevent_context, which means their
+ * handler will never be called again.
+ */
+static inline
+void tevent_common_fd_mpx_disarm_all(struct tevent_fd *any_fde)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
+ struct tevent_fd_mpx *mpx = NULL, *next = NULL;
+
+ for (mpx = primary->mpx.list; mpx != NULL; mpx = next) {
+ struct tevent_fd *mpx_fde = mpx->fde;
+
+ next = mpx->next;
+ DLIST_REMOVE(primary->mpx.list, mpx);
+
+ if (mpx_fde == primary) {
+ /* primary is handled below */
+ continue;
+ }
+
+ tevent_common_fd_disarm(mpx_fde);
+ }
+
+ tevent_common_fd_disarm(primary);
+}
+
+/*
+ * tevent_common_fd_mpx_select() selects the handler that
+ * should be called for the given low level event.
+ *
+ * Note it's important to pass the primary fde!
+ */
+static inline
+struct tevent_fd *tevent_common_fd_mpx_select(struct tevent_fd *primary,
+ uint16_t flags,
+ bool got_error)
+{
+ struct tevent_fd_mpx *mpx = NULL;
+ struct tevent_fd *selected = NULL;
+
+ /* optimize for the single event case. */
+ if (!primary->mpx.has_mpx) {
+ /*
+ * If we got an error, we won't report it if
+ * the caller only asked for TEVENT_FD_WRITE.
+ */
+ if (got_error &&
+ !(primary->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
+ {
+ return NULL;
+ }
+
+ if (flags & primary->flags) {
+ return primary;
+ }
+
+ return NULL;
+ }
+
+ for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
+ struct tevent_fd *mpx_fde = mpx->fde;
+
+ /*
+ * If we got an error, we won't report it if
+ * the caller only asked for TEVENT_FD_WRITE.
+ */
+ if (got_error &&
+ !(mpx_fde->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
+ {
+ continue;
+ }
+
+ if (flags & mpx_fde->flags) {
+ selected = mpx_fde;
+ break;
+ }
+ }
+
+ if (selected == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Maintain fairness and demote the just selected fde
+ */
+ DLIST_DEMOTE_SHORT(primary->mpx.list, &selected->mpx);
+ return selected;
+}
+
+/*
+ * tevent_common_fd_mpx_add() searches for an existing (active) fde
+ * for the same low level fd and adds the given 'add_fde'
+ * as multiplexed to the found fde.
+ *
+ * If another fde was found it is returned.
+ * NULL is returned to indicate no match
+ */
+static inline
+struct tevent_fd *tevent_common_fd_mpx_add(struct tevent_fd *add_fde)
+{
+ struct tevent_context *ev = add_fde->event_ctx;
+ struct tevent_fd *add_primary = tevent_common_fd_mpx_primary(add_fde);
+ uint16_t add_flags = tevent_common_fd_mpx_flags(add_primary);
+ struct tevent_fd *mpx_fde = NULL;
+ struct tevent_fd *mpx_primary = NULL;
+ struct tevent_fd_mpx *tmp = NULL;
+ struct tevent_fd_mpx *next = NULL;
+
+ /* Find the existing fde that caused the EEXIST error. */
+ for (mpx_fde = ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
+ mpx_primary = tevent_common_fd_mpx_primary(mpx_fde);
+
+ if (mpx_primary->fd != add_primary->fd) {
+ mpx_primary = NULL;
+ continue;
+ }
+
+ if (mpx_primary == add_primary) {
+ mpx_primary = NULL;
+ continue;
+ }
+
+ if (add_flags != 0 &&
+ tevent_common_fd_mpx_flags(mpx_primary) == 0)
+ {
+ /*
+ * only active events should match
+ */
+ mpx_primary = NULL;
+ continue;
+ }
+ break;
+ }
+ if (mpx_primary == NULL) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "can't find multiplex fde for fd[%d]",
+ add_fde->fd);
+ return NULL;
+ }
+
+ /*
+ * If add_primary is not in it's own list
+ * we add it in order to simplify the loop below.
+ */
+
+ if (add_primary->mpx.prev == NULL && add_primary->mpx.next == NULL) {
+ DLIST_ADD_END(add_primary->mpx.list, &add_primary->mpx);
+ }
+
+ /*
+ * Add the new mpx_primary to its own list before others,
+ * if it is not already added.
+ */
+ if (mpx_primary->mpx.prev == NULL && mpx_primary->mpx.next == NULL) {
+ DLIST_ADD_END(mpx_primary->mpx.list, &mpx_primary->mpx);
+ }
+
+ /*
+ * Now we clear all entries and move them to the
+ * new primary
+ */
+ for (tmp = add_primary->mpx.list; tmp != NULL; tmp = next) {
+ struct tevent_fd *tmp_fde = tmp->fde;
+
+ next = tmp->next;
+
+ DLIST_REMOVE(add_primary->mpx.list, tmp);
+ tevent_common_fd_mpx_reinit(tmp_fde);
+ DLIST_ADD_END(mpx_primary->mpx.list, tmp);
+ tmp->primary = mpx_primary;
+ tmp->has_mpx = true;
+ }
+
+ mpx_primary->mpx.has_mpx = true;
+ return mpx_primary;
+}
+
+/*
+ * tevent_common_fd_mpx_update() calls tevent_common_fd_mpx_update_flags()
+ * and compares tevent_common_fd_mpx_flags() before and after.
+ *
+ * When there's a low level update needed the primary fde,
+ * otherwise NULL is returned.
+ */
+static inline
+struct tevent_fd *tevent_common_fd_mpx_update(struct tevent_fd *update_fde)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(update_fde);
+ uint16_t old_total_flags;
+ uint16_t new_total_flags;
+
+ old_total_flags = primary->mpx.total_flags;
+ tevent_common_fd_mpx_update_flags(primary);
+ new_total_flags = primary->mpx.total_flags;
+
+ if (old_total_flags == new_total_flags) {
+ /* No update needed */
+ return NULL;
+ }
+
+ return primary;
+}
+
+/*
+ * tevent_common_fd_mpx_remove() removes remove_fde from its possible primary,
+ * if remove_fde is a primary itself, a new primary is selected.
+ *
+ * The remaining primary or NULL is returned.
+ */
+static inline
+struct tevent_fd *tevent_common_fd_mpx_remove(struct tevent_fd *remove_fde)
+{
+ struct tevent_fd *primary = tevent_common_fd_mpx_primary(remove_fde);
+ struct tevent_fd_mpx *mpx = NULL, *next = NULL;
+ struct tevent_fd *new_primary = NULL;
+
+ DLIST_REMOVE(primary->mpx.list, &remove_fde->mpx);
+
+ if (primary != remove_fde) {
+ tevent_common_fd_mpx_reinit(remove_fde);
+ return primary;
+ }
+
+ for (mpx = primary->mpx.list; mpx != NULL; mpx = next) {
+ struct tevent_fd *mpx_fde = mpx->fde;
+
+ next = mpx->next;
+
+ DLIST_REMOVE(primary->mpx.list, &mpx_fde->mpx);
+ tevent_common_fd_mpx_reinit(mpx_fde);
+ mpx->primary = new_primary;
+ if (new_primary == NULL) {
+ /*
+ * Select the first one as the new primary and add
+ * itself as the first mpx-fde to the mpx list
+ */
+ new_primary = mpx_fde;
+ DLIST_ADD(new_primary->mpx.list, &mpx_fde->mpx);
+ continue;
+ }
+ new_primary->mpx.has_mpx = true;
+ mpx->has_mpx = true;
+ DLIST_ADD_END(new_primary->mpx.list, &mpx_fde->mpx);
+ }
+
+ /* primary == remove_fde */
+ tevent_common_fd_mpx_reinit(primary);
+ return new_primary;
+}
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
new file mode 100644
index 0000000..91a9381
--- /dev/null
+++ b/lib/tevent/tevent_poll.c
@@ -0,0 +1,695 @@
+/*
+ Unix SMB/CIFS implementation.
+ main select loop and event handling
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "tevent.h"
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct poll_event_context {
+ /* a pointer back to the generic event_context */
+ struct tevent_context *ev;
+
+ /*
+ * one or more events were deleted or disabled
+ */
+ bool deleted;
+
+ /*
+ * These two arrays are maintained together.
+ *
+ * The following is always true:
+ * num_fds <= num_fdes
+ *
+ * new 'fresh' elements are added at the end
+ * of the 'fdes' array and picked up later
+ * to the 'fds' array in poll_event_sync_arrays()
+ * before the poll() syscall.
+ */
+ struct pollfd *fds;
+ size_t num_fds;
+ struct tevent_fd **fdes;
+ size_t num_fdes;
+
+ /*
+ * use tevent_common_wakeup(ev) to wake the poll() thread
+ */
+ bool use_mt_mode;
+};
+
+/*
+ create a poll_event_context structure.
+*/
+static int poll_event_context_init(struct tevent_context *ev)
+{
+ struct poll_event_context *poll_ev;
+
+ /*
+ * we might be called during tevent_re_initialise()
+ * which means we need to free our old additional_data
+ * in order to detach old fd events from the
+ * poll_ev->fresh list
+ */
+ TALLOC_FREE(ev->additional_data);
+
+ poll_ev = talloc_zero(ev, struct poll_event_context);
+ if (poll_ev == NULL) {
+ return -1;
+ }
+ poll_ev->ev = ev;
+ ev->additional_data = poll_ev;
+ return 0;
+}
+
+static int poll_event_context_init_mt(struct tevent_context *ev)
+{
+ struct poll_event_context *poll_ev;
+ int ret;
+
+ ret = poll_event_context_init(ev);
+ if (ret == -1) {
+ return ret;
+ }
+
+ poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ ret = tevent_common_wakeup_init(ev);
+ if (ret != 0) {
+ return ret;
+ }
+
+ poll_ev->use_mt_mode = true;
+
+ return 0;
+}
+
+static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
+{
+ if (!poll_ev->use_mt_mode) {
+ return;
+ }
+ tevent_common_wakeup(poll_ev->ev);
+}
+
+/*
+ destroy an fd_event
+*/
+static int poll_event_fd_destructor(struct tevent_fd *fde)
+{
+ struct tevent_context *ev = fde->event_ctx;
+ struct poll_event_context *poll_ev;
+ uint64_t del_idx = fde->additional_flags;
+
+ if (ev == NULL) {
+ goto done;
+ }
+
+ poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ if (del_idx == UINT64_MAX) {
+ goto done;
+ }
+
+ poll_ev->fdes[del_idx] = NULL;
+ poll_ev->deleted = true;
+ poll_event_wake_pollthread(poll_ev);
+done:
+ return tevent_common_fd_destructor(fde);
+}
+
+static void poll_event_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct poll_event_context *poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ tevent_common_schedule_immediate(im, ev, handler, private_data,
+ handler_name, location);
+ poll_event_wake_pollthread(poll_ev);
+}
+
+/*
+ Private function called by "standard" backend fallback.
+ Note this only allows fallback to "poll" backend, not "poll-mt".
+*/
+_PRIVATE_ bool tevent_poll_event_add_fd_internal(struct tevent_context *ev,
+ struct tevent_fd *fde)
+{
+ struct poll_event_context *poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+ uint64_t fde_idx = UINT64_MAX;
+ size_t num_fdes;
+
+ fde->additional_flags = UINT64_MAX;
+ tevent_common_fd_mpx_reinit(fde);
+ talloc_set_destructor(fde, poll_event_fd_destructor);
+
+ if (fde->flags == 0) {
+ /*
+ * Nothing more to do...
+ */
+ return true;
+ }
+
+ /*
+ * We need to add it to the end of the 'fdes' array.
+ */
+ num_fdes = poll_ev->num_fdes + 1;
+ if (num_fdes > talloc_array_length(poll_ev->fdes)) {
+ struct tevent_fd **tmp_fdes = NULL;
+ size_t array_length;
+
+ array_length = (num_fdes + 15) & ~15; /* round up to 16 */
+
+ tmp_fdes = talloc_realloc(poll_ev,
+ poll_ev->fdes,
+ struct tevent_fd *,
+ array_length);
+ if (tmp_fdes == NULL) {
+ return false;
+ }
+ poll_ev->fdes = tmp_fdes;
+ }
+
+ fde_idx = poll_ev->num_fdes;
+ fde->additional_flags = fde_idx;
+ poll_ev->fdes[fde_idx] = fde;
+ poll_ev->num_fdes++;
+
+ return true;
+}
+
+/*
+ add a fd based event
+ return NULL on failure (memory allocation error)
+*/
+static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct poll_event_context *poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+ struct tevent_fd *fde;
+ bool ok;
+
+ if (fd < 0) {
+ return NULL;
+ }
+
+ fde = tevent_common_add_fd(ev,
+ mem_ctx,
+ fd,
+ flags,
+ handler,
+ private_data,
+ handler_name,
+ location);
+ if (fde == NULL) {
+ return NULL;
+ }
+
+ ok = tevent_poll_event_add_fd_internal(ev, fde);
+ if (!ok) {
+ TALLOC_FREE(fde);
+ return NULL;
+ }
+ poll_event_wake_pollthread(poll_ev);
+
+ /*
+ * poll_event_loop_poll will take care of the rest in
+ * poll_event_setup_fresh
+ */
+ return fde;
+}
+
+/*
+ map from TEVENT_FD_* to POLLIN/POLLOUT
+*/
+static uint16_t poll_map_flags(uint16_t flags)
+{
+ uint16_t pollflags = 0;
+
+ /*
+ * we do not need to specify POLLERR | POLLHUP
+ * they are always reported.
+ */
+
+ if (flags & TEVENT_FD_READ) {
+ pollflags |= POLLIN;
+#ifdef POLLRDHUP
+ /*
+ * Note that at least on Linux
+ * POLLRDHUP always returns
+ * POLLIN in addition, so this
+ * is not strictly needed, but
+ * we want to make it explicit.
+ */
+ pollflags |= POLLRDHUP;
+#endif
+ }
+ if (flags & TEVENT_FD_WRITE) {
+ pollflags |= POLLOUT;
+ }
+ if (flags & TEVENT_FD_ERROR) {
+#ifdef POLLRDHUP
+ pollflags |= POLLRDHUP;
+#endif
+ }
+
+ return pollflags;
+}
+
+/*
+ set the fd event flags
+*/
+static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ struct tevent_context *ev = fde->event_ctx;
+ struct poll_event_context *poll_ev;
+ uint64_t idx = fde->additional_flags;
+
+ if (ev == NULL) {
+ return;
+ }
+
+ if (fde->flags == flags) {
+ return;
+ }
+
+ poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ fde->flags = flags;
+
+ if (idx == UINT64_MAX) {
+ /*
+ * We move it between the fresh and disabled lists.
+ */
+ tevent_poll_event_add_fd_internal(ev, fde);
+ poll_event_wake_pollthread(poll_ev);
+ return;
+ }
+
+ if (fde->flags == 0) {
+ /*
+ * We need to remove it from the array
+ * and move it to the disabled list.
+ */
+ poll_ev->fdes[idx] = NULL;
+ poll_ev->deleted = true;
+ fde->additional_flags = UINT64_MAX;
+ poll_event_wake_pollthread(poll_ev);
+ return;
+ }
+
+ if (idx >= poll_ev->num_fds) {
+ /*
+ * Not yet added to the
+ * poll_ev->fds array.
+ */
+ poll_event_wake_pollthread(poll_ev);
+ return;
+ }
+
+ poll_ev->fds[idx].events = poll_map_flags(flags);
+
+ poll_event_wake_pollthread(poll_ev);
+}
+
+static bool poll_event_sync_arrays(struct tevent_context *ev,
+ struct poll_event_context *poll_ev)
+{
+ size_t i;
+ size_t array_length;
+
+ if (poll_ev->deleted) {
+
+ for (i=0; i < poll_ev->num_fds;) {
+ struct tevent_fd *fde = poll_ev->fdes[i];
+ size_t ci;
+
+ if (fde != NULL) {
+ i++;
+ continue;
+ }
+
+ /*
+ * This fde was talloc_free()'ed. Delete it
+ * from the arrays
+ */
+ poll_ev->num_fds -= 1;
+ ci = poll_ev->num_fds;
+ if (ci > i) {
+ poll_ev->fds[i] = poll_ev->fds[ci];
+ poll_ev->fdes[i] = poll_ev->fdes[ci];
+ if (poll_ev->fdes[i] != NULL) {
+ poll_ev->fdes[i]->additional_flags = i;
+ }
+ }
+ poll_ev->fds[ci] = (struct pollfd) { .fd = -1 };
+ poll_ev->fdes[ci] = NULL;
+ }
+ poll_ev->deleted = false;
+ }
+
+ if (poll_ev->num_fds == poll_ev->num_fdes) {
+ return true;
+ }
+
+ /*
+ * Recheck the size of both arrays and make sure
+ * poll_fd->fds array has at least the size of the
+ * in use poll_ev->fdes array.
+ */
+ if (poll_ev->num_fdes > talloc_array_length(poll_ev->fds)) {
+ struct pollfd *tmp_fds = NULL;
+
+ /*
+ * Make sure both allocated the same length.
+ */
+ array_length = talloc_array_length(poll_ev->fdes);
+
+ tmp_fds = talloc_realloc(poll_ev,
+ poll_ev->fds,
+ struct pollfd,
+ array_length);
+ if (tmp_fds == NULL) {
+ return false;
+ }
+ poll_ev->fds = tmp_fds;
+ }
+
+ /*
+ * Now setup the new elements.
+ */
+ for (i = poll_ev->num_fds; i < poll_ev->num_fdes; i++) {
+ struct tevent_fd *fde = poll_ev->fdes[i];
+ struct pollfd *pfd = &poll_ev->fds[poll_ev->num_fds];
+
+ if (fde == NULL) {
+ continue;
+ }
+
+ if (i > poll_ev->num_fds) {
+ poll_ev->fdes[poll_ev->num_fds] = fde;
+ fde->additional_flags = poll_ev->num_fds;
+ poll_ev->fdes[i] = NULL;
+ }
+
+ pfd->fd = fde->fd;
+ pfd->events = poll_map_flags(fde->flags);
+ pfd->revents = 0;
+
+ poll_ev->num_fds += 1;
+ }
+ /* Both are in sync again */
+ poll_ev->num_fdes = poll_ev->num_fds;
+
+ /*
+ * Check if we should shrink the arrays
+ * But keep at least 16 elements.
+ */
+
+ array_length = (poll_ev->num_fds + 15) & ~15; /* round up to 16 */
+ array_length = MAX(array_length, 16);
+ if (array_length < talloc_array_length(poll_ev->fdes)) {
+ struct tevent_fd **tmp_fdes = NULL;
+ struct pollfd *tmp_fds = NULL;
+
+ tmp_fdes = talloc_realloc(poll_ev,
+ poll_ev->fdes,
+ struct tevent_fd *,
+ array_length);
+ if (tmp_fdes == NULL) {
+ return false;
+ }
+ poll_ev->fdes = tmp_fdes;
+
+ tmp_fds = talloc_realloc(poll_ev,
+ poll_ev->fds,
+ struct pollfd,
+ array_length);
+ if (tmp_fds == NULL) {
+ return false;
+ }
+ poll_ev->fds = tmp_fds;
+ }
+
+ return true;
+}
+
+/*
+ event loop handling using poll()
+*/
+static int poll_event_loop_poll(struct tevent_context *ev,
+ struct timeval *tvalp)
+{
+ struct poll_event_context *poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+ int pollrtn;
+ int timeout = -1;
+ int poll_errno;
+ struct tevent_fd *fde = NULL;
+ struct tevent_fd *next = NULL;
+ unsigned i;
+ bool ok;
+
+ if (ev->signal_events && tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (tvalp != NULL) {
+ timeout = tvalp->tv_sec * 1000;
+ timeout += (tvalp->tv_usec + 999) / 1000;
+ }
+
+ ok = poll_event_sync_arrays(ev, poll_ev);
+ if (!ok) {
+ return -1;
+ }
+
+ tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
+ pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
+ poll_errno = errno;
+ tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
+
+ if (pollrtn == -1 && poll_errno == EINTR && ev->signal_events) {
+ tevent_common_check_signal(ev);
+ return 0;
+ }
+
+ if (pollrtn == 0 && tvalp) {
+ /* we don't care about a possible delay here */
+ tevent_common_loop_timer_delay(ev);
+ return 0;
+ }
+
+ if (pollrtn <= 0) {
+ /*
+ * No fd's ready
+ */
+ return 0;
+ }
+
+ /* at least one file descriptor is ready - check
+ which ones and call the handler, being careful to allow
+ the handler to remove itself when called */
+
+ for (fde = ev->fd_events; fde; fde = next) {
+ uint64_t idx = fde->additional_flags;
+ struct pollfd *pfd;
+ uint16_t flags = 0;
+
+ next = fde->next;
+
+ if (idx == UINT64_MAX) {
+ continue;
+ }
+
+ pfd = &poll_ev->fds[idx];
+
+ if (pfd->revents & POLLNVAL) {
+ /*
+ * the socket is dead! this should never
+ * happen as the socket should have first been
+ * made readable and that should have removed
+ * the event, so this must be a bug.
+ *
+ * We ignore it here to match the epoll
+ * behavior.
+ */
+ tevent_debug(ev, TEVENT_DEBUG_ERROR,
+ "POLLNVAL on fde[%p] fd[%d] - disabling\n",
+ fde, pfd->fd);
+ poll_ev->fdes[idx] = NULL;
+ poll_ev->deleted = true;
+ tevent_common_fd_disarm(fde);
+ continue;
+ }
+
+#ifdef POLLRDHUP
+#define __POLL_RETURN_ERROR_FLAGS (POLLHUP|POLLERR|POLLRDHUP)
+#else
+#define __POLL_RETURN_ERROR_FLAGS (POLLHUP|POLLERR)
+#endif
+
+ if (pfd->revents & __POLL_RETURN_ERROR_FLAGS) {
+ /*
+ * If we only wait for TEVENT_FD_WRITE, we
+ * should not tell the event handler about it,
+ * and remove the writable flag, as we only
+ * report errors when waiting for read events
+ * or explicit for errors.
+ */
+ if (!(fde->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
+ {
+ TEVENT_FD_NOT_WRITEABLE(fde);
+ continue;
+ }
+ if (fde->flags & TEVENT_FD_ERROR) {
+ flags |= TEVENT_FD_ERROR;
+ }
+ if (fde->flags & TEVENT_FD_READ) {
+ flags |= TEVENT_FD_READ;
+ }
+ }
+ if (pfd->revents & POLLIN) {
+ flags |= TEVENT_FD_READ;
+ }
+ if (pfd->revents & POLLOUT) {
+ flags |= TEVENT_FD_WRITE;
+ }
+ /*
+ * Note that fde->flags could be changed when using
+ * the poll_mt backend together with threads,
+ * that why we need to check pfd->revents and fde->flags
+ */
+ flags &= fde->flags;
+ if (flags != 0) {
+ DLIST_DEMOTE(ev->fd_events, fde);
+ return tevent_common_invoke_fd_handler(fde, flags, NULL);
+ }
+ }
+
+ for (i = 0; i < poll_ev->num_fds; i++) {
+ if (poll_ev->fds[i].revents & POLLNVAL) {
+ /*
+ * the socket is dead! this should never
+ * happen as the socket should have first been
+ * made readable and that should have removed
+ * the event, so this must be a bug or
+ * a race in the poll_mt usage.
+ */
+ fde = poll_ev->fdes[i];
+ tevent_debug(ev, TEVENT_DEBUG_WARNING,
+ "POLLNVAL on dangling fd[%d] fde[%p] - disabling\n",
+ poll_ev->fds[i].fd, fde);
+ poll_ev->fdes[i] = NULL;
+ poll_ev->deleted = true;
+ if (fde != NULL) {
+ tevent_common_fd_disarm(fde);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ do a single event loop using the events defined in ev
+*/
+static int poll_event_loop_once(struct tevent_context *ev,
+ const char *location)
+{
+ struct timeval tval;
+
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (ev->threaded_contexts != NULL) {
+ tevent_common_threaded_activate_immediate(ev);
+ }
+
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
+
+ tval = tevent_common_loop_timer_delay(ev);
+ if (tevent_timeval_is_zero(&tval)) {
+ return 0;
+ }
+
+ return poll_event_loop_poll(ev, &tval);
+}
+
+static const struct tevent_ops poll_event_ops = {
+ .context_init = poll_event_context_init,
+ .add_fd = poll_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = poll_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer_v2,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = poll_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
+};
+
+_PRIVATE_ bool tevent_poll_init(void)
+{
+ return tevent_register_backend("poll", &poll_event_ops);
+}
+
+static const struct tevent_ops poll_event_mt_ops = {
+ .context_init = poll_event_context_init_mt,
+ .add_fd = poll_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = poll_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer_v2,
+ .schedule_immediate = poll_event_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = poll_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
+};
+
+_PRIVATE_ bool tevent_poll_mt_init(void)
+{
+ return tevent_register_backend("poll_mt", &poll_event_mt_ops);
+}
diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
new file mode 100644
index 0000000..8f0e6a5
--- /dev/null
+++ b/lib/tevent/tevent_queue.c
@@ -0,0 +1,462 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+#undef tevent_queue_add
+#undef tevent_queue_add_entry
+#undef tevent_queue_add_optimize_empty
+
+struct tevent_queue_entry {
+ struct tevent_queue_entry *prev, *next;
+ struct tevent_queue *queue;
+
+ bool triggered;
+
+ struct tevent_req *req;
+ struct tevent_context *ev;
+
+ tevent_queue_trigger_fn_t trigger;
+ const char *trigger_name;
+ void *private_data;
+ uint64_t tag;
+};
+
+struct tevent_queue {
+ const char *name;
+ const char *location;
+
+ bool running;
+ struct tevent_immediate *immediate;
+
+ size_t length;
+ struct tevent_queue_entry *list;
+};
+
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static int tevent_queue_entry_destructor(struct tevent_queue_entry *e)
+{
+ struct tevent_queue *q = e->queue;
+
+ if (!q) {
+ return 0;
+ }
+
+ tevent_trace_queue_callback(q->list->ev, e, TEVENT_EVENT_TRACE_DETACH);
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_QUEUE_LEAVE,
+ q->list->req,
+ q->list->req->internal.call_depth,
+ e->trigger_name);
+ DLIST_REMOVE(q->list, e);
+ q->length--;
+
+ if (!q->running) {
+ return 0;
+ }
+
+ if (!q->list) {
+ return 0;
+ }
+
+ if (q->list->triggered) {
+ return 0;
+ }
+
+ tevent_schedule_immediate(q->immediate,
+ q->list->ev,
+ tevent_queue_immediate_trigger,
+ q);
+
+ return 0;
+}
+
+static int tevent_queue_destructor(struct tevent_queue *q)
+{
+ q->running = false;
+
+ while (q->list) {
+ struct tevent_queue_entry *e = q->list;
+ talloc_free(e);
+ }
+
+ return 0;
+}
+
+struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *location)
+{
+ struct tevent_queue *queue;
+
+ queue = talloc_zero(mem_ctx, struct tevent_queue);
+ if (!queue) {
+ return NULL;
+ }
+
+ queue->name = talloc_strdup(queue, name);
+ if (!queue->name) {
+ talloc_free(queue);
+ return NULL;
+ }
+ queue->immediate = tevent_create_immediate(queue);
+ if (!queue->immediate) {
+ talloc_free(queue);
+ return NULL;
+ }
+
+ queue->location = location;
+
+ /* queue is running by default */
+ queue->running = true;
+
+ talloc_set_destructor(queue, tevent_queue_destructor);
+ return queue;
+}
+
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_queue *q =
+ talloc_get_type_abort(private_data,
+ struct tevent_queue);
+
+ if (!q->running) {
+ return;
+ }
+
+ if (!q->list) {
+ return;
+ }
+
+ tevent_trace_queue_callback(ev, q->list,
+ TEVENT_EVENT_TRACE_BEFORE_HANDLER);
+ /* Set the call depth of the request coming from the queue. */
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_QUEUE_TRIGGER,
+ q->list->req,
+ q->list->req->internal.call_depth,
+ q->list->trigger_name);
+ q->list->triggered = true;
+ q->list->trigger(q->list->req, q->list->private_data);
+}
+
+static void tevent_queue_noop_trigger(struct tevent_req *req,
+ void *_private_data)
+{
+ /* this is doing nothing but blocking the queue */
+}
+
+static struct tevent_queue_entry *tevent_queue_add_internal(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ const char *trigger_name,
+ void *private_data,
+ bool allow_direct)
+{
+ struct tevent_queue_entry *e;
+
+ e = talloc_zero(req, struct tevent_queue_entry);
+ if (e == NULL) {
+ return NULL;
+ }
+
+ /*
+ * if there is no trigger, it is just a blocker
+ */
+ if (trigger == NULL) {
+ trigger = tevent_queue_noop_trigger;
+ }
+
+ e->queue = queue;
+ e->req = req;
+ e->ev = ev;
+ e->trigger = trigger;
+ e->trigger_name = trigger_name;
+ e->private_data = private_data;
+
+ if (queue->length > 0) {
+ /*
+ * if there are already entries in the
+ * queue do not optimize.
+ */
+ allow_direct = false;
+ }
+
+ if (req->async.fn != NULL) {
+ /*
+ * If the caller wants to optimize for the
+ * empty queue case, call the trigger only
+ * if there is no callback defined for the
+ * request yet.
+ */
+ allow_direct = false;
+ }
+
+ DLIST_ADD_END(queue->list, e);
+ queue->length++;
+ talloc_set_destructor(e, tevent_queue_entry_destructor);
+ tevent_trace_queue_callback(ev, e, TEVENT_EVENT_TRACE_ATTACH);
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_QUEUE_ENTER,
+ req,
+ req->internal.call_depth,
+ e->trigger_name);
+
+ if (!queue->running) {
+ return e;
+ }
+
+ if (queue->list->triggered) {
+ return e;
+ }
+
+ /*
+ * If allowed we directly call the trigger
+ * avoiding possible delays caused by
+ * an immediate event.
+ */
+ if (allow_direct) {
+ tevent_trace_queue_callback(ev,
+ queue->list,
+ TEVENT_EVENT_TRACE_BEFORE_HANDLER);
+ queue->list->triggered = true;
+ queue->list->trigger(queue->list->req,
+ queue->list->private_data);
+ return e;
+ }
+
+ tevent_schedule_immediate(queue->immediate,
+ queue->list->ev,
+ tevent_queue_immediate_trigger,
+ queue);
+
+ return e;
+}
+
+bool tevent_queue_add(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data)
+{
+ return _tevent_queue_add(queue, ev, req, trigger, NULL, private_data);
+}
+
+bool _tevent_queue_add(struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ const char* trigger_name,
+ void *private_data)
+{
+ struct tevent_queue_entry *e;
+
+ e = tevent_queue_add_internal(queue, ev, req,
+ trigger, trigger_name,
+ private_data, false);
+ if (e == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+struct tevent_queue_entry *tevent_queue_add_entry(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data)
+{
+ return _tevent_queue_add_entry(queue, ev, req,
+ trigger, NULL,
+ private_data);
+}
+
+struct tevent_queue_entry *_tevent_queue_add_entry(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ const char* trigger_name,
+ void *private_data)
+{
+ return tevent_queue_add_internal(queue, ev, req,
+ trigger, trigger_name,
+ private_data, false);
+}
+
+struct tevent_queue_entry *tevent_queue_add_optimize_empty(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ void *private_data)
+{
+ return _tevent_queue_add_optimize_empty(queue, ev, req,
+ trigger, NULL,
+ private_data);
+}
+
+struct tevent_queue_entry *_tevent_queue_add_optimize_empty(
+ struct tevent_queue *queue,
+ struct tevent_context *ev,
+ struct tevent_req *req,
+ tevent_queue_trigger_fn_t trigger,
+ const char* trigger_name,
+ void *private_data)
+{
+ return tevent_queue_add_internal(queue, ev, req,
+ trigger, trigger_name,
+ private_data, true);
+}
+
+void tevent_queue_entry_untrigger(struct tevent_queue_entry *entry)
+{
+ if (entry->queue->running) {
+ abort();
+ }
+
+ if (entry->queue->list != entry) {
+ abort();
+ }
+
+ entry->triggered = false;
+}
+
+void tevent_queue_start(struct tevent_queue *queue)
+{
+ if (queue->running) {
+ /* already started */
+ return;
+ }
+
+ queue->running = true;
+
+ if (!queue->list) {
+ return;
+ }
+
+ if (queue->list->triggered) {
+ return;
+ }
+
+ tevent_schedule_immediate(queue->immediate,
+ queue->list->ev,
+ tevent_queue_immediate_trigger,
+ queue);
+}
+
+void tevent_queue_stop(struct tevent_queue *queue)
+{
+ queue->running = false;
+}
+
+size_t tevent_queue_length(struct tevent_queue *queue)
+{
+ return queue->length;
+}
+
+bool tevent_queue_running(struct tevent_queue *queue)
+{
+ return queue->running;
+}
+
+struct tevent_queue_wait_state {
+ uint8_t dummy;
+};
+
+static void tevent_queue_wait_trigger(struct tevent_req *req,
+ void *private_data);
+
+struct tevent_req *tevent_queue_wait_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tevent_queue *queue)
+{
+ struct tevent_req *req;
+ struct tevent_queue_wait_state *state;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tevent_queue_wait_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ok = _tevent_queue_add(queue, ev, req,
+ tevent_queue_wait_trigger,
+ "tevent_queue_wait_trigger",
+ NULL);
+ if (!ok) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tevent_queue_wait_trigger(struct tevent_req *req,
+ void *private_data)
+{
+ tevent_req_done(req);
+}
+
+bool tevent_queue_wait_recv(struct tevent_req *req)
+{
+ enum tevent_req_state state;
+ uint64_t err;
+
+ if (tevent_req_is_error(req, &state, &err)) {
+ tevent_req_received(req);
+ return false;
+ }
+
+ tevent_req_received(req);
+ return true;
+}
+
+void tevent_queue_entry_set_tag(struct tevent_queue_entry *qe, uint64_t tag)
+{
+ if (qe == NULL) {
+ return;
+ }
+
+ qe->tag = tag;
+}
+
+uint64_t tevent_queue_entry_get_tag(const struct tevent_queue_entry *qe)
+{
+ if (qe == NULL) {
+ return 0;
+ }
+
+ return qe->tag;
+}
diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c
new file mode 100644
index 0000000..544f853
--- /dev/null
+++ b/lib/tevent/tevent_req.c
@@ -0,0 +1,642 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+#undef tevent_req_set_callback
+#undef tevent_req_set_cancel_fn
+#undef tevent_req_set_cleanup_fn
+
+char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
+{
+ return talloc_asprintf(mem_ctx,
+ "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
+ " state[%s (%p)] timer[%p] finish[%s]",
+ req, req->internal.create_location,
+ req->internal.state,
+ (unsigned long long)req->internal.error,
+ (unsigned long long)req->internal.error,
+ req->internal.private_type,
+ req->data,
+ req->internal.timer,
+ req->internal.finish_location
+ );
+}
+
+char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
+{
+ if (req == NULL) {
+ return talloc_strdup(mem_ctx, "tevent_req[NULL]");
+ }
+
+ if (!req->private_print) {
+ return tevent_req_default_print(req, mem_ctx);
+ }
+
+ return req->private_print(req, mem_ctx);
+}
+
+static int tevent_req_destructor(struct tevent_req *req);
+
+struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
+ void *pdata,
+ size_t data_size,
+ const char *type,
+ const char *location)
+{
+ return __tevent_req_create(mem_ctx,
+ pdata,
+ data_size,
+ type,
+ NULL,
+ location);
+}
+
+struct tevent_req *__tevent_req_create(TALLOC_CTX *mem_ctx,
+ void *pdata,
+ size_t data_size,
+ const char *type,
+ const char *func,
+ const char *location)
+{
+ struct tevent_req *req;
+ struct tevent_req *parent;
+ void **ppdata = (void **)pdata;
+ void *data;
+ size_t payload;
+
+ payload = sizeof(struct tevent_immediate) + data_size;
+ if (payload < sizeof(struct tevent_immediate)) {
+ /* overflow */
+ return NULL;
+ }
+
+ req = talloc_pooled_object(
+ mem_ctx, struct tevent_req, 2,
+ sizeof(struct tevent_immediate) + data_size);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *req = (struct tevent_req) {
+ .internal = {
+ .private_type = type,
+ .create_location = location,
+ .state = TEVENT_REQ_IN_PROGRESS,
+ .trigger = tevent_create_immediate(req),
+ },
+ };
+
+ data = talloc_zero_size(req, data_size);
+
+ /*
+ * No need to check for req->internal.trigger!=NULL or
+ * data!=NULL, this can't fail: talloc_pooled_object has
+ * already allocated sufficient memory.
+ */
+
+ talloc_set_name_const(data, type);
+
+ req->data = data;
+
+ talloc_set_destructor(req, tevent_req_destructor);
+
+ parent = talloc_get_type(talloc_parent(mem_ctx), struct tevent_req);
+ if ((parent != NULL) && (parent->internal.profile != NULL)) {
+ bool ok = tevent_req_set_profile(req);
+
+ if (!ok) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ req->internal.profile->parent = parent->internal.profile;
+ DLIST_ADD_END(parent->internal.profile->subprofiles,
+ req->internal.profile);
+ }
+
+ *ppdata = data;
+
+ /* Initially, talloc_zero_size() sets internal.call_depth to 0 */
+ if (parent != NULL) {
+ req->internal.call_depth = parent->internal.call_depth + 1;
+ }
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CREATE,
+ req,
+ req->internal.call_depth,
+ func);
+
+ return req;
+}
+
+static int tevent_req_destructor(struct tevent_req *req)
+{
+ tevent_req_received(req);
+ return 0;
+}
+
+void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
+{
+ req->internal.finish_location = location;
+ if (req->internal.defer_callback_ev) {
+ (void)tevent_req_post(req, req->internal.defer_callback_ev);
+ req->internal.defer_callback_ev = NULL;
+ return;
+ }
+ if (req->async.fn != NULL) {
+ /* Calling back the parent code, decrement the call depth. */
+ size_t new_depth = req->internal.call_depth > 0 ?
+ req->internal.call_depth - 1 : 0;
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_NOTIFY_CB,
+ req,
+ new_depth,
+ req->async.fn_name);
+ req->async.fn(req);
+ }
+}
+
+static void tevent_req_cleanup(struct tevent_req *req)
+{
+ if (req->private_cleanup.state >= req->internal.state) {
+ /*
+ * Don't call the cleanup_function multiple times for the same
+ * state recursively
+ */
+ return;
+ }
+
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CLEANUP,
+ req,
+ req->internal.call_depth,
+ req->private_cleanup.fn_name);
+
+ if (req->private_cleanup.fn == NULL) {
+ return;
+ }
+
+ req->private_cleanup.state = req->internal.state;
+ req->private_cleanup.fn(req, req->internal.state);
+}
+
+static void tevent_req_finish(struct tevent_req *req,
+ enum tevent_req_state state,
+ const char *location)
+{
+ struct tevent_req_profile *p;
+ /*
+ * make sure we do not timeout after
+ * the request was already finished
+ */
+ TALLOC_FREE(req->internal.timer);
+
+ req->internal.state = state;
+ req->internal.finish_location = location;
+
+ tevent_req_cleanup(req);
+
+ p = req->internal.profile;
+
+ if (p != NULL) {
+ p->stop_location = location;
+ p->stop_time = tevent_timeval_current();
+ p->state = state;
+ p->user_error = req->internal.error;
+
+ if (p->parent != NULL) {
+ talloc_steal(p->parent, p);
+ req->internal.profile = NULL;
+ }
+ }
+
+ _tevent_req_notify_callback(req, location);
+}
+
+void _tevent_req_done(struct tevent_req *req,
+ const char *location)
+{
+ tevent_req_finish(req, TEVENT_REQ_DONE, location);
+}
+
+bool _tevent_req_error(struct tevent_req *req,
+ uint64_t error,
+ const char *location)
+{
+ if (error == 0) {
+ return false;
+ }
+
+ req->internal.error = error;
+ tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
+ return true;
+}
+
+void _tevent_req_oom(struct tevent_req *req, const char *location)
+{
+ tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
+}
+
+bool _tevent_req_nomem(const void *p,
+ struct tevent_req *req,
+ const char *location)
+{
+ if (p != NULL) {
+ return false;
+ }
+ _tevent_req_oom(req, location);
+ return true;
+}
+
+/**
+ * @internal
+ *
+ * @brief Immediate event callback.
+ *
+ * @param[in] ev The event context to use.
+ *
+ * @param[in] im The immediate event.
+ *
+ * @param[in] priv The async request to be finished.
+ */
+static void tevent_req_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+
+ tevent_req_finish(req, req->internal.state,
+ req->internal.finish_location);
+}
+
+struct tevent_req *tevent_req_post(struct tevent_req *req,
+ struct tevent_context *ev)
+{
+ tevent_schedule_immediate(req->internal.trigger,
+ ev, tevent_req_trigger, req);
+ return req;
+}
+
+void tevent_req_defer_callback(struct tevent_req *req,
+ struct tevent_context *ev)
+{
+ req->internal.defer_callback_ev = ev;
+}
+
+bool tevent_req_is_in_progress(struct tevent_req *req)
+{
+ if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
+ return true;
+ }
+
+ return false;
+}
+
+void tevent_req_received(struct tevent_req *req)
+{
+ talloc_set_destructor(req, NULL);
+
+ req->private_print = NULL;
+ req->private_cancel.fn = NULL;
+ req->private_cancel.fn_name = NULL;
+
+ TALLOC_FREE(req->internal.trigger);
+ TALLOC_FREE(req->internal.timer);
+
+ req->internal.state = TEVENT_REQ_RECEIVED;
+
+ tevent_req_cleanup(req);
+
+ TALLOC_FREE(req->data);
+}
+
+bool tevent_req_poll(struct tevent_req *req,
+ struct tevent_context *ev)
+{
+ while (tevent_req_is_in_progress(req)) {
+ int ret;
+
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
+ uint64_t *error)
+{
+ if (req->internal.state == TEVENT_REQ_DONE) {
+ return false;
+ }
+ if (req->internal.state == TEVENT_REQ_USER_ERROR) {
+ *error = req->internal.error;
+ }
+ *state = req->internal.state;
+ return true;
+}
+
+static void tevent_req_timedout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval now,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+
+ TALLOC_FREE(req->internal.timer);
+
+ tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
+}
+
+bool tevent_req_set_endtime(struct tevent_req *req,
+ struct tevent_context *ev,
+ struct timeval endtime)
+{
+ TALLOC_FREE(req->internal.timer);
+
+ req->internal.timer = tevent_add_timer(ev, req, endtime,
+ tevent_req_timedout,
+ req);
+ if (tevent_req_nomem(req->internal.timer, req)) {
+ return false;
+ }
+
+ return true;
+}
+
+void tevent_req_reset_endtime(struct tevent_req *req)
+{
+ TALLOC_FREE(req->internal.timer);
+}
+
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
+{
+ return _tevent_req_set_callback(req, fn, NULL, pvt);
+}
+
+void _tevent_req_set_callback(struct tevent_req *req,
+ tevent_req_fn fn,
+ const char *fn_name,
+ void *pvt)
+{
+ req->async.fn = fn;
+ req->async.fn_name = fn_name;
+ req->async.private_data = pvt;
+}
+
+void *_tevent_req_callback_data(struct tevent_req *req)
+{
+ return req->async.private_data;
+}
+
+void *_tevent_req_data(struct tevent_req *req)
+{
+ return req->data;
+}
+
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
+{
+ req->private_print = fn;
+}
+
+void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
+{
+ _tevent_req_set_cancel_fn(req, fn, NULL);
+}
+
+void _tevent_req_set_cancel_fn(struct tevent_req *req,
+ tevent_req_cancel_fn fn,
+ const char *fn_name)
+{
+ req->private_cancel.fn = fn;
+ req->private_cancel.fn_name = fn != NULL ? fn_name : NULL;
+}
+
+bool _tevent_req_cancel(struct tevent_req *req, const char *location)
+{
+ tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CANCEL,
+ req,
+ req->internal.call_depth,
+ req->private_cancel.fn_name);
+
+ if (req->private_cancel.fn == NULL) {
+ return false;
+ }
+
+ return req->private_cancel.fn(req);
+}
+
+void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn)
+{
+ _tevent_req_set_cleanup_fn(req, fn, NULL);
+}
+
+void _tevent_req_set_cleanup_fn(struct tevent_req *req,
+ tevent_req_cleanup_fn fn,
+ const char *fn_name)
+{
+ req->private_cleanup.state = req->internal.state;
+ req->private_cleanup.fn = fn;
+ req->private_cleanup.fn_name = fn != NULL ? fn_name : NULL;
+}
+
+static int tevent_req_profile_destructor(struct tevent_req_profile *p);
+
+bool tevent_req_set_profile(struct tevent_req *req)
+{
+ struct tevent_req_profile *p;
+
+ if (req->internal.profile != NULL) {
+ tevent_req_error(req, EINVAL);
+ return false;
+ }
+
+ p = tevent_req_profile_create(req);
+
+ if (tevent_req_nomem(p, req)) {
+ return false;
+ }
+
+ p->req_name = talloc_get_name(req->data);
+ p->start_location = req->internal.create_location;
+ p->start_time = tevent_timeval_current();
+
+ req->internal.profile = p;
+
+ return true;
+}
+
+static int tevent_req_profile_destructor(struct tevent_req_profile *p)
+{
+ if (p->parent != NULL) {
+ DLIST_REMOVE(p->parent->subprofiles, p);
+ p->parent = NULL;
+ }
+
+ while (p->subprofiles != NULL) {
+ p->subprofiles->parent = NULL;
+ DLIST_REMOVE(p->subprofiles, p->subprofiles);
+ }
+
+ return 0;
+}
+
+struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx)
+{
+ return talloc_move(mem_ctx, &req->internal.profile);
+}
+
+const struct tevent_req_profile *tevent_req_get_profile(
+ struct tevent_req *req)
+{
+ return req->internal.profile;
+}
+
+void tevent_req_profile_get_name(const struct tevent_req_profile *profile,
+ const char **req_name)
+{
+ if (req_name != NULL) {
+ *req_name = profile->req_name;
+ }
+}
+
+void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
+ const char **start_location,
+ struct timeval *start_time)
+{
+ if (start_location != NULL) {
+ *start_location = profile->start_location;
+ }
+ if (start_time != NULL) {
+ *start_time = profile->start_time;
+ }
+}
+
+void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
+ const char **stop_location,
+ struct timeval *stop_time)
+{
+ if (stop_location != NULL) {
+ *stop_location = profile->stop_location;
+ }
+ if (stop_time != NULL) {
+ *stop_time = profile->stop_time;
+ }
+}
+
+void tevent_req_profile_get_status(const struct tevent_req_profile *profile,
+ pid_t *pid,
+ enum tevent_req_state *state,
+ uint64_t *user_error)
+{
+ if (pid != NULL) {
+ *pid = profile->pid;
+ }
+ if (state != NULL) {
+ *state = profile->state;
+ }
+ if (user_error != NULL) {
+ *user_error = profile->user_error;
+ }
+}
+
+const struct tevent_req_profile *tevent_req_profile_get_subprofiles(
+ const struct tevent_req_profile *profile)
+{
+ return profile->subprofiles;
+}
+
+const struct tevent_req_profile *tevent_req_profile_next(
+ const struct tevent_req_profile *profile)
+{
+ return profile->next;
+}
+
+struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx)
+{
+ struct tevent_req_profile *result;
+
+ result = talloc_zero(mem_ctx, struct tevent_req_profile);
+ if (result == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(result, tevent_req_profile_destructor);
+
+ return result;
+}
+
+bool tevent_req_profile_set_name(struct tevent_req_profile *profile,
+ const char *req_name)
+{
+ profile->req_name = talloc_strdup(profile, req_name);
+ return (profile->req_name != NULL);
+}
+
+bool tevent_req_profile_set_start(struct tevent_req_profile *profile,
+ const char *start_location,
+ struct timeval start_time)
+{
+ profile->start_time = start_time;
+
+ profile->start_location = talloc_strdup(profile, start_location);
+ return (profile->start_location != NULL);
+}
+
+bool tevent_req_profile_set_stop(struct tevent_req_profile *profile,
+ const char *stop_location,
+ struct timeval stop_time)
+{
+ profile->stop_time = stop_time;
+
+ profile->stop_location = talloc_strdup(profile, stop_location);
+ return (profile->stop_location != NULL);
+}
+
+void tevent_req_profile_set_status(struct tevent_req_profile *profile,
+ pid_t pid,
+ enum tevent_req_state state,
+ uint64_t user_error)
+{
+ profile->pid = pid;
+ profile->state = state;
+ profile->user_error = user_error;
+}
+
+void tevent_req_profile_append_sub(struct tevent_req_profile *parent_profile,
+ struct tevent_req_profile **sub_profile)
+{
+ struct tevent_req_profile *sub;
+
+ sub = talloc_move(parent_profile, sub_profile);
+
+ sub->parent = parent_profile;
+ DLIST_ADD_END(parent_profile->subprofiles, sub);
+}
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
new file mode 100644
index 0000000..eab3654
--- /dev/null
+++ b/lib/tevent/tevent_signal.c
@@ -0,0 +1,539 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for signal events
+
+ Copyright (C) Andrew Tridgell 2007
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+/* maximum number of SA_SIGINFO signals to hold in the queue.
+ NB. This *MUST* be a power of 2, in order for the ring buffer
+ wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
+ for this. */
+
+#define TEVENT_SA_INFO_QUEUE_COUNT 256
+
+size_t tevent_num_signals(void)
+{
+ return TEVENT_NUM_SIGNALS;
+}
+
+size_t tevent_sa_info_queue_count(void)
+{
+ return TEVENT_SA_INFO_QUEUE_COUNT;
+}
+
+struct tevent_sigcounter {
+ uint32_t count;
+ uint32_t seen;
+};
+
+#if defined(HAVE___SYNC_FETCH_AND_ADD)
+#define TEVENT_SIG_INCREMENT(s) __sync_fetch_and_add(&((s).count), 1)
+#elif defined(HAVE_ATOMIC_ADD_32)
+#define TEVENT_SIG_INCREMENT(s) atomic_add_32(&((s).count), 1)
+#else
+#define TEVENT_SIG_INCREMENT(s) (s).count++
+#endif
+#define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
+#define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
+
+struct tevent_common_signal_list {
+ struct tevent_common_signal_list *prev, *next;
+ struct tevent_signal *se;
+};
+
+/*
+ the poor design of signals means that this table must be static global
+*/
+static struct tevent_sig_state {
+ struct tevent_common_signal_list *sig_handlers[TEVENT_NUM_SIGNALS+1];
+ struct sigaction *oldact[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter signal_count[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter got_signal;
+#ifdef SA_SIGINFO
+ /* with SA_SIGINFO we get quite a lot of info per signal */
+ siginfo_t *sig_info[TEVENT_NUM_SIGNALS+1];
+ struct tevent_sigcounter sig_blocked[TEVENT_NUM_SIGNALS+1];
+#endif
+} *sig_state;
+
+/*
+ return number of sigcounter events not processed yet
+*/
+static uint32_t tevent_sig_count(struct tevent_sigcounter s)
+{
+ return s.count - s.seen;
+}
+
+/*
+ signal handler - redirects to registered signals
+*/
+static void tevent_common_signal_handler(int signum)
+{
+ struct tevent_common_signal_list *sl;
+ struct tevent_context *ev = NULL;
+ int saved_errno = errno;
+
+ TEVENT_SIG_INCREMENT(sig_state->signal_count[signum]);
+ TEVENT_SIG_INCREMENT(sig_state->got_signal);
+
+ /* Write to each unique event context. */
+ for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
+ if (sl->se->event_ctx && sl->se->event_ctx != ev) {
+ ev = sl->se->event_ctx;
+ tevent_common_wakeup(ev);
+ }
+ }
+
+ errno = saved_errno;
+}
+
+#ifdef SA_SIGINFO
+/*
+ signal handler with SA_SIGINFO - redirects to registered signals
+*/
+static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
+ void *uctx)
+{
+ uint32_t count = tevent_sig_count(sig_state->signal_count[signum]);
+ /* sig_state->signal_count[signum].seen % TEVENT_SA_INFO_QUEUE_COUNT
+ * is the base of the unprocessed signals in the ringbuffer. */
+ uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
+ TEVENT_SA_INFO_QUEUE_COUNT;
+ sig_state->sig_info[signum][ofs] = *info;
+
+ tevent_common_signal_handler(signum);
+
+ /* handle SA_SIGINFO */
+ if (count+1 == TEVENT_SA_INFO_QUEUE_COUNT) {
+ /* we've filled the info array - block this signal until
+ these ones are delivered */
+#ifdef HAVE_UCONTEXT_T
+ /*
+ * This is the only way for this to work.
+ * By default signum is blocked inside this
+ * signal handler using a temporary mask,
+ * but what we really need to do now is
+ * block it in the callers mask, so it
+ * stays blocked when the temporary signal
+ * handler mask is replaced when we return
+ * from here. The callers mask can be found
+ * in the ucontext_t passed in as the
+ * void *uctx argument.
+ */
+ ucontext_t *ucp = (ucontext_t *)uctx;
+ sigaddset(&ucp->uc_sigmask, signum);
+#else
+ /*
+ * WARNING !!! WARNING !!!!
+ *
+ * This code doesn't work.
+ * By default signum is blocked inside this
+ * signal handler, but calling sigprocmask
+ * modifies the temporary signal mask being
+ * used *inside* this handler, which will be
+ * replaced by the callers signal mask once
+ * we return from here. See Samba
+ * bug #9550 for details.
+ */
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, signum);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+#endif
+ TEVENT_SIG_INCREMENT(sig_state->sig_blocked[signum]);
+ }
+}
+#endif
+
+static int tevent_common_signal_list_destructor(struct tevent_common_signal_list *sl)
+{
+ if (sig_state->sig_handlers[sl->se->signum]) {
+ DLIST_REMOVE(sig_state->sig_handlers[sl->se->signum], sl);
+ }
+ return 0;
+}
+
+/*
+ destroy a signal event
+*/
+static int tevent_signal_destructor(struct tevent_signal *se)
+{
+ if (se->destroyed) {
+ tevent_common_check_double_free(se, "tevent_signal double free");
+ goto done;
+ }
+ se->destroyed = true;
+
+ TALLOC_FREE(se->additional_data);
+
+ if (se->event_ctx != NULL) {
+ tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_DETACH);
+ DLIST_REMOVE(se->event_ctx->signal_events, se);
+ }
+
+ if (sig_state->sig_handlers[se->signum] == NULL) {
+ /* restore old handler, if any */
+ if (sig_state->oldact[se->signum]) {
+ sigaction(se->signum, sig_state->oldact[se->signum], NULL);
+ TALLOC_FREE(sig_state->oldact[se->signum]);
+ }
+#ifdef SA_SIGINFO
+ if (se->sa_flags & SA_SIGINFO) {
+ if (sig_state->sig_info[se->signum]) {
+ TALLOC_FREE(sig_state->sig_info[se->signum]);
+ }
+ }
+#endif
+ }
+
+ se->event_ctx = NULL;
+done:
+ if (se->busy) {
+ return -1;
+ }
+ se->wrapper = NULL;
+
+ return 0;
+}
+
+/*
+ add a signal event
+ return NULL on failure (memory allocation error)
+*/
+struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum,
+ int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_signal *se;
+ struct tevent_common_signal_list *sl;
+ sigset_t set, oldset;
+ int ret;
+
+ ret = tevent_common_wakeup_init(ev);
+ if (ret != 0) {
+ errno = ret;
+ return NULL;
+ }
+
+ if (signum >= TEVENT_NUM_SIGNALS) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* the sig_state needs to be on a global context as it can last across
+ multiple event contexts */
+ if (sig_state == NULL) {
+ sig_state = talloc_zero(NULL, struct tevent_sig_state);
+ if (sig_state == NULL) {
+ return NULL;
+ }
+ }
+
+ se = talloc_zero(mem_ctx?mem_ctx:ev, struct tevent_signal);
+ if (se == NULL) return NULL;
+
+ sl = talloc_zero(se, struct tevent_common_signal_list);
+ if (!sl) {
+ talloc_free(se);
+ return NULL;
+ }
+ sl->se = se;
+
+ *se = (struct tevent_signal) {
+ .event_ctx = ev,
+ .signum = signum,
+ .sa_flags = sa_flags,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .location = location,
+ .additional_data= sl,
+ };
+
+ /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
+ if (!talloc_reference(se, sig_state)) {
+ talloc_free(se);
+ return NULL;
+ }
+
+ /* only install a signal handler if not already installed */
+ if (sig_state->sig_handlers[signum] == NULL) {
+ struct sigaction act;
+ ZERO_STRUCT(act);
+ act.sa_handler = tevent_common_signal_handler;
+ act.sa_flags = sa_flags;
+#ifdef SA_SIGINFO
+ if (sa_flags & SA_SIGINFO) {
+ act.sa_handler = NULL;
+ act.sa_sigaction = tevent_common_signal_handler_info;
+ if (sig_state->sig_info[signum] == NULL) {
+ sig_state->sig_info[signum] =
+ talloc_zero_array(sig_state, siginfo_t,
+ TEVENT_SA_INFO_QUEUE_COUNT);
+ if (sig_state->sig_info[signum] == NULL) {
+ talloc_free(se);
+ return NULL;
+ }
+ }
+ }
+#endif
+ sig_state->oldact[signum] = talloc_zero(sig_state, struct sigaction);
+ if (sig_state->oldact[signum] == NULL) {
+ talloc_free(se);
+ return NULL;
+ }
+ if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
+ talloc_free(sig_state->oldact[signum]);
+ sig_state->oldact[signum] = NULL;
+ talloc_free(se);
+ return NULL;
+ }
+ }
+
+ DLIST_ADD(se->event_ctx->signal_events, se);
+
+ /* Make sure the signal doesn't come in while we're mangling list. */
+ sigemptyset(&set);
+ sigaddset(&set, signum);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+ tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_ATTACH);
+ DLIST_ADD(sig_state->sig_handlers[signum], sl);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+ talloc_set_destructor(se, tevent_signal_destructor);
+ talloc_set_destructor(sl, tevent_common_signal_list_destructor);
+
+ return se;
+}
+
+int tevent_common_invoke_signal_handler(struct tevent_signal *se,
+ int signum, int count, void *siginfo,
+ bool *removed)
+{
+ struct tevent_context *handler_ev = se->event_ctx;
+ bool remove = false;
+
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ if (se->event_ctx == NULL) {
+ return 0;
+ }
+
+ se->busy = true;
+ if (se->wrapper != NULL) {
+ handler_ev = se->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, se->wrapper);
+ se->wrapper->ops->before_signal_handler(
+ se->wrapper->wrap_ev,
+ se->wrapper->private_state,
+ se->wrapper->main_ev,
+ se,
+ signum,
+ count,
+ siginfo,
+ se->handler_name,
+ se->location);
+ }
+ tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
+ se->handler(handler_ev, se, signum, count, siginfo, se->private_data);
+ if (se->wrapper != NULL) {
+ se->wrapper->ops->after_signal_handler(
+ se->wrapper->wrap_ev,
+ se->wrapper->private_state,
+ se->wrapper->main_ev,
+ se,
+ signum,
+ count,
+ siginfo,
+ se->handler_name,
+ se->location);
+ tevent_wrapper_pop_use_internal(handler_ev, se->wrapper);
+ }
+ se->busy = false;
+
+#ifdef SA_RESETHAND
+ if (se->sa_flags & SA_RESETHAND) {
+ remove = true;
+ }
+#endif
+
+ if (se->destroyed) {
+ talloc_set_destructor(se, NULL);
+ remove = true;
+ }
+
+ if (remove) {
+ TALLOC_FREE(se);
+ if (removed != NULL) {
+ *removed = true;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ check if a signal is pending
+ return != 0 if a signal was pending
+*/
+int tevent_common_check_signal(struct tevent_context *ev)
+{
+ int i;
+
+ if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
+ return 0;
+ }
+
+ for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
+ struct tevent_common_signal_list *sl, *next;
+ struct tevent_sigcounter counter = sig_state->signal_count[i];
+ uint32_t count = tevent_sig_count(counter);
+ int ret;
+#ifdef SA_SIGINFO
+ /* Ensure we null out any stored siginfo_t entries
+ * after processing for debugging purposes. */
+ bool clear_processed_siginfo = false;
+#endif
+
+ if (count == 0) {
+ continue;
+ }
+ for (sl=sig_state->sig_handlers[i];sl;sl=next) {
+ struct tevent_signal *se = sl->se;
+
+ next = sl->next;
+
+#ifdef SA_SIGINFO
+ if (se->sa_flags & SA_SIGINFO) {
+ uint32_t j;
+
+ clear_processed_siginfo = true;
+
+ for (j=0;j<count;j++) {
+ /* sig_state->signal_count[i].seen
+ * % TEVENT_SA_INFO_QUEUE_COUNT is
+ * the base position of the unprocessed
+ * signals in the ringbuffer. */
+ uint32_t ofs = (counter.seen + j)
+ % TEVENT_SA_INFO_QUEUE_COUNT;
+ bool removed = false;
+
+ ret = tevent_common_invoke_signal_handler(
+ se, i, 1,
+ (void*)&sig_state->sig_info[i][ofs],
+ &removed);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
+ }
+ if (removed) {
+ break;
+ }
+ }
+ continue;
+ }
+#endif
+
+ ret = tevent_common_invoke_signal_handler(se, i, count,
+ NULL, NULL);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
+ }
+ }
+
+#ifdef SA_SIGINFO
+ if (clear_processed_siginfo && sig_state->sig_info[i] != NULL) {
+ uint32_t j;
+ for (j=0;j<count;j++) {
+ uint32_t ofs = (counter.seen + j)
+ % TEVENT_SA_INFO_QUEUE_COUNT;
+ memset((void*)&sig_state->sig_info[i][ofs],
+ '\0',
+ sizeof(siginfo_t));
+ }
+ }
+#endif
+
+ TEVENT_SIG_SEEN(sig_state->signal_count[i], count);
+ TEVENT_SIG_SEEN(sig_state->got_signal, count);
+
+#ifdef SA_SIGINFO
+ if (TEVENT_SIG_PENDING(sig_state->sig_blocked[i])) {
+ /* We'd filled the queue, unblock the
+ signal now the queue is empty again.
+ Note we MUST do this after the
+ TEVENT_SIG_SEEN(sig_state->signal_count[i], count)
+ call to prevent a new signal running
+ out of room in the sig_state->sig_info[i][]
+ ring buffer. */
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, i);
+ TEVENT_SIG_SEEN(sig_state->sig_blocked[i],
+ tevent_sig_count(sig_state->sig_blocked[i]));
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+ }
+#endif
+ }
+
+ return 1;
+}
+
+void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
+{
+ tevent_signal_destructor(se);
+ talloc_set_destructor(se, NULL);
+ return;
+}
+
+void tevent_signal_set_tag(struct tevent_signal *se, uint64_t tag)
+{
+ if (se == NULL) {
+ return;
+ }
+
+ se->tag = tag;
+}
+
+uint64_t tevent_signal_get_tag(const struct tevent_signal *se)
+{
+ if (se == NULL) {
+ return 0;
+ }
+
+ return se->tag;
+}
diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c
new file mode 100644
index 0000000..749cad0
--- /dev/null
+++ b/lib/tevent/tevent_standard.c
@@ -0,0 +1,238 @@
+/*
+ Unix SMB/CIFS implementation.
+ main select loop and event handling
+ Copyright (C) Stefan Metzmacher 2013
+ Copyright (C) Jeremy Allison 2013
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This is SAMBA's default event loop code
+
+ - we try to use epoll if configure detected support for it
+ otherwise we use poll()
+ - if epoll is broken on the system or the kernel doesn't support it
+ at runtime we fallback to poll()
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_util.h"
+#include "tevent_internal.h"
+
+struct std_event_glue {
+ const struct tevent_ops *epoll_ops;
+ const struct tevent_ops *poll_ops;
+ struct tevent_ops *glue_ops;
+ bool fallback_replay;
+};
+
+static int std_event_context_init(struct tevent_context *ev);
+
+static const struct tevent_ops std_event_ops = {
+ .context_init = std_event_context_init,
+};
+
+/*
+ If this function gets called. epoll failed at runtime.
+ Move us to using poll instead. If we return false here,
+ caller should abort().
+*/
+#ifdef HAVE_EPOLL
+static bool std_fallback_to_poll(struct tevent_context *ev, bool replay)
+{
+ void *glue_ptr = talloc_parent(ev->ops);
+ struct std_event_glue *glue =
+ talloc_get_type_abort(glue_ptr,
+ struct std_event_glue);
+ int ret;
+ struct tevent_fd *fde;
+
+ glue->fallback_replay = replay;
+
+ /* First switch all the ops to poll. */
+ glue->epoll_ops = NULL;
+
+ /*
+ * Set custom_ops the same as poll.
+ */
+ *glue->glue_ops = *glue->poll_ops;
+ glue->glue_ops->context_init = std_event_context_init;
+
+ /* Next initialize the poll backend. */
+ ret = glue->poll_ops->context_init(ev);
+ if (ret != 0) {
+ return false;
+ }
+
+ /*
+ * Now we have to change all the existing file descriptor
+ * events from the epoll backend to the poll backend.
+ */
+ for (fde = ev->fd_events; fde; fde = fde->next) {
+ bool ok;
+
+ /* Re-add this event as a poll backend event. */
+ ok = tevent_poll_event_add_fd_internal(ev, fde);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif
+
+static int std_event_loop_once(struct tevent_context *ev, const char *location)
+{
+ void *glue_ptr = talloc_parent(ev->ops);
+ struct std_event_glue *glue =
+ talloc_get_type_abort(glue_ptr,
+ struct std_event_glue);
+ int ret;
+
+ ret = glue->epoll_ops->loop_once(ev, location);
+ /*
+ * If the above hasn't panicked due to an epoll interface failure,
+ * std_fallback_to_poll() wasn't called, and hasn't cleared epoll_ops to
+ * signify fallback to poll_ops.
+ */
+ if (glue->epoll_ops != NULL) {
+ /* No fallback */
+ return ret;
+ }
+
+ if (!glue->fallback_replay) {
+ /*
+ * The problem happened while modifying an event.
+ * An event handler was triggered in this case
+ * and there is no need to call loop_once() again.
+ */
+ return ret;
+ }
+
+ return glue->poll_ops->loop_once(ev, location);
+}
+
+static int std_event_loop_wait(struct tevent_context *ev, const char *location)
+{
+ void *glue_ptr = talloc_parent(ev->ops);
+ struct std_event_glue *glue =
+ talloc_get_type_abort(glue_ptr,
+ struct std_event_glue);
+ int ret;
+
+ ret = glue->epoll_ops->loop_wait(ev, location);
+ /*
+ * If the above hasn't panicked due to an epoll interface failure,
+ * std_fallback_to_poll() wasn't called, and hasn't cleared epoll_ops to
+ * signify fallback to poll_ops.
+ */
+ if (glue->epoll_ops != NULL) {
+ /* No fallback */
+ return ret;
+ }
+
+ return glue->poll_ops->loop_wait(ev, location);
+}
+/*
+ Initialize the epoll backend and allow it to call a
+ switch function if epoll fails at runtime.
+*/
+static int std_event_context_init(struct tevent_context *ev)
+{
+ struct std_event_glue *glue;
+ int ret;
+
+ /*
+ * If this is the first initialization
+ * we need to set up the allocated ops
+ * pointers.
+ */
+
+ if (ev->ops->loop_once == NULL) {
+ glue = talloc_zero(ev, struct std_event_glue);
+ if (glue == NULL) {
+ return -1;
+ }
+
+ glue->epoll_ops = tevent_find_ops_byname("epoll");
+
+ glue->poll_ops = tevent_find_ops_byname("poll");
+ if (glue->poll_ops == NULL) {
+ return -1;
+ }
+
+ /*
+ * Allocate space for our custom ops.
+ * Allocate as a child of our epoll_ops pointer
+ * so we can easily get to it using talloc_parent.
+ */
+ glue->glue_ops = talloc_zero(glue, struct tevent_ops);
+ if (glue->glue_ops == NULL) {
+ talloc_free(glue);
+ return -1;
+ }
+
+ ev->ops = glue->glue_ops;
+ } else {
+ void *glue_ptr = talloc_parent(ev->ops);
+ glue = talloc_get_type_abort(glue_ptr, struct std_event_glue);
+ }
+
+ if (glue->epoll_ops != NULL) {
+ /*
+ * Set custom_ops the same as epoll,
+ * except re-init using std_event_context_init()
+ * and use std_event_loop_once() to add the
+ * ability to fallback to a poll backend on
+ * epoll runtime error.
+ */
+ *glue->glue_ops = *glue->epoll_ops;
+ glue->glue_ops->context_init = std_event_context_init;
+ glue->glue_ops->loop_once = std_event_loop_once;
+ glue->glue_ops->loop_wait = std_event_loop_wait;
+
+ ret = glue->epoll_ops->context_init(ev);
+ if (ret == -1) {
+ goto fallback;
+ }
+#ifdef HAVE_EPOLL
+ tevent_epoll_set_panic_fallback(ev, std_fallback_to_poll);
+#endif
+
+ return ret;
+ }
+
+fallback:
+ glue->epoll_ops = NULL;
+
+ /*
+ * Set custom_ops the same as poll.
+ */
+ *glue->glue_ops = *glue->poll_ops;
+ glue->glue_ops->context_init = std_event_context_init;
+
+ return glue->poll_ops->context_init(ev);
+}
+
+_PRIVATE_ bool tevent_standard_init(void)
+{
+ return tevent_register_backend("standard", &std_event_ops);
+}
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
new file mode 100644
index 0000000..2dc1f17
--- /dev/null
+++ b/lib/tevent/tevent_threads.c
@@ -0,0 +1,601 @@
+/*
+ tevent event library.
+
+ Copyright (C) Jeremy Allison 2015
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "talloc.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+
+struct tevent_immediate_list {
+ struct tevent_immediate_list *next, *prev;
+ tevent_immediate_handler_t handler;
+ struct tevent_immediate *im;
+ void *private_ptr;
+};
+
+struct tevent_thread_proxy {
+ pthread_mutex_t mutex;
+ struct tevent_context *dest_ev_ctx;
+ int read_fd;
+ int write_fd;
+ struct tevent_fd *pipe_read_fde;
+ /* Pending events list. */
+ struct tevent_immediate_list *im_list;
+ /* Completed events list. */
+ struct tevent_immediate_list *tofree_im_list;
+ struct tevent_immediate *free_im;
+};
+
+static void free_im_list(struct tevent_immediate_list **pp_list_head)
+{
+ struct tevent_immediate_list *im_entry = NULL;
+ struct tevent_immediate_list *im_next = NULL;
+
+ for (im_entry = *pp_list_head; im_entry; im_entry = im_next) {
+ im_next = im_entry->next;
+ DLIST_REMOVE(*pp_list_head, im_entry);
+ TALLOC_FREE(im_entry);
+ }
+}
+
+static void free_list_handler(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_ptr)
+{
+ struct tevent_thread_proxy *tp =
+ talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+ int ret;
+
+ ret = pthread_mutex_lock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return;
+ }
+
+ free_im_list(&tp->tofree_im_list);
+
+ ret = pthread_mutex_unlock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return;
+ }
+}
+
+static void schedule_immediate_functions(struct tevent_thread_proxy *tp)
+{
+ struct tevent_immediate_list *im_entry = NULL;
+ struct tevent_immediate_list *im_next = NULL;
+
+ for (im_entry = tp->im_list; im_entry; im_entry = im_next) {
+ im_next = im_entry->next;
+ DLIST_REMOVE(tp->im_list, im_entry);
+
+ tevent_schedule_immediate(im_entry->im,
+ tp->dest_ev_ctx,
+ im_entry->handler,
+ im_entry->private_ptr);
+
+ /* Move from pending list to free list. */
+ DLIST_ADD(tp->tofree_im_list, im_entry);
+ }
+ if (tp->tofree_im_list != NULL) {
+ /*
+ * Once the current immediate events
+ * are processed, we need to reschedule
+ * ourselves to free them. This works
+ * as tevent_schedule_immediate()
+ * always adds events to the *END* of
+ * the immediate events list.
+ */
+ tevent_schedule_immediate(tp->free_im,
+ tp->dest_ev_ctx,
+ free_list_handler,
+ tp);
+ }
+}
+
+static void pipe_read_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_ptr)
+{
+ struct tevent_thread_proxy *tp =
+ talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+ ssize_t len = 64;
+ int ret;
+
+ ret = pthread_mutex_lock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return;
+ }
+
+ /*
+ * Clear out all data in the pipe. We
+ * don't really care if this returns -1.
+ */
+ while (len == 64) {
+ char buf[64];
+ len = read(tp->read_fd, buf, 64);
+ };
+
+ schedule_immediate_functions(tp);
+
+ ret = pthread_mutex_unlock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return;
+ }
+}
+
+static int tevent_thread_proxy_destructor(struct tevent_thread_proxy *tp)
+{
+ int ret;
+
+ ret = pthread_mutex_lock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return 0;
+ }
+
+ TALLOC_FREE(tp->pipe_read_fde);
+
+ if (tp->read_fd != -1) {
+ (void)close(tp->read_fd);
+ tp->read_fd = -1;
+ }
+ if (tp->write_fd != -1) {
+ (void)close(tp->write_fd);
+ tp->write_fd = -1;
+ }
+
+ /* Hmmm. It's probably an error if we get here with
+ any non-NULL immediate entries.. */
+
+ free_im_list(&tp->im_list);
+ free_im_list(&tp->tofree_im_list);
+
+ TALLOC_FREE(tp->free_im);
+
+ ret = pthread_mutex_unlock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return 0;
+ }
+
+ ret = pthread_mutex_destroy(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Create a struct that can be passed to other threads
+ * to allow them to signal the struct tevent_context *
+ * passed in.
+ */
+
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+ struct tevent_context *dest_ev_ctx)
+{
+ int ret;
+ int pipefds[2];
+ struct tevent_thread_proxy *tp;
+
+ if (dest_ev_ctx->wrapper.glue != NULL) {
+ /*
+ * stacking of wrappers is not supported
+ */
+ tevent_debug(dest_ev_ctx->wrapper.glue->main_ev,
+ TEVENT_DEBUG_FATAL,
+ "%s() not allowed on a wrapper context\n",
+ __func__);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ tp = talloc_zero(dest_ev_ctx, struct tevent_thread_proxy);
+ if (tp == NULL) {
+ return NULL;
+ }
+
+ ret = pthread_mutex_init(&tp->mutex, NULL);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ tp->dest_ev_ctx = dest_ev_ctx;
+ tp->read_fd = -1;
+ tp->write_fd = -1;
+
+ talloc_set_destructor(tp, tevent_thread_proxy_destructor);
+
+ ret = pipe(pipefds);
+ if (ret == -1) {
+ goto fail;
+ }
+
+ tp->read_fd = pipefds[0];
+ tp->write_fd = pipefds[1];
+
+ ret = ev_set_blocking(pipefds[0], false);
+ if (ret != 0) {
+ goto fail;
+ }
+ ret = ev_set_blocking(pipefds[1], false);
+ if (ret != 0) {
+ goto fail;
+ }
+ if (!ev_set_close_on_exec(pipefds[0])) {
+ goto fail;
+ }
+ if (!ev_set_close_on_exec(pipefds[1])) {
+ goto fail;
+ }
+
+ tp->pipe_read_fde = tevent_add_fd(dest_ev_ctx,
+ tp,
+ tp->read_fd,
+ TEVENT_FD_READ,
+ pipe_read_handler,
+ tp);
+ if (tp->pipe_read_fde == NULL) {
+ goto fail;
+ }
+
+ /*
+ * Create an immediate event to free
+ * completed lists.
+ */
+ tp->free_im = tevent_create_immediate(tp);
+ if (tp->free_im == NULL) {
+ goto fail;
+ }
+
+ return tp;
+
+ fail:
+
+ TALLOC_FREE(tp);
+ return NULL;
+}
+
+/*
+ * This function schedules an immediate event to be called with argument
+ * *pp_private in the thread context of dest_ev_ctx. Caller doesn't
+ * wait for activation to take place, this is simply fire-and-forget.
+ *
+ * pp_im must be a pointer to an immediate event talloced on
+ * a context owned by the calling thread, or the NULL context.
+ * Ownership of *pp_im will be transferred to the tevent library.
+ *
+ * pp_private can be null, or contents of *pp_private must be
+ * talloc'ed memory on a context owned by the calling thread
+ * or the NULL context. If non-null, ownership of *pp_private will
+ * be transferred to the tevent library.
+ *
+ * If you want to return a message, have the destination use the
+ * same function call to send back to the caller.
+ */
+
+
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+ struct tevent_immediate **pp_im,
+ tevent_immediate_handler_t handler,
+ void *pp_private_data)
+{
+ struct tevent_immediate_list *im_entry;
+ int ret;
+ char c;
+ ssize_t written;
+
+ ret = pthread_mutex_lock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ return;
+ }
+
+ if (tp->write_fd == -1) {
+ /* In the process of being destroyed. Ignore. */
+ goto end;
+ }
+
+ /* Create a new immediate_list entry. MUST BE ON THE NULL CONTEXT */
+ im_entry = talloc_zero(NULL, struct tevent_immediate_list);
+ if (im_entry == NULL) {
+ goto end;
+ }
+
+ im_entry->handler = handler;
+ im_entry->im = talloc_move(im_entry, pp_im);
+
+ if (pp_private_data != NULL) {
+ void **pptr = (void **)pp_private_data;
+ im_entry->private_ptr = talloc_move(im_entry, pptr);
+ }
+
+ DLIST_ADD(tp->im_list, im_entry);
+
+ /* And notify the dest_ev_ctx to wake up. */
+ c = '\0';
+ do {
+ written = write(tp->write_fd, &c, 1);
+ } while (written == -1 && errno == EINTR);
+
+ end:
+
+ ret = pthread_mutex_unlock(&tp->mutex);
+ if (ret != 0) {
+ abort();
+ /* Notreached. */
+ }
+}
+#else
+/* !HAVE_PTHREAD */
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+ struct tevent_context *dest_ev_ctx)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+ struct tevent_immediate **pp_im,
+ tevent_immediate_handler_t handler,
+ void *pp_private_data)
+{
+ ;
+}
+#endif
+
+static int tevent_threaded_context_destructor(
+ struct tevent_threaded_context *tctx)
+{
+ struct tevent_context *main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
+ int ret;
+
+ if (main_ev != NULL) {
+ DLIST_REMOVE(main_ev->threaded_contexts, tctx);
+ }
+
+ /*
+ * We have to coordinate with _tevent_threaded_schedule_immediate's
+ * unlock of the event_ctx_mutex. We're in the main thread here,
+ * and we can be scheduled before the helper thread finalizes its
+ * call _tevent_threaded_schedule_immediate. This means we would
+ * pthreadpool_destroy a locked mutex, which is illegal.
+ */
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ ret = pthread_mutex_destroy(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ return 0;
+}
+
+struct tevent_threaded_context *tevent_threaded_context_create(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev)
+{
+#ifdef HAVE_PTHREAD
+ struct tevent_context *main_ev = tevent_wrapper_main_ev(ev);
+ struct tevent_threaded_context *tctx;
+ int ret;
+
+ ret = tevent_common_wakeup_init(main_ev);
+ if (ret != 0) {
+ errno = ret;
+ return NULL;
+ }
+
+ tctx = talloc(mem_ctx, struct tevent_threaded_context);
+ if (tctx == NULL) {
+ return NULL;
+ }
+ tctx->event_ctx = ev;
+
+ ret = pthread_mutex_init(&tctx->event_ctx_mutex, NULL);
+ if (ret != 0) {
+ TALLOC_FREE(tctx);
+ return NULL;
+ }
+
+ DLIST_ADD(main_ev->threaded_contexts, tctx);
+ talloc_set_destructor(tctx, tevent_threaded_context_destructor);
+
+ return tctx;
+#else
+ errno = ENOSYS;
+ return NULL;
+#endif
+}
+
+static int tevent_threaded_schedule_immediate_destructor(struct tevent_immediate *im)
+{
+ if (im->event_ctx != NULL) {
+ abort();
+ }
+ return 0;
+}
+
+void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
+ struct tevent_immediate *im,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+#ifdef HAVE_PTHREAD
+ const char *create_location = im->create_location;
+ struct tevent_context *main_ev = NULL;
+ struct tevent_wrapper_glue *glue = NULL;
+ int ret, wakeup_fd;
+
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ if (tctx->event_ctx == NULL) {
+ /*
+ * Our event context is already gone.
+ */
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+ return;
+ }
+
+ glue = tctx->event_ctx->wrapper.glue;
+
+ if ((im->event_ctx != NULL) || (handler == NULL)) {
+ abort();
+ }
+ if (im->destroyed) {
+ abort();
+ }
+ if (im->busy) {
+ abort();
+ }
+
+ main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
+
+ *im = (struct tevent_immediate) {
+ .event_ctx = tctx->event_ctx,
+ .wrapper = glue,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .create_location = create_location,
+ .schedule_location = location,
+ };
+
+ /*
+ * Make sure the event won't be destroyed while
+ * it's part of the ev->scheduled_immediates list.
+ * _tevent_schedule_immediate() will reset the destructor
+ * in tevent_common_threaded_activate_immediate().
+ */
+ talloc_set_destructor(im, tevent_threaded_schedule_immediate_destructor);
+
+ ret = pthread_mutex_lock(&main_ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ DLIST_ADD_END(main_ev->scheduled_immediates, im);
+ wakeup_fd = main_ev->wakeup_fd;
+
+ ret = pthread_mutex_unlock(&main_ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ /*
+ * We might want to wake up the main thread under the lock. We
+ * had a slightly similar situation in pthreadpool, changed
+ * with 1c4284c7395f23. This is not exactly the same, as the
+ * wakeup is only a last-resort thing in case the main thread
+ * is sleeping. Doing the wakeup under the lock can easily
+ * lead to a contended mutex, which is much more expensive
+ * than a noncontended one. So I'd opt for the lower footprint
+ * initially. Maybe we have to change that later.
+ */
+ tevent_common_wakeup_fd(wakeup_fd);
+#else
+ /*
+ * tevent_threaded_context_create() returned NULL with ENOSYS...
+ */
+ abort();
+#endif
+}
+
+void tevent_common_threaded_activate_immediate(struct tevent_context *ev)
+{
+#ifdef HAVE_PTHREAD
+ int ret;
+ ret = pthread_mutex_lock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ while (ev->scheduled_immediates != NULL) {
+ struct tevent_immediate *im = ev->scheduled_immediates;
+ struct tevent_immediate copy = *im;
+
+ DLIST_REMOVE(ev->scheduled_immediates, im);
+
+ TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
+ "Schedule immediate event \"%s\": %p from thread into main\n",
+ im->handler_name, im);
+ im->handler_name = NULL;
+ _tevent_schedule_immediate(im,
+ ev,
+ copy.handler,
+ copy.private_data,
+ copy.handler_name,
+ copy.schedule_location);
+ }
+
+ ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+ if (ret != 0) {
+ abort();
+ }
+#else
+ /*
+ * tevent_threaded_context_create() returned NULL with ENOSYS...
+ */
+ abort();
+#endif
+}
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
new file mode 100644
index 0000000..b4a2498
--- /dev/null
+++ b/lib/tevent/tevent_timed.c
@@ -0,0 +1,477 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for timed events
+
+ Copyright (C) Andrew Tridgell 2003-2006
+ Copyright (C) Stefan Metzmacher 2005-2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+/**
+ compare two timeval structures.
+ Return -1 if tv1 < tv2
+ Return 0 if tv1 == tv2
+ Return 1 if tv1 > tv2
+*/
+int tevent_timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return 1;
+ if (tv1->tv_sec < tv2->tv_sec) return -1;
+ if (tv1->tv_usec > tv2->tv_usec) return 1;
+ if (tv1->tv_usec < tv2->tv_usec) return -1;
+ return 0;
+}
+
+/**
+ return a zero timeval
+*/
+struct timeval tevent_timeval_zero(void)
+{
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return tv;
+}
+
+/**
+ return a timeval for the current time
+*/
+struct timeval tevent_timeval_current(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv;
+}
+
+/**
+ return a timeval struct with the given elements
+*/
+struct timeval tevent_timeval_set(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv;
+ tv.tv_sec = secs;
+ tv.tv_usec = usecs;
+ return tv;
+}
+
+/**
+ return the difference between two timevals as a timeval
+ if tv1 comes after tv2, then return a zero timeval
+ (this is *tv2 - *tv1)
+*/
+struct timeval tevent_timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ struct timeval t;
+ if (tevent_timeval_compare(tv1, tv2) >= 0) {
+ return tevent_timeval_zero();
+ }
+ t.tv_sec = tv2->tv_sec - tv1->tv_sec;
+ if (tv1->tv_usec > tv2->tv_usec) {
+ t.tv_sec--;
+ t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
+ } else {
+ t.tv_usec = tv2->tv_usec - tv1->tv_usec;
+ }
+ return t;
+}
+
+/**
+ return true if a timeval is zero
+*/
+bool tevent_timeval_is_zero(const struct timeval *tv)
+{
+ return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+struct timeval tevent_timeval_add(const struct timeval *tv, uint32_t secs,
+ uint32_t usecs)
+{
+ struct timeval tv2 = *tv;
+ tv2.tv_sec += secs;
+ tv2.tv_usec += usecs;
+ tv2.tv_sec += tv2.tv_usec / 1000000;
+ tv2.tv_usec = tv2.tv_usec % 1000000;
+
+ return tv2;
+}
+
+/**
+ return a timeval in the future with a specified offset
+*/
+struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv = tevent_timeval_current();
+ return tevent_timeval_add(&tv, secs, usecs);
+}
+
+/*
+ destroy a timed event
+*/
+static int tevent_common_timed_destructor(struct tevent_timer *te)
+{
+ if (te->destroyed) {
+ tevent_common_check_double_free(te, "tevent_timer double free");
+ goto done;
+ }
+ te->destroyed = true;
+
+ if (te->event_ctx == NULL) {
+ return 0;
+ }
+
+ TEVENT_DEBUG(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Destroying timer event %p \"%s\"\n",
+ te, te->handler_name);
+
+ if (te->event_ctx->last_zero_timer == te) {
+ te->event_ctx->last_zero_timer = DLIST_PREV(te);
+ }
+
+ tevent_trace_timer_callback(te->event_ctx, te, TEVENT_EVENT_TRACE_DETACH);
+ DLIST_REMOVE(te->event_ctx->timer_events, te);
+
+ te->event_ctx = NULL;
+done:
+ if (te->busy) {
+ return -1;
+ }
+ te->wrapper = NULL;
+
+ return 0;
+}
+
+static void tevent_common_insert_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ bool optimize_zero)
+{
+ struct tevent_timer *prev_te = NULL;
+
+ if (te->destroyed) {
+ tevent_abort(ev, "tevent_timer use after free");
+ return;
+ }
+
+ /* keep the list ordered */
+ if (optimize_zero && tevent_timeval_is_zero(&te->next_event)) {
+ /*
+ * Some callers use zero tevent_timer
+ * instead of tevent_immediate events.
+ *
+ * As these can happen very often,
+ * we remember the last zero timer
+ * in the list.
+ */
+ prev_te = ev->last_zero_timer;
+ ev->last_zero_timer = te;
+ } else {
+ struct tevent_timer *cur_te;
+
+ /*
+ * we traverse the list from the tail
+ * because it's much more likely that
+ * timers are added at the end of the list
+ */
+ for (cur_te = DLIST_TAIL(ev->timer_events);
+ cur_te != NULL;
+ cur_te = DLIST_PREV(cur_te))
+ {
+ int ret;
+
+ /*
+ * if the new event comes before the current
+ * we continue searching
+ */
+ ret = tevent_timeval_compare(&te->next_event,
+ &cur_te->next_event);
+ if (ret < 0) {
+ continue;
+ }
+
+ break;
+ }
+
+ prev_te = cur_te;
+ }
+
+ tevent_trace_timer_callback(te->event_ctx, te, TEVENT_EVENT_TRACE_ATTACH);
+ DLIST_ADD_AFTER(ev->timer_events, te, prev_te);
+}
+
+/*
+ add a timed event
+ return NULL on failure (memory allocation error)
+*/
+static struct tevent_timer *tevent_common_add_timer_internal(
+ struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location,
+ bool optimize_zero)
+{
+ struct tevent_timer *te;
+
+ te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
+ if (te == NULL) return NULL;
+
+ *te = (struct tevent_timer) {
+ .event_ctx = ev,
+ .next_event = next_event,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .location = location,
+ };
+
+ if (ev->timer_events == NULL) {
+ ev->last_zero_timer = NULL;
+ }
+
+ tevent_common_insert_timer(ev, te, optimize_zero);
+
+ talloc_set_destructor(te, tevent_common_timed_destructor);
+
+
+ TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
+ "Added timed event \"%s\": %p\n",
+ handler_name, te);
+ return te;
+}
+
+struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /*
+ * do not use optimization, there are broken Samba
+ * versions which use tevent_common_add_timer()
+ * without using tevent_common_loop_timer_delay(),
+ * it just uses DLIST_REMOVE(ev->timer_events, te)
+ * and would leave ev->last_zero_timer behind.
+ */
+ return tevent_common_add_timer_internal(ev, mem_ctx, next_event,
+ handler, private_data,
+ handler_name, location,
+ false);
+}
+
+struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /*
+ * Here we turn on last_zero_timer optimization
+ */
+ return tevent_common_add_timer_internal(ev, mem_ctx, next_event,
+ handler, private_data,
+ handler_name, location,
+ true);
+}
+
+void tevent_update_timer(struct tevent_timer *te, struct timeval next_event)
+{
+ struct tevent_context *ev = te->event_ctx;
+
+ if (ev->last_zero_timer == te) {
+ te->event_ctx->last_zero_timer = DLIST_PREV(te);
+ }
+ tevent_trace_timer_callback(te->event_ctx, te, TEVENT_EVENT_TRACE_DETACH);
+ DLIST_REMOVE(ev->timer_events, te);
+
+ te->next_event = next_event;
+
+ /*
+ * Not doing the zero_timer optimization. This is for new code
+ * that should know about immediates.
+ */
+ tevent_common_insert_timer(ev, te, false);
+}
+
+int tevent_common_invoke_timer_handler(struct tevent_timer *te,
+ struct timeval current_time,
+ bool *removed)
+{
+ struct tevent_context *handler_ev = te->event_ctx;
+
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ if (te->event_ctx == NULL) {
+ return 0;
+ }
+
+ /*
+ * We need to remove the timer from the list before calling the
+ * handler because in a semi-async inner event loop called from the
+ * handler we don't want to come across this event again -- vl
+ */
+ if (te->event_ctx->last_zero_timer == te) {
+ te->event_ctx->last_zero_timer = DLIST_PREV(te);
+ }
+ DLIST_REMOVE(te->event_ctx->timer_events, te);
+
+ TEVENT_DEBUG(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Running timer event %p \"%s\"\n",
+ te, te->handler_name);
+
+ /*
+ * If the timed event was registered for a zero current_time,
+ * then we pass a zero timeval here too! To avoid the
+ * overhead of gettimeofday() calls.
+ *
+ * otherwise we pass the current time
+ */
+ te->busy = true;
+ if (te->wrapper != NULL) {
+ handler_ev = te->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, te->wrapper);
+ te->wrapper->ops->before_timer_handler(
+ te->wrapper->wrap_ev,
+ te->wrapper->private_state,
+ te->wrapper->main_ev,
+ te,
+ te->next_event,
+ current_time,
+ te->handler_name,
+ te->location);
+ }
+ tevent_trace_timer_callback(te->event_ctx, te, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
+ te->handler(handler_ev, te, current_time, te->private_data);
+ if (te->wrapper != NULL) {
+ te->wrapper->ops->after_timer_handler(
+ te->wrapper->wrap_ev,
+ te->wrapper->private_state,
+ te->wrapper->main_ev,
+ te,
+ te->next_event,
+ current_time,
+ te->handler_name,
+ te->location);
+ tevent_wrapper_pop_use_internal(handler_ev, te->wrapper);
+ }
+ te->busy = false;
+
+ TEVENT_DEBUG(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Ending timer event %p \"%s\"\n",
+ te, te->handler_name);
+
+ /* The callback was already called when freed from the handler. */
+ if (!te->destroyed) {
+ tevent_trace_timer_callback(te->event_ctx, te, TEVENT_EVENT_TRACE_DETACH);
+ }
+
+ te->wrapper = NULL;
+ te->event_ctx = NULL;
+ talloc_set_destructor(te, NULL);
+ TALLOC_FREE(te);
+
+ if (removed != NULL) {
+ *removed = true;
+ }
+
+ return 0;
+}
+/*
+ do a single event loop using the events defined in ev
+
+ return the delay until the next timed event,
+ or zero if a timed event was triggered
+*/
+struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
+{
+ struct timeval current_time = tevent_timeval_zero();
+ struct tevent_timer *te = ev->timer_events;
+ int ret;
+
+ if (!te) {
+ /* have a default tick time of 30 seconds. This guarantees
+ that code that uses its own timeout checking will be
+ able to proceed eventually */
+ return tevent_timeval_set(30, 0);
+ }
+
+ /*
+ * work out the right timeout for the next timed event
+ *
+ * avoid the syscall to gettimeofday() if the timed event should
+ * be triggered directly
+ *
+ * if there's a delay till the next timed event, we're done
+ * with just returning the delay
+ */
+ if (!tevent_timeval_is_zero(&te->next_event)) {
+ struct timeval delay;
+
+ current_time = tevent_timeval_current();
+
+ delay = tevent_timeval_until(&current_time, &te->next_event);
+ if (!tevent_timeval_is_zero(&delay)) {
+ return delay;
+ }
+ }
+
+ /*
+ * ok, we have a timed event that we'll process ...
+ */
+ ret = tevent_common_invoke_timer_handler(te, current_time, NULL);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_timer_handler() failed");
+ }
+
+ return tevent_timeval_zero();
+}
+
+void tevent_timer_set_tag(struct tevent_timer *te, uint64_t tag)
+{
+ if (te == NULL) {
+ return;
+ }
+
+ te->tag = tag;
+}
+
+uint64_t tevent_timer_get_tag(const struct tevent_timer *te)
+{
+ if (te == NULL) {
+ return 0;
+ }
+
+ return te->tag;
+}
diff --git a/lib/tevent/tevent_util.c b/lib/tevent/tevent_util.c
new file mode 100644
index 0000000..7519e11
--- /dev/null
+++ b/lib/tevent/tevent_util.c
@@ -0,0 +1,77 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "talloc.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+#include <fcntl.h>
+
+/**
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+**/
+
+int ev_set_blocking(int fd, bool set)
+{
+ int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
+
+bool ev_set_close_on_exec(int fd)
+{
+#ifdef FD_CLOEXEC
+ int val;
+
+ val = fcntl(fd, F_GETFD, 0);
+ if (val >= 0) {
+ val |= FD_CLOEXEC;
+ val = fcntl(fd, F_SETFD, val);
+ if (val != -1) {
+ return true;
+ }
+ }
+#endif
+ return false;
+}
diff --git a/lib/tevent/tevent_util.h b/lib/tevent/tevent_util.h
new file mode 100644
index 0000000..a7bba0b
--- /dev/null
+++ b/lib/tevent/tevent_util.h
@@ -0,0 +1,28 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+int ev_set_blocking(int fd, bool set);
+bool ev_set_close_on_exec(int fd);
+
+#include "tevent_dlinklist.h"
diff --git a/lib/tevent/tevent_wakeup.c b/lib/tevent/tevent_wakeup.c
new file mode 100644
index 0000000..e217f33
--- /dev/null
+++ b/lib/tevent/tevent_wakeup.c
@@ -0,0 +1,67 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+struct tevent_wakeup_state {
+ struct timeval wakeup_time;
+};
+
+struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval wakeup_time)
+{
+ struct tevent_req *req;
+ struct tevent_wakeup_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tevent_wakeup_state);
+ if (!req) {
+ return NULL;
+ }
+ state->wakeup_time = wakeup_time;
+
+ if (!tevent_req_set_endtime(req, ev, wakeup_time)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+bool tevent_wakeup_recv(struct tevent_req *req)
+{
+ enum tevent_req_state state;
+ uint64_t error;
+
+ if (tevent_req_is_error(req, &state, &error)) {
+ if (state == TEVENT_REQ_TIMED_OUT) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
diff --git a/lib/tevent/tevent_wrapper.c b/lib/tevent/tevent_wrapper.c
new file mode 100644
index 0000000..3870d4f
--- /dev/null
+++ b/lib/tevent/tevent_wrapper.c
@@ -0,0 +1,569 @@
+/*
+ Infrastructure for event context wrappers
+
+ Copyright (C) Stefan Metzmacher 2014
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+#endif
+#define TEVENT_DEPRECATED 1
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
+{
+ tevent_abort(ev, "tevent_wrapper_glue_context_init() called");
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+ struct tevent_fd *fde = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_fd wrapper use after free");
+ return NULL;
+ }
+
+ if (glue->main_ev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
+ handler, private_data,
+ handler_name, location);
+ if (fde == NULL) {
+ return NULL;
+ }
+
+ fde->wrapper = glue;
+
+ return fde;
+}
+
+static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+ struct tevent_timer *te = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_timer wrapper use after free");
+ return NULL;
+ }
+
+ if (glue->main_ev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
+ handler, private_data,
+ handler_name, location);
+ if (te == NULL) {
+ return NULL;
+ }
+
+ te->wrapper = glue;
+
+ return te;
+}
+
+static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "scheduke_immediate wrapper use after free");
+ return;
+ }
+
+ if (glue->main_ev == NULL) {
+ tevent_abort(ev, location);
+ errno = EINVAL;
+ return;
+ }
+
+ _tevent_schedule_immediate(im, glue->main_ev,
+ handler, private_data,
+ handler_name, location);
+
+ im->wrapper = glue;
+
+ return;
+}
+
+static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum, int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+ struct tevent_signal *se = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_signal wrapper use after free");
+ return NULL;
+ }
+
+ if (glue->main_ev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ se = _tevent_add_signal(glue->main_ev, mem_ctx,
+ signum, sa_flags,
+ handler, private_data,
+ handler_name, location);
+ if (se == NULL) {
+ return NULL;
+ }
+
+ se->wrapper = glue;
+
+ return se;
+}
+
+static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
+{
+ tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
+ errno = ENOSYS;
+ return -1;
+}
+
+static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
+{
+ tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
+ errno = ENOSYS;
+ return -1;
+}
+
+static const struct tevent_ops tevent_wrapper_glue_ops = {
+ .context_init = tevent_wrapper_glue_context_init,
+ .add_fd = tevent_wrapper_glue_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = tevent_common_fd_set_flags,
+ .add_timer = tevent_wrapper_glue_add_timer,
+ .schedule_immediate = tevent_wrapper_glue_schedule_immediate,
+ .add_signal = tevent_wrapper_glue_add_signal,
+ .loop_once = tevent_wrapper_glue_loop_once,
+ .loop_wait = tevent_wrapper_glue_loop_wait,
+};
+
+static int tevent_wrapper_context_destructor(struct tevent_context *wrap_ev)
+{
+ struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
+ struct tevent_context *main_ev = NULL;
+ struct tevent_fd *fd = NULL, *fn = NULL;
+ struct tevent_timer *te = NULL, *tn = NULL;
+ struct tevent_immediate *ie = NULL, *in = NULL;
+ struct tevent_signal *se = NULL, *sn = NULL;
+#ifdef HAVE_PTHREAD
+ struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
+#endif
+
+ if (glue == NULL) {
+ tevent_abort(wrap_ev,
+ "tevent_wrapper_context_destructor() active on main");
+ /* static checker support, return below is never reached */
+ return -1;
+ }
+
+ if (glue->destroyed && glue->busy) {
+ tevent_common_check_double_free(wrap_ev,
+ "tevent_context wrapper double free");
+ }
+ glue->destroyed = true;
+
+ if (glue->busy) {
+ return -1;
+ }
+
+ main_ev = glue->main_ev;
+ if (main_ev == NULL) {
+ return 0;
+ }
+
+ TEVENT_DEBUG(wrap_ev, TEVENT_DEBUG_TRACE,
+ "Destroying wrapper context %p \"%s\"\n",
+ wrap_ev, talloc_get_name(glue->private_state));
+
+ glue->main_ev = NULL;
+ DLIST_REMOVE(main_ev->wrapper.list, glue);
+
+#ifdef HAVE_PTHREAD
+ for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
+ int ret;
+
+ tctxn = tctx->next;
+
+ if (tctx->event_ctx != glue->wrap_ev) {
+ continue;
+ }
+
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ /*
+ * Indicate to the thread that the tevent_context is
+ * gone. The counterpart of this is in
+ * _tevent_threaded_schedule_immediate, there we read
+ * this under the threaded_context's mutex.
+ */
+
+ tctx->event_ctx = NULL;
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ DLIST_REMOVE(main_ev->threaded_contexts, tctx);
+ }
+#endif
+
+ for (fd = main_ev->fd_events; fd; fd = fn) {
+ fn = fd->next;
+
+ if (fd->wrapper != glue) {
+ continue;
+ }
+
+ tevent_fd_set_flags(fd, 0);
+
+ tevent_common_fd_disarm(fd);
+ }
+
+ for (te = main_ev->timer_events; te; te = tn) {
+ tn = te->next;
+
+ if (te->wrapper != glue) {
+ continue;
+ }
+
+ te->wrapper = NULL;
+ te->event_ctx = NULL;
+
+ if (main_ev->last_zero_timer == te) {
+ main_ev->last_zero_timer = DLIST_PREV(te);
+ }
+ DLIST_REMOVE(main_ev->timer_events, te);
+ }
+
+ for (ie = main_ev->immediate_events; ie; ie = in) {
+ in = ie->next;
+
+ if (ie->wrapper != glue) {
+ continue;
+ }
+
+ ie->wrapper = NULL;
+ ie->event_ctx = NULL;
+ ie->cancel_fn = NULL;
+ DLIST_REMOVE(main_ev->immediate_events, ie);
+ }
+
+ for (se = main_ev->signal_events; se; se = sn) {
+ sn = se->next;
+
+ if (se->wrapper != glue) {
+ continue;
+ }
+
+ se->wrapper = NULL;
+ tevent_cleanup_pending_signal_handlers(se);
+ }
+
+ return 0;
+}
+
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+ TALLOC_CTX *mem_ctx,
+ const struct tevent_wrapper_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ void **ppstate = (void **)pstate;
+ struct tevent_context *ev = NULL;
+
+ if (main_ev->wrapper.glue != NULL) {
+ /*
+ * stacking of wrappers is not supported
+ */
+ tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
+ "%s: %s() stacking not allowed\n",
+ __func__, location);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (main_ev->nesting.allowed) {
+ /*
+ * wrappers conflict with nesting
+ */
+ tevent_debug(main_ev, TEVENT_DEBUG_FATAL,
+ "%s: %s() conflicts with nesting\n",
+ __func__, location);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ev = talloc_zero(mem_ctx, struct tevent_context);
+ if (ev == NULL) {
+ return NULL;
+ }
+ ev->ops = &tevent_wrapper_glue_ops;
+
+ ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
+ if (ev->wrapper.glue == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ talloc_set_destructor(ev, tevent_wrapper_context_destructor);
+
+ ev->wrapper.glue->wrap_ev = ev;
+ ev->wrapper.glue->main_ev = main_ev;
+ ev->wrapper.glue->ops = ops;
+ ev->wrapper.glue->private_state = talloc_zero_size(ev->wrapper.glue, psize);
+ if (ev->wrapper.glue->private_state == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+ talloc_set_name_const(ev->wrapper.glue->private_state, type);
+
+ DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
+
+ *ppstate = ev->wrapper.glue->private_state;
+ return ev;
+}
+
+bool tevent_context_is_wrapper(struct tevent_context *ev)
+{
+ if (ev->wrapper.glue != NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+_PRIVATE_
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
+{
+ if (ev == NULL) {
+ return NULL;
+ }
+
+ if (ev->wrapper.glue == NULL) {
+ return ev;
+ }
+
+ return ev->wrapper.glue->main_ev;
+}
+
+/*
+ * 32 stack elements should be more than enough
+ *
+ * e.g. Samba uses just 8 elements for [un]become_{root,user}()
+ */
+#define TEVENT_WRAPPER_STACK_SIZE 32
+
+static struct tevent_wrapper_stack {
+ const void *ev_ptr;
+ const struct tevent_wrapper_glue *wrapper;
+} wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
+
+static size_t wrapper_stack_idx;
+
+_PRIVATE_
+void tevent_wrapper_push_use_internal(struct tevent_context *ev,
+ struct tevent_wrapper_glue *wrapper)
+{
+ /*
+ * ev and wrapper need to belong together!
+ * It's also fine to only have a raw ev
+ * without a wrapper.
+ */
+ if (unlikely(ev->wrapper.glue != wrapper)) {
+ tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
+ return;
+ }
+
+ if (wrapper != NULL) {
+ if (unlikely(wrapper->busy)) {
+ tevent_abort(ev, "wrapper already busy!");
+ return;
+ }
+ wrapper->busy = true;
+ }
+
+ if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
+ tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
+ return;
+ }
+
+ wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
+ .ev_ptr = ev,
+ .wrapper = wrapper,
+ };
+ wrapper_stack_idx++;
+}
+
+_PRIVATE_
+void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
+ struct tevent_wrapper_glue *wrapper)
+{
+ struct tevent_context *main_ev = NULL;
+
+ /*
+ * Note that __ev_ptr might a a stale pointer and should not
+ * be touched, we just compare the pointer value in order
+ * to enforce the stack order.
+ */
+
+ if (wrapper != NULL) {
+ main_ev = wrapper->main_ev;
+ }
+
+ if (unlikely(wrapper_stack_idx == 0)) {
+ tevent_abort(main_ev, "tevent_wrapper stack already empty");
+ return;
+ }
+ wrapper_stack_idx--;
+
+ if (wrapper != NULL) {
+ wrapper->busy = false;
+ }
+
+ if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
+ tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
+ return;
+ }
+ if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
+ tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
+ return;
+ }
+
+ if (wrapper == NULL) {
+ return;
+ }
+
+ if (wrapper->destroyed) {
+ /*
+ * Notice that we can't use TALLOC_FREE()
+ * here because wrapper is a talloc child
+ * of wrapper->wrap_ev.
+ */
+ talloc_free(wrapper->wrap_ev);
+ }
+}
+
+bool _tevent_context_push_use(struct tevent_context *ev,
+ const char *location)
+{
+ bool ok;
+
+ if (ev->wrapper.glue == NULL) {
+ tevent_wrapper_push_use_internal(ev, NULL);
+ return true;
+ }
+
+ if (ev->wrapper.glue->main_ev == NULL) {
+ return false;
+ }
+
+ tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
+ ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
+ ev->wrapper.glue->private_state,
+ ev->wrapper.glue->main_ev,
+ location);
+ if (!ok) {
+ tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
+ return false;
+ }
+
+ return true;
+}
+
+void _tevent_context_pop_use(struct tevent_context *ev,
+ const char *location)
+{
+ tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
+
+ if (ev->wrapper.glue == NULL) {
+ return;
+ }
+
+ if (ev->wrapper.glue->main_ev == NULL) {
+ return;
+ }
+
+ ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
+ ev->wrapper.glue->private_state,
+ ev->wrapper.glue->main_ev,
+ location);
+}
+
+bool tevent_context_same_loop(struct tevent_context *ev1,
+ struct tevent_context *ev2)
+{
+ struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
+ struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
+
+ if (main_ev1 == NULL) {
+ return false;
+ }
+
+ if (main_ev1 == main_ev2) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
new file mode 100644
index 0000000..8df1b40
--- /dev/null
+++ b/lib/tevent/wscript
@@ -0,0 +1,172 @@
+#!/usr/bin/env python
+
+APPNAME = 'tevent'
+VERSION = '0.16.1'
+
+import sys, os
+
+# find the buildtools directory
+top = '.'
+while not os.path.exists(top+'/buildtools') and len(top.split('/')) < 5:
+ top = top + '/..'
+sys.path.insert(0, top + '/buildtools/wafsamba')
+
+out = 'bin'
+
+import wafsamba
+from wafsamba import samba_dist, samba_utils
+from waflib import Options, Logs, Context, Errors
+
+samba_dist.DIST_DIRS('''lib/tevent:. lib/replace:lib/replace
+ lib/talloc:lib/talloc buildtools:buildtools
+ third_party/cmocka:third_party/cmocka
+ third_party/waf:third_party/waf''')
+
+def options(opt):
+ opt.BUILTIN_DEFAULT('replace')
+ opt.PRIVATE_EXTENSION_DEFAULT('tevent', noextension='tevent')
+ opt.RECURSE('lib/replace')
+ opt.RECURSE('lib/talloc')
+
+
+def configure(conf):
+ conf.RECURSE('lib/replace')
+ conf.RECURSE('lib/talloc')
+
+ if conf.CHECK_FOR_THIRD_PARTY():
+ conf.RECURSE('third_party/cmocka')
+ else:
+ if not conf.CHECK_CMOCKA():
+ raise Errors.WafError('cmocka development package have not been found.\nIf third_party is installed, check that it is in the proper place.')
+ else:
+ conf.define('USING_SYSTEM_CMOCKA', 1)
+
+ conf.env.standalone_tevent = conf.IN_LAUNCH_DIR()
+
+ if not conf.env.standalone_tevent:
+ if conf.CHECK_BUNDLED_SYSTEM_PKG('tevent', minversion=VERSION,
+ onlyif='talloc', implied_deps='replace talloc'):
+ conf.define('USING_SYSTEM_TEVENT', 1)
+ if not conf.env.disable_python and \
+ conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytevent', 'tevent', minversion=VERSION):
+ conf.define('USING_SYSTEM_PYTEVENT', 1)
+
+ if conf.CHECK_FUNCS('epoll_create1', headers='sys/epoll.h'):
+ conf.DEFINE('HAVE_EPOLL', 1)
+
+ tevent_num_signals = 64
+ v = conf.CHECK_VALUEOF('NSIG', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v)
+ v = conf.CHECK_VALUEOF('_NSIG', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v)
+ v = conf.CHECK_VALUEOF('SIGRTMAX', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v)
+ v = conf.CHECK_VALUEOF('SIGRTMIN', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v*2)
+
+ if not conf.CONFIG_SET('USING_SYSTEM_TEVENT'):
+ conf.DEFINE('TEVENT_NUM_SIGNALS', tevent_num_signals)
+
+ conf.SAMBA_CHECK_PYTHON()
+ conf.SAMBA_CHECK_PYTHON_HEADERS()
+
+ conf.SAMBA_CONFIG_H()
+
+ conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
+
+def build(bld):
+ bld.RECURSE('lib/replace')
+ bld.RECURSE('lib/talloc')
+
+ if bld.CHECK_FOR_THIRD_PARTY():
+ bld.RECURSE('third_party/cmocka')
+
+ SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
+ tevent_queue.c tevent_req.c tevent_wrapper.c
+ tevent_poll.c tevent_threads.c
+ tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''
+
+ if bld.CONFIG_SET('HAVE_EPOLL'):
+ SRC += ' tevent_epoll.c'
+
+ if bld.env.standalone_tevent:
+ bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+ private_library = False
+ else:
+ private_library = True
+
+ if not bld.CONFIG_SET('USING_SYSTEM_TEVENT'):
+ tevent_deps = 'replace talloc'
+ if bld.CONFIG_SET('HAVE_PTHREAD'):
+ tevent_deps += ' pthread'
+
+ bld.SAMBA_LIBRARY('tevent',
+ SRC,
+ deps=tevent_deps,
+ enabled= not bld.CONFIG_SET('USING_SYSTEM_TEVENT'),
+ includes='.',
+ abi_directory='ABI',
+ abi_match='tevent_* _tevent_* __tevent_*',
+ vnum=VERSION,
+ public_headers=('' if private_library else 'tevent.h'),
+ public_headers_install=not private_library,
+ pc_files='tevent.pc',
+ private_library=private_library)
+
+ if not bld.CONFIG_SET('USING_SYSTEM_PYTEVENT') and not bld.env.disable_python:
+ bld.SAMBA_PYTHON('_tevent',
+ 'pytevent.c',
+ deps='tevent',
+ realname='_tevent.so',
+ cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+
+
+ bld.INSTALL_WILDCARD('${PYTHONARCHDIR}', 'tevent.py', flat=False)
+
+ # install out various python scripts for use by make test
+ bld.SAMBA_SCRIPT('tevent_python',
+ pattern='tevent.py',
+ installdir='python')
+
+ bld.SAMBA_BINARY('test_tevent_tag',
+ source='tests/test_tevent_tag.c',
+ deps='cmocka tevent',
+ install=False)
+
+ bld.SAMBA_BINARY('test_tevent_trace',
+ source='tests/test_tevent_trace.c',
+ deps='cmocka tevent',
+ install=False)
+
+def test(ctx):
+ '''test tevent'''
+ print("The tevent testsuite is part of smbtorture in samba4")
+
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared')
+ samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private')
+
+ pyret = samba_utils.RUN_PYTHON_TESTS(['bindings.py'])
+
+ unit_test_ret = 0
+ unit_tests = [
+ 'test_tevent_tag',
+ 'test_tevent_trace',
+ ]
+
+ for unit_test in unit_tests:
+ unit_test_cmd = os.path.join(Context.g_module.out, unit_test)
+ unit_test_ret = unit_test_ret or samba_utils.RUN_COMMAND(unit_test_cmd)
+
+ sys.exit(pyret or unit_test_ret)
+
+def dist():
+ '''makes a tarball for distribution'''
+ samba_dist.dist()
+
+def reconfigure(ctx):
+ '''reconfigure if config scripts have changed'''
+ samba_utils.reconfigure(ctx)
diff --git a/lib/texpect/texpect.c b/lib/texpect/texpect.c
new file mode 100644
index 0000000..1a6ebf4
--- /dev/null
+++ b/lib/texpect/texpect.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2008 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 INSTITUTE OR CONTRIBUTORS 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.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "lib/util/sys_rw.h"
+
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+#ifdef HAVE_BSD_LIBUTIL_H
+#include <bsd/libutil.h>
+#elif defined HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+
+#ifdef STREAMSPTY
+#include <stropts.h>
+#endif /* STREAMPTY */
+
+#include <popt.h>
+
+#ifdef HAVE_ERR_H
+#include <err.h>
+#else
+const char progname[] = "unknown program";
+
+static void err(int eval, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 0);
+static void errx(int eval, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 0);
+
+static void err(int eval, const char *fmt, ...)
+{
+ int err_errno = errno;
+ va_list ap;
+
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, ": %s\n", strerror(err_errno));
+ exit(eval);
+}
+
+static void errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(eval);
+}
+
+#endif
+
+struct command {
+ enum { CMD_EXPECT = 0, CMD_SEND, CMD_PASSWORD } type;
+ unsigned int lineno;
+ char *str;
+ struct command *next;
+};
+
+/*
+ *
+ */
+
+static struct command *commands, **next = &commands;
+
+static sig_atomic_t alarmset = 0;
+
+static int opt_timeout = 10;
+static int opt_verbose;
+
+static int master;
+static int slave;
+static char line[256] = { 0 };
+
+static void caught_signal(int signo)
+{
+ alarmset = signo;
+}
+
+
+static void open_pty(void)
+{
+#ifdef _AIX
+ printf("implement open_pty\n");
+ exit(77);
+#endif
+#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
+ if(openpty(&master, &slave, line, 0, 0) == 0)
+ return;
+#endif /* HAVE_OPENPTY .... */
+#ifdef STREAMSPTY
+ {
+ char *clone[] = {
+ "/dev/ptc",
+ "/dev/ptmx",
+ "/dev/ptm",
+ "/dev/ptym/clone",
+ NULL
+ };
+ char **q;
+
+ for(q = clone; *q; q++){
+ master = open(*q, O_RDWR);
+ if(master >= 0){
+#ifdef HAVE_GRANTPT
+ grantpt(master);
+#endif
+#ifdef HAVE_UNLOCKPT
+ unlockpt(master);
+#endif
+ strlcpy(line, ptsname(master), sizeof(line));
+ slave = open(line, O_RDWR);
+ if (slave < 0)
+ errx(1, "failed to open slave when using %s", *q);
+ ioctl(slave, I_PUSH, "ptem");
+ ioctl(slave, I_PUSH, "ldterm");
+
+ return;
+ }
+ }
+ }
+#endif /* STREAMSPTY */
+
+ /* more cases, like open /dev/ptmx, etc */
+
+ exit(77);
+}
+
+/*
+ *
+ */
+
+static char *iscmd(const char *buf, const char *s)
+{
+ size_t len = strlen(s);
+
+ if (strncmp(buf, s, len) != 0) {
+ return NULL;
+ }
+
+ return strdup(buf + len);
+}
+
+static void parse_configuration(const char *fn)
+{
+ struct command *c;
+ char s[1024];
+ char *str;
+ unsigned int lineno = 0;
+ FILE *cmd;
+
+ cmd = fopen(fn, "r");
+ if (cmd == NULL)
+ err(1, "open: %s", fn);
+
+ while (fgets(s, sizeof(s), cmd) != NULL) {
+
+ s[strcspn(s, "#\n")] = '\0';
+ lineno++;
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL)
+ errx(1, "malloc");
+
+ c->lineno = lineno;
+ (*next) = c;
+ next = &(c->next);
+
+ if ((str = iscmd(s, "expect ")) != NULL) {
+ c->type = CMD_EXPECT;
+ c->str = str;
+ } else if ((str = iscmd(s, "send ")) != NULL) {
+ c->type = CMD_SEND;
+ c->str = str;
+ } else if ((str = iscmd(s, "password ")) != NULL) {
+ c->type = CMD_PASSWORD;
+ c->str = str;
+ } else
+ errx(1, "Invalid command on line %d: %s", lineno, s);
+ }
+
+ fclose(cmd);
+}
+
+/*
+ *
+ */
+
+static int eval_parent(pid_t pid)
+{
+ struct command *c;
+ char in;
+ size_t len = 0;
+ ssize_t sret;
+
+ for (c = commands; c != NULL; c = c->next) {
+ switch(c->type) {
+ case CMD_EXPECT:
+ if (opt_verbose) {
+ printf("[expecting %s]\n", c->str);
+ }
+ len = 0;
+ alarm(opt_timeout);
+ while((sret = read(master, &in, sizeof(in))) > 0) {
+ alarm(opt_timeout);
+ printf("%c", in);
+ if (c->str[len] != in) {
+ len = 0;
+ continue;
+ }
+ len++;
+ if (c->str[len] == '\0') {
+ break;
+ }
+ }
+ alarm(0);
+ if (alarmset == SIGALRM) {
+ errx(1, "timeout waiting for %s (line %u)",
+ c->str, c->lineno);
+ } else if (alarmset) {
+ errx(1, "got a signal %d waiting for %s (line %u)",
+ (int)alarmset, c->str, c->lineno);
+ }
+
+ if (sret <= 0) {
+ errx(1, "end command while waiting for %s (line %u)",
+ c->str, c->lineno);
+ }
+ break;
+ case CMD_SEND:
+ case CMD_PASSWORD: {
+ size_t i = 0;
+ const char *msg = (c->type == CMD_PASSWORD) ? "****" : c->str;
+
+ if (opt_verbose) {
+ printf("[send %s]\n", msg);
+ }
+
+ len = strlen(c->str);
+
+ while (i < len) {
+ if (c->str[i] == '\\' && i < len - 1) {
+ char ctrl;
+ i++;
+ switch(c->str[i]) {
+ case 'n':
+ ctrl = '\n';
+ break;
+ case 'r':
+ ctrl = '\r';
+ break;
+ case 't':
+ ctrl = '\t';
+ break;
+ default:
+ errx(1,
+ "unknown control char %c (line %u)",
+ c->str[i],
+ c->lineno);
+ }
+ if (sys_write(master, &ctrl, 1) != 1) {
+ errx(1, "command refused input (line %u)", c->lineno);
+ }
+ } else {
+ if (sys_write(master, &c->str[i], 1) != 1) {
+ errx(1, "command refused input (line %u)", c->lineno);
+ }
+ }
+ i++;
+ }
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+
+ while(read(master, &in, sizeof(in)) > 0) {
+ printf("%c", in);
+ }
+
+ if (opt_verbose) {
+ printf("[end of program]\n");
+ }
+
+ /*
+ * Fetch status from child
+ */
+ {
+ int ret, status;
+
+ ret = waitpid(pid, &status, 0);
+ if (ret == -1) {
+ err(1, "waitpid");
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ return WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ printf("killed by signal: %d\n", WTERMSIG(status));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ *
+ */
+struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {
+ .longName = "timeout",
+ .shortName = 't',
+ .argInfo = POPT_ARG_INT,
+ .arg = &opt_timeout,
+ .val = 't',
+ },
+ {
+ .longName = "verbose",
+ .shortName = 'v',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &opt_verbose,
+ .val = 'v',
+ },
+ POPT_TABLEEND
+};
+
+int main(int argc, const char **argv)
+{
+ int optidx = 0;
+ pid_t pid;
+ poptContext pc = NULL;
+ const char *instruction_file;
+ const char **args;
+ const char *program;
+ char * const *program_args;
+
+ pc = poptGetContext("texpect",
+ argc,
+ argv,
+ long_options,
+ POPT_CONTEXT_POSIXMEHARDER);
+
+ if (argc == 1) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ while ((optidx = poptGetNextOpt(pc)) != -1) {
+ switch (optidx) {
+ case POPT_ERROR_BADOPT:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(optidx));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+
+ instruction_file = poptGetArg(pc);
+ args = poptGetArgs(pc);
+ if (args == NULL) {
+ poptPrintHelp(pc, stderr, 0);
+ goto out;
+ }
+
+ program_args = (char * const *)discard_const_p(char *, args);
+ program = program_args[0];
+
+ if (opt_verbose) {
+ int i;
+
+ printf("Using instruction_file: %s\n", instruction_file);
+ printf("Executing '%s' ", program);
+ for (i = 0; program_args[i] != NULL; i++) {
+ printf("'%s' ", program_args[i]);
+ }
+ printf("\n");
+ }
+
+ parse_configuration(instruction_file);
+
+ open_pty();
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ err(1, "Failed to fork");
+
+ /* Never reached */
+ goto out;
+ case 0:
+
+ if(setsid()<0)
+ err(1, "setsid");
+
+ dup2(slave, STDIN_FILENO);
+ dup2(slave, STDOUT_FILENO);
+ dup2(slave, STDERR_FILENO);
+
+ closefrom(STDERR_FILENO + 1);
+
+ /* texpect <expect_instructions> <progname> [<args>] */
+ execvp(program, program_args);
+ err(1, "Failed to exec: %s", program);
+
+ /* Never reached */
+ goto out;
+ default:
+ close(slave);
+ {
+ struct sigaction sa;
+
+ sa.sa_handler = caught_signal;
+ sa.sa_flags = 0;
+ sigemptyset (&sa.sa_mask);
+
+ sigaction(SIGALRM, &sa, NULL);
+ }
+
+ poptFreeContext(pc);
+ return eval_parent(pid);
+ }
+
+ /* Never reached */
+
+out:
+ poptFreeContext(pc);
+ return 1;
+}
diff --git a/lib/texpect/wscript b/lib/texpect/wscript
new file mode 100644
index 0000000..44f92a8
--- /dev/null
+++ b/lib/texpect/wscript
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+def configure(conf):
+ conf.CHECK_FUNCS_IN('openpty', 'util', checklibc=True, headers='pty.h util.h bsd/libutil.h libutil.h')
+
+def build(bld):
+ bld.SAMBA_BINARY('texpect',
+ 'texpect.c',
+ deps='popt util replace sys_rw',
+ for_selftest=True)
diff --git a/lib/torture/simple.c b/lib/torture/simple.c
new file mode 100644
index 0000000..d234776
--- /dev/null
+++ b/lib/torture/simple.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/torture/torture.h"
+
+static struct timeval last_suite_started;
+
+static void simple_suite_start(struct torture_context *ctx,
+ struct torture_suite *suite)
+{
+ last_suite_started = timeval_current();
+ printf("Running %s\n", suite->name);
+}
+
+static void simple_suite_finish(struct torture_context *ctx,
+ struct torture_suite *suite)
+{
+
+ printf("%s took %g secs\n\n", suite->name,
+ timeval_elapsed(&last_suite_started));
+}
+
+static void simple_test_result(struct torture_context *context,
+ enum torture_result res, const char *reason)
+{
+ switch (res) {
+ case TORTURE_OK:
+ if (reason)
+ printf("OK: %s\n", reason);
+ break;
+ case TORTURE_FAIL:
+ printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
+ break;
+ case TORTURE_ERROR:
+ printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
+ break;
+ case TORTURE_SKIP:
+ printf("SKIP: %s - %s\n", context->active_test->name, reason);
+ break;
+ }
+}
+
+static void simple_comment(struct torture_context *test,
+ const char *comment)
+{
+ printf("%s", comment);
+}
+
+static void simple_warning(struct torture_context *test,
+ const char *comment)
+{
+ fprintf(stderr, "WARNING: %s\n", comment);
+}
+
+static void simple_progress(struct torture_context *test,
+ int offset, enum torture_progress_whence whence)
+{
+}
+
+const struct torture_ui_ops torture_simple_ui_ops = {
+ .comment = simple_comment,
+ .warning = simple_warning,
+ .suite_start = simple_suite_start,
+ .suite_finish = simple_suite_finish,
+ .test_result = simple_test_result,
+ .progress = simple_progress,
+};
diff --git a/lib/torture/subunit.c b/lib/torture/subunit.c
new file mode 100644
index 0000000..693d903
--- /dev/null
+++ b/lib/torture/subunit.c
@@ -0,0 +1,143 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/torture/torture.h"
+
+static void subunit_send_event(char const * const event,
+ char const * const name,
+ char const * const details)
+{
+ if (NULL == details) {
+ printf("%s: %s\n", event, name);
+ } else {
+ printf("%s: %s [\n", event, name);
+ printf("%s", details);
+ if (details[strlen(details) - 1] != '\n')
+ puts("");
+ puts("]");
+ }
+ fflush(stdout);
+}
+
+static void torture_subunit_suite_start(struct torture_context *ctx,
+ struct torture_suite *suite)
+{
+}
+
+static void torture_subunit_report_time(struct torture_context *tctx)
+{
+ struct timespec tp;
+ struct tm *tmp;
+ char timestr[200];
+ if (clock_gettime(CLOCK_REALTIME, &tp) != 0) {
+ perror("clock_gettime");
+ return;
+ }
+
+ tmp = gmtime(&tp.tv_sec);
+ if (!tmp) {
+ perror("gmtime");
+ return;
+ }
+
+ if (strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tmp) <= 0) {
+ perror("strftime");
+ return;
+ }
+
+ printf("time: %s.%06ld\n", timestr, tp.tv_nsec / 1000);
+}
+
+static void torture_subunit_test_start(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ char *fullname = torture_subunit_test_name(context, context->active_tcase, context->active_test);
+ subunit_send_event("test", fullname, NULL);
+ torture_subunit_report_time(context);
+ talloc_free(fullname);
+}
+
+static void torture_subunit_test_result(struct torture_context *context,
+ enum torture_result res, const char *reason)
+{
+ char *fullname = torture_subunit_test_name(context, context->active_tcase, context->active_test);
+ const char *result_str = "unknown";
+ torture_subunit_report_time(context);
+ switch (res) {
+ case TORTURE_OK:
+ result_str = "success";
+ break;
+ case TORTURE_FAIL:
+ result_str = "failure";
+ break;
+ case TORTURE_ERROR:
+ result_str = "error";
+ break;
+ case TORTURE_SKIP:
+ result_str = "skip";
+ break;
+ }
+ subunit_send_event(result_str, fullname, reason);
+ talloc_free(fullname);
+}
+
+static void torture_subunit_comment(struct torture_context *test,
+ const char *comment)
+{
+ fprintf(stderr, "%s", comment);
+}
+
+static void torture_subunit_warning(struct torture_context *test,
+ const char *comment)
+{
+ fprintf(stderr, "WARNING!: %s\n", comment);
+}
+
+static void torture_subunit_progress(struct torture_context *tctx, int offset, enum torture_progress_whence whence)
+{
+ switch (whence) {
+ case TORTURE_PROGRESS_SET:
+ printf("progress: %d\n", offset);
+ break;
+ case TORTURE_PROGRESS_CUR:
+ printf("progress: %+-d\n", offset);
+ break;
+ case TORTURE_PROGRESS_POP:
+ printf("progress: pop\n");
+ break;
+ case TORTURE_PROGRESS_PUSH:
+ printf("progress: push\n");
+ break;
+ default:
+ fprintf(stderr, "Invalid call to progress()\n");
+ break;
+ }
+}
+
+const struct torture_ui_ops torture_subunit_ui_ops = {
+ .comment = torture_subunit_comment,
+ .warning = torture_subunit_warning,
+ .test_start = torture_subunit_test_start,
+ .test_result = torture_subunit_test_result,
+ .suite_start = torture_subunit_suite_start,
+ .progress = torture_subunit_progress,
+ .report_time = torture_subunit_report_time,
+};
diff --git a/lib/torture/torture.c b/lib/torture/torture.c
new file mode 100644
index 0000000..41226ef
--- /dev/null
+++ b/lib/torture/torture.c
@@ -0,0 +1,839 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture UI functions
+
+ Copyright (C) Jelmer Vernooij 2006-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "source4/include/includes.h"
+#include "../torture/torture.h"
+#include "../lib/util/dlinklist.h"
+#include "param/param.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+
+
+struct torture_results *torture_results_init(TALLOC_CTX *mem_ctx, const struct torture_ui_ops *ui_ops)
+{
+ struct torture_results *results = talloc_zero(mem_ctx, struct torture_results);
+
+ results->ui_ops = ui_ops;
+ results->returncode = true;
+
+ if (ui_ops->init)
+ ui_ops->init(results);
+
+ return results;
+}
+
+/**
+ * Initialize a torture context
+ */
+struct torture_context *torture_context_init(struct tevent_context *event_ctx,
+ struct torture_results *results)
+{
+ struct torture_context *torture = talloc_zero(event_ctx,
+ struct torture_context);
+
+ if (torture == NULL)
+ return NULL;
+
+ torture->ev = event_ctx;
+ torture->results = talloc_reference(torture, results);
+
+ /*
+ * We start with an empty subunit prefix
+ */
+ torture_subunit_prefix_reset(torture, NULL);
+
+ return torture;
+}
+
+/**
+ * Create a sub torture context
+ */
+struct torture_context *torture_context_child(struct torture_context *parent)
+{
+ struct torture_context *subtorture = talloc_zero(parent, struct torture_context);
+
+ if (subtorture == NULL)
+ return NULL;
+
+ subtorture->ev = talloc_reference(subtorture, parent->ev);
+ subtorture->lp_ctx = talloc_reference(subtorture, parent->lp_ctx);
+ subtorture->outputdir = talloc_reference(subtorture, parent->outputdir);
+ subtorture->results = talloc_reference(subtorture, parent->results);
+
+ return subtorture;
+}
+
+/**
+ create a temporary directory under the output dir
+*/
+_PUBLIC_ NTSTATUS torture_temp_dir(struct torture_context *tctx,
+ const char *prefix, char **tempdir)
+{
+ SMB_ASSERT(tctx->outputdir != NULL);
+
+ *tempdir = talloc_asprintf(tctx, "%s/%s.XXXXXX", tctx->outputdir,
+ prefix);
+ NT_STATUS_HAVE_NO_MEMORY(*tempdir);
+
+ if (mkdtemp(*tempdir) == NULL) {
+ return map_nt_error_from_unix_common(errno);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static int local_deltree(const char *path)
+{
+ int ret = 0;
+ struct dirent *dirent;
+ DIR *dir = opendir(path);
+ if (!dir) {
+ char *error = talloc_asprintf(NULL, "Could not open directory %s", path);
+ perror(error);
+ talloc_free(error);
+ return -1;
+ }
+ while ((dirent = readdir(dir))) {
+ char *name;
+ if ((strcmp(dirent->d_name, ".") == 0) || (strcmp(dirent->d_name, "..") == 0)) {
+ continue;
+ }
+ name = talloc_asprintf(NULL, "%s/%s", path,
+ dirent->d_name);
+ if (name == NULL) {
+ closedir(dir);
+ return -1;
+ }
+ DEBUG(0, ("About to remove %s\n", name));
+ ret = remove(name);
+ if (ret == 0) {
+ talloc_free(name);
+ continue;
+ }
+
+ if (errno == ENOTEMPTY) {
+ ret = local_deltree(name);
+ if (ret == 0) {
+ ret = remove(name);
+ }
+ }
+ talloc_free(name);
+ if (ret != 0) {
+ char *error = talloc_asprintf(NULL, "Could not remove %s", path);
+ perror(error);
+ talloc_free(error);
+ break;
+ }
+ }
+ closedir(dir);
+ rmdir(path);
+ return ret;
+}
+
+_PUBLIC_ NTSTATUS torture_deltree_outputdir(struct torture_context *tctx)
+{
+ if (tctx->outputdir == NULL) {
+ return NT_STATUS_OK;
+ }
+ if ((strcmp(tctx->outputdir, "/") == 0)
+ || (strcmp(tctx->outputdir, "") == 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (local_deltree(tctx->outputdir) == -1) {
+ if (errno != 0) {
+ return map_nt_error_from_unix_common(errno);
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Comment on the status/progress of a test
+ */
+void torture_comment(struct torture_context *context, const char *comment, ...)
+{
+ va_list ap;
+ char *tmp;
+
+ if (!context->results->ui_ops->comment)
+ return;
+
+ va_start(ap, comment);
+ tmp = talloc_vasprintf(context, comment, ap);
+ va_end(ap);
+
+ context->results->ui_ops->comment(context, tmp);
+
+ talloc_free(tmp);
+}
+
+/**
+ * Print a warning about the current test
+ */
+void torture_warning(struct torture_context *context, const char *comment, ...)
+{
+ va_list ap;
+ char *tmp;
+
+ if (!context->results->ui_ops->warning)
+ return;
+
+ va_start(ap, comment);
+ tmp = talloc_vasprintf(context, comment, ap);
+ va_end(ap);
+
+ context->results->ui_ops->warning(context, tmp);
+
+ talloc_free(tmp);
+}
+
+/**
+ * Store the result of a torture test.
+ */
+void torture_result(struct torture_context *context,
+ enum torture_result result, const char *fmt, ...)
+{
+ /* Of the two outcomes, keep that with the higher priority. */
+ if (result >= context->last_result) {
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (context->last_reason) {
+ torture_warning(context, "%s", context->last_reason);
+ talloc_free(context->last_reason);
+ }
+
+ context->last_result = result;
+ context->last_reason = talloc_vasprintf(context, fmt, ap);
+
+ va_end(ap);
+ }
+}
+
+/**
+ * Create a new torture suite
+ */
+struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name)
+{
+ struct torture_suite *suite = talloc_zero(ctx, struct torture_suite);
+
+ suite->name = talloc_strdup(suite, name);
+ suite->testcases = NULL;
+ suite->children = NULL;
+
+ return suite;
+}
+
+/**
+ * Set the setup() and teardown() functions for a testcase.
+ */
+void torture_tcase_set_fixture(struct torture_tcase *tcase,
+ bool (*setup) (struct torture_context *, void **),
+ bool (*teardown) (struct torture_context *, void *))
+{
+ tcase->setup = setup;
+ tcase->teardown = teardown;
+}
+
+static bool wrap_test_with_testcase_const(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *,
+ const void *tcase_data,
+ const void *test_data);
+
+ fn = test->fn;
+
+ return fn(torture_ctx, tcase->data, test->data);
+}
+
+/**
+ * Add a test that uses const data to a testcase
+ */
+struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase,
+ const char *name,
+ bool (*run) (struct torture_context *, const void *tcase_data,
+ const void *test_data),
+ const void *data)
+{
+ struct torture_test *test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_test_with_testcase_const;
+ test->fn = run;
+ test->dangerous = false;
+ test->data = data;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+/**
+ * Add a new testcase
+ */
+bool torture_suite_init_tcase(struct torture_suite *suite,
+ struct torture_tcase *tcase,
+ const char *name)
+{
+ tcase->name = talloc_strdup(tcase, name);
+ tcase->description = NULL;
+ tcase->setup = NULL;
+ tcase->teardown = NULL;
+ tcase->fixture_persistent = true;
+ tcase->tests = NULL;
+
+ DLIST_ADD_END(suite->testcases, tcase);
+ tcase->suite = suite;
+
+ return true;
+}
+
+
+struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite,
+ const char *name)
+{
+ struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
+
+ if (!torture_suite_init_tcase(suite, tcase, name))
+ return NULL;
+
+ return tcase;
+}
+
+char *torture_subunit_test_name(struct torture_context *ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ if (!strcmp(tcase->name, test->name)) {
+ return talloc_asprintf(ctx, "%s%s",
+ ctx->active_prefix->subunit_prefix,
+ test->name);
+ } else {
+ return talloc_asprintf(ctx, "%s%s.%s",
+ ctx->active_prefix->subunit_prefix,
+ tcase->name, test->name);
+ }
+}
+
+void torture_subunit_prefix_reset(struct torture_context *ctx,
+ const char *name)
+{
+ struct torture_subunit_prefix *prefix = &ctx->_initial_prefix;
+
+ ZERO_STRUCTP(prefix);
+
+ if (name != NULL) {
+ int ret;
+
+ ret = snprintf(prefix->subunit_prefix,
+ sizeof(prefix->subunit_prefix),
+ "%s.", name);
+ if (ret < 0) {
+ abort();
+ }
+ }
+
+ ctx->active_prefix = prefix;
+}
+
+static void torture_subunit_prefix_push(struct torture_context *ctx,
+ struct torture_subunit_prefix *prefix,
+ const char *name)
+{
+ *prefix = (struct torture_subunit_prefix) {
+ .parent = ctx->active_prefix,
+ };
+
+ if (ctx->active_prefix->parent != NULL ||
+ ctx->active_prefix->subunit_prefix[0] != '\0') {
+ /*
+ * We need a new component for the prefix.
+ */
+ int ret;
+
+ ret = snprintf(prefix->subunit_prefix,
+ sizeof(prefix->subunit_prefix),
+ "%s%s.",
+ ctx->active_prefix->subunit_prefix,
+ name);
+ if (ret < 0) {
+ abort();
+ }
+ }
+
+ ctx->active_prefix = prefix;
+}
+
+static void torture_subunit_prefix_pop(struct torture_context *ctx)
+{
+ ctx->active_prefix = ctx->active_prefix->parent;
+}
+
+int torture_suite_children_count(const struct torture_suite *suite)
+{
+ int ret = 0;
+ struct torture_tcase *tcase;
+ struct torture_test *test;
+ struct torture_suite *tsuite;
+ for (tcase = suite->testcases; tcase; tcase = tcase->next) {
+ for (test = tcase->tests; test; test = test->next) {
+ ret++;
+ }
+ }
+ for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
+ ret ++;
+ }
+ return ret;
+}
+
+/**
+ * Run a torture test suite.
+ */
+bool torture_run_suite(struct torture_context *context,
+ struct torture_suite *suite)
+{
+ return torture_run_suite_restricted(context, suite, NULL);
+}
+
+bool torture_run_suite_restricted(struct torture_context *context,
+ struct torture_suite *suite, const char **restricted)
+{
+ struct torture_subunit_prefix _prefix_stack;
+ bool ret = true;
+ struct torture_tcase *tcase;
+ struct torture_suite *tsuite;
+
+ torture_subunit_prefix_push(context, &_prefix_stack, suite->name);
+
+ if (context->results->ui_ops->suite_start)
+ context->results->ui_ops->suite_start(context, suite);
+
+ /* FIXME: Adjust torture_suite_children_count if restricted != NULL */
+ context->results->ui_ops->progress(context,
+ torture_suite_children_count(suite), TORTURE_PROGRESS_SET);
+
+ for (tcase = suite->testcases; tcase; tcase = tcase->next) {
+ ret &= torture_run_tcase_restricted(context, tcase, restricted);
+ }
+
+ for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
+ context->results->ui_ops->progress(context, 0, TORTURE_PROGRESS_PUSH);
+ ret &= torture_run_suite_restricted(context, tsuite, restricted);
+ context->results->ui_ops->progress(context, 0, TORTURE_PROGRESS_POP);
+ }
+
+ if (context->results->ui_ops->suite_finish)
+ context->results->ui_ops->suite_finish(context, suite);
+
+ torture_subunit_prefix_pop(context);
+
+ return ret;
+}
+
+void torture_ui_test_start(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ if (context->results->ui_ops->test_start)
+ context->results->ui_ops->test_start(context, tcase, test);
+}
+
+void torture_ui_test_result(struct torture_context *context,
+ enum torture_result result,
+ const char *comment)
+{
+ if (context->results->ui_ops->test_result)
+ context->results->ui_ops->test_result(context, result, comment);
+
+ if (result == TORTURE_ERROR || result == TORTURE_FAIL)
+ context->results->returncode = false;
+}
+
+static bool test_needs_running(const char *name, const char **restricted)
+{
+ int i;
+ if (restricted == NULL)
+ return true;
+ for (i = 0; restricted[i]; i++) {
+ if (!strcmp(name, restricted[i]))
+ return true;
+ }
+ return false;
+}
+
+static bool internal_torture_run_test(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test,
+ bool already_setup,
+ const char **restricted)
+{
+ bool success;
+ char *subunit_testname = torture_subunit_test_name(context, tcase, test);
+
+ if (!test_needs_running(subunit_testname, restricted))
+ return true;
+
+ context->active_tcase = tcase;
+ context->active_test = test;
+
+ torture_ui_test_start(context, tcase, test);
+
+ context->last_reason = NULL;
+ context->last_result = TORTURE_OK;
+
+ if (!already_setup && tcase->setup &&
+ !tcase->setup(context, &(tcase->data))) {
+ if (context->last_reason == NULL)
+ context->last_reason = talloc_strdup(context, "Setup failure");
+ context->last_result = TORTURE_ERROR;
+ success = false;
+ } else if (test->dangerous &&
+ !torture_setting_bool(context, "dangerous", false)) {
+ context->last_result = TORTURE_SKIP;
+ context->last_reason = talloc_asprintf(context,
+ "disabled %s - enable dangerous tests to use", test->name);
+ success = true;
+ } else {
+ success = test->run(context, tcase, test);
+
+ if (!success && context->last_result == TORTURE_OK) {
+ if (context->last_reason == NULL)
+ context->last_reason = talloc_strdup(context,
+ "Unknown error/failure. Missing torture_fail() or torture_assert_*() call?");
+ context->last_result = TORTURE_ERROR;
+ }
+ }
+
+ if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data)) {
+ if (context->last_reason == NULL)
+ context->last_reason = talloc_strdup(context, "Setup failure");
+ context->last_result = TORTURE_ERROR;
+ success = false;
+ }
+
+ torture_ui_test_result(context, context->last_result,
+ context->last_reason);
+
+ talloc_free(context->last_reason);
+ context->last_reason = NULL;
+
+ context->active_test = NULL;
+ context->active_tcase = NULL;
+
+ return success;
+}
+
+bool torture_run_tcase(struct torture_context *context,
+ struct torture_tcase *tcase)
+{
+ return torture_run_tcase_restricted(context, tcase, NULL);
+}
+
+bool torture_run_tcase_restricted(struct torture_context *context,
+ struct torture_tcase *tcase, const char **restricted)
+{
+ bool ret = true;
+ struct torture_test *test;
+ bool setup_succeeded = true;
+ const char * setup_reason = "Setup failed";
+
+ context->active_tcase = tcase;
+ if (context->results->ui_ops->tcase_start)
+ context->results->ui_ops->tcase_start(context, tcase);
+
+ if (tcase->fixture_persistent && tcase->setup) {
+ setup_succeeded = tcase->setup(context, &tcase->data);
+ }
+
+ if (!setup_succeeded) {
+ /* Uh-oh. The setup failed, so we can't run any of the tests
+ * in this testcase. The subunit format doesn't specify what
+ * to do here, so we keep the failure reason, and manually
+ * use it to fail every test.
+ */
+ if (context->last_reason != NULL) {
+ setup_reason = talloc_asprintf(context,
+ "Setup failed: %s", context->last_reason);
+ }
+ }
+
+ for (test = tcase->tests; test; test = test->next) {
+ if (setup_succeeded) {
+ ret &= internal_torture_run_test(context, tcase, test,
+ tcase->fixture_persistent, restricted);
+ } else {
+ context->active_tcase = tcase;
+ context->active_test = test;
+ torture_ui_test_start(context, tcase, test);
+ torture_ui_test_result(context, TORTURE_FAIL, setup_reason);
+ }
+ }
+
+ if (setup_succeeded && tcase->fixture_persistent && tcase->teardown &&
+ !tcase->teardown(context, tcase->data)) {
+ ret = false;
+ }
+
+ context->active_tcase = NULL;
+ context->active_test = NULL;
+
+ if (context->results->ui_ops->tcase_finish)
+ context->results->ui_ops->tcase_finish(context, tcase);
+
+ return (!setup_succeeded) ? false : ret;
+}
+
+bool torture_run_test(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ return internal_torture_run_test(context, tcase, test, false, NULL);
+}
+
+bool torture_run_test_restricted(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test,
+ const char **restricted)
+{
+ return internal_torture_run_test(context, tcase, test, false, restricted);
+}
+
+int torture_setting_int(struct torture_context *test, const char *name,
+ int default_value)
+{
+ return lpcfg_parm_int(test->lp_ctx, NULL, "torture", name, default_value);
+}
+
+unsigned long torture_setting_ulong(struct torture_context *test,
+ const char *name,
+ unsigned long default_value)
+{
+ return lpcfg_parm_ulong(test->lp_ctx, NULL, "torture", name,
+ default_value);
+}
+
+double torture_setting_double(struct torture_context *test, const char *name,
+ double default_value)
+{
+ return lpcfg_parm_double(test->lp_ctx, NULL, "torture", name, default_value);
+}
+
+bool torture_setting_bool(struct torture_context *test, const char *name,
+ bool default_value)
+{
+ return lpcfg_parm_bool(test->lp_ctx, NULL, "torture", name, default_value);
+}
+
+const char *torture_setting_string(struct torture_context *test,
+ const char *name,
+ const char *default_value)
+{
+ const char *ret;
+
+ SMB_ASSERT(test != NULL);
+ SMB_ASSERT(test->lp_ctx != NULL);
+
+ ret = lpcfg_parm_string(test->lp_ctx, NULL, "torture", name);
+
+ if (ret == NULL)
+ return default_value;
+
+ return ret;
+}
+
+static bool wrap_test_with_simple_tcase_const (
+ struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, const void *tcase_data);
+
+ fn = test->fn;
+
+ return fn(torture_ctx, test->data);
+}
+
+struct torture_tcase *torture_suite_add_simple_tcase_const(
+ struct torture_suite *suite, const char *name,
+ bool (*run) (struct torture_context *test, const void *),
+ const void *data)
+{
+ struct torture_tcase *tcase;
+ struct torture_test *test;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_test_with_simple_tcase_const;
+ test->fn = run;
+ test->data = data;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+ test->tcase = tcase;
+
+ return tcase;
+}
+
+static bool wrap_simple_test(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *);
+
+ fn = test->fn;
+
+ return fn(torture_ctx);
+}
+
+struct torture_tcase *torture_suite_add_simple_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *test))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_simple_test;
+ test->fn = run;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return tcase;
+}
+
+/**
+ * Add a child testsuite to a testsuite.
+ */
+bool torture_suite_add_suite(struct torture_suite *suite,
+ struct torture_suite *child)
+{
+ if (child == NULL)
+ return false;
+
+ DLIST_ADD_END(suite->children, child);
+ child->parent = suite;
+
+ /* FIXME: Check for duplicates and return false if the
+ * added suite already exists as a child */
+
+ return true;
+}
+
+/**
+ * Find the child testsuite with the specified name.
+ */
+struct torture_suite *torture_find_suite(struct torture_suite *parent,
+ const char *name)
+{
+ struct torture_suite *child;
+
+ for (child = parent->children; child; child = child->next)
+ if (!strcmp(child->name, name))
+ return child;
+
+ return NULL;
+}
+
+static bool wrap_test_with_simple_test_const(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, const void *tcase_data);
+
+ fn = test->fn;
+
+ return fn(torture_ctx, tcase->data);
+}
+
+struct torture_test *torture_tcase_add_simple_test_const(
+ struct torture_tcase *tcase,
+ const char *name,
+ bool (*run) (struct torture_context *test,
+ const void *tcase_data))
+{
+ struct torture_test *test;
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_test_with_simple_test_const;
+ test->fn = run;
+ test->data = NULL;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+static bool wrap_test_with_simple_test(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, void *tcase_data);
+
+ fn = test->fn;
+
+ return fn(torture_ctx, tcase->data);
+}
+
+struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase,
+ const char *name,
+ bool (*run) (struct torture_context *test, void *tcase_data))
+{
+ struct torture_test *test;
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_test_with_simple_test;
+ test->fn = run;
+ test->data = NULL;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+void torture_ui_report_time(struct torture_context *context)
+{
+ if (context->results->ui_ops->report_time)
+ context->results->ui_ops->report_time(context);
+}
diff --git a/lib/torture/torture.h b/lib/torture/torture.h
new file mode 100644
index 0000000..2e86e31
--- /dev/null
+++ b/lib/torture/torture.h
@@ -0,0 +1,874 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture UI functions
+
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TORTURE_UI_H__
+#define __TORTURE_UI_H__
+
+struct torture_test;
+struct torture_context;
+struct torture_suite;
+struct torture_tcase;
+struct torture_results;
+
+/*
+ * Arranged in precedence order. TORTURE_ERROR has the highest priority;
+ * TORTURE_OK the lowest.
+ */
+enum torture_result {
+ TORTURE_OK=0,
+ TORTURE_SKIP=1,
+ TORTURE_FAIL=2,
+ TORTURE_ERROR=3
+};
+
+enum torture_progress_whence {
+ TORTURE_PROGRESS_SET,
+ TORTURE_PROGRESS_CUR,
+ TORTURE_PROGRESS_POP,
+ TORTURE_PROGRESS_PUSH,
+};
+
+/*
+ * These callbacks should be implemented by any backend that wishes
+ * to listen to reports from the torture tests.
+ */
+struct torture_ui_ops
+{
+ void (*init) (struct torture_results *);
+ void (*comment) (struct torture_context *, const char *);
+ void (*warning) (struct torture_context *, const char *);
+ void (*suite_start) (struct torture_context *, struct torture_suite *);
+ void (*suite_finish) (struct torture_context *, struct torture_suite *);
+ void (*tcase_start) (struct torture_context *, struct torture_tcase *);
+ void (*tcase_finish) (struct torture_context *, struct torture_tcase *);
+ void (*test_start) (struct torture_context *,
+ struct torture_tcase *,
+ struct torture_test *);
+ void (*test_result) (struct torture_context *,
+ enum torture_result, const char *reason);
+ void (*progress) (struct torture_context *, int offset, enum torture_progress_whence whence);
+ void (*report_time) (struct torture_context *);
+};
+
+void torture_ui_test_start(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test);
+
+void torture_ui_test_result(struct torture_context *context,
+ enum torture_result result,
+ const char *comment);
+
+void torture_ui_report_time(struct torture_context *context);
+
+/*
+ * Holds information about a specific run of the testsuite.
+ * The data in this structure should be considered private to
+ * the torture tests and should only be used directly by the torture
+ * code and the ui backends.
+ *
+ * Torture tests should instead call the torture_*() macros and functions
+ * specified below.
+ */
+
+struct torture_subunit_prefix {
+ const struct torture_subunit_prefix *parent;
+ char subunit_prefix[256];
+};
+
+struct torture_context
+{
+ struct torture_results *results;
+
+ struct torture_test *active_test;
+ struct torture_tcase *active_tcase;
+ struct torture_subunit_prefix _initial_prefix;
+ const struct torture_subunit_prefix *active_prefix;
+
+ enum torture_result last_result;
+ char *last_reason;
+
+ /** Directory used for temporary test data */
+ const char *outputdir;
+
+ /** Event context */
+ struct tevent_context *ev;
+
+ /** Loadparm context (will go away in favor of torture_setting_ at some point) */
+ struct loadparm_context *lp_ctx;
+
+ int conn_index;
+};
+
+struct torture_results
+{
+ const struct torture_ui_ops *ui_ops;
+ void *ui_data;
+
+ /** Whether tests should avoid writing output to stdout */
+ bool quiet;
+
+ bool returncode;
+};
+
+/*
+ * Describes a particular torture test
+ */
+struct torture_test {
+ /** Short unique name for the test. */
+ const char *name;
+
+ /** Long description for the test. */
+ const char *description;
+
+ /** Whether this is a dangerous test
+ * (can corrupt the remote servers data or bring it down). */
+ bool dangerous;
+
+ /** Function to call to run this test */
+ bool (*run) (struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test);
+
+ struct torture_test *prev, *next;
+
+ /** Pointer to the actual test function. This is run by the
+ * run() function above. */
+ void *fn;
+
+ /** Use data for this test */
+ const void *data;
+
+ struct torture_tcase *tcase;
+};
+
+/*
+ * Describes a particular test case.
+ */
+struct torture_tcase {
+ const char *name;
+ const char *description;
+ bool (*setup) (struct torture_context *tcase, void **data);
+ bool (*teardown) (struct torture_context *tcase, void *data);
+ bool fixture_persistent;
+ void *data;
+ struct torture_test *tests;
+ struct torture_tcase *prev, *next;
+ const struct torture_suite *suite;
+};
+
+struct torture_suite
+{
+ const char *name;
+ const char *description;
+ struct torture_tcase *testcases;
+ struct torture_suite *children;
+ const struct torture_suite *parent;
+
+ /* Pointers to siblings of this torture suite */
+ struct torture_suite *prev, *next;
+};
+
+/** Create a new torture suite */
+struct torture_suite *torture_suite_create(TALLOC_CTX *mem_ctx,
+ const char *name);
+
+/** Change the setup and teardown functions for a testcase */
+void torture_tcase_set_fixture(struct torture_tcase *tcase,
+ bool (*setup) (struct torture_context *, void **),
+ bool (*teardown) (struct torture_context *, void *));
+
+/* Add another test to run for a particular testcase */
+struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase,
+ const char *name,
+ bool (*run) (struct torture_context *test,
+ const void *tcase_data, const void *test_data),
+ const void *test_data);
+
+/* Add a testcase to a testsuite */
+struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite,
+ const char *name);
+
+/* Convenience wrapper that adds a testcase against only one
+ * test will be run */
+struct torture_tcase *torture_suite_add_simple_tcase_const(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *test,
+ const void *test_data),
+ const void *data);
+
+/* Convenience function that adds a test which only
+ * gets the test case data */
+struct torture_test *torture_tcase_add_simple_test_const(
+ struct torture_tcase *tcase,
+ const char *name,
+ bool (*run) (struct torture_context *test,
+ const void *tcase_data));
+
+/* Convenience wrapper that adds a test that doesn't need any
+ * testcase data */
+struct torture_tcase *torture_suite_add_simple_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *test));
+
+/* Add a child testsuite to an existing testsuite */
+bool torture_suite_add_suite(struct torture_suite *suite,
+ struct torture_suite *child);
+
+char *torture_subunit_test_name(struct torture_context *ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test);
+void torture_subunit_prefix_reset(struct torture_context *ctx,
+ const char *name);
+
+/* Run the specified testsuite recursively */
+bool torture_run_suite(struct torture_context *context,
+ struct torture_suite *suite);
+
+/* Run the specified testsuite recursively, but only the specified
+ * tests */
+bool torture_run_suite_restricted(struct torture_context *context,
+ struct torture_suite *suite, const char **restricted);
+
+/* Run the specified testcase */
+bool torture_run_tcase(struct torture_context *context,
+ struct torture_tcase *tcase);
+
+bool torture_run_tcase_restricted(struct torture_context *context,
+ struct torture_tcase *tcase, const char **restricted);
+
+/* Run the specified test */
+bool torture_run_test(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test);
+
+bool torture_run_test_restricted(struct torture_context *context,
+ struct torture_tcase *tcase,
+ struct torture_test *test,
+ const char **restricted);
+
+void torture_comment(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3);
+void torture_warning(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3);
+void torture_result(struct torture_context *test,
+ enum torture_result, const char *reason, ...) PRINTF_ATTRIBUTE(3,4);
+
+#define torture_assert(torture_ctx,expr,cmt) do { \
+ if (!(expr)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": Expression `%s' failed: %s", __STRING(expr), cmt); \
+ return false; \
+ } \
+} while(0)
+
+#define torture_assertf(torture_ctx, expr, format, ...) do { \
+ if (!(expr)) { \
+ char *_msg = talloc_asprintf(torture_ctx, \
+ format, \
+ __VA_ARGS__); \
+ torture_result(torture_ctx, \
+ TORTURE_FAIL, \
+ __location__": Expression `%s' failed: %s", \
+ __STRING(expr), _msg); \
+ talloc_free(_msg); \
+ return false; \
+ } \
+} while(0)
+
+#define torture_assert_goto(torture_ctx,expr,ret,label,cmt) do { \
+ if (!(expr)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": Expression `%s' failed: %s", __STRING(expr), cmt); \
+ ret = false; \
+ goto label; \
+ } \
+} while(0)
+
+#define torture_assert_werr_equal(torture_ctx, got, expected, cmt) \
+ do { WERROR __got = got, __expected = expected; \
+ if (!W_ERROR_EQUAL(__got, __expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", win_errstr(__got), win_errstr(__expected), cmt); \
+ return false; \
+ } \
+ } while (0)
+
+#define torture_assert_werr_equal_goto(torture_ctx, got, expected, ret, label, cmt) \
+ do { WERROR __got = got, __expected = expected; \
+ if (!W_ERROR_EQUAL(__got, __expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", win_errstr(__got), win_errstr(__expected), cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while (0)
+
+#define torture_assert_ntstatus_equal(torture_ctx,got,expected,cmt) \
+ do { NTSTATUS __got = got, __expected = expected; \
+ if (!NT_STATUS_EQUAL(__got, __expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", nt_errstr(__got), nt_errstr(__expected), cmt); \
+ return false; \
+ }\
+ } while(0)
+
+#define torture_assert_ntstatus_equal_goto(torture_ctx,got,expected,ret,label,cmt) \
+ do { NTSTATUS __got = got, __expected = expected; \
+ if (!NT_STATUS_EQUAL(__got, __expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", nt_errstr(__got), nt_errstr(__expected), cmt); \
+ ret = false; \
+ goto label; \
+ }\
+ } while(0)
+
+#define torture_assert_ndr_err_equal(torture_ctx,got,expected,cmt) \
+ do { enum ndr_err_code __got = got, __expected = expected; \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %d (%s), expected %d (%s): %s", __got, ndr_errstr(__got), __expected, __STRING(expected), cmt); \
+ return false; \
+ }\
+ } while(0)
+
+#define torture_assert_ndr_err_equal_goto(torture_ctx,got,expected,ret,label,cmt) \
+ do { enum ndr_err_code __got = got, __expected = expected; \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %d (%s), expected %d (%s): %s", __got, ndr_errstr(__got), __expected, __STRING(expected), cmt); \
+ ret = false; \
+ goto label; \
+ }\
+ } while(0)
+
+#define torture_assert_hresult_equal(torture_ctx, got, expected, cmt) \
+ do { HRESULT __got = got, __expected = expected; \
+ if (!HRES_IS_EQUAL(__got, __expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", hresult_errstr(__got), hresult_errstr(__expected), cmt); \
+ return false; \
+ } \
+ } while (0)
+
+#define torture_assert_krb5_error_equal(torture_ctx, got, expected, cmt) \
+ do { krb5_error_code __got = got, __expected = expected; \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %d (%s), expected %d (%s): %s", __got, error_message(__got), __expected, error_message(__expected), cmt); \
+ return false; \
+ } \
+ } while (0)
+
+#define torture_assert_casestr_equal(torture_ctx,got,expected,cmt) \
+ do { const char *__got = (got), *__expected = (expected); \
+ if (!strequal(__got, __expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %s, expected %s: %s", \
+ __got, __expected == NULL ? "null" : __expected, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_str_equal(torture_ctx,got,expected,cmt)\
+ do { const char *__got = (got), *__expected = (expected); \
+ if (strcmp_safe(__got, __expected) != 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %s, expected %s: %s", \
+ __got, __expected == NULL ? "NULL" : __expected, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_strn_equal(torture_ctx,got,expected,len,cmt)\
+ do { const char *__got = (got), *__expected = (expected); \
+ if (strncmp(__got, __expected, len) != 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" %s of len %d did not match "#expected" %s: %s", \
+ __got, (int)len, __expected, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_str_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
+ do { const char *__got = (got), *__expected = (expected); \
+ if (strcmp_safe(__got, __expected) != 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %s, expected %s: %s", \
+ __got, __expected, cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_mem_equal(torture_ctx,got,expected,len,cmt)\
+ do { const void *__got = (got), *__expected = (expected); \
+ if (memcmp(__got, __expected, len) != 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" of len %d did not match "#expected": %s", (int)len, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_mem_equal_goto(torture_ctx,got,expected,len,ret,label,cmt) \
+ do { const void *__got = (got), *__expected = (expected); \
+ if (memcmp(__got, __expected, len) != 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" of len %d did not match "#expected": %s", (int)len, cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_mem_not_equal_goto(torture_ctx,got,expected,len,ret,label,cmt) \
+ do { const void *__got = (got), *__expected = (expected); \
+ if (memcmp(__got, __expected, len) == 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" of len %d unexpectedly matches "#expected": %s", (int)len, cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+static inline void torture_dump_data_str_cb(const char *buf, void *private_data)
+{
+ char **dump = (char **)private_data;
+ *dump = talloc_strdup_append_buffer(*dump, buf);
+}
+
+#define torture_assert_data_blob_equal(torture_ctx,got,expected,cmt)\
+ do { const DATA_BLOB __got = (got), __expected = (expected); \
+ if (__got.length != __expected.length) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got".len %d did not match "#expected" len %d: %s", \
+ (int)__got.length, (int)__expected.length, cmt); \
+ return false; \
+ } \
+ if (memcmp(__got.data, __expected.data, __got.length) != 0) { \
+ char *__dump = NULL; \
+ uint8_t __byte_a = 0x00;\
+ uint8_t __byte_b = 0x00;\
+ size_t __i;\
+ for (__i=0; __i < __expected.length; __i++) {\
+ __byte_a = __expected.data[__i];\
+ if (__i == __got.length) {\
+ __byte_b = 0x00;\
+ break;\
+ }\
+ __byte_b = __got.data[__i];\
+ if (__byte_a != __byte_b) {\
+ break;\
+ }\
+ }\
+ torture_warning(torture_ctx, "blobs differ at byte 0x%02X (%zu)", (unsigned int)__i, __i);\
+ torture_warning(torture_ctx, "expected byte[0x%02X] = 0x%02X got byte[0x%02X] = 0x%02X",\
+ (unsigned int)__i, __byte_a, (unsigned int)__i, __byte_b);\
+ __dump = talloc_strdup(torture_ctx, ""); \
+ dump_data_cb(__got.data, __got.length, true, \
+ torture_dump_data_str_cb, &__dump); \
+ torture_warning(torture_ctx, "got[0x%02X]: \n%s", \
+ (unsigned int)__got.length, __dump); \
+ TALLOC_FREE(__dump); \
+ __dump = talloc_strdup(torture_ctx, ""); \
+ dump_data_cb(__expected.data, __expected.length, true, \
+ torture_dump_data_str_cb, &__dump); \
+ torture_warning(torture_ctx, "expected[0x%02X]: \n%s", \
+ (int)__expected.length, __dump); \
+ TALLOC_FREE(__dump); \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" of len %d did not match "#expected": %s", (int)__got.length, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_file_contains_text(torture_ctx,filename,expected,cmt)\
+ do { \
+ char *__got; \
+ const char *__expected = (expected); \
+ size_t __size; \
+ __got = file_load(filename, &__size, 0, torture_ctx); \
+ if (__got == NULL) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": unable to open %s: %s\n", \
+ filename, cmt); \
+ return false; \
+ } \
+ \
+ if (strcmp_safe(__got, __expected) != 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": %s contained:\n%sExpected: %s%s\n", \
+ filename, __got, __expected, cmt); \
+ talloc_free(__got); \
+ return false; \
+ } \
+ talloc_free(__got); \
+ } while(0)
+
+#define torture_assert_file_contains(torture_ctx,filename,expected,cmt)\
+ do { const char *__got, *__expected = (expected); \
+ size_t __size; \
+ __got = file_load(filename, *size, 0, torture_ctx); \
+ if (strcmp_safe(__got, __expected) != 0) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": %s contained:\n%sExpected: %s%s\n", \
+ __got, __expected, cmt); \
+ talloc_free(__got); \
+ return false; \
+ } \
+ talloc_free(__got); \
+ } while(0)
+
+#define torture_assert_int_equal(torture_ctx,got,expected,cmt)\
+ do { int __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected %d (0x%X): %s", \
+ __got, __got, __expected, __expected, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_int_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
+ do { int __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected %d (0x%X): %s", \
+ __got, __got, __expected, __expected, cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_int_not_equal(torture_ctx,got,not_expected,cmt)\
+ do { int __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected a different number: %s", \
+ __got, __got, cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_int_not_equal_goto(torture_ctx,got,not_expected,ret,label,cmt)\
+ do { int __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %d (0x%X), expected a different number: %s", \
+ __got, __got, cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_u32_equal(torture_ctx,got,expected,cmt)\
+ do { uint32_t __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu32" (0x%"PRIX32"), expected %"PRIu32" (0x%"PRIX32"): %s", \
+ __got, __got, \
+ __expected, __expected, \
+ cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_u32_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
+ do { uint32_t __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu32" (0x%"PRIX32"), expected %"PRIu32" (0x%"PRIX32"): %s", \
+ __got, __got, \
+ __expected, __expected, \
+ cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_u32_not_equal(torture_ctx,got,not_expected,cmt)\
+ do { uint32_t __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu32" (0x%"PRIX32"), expected a different number: %s", \
+ __got, __got, \
+ cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_u32_not_equal_goto(torture_ctx,got,not_expected,ret,label,cmt)\
+ do { uint32_t __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu32" (0x%"PRIX32"), expected a different number: %s", \
+ __got, __got, \
+ cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_u64_equal(torture_ctx,got,expected,cmt)\
+ do { uint64_t __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu64" (0x%"PRIX64"), expected %"PRIu64" (0x%"PRIX64"): %s", \
+ __got, __got, \
+ __expected, __expected, \
+ cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_u64_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
+ do { uint64_t __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu64" (0x%"PRIX64"), expected %"PRIu64" (0x%"PRIX64"): %s", \
+ __got, __got, \
+ __expected, __expected, \
+ cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_u64_not_equal(torture_ctx,got,not_expected,cmt)\
+ do { uint64_t __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu64" (0x%"PRIX64"), expected a different number: %s", \
+ __got, __got, \
+ cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_u64_not_equal_goto(torture_ctx,got,not_expected,ret,label,cmt)\
+ do { uint64_t __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %"PRIu64" (0x%"PRIX64"), expected a different number: %s", \
+ __got, __got, \
+ cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_size_equal(torture_ctx,got,expected,cmt)\
+ do { size_t __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %zu (0x%zX), expected %zu (0x%zX): %s", \
+ __got, __got, \
+ __expected, __expected, \
+ cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_size_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
+ do { size_t __got = (got), __expected = (expected); \
+ if (__got != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %zu (0x%zX), expected %zu (0x%zX): %s", \
+ __got, __got, \
+ __expected, __expected, \
+ cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_size_not_equal(torture_ctx,got,not_expected,cmt)\
+ do { size_t __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %zu (0x%zX), expected a different number: %s", \
+ __got, __got, \
+ cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_size_not_equal_goto(torture_ctx,got,not_expected,ret,label,cmt)\
+ do { size_t __got = (got), __not_expected = (not_expected); \
+ if (__got == __not_expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %zu (0x%zX), expected a different number: %s", \
+ __got, __got, \
+ cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_errno_equal(torture_ctx,expected,cmt)\
+ do { int __expected = (expected); \
+ if (errno != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": errno was %d (%s), expected %d: %s: %s", \
+ errno, strerror(errno), __expected, \
+ strerror(__expected), cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_errno_equal_goto(torture_ctx,expected,ret,label,cmt)\
+ do { int __expected = (expected); \
+ if (errno != __expected) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": errno was %d (%s), expected %d: %s: %s", \
+ errno, strerror(errno), __expected, \
+ strerror(__expected), cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_assert_guid_equal(torture_ctx,got,expected,cmt)\
+ do {const struct GUID __got = (got), __expected = (expected); \
+ if (!GUID_equal(&__got, &__expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %s, expected %s: %s", \
+ GUID_string(torture_ctx, &__got), GUID_string(torture_ctx, &__expected), cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_nttime_equal(torture_ctx,got,expected,cmt) \
+ do { NTTIME __got = got, __expected = expected; \
+ if (!nt_time_equal(&__got, &__expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", nt_time_string(torture_ctx, __got), nt_time_string(torture_ctx, __expected), cmt); \
+ return false; \
+ }\
+ } while(0)
+
+#define torture_assert_sid_equal(torture_ctx,got,expected,cmt)\
+ do {const struct dom_sid *__got = (got), *__expected = (expected); \
+ if (!dom_sid_equal(__got, __expected)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was %s, expected %s: %s", \
+ dom_sid_string(torture_ctx, __got), dom_sid_string(torture_ctx, __expected), cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_not_null(torture_ctx,got,cmt)\
+ do {const void *__got = (got); \
+ if (__got == NULL) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was NULL, expected != NULL: %s", \
+ cmt); \
+ return false; \
+ } \
+ } while(0)
+
+#define torture_assert_not_null_goto(torture_ctx,got,ret,label,cmt)\
+ do {const void *__got = (got); \
+ if (__got == NULL) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got" was NULL, expected != NULL: %s", \
+ cmt); \
+ ret = false; \
+ goto label; \
+ } \
+ } while(0)
+
+#define torture_skip(torture_ctx,cmt) do {\
+ torture_result(torture_ctx, TORTURE_SKIP, __location__": %s", cmt);\
+ return true; \
+ } while(0)
+#define torture_skip_goto(torture_ctx,label,cmt) do {\
+ torture_result(torture_ctx, TORTURE_SKIP, __location__": %s", cmt);\
+ goto label; \
+ } while(0)
+#define torture_fail(torture_ctx,cmt) do {\
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\
+ return false; \
+ } while (0)
+#define torture_fail_goto(torture_ctx,label,cmt) do {\
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\
+ goto label; \
+ } while (0)
+
+#define torture_out stderr
+
+/* Convenience macros */
+#define torture_assert_ntstatus_ok(torture_ctx,expr,cmt) \
+ torture_assert_ntstatus_equal(torture_ctx,expr,NT_STATUS_OK,cmt)
+
+#define torture_assert_ntstatus_ok_goto(torture_ctx,expr,ret,label,cmt) \
+ torture_assert_ntstatus_equal_goto(torture_ctx,expr,NT_STATUS_OK,ret,label,cmt)
+
+#define torture_assert_werr_ok(torture_ctx,expr,cmt) \
+ torture_assert_werr_equal(torture_ctx,expr,WERR_OK,cmt)
+
+#define torture_assert_werr_ok_goto(torture_ctx,expr,ret,label,cmt) \
+ torture_assert_werr_equal_goto(torture_ctx,expr,WERR_OK,ret,label,cmt)
+
+#define torture_assert_ndr_success(torture_ctx,expr,cmt) \
+ torture_assert_ndr_err_equal(torture_ctx,expr,NDR_ERR_SUCCESS,cmt)
+
+#define torture_assert_ndr_success_goto(torture_ctx,expr,ret,label,cmt) \
+ torture_assert_ndr_err_equal_goto(torture_ctx,expr,NDR_ERR_SUCCESS,ret,label,cmt)
+
+#define torture_assert_hresult_ok(torture_ctx,expr,cmt) \
+ torture_assert_hresult_equal(torture_ctx,expr,HRES_ERROR(0), cmt)
+
+/* Getting settings */
+const char *torture_setting_string(struct torture_context *test, \
+ const char *name,
+ const char *default_value);
+
+int torture_setting_int(struct torture_context *test,
+ const char *name,
+ int default_value);
+
+double torture_setting_double(struct torture_context *test,
+ const char *name,
+ double default_value);
+
+bool torture_setting_bool(struct torture_context *test,
+ const char *name,
+ bool default_value);
+
+struct torture_suite *torture_find_suite(struct torture_suite *parent,
+ const char *name);
+
+unsigned long torture_setting_ulong(struct torture_context *test,
+ const char *name,
+ unsigned long default_value);
+
+NTSTATUS torture_temp_dir(struct torture_context *tctx,
+ const char *prefix,
+ char **tempdir);
+NTSTATUS torture_deltree_outputdir(struct torture_context *tctx);
+
+struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase,
+ const char *name,
+ bool (*run) (struct torture_context *test, void *tcase_data));
+
+
+bool torture_suite_init_tcase(struct torture_suite *suite,
+ struct torture_tcase *tcase,
+ const char *name);
+int torture_suite_children_count(const struct torture_suite *suite);
+
+struct torture_context *torture_context_init(struct tevent_context *event_ctx, struct torture_results *results);
+
+struct torture_results *torture_results_init(TALLOC_CTX *mem_ctx, const struct torture_ui_ops *ui_ops);
+
+struct torture_context *torture_context_child(struct torture_context *tctx);
+
+extern const struct torture_ui_ops torture_subunit_ui_ops;
+extern const struct torture_ui_ops torture_simple_ui_ops;
+
+#endif /* __TORTURE_UI_H__ */
diff --git a/lib/torture/wscript_build b/lib/torture/wscript_build
new file mode 100644
index 0000000..31c3862
--- /dev/null
+++ b/lib/torture/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('torture',
+ private_library=True,
+ source='torture.c subunit.c simple.c',
+ public_deps='samba-hostconfig samba-util samba-errors talloc tevent',
+ private_headers='torture.h'
+ )
diff --git a/lib/tsocket/doxy.config b/lib/tsocket/doxy.config
new file mode 100644
index 0000000..584ae73
--- /dev/null
+++ b/lib/tsocket/doxy.config
@@ -0,0 +1,1538 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = tsocket
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.cpp \
+ *.cc \
+ *.c \
+ *.h \
+ *.hh \
+ *.hpp \
+ *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */.git/* \
+ */.svn/* \
+ */cmake/* \
+ */build/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will
+# add generated date, project name and doxygen version to HTML footer.
+
+HTML_FOOTER_DESCRIPTION= NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NONE
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/lib/tsocket/tests/socketpair_tcp.c b/lib/tsocket/tests/socketpair_tcp.c
new file mode 100644
index 0000000..251b8bc
--- /dev/null
+++ b/lib/tsocket/tests/socketpair_tcp.c
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "socketpair_tcp.h"
+
+/*******************************************************************
+this is like socketpair but uses tcp. It is used by the Samba
+regression test code
+The function guarantees that nobody else can attach to the socket,
+or if they do that this function fails and the socket gets closed
+returns 0 on success, -1 on failure
+the resulting file descriptors are symmetrical
+ ******************************************************************/
+int socketpair_tcp(int fd[2])
+{
+ int listener;
+ struct sockaddr_in sock;
+ struct sockaddr_in sock2;
+ socklen_t socklen = sizeof(sock);
+ int connect_done = 0;
+
+ fd[0] = fd[1] = listener = -1;
+
+ memset(&sock, 0, sizeof(sock));
+
+ if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ memset(&sock2, 0, sizeof(sock2));
+#ifdef HAVE_SOCK_SIN_LEN
+ sock2.sin_len = sizeof(sock2);
+#endif
+ sock2.sin_family = PF_INET;
+
+ if (bind(listener, (struct sockaddr *)&sock2, sizeof(sock2)) != 0) goto failed;
+
+ if (listen(listener, 1) != 0) goto failed;
+
+ if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
+
+ if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ set_blocking(fd[1], 0);
+
+ sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (connect(fd[1], (struct sockaddr *)&sock, socklen) == -1) {
+ if (errno != EINPROGRESS) goto failed;
+ } else {
+ connect_done = 1;
+ }
+
+ if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
+
+ if (connect_done == 0) {
+ if (connect(fd[1], (struct sockaddr *)&sock, socklen) != 0
+ && errno != EISCONN) goto failed;
+ }
+ close(listener);
+
+ set_blocking(fd[1], 1);
+
+ /* all OK! */
+ return 0;
+
+ failed:
+ if (fd[0] != -1) close(fd[0]);
+ if (fd[1] != -1) close(fd[1]);
+ if (listener != -1) close(listener);
+ return -1;
+}
diff --git a/lib/tsocket/tests/socketpair_tcp.h b/lib/tsocket/tests/socketpair_tcp.h
new file mode 100644
index 0000000..dbee4ef
--- /dev/null
+++ b/lib/tsocket/tests/socketpair_tcp.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*******************************************************************
+this is like socketpair but uses tcp. It is used by the Samba
+regression test code
+The function guarantees that nobody else can attach to the socket,
+or if they do that this function fails and the socket gets closed
+returns 0 on success, -1 on failure
+the resulting file descriptors are symmetrical
+ ******************************************************************/
+int socketpair_tcp(int fd[2]);
diff --git a/lib/tsocket/tests/test_bsd_addr.c b/lib/tsocket/tests/test_bsd_addr.c
new file mode 100644
index 0000000..ac6e798
--- /dev/null
+++ b/lib/tsocket/tests/test_bsd_addr.c
@@ -0,0 +1,369 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2021 Uri Simchoni <uri@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cmocka.h>
+#include <tsocket.h>
+
+static int setup(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ assert_non_null(mem_ctx);
+ *state = mem_ctx;
+
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ TALLOC_FREE(mem_ctx);
+
+ return 0;
+}
+
+static void test_address_inet_from_strings(void **state)
+{
+ int rc = 0;
+ int save_errno;
+ TALLOC_CTX *mem_ctx = *state;
+ struct tsocket_address *addr = NULL;
+ char *addr_s = NULL;
+
+ /*
+ * Unspecified IP family, given an IPv4 address
+ */
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ip", "1.2.3.4", 1234,
+ &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv4:1.2.3.4:1234");
+ assert_true(tsocket_address_is_inet(addr, "ip"));
+ assert_true(tsocket_address_is_inet(addr, "ipv4"));
+ assert_false(tsocket_address_is_inet(addr, "ipv6"));
+ assert_int_equal(tsocket_address_inet_port(addr), 1234);
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * Expecting IPv4, given an IPv4 address
+ */
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ipv4", "1.2.3.4", 1234,
+ &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv4:1.2.3.4:1234");
+ assert_true(tsocket_address_is_inet(addr, "ip"));
+ assert_true(tsocket_address_is_inet(addr, "ipv4"));
+ assert_false(tsocket_address_is_inet(addr, "ipv6"));
+ assert_int_equal(tsocket_address_inet_port(addr), 1234);
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * Expecting IPv6, given an IPv4 address
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ipv6", "1.2.3.4", 1234,
+ &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * Unspecified IP family, given an IPv6 address
+ */
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ip", "2001::1", 1234,
+ &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv6:2001::1:1234");
+ assert_true(tsocket_address_is_inet(addr, "ip"));
+ assert_false(tsocket_address_is_inet(addr, "ipv4"));
+ assert_true(tsocket_address_is_inet(addr, "ipv6"));
+ assert_int_equal(tsocket_address_inet_port(addr), 1234);
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * Expecting IPv4, given an IPv6 address
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ipv4", "2001::1", 1234,
+ &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * expecting IPv6, given an IPv6 address
+ */
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ipv6", "2001::1", 1234,
+ &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv6:2001::1:1234");
+ assert_true(tsocket_address_is_inet(addr, "ip"));
+ assert_false(tsocket_address_is_inet(addr, "ipv4"));
+ assert_true(tsocket_address_is_inet(addr, "ipv6"));
+ assert_int_equal(tsocket_address_inet_port(addr), 1234);
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * Unspecified IP family, given an illegal address
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ip", "localhost", 1234,
+ &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * Illegal IP family
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ipx", "1.2.3.4", 1234,
+ &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * Unspecified IP family, given NULL, verify it returns something
+ */
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ip", NULL, 1234,
+ &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ TALLOC_FREE(addr);
+
+ /*
+ * IPv4, given NULL, verify it returns 0.0.0.0
+ */
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ipv4", NULL, 1234,
+ &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv4:0.0.0.0:1234");
+ assert_true(tsocket_address_is_inet(addr, "ip"));
+ assert_true(tsocket_address_is_inet(addr, "ipv4"));
+ assert_false(tsocket_address_is_inet(addr, "ipv6"));
+ assert_int_equal(tsocket_address_inet_port(addr), 1234);
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * IPv6, given NULL, verify it returns ::
+ */
+ rc = tsocket_address_inet_from_strings(mem_ctx, "ipv6", NULL, 1234,
+ &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv6::::1234");
+ assert_true(tsocket_address_is_inet(addr, "ip"));
+ assert_false(tsocket_address_is_inet(addr, "ipv4"));
+ assert_true(tsocket_address_is_inet(addr, "ipv6"));
+ assert_int_equal(tsocket_address_inet_port(addr), 1234);
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+}
+
+static void test_address_inet_from_hostport_strings(void **state)
+{
+ int rc = 0;
+ int save_errno;
+ TALLOC_CTX *mem_ctx = *state;
+ struct tsocket_address *addr = NULL;
+ char *addr_s = NULL;
+
+ /*
+ * IPv4 host:port
+ */
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "1.2.3.4:5678", 1234, &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv4:1.2.3.4:5678");
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * IPv4 host
+ */
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "1.2.3.4", 1234, &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv4:1.2.3.4:1234");
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * IPv6 [host]:port
+ */
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "[2001::1]:5678", 1234, &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv6:2001::1:5678");
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * IPv6 [host]
+ */
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "[2001::1]", 1234, &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv6:2001::1:1234");
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * IPv6 host
+ */
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "2001::1", 1234, &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv6:2001::1:1234");
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * Given NULL, verify it returns something
+ */
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ipv6", NULL, 1234, &addr);
+ assert_return_code(rc, errno);
+ assert_non_null(addr);
+ addr_s = tsocket_address_string(addr, mem_ctx);
+ assert_non_null(addr_s);
+ assert_string_equal(addr_s, "ipv6::::1234");
+ TALLOC_FREE(addr);
+ TALLOC_FREE(addr_s);
+
+ /*
+ * [host]grarbage
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "[2001::1]garbage", 1234, &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * [host]:grarbage
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "[2001::1]:garbage", 1234, &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * host:grarbage
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "1.2.3.4:garbage", 1234, &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * [host]:<port-too-large>
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "[2001::1]:100000", 1234, &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+
+ /*
+ * host:<port-too-large>
+ */
+ errno = 0;
+ rc = tsocket_address_inet_from_hostport_strings(
+ mem_ctx, "ip", "1.2.3.4:100000", 1234, &addr);
+ save_errno = errno;
+ assert_int_equal(rc, -1);
+ assert_int_not_equal(save_errno, 0);
+ assert_null(addr);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_address_inet_from_strings),
+ cmocka_unit_test(test_address_inet_from_hostport_strings),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, setup, teardown);
+
+ return rc;
+}
diff --git a/lib/tsocket/tests/test_tstream.c b/lib/tsocket/tests/test_tstream.c
new file mode 100644
index 0000000..47008bb
--- /dev/null
+++ b/lib/tsocket/tests/test_tstream.c
@@ -0,0 +1,517 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2022 Andrew Bartlett <abartlet@samba.org>
+ * Copyright (C) 2021 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include "includes.h"
+#include "system/network.h"
+#include "socketpair_tcp.h"
+#include "tsocket.h"
+
+enum socket_pair_selector {
+ SOCKET_SERVER = 0,
+ SOCKET_CLIENT = 1,
+};
+
+struct socket_pair {
+ struct tevent_context *ev;
+ int socket_server;
+ int socket_client;
+
+ /* for tstream tests */
+ int rc;
+ int sys_errno;
+ int expected_errno;
+ struct timeval endtime;
+ size_t max_loops;
+ size_t num_loops;
+};
+
+/* If this is too large, we get EPIPE rather than EAGAIN */
+static const uint8_t TEST_STRING[128] = { 0 };
+
+static int sigpipe_setup(void **state)
+{
+ BlockSignals(true, SIGPIPE);
+ return 0;
+}
+
+static int setup_socketpair_tcp_context(void **state)
+{
+ int fd[2];
+ struct socket_pair *sp = talloc_zero(NULL, struct socket_pair);
+ assert_non_null(sp);
+
+ /* Set up a socketpair over TCP to test with */
+ assert_return_code(socketpair_tcp(fd), errno);
+
+ sp->socket_server = fd[SOCKET_SERVER];
+ sp->socket_client = fd[SOCKET_CLIENT];
+
+ sp->ev = tevent_context_init(sp);
+ assert_non_null(sp->ev);
+
+ *state = sp;
+ return 0;
+}
+
+static int setup_socketpair_context(void **state)
+{
+ int fd[2];
+ struct socket_pair *sp = talloc_zero(NULL, struct socket_pair);
+ assert_non_null(sp);
+
+ /* Set up a socketpair over TCP to test with */
+ assert_return_code(socketpair(AF_UNIX, SOCK_STREAM, 0, fd), errno);
+
+ sp->socket_server = fd[SOCKET_SERVER];
+ sp->socket_client = fd[SOCKET_CLIENT];
+
+ sp->ev = tevent_context_init(sp);
+ assert_non_null(sp->ev);
+
+ *state = sp;
+ return 0;
+}
+
+static int teardown_socketpair_context(void **state)
+{
+ struct socket_pair *sp = *state;
+ struct socket_pair sp_save = *sp;
+
+ TALLOC_FREE(sp);
+
+ /*
+ * Close these after the TALLOC_FREE() to allow clean shutdown
+ * of epoll() in tstream
+ */
+ if (sp_save.socket_client != -1) {
+ close(sp_save.socket_client);
+ }
+ if (sp_save.socket_server != -1) {
+ close(sp_save.socket_server);
+ }
+ return 0;
+}
+
+
+/* Test socket behaviour */
+static void test_simple_socketpair(void **state) {
+
+ struct socket_pair *sp = *state;
+
+ char buf[sizeof(TEST_STRING)];
+
+ assert_int_equal(write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING)),
+ sizeof(TEST_STRING));
+ assert_int_equal(read(sp->socket_client, buf, sizeof(buf)),
+ sizeof(buf));
+
+
+}
+
+/* Test socket behaviour */
+static void test_read_client_after_close_server_socket(void **state) {
+
+ struct socket_pair *sp = *state;
+ int rc;
+ char buf[sizeof(TEST_STRING)];
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(TEST_STRING));
+
+ assert_return_code(close(sp->socket_server), 0);
+
+ rc = read(sp->socket_client, buf, sizeof(buf));
+
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(buf));
+}
+
+static void test_write_server_after_close_client_socket(void **state) {
+
+ struct socket_pair *sp = *state;
+ int rc;
+
+ assert_return_code(close(sp->socket_client), 0);
+ sp->socket_client = -1;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(TEST_STRING));
+}
+
+static void test_fill_socket(int sock)
+{
+ size_t num_busy = 0;
+ int rc;
+
+ while (true) {
+ rc = write(sock, TEST_STRING, sizeof(TEST_STRING));
+ if (rc == -1 && errno == EAGAIN) {
+ /*
+ * This makes sure we write until we get a whole second
+ * only with EAGAIN every 50 ms (20 times)
+ *
+ * Otherwise the tests are not reliable...
+ */
+ num_busy++;
+ if (num_busy > 20) {
+ break;
+ }
+ smb_msleep(50);
+ continue;
+ }
+ /* try again next time */
+ num_busy = 0;
+ }
+
+ assert_int_equal(rc, -1);
+ assert_int_equal(errno, EAGAIN);
+}
+
+static void test_big_write_server(void **state) {
+
+ struct socket_pair *sp = *state;
+ int rc;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(TEST_STRING));
+
+ rc = set_blocking(sp->socket_server, 0);
+ assert_return_code(rc, errno);
+
+ test_fill_socket(sp->socket_server);
+}
+
+static void test_big_write_server_close_write(void **state) {
+
+ struct socket_pair *sp = *state;
+ int rc;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(TEST_STRING));
+
+ rc = set_blocking(sp->socket_server, 0);
+ assert_return_code(rc, errno);
+
+ test_fill_socket(sp->socket_server);
+
+ assert_return_code(close(sp->socket_client), 0);
+ sp->socket_client = -1;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_int_equal(errno, ECONNRESET);
+
+}
+
+static void test_big_write_server_shutdown_wr_write(void **state) {
+
+ struct socket_pair *sp = *state;
+ int rc;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(TEST_STRING));
+
+ rc = set_blocking(sp->socket_server, 0);
+ assert_return_code(rc, errno);
+
+ test_fill_socket(sp->socket_server);
+
+ assert_return_code(shutdown(sp->socket_client, SHUT_WR), 0);
+ sp->socket_client = -1;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_int_equal(rc, -1);
+ assert_int_equal(errno, EAGAIN);
+}
+
+static void test_big_write_server_shutdown_rd_write(void **state) {
+
+ struct socket_pair *sp = *state;
+ int rc;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(TEST_STRING));
+
+ rc = set_blocking(sp->socket_server, 0);
+ assert_return_code(rc, errno);
+
+ test_fill_socket(sp->socket_server);
+
+ assert_return_code(shutdown(sp->socket_client, SHUT_RD), 0);
+ sp->socket_client = -1;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_int_equal(rc, -1);
+ assert_int_equal(errno, EAGAIN);
+}
+
+static void test_call_writev_done(struct tevent_req *subreq)
+{
+ struct socket_pair *sp =
+ tevent_req_callback_data(subreq,
+ struct socket_pair);
+ int rc;
+
+ rc = tstream_writev_recv(subreq, &sp->sys_errno);
+ TALLOC_FREE(subreq);
+
+ sp->rc = rc;
+}
+
+static void test_tstream_server_spin_client_shutdown(struct socket_pair *sp)
+{
+ int rc;
+
+ rc = shutdown(sp->socket_client, SHUT_WR);
+ assert_return_code(rc, errno);
+ /*
+ * It should only take a few additional loop to realise that this socket is
+ * in CLOSE_WAIT
+ */
+ sp->max_loops = sp->num_loops + 2;
+ sp->expected_errno = ECONNRESET;
+}
+
+static void test_tstream_server_spin_client_write(struct socket_pair *sp)
+{
+ int rc;
+ int timeout = 5000;
+
+ sp->endtime = timeval_current_ofs_msec(timeout);
+
+ rc = write(sp->socket_client, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ sp->expected_errno = ETIMEDOUT;
+}
+
+static void test_tstream_server_spin_client_tcp_user_timeout(struct socket_pair *sp)
+{
+ int rc;
+ int timeout = 5000;
+
+ rc = setsockopt(sp->socket_server, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout));
+ assert_return_code(rc, errno);
+
+ rc = write(sp->socket_client, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ sp->expected_errno = ETIMEDOUT;
+ sp->max_loops = 30;
+}
+
+static void test_tstream_server_spin_client_both_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct socket_pair *sp =
+ talloc_get_type_abort(private_data,
+ struct socket_pair);
+
+ test_tstream_server_spin_client_shutdown(sp);
+}
+
+static void test_tstream_server_spin_client_both(struct socket_pair *sp)
+{
+ struct tevent_timer *te = NULL;
+ struct timeval endtime;
+
+ test_tstream_server_spin_client_write(sp);
+
+ endtime = timeval_current_ofs_msec(2500);
+
+ te = tevent_add_timer(sp->ev,
+ sp,
+ endtime,
+ test_tstream_server_spin_client_both_timer,
+ sp);
+ assert_non_null(te);
+ sp->expected_errno = ENXIO;
+}
+
+static void test_tstream_server_spin(struct socket_pair *sp,
+ void (*client_fn)(struct socket_pair *sp))
+{
+ struct tstream_context *stream = NULL;
+ struct tevent_req *req = NULL;
+ struct iovec iov;
+ int rc;
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_return_code(rc, errno);
+ assert_int_equal(rc, sizeof(TEST_STRING));
+
+ rc = set_blocking(sp->socket_server, 0);
+ assert_return_code(rc, errno);
+
+ test_fill_socket(sp->socket_server);
+
+ /*
+ * by default we don't expect more then 2 loop iterations
+ * for a timeout of 5 seconds.
+ */
+ sp->max_loops = 10;
+
+ client_fn(sp);
+
+ rc = write(sp->socket_server, TEST_STRING, sizeof(TEST_STRING));
+ assert_int_equal(rc, -1);
+ assert_int_equal(errno, EAGAIN);
+
+ /* OK, so we now know the socket is in CLOSE_WAIT */
+
+ rc = tstream_bsd_existing_socket(sp->ev, sp->socket_server, &stream);
+ assert_return_code(rc, errno);
+ sp->socket_server = -1;
+
+ iov.iov_base = discard_const_p(char, TEST_STRING);
+ iov.iov_len = sizeof(TEST_STRING);
+
+ req = tstream_writev_send(stream, sp->ev, stream, &iov, 1);
+ assert_non_null(req);
+ if (!timeval_is_zero(&sp->endtime)) {
+ assert_true(tevent_req_set_endtime(req, sp->ev, sp->endtime));
+ }
+ tevent_req_set_callback(req, test_call_writev_done, sp);
+
+ while (tevent_req_is_in_progress(req)) {
+ if (sp->num_loops >= sp->max_loops) {
+ assert_int_not_equal(sp->num_loops, sp->max_loops);
+ assert_int_equal(sp->num_loops, sp->max_loops);
+ }
+ sp->num_loops += 1;
+
+ rc = tevent_loop_once(sp->ev);
+ assert_int_equal(rc, 0);
+ }
+
+ assert_int_equal(sp->rc, -1);
+ assert_int_equal(sp->sys_errno, sp->expected_errno);
+ return;
+}
+
+/*
+ * We need two names to run this with the two different setup
+ * routines
+ */
+static void test_tstream_disconnected_tcp_client_spin(void **state)
+{
+ struct socket_pair *sp = *state;
+ test_tstream_server_spin(sp, test_tstream_server_spin_client_shutdown);
+}
+
+static void test_tstream_disconnected_unix_client_spin(void **state)
+{
+ struct socket_pair *sp = *state;
+ test_tstream_server_spin(sp, test_tstream_server_spin_client_shutdown);
+}
+
+static void test_tstream_more_tcp_client_spin(void **state)
+{
+ struct socket_pair *sp = *state;
+ test_tstream_server_spin(sp, test_tstream_server_spin_client_write);
+}
+
+static void test_tstream_more_unix_client_spin(void **state)
+{
+ struct socket_pair *sp = *state;
+ test_tstream_server_spin(sp, test_tstream_server_spin_client_write);
+}
+
+static void test_tstream_more_disconnect_tcp_client_spin(void **state)
+{
+ struct socket_pair *sp = *state;
+ test_tstream_server_spin(sp, test_tstream_server_spin_client_both);
+}
+
+static void test_tstream_more_disconnect_unix_client_spin(void **state)
+{
+ struct socket_pair *sp = *state;
+ test_tstream_server_spin(sp, test_tstream_server_spin_client_both);
+}
+
+static void test_tstream_more_tcp_user_timeout_spin(void **state)
+{
+ struct socket_pair *sp = *state;
+ if (socket_wrapper_enabled()) {
+ skip();
+ }
+ test_tstream_server_spin(sp, test_tstream_server_spin_client_tcp_user_timeout);
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_simple_socketpair,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_read_client_after_close_server_socket,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_write_server_after_close_client_socket,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_big_write_server,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_big_write_server_close_write,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_big_write_server_shutdown_wr_write,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_big_write_server_shutdown_rd_write,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_tstream_disconnected_tcp_client_spin,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_tstream_disconnected_unix_client_spin,
+ setup_socketpair_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_tstream_more_tcp_client_spin,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_tstream_more_unix_client_spin,
+ setup_socketpair_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_tstream_more_disconnect_tcp_client_spin,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_tstream_more_disconnect_unix_client_spin,
+ setup_socketpair_context,
+ teardown_socketpair_context),
+ cmocka_unit_test_setup_teardown(test_tstream_more_tcp_user_timeout_spin,
+ setup_socketpair_tcp_context,
+ teardown_socketpair_context),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, sigpipe_setup, NULL);
+}
diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c
new file mode 100644
index 0000000..674858d
--- /dev/null
+++ b/lib/tsocket/tsocket.c
@@ -0,0 +1,812 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tsocket
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
+{
+ enum tevent_req_state state;
+ uint64_t error;
+
+ if (!tevent_req_is_error(req, &state, &error)) {
+ return 0;
+ }
+
+ switch (state) {
+ case TEVENT_REQ_NO_MEMORY:
+ *perrno = ENOMEM;
+ return -1;
+ case TEVENT_REQ_TIMED_OUT:
+ *perrno = ETIMEDOUT;
+ return -1;
+ case TEVENT_REQ_USER_ERROR:
+ *perrno = (int)error;
+ return -1;
+ default:
+ break;
+ }
+
+ *perrno = EIO;
+ return -1;
+}
+
+struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ void **ppstate = (void **)pstate;
+ struct tsocket_address *addr;
+
+ addr = talloc_zero(mem_ctx, struct tsocket_address);
+ if (!addr) {
+ return NULL;
+ }
+ addr->ops = ops;
+ addr->location = location;
+ addr->private_data = talloc_size(addr, psize);
+ if (!addr->private_data) {
+ talloc_free(addr);
+ return NULL;
+ }
+ talloc_set_name_const(addr->private_data, type);
+
+ *ppstate = addr->private_data;
+ return addr;
+}
+
+char *tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ if (!addr) {
+ return talloc_strdup(mem_ctx, "NULL");
+ }
+ return addr->ops->string(addr, mem_ctx);
+}
+
+struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx,
+ const char *location)
+{
+ return addr->ops->copy(addr, mem_ctx, location);
+}
+
+struct tdgram_context {
+ const char *location;
+ const struct tdgram_context_ops *ops;
+ void *private_data;
+
+ struct tevent_req *recvfrom_req;
+ struct tevent_req *sendto_req;
+};
+
+static int tdgram_context_destructor(struct tdgram_context *dgram)
+{
+ if (dgram->recvfrom_req) {
+ tevent_req_received(dgram->recvfrom_req);
+ }
+
+ if (dgram->sendto_req) {
+ tevent_req_received(dgram->sendto_req);
+ }
+
+ return 0;
+}
+
+struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
+ const struct tdgram_context_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ struct tdgram_context *dgram;
+ void **ppstate = (void **)pstate;
+ void *state;
+
+ dgram = talloc(mem_ctx, struct tdgram_context);
+ if (dgram == NULL) {
+ return NULL;
+ }
+ dgram->location = location;
+ dgram->ops = ops;
+ dgram->recvfrom_req = NULL;
+ dgram->sendto_req = NULL;
+
+ state = talloc_size(dgram, psize);
+ if (state == NULL) {
+ talloc_free(dgram);
+ return NULL;
+ }
+ talloc_set_name_const(state, type);
+
+ dgram->private_data = state;
+
+ talloc_set_destructor(dgram, tdgram_context_destructor);
+
+ *ppstate = state;
+ return dgram;
+}
+
+void *_tdgram_context_data(struct tdgram_context *dgram)
+{
+ return dgram->private_data;
+}
+
+struct tdgram_recvfrom_state {
+ const struct tdgram_context_ops *ops;
+ struct tdgram_context *dgram;
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+};
+
+static int tdgram_recvfrom_destructor(struct tdgram_recvfrom_state *state)
+{
+ if (state->dgram) {
+ state->dgram->recvfrom_req = NULL;
+ }
+
+ return 0;
+}
+
+static void tdgram_recvfrom_done(struct tevent_req *subreq);
+
+struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tevent_req *req;
+ struct tdgram_recvfrom_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_recvfrom_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = dgram->ops;
+ state->dgram = dgram;
+ state->buf = NULL;
+ state->len = 0;
+ state->src = NULL;
+
+ if (dgram->recvfrom_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+ dgram->recvfrom_req = req;
+
+ talloc_set_destructor(state, tdgram_recvfrom_destructor);
+
+ subreq = state->ops->recvfrom_send(state, ev, dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_recvfrom_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_recvfrom_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
+ &state->buf, &state->src);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->len = ret;
+
+ tevent_req_done(req);
+}
+
+ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src)
+{
+ struct tdgram_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_recvfrom_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ *buf = talloc_move(mem_ctx, &state->buf);
+ ret = state->len;
+ if (src) {
+ *src = talloc_move(mem_ctx, &state->src);
+ }
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tdgram_sendto_state {
+ const struct tdgram_context_ops *ops;
+ struct tdgram_context *dgram;
+ ssize_t ret;
+};
+
+static int tdgram_sendto_destructor(struct tdgram_sendto_state *state)
+{
+ if (state->dgram) {
+ state->dgram->sendto_req = NULL;
+ }
+
+ return 0;
+}
+
+static void tdgram_sendto_done(struct tevent_req *subreq);
+
+struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tdgram_sendto_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_sendto_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = dgram->ops;
+ state->dgram = dgram;
+ state->ret = -1;
+
+ if (len == 0) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ if (dgram->sendto_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+ dgram->sendto_req = req;
+
+ talloc_set_destructor(state, tdgram_sendto_destructor);
+
+ subreq = state->ops->sendto_send(state, ev, dgram,
+ buf, len, dst);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tdgram_sendto_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_sendto_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_sendto_state *state = tevent_req_data(req,
+ struct tdgram_sendto_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = state->ops->sendto_recv(subreq, &sys_errno);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+ssize_t tdgram_sendto_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tdgram_sendto_state *state = tevent_req_data(req,
+ struct tdgram_sendto_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tdgram_disconnect_state {
+ const struct tdgram_context_ops *ops;
+};
+
+static void tdgram_disconnect_done(struct tevent_req *subreq);
+
+struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tevent_req *req;
+ struct tdgram_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = dgram->ops;
+
+ if (dgram->recvfrom_req || dgram->sendto_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+
+ subreq = state->ops->disconnect_send(state, ev, dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_disconnect_state *state = tevent_req_data(req,
+ struct tdgram_disconnect_state);
+ int ret;
+ int sys_errno;
+
+ ret = state->ops->disconnect_recv(subreq, &sys_errno);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int tdgram_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_context {
+ const char *location;
+ const struct tstream_context_ops *ops;
+ void *private_data;
+
+ struct tevent_req *readv_req;
+ struct tevent_req *writev_req;
+};
+
+static int tstream_context_destructor(struct tstream_context *stream)
+{
+ if (stream->readv_req) {
+ tevent_req_received(stream->readv_req);
+ }
+
+ if (stream->writev_req) {
+ tevent_req_received(stream->writev_req);
+ }
+
+ return 0;
+}
+
+struct tstream_context *_tstream_context_create(TALLOC_CTX *mem_ctx,
+ const struct tstream_context_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ struct tstream_context *stream;
+ void **ppstate = (void **)pstate;
+ void *state;
+
+ stream = talloc(mem_ctx, struct tstream_context);
+ if (stream == NULL) {
+ return NULL;
+ }
+ stream->location = location;
+ stream->ops = ops;
+ stream->readv_req = NULL;
+ stream->writev_req = NULL;
+
+ state = talloc_size(stream, psize);
+ if (state == NULL) {
+ talloc_free(stream);
+ return NULL;
+ }
+ talloc_set_name_const(state, type);
+
+ stream->private_data = state;
+
+ talloc_set_destructor(stream, tstream_context_destructor);
+
+ *ppstate = state;
+ return stream;
+}
+
+void *_tstream_context_data(struct tstream_context *stream)
+{
+ return stream->private_data;
+}
+
+ssize_t tstream_pending_bytes(struct tstream_context *stream)
+{
+ return stream->ops->pending_bytes(stream);
+}
+
+struct tstream_readv_state {
+ const struct tstream_context_ops *ops;
+ struct tstream_context *stream;
+ int ret;
+};
+
+static int tstream_readv_destructor(struct tstream_readv_state *state)
+{
+ if (state->stream) {
+ state->stream->readv_req = NULL;
+ }
+
+ return 0;
+}
+
+static void tstream_readv_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_readv_state *state;
+ struct tevent_req *subreq;
+ int to_read = 0;
+ size_t i;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_readv_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = stream->ops;
+ state->stream = stream;
+ state->ret = -1;
+
+ /* first check if the input is ok */
+#ifdef IOV_MAX
+ if (count > IOV_MAX) {
+ tevent_req_error(req, EMSGSIZE);
+ goto post;
+ }
+#endif
+
+ for (i=0; i < count; i++) {
+ int tmp = to_read;
+ tmp += vector[i].iov_len;
+
+ if (tmp < to_read) {
+ tevent_req_error(req, EMSGSIZE);
+ goto post;
+ }
+
+ to_read = tmp;
+ }
+
+ if (to_read == 0) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ if (stream->readv_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+ stream->readv_req = req;
+
+ talloc_set_destructor(state, tstream_readv_destructor);
+
+ subreq = state->ops->readv_send(state, ev, stream, vector, count);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_readv_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_readv_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_readv_state *state = tevent_req_data(req,
+ struct tstream_readv_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = state->ops->readv_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+int tstream_readv_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_readv_state *state = tevent_req_data(req,
+ struct tstream_readv_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_writev_state {
+ const struct tstream_context_ops *ops;
+ struct tstream_context *stream;
+ int ret;
+};
+
+static int tstream_writev_destructor(struct tstream_writev_state *state)
+{
+ if (state->stream) {
+ state->stream->writev_req = NULL;
+ }
+
+ return 0;
+}
+
+static void tstream_writev_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_writev_state *state;
+ struct tevent_req *subreq;
+ int to_write = 0;
+ size_t i;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_writev_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = stream->ops;
+ state->stream = stream;
+ state->ret = -1;
+
+ /* first check if the input is ok */
+#ifdef IOV_MAX
+ if (count > IOV_MAX) {
+ tevent_req_error(req, EMSGSIZE);
+ goto post;
+ }
+#endif
+
+ for (i=0; i < count; i++) {
+ int tmp = to_write;
+ tmp += vector[i].iov_len;
+
+ if (tmp < to_write) {
+ tevent_req_error(req, EMSGSIZE);
+ goto post;
+ }
+
+ to_write = tmp;
+ }
+
+ if (to_write == 0) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ if (stream->writev_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+ stream->writev_req = req;
+
+ talloc_set_destructor(state, tstream_writev_destructor);
+
+ subreq = state->ops->writev_send(state, ev, stream, vector, count);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_writev_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_writev_state *state = tevent_req_data(req,
+ struct tstream_writev_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = state->ops->writev_recv(subreq, &sys_errno);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+int tstream_writev_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_writev_state *state = tevent_req_data(req,
+ struct tstream_writev_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_disconnect_state {
+ const struct tstream_context_ops *ops;
+};
+
+static void tstream_disconnect_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream)
+{
+ struct tevent_req *req;
+ struct tstream_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = stream->ops;
+
+ if (stream->readv_req || stream->writev_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+
+ subreq = state->ops->disconnect_send(state, ev, stream);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_disconnect_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_disconnect_state *state = tevent_req_data(req,
+ struct tstream_disconnect_state);
+ int ret;
+ int sys_errno;
+
+ ret = state->ops->disconnect_recv(subreq, &sys_errno);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int tstream_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
+}
+
diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h
new file mode 100644
index 0000000..07e10c8
--- /dev/null
+++ b/lib/tsocket/tsocket.h
@@ -0,0 +1,1319 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tsocket
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TSOCKET_H
+#define _TSOCKET_H
+
+#include <tevent.h>
+
+struct samba_sockaddr;
+struct tsocket_address;
+struct tdgram_context;
+struct tstream_context;
+struct iovec;
+
+/**
+ * @mainpage
+ *
+ * The tsocket abstraction is an API ...
+ */
+
+/**
+ * @defgroup tsocket The tsocket API
+ *
+ * The tsocket abstraction is split into two different kinds of
+ * communication interfaces.
+ *
+ * There's the "tstream_context" interface with abstracts the communication
+ * through a bidirectional byte stream between two endpoints.
+ *
+ * And there's the "tdgram_context" interface with abstracts datagram based
+ * communication between any number of endpoints.
+ *
+ * Both interfaces share the "tsocket_address" abstraction for endpoint
+ * addresses.
+ *
+ * The whole library is based on the talloc(3) and 'tevent' libraries and
+ * provides "tevent_req" based "foo_send()"/"foo_recv()" functions pairs for
+ * all abstracted methods that need to be async.
+ *
+ * @section vsock Virtual Sockets
+ *
+ * The abstracted layout of tdgram_context and tstream_context allow
+ * implementations around virtual sockets for encrypted tunnels (like TLS,
+ * SASL or GSSAPI) or named pipes over smb.
+ *
+ * @section npa Named Pipe Auth (NPA) Sockets
+ *
+ * Samba has an implementation to abstract named pipes over smb (within the
+ * server side). See libcli/named_pipe_auth/npa_tstream.[ch] for the core code.
+ * The current callers are located in source4/ntvfs/ipc/vfs_ipc.c and
+ * source4/rpc_server/service_rpc.c for the users.
+ */
+
+/**
+ * @defgroup tsocket_address The tsocket_address abstraction
+ * @ingroup tsocket
+ *
+ * The tsocket_address represents an socket endpoint generically.
+ * As it's like an abstract class it has no specific constructor.
+ * The specific constructors are described in later sections.
+ *
+ * @{
+ */
+
+/**
+ * @brief Get a string representation of the endpoint.
+ *
+ * This function creates a string representation of the endpoint for debugging.
+ * The output will look as followed:
+ * prefix:address:port
+ *
+ * e.g.
+ * ipv4:192.168.1.1:143
+ *
+ * Callers should not try to parse the string! The should use additional methods
+ * of the specific tsocket_address implementation to get more details.
+ *
+ * @param[in] addr The address to convert.
+ *
+ * @param[in] mem_ctx The talloc memory context to allocate the memory.
+ *
+ * @return The address as a string representation, NULL on error.
+ *
+ * @see tsocket_address_is_inet()
+ * @see tsocket_address_inet_addr_string()
+ * @see tsocket_address_inet_port()
+ */
+char *tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+#ifdef DOXYGEN
+/**
+ * @brief This creates a copy of a tsocket_address.
+ *
+ * This is useful when before doing modifications to a socket via additional
+ * methods of the specific tsocket_address implementation.
+ *
+ * @param[in] addr The address to create the copy from.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @return A newly allocated copy of addr (tsocket_address *), NULL
+ * on error.
+ */
+struct tsocket_address *tsocket_address_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+#else
+struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx,
+ const char *location);
+
+#define tsocket_address_copy(addr, mem_ctx) \
+ _tsocket_address_copy(addr, mem_ctx, __location__)
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup tdgram_context The tdgram_context abstraction
+ * @ingroup tsocket
+ *
+ * The tdgram_context is like an abstract class for datagram based sockets. The
+ * interface provides async 'tevent_req' based functions on top functionality
+ * is similar to the recvfrom(2)/sendto(2)/close(2) syscalls.
+ *
+ * @note You can always use talloc_free(tdgram) to cleanup the resources
+ * of the tdgram_context on a fatal error.
+ * @{
+ */
+
+/**
+ * @brief Ask for next available datagram on the abstracted tdgram_context.
+ *
+ * It returns a 'tevent_req' handle, where the caller can register
+ * a callback with tevent_req_set_callback(). The callback is triggered
+ * when a datagram is available or an error happened.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] dgram The dgram context to work on.
+ *
+ * @return Returns a 'tevent_req' handle, where the caller can
+ * register a callback with tevent_req_set_callback().
+ * NULL on fatal error.
+ *
+ * @see tdgram_inet_udp_socket()
+ * @see tdgram_unix_socket()
+ */
+struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+
+/**
+ * @brief Receive the next available datagram on the abstracted tdgram_context.
+ *
+ * This function should be called by the callback when a datagram is available
+ * or an error happened.
+ *
+ * The caller can only have one outstanding tdgram_recvfrom_send() at a time
+ * otherwise the caller will get '*perrno = EBUSY'.
+ *
+ * @param[in] req The tevent request from tdgram_recvfrom_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @param[in] mem_ctx The memory context to use.
+ *
+ * @param[out] buf This will hold the buffer of the datagram.
+ *
+ * @param[out] src The abstracted tsocket_address of the sender of the
+ * received datagram.
+ *
+ * @return The length of the datagram (0 is never returned!),
+ * -1 on error with perrno set to the actual errno.
+ *
+ * @see tdgram_recvfrom_send()
+ */
+ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+/**
+ * @brief Send a datagram to a destination endpoint.
+ *
+ * The function can be called to send a datagram (specified by a buf/len) to a
+ * destination endpoint (specified by dst). It's not allowed for len to be 0.
+ *
+ * It returns a 'tevent_req' handle, where the caller can register a callback
+ * with tevent_req_set_callback(). The callback is triggered when the specific
+ * implementation (assumes it) has delivered the datagram to the "wire".
+ *
+ * The callback is then supposed to get the result by calling
+ * tdgram_sendto_recv() on the 'tevent_req'.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] dgram The dgram context to work on.
+ *
+ * @param[in] buf The buffer to send.
+ *
+ * @param[in] len The length of the buffer to send. It has to be bigger
+ * than 0.
+ *
+ * @param[in] dst The destination to send the datagram to in form of a
+ * tsocket_address.
+ *
+ * @return Returns a 'tevent_req' handle, where the caller can
+ * register a callback with tevent_req_set_callback().
+ * NULL on fatal error.
+ *
+ * @see tdgram_inet_udp_socket()
+ * @see tdgram_unix_socket()
+ * @see tdgram_sendto_recv()
+ */
+struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst);
+
+/**
+ * @brief Receive the result of the sent datagram.
+ *
+ * The caller can only have one outstanding tdgram_sendto_send() at a time
+ * otherwise the caller will get '*perrno = EBUSY'.
+ *
+ * @param[in] req The tevent request from tdgram_sendto_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @return The length of the datagram (0 is never returned!), -1 on
+ * error with perrno set to the actual errno.
+ *
+ * @see tdgram_sendto_send()
+ */
+ssize_t tdgram_sendto_recv(struct tevent_req *req,
+ int *perrno);
+
+/**
+ * @brief Shutdown/close an abstracted socket.
+ *
+ * It returns a 'tevent_req' handle, where the caller can register a callback
+ * with tevent_req_set_callback(). The callback is triggered when the specific
+ * implementation (assumes it) has delivered the datagram to the "wire".
+ *
+ * The callback is then supposed to get the result by calling
+ * tdgram_sendto_recv() on the 'tevent_req'.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] dgram The dgram context to disconnect from.
+ *
+ * @return Returns a 'tevent_req' handle, where the caller can
+ * register a callback with tevent_req_set_callback().
+ * NULL on fatal error.
+ *
+ * @see tdgram_disconnect_recv()
+ */
+struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+
+/**
+ * @brief Receive the result from a tdgram_disconnect_send() request.
+ *
+ * The caller should make sure there're no outstanding tdgram_recvfrom_send()
+ * and tdgram_sendto_send() calls otherwise the caller will get
+ * '*perrno = EBUSY'.
+ *
+ * @param[in] req The tevent request from tdgram_disconnect_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @return The length of the datagram (0 is never returned!), -1 on
+ * error with perrno set to the actual errno.
+ *
+ * @see tdgram_disconnect_send()
+ */
+int tdgram_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup tstream_context The tstream_context abstraction
+ * @ingroup tsocket
+ *
+ * The tstream_context is like an abstract class for stream based sockets. The
+ * interface provides async 'tevent_req' based functions on top functionality
+ * is similar to the readv(2)/writev(2)/close(2) syscalls.
+ *
+ * @note You can always use talloc_free(tstream) to cleanup the resources
+ * of the tstream_context on a fatal error.
+ *
+ * @{
+ */
+
+/**
+ * @brief Report the number of bytes received but not consumed yet.
+ *
+ * The tstream_pending_bytes() function reports how much bytes of the incoming
+ * stream have been received but not consumed yet.
+ *
+ * @param[in] stream The tstream_context to check for pending bytes.
+ *
+ * @return The number of bytes received, -1 on error with errno
+ * set.
+ */
+ssize_t tstream_pending_bytes(struct tstream_context *stream);
+
+/**
+ * @brief Read a specific amount of bytes from a stream socket.
+ *
+ * The function can be called to read for a specific amount of bytes from the
+ * stream into given buffers. The caller has to preallocate the buffers.
+ *
+ * The caller might need to use tstream_pending_bytes() if the protocol doesn't
+ * have a fixed pdu header containing the pdu size.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] stream The tstream context to work on.
+ *
+ * @param[out] vector A preallocated iovec to store the data to read.
+ *
+ * @param[in] count The number of buffers in the vector allocated.
+ *
+ * @return A 'tevent_req' handle, where the caller can register
+ * a callback with tevent_req_set_callback(). NULL on
+ * fatal error.
+ *
+ * @see tstream_unix_connect_send()
+ * @see tstream_inet_tcp_connect_send()
+ */
+struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count);
+
+/**
+ * @brief Get the result of a tstream_readv_send().
+ *
+ * The caller can only have one outstanding tstream_readv_send()
+ * at a time otherwise the caller will get *perrno = EBUSY.
+ *
+ * @param[in] req The tevent request from tstream_readv_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @return The length of the stream (0 is never returned!), -1 on
+ * error with perrno set to the actual errno.
+ */
+int tstream_readv_recv(struct tevent_req *req,
+ int *perrno);
+
+/**
+ * @brief Write buffers from a vector into a stream socket.
+ *
+ * The function can be called to write buffers from a given vector
+ * to a stream socket.
+ *
+ * You have to ensure that the vector is not empty.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] stream The tstream context to work on.
+ *
+ * @param[in] vector The iovec vector with data to write on a stream socket.
+ *
+ * @param[in] count The number of buffers in the vector to write.
+ *
+ * @return A 'tevent_req' handle, where the caller can register
+ * a callback with tevent_req_set_callback(). NULL on
+ * fatal error.
+ */
+struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count);
+
+/**
+ * @brief Get the result of a tstream_writev_send().
+ *
+ * The caller can only have one outstanding tstream_writev_send()
+ * at a time otherwise the caller will get *perrno = EBUSY.
+ *
+ * @param[in] req The tevent request from tstream_writev_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @return The length of the stream (0 is never returned!), -1 on
+ * error with perrno set to the actual errno.
+ */
+int tstream_writev_recv(struct tevent_req *req,
+ int *perrno);
+
+/**
+ * @brief Shutdown/close an abstracted socket.
+ *
+ * It returns a 'tevent_req' handle, where the caller can register a callback
+ * with tevent_req_set_callback(). The callback is triggered when the specific
+ * implementation (assumes it) has delivered the stream to the "wire".
+ *
+ * The callback is then supposed to get the result by calling
+ * tdgram_sendto_recv() on the 'tevent_req'.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] stream The tstream context to work on.
+ *
+ * @return A 'tevent_req' handle, where the caller can register
+ * a callback with tevent_req_set_callback(). NULL on
+ * fatal error.
+ */
+struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+
+/**
+ * @brief Get the result of a tstream_disconnect_send().
+ *
+ * The caller can only have one outstanding tstream_writev_send()
+ * at a time otherwise the caller will get *perrno = EBUSY.
+ *
+ * @param[in] req The tevent request from tstream_disconnect_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @return The length of the stream (0 is never returned!), -1 on
+ * error with perrno set to the actual errno.
+ */
+int tstream_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+/**
+ * @}
+ */
+
+
+/**
+ * @defgroup tsocket_bsd tsocket_bsd - inet, inet6 and unix
+ * @ingroup tsocket
+ *
+ * The main tsocket library comes with implementations for BSD style ipv4, ipv6
+ * and unix sockets.
+ *
+ * @{
+ */
+
+/**
+ * @brief Find out if the tsocket_address represents an ipv4 or ipv6 endpoint.
+ *
+ * @param[in] addr The tsocket_address pointer
+ *
+ * @param[in] fam The family can be can be "ipv4", "ipv6" or "ip". With
+ * "ip" is autodetects "ipv4" or "ipv6" based on the
+ * addr.
+ *
+ * @return true if addr represents an address of the given family,
+ * otherwise false.
+ */
+bool tsocket_address_is_inet(const struct tsocket_address *addr, const char *fam);
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a tsocket_address for ipv4 and ipv6 endpoint addresses.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] fam The family can be can be "ipv4", "ipv6" or "ip". With
+ * "ip" is autodetects "ipv4" or "ipv6" based on the
+ * addr.
+ *
+ * @param[in] addr A valid ip address string based on the selected family
+ * (dns names are not allowed!). It's valid to pass NULL,
+ * which gets mapped to "0.0.0.0" or "::".
+ *
+ * @param[in] port A valid port number.
+ *
+ * @param[out] _addr A tsocket_address pointer to store the information.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ */
+int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *addr,
+ uint16_t port,
+ struct tsocket_address **_addr);
+#else
+int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *addr,
+ uint16_t port,
+ struct tsocket_address **_addr,
+ const char *location);
+
+#define tsocket_address_inet_from_strings(mem_ctx, fam, addr, port, _addr) \
+ _tsocket_address_inet_from_strings(mem_ctx, fam, addr, port, _addr, \
+ __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a tsocket_address for ipv4 and ipv6 endpoint addresses.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] fam The family can be can be "ipv4", "ipv6" or "ip". With
+ * "ip" it autodetects "ipv4" or "ipv6" based on the
+ * addr.
+ *
+ * @param[in] host_port_addr A valid ip address string based on the
+ * selected family (dns names are not allowed!). A port
+ * number may follow separated by a colon. IPv6 may be
+ * surrounded in square brackets, and these are required
+ * if appending a port number. It's valid to pass NULL,
+ * which gets mapped to "0.0.0.0" or "::".
+ *
+ * @param[in] default_port A valid port number for the default port if none
+ * given.
+ *
+ * @param[out] _addr A tsocket_address pointer to store the information.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ */
+int tsocket_address_inet_from_hostport_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *host_port_addr,
+ uint16_t default_port,
+ struct tsocket_address **_addr);
+#else
+int _tsocket_address_inet_from_hostport_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *host_port_addr,
+ uint16_t default_port,
+ struct tsocket_address **_addr,
+ const char *location);
+
+#define tsocket_address_inet_from_hostport_strings( \
+ mem_ctx, fam, host_port_addr, default_port, _addr) \
+ _tsocket_address_inet_from_hostport_strings( \
+ mem_ctx, fam, host_port_addr, default_port, _addr, __location__)
+#endif
+
+/**
+ * @brief Get the address of an 'inet' tsocket_address as a string.
+ *
+ * @param[in] addr The address to convert to a string.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @return A newly allocated string of the address, NULL on error
+ * with errno set.
+ *
+ * @see tsocket_address_is_inet()
+ */
+char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Get the port number as an integer from an 'inet' tsocket_address.
+ *
+ * @param[in] addr The tsocket address to use.
+ *
+ * @return The port number, 0 on error with errno set.
+ */
+uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
+
+/**
+ * @brief Set the port number of an existing 'inet' tsocket_address.
+ *
+ * @param[in] addr The existing tsocket_address to use.
+ *
+ * @param[in] port The valid port number to set.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ */
+int tsocket_address_inet_set_port(struct tsocket_address *addr,
+ uint16_t port);
+
+/**
+ * @brief Find out if the tsocket_address represents an unix domain endpoint.
+ *
+ * @param[in] addr The tsocket_address pointer
+ *
+ * @return true if addr represents an unix domain endpoint,
+ * otherwise false.
+ */
+bool tsocket_address_is_unix(const struct tsocket_address *addr);
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a tsocket_address for a unix domain endpoint addresses.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] path The filesystem path, NULL will map "".
+ *
+ * @param[in] _addr The tsocket_address pointer to store the information.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ *
+ * @see tsocket_address_is_unix()
+ */
+int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+ const char *path,
+ struct tsocket_address **_addr);
+#else
+int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+ const char *path,
+ struct tsocket_address **_addr,
+ const char *location);
+
+#define tsocket_address_unix_from_path(mem_ctx, path, _addr) \
+ _tsocket_address_unix_from_path(mem_ctx, path, _addr, \
+ __location__)
+#endif
+
+/**
+ * @brief Get the address of an 'unix' tsocket_address.
+ *
+ * @param[in] addr A valid 'unix' tsocket_address.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @return The path of the unix domain socket, NULL on error or if
+ * the tsocket_address doesn't represent an unix domain
+ * endpoint path.
+ */
+char *tsocket_address_unix_path(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+#ifdef DOXYGEN
+/**
+ * @brief Wrap an existing file descriptors into the tdgram abstraction.
+ *
+ * You can use this function to wrap an existing file descriptors into the
+ * tdgram abstraction. After that you're not able to use this file descriptor
+ * for anything else. The file descriptor will be closed when the stream gets
+ * freed. If you still want to use the fd you have to create a duplicate.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] fd The non blocking fd to use!
+ *
+ * @param[out] dgram A pointer to store an allocated tdgram_context.
+ *
+ * @return 0 on success, -1 on error.
+ *
+ * Example:
+ * @code
+ * fd2 = dup(fd);
+ * rc = tdgram_bsd_existing_socket(mem_ctx, fd2, &tdgram);
+ * if (rc < 0) {
+ * return;
+ * }
+ * @endcode
+ *
+ * @warning This is an internal function. You should read the code to fully
+ * understand it if you plan to use it.
+ */
+int tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tdgram_context **dgram);
+#else
+int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tdgram_context **_dgram,
+ const char *location);
+#define tdgram_bsd_existing_socket(mem_ctx, fd, dgram) \
+ _tdgram_bsd_existing_socket(mem_ctx, fd, dgram, \
+ __location__)
+#endif
+
+/**
+ * @brief Request a syscall optimization for tdgram_recvfrom_send()
+ *
+ * This function is only used to reduce the amount of syscalls and
+ * optimize performance. You should only use this if you know
+ * what you're doing.
+ *
+ * The optimization is off by default.
+ *
+ * @param[in] dgram The tdgram_context of a bsd socket, if this
+ * not a bsd socket the function does nothing.
+ *
+ * @param[in] on The boolean value to turn the optimization on and off.
+ *
+ * @return The old boolean value.
+ *
+ * @see tdgram_recvfrom_send()
+ */
+bool tdgram_bsd_optimize_recvfrom(struct tdgram_context *dgram,
+ bool on);
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a tdgram_context for a ipv4 or ipv6 UDP communication.
+ *
+ * @param[in] local An 'inet' tsocket_address for the local endpoint.
+ *
+ * @param[in] remote An 'inet' tsocket_address for the remote endpoint or
+ * NULL (??? to create a listener?).
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] dgram The tdgram_context pointer to setup the udp
+ * communication. The function will allocate the memory.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ *
+ * @see tdgram_inet_udp_broadcast_socket()
+ */
+int tdgram_inet_udp_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram);
+#else
+int _tdgram_inet_udp_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location);
+#define tdgram_inet_udp_socket(local, remote, mem_ctx, dgram) \
+ _tdgram_inet_udp_socket(local, remote, mem_ctx, dgram, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a tdgram_context for a ipv4 UDP broadcast (and unicast) communication.
+ *
+ * @param[in] local An 'inet' (ipv4 only) tsocket_address for the local endpoint.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] dgram The tdgram_context pointer to setup the udp
+ * communication. The function will allocate the memory.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ *
+ * @see tdgram_inet_udp_socket()
+ */
+int tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram);
+#else
+int _tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location);
+#define tdgram_inet_udp_broadcast_socket(local, mem_ctx, dgram) \
+ _tdgram_inet_udp_broadcast_socket(local, mem_ctx, dgram, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a tdgram_context for unix domain datagram communication.
+ *
+ * @param[in] local An 'unix' tsocket_address for the local endpoint.
+ *
+ * @param[in] remote An 'unix' tsocket_address for the remote endpoint or
+ * NULL (??? to create a listener?).
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] dgram The tdgram_context pointer to setup the udp
+ * communication. The function will allocate the memory.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ */
+int tdgram_unix_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram);
+#else
+int _tdgram_unix_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location);
+
+#define tdgram_unix_socket(local, remote, mem_ctx, dgram) \
+ _tdgram_unix_socket(local, remote, mem_ctx, dgram, __location__)
+#endif
+
+/**
+ * @brief Request a syscall optimization for tstream_readv_send()
+ *
+ * This function is only used to reduce the amount of syscalls and
+ * optimize performance. You should only use this if you know
+ * what you're doing.
+ *
+ * The optimization is off by default.
+ *
+ * @param[in] stream The tstream_context of a bsd socket, if this
+ * not a bsd socket the function does nothing.
+ *
+ * @param[in] on The boolean value to turn the optimization on and off.
+ *
+ * @return The old boolean value.
+ *
+ * @see tstream_readv_send()
+ */
+bool tstream_bsd_optimize_readv(struct tstream_context *stream,
+ bool on);
+
+/**
+ * @brief Request that tstream_readv_send() fails within pending data
+ *
+ * By default we allow pending data to be drained from the
+ * recv queue, before we report EPIPE when reaching EOF.
+ *
+ * For server applications it's typically useful to
+ * fail early in order to avoid useless work,
+ * as the response can't be transferred to the client anyway.
+ *
+ * @param[in] stream The tstream_context of a bsd socket, if this
+ * not a bsd socket the function does nothing.
+ *
+ * @param[in] on The boolean value to turn the early fail on and off.
+ *
+ * @return The old boolean value.
+ *
+ * @see tstream_readv_send()
+ */
+bool tstream_bsd_fail_readv_first_error(struct tstream_context *stream,
+ bool on);
+
+/**
+ * @brief Connect async to a TCP endpoint and create a tstream_context for the
+ * stream based communication.
+ *
+ * Use this function to connect asynchronously to a remote ipv4 or ipv6 TCP
+ * endpoint and create a tstream_context for the stream based communication.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] local An 'inet' tsocket_address for the local endpoint.
+ *
+ * @param[in] remote An 'inet' tsocket_address for the remote endpoint.
+ *
+ * @return A 'tevent_req' handle, where the caller can register a
+ * callback with tevent_req_set_callback(). NULL on a fatal
+ * error.
+ *
+ * @see tstream_inet_tcp_connect_recv()
+ */
+struct tevent_req *tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote);
+
+#ifdef DOXYGEN
+/**
+ * @brief Receive the result from a tstream_inet_tcp_connect_send().
+ *
+ * @param[in] req The tevent request from tstream_inet_tcp_connect_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[out] stream A tstream_context pointer to setup the tcp communication
+ * on. This function will allocate the memory.
+ *
+ * @param[out] local The real 'inet' tsocket_address of the local endpoint.
+ * This parameter is optional and can be NULL.
+ *
+ * @return 0 on success, -1 on error with perrno set.
+ */
+int tstream_inet_tcp_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct tsocket_address **local)
+#else
+int _tstream_inet_tcp_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct tsocket_address **local,
+ const char *location);
+#define tstream_inet_tcp_connect_recv(req, perrno, mem_ctx, stream, local) \
+ _tstream_inet_tcp_connect_recv(req, perrno, mem_ctx, stream, local, \
+ __location__)
+#endif
+
+/**
+ * @brief Connect async to a unix domain endpoint and create a tstream_context
+ * for the stream based communication.
+ *
+ * Use this function to connect asynchronously to a unix domainendpoint and
+ * create a tstream_context for the stream based communication.
+ *
+ * The callback is triggered when a socket is connected and ready for IO or an
+ * error happened.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] local An 'unix' tsocket_address for the local endpoint.
+ *
+ * @param[in] remote An 'unix' tsocket_address for the remote endpoint.
+ *
+ * @return A 'tevent_req' handle, where the caller can register a
+ * callback with tevent_req_set_callback(). NULL on a falal
+ * error.
+ *
+ * @see tstream_unix_connect_recv()
+ */
+struct tevent_req * tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote);
+
+#ifdef DOXYGEN
+/**
+ * @brief Receive the result from a tstream_unix_connect_send().
+ *
+ * @param[in] req The tevent request from tstream_inet_tcp_connect_send().
+ *
+ * @param[out] perrno The error number, set if an error occurred.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] stream The tstream context to work on.
+ *
+ * @return 0 on success, -1 on error with perrno set.
+ */
+int tstream_unix_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream);
+#else
+int _tstream_unix_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ const char *location);
+#define tstream_unix_connect_recv(req, perrno, mem_ctx, stream) \
+ _tstream_unix_connect_recv(req, perrno, mem_ctx, stream, \
+ __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Create two connected 'unix' tsocket_contexts for stream based
+ * communication.
+ *
+ * @param[in] mem_ctx1 The talloc memory context to use for stream1.
+ *
+ * @param[in] stream1 The first stream to connect.
+ *
+ * @param[in] mem_ctx2 The talloc memory context to use for stream2.
+ *
+ * @param[in] stream2 The second stream to connect.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ */
+int tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
+ struct tstream_context **stream1,
+ TALLOC_CTX *mem_ctx2,
+ struct tstream_context **stream2);
+#else
+int _tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
+ struct tstream_context **_stream1,
+ TALLOC_CTX *mem_ctx2,
+ struct tstream_context **_stream2,
+ const char *location);
+
+#define tstream_unix_socketpair(mem_ctx1, stream1, mem_ctx2, stream2) \
+ _tstream_unix_socketpair(mem_ctx1, stream1, mem_ctx2, stream2, \
+ __location__)
+#endif
+
+struct sockaddr;
+
+#ifdef DOXYGEN
+/**
+ * @brief Convert a tsocket address to a bsd socket address.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] sa The sockaddr structure to convert.
+ *
+ * @param[in] sa_socklen The length of the sockaddr structure.
+ *
+ * @param[out] addr The tsocket pointer to allocate and fill.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ */
+int tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
+ const struct sockaddr *sa,
+ size_t sa_socklen,
+ struct tsocket_address **addr);
+#else
+int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
+ const struct sockaddr *sa,
+ size_t sa_socklen,
+ struct tsocket_address **_addr,
+ const char *location);
+
+#define tsocket_address_bsd_from_sockaddr(mem_ctx, sa, sa_socklen, _addr) \
+ _tsocket_address_bsd_from_sockaddr(mem_ctx, sa, sa_socklen, _addr, \
+ __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Convert a samba address to a tsocket address.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] s_addr The samba address structure to convert.
+ *
+ * @param[out] t_addr The tsocket pointer to allocate and fill.
+ *
+ * @return 0 on success, -1 on error with errno set.
+ */
+int tsocket_address_bsd_from_samba_sockaddr(TALLOC_CTX *mem_ctx,
+ const struct samba_sockaddr *xs_addr,
+ struct tsocket_address **t_addr);
+#else
+int _tsocket_address_bsd_from_samba_sockaddr(TALLOC_CTX *mem_ctx,
+ const struct samba_sockaddr *xs_addr,
+ struct tsocket_address **t_addr,
+ const char *location);
+
+#define tsocket_address_bsd_from_samba_sockaddr(mem_ctx, xs_addr, t_addr) \
+ _tsocket_address_bsd_from_samba_sockaddr(mem_ctx, xs_addr, t_addr, \
+ __location__)
+#endif
+
+/**
+ * @brief Fill a bsd sockaddr structure.
+ *
+ * @param[in] addr The tsocket address structure to use.
+ *
+ * @param[in] sa The bsd sockaddr structure to fill out.
+ *
+ * @param[in] sa_socklen The length of the bsd sockaddr structure to fill out.
+ *
+ * @return The actual size of the sockaddr structure, -1 on error
+ * with errno set. The size could differ from sa_socklen.
+ *
+ * @code
+ * ssize_t socklen;
+ * struct sockaddr_storage ss;
+ *
+ * socklen = tsocket_address_bsd_sockaddr(taddr,
+ * (struct sockaddr *) &ss,
+ * sizeof(struct sockaddr_storage));
+ * if (socklen < 0) {
+ * return -1;
+ * }
+ * @endcode
+ */
+ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
+ struct sockaddr *sa,
+ size_t sa_socklen);
+
+#ifdef DOXYGEN
+/**
+ * @brief Wrap an existing file descriptors into the tstream abstraction.
+ *
+ * You can use this function to wrap an existing file descriptors into the
+ * tstream abstraction. After that you're not able to use this file descriptor
+ * for anything else. The file descriptor will be closed when the stream gets
+ * freed. If you still want to use the fd you have to create a duplicate.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] fd The non blocking fd to use!
+ *
+ * @param[out] stream A pointer to store an allocated tstream_context.
+ *
+ * @return 0 on success, -1 on error.
+ *
+ * Example:
+ * @code
+ * fd2 = dup(fd);
+ * rc = tstream_bsd_existing_socket(mem_ctx, fd2, &tstream);
+ * if (rc < 0) {
+ * stream_terminate_connection(conn, "named_pipe_accept: out of memory");
+ * return;
+ * }
+ * @endcode
+ *
+ * @warning This is an internal function. You should read the code to fully
+ * understand it if you plan to use it.
+ */
+int tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tstream_context **stream);
+#else
+int _tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tstream_context **_stream,
+ const char *location);
+#define tstream_bsd_existing_socket(mem_ctx, fd, stream) \
+ _tstream_bsd_existing_socket(mem_ctx, fd, stream, \
+ __location__)
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup tsocket_helper Queue and PDU helpers
+ * @ingroup tsocket
+ *
+ * In order to make the live easier for callers which want to implement a
+ * function to receive a full PDU with a single async function pair, there're
+ * some helper functions.
+ *
+ * There're some cases where the caller wants doesn't care about the order of
+ * doing IO on the abstracted sockets.
+ *
+ * @{
+ */
+
+/**
+ * @brief Queue a dgram blob for sending through the socket.
+ *
+ * This function queues a blob for sending to destination through an existing
+ * dgram socket. The async callback is triggered when the whole blob is
+ * delivered to the underlying system socket.
+ *
+ * The caller needs to make sure that all non-scalar input parameters hang
+ * around for the whole lifetime of the request.
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ *
+ * @param[in] ev The event context the operation should work on.
+ *
+ * @param[in] dgram The tdgram_context to send the message buffer.
+ *
+ * @param[in] queue The existing dgram queue.
+ *
+ * @param[in] buf The message buffer to send.
+ *
+ * @param[in] len The message length.
+ *
+ * @param[in] dst The destination socket address.
+ *
+ * @return The async request handle. NULL on fatal error.
+ *
+ * @see tdgram_sendto_queue_recv()
+ */
+struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst);
+
+/**
+ * @brief Receive the result of the sent dgram blob.
+ *
+ * @param[in] req The tevent request from tdgram_sendto_queue_send().
+ *
+ * @param[out] perrno The error set to the actual errno.
+ *
+ * @return The length of the datagram (0 is never returned!), -1 on
+ * error with perrno set to the actual errno.
+ */
+ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
+typedef int (*tstream_readv_pdu_next_vector_t)(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **vector,
+ size_t *count);
+
+struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private);
+int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno);
+
+/**
+ * @brief Queue a read request for a PDU on the socket.
+ *
+ * This function queues a read request for a PDU on a stream socket. The async
+ * callback is triggered when a full PDU has been read from the socket.
+ *
+ * The caller needs to make sure that all non-scalar input parameters hang
+ * around for the whole lifetime of the request.
+ *
+ * @param[in] mem_ctx The memory context for the result
+ *
+ * @param[in] ev The tevent_context to run on
+ *
+ * @param[in] stream The stream to send data through
+ *
+ * @param[in] queue The existing send queue
+ *
+ * @param[in] next_vector_fn The next vector function
+ *
+ * @param[in] next_vector_private The private_data of the next vector function
+ *
+ * @return The async request handle. NULL on fatal error.
+ *
+ * @see tstream_readv_pdu_queue_recv()
+ */
+struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private);
+
+/**
+ * @brief Receive the PDU blob read from the stream.
+ *
+ * @param[in] req The tevent request from tstream_readv_pdu_queue_send().
+ *
+ * @param[out] perrno The error set to the actual errno.
+ *
+ * @return The number of bytes read on success, -1 on error with
+ * perrno set to the actual errno.
+ */
+int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno);
+
+/**
+ * @brief Queue an iovector for sending through the socket
+ *
+ * This function queues an iovector for sending to destination through an
+ * existing stream socket. The async callback is triggered when the whole
+ * vector has been delivered to the underlying system socket.
+ *
+ * The caller needs to make sure that all non-scalar input parameters hang
+ * around for the whole lifetime of the request.
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ *
+ * @param[in] ev The tevent_context to run on.
+ *
+ * @param[in] stream The stream to send data through.
+ *
+ * @param[in] queue The existing send queue.
+ *
+ * @param[in] vector The iovec vector so write.
+ *
+ * @param[in] count The size of the vector.
+ *
+ * @return The async request handle. NULL on fatal error.
+ */
+struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ const struct iovec *vector,
+ size_t count);
+
+/**
+ * @brief Receive the result of the sent iovector.
+ *
+ * @param[in] req The tevent request from tstream_writev_queue_send().
+ *
+ * @param[out] perrno The error set to the actual errno.
+ *
+ * @return The length of the iovector (0 is never returned!), -1 on
+ * error with perrno set to the actual errno.
+ */
+int tstream_writev_queue_recv(struct tevent_req *req, int *perrno);
+
+/**
+ * @}
+ */
+
+#endif /* _TSOCKET_H */
+
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
new file mode 100644
index 0000000..4483b03
--- /dev/null
+++ b/lib/tsocket/tsocket_bsd.c
@@ -0,0 +1,2845 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tsocket
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+#include "lib/util/iov_buf.h"
+#include "lib/util/blocking.h"
+#include "lib/util/util_net.h"
+#include "lib/util/samba_util.h"
+
+static int tsocket_bsd_error_from_errno(int ret,
+ int sys_errno,
+ bool *retry)
+{
+ *retry = false;
+
+ if (ret >= 0) {
+ return 0;
+ }
+
+ if (ret != -1) {
+ return EIO;
+ }
+
+ if (sys_errno == 0) {
+ return EIO;
+ }
+
+ if (sys_errno == EINTR) {
+ *retry = true;
+ return sys_errno;
+ }
+
+ if (sys_errno == EINPROGRESS) {
+ *retry = true;
+ return sys_errno;
+ }
+
+ if (sys_errno == EAGAIN) {
+ *retry = true;
+ return sys_errno;
+ }
+
+ /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
+ if (sys_errno == ENOMEM) {
+ *retry = true;
+ return sys_errno;
+ }
+
+#ifdef EWOULDBLOCK
+ if (sys_errno == EWOULDBLOCK) {
+ *retry = true;
+ return sys_errno;
+ }
+#endif
+
+ return sys_errno;
+}
+
+static int tsocket_bsd_common_prepare_fd(int fd, bool high_fd)
+{
+ int i;
+ int sys_errno = 0;
+ int fds[3];
+ int num_fds = 0;
+
+ int result;
+ bool ok;
+
+ if (fd == -1) {
+ return -1;
+ }
+
+ /* first make a fd >= 3 */
+ if (high_fd) {
+ while (fd < 3) {
+ fds[num_fds++] = fd;
+ fd = dup(fd);
+ if (fd == -1) {
+ sys_errno = errno;
+ break;
+ }
+ }
+ for (i=0; i<num_fds; i++) {
+ close(fds[i]);
+ }
+ if (fd == -1) {
+ errno = sys_errno;
+ return fd;
+ }
+ }
+
+ result = set_blocking(fd, false);
+ if (result == -1) {
+ goto fail;
+ }
+
+ ok = smb_set_close_on_exec(fd);
+ if (!ok) {
+ goto fail;
+ }
+
+ return fd;
+
+ fail:
+ if (fd != -1) {
+ sys_errno = errno;
+ close(fd);
+ errno = sys_errno;
+ }
+ return -1;
+}
+
+#ifdef HAVE_LINUX_RTNETLINK_H
+/**
+ * Get the amount of pending bytes from a netlink socket
+ *
+ * For some reason netlink sockets don't support querying the amount of pending
+ * data via ioctl with FIONREAD, which is what we use in tsocket_bsd_pending()
+ * below.
+ *
+ * We know we are on Linux as we're using netlink, which means we have a working
+ * MSG_TRUNC flag to recvmsg() as well, so we use that together with MSG_PEEK.
+ **/
+static ssize_t tsocket_bsd_netlink_pending(int fd)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ char buf[1];
+
+ iov = (struct iovec) {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)
+ };
+
+ msg = (struct msghdr) {
+ .msg_iov = &iov,
+ .msg_iovlen = 1
+ };
+
+ return recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC);
+}
+#else
+static ssize_t tsocket_bsd_netlink_pending(int fd)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+static ssize_t tsocket_bsd_pending(int fd)
+{
+ int ret;
+ int value = 0;
+
+ ret = ioctl(fd, FIONREAD, &value);
+ if (ret == -1) {
+ return ret;
+ }
+
+ if (ret != 0) {
+ /* this should not be reached */
+ errno = EIO;
+ return -1;
+ }
+
+ if (value != 0) {
+ return value;
+ }
+
+ return samba_socket_poll_or_sock_error(fd);
+}
+
+static const struct tsocket_address_ops tsocket_address_bsd_ops;
+
+int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
+ const struct sockaddr *sa,
+ size_t sa_socklen,
+ struct tsocket_address **_addr,
+ const char *location)
+{
+ struct tsocket_address *addr;
+ struct samba_sockaddr *bsda = NULL;
+
+ if (sa_socklen < sizeof(sa->sa_family)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch (sa->sa_family) {
+ case AF_UNIX:
+ if (sa_socklen > sizeof(struct sockaddr_un)) {
+ sa_socklen = sizeof(struct sockaddr_un);
+ }
+ break;
+ case AF_INET:
+ if (sa_socklen < sizeof(struct sockaddr_in)) {
+ errno = EINVAL;
+ return -1;
+ }
+ sa_socklen = sizeof(struct sockaddr_in);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (sa_socklen < sizeof(struct sockaddr_in6)) {
+ errno = EINVAL;
+ return -1;
+ }
+ sa_socklen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (sa_socklen > sizeof(struct sockaddr_storage)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ addr = tsocket_address_create(mem_ctx,
+ &tsocket_address_bsd_ops,
+ &bsda,
+ struct samba_sockaddr,
+ location);
+ if (!addr) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ZERO_STRUCTP(bsda);
+
+ memcpy(&bsda->u.ss, sa, sa_socklen);
+
+ bsda->sa_socklen = sa_socklen;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ bsda->u.sa.sa_len = bsda->sa_socklen;
+#endif
+
+ *_addr = addr;
+ return 0;
+}
+
+int _tsocket_address_bsd_from_samba_sockaddr(TALLOC_CTX *mem_ctx,
+ const struct samba_sockaddr *xs_addr,
+ struct tsocket_address **t_addr,
+ const char *location)
+{
+ return _tsocket_address_bsd_from_sockaddr(mem_ctx,
+ &xs_addr->u.sa,
+ xs_addr->sa_socklen,
+ t_addr,
+ location);
+}
+
+ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
+ struct sockaddr *sa,
+ size_t sa_socklen)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+
+ if (!bsda) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (sa_socklen < bsda->sa_socklen) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (sa_socklen > bsda->sa_socklen) {
+ memset(sa, 0, sa_socklen);
+ sa_socklen = bsda->sa_socklen;
+ }
+
+ memcpy(sa, &bsda->u.ss, sa_socklen);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sa->sa_len = sa_socklen;
+#endif
+ return sa_socklen;
+}
+
+bool tsocket_address_is_inet(const struct tsocket_address *addr, const char *fam)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+
+ if (!bsda) {
+ return false;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_INET:
+ if (strcasecmp(fam, "ip") == 0) {
+ return true;
+ }
+
+ if (strcasecmp(fam, "ipv4") == 0) {
+ return true;
+ }
+
+ return false;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (strcasecmp(fam, "ip") == 0) {
+ return true;
+ }
+
+ if (strcasecmp(fam, "ipv6") == 0) {
+ return true;
+ }
+
+ return false;
+#endif
+ }
+
+ return false;
+}
+
+int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *addr,
+ uint16_t port,
+ struct tsocket_address **_addr,
+ const char *location)
+{
+ struct addrinfo hints;
+ struct addrinfo *result = NULL;
+ char port_str[6];
+ int ret;
+
+ ZERO_STRUCT(hints);
+ /*
+ * we use SOCKET_STREAM here to get just one result
+ * back from getaddrinfo().
+ */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+ if (strcasecmp(fam, "ip") == 0) {
+ hints.ai_family = AF_UNSPEC;
+ if (!addr) {
+#ifdef HAVE_IPV6
+ addr = "::";
+#else
+ addr = "0.0.0.0";
+#endif
+ }
+ } else if (strcasecmp(fam, "ipv4") == 0) {
+ hints.ai_family = AF_INET;
+ if (!addr) {
+ addr = "0.0.0.0";
+ }
+#ifdef HAVE_IPV6
+ } else if (strcasecmp(fam, "ipv6") == 0) {
+ hints.ai_family = AF_INET6;
+ if (!addr) {
+ addr = "::";
+ }
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ snprintf(port_str, sizeof(port_str), "%u", port);
+
+ ret = getaddrinfo(addr, port_str, &hints, &result);
+ if (ret != 0) {
+ switch (ret) {
+ case EAI_FAIL:
+ case EAI_NONAME:
+#ifdef EAI_ADDRFAMILY
+ case EAI_ADDRFAMILY:
+#endif
+ errno = EINVAL;
+ break;
+ }
+ ret = -1;
+ goto done;
+ }
+
+ if (result->ai_socktype != SOCK_STREAM) {
+ errno = EINVAL;
+ ret = -1;
+ goto done;
+ }
+
+ ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+ result->ai_addr,
+ result->ai_addrlen,
+ _addr,
+ location);
+
+done:
+ if (result) {
+ freeaddrinfo(result);
+ }
+ return ret;
+}
+
+int _tsocket_address_inet_from_hostport_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *host_port_addr,
+ uint16_t default_port,
+ struct tsocket_address **_addr,
+ const char *location)
+{
+ char *pl_sq = NULL;
+ char *pr_sq = NULL;
+ char *pl_period = NULL;
+ char *port_sep = NULL;
+ char *cport = NULL;
+ char *buf = NULL;
+ uint64_t port = 0;
+ int ret;
+ char *s_addr = NULL;
+ uint16_t s_port = default_port;
+ bool conv_ret;
+ bool is_ipv6_by_squares = false;
+
+ if (host_port_addr == NULL) {
+ /* got straight to next function if host_port_addr is NULL */
+ goto get_addr;
+ }
+ buf = talloc_strdup(mem_ctx, host_port_addr);
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ pl_period = strchr_m(buf, '.');
+ port_sep = strrchr_m(buf, ':');
+ pl_sq = strchr_m(buf, '[');
+ pr_sq = strrchr_m(buf, ']');
+ /* See if its IPv4 or IPv6 */
+ /* Only parse IPv6 with squares with/without port, and IPv4 with port */
+ /* Everything else, let tsocket_address_inet_from string() */
+ /* find parsing errors */
+#ifdef HAVE_IPV6
+ is_ipv6_by_squares = (pl_sq != NULL && pr_sq != NULL && pr_sq > pl_sq);
+#endif
+ if (is_ipv6_by_squares) {
+ /* IPv6 possibly with port - squares detected */
+ port_sep = pr_sq + 1;
+ if (*port_sep == '\0') {
+ s_addr = pl_sq + 1;
+ *pr_sq = 0;
+ s_port = default_port;
+ goto get_addr;
+ }
+ if (*port_sep != ':') {
+ errno = EINVAL;
+ return -1;
+ }
+ cport = port_sep + 1;
+ conv_ret = conv_str_u64(cport, &port);
+ if (!conv_ret) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (port > 65535) {
+ errno = EINVAL;
+ return -1;
+ }
+ s_port = (uint16_t)port;
+ *port_sep = 0;
+ *pr_sq = 0;
+ s_addr = pl_sq + 1;
+ *pl_sq = 0;
+ goto get_addr;
+ } else if (pl_period != NULL && port_sep != NULL) {
+ /* IPv4 with port - more than one period in string */
+ cport = port_sep + 1;
+ conv_ret = conv_str_u64(cport, &port);
+ if (!conv_ret) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (port > 65535) {
+ errno = EINVAL;
+ return -1;
+ }
+ s_port = (uint16_t)port;
+ *port_sep = 0;
+ s_addr = buf;
+ goto get_addr;
+ } else {
+ /* Everything else, let tsocket_address_inet_from string() */
+ /* find parsing errors */
+ s_addr = buf;
+ s_port = default_port;
+ goto get_addr;
+ }
+get_addr:
+ ret = _tsocket_address_inet_from_strings(
+ mem_ctx, fam, s_addr, s_port, _addr, location);
+
+ return ret;
+}
+
+char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+ char addr_str[INET6_ADDRSTRLEN+1];
+ const char *str;
+
+ if (!bsda) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_INET:
+ str = inet_ntop(bsda->u.in.sin_family,
+ &bsda->u.in.sin_addr,
+ addr_str, sizeof(addr_str));
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ str = inet_ntop(bsda->u.in6.sin6_family,
+ &bsda->u.in6.sin6_addr,
+ addr_str, sizeof(addr_str));
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (!str) {
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, str);
+}
+
+uint16_t tsocket_address_inet_port(const struct tsocket_address *addr)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+ uint16_t port = 0;
+
+ if (!bsda) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_INET:
+ port = ntohs(bsda->u.in.sin_port);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ port = ntohs(bsda->u.in6.sin6_port);
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return 0;
+ }
+
+ return port;
+}
+
+int tsocket_address_inet_set_port(struct tsocket_address *addr,
+ uint16_t port)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+
+ if (!bsda) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_INET:
+ bsda->u.in.sin_port = htons(port);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ bsda->u.in6.sin6_port = htons(port);
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+bool tsocket_address_is_unix(const struct tsocket_address *addr)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+
+ if (!bsda) {
+ return false;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_UNIX:
+ return true;
+ }
+
+ return false;
+}
+
+int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+ const char *path,
+ struct tsocket_address **_addr,
+ const char *location)
+{
+ struct sockaddr_un un;
+ void *p = &un;
+ int ret;
+
+ if (!path) {
+ path = "";
+ }
+
+ if (strlen(path) > sizeof(un.sun_path)-1) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ ZERO_STRUCT(un);
+ un.sun_family = AF_UNIX;
+ strncpy(un.sun_path, path, sizeof(un.sun_path)-1);
+
+ ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+ (struct sockaddr *)p,
+ sizeof(un),
+ _addr,
+ location);
+
+ return ret;
+}
+
+char *tsocket_address_unix_path(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+ const char *str;
+
+ if (!bsda) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_UNIX:
+ str = bsda->u.un.sun_path;
+ break;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, str);
+}
+
+static char *tsocket_address_bsd_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+ char *str;
+ char *addr_str;
+ const char *prefix = NULL;
+ uint16_t port;
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_UNIX:
+ return talloc_asprintf(mem_ctx, "unix:%s",
+ bsda->u.un.sun_path);
+ case AF_INET:
+ prefix = "ipv4";
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ prefix = "ipv6";
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ addr_str = tsocket_address_inet_addr_string(addr, mem_ctx);
+ if (!addr_str) {
+ return NULL;
+ }
+
+ port = tsocket_address_inet_port(addr);
+
+ str = talloc_asprintf(mem_ctx, "%s:%s:%u",
+ prefix, addr_str, port);
+ talloc_free(addr_str);
+
+ return str;
+}
+
+static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx,
+ const char *location)
+{
+ struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
+ struct samba_sockaddr);
+ struct tsocket_address *copy;
+ int ret;
+
+ ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+ &bsda->u.sa,
+ bsda->sa_socklen,
+ &copy,
+ location);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ return copy;
+}
+
+static const struct tsocket_address_ops tsocket_address_bsd_ops = {
+ .name = "bsd",
+ .string = tsocket_address_bsd_string,
+ .copy = tsocket_address_bsd_copy,
+};
+
+struct tdgram_bsd {
+ int fd;
+
+ void *event_ptr;
+ struct tevent_fd *fde;
+ bool optimize_recvfrom;
+ bool netlink;
+
+ void *readable_private;
+ void (*readable_handler)(void *private_data);
+ void *writeable_private;
+ void (*writeable_handler)(void *private_data);
+};
+
+bool tdgram_bsd_optimize_recvfrom(struct tdgram_context *dgram,
+ bool on)
+{
+ struct tdgram_bsd *bsds =
+ talloc_get_type(_tdgram_context_data(dgram),
+ struct tdgram_bsd);
+ bool old;
+
+ if (bsds == NULL) {
+ /* not a bsd socket */
+ return false;
+ }
+
+ old = bsds->optimize_recvfrom;
+ bsds->optimize_recvfrom = on;
+
+ return old;
+}
+
+static void tdgram_bsd_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tdgram_bsd *bsds = talloc_get_type_abort(private_data,
+ struct tdgram_bsd);
+
+ if (flags & TEVENT_FD_WRITE) {
+ bsds->writeable_handler(bsds->writeable_private);
+ return;
+ }
+ if (flags & TEVENT_FD_READ) {
+ if (!bsds->readable_handler) {
+ TEVENT_FD_NOT_READABLE(bsds->fde);
+ return;
+ }
+ bsds->readable_handler(bsds->readable_private);
+ return;
+ }
+}
+
+static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
+{
+ if (ev == NULL) {
+ if (handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bsds->readable_handler) {
+ return 0;
+ }
+ bsds->readable_handler = NULL;
+ bsds->readable_private = NULL;
+
+ return 0;
+ }
+
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
+ }
+
+ if (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
+
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd, TEVENT_FD_READ,
+ tdgram_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->readable_handler) {
+ TEVENT_FD_READABLE(bsds->fde);
+ }
+
+ bsds->readable_handler = handler;
+ bsds->readable_private = private_data;
+
+ return 0;
+}
+
+static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
+{
+ if (ev == NULL) {
+ if (handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bsds->writeable_handler) {
+ return 0;
+ }
+ bsds->writeable_handler = NULL;
+ bsds->writeable_private = NULL;
+ TEVENT_FD_NOT_WRITEABLE(bsds->fde);
+
+ return 0;
+ }
+
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
+ }
+
+ if (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
+
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd, TEVENT_FD_WRITE,
+ tdgram_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->writeable_handler) {
+ TEVENT_FD_WRITEABLE(bsds->fde);
+ }
+
+ bsds->writeable_handler = handler;
+ bsds->writeable_private = private_data;
+
+ return 0;
+}
+
+struct tdgram_bsd_recvfrom_state {
+ struct tdgram_context *dgram;
+ bool first_try;
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+};
+
+static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
+ struct tdgram_bsd);
+
+ tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static void tdgram_bsd_recvfrom_handler(void *private_data);
+
+static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tevent_req *req;
+ struct tdgram_bsd_recvfrom_state *state;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_recvfrom_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->dgram = dgram;
+ state->first_try= true;
+ state->buf = NULL;
+ state->len = 0;
+ state->src = NULL;
+
+ talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor);
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit readable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ if (bsds->optimize_recvfrom) {
+ /*
+ * We only do the optimization on
+ * recvfrom if the caller asked for it.
+ *
+ * This is needed because in most cases
+ * we prefer to flush send buffers before
+ * receiving incoming requests.
+ */
+ tdgram_bsd_recvfrom_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+ }
+
+ ret = tdgram_bsd_set_readable_handler(bsds, ev,
+ tdgram_bsd_recvfrom_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_bsd_recvfrom_handler(void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_bsd_recvfrom_state);
+ struct tdgram_context *dgram = state->dgram;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct samba_sockaddr *bsda = NULL;
+ ssize_t ret;
+ int err;
+ bool retry;
+
+ if (bsds->netlink) {
+ ret = tsocket_bsd_netlink_pending(bsds->fd);
+ } else {
+ ret = tsocket_bsd_pending(bsds->fd);
+ }
+
+ if (state->first_try && ret == 0) {
+ state->first_try = false;
+ /* retry later */
+ return;
+ }
+ state->first_try = false;
+
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ /* note that 'ret' can be 0 here */
+ state->buf = talloc_array(state, uint8_t, ret);
+ if (tevent_req_nomem(state->buf, req)) {
+ return;
+ }
+ state->len = ret;
+
+ state->src = tsocket_address_create(state,
+ &tsocket_address_bsd_ops,
+ &bsda,
+ struct samba_sockaddr,
+ __location__ "bsd_recvfrom");
+ if (tevent_req_nomem(state->src, req)) {
+ return;
+ }
+
+ ZERO_STRUCTP(bsda);
+ bsda->sa_socklen = sizeof(bsda->u.ss);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ bsda->u.sa.sa_len = bsda->sa_socklen;
+#endif
+
+ ret = recvfrom(bsds->fd, state->buf, state->len, 0,
+ &bsda->u.sa, &bsda->sa_socklen);
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ /*
+ * Some systems (FreeBSD, see bug #7115) return too much
+ * bytes in tsocket_bsd_pending()/ioctl(fd, FIONREAD, ...),
+ * the return value includes some IP/UDP header bytes,
+ * while recvfrom() just returns the payload.
+ */
+ state->buf = talloc_realloc(state, state->buf, uint8_t, ret);
+ if (tevent_req_nomem(state->buf, req)) {
+ return;
+ }
+ state->len = ret;
+
+ tevent_req_done(req);
+}
+
+static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src)
+{
+ struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_bsd_recvfrom_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ *buf = talloc_move(mem_ctx, &state->buf);
+ ret = state->len;
+ if (src) {
+ *src = talloc_move(mem_ctx, &state->src);
+ }
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tdgram_bsd_sendto_state {
+ struct tdgram_context *dgram;
+
+ const uint8_t *buf;
+ size_t len;
+ const struct tsocket_address *dst;
+
+ ssize_t ret;
+};
+
+static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
+ struct tdgram_bsd);
+
+ tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static void tdgram_bsd_sendto_handler(void *private_data);
+
+static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf,
+ size_t len,
+ const struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tdgram_bsd_sendto_state *state;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_sendto_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->dgram = dgram;
+ state->buf = buf;
+ state->len = len;
+ state->dst = dst;
+ state->ret = -1;
+
+ talloc_set_destructor(state, tdgram_bsd_sendto_destructor);
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit writeable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ tdgram_bsd_sendto_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+
+ ret = tdgram_bsd_set_writeable_handler(bsds, ev,
+ tdgram_bsd_sendto_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_bsd_sendto_handler(void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
+ struct tdgram_bsd_sendto_state);
+ struct tdgram_context *dgram = state->dgram;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct sockaddr *sa = NULL;
+ socklen_t sa_socklen = 0;
+ ssize_t ret;
+ int err;
+ bool retry;
+
+ if (state->dst) {
+ struct samba_sockaddr *bsda =
+ talloc_get_type(state->dst->private_data,
+ struct samba_sockaddr);
+
+ sa = &bsda->u.sa;
+ sa_socklen = bsda->sa_socklen;
+ }
+
+ ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_socklen);
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+
+ if (err == EMSGSIZE) {
+ /* round up in 1K increments */
+ int bufsize = ((state->len + 1023) & (~1023));
+
+ ret = setsockopt(bsds->fd, SOL_SOCKET, SO_SNDBUF, &bufsize,
+ sizeof(bufsize));
+ if (ret == 0) {
+ /*
+ * We do the retry here, rather then via the
+ * handler, as we only want to retry once for
+ * this condition, so if there is a mismatch
+ * between what setsockopt() accepts and what can
+ * actually be sent, we do not end up in a
+ * loop.
+ */
+
+ ret = sendto(bsds->fd, state->buf, state->len,
+ 0, sa, sa_socklen);
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) { /* retry later */
+ return;
+ }
+ }
+ }
+
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno)
+{
+ struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
+ struct tdgram_bsd_sendto_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tdgram_bsd_disconnect_state {
+ uint8_t __dummy;
+};
+
+static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tevent_req *req;
+ struct tdgram_bsd_disconnect_state *state;
+ int ret;
+ int err;
+ bool dummy;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ TALLOC_FREE(bsds->fde);
+ ret = close(bsds->fd);
+ bsds->fd = -1;
+ err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
+ if (tevent_req_error(req, err)) {
+ goto post;
+ }
+
+ tevent_req_done(req);
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static int tdgram_bsd_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
+}
+
+static const struct tdgram_context_ops tdgram_bsd_ops = {
+ .name = "bsd",
+
+ .recvfrom_send = tdgram_bsd_recvfrom_send,
+ .recvfrom_recv = tdgram_bsd_recvfrom_recv,
+
+ .sendto_send = tdgram_bsd_sendto_send,
+ .sendto_recv = tdgram_bsd_sendto_recv,
+
+ .disconnect_send = tdgram_bsd_disconnect_send,
+ .disconnect_recv = tdgram_bsd_disconnect_recv,
+};
+
+static int tdgram_bsd_destructor(struct tdgram_bsd *bsds)
+{
+ TALLOC_FREE(bsds->fde);
+ if (bsds->fd != -1) {
+ close(bsds->fd);
+ bsds->fd = -1;
+ }
+ return 0;
+}
+
+static int tdgram_bsd_dgram_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ bool broadcast,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **_dgram,
+ const char *location)
+{
+ struct samba_sockaddr *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct samba_sockaddr);
+ struct samba_sockaddr *rbsda = NULL;
+ struct tdgram_context *dgram;
+ struct tdgram_bsd *bsds;
+ int fd;
+ int ret;
+ bool do_bind = false;
+ bool do_reuseaddr = false;
+ bool do_ipv6only = false;
+ bool is_inet = false;
+ int sa_fam = lbsda->u.sa.sa_family;
+
+ if (remote) {
+ rbsda = talloc_get_type_abort(remote->private_data,
+ struct samba_sockaddr);
+ }
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_UNIX:
+ if (broadcast) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (lbsda->u.un.sun_path[0] != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ break;
+ case AF_INET:
+ if (lbsda->u.in.sin_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
+ do_bind = true;
+ }
+ is_inet = true;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (lbsda->u.in6.sin6_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (memcmp(&in6addr_any,
+ &lbsda->u.in6.sin6_addr,
+ sizeof(in6addr_any)) != 0) {
+ do_bind = true;
+ }
+ is_inet = true;
+ do_ipv6only = true;
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!do_bind && is_inet && rbsda) {
+ sa_fam = rbsda->u.sa.sa_family;
+ switch (sa_fam) {
+ case AF_INET:
+ do_ipv6only = false;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ do_ipv6only = true;
+ break;
+#endif
+ }
+ }
+
+ fd = socket(sa_fam, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return -1;
+ }
+
+ fd = tsocket_bsd_common_prepare_fd(fd, true);
+ if (fd < 0) {
+ return -1;
+ }
+
+ dgram = tdgram_context_create(mem_ctx,
+ &tdgram_bsd_ops,
+ &bsds,
+ struct tdgram_bsd,
+ location);
+ if (!dgram) {
+ int saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return -1;
+ }
+ ZERO_STRUCTP(bsds);
+ bsds->fd = fd;
+ talloc_set_destructor(bsds, tdgram_bsd_destructor);
+
+#ifdef HAVE_IPV6
+ if (do_ipv6only) {
+ int val = 1;
+
+ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+#endif
+
+ if (broadcast) {
+ int val = 1;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ if (do_reuseaddr) {
+ int val = 1;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ if (do_bind) {
+ ret = bind(fd, &lbsda->u.sa, lbsda->sa_socklen);
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ if (rbsda) {
+ if (rbsda->u.sa.sa_family != sa_fam) {
+ talloc_free(dgram);
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = connect(fd, &rbsda->u.sa, rbsda->sa_socklen);
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ *_dgram = dgram;
+ return 0;
+}
+
+int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tdgram_context **_dgram,
+ const char *location)
+{
+ struct tdgram_context *dgram;
+ struct tdgram_bsd *bsds;
+#ifdef HAVE_LINUX_RTNETLINK_H
+ int result;
+ struct sockaddr sa;
+ socklen_t sa_len = sizeof(struct sockaddr);
+#endif
+
+ dgram = tdgram_context_create(mem_ctx,
+ &tdgram_bsd_ops,
+ &bsds,
+ struct tdgram_bsd,
+ location);
+ if (!dgram) {
+ return -1;
+ }
+ ZERO_STRUCTP(bsds);
+ bsds->fd = fd;
+ talloc_set_destructor(bsds, tdgram_bsd_destructor);
+
+ *_dgram = dgram;
+
+#ifdef HAVE_LINUX_RTNETLINK_H
+ /*
+ * Try to determine the protocol family and remember if it's
+ * AF_NETLINK. We don't care if this fails.
+ */
+ result = getsockname(fd, &sa, &sa_len);
+ if (result == 0 && sa.sa_family == AF_NETLINK) {
+ bsds->netlink = true;
+ }
+#endif
+
+ return 0;
+}
+
+int _tdgram_inet_udp_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location)
+{
+ struct samba_sockaddr *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct samba_sockaddr);
+ int ret;
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_INET:
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = tdgram_bsd_dgram_socket(local, remote, false,
+ mem_ctx, dgram, location);
+
+ return ret;
+}
+
+int _tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location)
+{
+ struct samba_sockaddr *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct samba_sockaddr);
+ int ret;
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_INET:
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ /* only ipv4 */
+ errno = EINVAL;
+ return -1;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = tdgram_bsd_dgram_socket(local, NULL, true,
+ mem_ctx, dgram, location);
+
+ return ret;
+}
+
+int _tdgram_unix_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location)
+{
+ struct samba_sockaddr *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct samba_sockaddr);
+ int ret;
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_UNIX:
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = tdgram_bsd_dgram_socket(local, remote, false,
+ mem_ctx, dgram, location);
+
+ return ret;
+}
+
+struct tstream_bsd {
+ int fd;
+ int error;
+
+ void *event_ptr;
+ struct tevent_fd *fde;
+ bool optimize_readv;
+ bool fail_readv_first_error;
+
+ void *readable_private;
+ void (*readable_handler)(void *private_data);
+ void *writeable_private;
+ void (*writeable_handler)(void *private_data);
+};
+
+bool tstream_bsd_optimize_readv(struct tstream_context *stream,
+ bool on)
+{
+ struct tstream_bsd *bsds =
+ talloc_get_type(_tstream_context_data(stream),
+ struct tstream_bsd);
+ bool old;
+
+ if (bsds == NULL) {
+ /* not a bsd socket */
+ return false;
+ }
+
+ old = bsds->optimize_readv;
+ bsds->optimize_readv = on;
+
+ return old;
+}
+
+bool tstream_bsd_fail_readv_first_error(struct tstream_context *stream,
+ bool on)
+{
+ struct tstream_bsd *bsds =
+ talloc_get_type(_tstream_context_data(stream),
+ struct tstream_bsd);
+ bool old;
+
+ if (bsds == NULL) {
+ /* not a bsd socket */
+ return false;
+ }
+
+ old = bsds->fail_readv_first_error;
+ bsds->fail_readv_first_error = on;
+
+ return old;
+}
+
+static void tstream_bsd_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tstream_bsd *bsds = talloc_get_type_abort(private_data,
+ struct tstream_bsd);
+
+ if (flags & TEVENT_FD_ERROR) {
+ /*
+ * We lazily keep TEVENT_FD_READ alive
+ * in tstream_bsd_set_readable_handler()
+ *
+ * So we have to check TEVENT_FD_READ
+ * as well as bsds->readable_handler
+ *
+ * We only drain remaining data from the
+ * the recv queue if available and desired.
+ */
+ if ((flags & TEVENT_FD_READ) &&
+ !bsds->fail_readv_first_error &&
+ (bsds->readable_handler != NULL))
+ {
+ /*
+ * If there's still data to read
+ * we allow it to be read until
+ * we reach EOF (=> EPIPE).
+ */
+ bsds->readable_handler(bsds->readable_private);
+ return;
+ }
+
+ /*
+ * If there's no data left to read,
+ * we get the error.
+ *
+ * It means we no longer call any readv or
+ * writev, as bsds->error is checked first.
+ */
+ if (bsds->error == 0) {
+ int ret = samba_socket_poll_or_sock_error(bsds->fd);
+
+ if (ret == -1) {
+ bsds->error = errno;
+ }
+ /* fallback to EPIPE */
+ if (bsds->error == 0) {
+ bsds->error = EPIPE;
+ }
+ }
+
+ /*
+ * Let write to fail early.
+ *
+ * Note we only need to check TEVENT_FD_WRITE
+ * as tstream_bsd_set_writeable_handler()
+ * clear it together with the handler.
+ */
+ if (flags & TEVENT_FD_WRITE) {
+ bsds->writeable_handler(bsds->writeable_private);
+ return;
+ }
+
+ /* We prefer the readable handler to fire first. */
+ if (bsds->readable_handler != NULL) {
+ bsds->readable_handler(bsds->readable_private);
+ return;
+ }
+
+ /* As last resort we notify the writeable handler */
+ if (bsds->writeable_handler != NULL) {
+ bsds->writeable_handler(bsds->writeable_private);
+ return;
+ }
+
+ /*
+ * We may hit this because we don't clear TEVENT_FD_ERROR
+ * in tstream_bsd_set_readable_handler() nor
+ * tstream_bsd_set_writeable_handler().
+ *
+ * As we already captured the error, we can remove
+ * the fde completely.
+ */
+ TALLOC_FREE(bsds->fde);
+ return;
+ }
+ if (flags & TEVENT_FD_WRITE) {
+ bsds->writeable_handler(bsds->writeable_private);
+ return;
+ }
+ if (flags & TEVENT_FD_READ) {
+ if (!bsds->readable_handler) {
+ /*
+ * tstream_bsd_set_readable_handler
+ * doesn't clear TEVENT_FD_READ.
+ *
+ * In order to avoid cpu-spinning
+ * we need to clear it here.
+ */
+ TEVENT_FD_NOT_READABLE(bsds->fde);
+
+ /*
+ * Here we're lazy and keep TEVENT_FD_ERROR
+ * alive. If it's triggered the next time
+ * we'll handle it gracefully above
+ * and end up with TALLOC_FREE(bsds->fde);
+ * in order to spin on TEVENT_FD_ERROR.
+ */
+ return;
+ }
+ bsds->readable_handler(bsds->readable_private);
+ return;
+ }
+}
+
+static int tstream_bsd_set_readable_handler(struct tstream_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
+{
+ if (ev == NULL) {
+ if (handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bsds->readable_handler) {
+ return 0;
+ }
+ bsds->readable_handler = NULL;
+ bsds->readable_private = NULL;
+
+ /*
+ * Here we are lazy as it's very likely that the next
+ * tevent_readv_send() will come in shortly,
+ * so we keep TEVENT_FD_READ alive.
+ */
+ return 0;
+ }
+
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
+ }
+
+ if (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
+
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd,
+ TEVENT_FD_ERROR | TEVENT_FD_READ,
+ tstream_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->readable_handler) {
+ TEVENT_FD_READABLE(bsds->fde);
+ /*
+ * TEVENT_FD_ERROR is likely already set, so
+ * TEVENT_FD_WANTERROR() is most likely a no-op.
+ */
+ TEVENT_FD_WANTERROR(bsds->fde);
+ }
+
+ bsds->readable_handler = handler;
+ bsds->readable_private = private_data;
+
+ return 0;
+}
+
+static int tstream_bsd_set_writeable_handler(struct tstream_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
+{
+ if (ev == NULL) {
+ if (handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bsds->writeable_handler) {
+ return 0;
+ }
+ bsds->writeable_handler = NULL;
+ bsds->writeable_private = NULL;
+
+ /*
+ * The writeable handler is only
+ * set if we got EAGAIN or a short
+ * writev on the first try, so
+ * this isn't the hot path.
+ *
+ * Here we are lazy and leave TEVENT_FD_ERROR
+ * alive as it's shared with the readable
+ * handler. So we only clear TEVENT_FD_WRITE.
+ */
+ TEVENT_FD_NOT_WRITEABLE(bsds->fde);
+ return 0;
+ }
+
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
+ }
+
+ if (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
+
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd,
+ TEVENT_FD_ERROR | TEVENT_FD_WRITE,
+ tstream_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->writeable_handler) {
+ TEVENT_FD_WRITEABLE(bsds->fde);
+ /*
+ * TEVENT_FD_ERROR is likely already set, so
+ * TEVENT_FD_WANTERROR() is most likely a no-op.
+ */
+ TEVENT_FD_WANTERROR(bsds->fde);
+ }
+
+ bsds->writeable_handler = handler;
+ bsds->writeable_private = private_data;
+
+ return 0;
+}
+
+static ssize_t tstream_bsd_pending_bytes(struct tstream_context *stream)
+{
+ struct tstream_bsd *bsds = tstream_context_data(stream,
+ struct tstream_bsd);
+ ssize_t ret;
+
+ if (bsds->fd == -1) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ if (bsds->error != 0) {
+ errno = bsds->error;
+ return -1;
+ }
+
+ ret = tsocket_bsd_pending(bsds->fd);
+ if (ret == -1) {
+ /*
+ * remember the error and don't
+ * allow further requests
+ */
+ bsds->error = errno;
+ }
+
+ return ret;
+}
+
+struct tstream_bsd_readv_state {
+ struct tstream_context *stream;
+
+ struct iovec *vector;
+ size_t count;
+
+ int ret;
+};
+
+static int tstream_bsd_readv_destructor(struct tstream_bsd_readv_state *state)
+{
+ struct tstream_bsd *bsds = tstream_context_data(state->stream,
+ struct tstream_bsd);
+
+ tstream_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static void tstream_bsd_readv_handler(void *private_data);
+
+static struct tevent_req *tstream_bsd_readv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_bsd_readv_state *state;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bsd_readv_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->stream = stream;
+ /* we make a copy of the vector so that we can modify it */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
+ goto post;
+ }
+ memcpy(state->vector, vector, sizeof(struct iovec)*count);
+ state->count = count;
+ state->ret = 0;
+
+ talloc_set_destructor(state, tstream_bsd_readv_destructor);
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit readable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ if (bsds->optimize_readv) {
+ /*
+ * We only do the optimization on
+ * readv if the caller asked for it.
+ *
+ * This is needed because in most cases
+ * we prefer to flush send buffers before
+ * receiving incoming requests.
+ */
+ tstream_bsd_readv_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+ }
+
+ ret = tstream_bsd_set_readable_handler(bsds, ev,
+ tstream_bsd_readv_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_bsd_readv_handler(void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tstream_bsd_readv_state *state = tevent_req_data(req,
+ struct tstream_bsd_readv_state);
+ struct tstream_context *stream = state->stream;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
+ int ret;
+ int err;
+ int _count;
+ bool ok, retry;
+
+ if (bsds->error != 0) {
+ tevent_req_error(req, bsds->error);
+ return;
+ }
+
+ ret = readv(bsds->fd, state->vector, state->count);
+ if (ret == 0) {
+ /* propagate end of file */
+ bsds->error = EPIPE;
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (err != 0) {
+ /*
+ * remember the error and don't
+ * allow further requests
+ */
+ bsds->error = err;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ state->ret += ret;
+
+ _count = state->count; /* tstream has size_t count, readv has int */
+ ok = iov_advance(&state->vector, &_count, ret);
+ state->count = _count;
+
+ if (!ok) {
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ if (state->count > 0) {
+ /* we have more to read */
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int tstream_bsd_readv_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_bsd_readv_state *state = tevent_req_data(req,
+ struct tstream_bsd_readv_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_bsd_writev_state {
+ struct tstream_context *stream;
+
+ struct iovec *vector;
+ size_t count;
+
+ int ret;
+};
+
+static int tstream_bsd_writev_destructor(struct tstream_bsd_writev_state *state)
+{
+ struct tstream_bsd *bsds = tstream_context_data(state->stream,
+ struct tstream_bsd);
+
+ tstream_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static void tstream_bsd_writev_handler(void *private_data);
+
+static struct tevent_req *tstream_bsd_writev_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_bsd_writev_state *state;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bsd_writev_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->stream = stream;
+ /* we make a copy of the vector so that we can modify it */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
+ goto post;
+ }
+ memcpy(state->vector, vector, sizeof(struct iovec)*count);
+ state->count = count;
+ state->ret = 0;
+
+ talloc_set_destructor(state, tstream_bsd_writev_destructor);
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit writeable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ tstream_bsd_writev_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+
+ ret = tstream_bsd_set_writeable_handler(bsds, ev,
+ tstream_bsd_writev_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_bsd_writev_handler(void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tstream_bsd_writev_state *state = tevent_req_data(req,
+ struct tstream_bsd_writev_state);
+ struct tstream_context *stream = state->stream;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
+ ssize_t ret;
+ int err;
+ int _count;
+ bool ok, retry;
+
+ if (bsds->error != 0) {
+ tevent_req_error(req, bsds->error);
+ return;
+ }
+
+ ret = writev(bsds->fd, state->vector, state->count);
+ if (ret == 0) {
+ /* propagate end of file */
+ bsds->error = EPIPE;
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /*
+ * retry later...
+ */
+ return;
+ }
+ if (err != 0) {
+ /*
+ * remember the error and don't
+ * allow further requests
+ */
+ bsds->error = err;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ state->ret += ret;
+
+ _count = state->count; /* tstream has size_t count, writev has int */
+ ok = iov_advance(&state->vector, &_count, ret);
+ state->count = _count;
+
+ if (!ok) {
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ if (state->count > 0) {
+ /*
+ * we have more to write
+ */
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int tstream_bsd_writev_recv(struct tevent_req *req, int *perrno)
+{
+ struct tstream_bsd_writev_state *state = tevent_req_data(req,
+ struct tstream_bsd_writev_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_bsd_disconnect_state {
+ void *__dummy;
+};
+
+static struct tevent_req *tstream_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream)
+{
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
+ struct tevent_req *req;
+ struct tstream_bsd_disconnect_state *state;
+ int ret;
+ int err;
+ bool dummy;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bsd_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ TALLOC_FREE(bsds->fde);
+ ret = close(bsds->fd);
+ bsds->fd = -1;
+ err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
+ if (tevent_req_error(req, err)) {
+ goto post;
+ }
+
+ tevent_req_done(req);
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static int tstream_bsd_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
+}
+
+static const struct tstream_context_ops tstream_bsd_ops = {
+ .name = "bsd",
+
+ .pending_bytes = tstream_bsd_pending_bytes,
+
+ .readv_send = tstream_bsd_readv_send,
+ .readv_recv = tstream_bsd_readv_recv,
+
+ .writev_send = tstream_bsd_writev_send,
+ .writev_recv = tstream_bsd_writev_recv,
+
+ .disconnect_send = tstream_bsd_disconnect_send,
+ .disconnect_recv = tstream_bsd_disconnect_recv,
+};
+
+static int tstream_bsd_destructor(struct tstream_bsd *bsds)
+{
+ TALLOC_FREE(bsds->fde);
+ if (bsds->fd != -1) {
+ close(bsds->fd);
+ bsds->fd = -1;
+ }
+ return 0;
+}
+
+int _tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_context *stream;
+ struct tstream_bsd *bsds;
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_bsd_ops,
+ &bsds,
+ struct tstream_bsd,
+ location);
+ if (!stream) {
+ return -1;
+ }
+ ZERO_STRUCTP(bsds);
+ bsds->fd = fd;
+ talloc_set_destructor(bsds, tstream_bsd_destructor);
+
+ *_stream = stream;
+ return 0;
+}
+
+struct tstream_bsd_connect_state {
+ int fd;
+ struct tevent_fd *fde;
+ struct tstream_conext *stream;
+ struct tsocket_address *local;
+};
+
+static int tstream_bsd_connect_destructor(struct tstream_bsd_connect_state *state)
+{
+ TALLOC_FREE(state->fde);
+ if (state->fd != -1) {
+ close(state->fd);
+ state->fd = -1;
+ }
+
+ return 0;
+}
+
+static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int sys_errno,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote)
+{
+ struct tevent_req *req;
+ struct tstream_bsd_connect_state *state;
+ struct samba_sockaddr *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct samba_sockaddr);
+ struct samba_sockaddr *lrbsda = NULL;
+ struct samba_sockaddr *rbsda =
+ talloc_get_type_abort(remote->private_data,
+ struct samba_sockaddr);
+ int ret;
+ bool do_bind = false;
+ bool do_reuseaddr = false;
+ bool do_ipv6only = false;
+ bool is_inet = false;
+ int sa_fam = lbsda->u.sa.sa_family;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bsd_connect_state);
+ if (!req) {
+ return NULL;
+ }
+ state->fd = -1;
+ state->fde = NULL;
+
+ talloc_set_destructor(state, tstream_bsd_connect_destructor);
+
+ /* give the wrappers a chance to report an error */
+ if (sys_errno != 0) {
+ tevent_req_error(req, sys_errno);
+ goto post;
+ }
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_UNIX:
+ if (lbsda->u.un.sun_path[0] != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ break;
+ case AF_INET:
+ if (lbsda->u.in.sin_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
+ do_bind = true;
+ }
+ is_inet = true;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (lbsda->u.in6.sin6_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (memcmp(&in6addr_any,
+ &lbsda->u.in6.sin6_addr,
+ sizeof(in6addr_any)) != 0) {
+ do_bind = true;
+ }
+ is_inet = true;
+ do_ipv6only = true;
+ break;
+#endif
+ default:
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ if (!do_bind && is_inet) {
+ sa_fam = rbsda->u.sa.sa_family;
+ switch (sa_fam) {
+ case AF_INET:
+ do_ipv6only = false;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ do_ipv6only = true;
+ break;
+#endif
+ }
+ }
+
+ if (is_inet) {
+ state->local = tsocket_address_create(state,
+ &tsocket_address_bsd_ops,
+ &lrbsda,
+ struct samba_sockaddr,
+ __location__ "bsd_connect");
+ if (tevent_req_nomem(state->local, req)) {
+ goto post;
+ }
+
+ ZERO_STRUCTP(lrbsda);
+ lrbsda->sa_socklen = sizeof(lrbsda->u.ss);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ lrbsda->u.sa.sa_len = lrbsda->sa_socklen;
+#endif
+ }
+
+ state->fd = socket(sa_fam, SOCK_STREAM, 0);
+ if (state->fd == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ state->fd = tsocket_bsd_common_prepare_fd(state->fd, true);
+ if (state->fd == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+#ifdef HAVE_IPV6
+ if (do_ipv6only) {
+ int val = 1;
+
+ ret = setsockopt(state->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ }
+#endif
+
+ if (do_reuseaddr) {
+ int val = 1;
+
+ ret = setsockopt(state->fd, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ }
+
+ if (do_bind) {
+ ret = bind(state->fd, &lbsda->u.sa, lbsda->sa_socklen);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ }
+
+ if (rbsda->u.sa.sa_family != sa_fam) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ ret = connect(state->fd, &rbsda->u.sa, rbsda->sa_socklen);
+ if (ret == -1) {
+ if (errno == EINPROGRESS) {
+ goto async;
+ }
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ if (!state->local) {
+ tevent_req_done(req);
+ goto post;
+ }
+
+ if (lrbsda != NULL) {
+ ret = getsockname(state->fd,
+ &lrbsda->u.sa,
+ &lrbsda->sa_socklen);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ }
+
+ tevent_req_done(req);
+ goto post;
+
+ async:
+
+ /*
+ * Note for historic reasons TEVENT_FD_WRITE is not enough
+ * to get notified for POLLERR or EPOLLHUP even if they
+ * come together with POLLOUT. That means we need to
+ * use TEVENT_FD_READ in addition until we have
+ * TEVENT_FD_ERROR.
+ */
+ state->fde = tevent_add_fd(ev, state,
+ state->fd,
+ TEVENT_FD_ERROR | TEVENT_FD_WRITE,
+ tstream_bsd_connect_fde_handler,
+ req);
+ if (tevent_req_nomem(state->fde, req)) {
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tstream_bsd_connect_state *state = tevent_req_data(req,
+ struct tstream_bsd_connect_state);
+ struct samba_sockaddr *lrbsda = NULL;
+ int ret;
+ int err;
+ bool retry;
+
+ ret = samba_socket_sock_error(state->fd);
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ if (!state->local) {
+ tevent_req_done(req);
+ return;
+ }
+
+ lrbsda = talloc_get_type_abort(state->local->private_data,
+ struct samba_sockaddr);
+
+ ret = getsockname(state->fd, &lrbsda->u.sa, &lrbsda->sa_socklen);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int tstream_bsd_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct tsocket_address **local,
+ const char *location)
+{
+ struct tstream_bsd_connect_state *state = tevent_req_data(req,
+ struct tstream_bsd_connect_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = _tstream_bsd_existing_socket(mem_ctx,
+ state->fd,
+ stream,
+ location);
+ if (ret == -1) {
+ *perrno = errno;
+ goto done;
+ }
+ TALLOC_FREE(state->fde);
+ state->fd = -1;
+
+ if (local) {
+ *local = talloc_move(mem_ctx, &state->local);
+ }
+ }
+
+done:
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tevent_req * tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote)
+{
+ struct samba_sockaddr *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct samba_sockaddr);
+ struct tevent_req *req;
+ int sys_errno = 0;
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_INET:
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ break;
+#endif
+ default:
+ sys_errno = EINVAL;
+ break;
+ }
+
+ req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
+
+ return req;
+}
+
+int _tstream_inet_tcp_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct tsocket_address **local,
+ const char *location)
+{
+ return tstream_bsd_connect_recv(req, perrno,
+ mem_ctx, stream, local,
+ location);
+}
+
+struct tevent_req * tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote)
+{
+ struct samba_sockaddr *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct samba_sockaddr);
+ struct tevent_req *req;
+ int sys_errno = 0;
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_UNIX:
+ break;
+ default:
+ sys_errno = EINVAL;
+ break;
+ }
+
+ req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
+
+ return req;
+}
+
+int _tstream_unix_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ const char *location)
+{
+ return tstream_bsd_connect_recv(req, perrno,
+ mem_ctx, stream, NULL,
+ location);
+}
+
+int _tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
+ struct tstream_context **_stream1,
+ TALLOC_CTX *mem_ctx2,
+ struct tstream_context **_stream2,
+ const char *location)
+{
+ int ret;
+ int fds[2];
+ int fd1;
+ int fd2;
+ struct tstream_context *stream1 = NULL;
+ struct tstream_context *stream2 = NULL;
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ if (ret == -1) {
+ return -1;
+ }
+ fd1 = fds[0];
+ fd2 = fds[1];
+
+ fd1 = tsocket_bsd_common_prepare_fd(fd1, true);
+ if (fd1 == -1) {
+ int sys_errno = errno;
+ close(fd2);
+ errno = sys_errno;
+ return -1;
+ }
+
+ fd2 = tsocket_bsd_common_prepare_fd(fd2, true);
+ if (fd2 == -1) {
+ int sys_errno = errno;
+ close(fd1);
+ errno = sys_errno;
+ return -1;
+ }
+
+ ret = _tstream_bsd_existing_socket(mem_ctx1,
+ fd1,
+ &stream1,
+ location);
+ if (ret == -1) {
+ int sys_errno = errno;
+ close(fd1);
+ close(fd2);
+ errno = sys_errno;
+ return -1;
+ }
+
+ ret = _tstream_bsd_existing_socket(mem_ctx2,
+ fd2,
+ &stream2,
+ location);
+ if (ret == -1) {
+ int sys_errno = errno;
+ talloc_free(stream1);
+ close(fd2);
+ errno = sys_errno;
+ return -1;
+ }
+
+ *_stream1 = stream1;
+ *_stream2 = stream2;
+ return 0;
+}
+
diff --git a/lib/tsocket/tsocket_guide.txt b/lib/tsocket/tsocket_guide.txt
new file mode 100644
index 0000000..1b56056
--- /dev/null
+++ b/lib/tsocket/tsocket_guide.txt
@@ -0,0 +1,481 @@
+
+Basic design of the tsocket abstraction
+=======================================
+
+The tsocket abstraction is split into two
+different kinds of communication interfaces.
+
+There is the "tstream_context" interface which abstracts
+the communication through a bidirectional
+byte stream between two endpoints.
+
+And there is the "tdgram_context" interface
+which abstracts datagram based communication between any
+number of endpoints.
+
+Both interfaces share the "tsocket_address" abstraction
+for endpoint addresses.
+
+The whole library is based on the talloc(3) and 'tevent' libraries
+and provides "tevent_req" based "foo_send()"/"foo_recv()" functions pairs
+for all abstracted methods that need to be async.
+
+The tsocket_address abstraction
+===============================
+
+A tsocket_address represents a generic socket endpoint.
+It behaves like an abstract class, therefore it has no direct constructor.
+Constructors are described in later sections of this document.
+
+A function to get the string representation of an endpoint for debugging is
+available but callers SHOULD NOT try to parse this string. To get more
+details, callers should use getter methods of the specific tsocket_address
+implementation.
+
+ char *tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+A function to create a copy of the tsocket_address is also available.
+This is useful before doing modifications to a socket
+via additional methods of the specific tsocket_address implementation.
+
+ struct tsocket_address *tsocket_address_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+The tdgram_context abstraction
+==============================
+
+The tdgram_context is like an abstract class for datagram
+based sockets. The interface provides async 'tevent_req' based
+functions similar to recvfrom(2)/sendto(2)/close(2) syscalls.
+
+The tdgram_recvfrom_send() method can be called to ask for the
+next available datagram from the abstracted tdgram_context.
+It returns a 'tevent_req' handle, where the caller can register
+a callback with tevent_req_set_callback(). The callback is triggered
+when a datagram is available or an error occurs.
+
+The callback is then supposed to get the result by calling
+tdgram_recvfrom_recv() on the 'tevent_req'. It returns -1
+and sets '*perrno' to the actual 'errno' on failure.
+Otherwise it returns the length of the datagram
+(0 is never returned!). '*buf' will contain the buffer of the
+datagram and '*src' the abstracted tsocket_address of the sender
+of the received datagram.
+
+The caller can only have one outstanding tdgram_recvfrom_send()
+at a time otherwise the caller will get '*perrno = EBUSY'.
+
+ struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+
+ ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+The tdgram_sendto_send() method can be called to send a
+datagram (specified by a buf/len) to a destination endpoint
+(specified by dst). It is not allowed for len to be 0.
+It returns a 'tevent_req' handle, where the caller can register a
+callback with tevent_req_set_callback(). The callback is triggered
+when the specific implementation (thinks it)
+has delivered the datagram to the "wire".
+
+The callback is then supposed to get the result by calling
+tdgram_sendto_recv() on the 'tevent_req'. It returns -1
+and sets '*perrno' to the actual 'errno' on failure.
+Otherwise it returns the length of the datagram
+(0 is never returned!).
+
+The caller can only have one outstanding tdgram_sendto_send()
+at a time otherwise the caller will get '*perrno = EBUSY'.
+
+ struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst);
+
+ ssize_t tdgram_sendto_recv(struct tevent_req *req,
+ int *perrno);
+
+The tdgram_disconnect_send() method should be used to normally
+shutdown/close the abstracted socket.
+
+The caller should make sure there are no outstanding tdgram_recvfrom_send()
+and tdgram_sendto_send() calls otherwise the caller will get '*perrno = EBUSY'.
+
+Note: you can always use talloc_free(tdgram) to cleanup the resources
+of the tdgram_context on a fatal error.
+
+ struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+
+ int tdgram_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+The tstream_context abstraction
+===============================
+
+A tstream_context is like an abstract class for stream
+based sockets. The interface provides async 'tevent_req' based
+functions similar to the readv(2)/writev(2)/close(2) syscalls.
+
+The tstream_pending_bytes() function is able to report how many bytes of
+the incoming stream have been received but have not been consumed yet.
+It returns -1 and sets 'errno' on failure.
+Otherwise it returns the number of unconsumed bytes (it can return 0!).
+
+ ssize_t tstream_pending_bytes(struct tstream_context *stream);
+
+The tstream_readv_send() method can be called to read a
+specific amount of bytes from the stream into the buffers
+of the given iovec vector. The caller has to preallocate the buffers
+in the iovec vector. The caller might need to use
+tstream_pending_bytes() if the protocol does not have a fixed pdu header
+containing the pdu size. tstream_readv_send() returns a 'tevent_req' handle,
+where the caller can register a callback with tevent_req_set_callback().
+The callback is triggered when all iovec buffers are completely
+filled with bytes from the socket or an error occurs.
+
+The callback is then supposed to get the result by calling
+tstream_readv_recv() on the 'tevent_req'. It returns -1
+and sets '*perrno' to the actual 'errno' on failure.
+Otherwise it returns the total number of bytes received
+(0 is never returned!).
+
+The caller can only have one outstanding tstream_readv_send()
+at a time otherwise the caller will get *perrno = EBUSY.
+
+ struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count);
+
+ int tstream_readv_recv(struct tevent_req *req,
+ int *perrno);
+
+The tstream_writev_send() method can be called to write
+buffers in the given iovec vector into the stream socket.
+It is invalid to pass an empty vector.
+tstream_writev_send() returns a 'tevent_req' handle,
+where the caller can register a callback with tevent_req_set_callback().
+The callback is triggered when the specific implementation (thinks it)
+has delivered the all buffers to the "wire".
+
+The callback is then supposed to get the result by calling
+tstream_writev_recv() on the 'tevent_req'. It returns -1
+and sets '*perrno' to the actual 'errno' on failure.
+Otherwise it returns the total amount of bytes sent
+(0 is never returned!).
+
+The caller can only have one outstanding tstream_writev_send()
+at a time otherwise the caller will get '*perrno = EBUSY'.
+
+ struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count);
+
+ int tstream_writev_recv(struct tevent_req *req,
+ int *perrno);
+
+The tstream_disconnect_send() method should normally be used to
+shutdown/close the abstracted socket.
+
+The caller should make sure there are no outstanding tstream_readv_send()
+and tstream_writev_send() calls otherwise the caller will get '*perrno = EBUSY'.
+
+Note: you can always use talloc_free(tstream) to cleanup the resources
+of the tstream_context on a fatal error.
+
+ struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+
+ int tstream_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+PDU receive helper functions
+============================
+
+In order to simplify the job, for callers that want to implement
+a function to receive a full PDU with a single async function pair,
+some helper functions are provided.
+
+The caller can use the tstream_readv_pdu_send() function
+to ask for the next available PDU on the abstracted tstream_context.
+The caller needs to provide a "next_vector" function and a private
+state for this function. The tstream_readv_pdu engine will ask
+the next_vector function for the next iovec vector to be used.
+There is a tstream_readv_send/recv pair for each vector returned
+by the next_vector function. If the next_vector function detects
+it received a full pdu, it returns an empty vector. The callback
+of the tevent_req (returned by tstream_readv_pdu_send()) is triggered.
+Note: the buffer allocation is completely up to the next_vector function
+and its private state.
+
+See the 'dcerpc_read_ncacn_packet_send/recv' functions in Samba as an
+example.
+
+ typedef int (*tstream_readv_pdu_next_vector_t)(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **vector,
+ size_t *count);
+
+ struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private);
+
+ int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno);
+
+Async 'tevent_queue' based helper functions
+===========================================
+
+In some cases, the caller does not care about the IO ordering on the
+abstracted socket.
+(Remember at the low level there is always only one IO in a specific
+ direction allowed, only one tdgram_sendto_send() at a time).
+
+Some helpers that use 'tevent_queue' are available to simplify handling
+multiple IO requests. The functions just get a 'queue' argument and
+internally serialize all operations.
+
+ struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst);
+
+ ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
+ struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private);
+
+ int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno);
+
+ struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ const struct iovec *vector,
+ size_t count);
+
+ int tstream_writev_queue_recv(struct tevent_req *req, int *perrno);
+
+BSD sockets: ipv4, ipv6 and unix
+================================
+
+The main tsocket library comes with implementations
+for BSD style ipv4, ipv6 and unix sockets.
+
+You can use the tsocket_address_inet_from_strings()
+function to create a tsocket_address for ipv4 and ipv6
+endpoint addresses. "family" can be "ipv4", "ipv6" or "ip".
+With "ip" it autodetects "ipv4" or "ipv6" based on the
+"addr_string" string. "addr_string" must be a valid
+ip address string based on the selected family
+(dns names are not allowed!). But it is valid to pass NULL,
+which gets mapped to "0.0.0.0" or "::".
+It returns -1 and sets errno on error. Otherwise it returns 0.
+
+ int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *family,
+ const char *addr_string,
+ uint16_t port,
+ struct tsocket_address **addr);
+
+To get the ip address string of an existing 'inet' tsocket_address
+you can use the tsocket_address_inet_addr_string() function.
+It will return NULL and set errno to EINVAL if the tsocket_address
+does not represent an ipv4 or ipv6 endpoint address.
+
+ char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+To get the port number of an existing 'inet' tsocket_address
+you can use the tsocket_address_inet_port() function.
+It will return 0 and set errno to EINVAL if the tsocket_address
+does not represent an ipv4 or ipv6 endpoint address.
+
+ uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
+
+To set the port number of an existing 'inet' tsocket_address
+you can use the tsocket_address_inet_set_port() function.
+It will return -1 and set errno to EINVAL if the tsocket_address
+does not represent an ipv4 or ipv6 endpoint address.
+It returns 0 on success.
+
+ int tsocket_address_inet_set_port(struct tsocket_address *addr,
+ uint16_t port);
+
+You can use the tsocket_address_unix_from_path()
+function to create a tsocket_address for unix domain
+endpoint addresses. "path" is the filesystem path
+(NULL will map ""). If the path is longer than
+the low level kernel supports the function will
+return -1 and set errno to ENAMETOOLONG.
+On success it returns 0.
+
+ int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+ const char *path,
+ struct tsocket_address **addr);
+
+To get the path of a 'unix' tsocket_address
+you can use the tsocket_address_unix_path() function.
+It will return NULL and set errno to EINVAL if the tsocket_address
+does not represent a unix domain endpoint path.
+
+ char *tsocket_address_unix_path(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+You can use tdgram_inet_udp_socket() to create a tdgram_context
+for ipv4 or ipv6 UDP communication. "local_address" has to be
+an 'inet' tsocket_address and it has to represent the local
+endpoint. "remote_address" can be NULL or an 'inet' tsocket_address
+presenting a remote endpoint. It returns -1 ans sets errno on error
+and it returns 0 on success.
+
+ int tdgram_inet_udp_socket(const struct tsocket_address *local_address,
+ const struct tsocket_address *remote_address,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram);
+
+You can use tdgram_unix_socket() to create a tdgram_context
+for unix domain datagram communication. "local_address" has to be
+an 'unix' tsocket_address and it has to represent the local
+endpoint. "remote_address" can be NULL or an 'unix' tsocket_address
+presenting a remote endpoint. It returns -1 ans sets errno on error
+and it returns 0 on success.
+
+ int tdgram_unix_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram);
+
+You can use tstream_inet_tcp_connect_send to asynchronously
+connect to a remote ipv4 or ipv6 TCP endpoint and create a
+tstream_context for the stream based communication. "local_address" has to be
+an 'inet' tsocket_address and it has to represent the local
+endpoint. "remote_address" has to be an 'inet' tsocket_address
+presenting a remote endpoint. It returns a 'tevent_req' handle,
+where the caller can register a callback with tevent_req_set_callback().
+The callback is triggered when a socket is connected and ready for IO
+or an error happened.
+
+The callback is then supposed to get the result by calling
+tstream_inet_tcp_connect_recv() on the 'tevent_req'. It returns -1
+and sets '*perrno' to the actual 'errno' on failure.
+It returns 0 on success and returns the new tstream_context
+in '*stream'.
+
+ struct tevent_req *tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local_address,
+ const struct tsocket_address *remote_address);
+
+ int tstream_inet_tcp_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream);
+
+You can use tstream_unix_connect_send to asynchronously
+connect to a unix domain endpoint and create a
+tstream_context for the stream based communication.
+"local_address" has to be an 'unix' tsocket_address and
+it has to represent the local endpoint. "remote_address"
+has to be an 'inet' tsocket_address presenting a remote endpoint.
+It returns a 'tevent_req' handle, where the caller can register
+a callback with tevent_req_set_callback(). The callback is
+triggered when a socket is connected and ready for IO
+or an error happened.
+
+The callback is then supposed to get the result by calling
+tstream_unix_connect_recv() on the 'tevent_req'. It returns -1
+and sets '*perrno' to the actual 'errno' on failure.
+It returns 0 on success and returns the new tstream_context
+in '*stream'.
+
+ struct tevent_req *tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote);
+
+ int _tstream_unix_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream);
+
+You can use tstream_unix_socketpair to create two connected
+'unix' tsocket_contexts for the stream based communication.
+It returns -1 and sets errno on error and it returns 0 on
+success.
+
+ int tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
+ struct tstream_context **stream1,
+ TALLOC_CTX *mem_ctx2,
+ struct tstream_context **stream2);
+
+In some situations, it is needed to create a tsocket_address from
+a given 'struct sockaddr'. You can use tsocket_address_bsd_from_sockaddr()
+for that. This should only be used if really needed, because of
+already existing fixed APIs. Only AF_INET, AF_INET6 and AF_UNIX
+sockets are allowed. The function returns -1 and sets errno on error.
+Otherwise it returns 0.
+
+ int tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
+ struct sockaddr *sa,
+ socklen_t sa_socklen,
+ struct tsocket_address **addr);
+
+In some situations, it is needed to get a 'struct sockaddr' from a
+given tsocket_address . You can use tsocket_address_bsd_sockaddr()
+for that. This should only be used if really needed. Only AF_INET,
+AF_INET6 and AF_UNIX are supported. It returns the size of '*sa' on
+success, otherwise it returns -1 and sets 'errno'.
+
+ ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
+ struct sockaddr *sa,
+ socklen_t sa_socklen);
+
+In some situations, it is needed to wrap existing file descriptors
+into the tstream abstraction. You can use tstream_bsd_existing_socket()
+for that. But you should read the tsocket_bsd.c code and unterstand it
+in order use this function. E.g. the fd has to be non blocking already.
+It will return -1 and set errno on error. Otherwise it returns 0
+and sets '*stream' to point to the new tstream_context.
+
+ int tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tstream_context **stream);
+
+Virtual Sockets
+===============
+
+The abstracted layout of tdgram_context and tstream_context
+allow implementations around virtual sockets for encrypted tunnels
+(like TLS, SASL or GSSAPI) or named pipes over smb.
+
+Named Pipe Auth (NPA) Sockets
+=============================
+
+Samba has an implementation to abstract named pipes over smb
+(within the server side). See libcli/named_pipe_auth/npa_tstream.[ch]
+for the core code. The current callers are located in source4/ntvfs/ipc/vfs_ipc.c
+and source4/rpc_server/service_rpc.c for the users.
+
diff --git a/lib/tsocket/tsocket_helpers.c b/lib/tsocket/tsocket_helpers.c
new file mode 100644
index 0000000..c7ad531
--- /dev/null
+++ b/lib/tsocket/tsocket_helpers.c
@@ -0,0 +1,559 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tsocket
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "tsocket.h"
+#include "tsocket_internal.h"
+
+struct tdgram_sendto_queue_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tevent_context *ev;
+ struct tdgram_context *dgram;
+ const uint8_t *buf;
+ size_t len;
+ const struct tsocket_address *dst;
+ } caller;
+ ssize_t ret;
+};
+
+static void tdgram_sendto_queue_trigger(struct tevent_req *req,
+ void *private_data);
+static void tdgram_sendto_queue_done(struct tevent_req *subreq);
+
+struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tdgram_sendto_queue_state *state;
+ struct tevent_queue_entry *e;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_sendto_queue_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+ state->caller.dgram = dgram;
+ state->caller.buf = buf;
+ state->caller.len = len;
+ state->caller.dst = dst;
+ state->ret = -1;
+
+ /*
+ * we use tevent_queue_add_optimize_empty() with allow_direct
+ * in order to optimize for the empty queue case.
+ */
+ e = tevent_queue_add_optimize_empty(
+ queue,
+ ev,
+ req,
+ tdgram_sendto_queue_trigger,
+ NULL);
+ if (tevent_req_nomem(e, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tdgram_sendto_queue_trigger(struct tevent_req *req,
+ void *private_data)
+{
+ struct tdgram_sendto_queue_state *state = tevent_req_data(req,
+ struct tdgram_sendto_queue_state);
+ struct tevent_req *subreq;
+
+ subreq = tdgram_sendto_send(state,
+ state->caller.ev,
+ state->caller.dgram,
+ state->caller.buf,
+ state->caller.len,
+ state->caller.dst);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
+}
+
+static void tdgram_sendto_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_sendto_queue_state *state = tevent_req_data(req,
+ struct tdgram_sendto_queue_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = tdgram_sendto_recv(subreq, &sys_errno);
+ talloc_free(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
+{
+ struct tdgram_sendto_queue_state *state = tevent_req_data(req,
+ struct tdgram_sendto_queue_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_readv_pdu_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ tstream_readv_pdu_next_vector_t next_vector_fn;
+ void *next_vector_private;
+ } caller;
+
+ /*
+ * Each call to the callback resets iov and count
+ * the callback allocated the iov as child of our state,
+ * that means we are allowed to modify and free it.
+ *
+ * we should call the callback every time we filled the given
+ * vector and ask for a new vector. We return if the callback
+ * ask for 0 bytes.
+ */
+ struct iovec *vector;
+ size_t count;
+
+ /*
+ * the total number of bytes we read,
+ * the return value of the _recv function
+ */
+ int total_read;
+};
+
+static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req);
+static void tstream_readv_pdu_readv_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private)
+{
+ struct tevent_req *req;
+ struct tstream_readv_pdu_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_readv_pdu_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+ state->caller.stream = stream;
+ state->caller.next_vector_fn = next_vector_fn;
+ state->caller.next_vector_private = next_vector_private;
+
+ state->vector = NULL;
+ state->count = 0;
+ state->total_read = 0;
+
+ tstream_readv_pdu_ask_for_next_vector(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+
+ return req;
+
+ post:
+ return tevent_req_post(req, ev);
+}
+
+static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req)
+{
+ struct tstream_readv_pdu_state *state = tevent_req_data(req,
+ struct tstream_readv_pdu_state);
+ int ret;
+ size_t to_read = 0;
+ size_t i;
+ struct tevent_req *subreq;
+ bool optimize = false;
+ bool save_optimize = false;
+
+ if (state->count > 0) {
+ /*
+ * This is not the first time we asked for a vector,
+ * which means parts of the pdu already arrived.
+ *
+ * In this case it make sense to enable
+ * a syscall/performance optimization if the
+ * low level tstream implementation supports it.
+ */
+ optimize = true;
+ }
+
+ TALLOC_FREE(state->vector);
+ state->count = 0;
+
+ ret = state->caller.next_vector_fn(state->caller.stream,
+ state->caller.next_vector_private,
+ state, &state->vector, &state->count);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ return;
+ }
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ for (i=0; i < state->count; i++) {
+ size_t tmp = to_read;
+ tmp += state->vector[i].iov_len;
+
+ if (tmp < to_read) {
+ tevent_req_error(req, EMSGSIZE);
+ return;
+ }
+
+ to_read = tmp;
+ }
+
+ /*
+ * this is invalid the next vector function should have
+ * reported count == 0.
+ */
+ if (to_read == 0) {
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ if (state->total_read + to_read < state->total_read) {
+ tevent_req_error(req, EMSGSIZE);
+ return;
+ }
+
+ if (optimize) {
+ /*
+ * If the low level stream is a bsd socket
+ * we will get syscall optimization.
+ *
+ * If it is not a bsd socket
+ * tstream_bsd_optimize_readv() just returns.
+ */
+ save_optimize = tstream_bsd_optimize_readv(state->caller.stream,
+ true);
+ }
+ subreq = tstream_readv_send(state,
+ state->caller.ev,
+ state->caller.stream,
+ state->vector,
+ state->count);
+ if (optimize) {
+ tstream_bsd_optimize_readv(state->caller.stream,
+ save_optimize);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_readv_pdu_readv_done, req);
+}
+
+static void tstream_readv_pdu_readv_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_readv_pdu_state *state = tevent_req_data(req,
+ struct tstream_readv_pdu_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_readv_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->total_read += ret;
+
+ /* ask the callback for a new vector we should fill */
+ tstream_readv_pdu_ask_for_next_vector(req);
+}
+
+int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno)
+{
+ struct tstream_readv_pdu_state *state = tevent_req_data(req,
+ struct tstream_readv_pdu_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->total_read;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_readv_pdu_queue_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ tstream_readv_pdu_next_vector_t next_vector_fn;
+ void *next_vector_private;
+ } caller;
+ int ret;
+};
+
+static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
+ void *private_data);
+static void tstream_readv_pdu_queue_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ tstream_readv_pdu_next_vector_t next_vector_fn,
+ void *next_vector_private)
+{
+ struct tevent_req *req;
+ struct tstream_readv_pdu_queue_state *state;
+ struct tevent_queue_entry *e;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_readv_pdu_queue_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+ state->caller.stream = stream;
+ state->caller.next_vector_fn = next_vector_fn;
+ state->caller.next_vector_private = next_vector_private;
+ state->ret = -1;
+
+ /*
+ * we use tevent_queue_add_optimize_empty() with allow_direct
+ * in order to optimize for the empty queue case.
+ */
+ e = tevent_queue_add_optimize_empty(
+ queue,
+ ev,
+ req,
+ tstream_readv_pdu_queue_trigger,
+ NULL);
+ if (tevent_req_nomem(e, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
+ void *private_data)
+{
+ struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
+ struct tstream_readv_pdu_queue_state);
+ struct tevent_req *subreq;
+
+ subreq = tstream_readv_pdu_send(state,
+ state->caller.ev,
+ state->caller.stream,
+ state->caller.next_vector_fn,
+ state->caller.next_vector_private);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_readv_pdu_queue_done ,req);
+}
+
+static void tstream_readv_pdu_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
+ struct tstream_readv_pdu_queue_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_readv_pdu_recv(subreq, &sys_errno);
+ talloc_free(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno)
+{
+ struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
+ struct tstream_readv_pdu_queue_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_writev_queue_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ const struct iovec *vector;
+ size_t count;
+ } caller;
+ int ret;
+};
+
+static void tstream_writev_queue_trigger(struct tevent_req *req,
+ void *private_data);
+static void tstream_writev_queue_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct tevent_queue *queue,
+ const struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_writev_queue_state *state;
+ struct tevent_queue_entry *e;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_writev_queue_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+ state->caller.stream = stream;
+ state->caller.vector = vector;
+ state->caller.count = count;
+ state->ret = -1;
+
+ /*
+ * we use tevent_queue_add_optimize_empty() with allow_direct
+ * in order to optimize for the empty queue case.
+ */
+ e = tevent_queue_add_optimize_empty(
+ queue,
+ ev,
+ req,
+ tstream_writev_queue_trigger,
+ NULL);
+ if (tevent_req_nomem(e, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tstream_writev_queue_trigger(struct tevent_req *req,
+ void *private_data)
+{
+ struct tstream_writev_queue_state *state = tevent_req_data(req,
+ struct tstream_writev_queue_state);
+ struct tevent_req *subreq;
+
+ subreq = tstream_writev_send(state,
+ state->caller.ev,
+ state->caller.stream,
+ state->caller.vector,
+ state->caller.count);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_writev_queue_done ,req);
+}
+
+static void tstream_writev_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_writev_queue_state *state = tevent_req_data(req,
+ struct tstream_writev_queue_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_writev_recv(subreq, &sys_errno);
+ talloc_free(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+int tstream_writev_queue_recv(struct tevent_req *req, int *perrno)
+{
+ struct tstream_writev_queue_state *state = tevent_req_data(req,
+ struct tstream_writev_queue_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
diff --git a/lib/tsocket/tsocket_internal.h b/lib/tsocket/tsocket_internal.h
new file mode 100644
index 0000000..154b2ce
--- /dev/null
+++ b/lib/tsocket/tsocket_internal.h
@@ -0,0 +1,144 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ ** NOTE! The following LGPL license applies to the tsocket
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TSOCKET_INTERNAL_H
+#define _TSOCKET_INTERNAL_H
+
+#include <unistd.h>
+#include <sys/uio.h>
+
+struct tsocket_address_ops {
+ const char *name;
+
+ char *(*string)(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+ struct tsocket_address *(*copy)(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx,
+ const char *location);
+};
+
+struct tsocket_address {
+ const char *location;
+ const struct tsocket_address_ops *ops;
+
+ void *private_data;
+};
+
+struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location);
+#define tsocket_address_create(mem_ctx, ops, state, type, location) \
+ _tsocket_address_create(mem_ctx, ops, state, sizeof(type), \
+ #type, location)
+
+struct tdgram_context_ops {
+ const char *name;
+
+ struct tevent_req *(*recvfrom_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+ ssize_t (*recvfrom_recv)(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+ struct tevent_req *(*sendto_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst);
+ ssize_t (*sendto_recv)(struct tevent_req *req,
+ int *perrno);
+
+ struct tevent_req *(*disconnect_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+ int (*disconnect_recv)(struct tevent_req *req,
+ int *perrno);
+};
+
+struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
+ const struct tdgram_context_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location);
+#define tdgram_context_create(mem_ctx, ops, state, type, location) \
+ _tdgram_context_create(mem_ctx, ops, state, sizeof(type), \
+ #type, location)
+
+void *_tdgram_context_data(struct tdgram_context *dgram);
+#define tdgram_context_data(_req, _type) \
+ talloc_get_type_abort(_tdgram_context_data(_req), _type)
+
+struct tstream_context_ops {
+ const char *name;
+
+ ssize_t (*pending_bytes)(struct tstream_context *stream);
+
+ struct tevent_req *(*readv_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count);
+ int (*readv_recv)(struct tevent_req *req,
+ int *perrno);
+
+ struct tevent_req *(*writev_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count);
+ int (*writev_recv)(struct tevent_req *req,
+ int *perrno);
+
+ struct tevent_req *(*disconnect_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+ int (*disconnect_recv)(struct tevent_req *req,
+ int *perrno);
+};
+
+struct tstream_context *_tstream_context_create(TALLOC_CTX *mem_ctx,
+ const struct tstream_context_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location);
+#define tstream_context_create(mem_ctx, ops, state, type, location) \
+ _tstream_context_create(mem_ctx, ops, state, sizeof(type), \
+ #type, location)
+
+void *_tstream_context_data(struct tstream_context *stream);
+#define tstream_context_data(_req, _type) \
+ talloc_get_type_abort(_tstream_context_data(_req), _type)
+
+int tsocket_simple_int_recv(struct tevent_req *req, int *perrno);
+
+#endif /* _TSOCKET_H */
+
diff --git a/lib/tsocket/wscript b/lib/tsocket/wscript
new file mode 100644
index 0000000..fa284a7
--- /dev/null
+++ b/lib/tsocket/wscript
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+def configure(conf):
+ conf.CHECK_CODE('''
+ #include <netinet/tcp.h>
+ int main(void) { return TCP_USER_TIMEOUT; }
+ ''',
+ 'HAVE_TCP_USER_TIMEOUT',
+ addmain=False,
+ msg='Checking for TCP_USER_TIMEOUT')
+
+def build(bld):
+ bld.SAMBA_SUBSYSTEM(
+ 'LIBTSOCKET',
+ source='tsocket.c tsocket_helpers.c tsocket_bsd.c',
+ public_deps='talloc tevent iov_buf socket-blocking',
+ public_headers='tsocket.h tsocket_internal.h'
+ )
+
+ bld.SAMBA_BINARY(
+ 'test_tsocket_bsd_addr',
+ source='tests/test_bsd_addr.c',
+ deps='cmocka replace LIBTSOCKET',
+ local_include=False,
+ for_selftest=True
+ )
+
+ bld.SAMBA_BINARY(
+ 'test_tstream',
+ source='tests/test_tstream.c tests/socketpair_tcp.c',
+ deps='cmocka replace LIBTSOCKET',
+ local_include=False,
+ enabled=bld.CONFIG_SET('HAVE_TCP_USER_TIMEOUT'),
+ for_selftest=True
+ )
+
diff --git a/lib/util/Doxyfile b/lib/util/Doxyfile
new file mode 100644
index 0000000..02e36a7
--- /dev/null
+++ b/lib/util/Doxyfile
@@ -0,0 +1,24 @@
+PROJECT_NAME = SAMBA_UTIL
+OUTPUT_DIRECTORY = apidocs
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+OPTIMIZE_OUTPUT_FOR_C = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+GENERATE_TODOLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+INPUT = .
+FILE_PATTERNS = *.c *.h *.dox
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+GENERATE_MAN = YES
+ALWAYS_DETAILED_SEC = YES
+JAVADOC_AUTOBRIEF = YES
diff --git a/lib/util/README b/lib/util/README
new file mode 100644
index 0000000..fffd44d
--- /dev/null
+++ b/lib/util/README
@@ -0,0 +1,6 @@
+This directory contains libutil (until we can think of a better name)
+
+The idea is that this library contains simple but useful data structures
+and support functions that are generally useful; not just for Samba but for
+other projects as well. Functions here should not depend on any external
+libraries, just on libc (perhaps partially provided by libreplace).
diff --git a/lib/util/access.c b/lib/util/access.c
new file mode 100644
index 0000000..fd9912d
--- /dev/null
+++ b/lib/util/access.c
@@ -0,0 +1,377 @@
+/*
+ This module is an adaption of code from the tcpd-1.4 package written
+ by Wietse Venema, Eindhoven University of Technology, The Netherlands.
+
+ The code is used here with permission.
+
+ The code has been considerably changed from the original. Bug reports
+ should be sent to samba-technical@lists.samba.org
+
+ Updated for IPv6 by Jeremy Allison (C) 2007.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "lib/util/debug.h"
+#include "../lib/util/memcache.h"
+#include "lib/socket/interfaces.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/util_net.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/memory.h"
+#include "lib/util/access.h"
+#include "lib/util/unix_match.h"
+#include "lib/util/smb_strtox.h"
+
+#define NAME_INDEX 0
+#define ADDR_INDEX 1
+
+/* masked_match - match address against netnumber/netmask */
+static bool masked_match(const char *tok, const char *slash, const char *s)
+{
+ struct sockaddr_storage ss_mask;
+ struct sockaddr_storage ss_tok;
+ struct sockaddr_storage ss_host;
+ char *tok_copy = NULL;
+
+ if (!interpret_string_addr(&ss_host, s, 0)) {
+ return false;
+ }
+
+ if (*tok == '[') {
+ /* IPv6 address - remove braces. */
+ tok_copy = smb_xstrdup(tok+1);
+ if (!tok_copy) {
+ return false;
+ }
+ /* Remove the terminating ']' */
+ tok_copy[PTR_DIFF(slash,tok)-1] = '\0';
+ } else {
+ tok_copy = smb_xstrdup(tok);
+ if (!tok_copy) {
+ return false;
+ }
+ /* Remove the terminating '/' */
+ tok_copy[PTR_DIFF(slash,tok)] = '\0';
+ }
+
+ if (!interpret_string_addr(&ss_tok, tok_copy, 0)) {
+ SAFE_FREE(tok_copy);
+ return false;
+ }
+
+ SAFE_FREE(tok_copy);
+
+ if (strlen(slash + 1) > 2) {
+ if (!interpret_string_addr(&ss_mask, slash+1, 0)) {
+ return false;
+ }
+ } else {
+ int error = 0;
+ unsigned long val;
+
+ val = smb_strtoul(slash+1,
+ NULL,
+ 0,
+ &error,
+ SMB_STR_FULL_STR_CONV);
+ if (error != 0) {
+ return false;
+ }
+ if (!make_netmask(&ss_mask, &ss_tok, val)) {
+ return false;
+ }
+ }
+
+ return same_net((struct sockaddr *)(void *)&ss_host,
+ (struct sockaddr *)(void *)&ss_tok,
+ (struct sockaddr *)(void *)&ss_mask);
+}
+
+/* string_match - match string s against token tok */
+static bool string_match(const char *tok,const char *s)
+{
+ size_t tok_len;
+ size_t str_len;
+ const char *cut;
+
+ /* Return true if a token has the magic value "ALL". Return
+ * true if the token is "FAIL". If the token starts with a "."
+ * (domain name), return true if it matches the last fields of
+ * the string. If the token has the magic value "LOCAL",
+ * return true if the string does not contain a "."
+ * character. If the token ends on a "." (network number),
+ * return true if it matches the first fields of the
+ * string. If the token begins with a "@" (netgroup name),
+ * return true if the string is a (host) member of the
+ * netgroup. Return true if the token fully matches the
+ * string. If the token is a netnumber/netmask pair, return
+ * true if the address is a member of the specified subnet.
+ */
+
+ if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(s)) > (tok_len = strlen(tok))
+ && strequal_m(tok, s + str_len - tok_len)) {
+ return true;
+ }
+ } else if (tok[0] == '@') { /* netgroup: look it up */
+#if defined(HAVE_NETGROUP) && defined(HAVE_INNETGR)
+ DATA_BLOB tmp;
+ char *mydomain = NULL;
+ char *hostname = NULL;
+ bool netgroup_ok = false;
+ char nis_domain_buf[256];
+
+ if (memcache_lookup(
+ NULL, SINGLETON_CACHE,
+ data_blob_string_const_null("yp_default_domain"),
+ &tmp)) {
+
+ SMB_ASSERT(tmp.length > 0);
+ mydomain = (tmp.data[0] == '\0')
+ ? NULL : (char *)tmp.data;
+ } else {
+ if (getdomainname(nis_domain_buf,
+ sizeof(nis_domain_buf)) == 0) {
+ mydomain = &nis_domain_buf[0];
+ memcache_add(NULL,
+ SINGLETON_CACHE,
+ data_blob_string_const_null(
+ "yp_default_domain"),
+ data_blob_string_const_null(
+ mydomain));
+ } else {
+ mydomain = NULL;
+ }
+ }
+
+ if (!mydomain) {
+ DEBUG(0,("Unable to get default yp domain. "
+ "Try without it.\n"));
+ }
+ if (!(hostname = smb_xstrdup(s))) {
+ DEBUG(1,("out of memory for strdup!\n"));
+ return false;
+ }
+
+ netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain);
+
+ DBG_INFO("%s %s of domain %s in netgroup %s\n",
+ netgroup_ok ? "Found" : "Could not find",
+ hostname,
+ mydomain?mydomain:"(ANY)",
+ tok+1);
+
+ SAFE_FREE(hostname);
+
+ if (netgroup_ok)
+ return true;
+#else
+ DEBUG(0,("access: netgroup support is not configured\n"));
+ return false;
+#endif
+ } else if (strequal_m(tok, "ALL")) { /* all: match any */
+ return true;
+ } else if (strequal_m(tok, "FAIL")) { /* fail: match any */
+ return true;
+ } else if (strequal_m(tok, "LOCAL")) { /* local: no dots */
+ if (strchr_m(s, '.') == 0 && !strequal_m(s, "unknown")) {
+ return true;
+ }
+ } else if (strequal_m(tok, s)) { /* match host name or address */
+ return true;
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */
+ if (strncmp(tok, s, tok_len) == 0) {
+ return true;
+ }
+ } else if ((cut = strchr_m(tok, '/')) != 0) { /* netnumber/netmask */
+ if ((isdigit(s[0]) && strchr_m(tok, '.') != NULL) ||
+ (tok[0] == '[' && cut > tok && cut[-1] == ']') ||
+ ((isxdigit(s[0]) || s[0] == ':') &&
+ strchr_m(tok, ':') != NULL)) {
+ /* IPv4/netmask or
+ * [IPv6:addr]/netmask or IPv6:addr/netmask */
+ return masked_match(tok, cut, s);
+ }
+ } else if (strchr_m(tok, '*') != 0 || strchr_m(tok, '?')) {
+ return unix_wild_match(tok, s);
+ }
+ return false;
+}
+
+/* client_match - match host name and address against token */
+bool client_match(const char *tok, const void *item)
+{
+ const char **client = discard_const_p(const char *, item);
+ const char *tok_addr = tok;
+ const char *cli_addr = client[ADDR_INDEX];
+
+ /*
+ * tok and client[ADDR_INDEX] can be an IPv4 mapped to IPv6,
+ * we try and match the IPv4 part of address only.
+ * Bug #5311 and #7383.
+ */
+
+ if (strncasecmp_m(tok_addr, "::ffff:", 7) == 0) {
+ tok_addr += 7;
+ }
+
+ if (strncasecmp_m(cli_addr, "::ffff:", 7) == 0) {
+ cli_addr += 7;
+ }
+
+ /*
+ * Try to match the address first. If that fails, try to match the host
+ * name if available.
+ */
+
+ if (string_match(tok_addr, cli_addr)) {
+ return true;
+ }
+
+ if (client[NAME_INDEX][0] != 0) {
+ if (string_match(tok, client[NAME_INDEX])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+bool list_match(const char **list,const void *item,
+ bool (*match_fn)(const char *, const void *))
+{
+ bool match = false;
+
+ if (!list) {
+ return false;
+ }
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * the match is affected by any exceptions.
+ */
+
+ for (; *list ; list++) {
+ if (strequal_m(*list, "EXCEPT")) {
+ /* EXCEPT: give up */
+ break;
+ }
+ if ((match = (*match_fn) (*list, item))) {
+ /* true or FAIL */
+ break;
+ }
+ }
+ /* Process exceptions to true or FAIL matches. */
+
+ if (match != false) {
+ while (*list && !strequal_m(*list, "EXCEPT")) {
+ list++;
+ }
+
+ for (; *list; list++) {
+ if ((*match_fn) (*list, item)) {
+ /* Exception Found */
+ return false;
+ }
+ }
+ }
+
+ return match;
+}
+
+/* return true if access should be allowed */
+static bool allow_access_internal(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr)
+{
+ const char *client[2];
+
+ client[NAME_INDEX] = cname;
+ client[ADDR_INDEX] = caddr;
+
+ /* if it is loopback then always allow unless specifically denied */
+ if (strcmp(caddr, "127.0.0.1") == 0 || strcmp(caddr, "::1") == 0) {
+ /*
+ * If 127.0.0.1 matches both allow and deny then allow.
+ * Patch from Steve Langasek vorlon@netexpress.net.
+ */
+ if (deny_list &&
+ list_match(deny_list,client,client_match) &&
+ (!allow_list ||
+ !list_match(allow_list,client, client_match))) {
+ return false;
+ }
+ return true;
+ }
+
+ /* if there's no deny list and no allow list then allow access */
+ if ((!deny_list || *deny_list == 0) &&
+ (!allow_list || *allow_list == 0)) {
+ return true;
+ }
+
+ /* if there is an allow list but no deny list then allow only hosts
+ on the allow list */
+ if (!deny_list || *deny_list == 0) {
+ return(list_match(allow_list,client,client_match));
+ }
+
+ /* if there's a deny list but no allow list then allow
+ all hosts not on the deny list */
+ if (!allow_list || *allow_list == 0) {
+ return(!list_match(deny_list,client,client_match));
+ }
+
+ /* if there are both types of list then allow all hosts on the
+ allow list */
+ if (list_match(allow_list,(const char *)client,client_match)) {
+ return true;
+ }
+
+ /* if there are both types of list and it's not on the allow then
+ allow it if its not on the deny */
+ if (list_match(deny_list,(const char *)client,client_match)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* return true if access should be allowed - doesn't print log message */
+bool allow_access_nolog(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr)
+{
+ bool ret;
+ char *nc_cname = smb_xstrdup(cname);
+ char *nc_caddr = smb_xstrdup(caddr);
+
+ ret = allow_access_internal(deny_list, allow_list, nc_cname, nc_caddr);
+
+ SAFE_FREE(nc_cname);
+ SAFE_FREE(nc_caddr);
+ return ret;
+}
+
+/* return true if access should be allowed - prints log message */
+bool allow_access(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr)
+{
+ bool ret;
+
+ ret = allow_access_nolog(deny_list, allow_list, cname, caddr);
+
+ DEBUG(ret ? 3 : 0,
+ ("%s connection from %s (%s)\n",
+ ret ? "Allowed" : "Denied", cname, caddr));
+
+ return ret;
+}
diff --git a/lib/util/access.h b/lib/util/access.h
new file mode 100644
index 0000000..73f71b6
--- /dev/null
+++ b/lib/util/access.h
@@ -0,0 +1,28 @@
+/*
+ This module is an adaption of code from the tcpd-1.4 package written
+ by Wietse Venema, Eindhoven University of Technology, The Netherlands.
+
+ The code is used here with permission.
+
+ The code has been considerably changed from the original. Bug reports
+ should be sent to samba-technical@lists.samba.org
+
+ Updated for IPv6 by Jeremy Allison (C) 2007.
+*/
+
+#ifndef _UTIL_ACCESS_H_
+#define _UTIL_ACCESS_H_
+
+bool client_match(const char *tok, const void *item);
+bool list_match(const char **list,const void *item,
+ bool (*match_fn)(const char *, const void *));
+bool allow_access_nolog(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr);
+bool allow_access(const char **deny_list,
+ const char **allow_list,
+ const char *cname,
+ const char *caddr);
+
+#endif
diff --git a/lib/util/asn1.c b/lib/util/asn1.c
new file mode 100644
index 0000000..1a92a55
--- /dev/null
+++ b/lib/util/asn1.c
@@ -0,0 +1,1176 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple ASN1 routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "lib/util/asn1.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/smb_strtox.h"
+
+struct nesting {
+ off_t start;
+ size_t taglen; /* for parsing */
+ struct nesting *next;
+};
+
+
+struct asn1_data {
+ uint8_t *data;
+ size_t length;
+ off_t ofs;
+ struct nesting *nesting;
+ bool has_error;
+ unsigned depth;
+ unsigned max_depth;
+};
+
+/* allocate an asn1 structure */
+struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx, unsigned max_depth)
+{
+ struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
+ if (ret == NULL) {
+ DBG_ERR("asn1_init failed! out of memory\n");
+ return ret;
+ }
+ ret->max_depth = max_depth;
+ return ret;
+}
+
+/* free an asn1 structure */
+void asn1_free(struct asn1_data *data)
+{
+ talloc_free(data);
+}
+
+bool asn1_has_error(const struct asn1_data *data)
+{
+ return data->has_error;
+}
+
+void asn1_set_error(struct asn1_data *data)
+{
+ data->has_error = true;
+}
+
+bool asn1_has_nesting(const struct asn1_data *data)
+{
+ return data->nesting != NULL;
+}
+
+off_t asn1_current_ofs(const struct asn1_data *data)
+{
+ return data->ofs;
+}
+
+/* write to the ASN1 buffer, advancing the buffer pointer */
+bool asn1_write(struct asn1_data *data, const void *p, int len)
+{
+ if (data->has_error) return false;
+
+ if ((len < 0) || (data->ofs + (size_t)len < data->ofs)) {
+ data->has_error = true;
+ return false;
+ }
+
+ if (data->length < data->ofs+len) {
+ uint8_t *newp;
+ newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
+ if (!newp) {
+ data->has_error = true;
+ return false;
+ }
+ data->data = newp;
+ data->length = data->ofs+len;
+ }
+ if (len > 0) {
+ memcpy(data->data + data->ofs, p, len);
+ data->ofs += len;
+ }
+ return true;
+}
+
+/* useful fn for writing a uint8_t */
+bool asn1_write_uint8(struct asn1_data *data, uint8_t v)
+{
+ return asn1_write(data, &v, 1);
+}
+
+/* push a tag onto the asn1 data buffer. Used for nested structures */
+bool asn1_push_tag(struct asn1_data *data, uint8_t tag)
+{
+ struct nesting *nesting;
+
+ if (!asn1_write_uint8(data, tag)) {
+ return false;
+ }
+ nesting = talloc(data, struct nesting);
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return asn1_write_uint8(data, 0xff);
+}
+
+/* pop a tag */
+bool asn1_pop_tag(struct asn1_data *data)
+{
+ struct nesting *nesting;
+ size_t len;
+
+ if (data->has_error) {
+ return false;
+ }
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+ len = data->ofs - (nesting->start+1);
+ /* yes, this is ugly. We don't know in advance how many bytes the length
+ of a tag will take, so we assumed 1 byte. If we were wrong then we
+ need to correct our mistake */
+ if (len > 0xFFFFFF) {
+ data->data[nesting->start] = 0x84;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ memmove(data->data+nesting->start+5, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = (len>>24) & 0xFF;
+ data->data[nesting->start+2] = (len>>16) & 0xFF;
+ data->data[nesting->start+3] = (len>>8) & 0xFF;
+ data->data[nesting->start+4] = len&0xff;
+ } else if (len > 0xFFFF) {
+ data->data[nesting->start] = 0x83;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = (len>>16) & 0xFF;
+ data->data[nesting->start+2] = (len>>8) & 0xFF;
+ data->data[nesting->start+3] = len&0xff;
+ } else if (len > 255) {
+ data->data[nesting->start] = 0x82;
+ if (!asn1_write_uint8(data, 0)) return false;
+ if (!asn1_write_uint8(data, 0)) return false;
+ memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len>>8;
+ data->data[nesting->start+2] = len&0xff;
+ } else if (len > 127) {
+ data->data[nesting->start] = 0x81;
+ if (!asn1_write_uint8(data, 0)) return false;
+ memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len;
+ } else {
+ data->data[nesting->start] = len;
+ }
+
+ data->nesting = nesting->next;
+ talloc_free(nesting);
+ return true;
+}
+
+/* "i" is the one's complement representation, as is the normal result of an
+ * implicit signed->unsigned conversion */
+
+static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool negative)
+{
+ uint8_t lowest = i & 0xFF;
+
+ i = i >> 8;
+ if (i != 0)
+ if (!push_int_bigendian(data, i, negative))
+ return false;
+
+ if (data->nesting->start+1 == data->ofs) {
+
+ /* We did not write anything yet, looking at the highest
+ * valued byte */
+
+ if (negative) {
+ /* Don't write leading 0xff's */
+ if (lowest == 0xFF)
+ return true;
+
+ if ((lowest & 0x80) == 0) {
+ /* The only exception for a leading 0xff is if
+ * the highest bit is 0, which would indicate
+ * a positive value */
+ if (!asn1_write_uint8(data, 0xff))
+ return false;
+ }
+ } else {
+ if (lowest & 0x80) {
+ /* The highest bit of a positive integer is 1,
+ * this would indicate a negative number. Push
+ * a 0 to indicate a positive one */
+ if (!asn1_write_uint8(data, 0))
+ return false;
+ }
+ }
+ }
+
+ return asn1_write_uint8(data, lowest);
+}
+
+/* write an Integer without the tag framing. Needed for example for the LDAP
+ * Abandon Operation */
+
+bool asn1_write_implicit_Integer(struct asn1_data *data, int i)
+{
+ if (data->has_error) {
+ return false;
+ }
+
+ if (i == -1) {
+ /* -1 is special as it consists of all-0xff bytes. In
+ push_int_bigendian this is the only case that is not
+ properly handled, as all 0xff bytes would be handled as
+ leading ones to be ignored. */
+ return asn1_write_uint8(data, 0xff);
+ } else {
+ return push_int_bigendian(data, i, i<0);
+ }
+}
+
+
+/* write an integer */
+bool asn1_write_Integer(struct asn1_data *data, int i)
+{
+ if (!asn1_push_tag(data, ASN1_INTEGER)) return false;
+ if (!asn1_write_implicit_Integer(data, i)) return false;
+ return asn1_pop_tag(data);
+}
+
+/* write a BIT STRING */
+bool asn1_write_BitString(struct asn1_data *data, const void *p, size_t length, uint8_t padding)
+{
+ if (!asn1_push_tag(data, ASN1_BIT_STRING)) return false;
+ if (!asn1_write_uint8(data, padding)) return false;
+ if (!asn1_write(data, p, length)) return false;
+ return asn1_pop_tag(data);
+}
+
+bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID)
+{
+ unsigned int v, v2;
+ const char *p = (const char *)OID;
+ char *newp;
+ int i;
+ int error = 0;
+
+ if (!isdigit(*p)) return false;
+ v = smb_strtoul(p, &newp, 10, &error, SMB_STR_STANDARD);
+ if (newp[0] != '.' || error != 0) {
+ return false;
+ }
+ p = newp + 1;
+
+ if (!isdigit(*p)) return false;
+ v2 = smb_strtoul(p, &newp, 10, &error, SMB_STR_STANDARD);
+ if (newp[0] != '.' || error != 0) {
+ return false;
+ }
+ p = newp + 1;
+
+ /*the ber representation can't use more space than the string one */
+ *blob = data_blob_talloc(mem_ctx, NULL, strlen(OID));
+ if (!blob->data) return false;
+
+ blob->data[0] = 40*v + v2;
+
+ i = 1;
+ while (*p) {
+ if (!isdigit(*p)) return false;
+ v = smb_strtoul(p, &newp, 10, &error, SMB_STR_STANDARD);
+ if (newp[0] == '.' || error != 0) {
+ p = newp + 1;
+ /* check for empty last component */
+ if (!*p) return false;
+ } else if (newp[0] == '\0') {
+ p = newp;
+ } else {
+ data_blob_free(blob);
+ return false;
+ }
+ if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
+ if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
+ if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
+ if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
+ blob->data[i++] = (v&0x7f);
+ }
+
+ blob->length = i;
+
+ return true;
+}
+
+/**
+ * Serialize partial OID string.
+ * Partial OIDs are in the form:
+ * 1:2.5.6:0x81
+ * 1:2.5.6:0x8182
+ */
+bool ber_write_partial_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *partial_oid)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ char *oid = talloc_strdup(tmp_ctx, partial_oid);
+ char *p;
+
+ /* truncate partial part so ber_write_OID_String() works */
+ p = strchr(oid, ':');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+
+ if (!ber_write_OID_String(mem_ctx, blob, oid)) {
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ /* Add partially encoded sub-identifier */
+ if (p) {
+ DATA_BLOB tmp_blob = strhex_to_data_blob(tmp_ctx, p);
+ if (!data_blob_append(mem_ctx, blob, tmp_blob.data,
+ tmp_blob.length)) {
+ talloc_free(tmp_ctx);
+ return false;
+ }
+ }
+
+ talloc_free(tmp_ctx);
+
+ return true;
+}
+
+/* write an object ID to a ASN1 buffer */
+bool asn1_write_OID(struct asn1_data *data, const char *OID)
+{
+ DATA_BLOB blob;
+
+ if (!asn1_push_tag(data, ASN1_OID)) return false;
+
+ if (!ber_write_OID_String(NULL, &blob, OID)) {
+ data->has_error = true;
+ return false;
+ }
+
+ if (!asn1_write(data, blob.data, blob.length)) {
+ data_blob_free(&blob);
+ data->has_error = true;
+ return false;
+ }
+ data_blob_free(&blob);
+ return asn1_pop_tag(data);
+}
+
+/* write an octet string */
+bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
+{
+ if (!asn1_push_tag(data, ASN1_OCTET_STRING)) return false;
+ if (!asn1_write(data, p, length)) return false;
+ return asn1_pop_tag(data);
+}
+
+/* write a LDAP string */
+bool asn1_write_LDAPString(struct asn1_data *data, const char *s)
+{
+ return asn1_write(data, s, strlen(s));
+}
+
+/* write a LDAP string from a DATA_BLOB */
+bool asn1_write_DATA_BLOB_LDAPString(struct asn1_data *data, const DATA_BLOB *s)
+{
+ return asn1_write(data, s->data, s->length);
+}
+
+/* write a general string */
+bool asn1_write_GeneralString(struct asn1_data *data, const char *s)
+{
+ if (!asn1_push_tag(data, ASN1_GENERAL_STRING)) return false;
+ if (!asn1_write_LDAPString(data, s)) return false;
+ return asn1_pop_tag(data);
+}
+
+bool asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
+{
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num))) return false;
+ if (!asn1_write(data, blob->data, blob->length)) return false;
+ return asn1_pop_tag(data);
+}
+
+/* write a BOOLEAN */
+bool asn1_write_BOOLEAN(struct asn1_data *data, bool v)
+{
+ if (!asn1_push_tag(data, ASN1_BOOLEAN)) return false;
+ if (!asn1_write_uint8(data, v ? 0xFF : 0)) return false;
+ return asn1_pop_tag(data);
+}
+
+bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v)
+{
+ uint8_t tmp = 0;
+ if (!asn1_start_tag(data, ASN1_BOOLEAN)) return false;
+ *v = false;
+ if (!asn1_read_uint8(data, &tmp)) return false;
+ if (tmp == 0xFF) {
+ *v = true;
+ }
+ return asn1_end_tag(data);
+}
+
+/* write a BOOLEAN in a simple context */
+bool asn1_write_BOOLEAN_context(struct asn1_data *data, bool v, int context)
+{
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(context))) return false;
+ if (!asn1_write_uint8(data, v ? 0xFF : 0)) return false;
+ return asn1_pop_tag(data);
+}
+
+bool asn1_read_BOOLEAN_context(struct asn1_data *data, bool *v, int context)
+{
+ uint8_t tmp = 0;
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(context))) return false;
+ *v = false;
+ if (!asn1_read_uint8(data, &tmp)) return false;
+ if (tmp == 0xFF) {
+ *v = true;
+ }
+ return asn1_end_tag(data);
+}
+
+/* check a BOOLEAN */
+bool asn1_check_BOOLEAN(struct asn1_data *data, bool v)
+{
+ uint8_t b = 0;
+
+ if (!asn1_read_uint8(data, &b)) return false;
+ if (b != ASN1_BOOLEAN) {
+ data->has_error = true;
+ return false;
+ }
+ if (!asn1_read_uint8(data, &b)) return false;
+ if (b != v) {
+ data->has_error = true;
+ return false;
+ }
+ return !data->has_error;
+}
+
+
+/* load a struct asn1_data structure with a lump of data, ready to be parsed */
+bool asn1_load(struct asn1_data *data, DATA_BLOB blob)
+{
+ /*
+ * Save the maximum depth
+ */
+ unsigned max_depth = data->max_depth;
+
+ ZERO_STRUCTP(data);
+ data->data = (uint8_t *)talloc_memdup(data, blob.data, blob.length);
+ if (!data->data) {
+ data->has_error = true;
+ return false;
+ }
+ data->length = blob.length;
+ data->max_depth = max_depth;
+ return true;
+}
+
+/* Peek into an ASN1 buffer, not advancing the pointer */
+bool asn1_peek(struct asn1_data *data, void *p, int len)
+{
+ if (data->has_error)
+ return false;
+
+ if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len)
+ return false;
+
+ if (data->ofs + len > data->length) {
+ /* we need to mark the buffer as consumed, so the caller knows
+ this was an out of data error, and not a decode error */
+ data->ofs = data->length;
+ return false;
+ }
+
+ memcpy(p, data->data + data->ofs, len);
+ return true;
+}
+
+/* read from a ASN1 buffer, advancing the buffer pointer */
+bool asn1_read(struct asn1_data *data, void *p, int len)
+{
+ if (!asn1_peek(data, p, len)) {
+ data->has_error = true;
+ return false;
+ }
+
+ data->ofs += len;
+ return true;
+}
+
+/* read a uint8_t from a ASN1 buffer */
+bool asn1_read_uint8(struct asn1_data *data, uint8_t *v)
+{
+ return asn1_read(data, v, 1);
+}
+
+bool asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
+{
+ return asn1_peek(data, v, 1);
+}
+
+bool asn1_peek_tag(struct asn1_data *data, uint8_t tag)
+{
+ uint8_t b;
+
+ if (asn1_tag_remaining(data) <= 0) {
+ return false;
+ }
+
+ if (!asn1_peek_uint8(data, &b))
+ return false;
+
+ return (b == tag);
+}
+
+/*
+ * just get the needed size the tag would consume
+ */
+static bool asn1_peek_tag_needed_size(struct asn1_data *data, uint8_t tag,
+ size_t *size)
+{
+ off_t start_ofs = data->ofs;
+ uint8_t b;
+ size_t taglen = 0;
+
+ if (data->has_error) {
+ return false;
+ }
+
+ if (!asn1_read_uint8(data, &b)) {
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return false;
+ }
+
+ if (b != tag) {
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return false;
+ }
+
+ if (!asn1_read_uint8(data, &b)) {
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return false;
+ }
+
+ if (b & 0x80) {
+ int n = b & 0x7f;
+ if (!asn1_read_uint8(data, &b)) {
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return false;
+ }
+ if (n > 4) {
+ /*
+ * We should not allow more than 4 bytes
+ * for the encoding of the tag length.
+ *
+ * Otherwise we'd overflow the taglen
+ * variable on 32 bit systems.
+ */
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return false;
+ }
+ taglen = b;
+ while (n > 1) {
+ size_t tmp_taglen;
+
+ if (!asn1_read_uint8(data, &b)) {
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return false;
+ }
+
+ tmp_taglen = (taglen << 8) | b;
+
+ if ((tmp_taglen >> 8) != taglen) {
+ /* overflow */
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return false;
+ }
+ taglen = tmp_taglen;
+
+ n--;
+ }
+ } else {
+ taglen = b;
+ }
+
+ *size = (data->ofs - start_ofs) + taglen;
+
+ data->ofs = start_ofs;
+ data->has_error = false;
+ return true;
+}
+
+/* start reading a nested asn1 structure */
+bool asn1_start_tag(struct asn1_data *data, uint8_t tag)
+{
+ uint8_t b;
+ struct nesting *nesting;
+
+ /*
+ * Check the depth of the parse tree and prevent it from growing
+ * too large.
+ */
+ data->depth++;
+ if (data->depth > data->max_depth) {
+ data->has_error = true;
+ return false;
+ }
+
+ if (!asn1_read_uint8(data, &b))
+ return false;
+
+ if (b != tag) {
+ data->has_error = true;
+ return false;
+ }
+ nesting = talloc(data, struct nesting);
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+
+ if (!asn1_read_uint8(data, &b)) {
+ return false;
+ }
+
+ if (b & 0x80) {
+ int n = b & 0x7f;
+ if (!asn1_read_uint8(data, &b))
+ return false;
+ nesting->taglen = b;
+ while (n > 1) {
+ size_t taglen;
+
+ if (!asn1_read_uint8(data, &b))
+ return false;
+
+ taglen = (nesting->taglen << 8) | b;
+
+ if ((taglen >> 8) != nesting->taglen) {
+ /* overflow */
+ data->has_error = true;
+ return false;
+ }
+ nesting->taglen = taglen;
+
+ n--;
+ }
+ } else {
+ nesting->taglen = b;
+ }
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ if (asn1_tag_remaining(data) == -1) {
+ return false;
+ }
+ return !data->has_error;
+}
+
+/* stop reading a tag */
+bool asn1_end_tag(struct asn1_data *data)
+{
+ struct nesting *nesting;
+
+ if (data->depth == 0) {
+ smb_panic("Unbalanced ASN.1 Tag nesting");
+ }
+ data->depth--;
+ /* make sure we read it all */
+ if (asn1_tag_remaining(data) != 0) {
+ data->has_error = true;
+ return false;
+ }
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = true;
+ return false;
+ }
+
+ data->nesting = nesting->next;
+ talloc_free(nesting);
+ return true;
+}
+
+/* work out how many bytes are left in this nested tag */
+int asn1_tag_remaining(struct asn1_data *data)
+{
+ int remaining;
+ if (data->has_error) {
+ return -1;
+ }
+
+ if (!data->nesting) {
+ data->has_error = true;
+ return -1;
+ }
+ remaining = data->nesting->taglen - (data->ofs - data->nesting->start);
+ if (remaining > (data->length - data->ofs)) {
+ data->has_error = true;
+ return -1;
+ }
+ if (remaining < 0) {
+ data->has_error = true;
+ return -1;
+ }
+ return remaining;
+}
+
+/**
+ * Internal implementation for reading binary OIDs
+ * Reading is done as far in the buffer as valid OID
+ * till buffer ends or not valid sub-identifier is found.
+ */
+static bool _ber_read_OID_String_impl(TALLOC_CTX *mem_ctx, DATA_BLOB blob,
+ char **OID, size_t *bytes_eaten)
+{
+ int i;
+ uint8_t *b;
+ unsigned int v;
+ char *tmp_oid = NULL;
+
+ if (blob.length < 2) return false;
+
+ b = blob.data;
+
+ tmp_oid = talloc_asprintf(mem_ctx, "%u.%u", b[0]/40, b[0]%40);
+ if (!tmp_oid) goto nomem;
+
+ if (bytes_eaten != NULL) {
+ *bytes_eaten = 0;
+ }
+
+ for(i = 1, v = 0; i < blob.length; i++) {
+ v = (v<<7) | (b[i]&0x7f);
+ if ( ! (b[i] & 0x80)) {
+ tmp_oid = talloc_asprintf_append_buffer(tmp_oid, ".%u", v);
+ v = 0;
+ if (bytes_eaten)
+ *bytes_eaten = i+1;
+ }
+ if (!tmp_oid) goto nomem;
+ }
+
+ *OID = tmp_oid;
+ return true;
+
+nomem:
+ return false;
+}
+
+/* read an object ID from a data blob */
+bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, char **OID)
+{
+ size_t bytes_eaten;
+
+ if (!_ber_read_OID_String_impl(mem_ctx, blob, OID, &bytes_eaten))
+ return false;
+
+ return (bytes_eaten == blob.length);
+}
+
+/**
+ * Deserialize partial OID string.
+ * Partial OIDs are in the form:
+ * 1:2.5.6:0x81
+ * 1:2.5.6:0x8182
+ */
+bool ber_read_partial_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob,
+ char **partial_oid)
+{
+ size_t bytes_left;
+ size_t bytes_eaten;
+ char *identifier = NULL;
+ char *tmp_oid = NULL;
+
+ if (!_ber_read_OID_String_impl(mem_ctx, blob, &tmp_oid, &bytes_eaten))
+ return false;
+
+ if (bytes_eaten < blob.length) {
+ bytes_left = blob.length - bytes_eaten;
+ identifier = hex_encode_talloc(mem_ctx, &blob.data[bytes_eaten], bytes_left);
+ if (!identifier) goto nomem;
+
+ *partial_oid = talloc_asprintf_append_buffer(tmp_oid, ":0x%s", identifier);
+ if (!*partial_oid) goto nomem;
+ TALLOC_FREE(identifier);
+ } else {
+ *partial_oid = tmp_oid;
+ }
+
+ return true;
+
+nomem:
+ TALLOC_FREE(identifier);
+ TALLOC_FREE(tmp_oid);
+ return false;
+}
+
+/* read an object ID from a ASN1 buffer */
+bool asn1_read_OID(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **OID)
+{
+ DATA_BLOB blob;
+ int len;
+
+ if (!asn1_start_tag(data, ASN1_OID)) return false;
+
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+
+ blob = data_blob(NULL, len);
+ if (!blob.data) {
+ data->has_error = true;
+ return false;
+ }
+
+ if (!asn1_read(data, blob.data, len)) return false;
+ if (!asn1_end_tag(data)) {
+ data_blob_free(&blob);
+ return false;
+ }
+
+ if (!ber_read_OID_String(mem_ctx, blob, OID)) {
+ data->has_error = true;
+ data_blob_free(&blob);
+ return false;
+ }
+
+ data_blob_free(&blob);
+ return true;
+}
+
+/* check that the next object ID is correct */
+bool asn1_check_OID(struct asn1_data *data, const char *OID)
+{
+ char *id;
+
+ if (!asn1_read_OID(data, data, &id)) return false;
+
+ if (strcmp(id, OID) != 0) {
+ talloc_free(id);
+ data->has_error = true;
+ return false;
+ }
+ talloc_free(id);
+ return true;
+}
+
+/* read a LDAPString from a ASN1 buffer */
+bool asn1_read_LDAPString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
+{
+ int len;
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+ *s = talloc_array(mem_ctx, char, len+1);
+ if (! *s) {
+ data->has_error = true;
+ return false;
+ }
+ (*s)[len] = 0;
+ return asn1_read(data, *s, len);
+}
+
+
+/* read a GeneralString from a ASN1 buffer */
+bool asn1_read_GeneralString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
+{
+ if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return false;
+ if (!asn1_read_LDAPString(data, mem_ctx, s)) return false;
+ return asn1_end_tag(data);
+}
+
+
+/* read a octet string blob */
+bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
+{
+ int len;
+ ZERO_STRUCTP(blob);
+ if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return false;
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+ *blob = data_blob_talloc(mem_ctx, NULL, len+1);
+ if (!blob->data || blob->length < len) {
+ data->has_error = true;
+ return false;
+ }
+ if (!asn1_read(data, blob->data, len)) goto err;
+ if (!asn1_end_tag(data)) goto err;
+ blob->length--;
+ blob->data[len] = 0;
+ return true;
+
+ err:
+
+ data_blob_free(blob);
+ *blob = data_blob_null;
+ return false;
+}
+
+bool asn1_read_ContextSimple(struct asn1_data *data, TALLOC_CTX *mem_ctx, uint8_t num,
+ DATA_BLOB *blob)
+{
+ int len;
+ ZERO_STRUCTP(blob);
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return false;
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+ *blob = data_blob_talloc(mem_ctx, NULL, len + 1);
+ if ((len != 0) && (!blob->data)) {
+ data->has_error = true;
+ return false;
+ }
+ if (!asn1_read(data, blob->data, len)) return false;
+ blob->length--;
+ blob->data[len] = 0;
+ return asn1_end_tag(data);
+}
+
+/* read an integer without tag*/
+bool asn1_read_implicit_Integer(struct asn1_data *data, int *i)
+{
+ uint8_t b;
+ uint32_t x = 0;
+ bool first_byte = true;
+
+ *i = 0;
+
+ while (!data->has_error && asn1_tag_remaining(data)>0) {
+ if (!asn1_read_uint8(data, &b)) return false;
+ if (first_byte) {
+ if (b & 0x80) {
+ /* Number is negative. */
+ x = (uint32_t)-1;
+ }
+ first_byte = false;
+ }
+ x = (x << 8) + b;
+ }
+ *i = (int)x;
+
+ return !data->has_error;
+}
+
+/* read an integer */
+bool asn1_read_Integer(struct asn1_data *data, int *i)
+{
+ *i = 0;
+
+ if (!asn1_start_tag(data, ASN1_INTEGER)) return false;
+ if (!asn1_read_implicit_Integer(data, i)) return false;
+ return asn1_end_tag(data);
+}
+
+/* read a BIT STRING */
+bool asn1_read_BitString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint8_t *padding)
+{
+ int len;
+ ZERO_STRUCTP(blob);
+ if (!asn1_start_tag(data, ASN1_BIT_STRING)) return false;
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+ if (!asn1_read_uint8(data, padding)) return false;
+
+ *blob = data_blob_talloc(mem_ctx, NULL, len+1);
+ if (!blob->data || blob->length < len) {
+ data->has_error = true;
+ return false;
+ }
+ if (asn1_read(data, blob->data, len - 1)) {
+ blob->length--;
+ blob->data[len] = 0;
+ asn1_end_tag(data);
+ }
+
+ if (data->has_error) {
+ data_blob_free(blob);
+ *blob = data_blob_null;
+ *padding = 0;
+ return false;
+ }
+ return true;
+}
+
+/* read a non-negative enumerated value */
+bool asn1_read_enumerated(struct asn1_data *data, int *v)
+{
+ unsigned int val_will_wrap = (0xFFU << ((sizeof(int)*8)-8));
+ *v = 0;
+
+ if (!asn1_start_tag(data, ASN1_ENUMERATED)) return false;
+ while (!data->has_error && asn1_tag_remaining(data)>0) {
+ uint8_t b;
+ if (!asn1_read_uint8(data, &b)) {
+ return false;
+ }
+ if (*v & val_will_wrap) {
+ /*
+ * There is something already in
+ * the top byte of the int. If we
+ * shift left by 8 it's going to
+ * wrap. Prevent this.
+ */
+ data->has_error = true;
+ return false;
+ }
+ /*
+ * To please/fool the Undefined Behaviour Sanitizer we cast to
+ * unsigned for the left shift.
+ */
+ *v = ((unsigned int)*v << 8) + b;
+ if (*v < 0) {
+ /* ASN1_ENUMERATED can't be -ve. */
+ data->has_error = true;
+ return false;
+ }
+ }
+ return asn1_end_tag(data);
+}
+
+/* write an enumerated value to the stream */
+bool asn1_write_enumerated(struct asn1_data *data, uint8_t v)
+{
+ if (!asn1_push_tag(data, ASN1_ENUMERATED)) return false;
+ if (!asn1_write_uint8(data, v)) return false;
+ return asn1_pop_tag(data);
+}
+
+/*
+ Get us the data just written without copying
+*/
+bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob)
+{
+ if (asn1->has_error) {
+ return false;
+ }
+ if (asn1->nesting != NULL) {
+ return false;
+ }
+ blob->data = asn1->data;
+ blob->length = asn1->length;
+ return true;
+}
+
+bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob)
+{
+ DATA_BLOB blob;
+
+ if (!asn1_blob(asn1, &blob)) {
+ return false;
+ }
+
+ *pblob = (DATA_BLOB) { .length = blob.length };
+ pblob->data = talloc_move(mem_ctx, &blob.data);
+
+ /*
+ * Stop access from here on
+ */
+ asn1->has_error = true;
+
+ return true;
+}
+
+/*
+ Fill in an asn1 struct without making a copy
+*/
+void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len)
+{
+ /*
+ * Save max_depth
+ */
+ unsigned max_depth = data->max_depth;
+ ZERO_STRUCTP(data);
+ data->data = buf;
+ data->length = len;
+ data->max_depth = max_depth;
+}
+
+int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
+{
+ struct asn1_data asn1;
+ size_t size;
+ bool ok;
+
+ ZERO_STRUCT(asn1);
+ asn1.data = blob.data;
+ asn1.length = blob.length;
+
+ ok = asn1_peek_tag_needed_size(&asn1, tag, &size);
+ if (!ok) {
+ return EMSGSIZE;
+ }
+
+ if (size > blob.length) {
+ *packet_size = size;
+ return EAGAIN;
+ }
+
+ *packet_size = size;
+ return 0;
+}
+
+/*
+ * Get the length of the ASN.1 data
+ */
+size_t asn1_get_length(const struct asn1_data *asn1) {
+ return asn1->length;
+}
diff --git a/lib/util/asn1.h b/lib/util/asn1.h
new file mode 100644
index 0000000..9043c34
--- /dev/null
+++ b/lib/util/asn1.h
@@ -0,0 +1,110 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple ASN1 code
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _ASN_1_H
+#define _ASN_1_H
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+
+
+struct nesting;
+struct asn1_data;
+typedef struct asn1_data ASN1_DATA;
+
+#define ASN1_APPLICATION(x) ((x)+0x60)
+#define ASN1_APPLICATION_SIMPLE(x) ((x)+0x40)
+#define ASN1_SEQUENCE(x) ((x)+0x30)
+#define ASN1_CONTEXT(x) ((x)+0xa0)
+#define ASN1_CONTEXT_SIMPLE(x) ((x)+0x80)
+#define ASN1_GENERAL_STRING 0x1b
+#define ASN1_OCTET_STRING 0x4
+#define ASN1_OID 0x6
+#define ASN1_BOOLEAN 0x1
+#define ASN1_INTEGER 0x2
+#define ASN1_BIT_STRING 0x3
+#define ASN1_ENUMERATED 0xa
+#define ASN1_SET 0x31
+
+#define ASN1_MAX_OIDS 20
+
+/*
+ * The maximum permitted depth for an ASN.1 parse tree, the limit is chosen
+ * to align with the value for windows. Note that this value will trigger
+ * ASAN stack overflow errors.
+ */
+#define ASN1_MAX_TREE_DEPTH 512
+
+struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx, unsigned max_depth);
+void asn1_free(struct asn1_data *data);
+bool asn1_has_error(const struct asn1_data *data);
+void asn1_set_error(struct asn1_data *data);
+bool asn1_has_nesting(const struct asn1_data *data);
+off_t asn1_current_ofs(const struct asn1_data *data);
+bool asn1_write(struct asn1_data *data, const void *p, int len);
+bool asn1_write_uint8(struct asn1_data *data, uint8_t v);
+bool asn1_push_tag(struct asn1_data *data, uint8_t tag);
+bool asn1_pop_tag(struct asn1_data *data);
+bool asn1_write_implicit_Integer(struct asn1_data *data, int i);
+bool asn1_write_Integer(struct asn1_data *data, int i);
+bool asn1_write_BitString(struct asn1_data *data, const void *p, size_t length, uint8_t padding);
+bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID);
+bool ber_write_partial_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *partial_oid);
+bool asn1_write_OID(struct asn1_data *data, const char *OID);
+bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length);
+bool asn1_write_LDAPString(struct asn1_data *data, const char *s);
+bool asn1_write_DATA_BLOB_LDAPString(struct asn1_data *data, const DATA_BLOB *s);
+bool asn1_write_GeneralString(struct asn1_data *data, const char *s);
+bool asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob);
+bool asn1_write_BOOLEAN(struct asn1_data *data, bool v);
+bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v);
+bool asn1_check_BOOLEAN(struct asn1_data *data, bool v);
+bool asn1_write_BOOLEAN_context(struct asn1_data *data, bool v, int context);
+bool asn1_read_BOOLEAN_context(struct asn1_data *data, bool *v, int context);
+bool asn1_load(struct asn1_data *data, DATA_BLOB blob);
+bool asn1_peek(struct asn1_data *data, void *p, int len);
+bool asn1_read(struct asn1_data *data, void *p, int len);
+bool asn1_read_uint8(struct asn1_data *data, uint8_t *v);
+bool asn1_peek_uint8(struct asn1_data *data, uint8_t *v);
+bool asn1_peek_tag(struct asn1_data *data, uint8_t tag);
+bool asn1_start_tag(struct asn1_data *data, uint8_t tag);
+bool asn1_end_tag(struct asn1_data *data);
+int asn1_tag_remaining(struct asn1_data *data);
+bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, char **OID);
+bool ber_read_partial_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, char **partial_oid);
+bool asn1_read_OID(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **OID);
+bool asn1_check_OID(struct asn1_data *data, const char *OID);
+bool asn1_read_LDAPString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s);
+bool asn1_read_GeneralString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s);
+bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob);
+bool asn1_read_ContextSimple(struct asn1_data *data, TALLOC_CTX *mem_ctx, uint8_t num, DATA_BLOB *blob);
+bool asn1_read_implicit_Integer(struct asn1_data *data, int *i);
+bool asn1_read_Integer(struct asn1_data *data, int *i);
+bool asn1_read_BitString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint8_t *padding);
+bool asn1_read_enumerated(struct asn1_data *data, int *v);
+bool asn1_write_enumerated(struct asn1_data *data, uint8_t v);
+bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob);
+bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob);
+void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len);
+int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
+size_t asn1_get_length(const struct asn1_data *asn1);
+
+#endif /* _ASN_1_H */
diff --git a/lib/util/attr.h b/lib/util/attr.h
new file mode 100644
index 0000000..af3e244
--- /dev/null
+++ b/lib/util/attr.h
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __UTIL_ATTR_H__
+#define __UTIL_ATTR_H__
+
+/* for old gcc releases that don't have the feature test macro __has_attribute */
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef _UNUSED_
+#if __has_attribute(unused) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+/** gcc attribute used on function parameters so that it does not emit
+ * warnings about them being unused. **/
+# define _UNUSED_ __attribute__ ((unused))
+#else
+# define _UNUSED_
+#endif
+#endif
+#ifndef UNUSED
+#define UNUSED(param) param _UNUSED_
+#endif
+
+#ifndef _DEPRECATED_
+#if __has_attribute(deprecated) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+
+#ifndef _WARN_UNUSED_RESULT_
+#if __has_attribute(warn_unused_result) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+#define _WARN_UNUSED_RESULT_ __attribute__ ((warn_unused_result))
+#else
+#define _WARN_UNUSED_RESULT_
+#endif
+#endif
+
+#ifndef _NORETURN_
+#if __has_attribute(noreturn) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+#define _NORETURN_ __attribute__ ((noreturn))
+#else
+#define _NORETURN_
+#endif
+#endif
+
+#ifndef _PURE_
+#if __has_attribute(pure) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+#define _PURE_ __attribute__((pure))
+#else
+#define _PURE_
+#endif
+#endif
+
+#ifndef NONNULL
+#if __has_attribute(nonnull) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+#define NONNULL(param) param __attribute__((nonnull))
+#else
+#define NONNULL(param) param
+#endif
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if __has_attribute(format) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+#ifndef FORMAT_ATTRIBUTE
+#if __has_attribute(format) || ( (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) )
+/** Use gcc attribute to check printf fns. a1 is argument to format()
+ * in the above macro. This is needed to support Heimdal's printf
+ * decorations. Note that some gcc 2.x versions don't handle this
+ * properly. **/
+#define FORMAT_ATTRIBUTE(a) __attribute__ ((format a))
+#else
+#define FORMAT_ATTRIBUTE(a)
+#endif
+#endif
+
+#endif /* __UTIL_ATTR_H__ */
diff --git a/lib/util/base64.c b/lib/util/base64.c
new file mode 100644
index 0000000..7acc83d
--- /dev/null
+++ b/lib/util/base64.c
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2006
+ Copyright (C) Jeremy Allison 1992-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/base64.h"
+
+static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * Decode a base64 string into a DATA_BLOB - simple and slow algorithm.
+ *
+ * A DATA_BLOB like {.data = NULL, length = 0} indicates memory error.
+ *
+ * Decoding stops at the first invalid character.
+ **/
+_PUBLIC_ DATA_BLOB base64_decode_data_blob_talloc(TALLOC_CTX *mem_ctx, const char *s)
+{
+ int bit_offset, byte_offset, idx, i, n;
+ DATA_BLOB decoded = data_blob_talloc(mem_ctx, s, strlen(s)+1);
+ unsigned char *d = decoded.data;
+ char *p;
+
+ if (decoded.data == NULL) {
+ decoded.length = 0;
+ return decoded;
+ }
+
+ n=i=0;
+
+ while (*s && (p=strchr(b64,*s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ d[byte_offset] &= ~((1<<(8-bit_offset))-1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (idx << (2-bit_offset));
+ n = byte_offset+1;
+ } else {
+ d[byte_offset] |= (idx >> (bit_offset-2));
+ d[byte_offset+1] = (idx << (8-(bit_offset-2))) & 0xFF;
+ n = byte_offset+2;
+ }
+ s++; i++;
+ }
+
+ if ((n > 0) && (*s == '=')) {
+ n -= 1;
+ }
+
+ /* fix up length */
+ decoded.length = n;
+ decoded.data = talloc_realloc(mem_ctx, decoded.data, uint8_t, n);
+ return decoded;
+}
+
+/**
+ * Decode a base64 string into a DATA_BLOB - simple and slow algorithm
+ **/
+_PUBLIC_ DATA_BLOB base64_decode_data_blob(const char *s)
+{
+ return base64_decode_data_blob_talloc(NULL, s);
+}
+
+/**
+ * Decode a base64 string in-place - wrapper for the above
+ **/
+_PUBLIC_ void base64_decode_inplace(char *s)
+{
+ DATA_BLOB decoded = base64_decode_data_blob(s);
+
+ if ( decoded.length != 0 ) {
+ memcpy(s, decoded.data, decoded.length);
+
+ /* null terminate */
+ s[decoded.length] = '\0';
+ } else {
+ *s = '\0';
+ }
+
+ data_blob_free(&decoded);
+}
+
+/**
+ * Encode a base64 string into a talloc()ed string caller to free.
+ *
+ * From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c
+ * with adjustments
+ **/
+
+_PUBLIC_ char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data)
+{
+ int bits = 0;
+ int char_count = 0;
+ size_t out_cnt, len, output_len;
+ char *result;
+
+ /*
+ * Note: we return NULL for a zero-length blob, even though it can be
+ * encoded as a zero length string in base64.
+ *
+ * FIXME, perhaps, but we need to check carefully before changing
+ * this.
+ */
+ if (data.length == 0 || data.data == NULL) {
+ return NULL;
+ }
+
+ out_cnt = 0;
+ len = data.length;
+ output_len = data.length * 2 + 4; /* Account for closing bytes. 4 is
+ * random but should be enough for
+ * the = and \0 */
+ result = talloc_array(mem_ctx, char, output_len); /* get us plenty of space */
+ if (result == NULL) {
+ return NULL;
+ }
+
+ while (len--) {
+ int c = (unsigned char) *(data.data++);
+ bits += c;
+ char_count++;
+ if (char_count == 3) {
+ result[out_cnt++] = b64[bits >> 18];
+ result[out_cnt++] = b64[(bits >> 12) & 0x3f];
+ result[out_cnt++] = b64[(bits >> 6) & 0x3f];
+ result[out_cnt++] = b64[bits & 0x3f];
+ bits = 0;
+ char_count = 0;
+ } else {
+ bits <<= 8;
+ }
+ }
+ if (char_count != 0) {
+ bits <<= 16 - (8 * char_count);
+ result[out_cnt++] = b64[bits >> 18];
+ result[out_cnt++] = b64[(bits >> 12) & 0x3f];
+ if (char_count == 1) {
+ result[out_cnt++] = '=';
+ result[out_cnt++] = '=';
+ } else {
+ result[out_cnt++] = b64[(bits >> 6) & 0x3f];
+ result[out_cnt++] = '=';
+ }
+ }
+ result[out_cnt] = '\0'; /* terminate */
+ return result;
+}
+
diff --git a/lib/util/base64.h b/lib/util/base64.h
new file mode 100644
index 0000000..4763804
--- /dev/null
+++ b/lib/util/base64.h
@@ -0,0 +1,52 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ *
+ * Copyright (C) Andrew Tridgell 1992-2001
+ * Copyright (C) Simo Sorce 2001-2002
+ * Copyright (C) Martin Pool 2003
+ * Copyright (C) James Peach 2006
+ * Copyright (C) Jeremy Allison 1992-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_UTIL_BASE64_H__
+#define __LIB_UTIL_BASE64_H__
+
+#include "replace.h"
+#include "lib/util/data_blob.h"
+
+/**
+ Base64 decode a string, place into a data blob. Caller to
+ data_blob_free() the result.
+**/
+DATA_BLOB base64_decode_data_blob_talloc(TALLOC_CTX *mem_ctx, const char *s);
+
+/**
+ Base64 decode a string, place into a data blob on NULL context.
+ Caller to data_blob_free() the result.
+**/
+DATA_BLOB base64_decode_data_blob(const char *s);
+
+/**
+ Base64 decode a string, inplace
+**/
+void base64_decode_inplace(char *s);
+/**
+ Base64 encode a binary data blob into a string
+**/
+char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data);
+
+#endif
diff --git a/lib/util/become_daemon.c b/lib/util/become_daemon.c
new file mode 100644
index 0000000..c6795c5
--- /dev/null
+++ b/lib/util/become_daemon.c
@@ -0,0 +1,151 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
+#include <systemd/sd-daemon.h>
+#endif
+
+#include "close_low_fd.h"
+#include "debug.h"
+
+#include "become_daemon.h"
+
+static bool sd_notifications = true;
+
+/*******************************************************************
+ Enable or disable daemon status systemd notifications
+********************************************************************/
+void daemon_sd_notifications(bool enable)
+{
+ sd_notifications = enable;
+ DBG_DEBUG("Daemon status systemd notifications %s\n",
+ sd_notifications ? "enabled" : "disabled");
+}
+
+/****************************************************************************
+ Become a daemon, discarding the controlling terminal.
+****************************************************************************/
+
+void become_daemon(bool do_fork, bool no_session, bool log_stdout)
+{
+ pid_t newpid;
+ if (do_fork) {
+ newpid = fork();
+ if (newpid == -1) {
+ exit_daemon("Fork failed", errno);
+ }
+ if (newpid) {
+ _exit(0);
+ }
+#if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
+ } else if (sd_notifications) {
+ sd_notify(0, "STATUS=Starting process...");
+#endif
+ }
+
+ /* detach from the terminal */
+#ifdef HAVE_SETSID
+ if (!no_session) {
+ int ret = setsid();
+ if (ret == -1) {
+ exit_daemon("Failed to create session", errno);
+ }
+ }
+#elif defined(TIOCNOTTY)
+ if (!no_session) {
+ int i = open("/dev/tty", O_RDWR, 0);
+ if (i != -1) {
+ ioctl(i, (int) TIOCNOTTY, (char *)0);
+ close(i);
+ }
+ }
+#endif /* HAVE_SETSID */
+
+ /* Close fd's 0,1,2 as appropriate. Needed if started by rsh. */
+ /* stdin must be open if we do not fork, for monitoring for
+ * close. stdout must be open if we are logging there, and we
+ * never close stderr (but debug might dup it onto a log file) */
+ if (do_fork) {
+ int ret = close_low_fd(0);
+ if (ret != 0) {
+ exit_daemon("close_low_fd(0) failed: %s\n", errno);
+ }
+ }
+ if (!log_stdout) {
+ int ret = close_low_fd(1);
+ if (ret != 0) {
+ exit_daemon("close_low_fd(1) failed: %s\n", errno);
+ }
+ }
+}
+
+void exit_daemon(const char *msg, int error)
+{
+ if (msg == NULL) {
+ msg = strerror(error);
+ }
+
+#if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
+ if (sd_notifications) {
+ sd_notifyf(0, "STATUS=daemon failed to start: %s\n"
+ "ERRNO=%i",
+ msg,
+ error);
+ }
+#endif
+ DBG_ERR("daemon failed to start: %s, error code %d\n",
+ msg, error);
+ exit(1);
+}
+
+void daemon_ready(const char *daemon)
+{
+ if (daemon == NULL) {
+ daemon = "Samba";
+ }
+#if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
+ if (sd_notifications) {
+ sd_notifyf(0,
+ "READY=1\nSTATUS=%s: ready to serve connections...",
+ daemon);
+ }
+#endif
+ DBG_INFO("daemon '%s' finished starting up and ready to serve "
+ "connections\n", daemon);
+}
+
+void daemon_status(const char *daemon, const char *msg)
+{
+ if (daemon == NULL) {
+ daemon = "Samba";
+ }
+#if defined(HAVE_LIBSYSTEMD_DAEMON) || defined(HAVE_LIBSYSTEMD)
+ if (sd_notifications) {
+ sd_notifyf(0, "STATUS=%s: %s", daemon, msg);
+ }
+#endif
+ DBG_STARTUP_NOTICE("daemon '%s' : %s\n", daemon, msg);
+}
diff --git a/lib/util/become_daemon.h b/lib/util/become_daemon.h
new file mode 100644
index 0000000..e12be27
--- /dev/null
+++ b/lib/util/become_daemon.h
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _BECOME_DAEMON_H
+#define _BECOME_DAEMON_H
+
+#include <stdbool.h>
+
+/**
+ * @file become_daemon.h
+ *
+ * @brief Utilities for demonising
+ */
+
+/**
+ * @brief Enable or disable daemon status systemd notifications
+ *
+ * When samba runs as AD DC only the main 'samba' process has to
+ * notify systemd. Child processes started by the main 'samba', like
+ * smbd and winbindd should call this function to disable sd_notify()
+ * calls.
+ *
+ * @param[in] enable True to enable notifications, false to disable
+**/
+void daemon_sd_notifications(bool enable);
+
+/**
+ * @brief Become a daemon, optionally discarding the controlling terminal
+ *
+ * @param[in] do_fork Should the process fork?
+ * @param[in] no_session Don't start a new session
+ * @param[in] log_stdour Should stdout be closed?
+**/
+void become_daemon(bool do_fork, bool no_session, bool log_stdout);
+
+/**
+ * @brief Exit daemon and log an error message at ERR level
+ *
+ * Optionally report failure to systemd if systemd integration is
+ * enabled.
+ *
+ * @param[in] msg Message to log, generated from error if NULL
+ * @param[in] error Errno of error that occurred
+**/
+void exit_daemon(const char *msg, int error);
+
+/**
+ * @brief Log at ERR level that the daemon is ready to serve connections
+ *
+ * Optionally report status to systemd if systemd integration is enabled.
+ *
+ * @param[in] daemon Name of daemon to include it message
+**/
+void daemon_ready(const char *daemon);
+
+/**
+ * @brief Log at ERR level the specified daemon status
+ *
+ * For example if it is not ready to serve connections and is waiting
+ * for some event to happen.
+ *
+ * Optionally report status to systemd if systemd integration is enabled.
+ *
+ * @param[in] daemon Name of daemon to include it message
+ * @param[in] msg Message to log
+**/
+void daemon_status(const char *daemon, const char *msg);
+
+#endif /* _BECOME_DAEMON_H */
diff --git a/lib/util/binsearch.h b/lib/util/binsearch.h
new file mode 100644
index 0000000..8ae9da2
--- /dev/null
+++ b/lib/util/binsearch.h
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a generic binary search macro
+
+ Copyright (C) Andrew Tridgell 2009
+
+ ** NOTE! The following LGPL license applies to the binsearch.h
+ ** header. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _BINSEARCH_H
+#define _BINSEARCH_H
+
+/* a binary array search, where the array is an array of pointers to structures,
+ and we want to find a match for 'target' on 'field' in those structures.
+
+ Inputs:
+ array: base pointer to an array of structures
+ arrray_size: number of elements in the array
+ field: the name of the field in the structure we are keying off
+ target: the field value we are looking for
+ comparison_fn: the comparison function
+ result: where the result of the search is put
+
+ if the element is found, then 'result' is set to point to the found array element. If not,
+ then 'result' is set to NULL.
+
+ The array is assumed to be sorted by the same comparison_fn as the
+ search (with, for example, qsort)
+ */
+#define BINARY_ARRAY_SEARCH_P(array, array_size, field, target, comparison_fn, result) do { \
+ int32_t _b, _e; \
+ (result) = NULL; \
+ if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b+_e)/2; \
+ int _r = comparison_fn(target, array[_i]->field); \
+ if (_r == 0) { (result) = array[_i]; break; } \
+ if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+ }} } while (0)
+
+/*
+ like BINARY_ARRAY_SEARCH_P, but assumes that the array is an array
+ of structures, rather than pointers to structures
+
+ result points to the found structure, or NULL
+ */
+#define BINARY_ARRAY_SEARCH(array, array_size, field, target, comparison_fn, result) do { \
+ int32_t _b, _e; \
+ (result) = NULL; \
+ if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b+_e)/2; \
+ int _r = comparison_fn(target, array[_i].field); \
+ if (_r == 0) { (result) = &array[_i]; break; } \
+ if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+ }} } while (0)
+
+/*
+ like BINARY_ARRAY_SEARCH_P, but assumes that the array is an array
+ of elements, rather than pointers to structures
+
+ result points to the found structure, or NULL
+ */
+#define BINARY_ARRAY_SEARCH_V(array, array_size, target, comparison_fn, result) do { \
+ int32_t _b, _e; \
+ (result) = NULL; \
+ if (array_size) { for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b+_e)/2; \
+ int _r = comparison_fn(target, array[_i]); \
+ if (_r == 0) { (result) = &array[_i]; break; } \
+ if (_r < 0) _e = _i - 1; else _b = _i + 1; \
+ }} } while (0)
+
+
+/*
+ like BINARY_ARRAY_SEARCH_V, but if an exact result is not found, the 'next'
+ argument will point to the element after the place where the exact result
+ would have been. If an exact result is found, 'next' will be NULL. If the
+ target is beyond the end of the list, both 'exact' and 'next' will be NULL.
+ Unlike other binsearch macros, where there are several elements that compare
+ the same, the exact result will always point to the first one.
+
+ If you don't care to distinguish between the 'greater than' and 'equals'
+ cases, you can use the same pointer for both 'exact' and 'next'.
+
+ As with all the binsearch macros, the comparison function is always called
+ with the search term first.
+ */
+#define BINARY_ARRAY_SEARCH_GTE(array, array_size, target, comparison_fn, \
+ exact, next) do { \
+ int32_t _b, _e; \
+ (exact) = NULL; (next) = NULL; \
+ if ((array_size) > 0) { \
+ for (_b = 0, _e = (array_size)-1; _b <= _e; ) { \
+ int32_t _i = (_b + _e) / 2; \
+ int _r = comparison_fn(target, &array[_i]); \
+ if (_r == 0) { \
+ (exact) = &array[_i]; \
+ _e = _i - 1; \
+ } else if (_r < 0) { _e = _i - 1; \
+ } else { _b = _i + 1; } \
+ } \
+ if ((exact) == NULL &&_b < (array_size)) { \
+ (next) = &array[_b]; \
+ } } } while (0)
+
+#endif
diff --git a/lib/util/bitmap.c b/lib/util/bitmap.c
new file mode 100644
index 0000000..12cdfe4
--- /dev/null
+++ b/lib/util/bitmap.c
@@ -0,0 +1,144 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple bitmap functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/bitmap.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+
+struct bitmap {
+ unsigned int n;
+ uint32_t b[1]; /* We allocate more */
+};
+
+/* these functions provide a simple way to allocate integers from a
+ pool without repetition */
+
+/****************************************************************************
+talloc a bitmap
+****************************************************************************/
+struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n)
+{
+ struct bitmap *bm;
+
+ bm = (struct bitmap *)talloc_zero_size(
+ mem_ctx,
+ offsetof(struct bitmap, b) + sizeof(uint32_t)*((n+31)/32));
+
+ if (!bm) return NULL;
+
+ talloc_set_name_const(bm, "struct bitmap");
+
+ bm->n = n;
+ return bm;
+}
+
+/****************************************************************************
+copy as much of the source bitmap as will fit in the destination bitmap.
+****************************************************************************/
+
+int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src)
+{
+ int count = MIN(dst->n, src->n);
+
+ SMB_ASSERT(dst->b != src->b);
+ memcpy(dst->b, src->b, sizeof(uint32_t)*((count+31)/32));
+
+ return count;
+}
+
+/****************************************************************************
+set a bit in a bitmap
+****************************************************************************/
+bool bitmap_set(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return false;
+ }
+ bm->b[i/32] |= (1U<<(i%32));
+ return true;
+}
+
+/****************************************************************************
+clear a bit in a bitmap
+****************************************************************************/
+bool bitmap_clear(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) {
+ DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n",
+ i, bm->n));
+ return false;
+ }
+ bm->b[i/32] &= ~(1U<<(i%32));
+ return true;
+}
+
+/****************************************************************************
+query a bit in a bitmap
+****************************************************************************/
+bool bitmap_query(struct bitmap *bm, unsigned i)
+{
+ if (i >= bm->n) return false;
+ if (bm->b[i/32] & (1U<<(i%32))) {
+ return true;
+ }
+ return false;
+}
+
+/****************************************************************************
+find a zero bit in a bitmap starting at the specified offset, with
+wraparound
+****************************************************************************/
+int bitmap_find(struct bitmap *bm, unsigned ofs)
+{
+ unsigned int i, j;
+
+ if (ofs > bm->n) ofs = 0;
+
+ i = ofs;
+ while (i < bm->n) {
+ if (~(bm->b[i/32])) {
+ j = i;
+ do {
+ if (!bitmap_query(bm, j)) return j;
+ j++;
+ } while (j & 31 && j < bm->n);
+ }
+ i += 32;
+ i &= ~31;
+ }
+
+ i = 0;
+ while (i < ofs) {
+ if (~(bm->b[i/32])) {
+ j = i;
+ do {
+ if (!bitmap_query(bm, j)) return j;
+ j++;
+ } while (j & 31 && j < bm->n);
+ }
+ i += 32;
+ i &= ~31;
+ }
+
+ return -1;
+}
diff --git a/lib/util/bitmap.h b/lib/util/bitmap.h
new file mode 100644
index 0000000..6d75929
--- /dev/null
+++ b/lib/util/bitmap.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple bitmap functions
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* The following definitions come from lib/bitmap.c */
+
+struct bitmap;
+
+struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n);
+int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src);
+bool bitmap_set(struct bitmap *bm, unsigned i);
+bool bitmap_clear(struct bitmap *bm, unsigned i);
+bool bitmap_query(struct bitmap *bm, unsigned i);
+int bitmap_find(struct bitmap *bm, unsigned ofs);
diff --git a/lib/util/blocking.c b/lib/util/blocking.c
new file mode 100644
index 0000000..6d7fc91
--- /dev/null
+++ b/lib/util/blocking.c
@@ -0,0 +1,76 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "blocking.h"
+
+/**
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+**/
+
+_PUBLIC_ int set_blocking(int fd, bool set)
+{
+ int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
+
+
+_PUBLIC_ bool smb_set_close_on_exec(int fd)
+{
+#ifdef FD_CLOEXEC
+ int val;
+
+ val = fcntl(fd, F_GETFD, 0);
+ if (val >= 0) {
+ val |= FD_CLOEXEC;
+ val = fcntl(fd, F_SETFD, val);
+ if (val != -1) {
+ return true;
+ }
+ }
+#else
+ errno = ENOSYS;
+#endif
+ return false;
+}
diff --git a/lib/util/blocking.h b/lib/util/blocking.h
new file mode 100644
index 0000000..d605352
--- /dev/null
+++ b/lib/util/blocking.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_BLOCKING_H_
+#define _SAMBA_BLOCKING_H_
+
+#include <stdbool.h>
+
+int set_blocking(int fd, bool set);
+bool smb_set_close_on_exec(int fd);
+
+#define set_close_on_exec(fd) smb_set_close_on_exec(fd)
+
+#endif /* _SAMBA_BLOCKING_H_ */
diff --git a/lib/util/bytearray.h b/lib/util/bytearray.h
new file mode 100644
index 0000000..0af8a82
--- /dev/null
+++ b/lib/util/bytearray.h
@@ -0,0 +1,124 @@
+/*
+ * Macros for handling integer types in byte arrays
+ *
+ * This file is originally from the libssh.org project
+ *
+ * Copyright (c) 2018 Andreas Schneider <asn@cryptomilk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef _BYTEARRAY_H
+#define _BYTEARRAY_H
+
+#define _DATA_BYTE_CONST(data, pos) \
+ ((uint8_t)(((const uint8_t *)(data))[(pos)]))
+
+#define _DATA_BYTE(data, pos) \
+ (((uint8_t *)(data))[(pos)])
+
+/*
+ * These macros pull or push integer values from byte arrays stored in
+ * little-endian byte order.
+ */
+#define PULL_LE_U8(data, pos) \
+ (_DATA_BYTE_CONST(data, pos))
+#define PULL_LE_I8(data, pos) \
+ (int8_t)PULL_LE_U8(data, pos)
+
+#define PULL_LE_U16(data, pos) \
+ ((uint16_t)PULL_LE_U8(data, pos) | ((uint16_t)(PULL_LE_U8(data, (pos) + 1))) << 8)
+#define PULL_LE_I16(data, pos) \
+ (int16_t)PULL_LE_U16(data, pos)
+
+#define PULL_LE_U32(data, pos) \
+ ((uint32_t)(PULL_LE_U16(data, pos) | ((uint32_t)PULL_LE_U16(data, (pos) + 2)) << 16))
+#define PULL_LE_I32(data, pos) \
+ (int32_t)PULL_LE_U32(data, pos)
+
+#define PULL_LE_U64(data, pos) \
+ ((uint64_t)(PULL_LE_U32(data, pos) | ((uint64_t)PULL_LE_U32(data, (pos) + 4)) << 32))
+#define PULL_LE_I64(data, pos) \
+ (int64_t)PULL_LE_U64(data, pos)
+
+
+#define PUSH_LE_U8(data, pos, val) \
+ (_DATA_BYTE(data, pos) = ((uint8_t)(val)))
+#define PUSH_LE_I8(data, pos, val) \
+ PUSH_LE_U8(data, pos, val)
+
+#define PUSH_LE_U16(data, pos, val) \
+ (PUSH_LE_U8(data, pos, (uint16_t)(val) & 0xff), PUSH_LE_U8(data, (pos) + 1, (uint16_t)(val) >> 8))
+#define PUSH_LE_I16(data, pos, val) \
+ PUSH_LE_U16(data, pos, val)
+
+#define PUSH_LE_U32(data, pos, val) \
+ (PUSH_LE_U16(data, pos, (uint32_t)(val) & 0xffff), PUSH_LE_U16(data, (pos) + 2, (uint32_t)(val) >> 16))
+#define PUSH_LE_I32(data, pos, val) \
+ PUSH_LE_U32(data, pos, val)
+
+#define PUSH_LE_U64(data, pos, val) \
+ (PUSH_LE_U32(data, pos, (uint64_t)(val) & 0xffffffff), PUSH_LE_U32(data, (pos) + 4, (uint64_t)(val) >> 32))
+#define PUSH_LE_I64(data, pos, val) \
+ PUSH_LE_U64(data, pos, val)
+
+
+
+/*
+ * These macros pull or push integer values from byte arrays stored in
+ * big-endian byte order (network byte order).
+ */
+#define PULL_BE_U8(data, pos) \
+ (_DATA_BYTE_CONST(data, pos))
+#define PULL_BE_I8(data, pos) \
+ (int8_t)PULL_BE_U8(data, pos)
+
+#define PULL_BE_U16(data, pos) \
+ ((((uint16_t)(PULL_BE_U8(data, pos))) << 8) | (uint16_t)PULL_BE_U8(data, (pos) + 1))
+#define PULL_BE_I16(data, pos) \
+ (int16_t)PULL_BE_U16(data, pos)
+
+#define PULL_BE_U32(data, pos) \
+ ((((uint32_t)PULL_BE_U16(data, pos)) << 16) | (uint32_t)(PULL_BE_U16(data, (pos) + 2)))
+#define PULL_BE_I32(data, pos) \
+ (int32_t)PULL_BE_U32(data, pos)
+
+#define PULL_BE_U64(data, pos) \
+ ((((uint64_t)PULL_BE_U32(data, pos)) << 32) | (uint64_t)(PULL_BE_U32(data, (pos) + 4)))
+#define PULL_BE_I64(data, pos) \
+ (int64_t)PULL_BE_U64(data, pos)
+
+
+
+#define PUSH_BE_U8(data, pos, val) \
+ (_DATA_BYTE(data, pos) = ((uint8_t)(val)))
+#define PUSH_BE_I8(data, pos, val) \
+ PUSH_BE_U8(data, pos, val)
+
+#define PUSH_BE_U16(data, pos, val) \
+ (PUSH_BE_U8(data, pos, ((uint16_t)(val)) >> 8), PUSH_BE_U8(data, (pos) + 1, (uint16_t)(val) & 0xff))
+#define PUSH_BE_I16(data, pos, val) \
+ PUSH_BE_U16(data, pos, val)
+
+#define PUSH_BE_U32(data, pos, val) \
+ (PUSH_BE_U16(data, pos, (uint32_t)(val) >> 16), PUSH_BE_U16(data, (pos) + 2, (uint32_t)(val) & 0xffff))
+#define PUSH_BE_I32(data, pos, val) \
+ PUSH_BE_U32(data, pos, val)
+
+#define PUSH_BE_U64(data, pos, val) \
+ (PUSH_BE_U32(data, pos, (uint64_t)(val) >> 32), PUSH_BE_U32(data, (pos) + 4, (uint64_t)(val) & 0xffffffff))
+#define PUSH_BE_I64(data, pos, val) \
+ PUSH_BE_U64(data, pos, val)
+
+#endif /* _BYTEARRAY_H */
diff --git a/lib/util/byteorder.h b/lib/util/byteorder.h
new file mode 100644
index 0000000..65023f9
--- /dev/null
+++ b/lib/util/byteorder.h
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Byte handling
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _BYTEORDER_H
+#define _BYTEORDER_H
+
+#include "bytearray.h"
+
+/*
+ This file implements macros for machine independent short and
+ int manipulation
+
+Here is a description of this file that I emailed to the samba list once:
+
+> I am confused about the way that byteorder.h works in Samba. I have
+> looked at it, and I would have thought that you might make a distinction
+> between LE and BE machines, but you only seem to distinguish between 386
+> and all other architectures.
+>
+> Can you give me a clue?
+
+sure.
+
+Ok, now to the macros themselves. I'll take a simple example, say we
+want to extract a 2 byte integer from a SMB packet and put it into a
+type called uint16_t that is in the local machines byte order, and you
+want to do it with only the assumption that uint16_t is _at_least_ 16
+bits long (this last condition is very important for architectures
+that don't have any int types that are 2 bytes long)
+
+You do this:
+
+#define CVAL(buf,pos) (((uint8_t *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned int)CVAL(buf,pos))
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+
+then to extract a uint16_t value at offset 25 in a buffer you do this:
+
+char *buffer = foo_bar();
+uint16_t xx = SVAL(buffer,25);
+
+We are using the byteorder independence of the ANSI C bitshifts to do
+the work. A good optimising compiler should turn this into efficient
+code, especially if it happens to have the right byteorder :-)
+
+I know these macros can be made a bit tidier by removing some of the
+casts, but you need to look at byteorder.h as a whole to see the
+reasoning behind them. byteorder.h defines the following macros:
+
+SVAL(buf,pos) - extract a 2 byte SMB value
+IVAL(buf,pos) - extract a 4 byte SMB value
+BVAL(buf,pos) - extract a 8 byte SMB value
+SVALS(buf,pos) - signed version of SVAL()
+IVALS(buf,pos) - signed version of IVAL()
+BVALS(buf,pos) - signed version of BVAL()
+
+SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
+SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
+SBVAL(buf,pos,val) - put a 8 byte SMB value into a buffer
+SSVALS(buf,pos,val) - signed version of SSVAL()
+SIVALS(buf,pos,val) - signed version of SIVAL()
+SBVALS(buf,pos,val) - signed version of SBVAL()
+
+RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
+RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
+RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
+RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
+RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
+RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
+RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering
+
+it also defines lots of intermediate macros, just ignore those :-)
+
+*/
+
+
+/****************************************************************************
+ *
+ * ATTENTION: Do not use those macros anymore, use the ones from bytearray.h
+ *
+ ****************************************************************************/
+
+#define CVAL(buf,pos) ((uint32_t)_DATA_BYTE_CONST(buf, pos))
+#define CVAL_NC(buf,pos) _DATA_BYTE(buf, pos) /* Non-const version of CVAL */
+#define PVAL(buf,pos) (CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL_NC(buf,pos) = (val))
+
+/****************************************************************************
+ *
+ * ATTENTION: Do not use those macros anymore, use the ones from bytearray.h
+ *
+ ****************************************************************************/
+
+#define SVAL(buf,pos) (uint32_t)PULL_LE_U16(buf, pos)
+#define IVAL(buf,pos) PULL_LE_U32(buf, pos)
+#define SSVALX(buf,pos,val) (CVAL_NC(buf,pos)=(uint8_t)((val)&0xFF),CVAL_NC(buf,(pos)+1)=(uint8_t)((val)>>8))
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,(val)&0xFFFF),SSVALX(buf,(pos)+2,(val)>>16))
+#define SVALS(buf,pos) ((int16_t)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32_t)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) PUSH_LE_U16(buf, pos, val)
+#define SIVAL(buf,pos,val) PUSH_LE_U32(buf, pos, val)
+#define SSVALS(buf,pos,val) PUSH_LE_U16(buf, pos, val)
+#define SIVALS(buf,pos,val) PUSH_LE_U32(buf, pos, val)
+
+/****************************************************************************
+ *
+ * ATTENTION: Do not use those macros anymore, use the ones from bytearray.h
+ *
+ ****************************************************************************/
+
+/* 64 bit macros */
+#define BVAL(p, ofs) PULL_LE_U64(p, ofs)
+#define BVALS(p, ofs) ((int64_t)BVAL(p,ofs))
+#define SBVAL(p, ofs, v) PUSH_LE_U64(p, ofs, v)
+#define SBVALS(p, ofs, v) (SBVAL(p,ofs,(uint64_t)(v)))
+
+/****************************************************************************
+ *
+ * ATTENTION: Do not use those macros anymore, use the ones from bytearray.h
+ *
+ ****************************************************************************/
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV((uint32_t)(x))<<16) | (SREV(((uint32_t)(x))>>16)))
+#define BREV(x) ((IREV((uint64_t)(x))<<32) | (IREV(((uint64_t)(x))>>32)))
+
+/****************************************************************************
+ *
+ * ATTENTION: Do not use those macros anymore, use the ones from bytearray.h
+ *
+ ****************************************************************************/
+
+#define RSVAL(buf,pos) (uint32_t)PULL_BE_U16(buf, pos)
+#define RSVALS(buf,pos) PULL_BE_U16(buf, pos)
+#define RIVAL(buf,pos) PULL_BE_U32(buf, pos)
+#define RIVALS(buf,pos) PULL_BE_U32(buf, pos)
+#define RBVAL(buf,pos) PULL_BE_U64(buf, pos)
+#define RBVALS(buf,pos) PULL_BE_U64(buf, pos)
+#define RSSVAL(buf,pos,val) PUSH_BE_U16(buf, pos, val)
+#define RSSVALS(buf,pos,val) PUSH_BE_U16(buf, pos, val)
+#define RSIVAL(buf,pos,val) PUSH_BE_U32(buf, pos, val)
+#define RSIVALS(buf,pos,val) PUSH_BE_U32(buf, pos, val)
+#define RSBVAL(buf,pos,val) PUSH_BE_U64(buf, pos, val)
+#define RSBVALS(buf,pos,val) PUSH_BE_U64(buf, pos, val)
+
+/****************************************************************************
+ *
+ * ATTENTION: Do not use those macros anymore, use the ones from bytearray.h
+ *
+ ****************************************************************************/
+
+#endif /* _BYTEORDER_H */
diff --git a/lib/util/charset/charset.h b/lib/util/charset/charset.h
new file mode 100644
index 0000000..12dc348
--- /dev/null
+++ b/lib/util/charset/charset.h
@@ -0,0 +1,299 @@
+/*
+ Unix SMB/CIFS implementation.
+ charset defines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This is a public header file that is installed as part of Samba.
+ * If you remove any functions or change their signature, update
+ * the so version number. */
+
+#ifndef __CHARSET_H__
+#define __CHARSET_H__
+
+#include <talloc.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/* this defines the charset types used in samba */
+typedef enum {
+ CH_UTF16LE = 0,
+ CH_UTF16 = 0,
+ CH_UNIX,
+ CH_DOS,
+ CH_UTF8,
+ CH_UTF16BE,
+ CH_UTF16MUNGED,
+ /* The number of distinct character sets. */
+ NUM_CHARSETS
+} charset_t;
+
+/*
+ * SMB UCS2 (16-bit unicode) internal type.
+ * smb_ucs2_t is *always* in little endian format.
+ */
+
+typedef uint16_t smb_ucs2_t;
+
+#ifdef WORDS_BIGENDIAN
+#define UCS2_SHIFT 8
+#else
+#define UCS2_SHIFT 0
+#endif
+
+/* turn a 7 bit character into a ucs2 character */
+#define UCS2_CHAR(c) ((c) << UCS2_SHIFT)
+
+/*
+ * for each charset we have a function that pulls from that charset to
+ * a ucs2 buffer, and a function that pushes to a ucs2 buffer
+ * */
+
+struct charset_functions {
+ const char *name;
+ size_t (*pull)(void *, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*push)(void *, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ bool samba_internal_charset;
+};
+
+/* this type is used for manipulating unicode codepoints */
+typedef uint32_t codepoint_t;
+
+#define INVALID_CODEPOINT ((codepoint_t)-1)
+
+/* generic iconv conversion structure */
+typedef struct smb_iconv_s {
+ size_t (*direct)(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*pull)(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ size_t (*push)(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+ void *cd_direct, *cd_pull, *cd_push;
+ char *from_name, *to_name;
+} *smb_iconv_t;
+
+/* string manipulation flags */
+#define STR_TERMINATE 1
+#define STR_UPPER 2
+#define STR_ASCII 4
+#define STR_UNICODE 8
+#define STR_NOALIGN 16
+#define STR_NO_RANGE_CHECK 32
+#define STR_LEN8BIT 64
+#define STR_TERMINATE_ASCII 128 /* only terminate if ascii */
+#define STR_LEN_NOTERM 256 /* the length field is the unterminated length */
+
+struct loadparm_context;
+struct smb_iconv_handle;
+
+size_t ucs2_align(const void *base_ptr, const void *p, int flags);
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+**/
+size_t utf16_len(const void *buf);
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+**/
+size_t utf16_null_terminated_len(const void *buf);
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+limited by 'n' bytes
+**/
+size_t utf16_len_n(const void *src, size_t n);
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+limited by 'n' bytes
+**/
+size_t utf16_null_terminated_len_n(const void *src, size_t n);
+
+unsigned char *talloc_utf16_strlendup(TALLOC_CTX *mem_ctx, const char *str, size_t len);
+unsigned char *talloc_utf16_strdup(TALLOC_CTX *mem_ctx, const char *str);
+unsigned char *talloc_utf16_strndup(TALLOC_CTX *mem_ctx, const char *str, size_t n);
+
+char *strchr_m(const char *s, char c);
+/**
+ * Calculate the number of units (8 or 16-bit, depending on the
+ * destination charset) that would be needed to convert the input
+ * string, which is expected to be in src_charset encoding, to the
+ * destination charset (which should be a unicode charset).
+ */
+size_t strlen_m_ext_handle(struct smb_iconv_handle *ic,
+ const char *s, charset_t src_charset, charset_t dst_charset);
+size_t strlen_m_ext(const char *s, charset_t src_charset, charset_t dst_charset);
+size_t strlen_m_ext_term(const char *s, charset_t src_charset,
+ charset_t dst_charset);
+size_t strlen_m_ext_term_null(const char *s,
+ charset_t src_charset,
+ charset_t dst_charset);
+size_t strlen_m(const char *s);
+size_t strlen_m_term(const char *s);
+size_t strlen_m_term_null(const char *s);
+char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength);
+char *talloc_alpha_strcpy(TALLOC_CTX *mem_ctx,
+ const char *src,
+ const char *other_safe_chars);
+void string_replace_m(char *s, char oldc, char newc);
+bool strcsequal(const char *s1,const char *s2);
+bool strequal_m(const char *s1, const char *s2);
+int strncasecmp_m(const char *s1, const char *s2, size_t n);
+int strncasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
+ const char *s1, const char *s2, size_t n);
+bool next_token(const char **ptr,char *buff, const char *sep, size_t bufsize);
+int strcasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
+ const char *s1, const char *s2);
+int strcasecmp_m(const char *s1, const char *s2);
+size_t count_chars_m(const char *s, char c);
+char *strupper_talloc(TALLOC_CTX *ctx, const char *src);
+char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *src);
+char *strupper_talloc_n_handle(struct smb_iconv_handle *iconv_handle,
+ TALLOC_CTX *ctx, const char *src, size_t n);
+char *strupper_talloc_n(TALLOC_CTX *ctx, const char *src, size_t n);
+ char *strlower_talloc_handle(struct smb_iconv_handle *iconv_handle,
+ TALLOC_CTX *ctx, const char *src);
+char *strlower_talloc(TALLOC_CTX *ctx, const char *src);
+bool strhasupper(const char *string);
+bool strhaslower_handle(struct smb_iconv_handle *ic,
+ const char *string);
+bool strhaslower(const char *string);
+bool strhasupper_handle(struct smb_iconv_handle *ic,
+ const char *string);
+char *strrchr_m(const char *s, char c);
+char *strchr_m(const char *s, char c);
+char *strstr_m(const char *src, const char *findstr);
+
+bool utf8_check(const char *input, size_t maxlen,
+ size_t *byte_len,
+ size_t *char_len,
+ size_t *utf16_len);
+
+bool push_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size);
+bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src, size_t *converted_size);
+bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size);
+bool pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size);
+bool pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src, size_t *converted_size);
+bool pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size);
+ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags);
+ssize_t pull_string(char *dest, const void *src, size_t dest_len, size_t src_len, int flags);
+
+bool convert_string_talloc(TALLOC_CTX *ctx,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t *converted_size);
+
+bool convert_string(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen,
+ size_t *converted_size);
+bool convert_string_error(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen,
+ size_t *converted_size);
+
+struct smb_iconv_handle *get_iconv_handle(void);
+struct smb_iconv_handle *get_iconv_testing_handle(TALLOC_CTX *mem_ctx,
+ const char *dos_charset,
+ const char *unix_charset,
+ bool use_builtin_handlers);
+struct smb_iconv_handle *reinit_iconv_handle(TALLOC_CTX *mem_ctx,
+ const char *dos_charset,
+ const char *unix_charset);
+void free_iconv_handle(void);
+
+smb_iconv_t get_conv_handle(struct smb_iconv_handle *ic,
+ charset_t from, charset_t to);
+const char *charset_name(struct smb_iconv_handle *ic, charset_t ch);
+
+codepoint_t next_codepoint_ext(const char *str, size_t len,
+ charset_t src_charset, size_t *size);
+codepoint_t next_codepoint(const char *str, size_t *size);
+ssize_t push_codepoint(char *str, codepoint_t c);
+
+/* codepoints */
+codepoint_t next_codepoint_handle_ext(struct smb_iconv_handle *ic,
+ const char *str, size_t len,
+ charset_t src_charset,
+ size_t *size);
+codepoint_t next_codepoint_handle(struct smb_iconv_handle *ic,
+ const char *str, size_t *size);
+ssize_t push_codepoint_handle(struct smb_iconv_handle *ic,
+ char *str, codepoint_t c);
+
+codepoint_t toupper_m(codepoint_t val);
+codepoint_t tolower_m(codepoint_t val);
+bool islower_m(codepoint_t val);
+bool isupper_m(codepoint_t val);
+int codepoint_cmpi(codepoint_t c1, codepoint_t c2);
+
+/* Iconv convenience functions */
+struct smb_iconv_handle *smb_iconv_handle_reinit(TALLOC_CTX *mem_ctx,
+ const char *dos_charset,
+ const char *unix_charset,
+ bool use_builtin_handlers,
+ struct smb_iconv_handle *old_ic);
+
+bool convert_string_handle(struct smb_iconv_handle *ic,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen, size_t *converted_size);
+bool convert_string_error_handle(struct smb_iconv_handle *ic,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen,
+ size_t *converted_size);
+
+bool convert_string_talloc_handle(TALLOC_CTX *ctx,
+ struct smb_iconv_handle *ic,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t *converted_size);
+/* iconv */
+smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode);
+int smb_iconv_close(smb_iconv_t cd);
+size_t smb_iconv(smb_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+smb_iconv_t smb_iconv_open_ex(TALLOC_CTX *mem_ctx, const char *tocode,
+ const char *fromcode, bool use_builtin_handlers);
+
+void smb_init_locale(void);
+
+/* The following definitions come from util_unistr_w.c */
+
+size_t strlen_w(const smb_ucs2_t *src);
+size_t strnlen_w(const smb_ucs2_t *src, size_t max);
+smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c);
+smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c);
+smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c);
+smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n);
+smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins);
+bool strlower_w(smb_ucs2_t *s);
+bool strupper_w(smb_ucs2_t *s);
+int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b);
+int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len);
+int strcmp_wa(const smb_ucs2_t *a, const char *b);
+smb_ucs2_t toupper_w(smb_ucs2_t v);
+
+#endif /* __CHARSET_H__ */
diff --git a/lib/util/charset/charset_macosxfs.c b/lib/util/charset/charset_macosxfs.c
new file mode 100644
index 0000000..2ecfdff
--- /dev/null
+++ b/lib/util/charset/charset_macosxfs.c
@@ -0,0 +1,605 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba charset module for Mac OS X/Darwin
+ Copyright (C) Benjamin Riefenstahl 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * modules/charset_macosxfs.c
+ *
+ * A Samba charset module to use on Mac OS X/Darwin as the filesystem
+ * and display encoding.
+ *
+ * Actually two implementations are provided here. The default
+ * implementation is based on the official CFString API. The other is
+ * based on internal CFString APIs as defined in the OpenDarwin
+ * source.
+ */
+
+#include "replace.h"
+#include "charset.h"
+#include "charset_proto.h"
+#include "lib/util/debug.h"
+#undef realloc
+
+#ifdef DARWINOS
+
+/*
+ * Include OS frameworks. These are only needed in this module.
+ */
+#include <CoreFoundation/CFString.h>
+
+/*
+ * See if autoconf has found us the internal headers in some form.
+ */
+#if defined(HAVE_COREFOUNDATION_CFSTRINGENCODINGCONVERTER_H)
+# include <CoreFoundation/CFStringEncodingConverter.h>
+# include <CoreFoundation/CFUnicodePrecomposition.h>
+# define USE_INTERNAL_API 1
+#elif defined(HAVE_CFSTRINGENCODINGCONVERTER_H)
+# include <CFStringEncodingConverter.h>
+# include <CFUnicodePrecomposition.h>
+# define USE_INTERNAL_API 1
+#endif
+
+/*
+ * Compile time configuration: Do we want debug output?
+ */
+/* #define DEBUG_STRINGS 1 */
+
+/*
+ * A simple, but efficient memory provider for our buffers.
+ */
+static inline void *resize_buffer (void *buffer, size_t *size, size_t newsize)
+{
+ if (newsize > *size) {
+ *size = newsize + 128;
+ buffer = realloc(buffer, *size);
+ }
+ return buffer;
+}
+
+/*
+ * While there is a version of OpenDarwin for intel, the usual case is
+ * big-endian PPC. So we need byte swapping to handle the
+ * little-endian byte order of the network protocol. We also need an
+ * additional dynamic buffer to do this work for incoming data blocks,
+ * because we have to consider the original data as constant.
+ *
+ * We abstract the differences away by providing a simple facade with
+ * these functions/macros:
+ *
+ * le_to_native(dst,src,len)
+ * native_to_le(cp,len)
+ * set_ucbuffer_with_le(buffer,bufsize,data,size)
+ * set_ucbuffer_with_le_copy(buffer,bufsize,data,size,reserve)
+ */
+#ifdef WORDS_BIGENDIAN
+
+static inline void swap_bytes (char * dst, const char * src, size_t len)
+{
+ const char *srcend = src + len;
+ while (src < srcend) {
+ dst[0] = src[1];
+ dst[1] = src[0];
+ dst += 2;
+ src += 2;
+ }
+}
+static inline void swap_bytes_inplace (char * cp, size_t len)
+{
+ char temp;
+ char *end = cp + len;
+ while (cp < end) {
+ temp = cp[1];
+ cp[1] = cp[0];
+ cp[0] = temp;
+ cp += 2;
+ }
+}
+
+#define le_to_native(dst,src,len) swap_bytes(dst,src,len)
+#define native_to_le(cp,len) swap_bytes_inplace(cp,len)
+#define set_ucbuffer_with_le(buffer,bufsize,data,size) \
+ set_ucbuffer_with_le_copy(buffer,bufsize,data,size,0)
+
+#else /* ! WORDS_BIGENDIAN */
+
+#define le_to_native(dst,src,len) memcpy(dst,src,len)
+#define native_to_le(cp,len) /* nothing */
+#define set_ucbuffer_with_le(buffer,bufsize,data,size) \
+ (((void)(bufsize)),(UniChar*)(data))
+
+#endif
+
+static inline UniChar *set_ucbuffer_with_le_copy (
+ UniChar *buffer, size_t *bufsize,
+ const void *data, size_t size, size_t reserve)
+{
+ buffer = resize_buffer(buffer, bufsize, size+reserve);
+ le_to_native((char*)buffer,data,size);
+ return buffer;
+}
+
+
+/*
+ * A simple hexdump function for debugging error conditions.
+ */
+#define debug_out(s) DEBUG(0,(s))
+
+#ifdef DEBUG_STRINGS
+
+static void hexdump( const char * label, const char * s, size_t len )
+{
+ size_t restlen = len;
+ debug_out("<<<<<<<\n");
+ debug_out(label);
+ debug_out("\n");
+ while (restlen > 0) {
+ char line[100];
+ size_t i, j;
+ char * d = line;
+#undef sprintf
+ d += sprintf(d, "%04X ", (unsigned)(len-restlen));
+ *d++ = ' ';
+ for( i = 0; i<restlen && i<8; ++i ) {
+ d += sprintf(d, "%02X ", ((unsigned)s[i]) & 0xFF);
+ }
+ for( j = i; j<8; ++j ) {
+ d += sprintf(d, " ");
+ }
+ *d++ = ' ';
+ for( i = 8; i<restlen && i<16; ++i ) {
+ d += sprintf(d, "%02X ", ((unsigned)s[i]) & 0xFF);
+ }
+ for( j = i; j<16; ++j ) {
+ d += sprintf(d, " ");
+ }
+ *d++ = ' ';
+ for( i = 0; i<restlen && i<16; ++i ) {
+ if(s[i] < ' ' || s[i] >= 0x7F || !isprint(s[i]))
+ *d++ = '.';
+ else
+ *d++ = s[i];
+ }
+ *d++ = '\n';
+ *d = 0;
+ restlen -= i;
+ s += i;
+ debug_out(line);
+ }
+ debug_out(">>>>>>>\n");
+}
+
+#else /* !DEBUG_STRINGS */
+
+#define hexdump(label,s,len) /* nothing */
+
+#endif
+
+
+#if !USE_INTERNAL_API
+
+/*
+ * An implementation based on documented Mac OS X APIs.
+ *
+ * This does a certain amount of memory management, creating and
+ * manipulating CFString objects. We try to minimize the impact by
+ * keeping those objects around and re-using them. We also use
+ * external backing store for the CFStrings where this is possible and
+ * benficial.
+ *
+ * The Unicode normalizations forms available at this level are
+ * generic, not specifically for the file system. So they may not be
+ * perfect fits.
+ */
+size_t macosxfs_encoding_pull(
+ void *cd, /* Encoder handle */
+ const char **inbuf, size_t *inbytesleft, /* Script string */
+ char **outbuf, size_t *outbytesleft) /* UTF-16-LE string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ static CFMutableStringRef cfstring = NULL;
+ size_t outsize;
+ CFRange range;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ if (NULL == cfstring) {
+ /*
+ * A version with an external backing store as in the
+ * push function should have been more efficient, but
+ * testing shows, that it is actually slower (!).
+ * Maybe kCFAllocatorDefault gets shortcut evaluation
+ * internally, while kCFAllocatorNull doesn't.
+ */
+ cfstring = CFStringCreateMutable(kCFAllocatorDefault,0);
+ }
+
+ /*
+ * Three methods of appending to a CFString, choose the most
+ * efficient.
+ */
+ if (0 == (*inbuf)[*inbytesleft-1]) {
+ CFStringAppendCString(cfstring, *inbuf, script_code);
+ } else if (*inbytesleft <= 255) {
+ Str255 buffer;
+ buffer[0] = *inbytesleft;
+ memcpy(buffer+1, *inbuf, buffer[0]);
+ CFStringAppendPascalString(cfstring, buffer, script_code);
+ } else {
+ /*
+ * We would like to use a fixed buffer and a loop
+ * here, but then we can't guarantee that the input is
+ * well-formed UTF-8, as we are supposed to do.
+ */
+ static char *buffer = NULL;
+ static size_t buflen = 0;
+ buffer = resize_buffer(buffer, &buflen, *inbytesleft+1);
+ memcpy(buffer, *inbuf, *inbytesleft);
+ buffer[*inbytesleft] = 0;
+ CFStringAppendCString(cfstring, *inbuf, script_code);
+ }
+
+ /*
+ * Compose characters, using the non-canonical composition
+ * form.
+ */
+ CFStringNormalize(cfstring, kCFStringNormalizationFormC);
+
+ outsize = CFStringGetLength(cfstring);
+ range = CFRangeMake(0,outsize);
+
+ if (outsize == 0) {
+ /*
+ * HACK: smbd/mangle_hash2.c:is_legal_name() expects
+ * errors here. That function will always pass 2
+ * characters. smbd/open.c:check_for_pipe() cuts a
+ * patchname to 10 characters blindly. Suppress the
+ * debug output in those cases.
+ */
+ if(2 != *inbytesleft && 10 != *inbytesleft) {
+ debug_out("String conversion: "
+ "An unknown error occurred\n");
+ hexdump("UTF8->UTF16LE (old) input",
+ *inbuf, *inbytesleft);
+ }
+ errno = EILSEQ; /* Not sure, but this is what we have
+ * actually seen. */
+ return -1;
+ }
+ if (outsize*2 > *outbytesleft) {
+ CFStringDelete(cfstring, range);
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF8->UTF16LE (old) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ }
+
+ CFStringGetCharacters(cfstring, range, (UniChar*)*outbuf);
+ CFStringDelete(cfstring, range);
+
+ native_to_le(*outbuf, outsize*2);
+
+ /*
+ * Add a converted null byte, if the CFString conversions
+ * prevented that until now.
+ */
+ if (0 == (*inbuf)[*inbytesleft-1] &&
+ (0 != (*outbuf)[outsize*2-1] || 0 != (*outbuf)[outsize*2-2])) {
+
+ if ((outsize*2+2) > *outbytesleft) {
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF8->UTF16LE (old) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ }
+
+ (*outbuf)[outsize*2] = (*outbuf)[outsize*2+1] = 0;
+ outsize += 2;
+ }
+
+ *inbuf += *inbytesleft;
+ *inbytesleft = 0;
+ *outbuf += outsize*2;
+ *outbytesleft -= outsize*2;
+
+ return 0;
+}
+
+size_t macosxfs_encoding_push(
+ void *cd, /* Encoder handle */
+ const char **inbuf, size_t *inbytesleft, /* UTF-16-LE string */
+ char **outbuf, size_t *outbytesleft) /* Script string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ static CFMutableStringRef cfstring = NULL;
+ static UniChar *buffer = NULL;
+ static size_t buflen = 0;
+ CFIndex outsize, cfsize, charsconverted;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ /*
+ * We need a buffer that can hold 4 times the original data,
+ * because that is the theoretical maximum that decomposition
+ * can create currently (in Unicode 4.0).
+ */
+ buffer = set_ucbuffer_with_le_copy(
+ buffer, &buflen, *inbuf, *inbytesleft, 3 * *inbytesleft);
+
+ if (NULL == cfstring) {
+ cfstring = CFStringCreateMutableWithExternalCharactersNoCopy(
+ kCFAllocatorDefault,
+ buffer, *inbytesleft/2, buflen/2,
+ kCFAllocatorNull);
+ } else {
+ CFStringSetExternalCharactersNoCopy(
+ cfstring,
+ buffer, *inbytesleft/2, buflen/2);
+ }
+
+ /*
+ * Decompose characters, using the non-canonical decomposition
+ * form.
+ *
+ * NB: This isn't exactly what HFS+ wants (see note on
+ * kCFStringEncodingUseHFSPlusCanonical in
+ * CFStringEncodingConverter.h), but AFAIK it's the best that
+ * the official API can do.
+ */
+ CFStringNormalize(cfstring, kCFStringNormalizationFormD);
+
+ cfsize = CFStringGetLength(cfstring);
+ charsconverted = CFStringGetBytes(
+ cfstring, CFRangeMake(0,cfsize),
+ script_code, 0, false,
+ *(UInt8 **)outbuf, *outbytesleft, &outsize);
+
+ if (0 == charsconverted) {
+ debug_out("String conversion: "
+ "Buffer too small or not convertible\n");
+ hexdump("UTF16LE->UTF8 (old) input",
+ *inbuf, *inbytesleft);
+ errno = EILSEQ; /* Probably more likely. */
+ return -1;
+ }
+
+ /*
+ * Add a converted null byte, if the CFString conversions
+ * prevented that until now.
+ */
+ if (0 == (*inbuf)[*inbytesleft-1] && 0 == (*inbuf)[*inbytesleft-2] &&
+ (0 != (*outbuf)[outsize-1])) {
+
+ if (((size_t)outsize+1) > *outbytesleft) {
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF16LE->UTF8 (old) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ }
+
+ (*outbuf)[outsize] = 0;
+ ++outsize;
+ }
+
+ *inbuf += *inbytesleft;
+ *inbytesleft = 0;
+ *outbuf += outsize;
+ *outbytesleft -= outsize;
+
+ return 0;
+}
+
+#else /* USE_INTERNAL_API */
+
+/*
+ * An implementation based on internal code as known from the
+ * OpenDarwin CVS.
+ *
+ * This code doesn't need much memory management because it uses
+ * functions that operate on the raw memory directly.
+ *
+ * The push routine here is faster and more compatible with HFS+ than
+ * the other implementation above. The pull routine is only faster
+ * for some strings, slightly slower for others. The pull routine
+ * looses because it has to iterate over the data twice, once to
+ * decode UTF-8 and than to do the character composition required by
+ * Windows.
+ */
+static size_t macosxfs_encoding_pull(
+ void *cd, /* Encoder handle */
+ const char **inbuf, size_t *inbytesleft, /* Script string */
+ char **outbuf, size_t *outbytesleft) /* UTF-16-LE string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ UInt32 srcCharsUsed = 0;
+ UInt32 dstCharsUsed = 0;
+ UInt32 result;
+ uint32_t dstDecomposedUsed = 0;
+ uint32_t dstPrecomposedUsed = 0;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ result = CFStringEncodingBytesToUnicode(
+ script_code, kCFStringEncodingComposeCombinings,
+ *inbuf, *inbytesleft, &srcCharsUsed,
+ (UniChar*)*outbuf, *outbytesleft, &dstCharsUsed);
+
+ switch(result) {
+ case kCFStringEncodingConversionSuccess:
+ if (*inbytesleft == srcCharsUsed) {
+ break;
+ }
+
+ FALL_THROUGH;
+ case kCFStringEncodingInsufficientOutputBufferLength:
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF8->UTF16LE (new) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ case kCFStringEncodingInvalidInputStream:
+ /*
+ * HACK: smbd/mangle_hash2.c:is_legal_name() expects
+ * errors here. That function will always pass 2
+ * characters. smbd/open.c:check_for_pipe() cuts a
+ * patchname to 10 characters blindly. Suppress the
+ * debug output in those cases.
+ */
+ if(2 != *inbytesleft && 10 != *inbytesleft) {
+ debug_out("String conversion: "
+ "Invalid input sequence\n");
+ hexdump("UTF8->UTF16LE (new) input",
+ *inbuf, *inbytesleft);
+ }
+ errno = EILSEQ;
+ return -1;
+ case kCFStringEncodingConverterUnavailable:
+ debug_out("String conversion: "
+ "Unknown encoding\n");
+ hexdump("UTF8->UTF16LE (new) input",
+ *inbuf, *inbytesleft);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * It doesn't look like CFStringEncodingBytesToUnicode() can
+ * produce precomposed characters (flags=ComposeCombinings
+ * doesn't do it), so we need another pass over the data here.
+ * We can do this in-place, as the string can only get
+ * shorter.
+ *
+ * (Actually in theory there should be an internal
+ * decomposition and reordering before the actual composition
+ * step. But we should be able to rely on that we always get
+ * fully decomposed strings for input, so this can't create
+ * problems in reality.)
+ */
+ CFUniCharPrecompose(
+ (const UTF16Char *)*outbuf, dstCharsUsed, &dstDecomposedUsed,
+ (UTF16Char *)*outbuf, dstCharsUsed, &dstPrecomposedUsed);
+
+ native_to_le(*outbuf, dstPrecomposedUsed*2);
+
+ *inbuf += srcCharsUsed;
+ *inbytesleft -= srcCharsUsed;
+ *outbuf += dstPrecomposedUsed*2;
+ *outbytesleft -= dstPrecomposedUsed*2;
+
+ return 0;
+}
+
+static size_t macosxfs_encoding_push(
+ void *cd, /* Encoder handle */
+ const char **inbuf, size_t *inbytesleft, /* UTF-16-LE string */
+ char **outbuf, size_t *outbytesleft) /* Script string */
+{
+ static const int script_code = kCFStringEncodingUTF8;
+ static UniChar *buffer = NULL;
+ static size_t buflen = 0;
+ UInt32 srcCharsUsed=0, dstCharsUsed=0, result;
+
+ (void) cd; /* UNUSED */
+
+ if (0 == *inbytesleft) {
+ return 0;
+ }
+
+ buffer = set_ucbuffer_with_le(
+ buffer, &buflen, *inbuf, *inbytesleft);
+
+ result = CFStringEncodingUnicodeToBytes(
+ script_code, kCFStringEncodingUseHFSPlusCanonical,
+ buffer, *inbytesleft/2, &srcCharsUsed,
+ *outbuf, *outbytesleft, &dstCharsUsed);
+
+ switch(result) {
+ case kCFStringEncodingConversionSuccess:
+ if (*inbytesleft/2 == srcCharsUsed) {
+ break;
+ }
+
+ FALL_THROUGH;
+ case kCFStringEncodingInsufficientOutputBufferLength:
+ debug_out("String conversion: "
+ "Output buffer too small\n");
+ hexdump("UTF16LE->UTF8 (new) input",
+ *inbuf, *inbytesleft);
+ errno = E2BIG;
+ return -1;
+ case kCFStringEncodingInvalidInputStream:
+ /*
+ * HACK: smbd/open.c:check_for_pipe():is_legal_name()
+ * cuts a pathname to 10 characters blindly. Suppress
+ * the debug output in those cases.
+ */
+ if(10 != *inbytesleft) {
+ debug_out("String conversion: "
+ "Invalid input sequence\n");
+ hexdump("UTF16LE->UTF8 (new) input",
+ *inbuf, *inbytesleft);
+ }
+ errno = EILSEQ;
+ return -1;
+ case kCFStringEncodingConverterUnavailable:
+ debug_out("String conversion: "
+ "Unknown encoding\n");
+ hexdump("UTF16LE->UTF8 (new) input",
+ *inbuf, *inbytesleft);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *inbuf += srcCharsUsed*2;
+ *inbytesleft -= srcCharsUsed*2;
+ *outbuf += dstCharsUsed;
+ *outbytesleft -= dstCharsUsed;
+
+ return 0;
+}
+
+#endif /* USE_INTERNAL_API */
+
+#else /* DARWIN */
+
+void charset_macosfs_dummy(void);
+void charset_macosfs_dummy(void)
+{
+ return;
+}
+
+#endif /* DARWIN */
diff --git a/lib/util/charset/charset_proto.h b/lib/util/charset/charset_proto.h
new file mode 100644
index 0000000..6da7118
--- /dev/null
+++ b/lib/util/charset/charset_proto.h
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba charset modules
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) Benjamin Riefenstahl 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+size_t weird_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+size_t weird_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+
+size_t macosxfs_encoding_pull(
+ void *cd, /* Encoder handle */
+ const char **inbuf, size_t *inbytesleft, /* Script string */
+ char **outbuf, size_t *outbytesleft); /* UTF-16-LE string */
+size_t macosxfs_encoding_push(
+ void *cd, /* Encoder handle */
+ const char **inbuf, size_t *inbytesleft, /* UTF-16-LE string */
+ char **outbuf, size_t *outbytesleft); /* Script string */
+
+
diff --git a/lib/util/charset/codepoints.c b/lib/util/charset/codepoints.c
new file mode 100644
index 0000000..ea2c4be
--- /dev/null
+++ b/lib/util/charset/codepoints.c
@@ -0,0 +1,16850 @@
+/*
+ Unix SMB/CIFS implementation.
+ Character set conversion Extensions
+ Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "replace.h"
+#include "lib/util/charset/charset.h"
+#include "system/locale.h"
+#include "dynconfig/dynconfig.h"
+#include "lib/util/debug.h"
+#include "lib/util/byteorder.h"
+
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
+
+/**
+ * @file
+ * @brief Unicode string manipulation
+ */
+
+static const uint16_t lowcase_table[] = {
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+ 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
+ 0x0040,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007a,0x005b,0x005c,0x005d,0x005e,0x005f,
+ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,
+ 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+ 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+ 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+ 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+ 0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+ 0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+ 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+ 0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+ 0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
+ 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+ 0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00d7,
+ 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00df,
+ 0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
+ 0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+ 0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
+ 0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff,
+ 0x0101,0x0101,0x0103,0x0103,0x0105,0x0105,0x0107,0x0107,
+ 0x0109,0x0109,0x010b,0x010b,0x010d,0x010d,0x010f,0x010f,
+ 0x0111,0x0111,0x0113,0x0113,0x0115,0x0115,0x0117,0x0117,
+ 0x0119,0x0119,0x011b,0x011b,0x011d,0x011d,0x011f,0x011f,
+ 0x0121,0x0121,0x0123,0x0123,0x0125,0x0125,0x0127,0x0127,
+ 0x0129,0x0129,0x012b,0x012b,0x012d,0x012d,0x012f,0x012f,
+ 0x0130,0x0131,0x0133,0x0133,0x0135,0x0135,0x0137,0x0137,
+ 0x0138,0x013a,0x013a,0x013c,0x013c,0x013e,0x013e,0x0140,
+ 0x0140,0x0142,0x0142,0x0144,0x0144,0x0146,0x0146,0x0148,
+ 0x0148,0x0149,0x014b,0x014b,0x014d,0x014d,0x014f,0x014f,
+ 0x0151,0x0151,0x0153,0x0153,0x0155,0x0155,0x0157,0x0157,
+ 0x0159,0x0159,0x015b,0x015b,0x015d,0x015d,0x015f,0x015f,
+ 0x0161,0x0161,0x0163,0x0163,0x0165,0x0165,0x0167,0x0167,
+ 0x0169,0x0169,0x016b,0x016b,0x016d,0x016d,0x016f,0x016f,
+ 0x0171,0x0171,0x0173,0x0173,0x0175,0x0175,0x0177,0x0177,
+ 0x00ff,0x017a,0x017a,0x017c,0x017c,0x017e,0x017e,0x017f,
+ 0x0180,0x0253,0x0183,0x0183,0x0185,0x0185,0x0254,0x0188,
+ 0x0188,0x0256,0x0257,0x018c,0x018c,0x018d,0x01dd,0x0259,
+ 0x025b,0x0192,0x0192,0x0260,0x0263,0x0195,0x0269,0x0268,
+ 0x0199,0x0199,0x019a,0x019b,0x026f,0x0272,0x019e,0x0275,
+ 0x01a1,0x01a1,0x01a3,0x01a3,0x01a5,0x01a5,0x01a6,0x01a8,
+ 0x01a8,0x0283,0x01aa,0x01ab,0x01ad,0x01ad,0x0288,0x01b0,
+ 0x01b0,0x028a,0x028b,0x01b4,0x01b4,0x01b6,0x01b6,0x0292,
+ 0x01b9,0x01b9,0x01ba,0x01bb,0x01bd,0x01bd,0x01be,0x01bf,
+ 0x01c0,0x01c1,0x01c2,0x01c3,0x01c6,0x01c5,0x01c6,0x01c9,
+ 0x01c8,0x01c9,0x01cc,0x01cb,0x01cc,0x01ce,0x01ce,0x01d0,
+ 0x01d0,0x01d2,0x01d2,0x01d4,0x01d4,0x01d6,0x01d6,0x01d8,
+ 0x01d8,0x01da,0x01da,0x01dc,0x01dc,0x01dd,0x01df,0x01df,
+ 0x01e1,0x01e1,0x01e3,0x01e3,0x01e5,0x01e5,0x01e7,0x01e7,
+ 0x01e9,0x01e9,0x01eb,0x01eb,0x01ed,0x01ed,0x01ef,0x01ef,
+ 0x01f0,0x01f3,0x01f2,0x01f3,0x01f5,0x01f5,0x01f6,0x01f7,
+ 0x01f8,0x01f9,0x01fb,0x01fb,0x01fd,0x01fd,0x01ff,0x01ff,
+ 0x0201,0x0201,0x0203,0x0203,0x0205,0x0205,0x0207,0x0207,
+ 0x0209,0x0209,0x020b,0x020b,0x020d,0x020d,0x020f,0x020f,
+ 0x0211,0x0211,0x0213,0x0213,0x0215,0x0215,0x0217,0x0217,
+ 0x0218,0x0219,0x021a,0x021b,0x021c,0x021d,0x021e,0x021f,
+ 0x0220,0x0221,0x0222,0x0223,0x0224,0x0225,0x0226,0x0227,
+ 0x0228,0x0229,0x022a,0x022b,0x022c,0x022d,0x022e,0x022f,
+ 0x0230,0x0231,0x0232,0x0233,0x0234,0x0235,0x0236,0x0237,
+ 0x0238,0x0239,0x023a,0x023b,0x023c,0x023d,0x023e,0x023f,
+ 0x0240,0x0241,0x0242,0x0243,0x0244,0x0245,0x0246,0x0247,
+ 0x0248,0x0249,0x024a,0x024b,0x024c,0x024d,0x024e,0x024f,
+ 0x0250,0x0251,0x0252,0x0253,0x0254,0x0255,0x0256,0x0257,
+ 0x0258,0x0259,0x025a,0x025b,0x025c,0x025d,0x025e,0x025f,
+ 0x0260,0x0261,0x0262,0x0263,0x0264,0x0265,0x0266,0x0267,
+ 0x0268,0x0269,0x026a,0x026b,0x026c,0x026d,0x026e,0x026f,
+ 0x0270,0x0271,0x0272,0x0273,0x0274,0x0275,0x0276,0x0277,
+ 0x0278,0x0279,0x027a,0x027b,0x027c,0x027d,0x027e,0x027f,
+ 0x0280,0x0281,0x0282,0x0283,0x0284,0x0285,0x0286,0x0287,
+ 0x0288,0x0289,0x028a,0x028b,0x028c,0x028d,0x028e,0x028f,
+ 0x0290,0x0291,0x0292,0x0293,0x0294,0x0295,0x0296,0x0297,
+ 0x0298,0x0299,0x029a,0x029b,0x029c,0x029d,0x029e,0x029f,
+ 0x02a0,0x02a1,0x02a2,0x02a3,0x02a4,0x02a5,0x02a6,0x02a7,
+ 0x02a8,0x02a9,0x02aa,0x02ab,0x02ac,0x02ad,0x02ae,0x02af,
+ 0x02b0,0x02b1,0x02b2,0x02b3,0x02b4,0x02b5,0x02b6,0x02b7,
+ 0x02b8,0x02b9,0x02ba,0x02bb,0x02bc,0x02bd,0x02be,0x02bf,
+ 0x02c0,0x02c1,0x02c2,0x02c3,0x02c4,0x02c5,0x02c6,0x02c7,
+ 0x02c8,0x02c9,0x02ca,0x02cb,0x02cc,0x02cd,0x02ce,0x02cf,
+ 0x02d0,0x02d1,0x02d2,0x02d3,0x02d4,0x02d5,0x02d6,0x02d7,
+ 0x02d8,0x02d9,0x02da,0x02db,0x02dc,0x02dd,0x02de,0x02df,
+ 0x02e0,0x02e1,0x02e2,0x02e3,0x02e4,0x02e5,0x02e6,0x02e7,
+ 0x02e8,0x02e9,0x02ea,0x02eb,0x02ec,0x02ed,0x02ee,0x02ef,
+ 0x02f0,0x02f1,0x02f2,0x02f3,0x02f4,0x02f5,0x02f6,0x02f7,
+ 0x02f8,0x02f9,0x02fa,0x02fb,0x02fc,0x02fd,0x02fe,0x02ff,
+ 0x0300,0x0301,0x0302,0x0303,0x0304,0x0305,0x0306,0x0307,
+ 0x0308,0x0309,0x030a,0x030b,0x030c,0x030d,0x030e,0x030f,
+ 0x0310,0x0311,0x0312,0x0313,0x0314,0x0315,0x0316,0x0317,
+ 0x0318,0x0319,0x031a,0x031b,0x031c,0x031d,0x031e,0x031f,
+ 0x0320,0x0321,0x0322,0x0323,0x0324,0x0325,0x0326,0x0327,
+ 0x0328,0x0329,0x032a,0x032b,0x032c,0x032d,0x032e,0x032f,
+ 0x0330,0x0331,0x0332,0x0333,0x0334,0x0335,0x0336,0x0337,
+ 0x0338,0x0339,0x033a,0x033b,0x033c,0x033d,0x033e,0x033f,
+ 0x0340,0x0341,0x0342,0x0343,0x0344,0x0345,0x0346,0x0347,
+ 0x0348,0x0349,0x034a,0x034b,0x034c,0x034d,0x034e,0x034f,
+ 0x0350,0x0351,0x0352,0x0353,0x0354,0x0355,0x0356,0x0357,
+ 0x0358,0x0359,0x035a,0x035b,0x035c,0x035d,0x035e,0x035f,
+ 0x0360,0x0361,0x0362,0x0363,0x0364,0x0365,0x0366,0x0367,
+ 0x0368,0x0369,0x036a,0x036b,0x036c,0x036d,0x036e,0x036f,
+ 0x0370,0x0371,0x0372,0x0373,0x0374,0x0375,0x0376,0x0377,
+ 0x0378,0x0379,0x037a,0x037b,0x037c,0x037d,0x037e,0x037f,
+ 0x0380,0x0381,0x0382,0x0383,0x0384,0x0385,0x03ac,0x0387,
+ 0x03ad,0x03ae,0x03af,0x038b,0x03cc,0x038d,0x03cd,0x03ce,
+ 0x0390,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
+ 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
+ 0x03c0,0x03c1,0x03a2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
+ 0x03c8,0x03c9,0x03ca,0x03cb,0x03ac,0x03ad,0x03ae,0x03af,
+ 0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
+ 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
+ 0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
+ 0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,0x03cf,
+ 0x03d0,0x03d1,0x03d2,0x03d3,0x03d4,0x03d5,0x03d6,0x03d7,
+ 0x03d8,0x03d9,0x03da,0x03db,0x03dc,0x03dd,0x03de,0x03df,
+ 0x03e0,0x03e1,0x03e3,0x03e3,0x03e5,0x03e5,0x03e7,0x03e7,
+ 0x03e9,0x03e9,0x03eb,0x03eb,0x03ed,0x03ed,0x03ef,0x03ef,
+ 0x03f0,0x03f1,0x03f2,0x03f3,0x03f4,0x03f5,0x03f6,0x03f7,
+ 0x03f8,0x03f9,0x03fa,0x03fb,0x03fc,0x03fd,0x03fe,0x03ff,
+ 0x0400,0x0451,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,
+ 0x0458,0x0459,0x045a,0x045b,0x045c,0x040d,0x045e,0x045f,
+ 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
+ 0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
+ 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
+ 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
+ 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
+ 0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
+ 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
+ 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
+ 0x0450,0x0451,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,
+ 0x0458,0x0459,0x045a,0x045b,0x045c,0x045d,0x045e,0x045f,
+ 0x0461,0x0461,0x0463,0x0463,0x0465,0x0465,0x0467,0x0467,
+ 0x0469,0x0469,0x046b,0x046b,0x046d,0x046d,0x046f,0x046f,
+ 0x0471,0x0471,0x0473,0x0473,0x0475,0x0475,0x0477,0x0477,
+ 0x0479,0x0479,0x047b,0x047b,0x047d,0x047d,0x047f,0x047f,
+ 0x0481,0x0481,0x0482,0x0483,0x0484,0x0485,0x0486,0x0487,
+ 0x0488,0x0489,0x048a,0x048b,0x048c,0x048d,0x048e,0x048f,
+ 0x0491,0x0491,0x0493,0x0493,0x0495,0x0495,0x0497,0x0497,
+ 0x0499,0x0499,0x049b,0x049b,0x049d,0x049d,0x049f,0x049f,
+ 0x04a1,0x04a1,0x04a3,0x04a3,0x04a5,0x04a5,0x04a7,0x04a7,
+ 0x04a9,0x04a9,0x04ab,0x04ab,0x04ad,0x04ad,0x04af,0x04af,
+ 0x04b1,0x04b1,0x04b3,0x04b3,0x04b5,0x04b5,0x04b7,0x04b7,
+ 0x04b9,0x04b9,0x04bb,0x04bb,0x04bd,0x04bd,0x04bf,0x04bf,
+ 0x04c0,0x04c2,0x04c2,0x04c4,0x04c4,0x04c5,0x04c6,0x04c8,
+ 0x04c8,0x04c9,0x04ca,0x04cc,0x04cc,0x04cd,0x04ce,0x04cf,
+ 0x04d1,0x04d1,0x04d3,0x04d3,0x04d5,0x04d5,0x04d7,0x04d7,
+ 0x04d9,0x04d9,0x04db,0x04db,0x04dd,0x04dd,0x04df,0x04df,
+ 0x04e1,0x04e1,0x04e3,0x04e3,0x04e5,0x04e5,0x04e7,0x04e7,
+ 0x04e9,0x04e9,0x04eb,0x04eb,0x04ec,0x04ed,0x04ef,0x04ef,
+ 0x04f1,0x04f1,0x04f3,0x04f3,0x04f5,0x04f5,0x04f6,0x04f7,
+ 0x04f9,0x04f9,0x04fa,0x04fb,0x04fc,0x04fd,0x04fe,0x04ff,
+ 0x0500,0x0501,0x0502,0x0503,0x0504,0x0505,0x0506,0x0507,
+ 0x0508,0x0509,0x050a,0x050b,0x050c,0x050d,0x050e,0x050f,
+ 0x0510,0x0511,0x0512,0x0513,0x0514,0x0515,0x0516,0x0517,
+ 0x0518,0x0519,0x051a,0x051b,0x051c,0x051d,0x051e,0x051f,
+ 0x0520,0x0521,0x0522,0x0523,0x0524,0x0525,0x0526,0x0527,
+ 0x0528,0x0529,0x052a,0x052b,0x052c,0x052d,0x052e,0x052f,
+ 0x0530,0x0561,0x0562,0x0563,0x0564,0x0565,0x0566,0x0567,
+ 0x0568,0x0569,0x056a,0x056b,0x056c,0x056d,0x056e,0x056f,
+ 0x0570,0x0571,0x0572,0x0573,0x0574,0x0575,0x0576,0x0577,
+ 0x0578,0x0579,0x057a,0x057b,0x057c,0x057d,0x057e,0x057f,
+ 0x0580,0x0581,0x0582,0x0583,0x0584,0x0585,0x0586,0x0557,
+ 0x0558,0x0559,0x055a,0x055b,0x055c,0x055d,0x055e,0x055f,
+ 0x0560,0x0561,0x0562,0x0563,0x0564,0x0565,0x0566,0x0567,
+ 0x0568,0x0569,0x056a,0x056b,0x056c,0x056d,0x056e,0x056f,
+ 0x0570,0x0571,0x0572,0x0573,0x0574,0x0575,0x0576,0x0577,
+ 0x0578,0x0579,0x057a,0x057b,0x057c,0x057d,0x057e,0x057f,
+ 0x0580,0x0581,0x0582,0x0583,0x0584,0x0585,0x0586,0x0587,
+ 0x0588,0x0589,0x058a,0x058b,0x058c,0x058d,0x058e,0x058f,
+ 0x0590,0x0591,0x0592,0x0593,0x0594,0x0595,0x0596,0x0597,
+ 0x0598,0x0599,0x059a,0x059b,0x059c,0x059d,0x059e,0x059f,
+ 0x05a0,0x05a1,0x05a2,0x05a3,0x05a4,0x05a5,0x05a6,0x05a7,
+ 0x05a8,0x05a9,0x05aa,0x05ab,0x05ac,0x05ad,0x05ae,0x05af,
+ 0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,
+ 0x05b8,0x05b9,0x05ba,0x05bb,0x05bc,0x05bd,0x05be,0x05bf,
+ 0x05c0,0x05c1,0x05c2,0x05c3,0x05c4,0x05c5,0x05c6,0x05c7,
+ 0x05c8,0x05c9,0x05ca,0x05cb,0x05cc,0x05cd,0x05ce,0x05cf,
+ 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
+ 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
+ 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
+ 0x05e8,0x05e9,0x05ea,0x05eb,0x05ec,0x05ed,0x05ee,0x05ef,
+ 0x05f0,0x05f1,0x05f2,0x05f3,0x05f4,0x05f5,0x05f6,0x05f7,
+ 0x05f8,0x05f9,0x05fa,0x05fb,0x05fc,0x05fd,0x05fe,0x05ff,
+ 0x0600,0x0601,0x0602,0x0603,0x0604,0x0605,0x0606,0x0607,
+ 0x0608,0x0609,0x060a,0x060b,0x060c,0x060d,0x060e,0x060f,
+ 0x0610,0x0611,0x0612,0x0613,0x0614,0x0615,0x0616,0x0617,
+ 0x0618,0x0619,0x061a,0x061b,0x061c,0x061d,0x061e,0x061f,
+ 0x0620,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
+ 0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
+ 0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637,
+ 0x0638,0x0639,0x063a,0x063b,0x063c,0x063d,0x063e,0x063f,
+ 0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647,
+ 0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f,
+ 0x0650,0x0651,0x0652,0x0653,0x0654,0x0655,0x0656,0x0657,
+ 0x0658,0x0659,0x065a,0x065b,0x065c,0x065d,0x065e,0x065f,
+ 0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,
+ 0x0668,0x0669,0x066a,0x066b,0x066c,0x066d,0x066e,0x066f,
+ 0x0670,0x0671,0x0672,0x0673,0x0674,0x0675,0x0676,0x0677,
+ 0x0678,0x0679,0x067a,0x067b,0x067c,0x067d,0x067e,0x067f,
+ 0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0686,0x0687,
+ 0x0688,0x0689,0x068a,0x068b,0x068c,0x068d,0x068e,0x068f,
+ 0x0690,0x0691,0x0692,0x0693,0x0694,0x0695,0x0696,0x0697,
+ 0x0698,0x0699,0x069a,0x069b,0x069c,0x069d,0x069e,0x069f,
+ 0x06a0,0x06a1,0x06a2,0x06a3,0x06a4,0x06a5,0x06a6,0x06a7,
+ 0x06a8,0x06a9,0x06aa,0x06ab,0x06ac,0x06ad,0x06ae,0x06af,
+ 0x06b0,0x06b1,0x06b2,0x06b3,0x06b4,0x06b5,0x06b6,0x06b7,
+ 0x06b8,0x06b9,0x06ba,0x06bb,0x06bc,0x06bd,0x06be,0x06bf,
+ 0x06c0,0x06c1,0x06c2,0x06c3,0x06c4,0x06c5,0x06c6,0x06c7,
+ 0x06c8,0x06c9,0x06ca,0x06cb,0x06cc,0x06cd,0x06ce,0x06cf,
+ 0x06d0,0x06d1,0x06d2,0x06d3,0x06d4,0x06d5,0x06d6,0x06d7,
+ 0x06d8,0x06d9,0x06da,0x06db,0x06dc,0x06dd,0x06de,0x06df,
+ 0x06e0,0x06e1,0x06e2,0x06e3,0x06e4,0x06e5,0x06e6,0x06e7,
+ 0x06e8,0x06e9,0x06ea,0x06eb,0x06ec,0x06ed,0x06ee,0x06ef,
+ 0x06f0,0x06f1,0x06f2,0x06f3,0x06f4,0x06f5,0x06f6,0x06f7,
+ 0x06f8,0x06f9,0x06fa,0x06fb,0x06fc,0x06fd,0x06fe,0x06ff,
+ 0x0700,0x0701,0x0702,0x0703,0x0704,0x0705,0x0706,0x0707,
+ 0x0708,0x0709,0x070a,0x070b,0x070c,0x070d,0x070e,0x070f,
+ 0x0710,0x0711,0x0712,0x0713,0x0714,0x0715,0x0716,0x0717,
+ 0x0718,0x0719,0x071a,0x071b,0x071c,0x071d,0x071e,0x071f,
+ 0x0720,0x0721,0x0722,0x0723,0x0724,0x0725,0x0726,0x0727,
+ 0x0728,0x0729,0x072a,0x072b,0x072c,0x072d,0x072e,0x072f,
+ 0x0730,0x0731,0x0732,0x0733,0x0734,0x0735,0x0736,0x0737,
+ 0x0738,0x0739,0x073a,0x073b,0x073c,0x073d,0x073e,0x073f,
+ 0x0740,0x0741,0x0742,0x0743,0x0744,0x0745,0x0746,0x0747,
+ 0x0748,0x0749,0x074a,0x074b,0x074c,0x074d,0x074e,0x074f,
+ 0x0750,0x0751,0x0752,0x0753,0x0754,0x0755,0x0756,0x0757,
+ 0x0758,0x0759,0x075a,0x075b,0x075c,0x075d,0x075e,0x075f,
+ 0x0760,0x0761,0x0762,0x0763,0x0764,0x0765,0x0766,0x0767,
+ 0x0768,0x0769,0x076a,0x076b,0x076c,0x076d,0x076e,0x076f,
+ 0x0770,0x0771,0x0772,0x0773,0x0774,0x0775,0x0776,0x0777,
+ 0x0778,0x0779,0x077a,0x077b,0x077c,0x077d,0x077e,0x077f,
+ 0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0786,0x0787,
+ 0x0788,0x0789,0x078a,0x078b,0x078c,0x078d,0x078e,0x078f,
+ 0x0790,0x0791,0x0792,0x0793,0x0794,0x0795,0x0796,0x0797,
+ 0x0798,0x0799,0x079a,0x079b,0x079c,0x079d,0x079e,0x079f,
+ 0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a6,0x07a7,
+ 0x07a8,0x07a9,0x07aa,0x07ab,0x07ac,0x07ad,0x07ae,0x07af,
+ 0x07b0,0x07b1,0x07b2,0x07b3,0x07b4,0x07b5,0x07b6,0x07b7,
+ 0x07b8,0x07b9,0x07ba,0x07bb,0x07bc,0x07bd,0x07be,0x07bf,
+ 0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7,
+ 0x07c8,0x07c9,0x07ca,0x07cb,0x07cc,0x07cd,0x07ce,0x07cf,
+ 0x07d0,0x07d1,0x07d2,0x07d3,0x07d4,0x07d5,0x07d6,0x07d7,
+ 0x07d8,0x07d9,0x07da,0x07db,0x07dc,0x07dd,0x07de,0x07df,
+ 0x07e0,0x07e1,0x07e2,0x07e3,0x07e4,0x07e5,0x07e6,0x07e7,
+ 0x07e8,0x07e9,0x07ea,0x07eb,0x07ec,0x07ed,0x07ee,0x07ef,
+ 0x07f0,0x07f1,0x07f2,0x07f3,0x07f4,0x07f5,0x07f6,0x07f7,
+ 0x07f8,0x07f9,0x07fa,0x07fb,0x07fc,0x07fd,0x07fe,0x07ff,
+ 0x0800,0x0801,0x0802,0x0803,0x0804,0x0805,0x0806,0x0807,
+ 0x0808,0x0809,0x080a,0x080b,0x080c,0x080d,0x080e,0x080f,
+ 0x0810,0x0811,0x0812,0x0813,0x0814,0x0815,0x0816,0x0817,
+ 0x0818,0x0819,0x081a,0x081b,0x081c,0x081d,0x081e,0x081f,
+ 0x0820,0x0821,0x0822,0x0823,0x0824,0x0825,0x0826,0x0827,
+ 0x0828,0x0829,0x082a,0x082b,0x082c,0x082d,0x082e,0x082f,
+ 0x0830,0x0831,0x0832,0x0833,0x0834,0x0835,0x0836,0x0837,
+ 0x0838,0x0839,0x083a,0x083b,0x083c,0x083d,0x083e,0x083f,
+ 0x0840,0x0841,0x0842,0x0843,0x0844,0x0845,0x0846,0x0847,
+ 0x0848,0x0849,0x084a,0x084b,0x084c,0x084d,0x084e,0x084f,
+ 0x0850,0x0851,0x0852,0x0853,0x0854,0x0855,0x0856,0x0857,
+ 0x0858,0x0859,0x085a,0x085b,0x085c,0x085d,0x085e,0x085f,
+ 0x0860,0x0861,0x0862,0x0863,0x0864,0x0865,0x0866,0x0867,
+ 0x0868,0x0869,0x086a,0x086b,0x086c,0x086d,0x086e,0x086f,
+ 0x0870,0x0871,0x0872,0x0873,0x0874,0x0875,0x0876,0x0877,
+ 0x0878,0x0879,0x087a,0x087b,0x087c,0x087d,0x087e,0x087f,
+ 0x0880,0x0881,0x0882,0x0883,0x0884,0x0885,0x0886,0x0887,
+ 0x0888,0x0889,0x088a,0x088b,0x088c,0x088d,0x088e,0x088f,
+ 0x0890,0x0891,0x0892,0x0893,0x0894,0x0895,0x0896,0x0897,
+ 0x0898,0x0899,0x089a,0x089b,0x089c,0x089d,0x089e,0x089f,
+ 0x08a0,0x08a1,0x08a2,0x08a3,0x08a4,0x08a5,0x08a6,0x08a7,
+ 0x08a8,0x08a9,0x08aa,0x08ab,0x08ac,0x08ad,0x08ae,0x08af,
+ 0x08b0,0x08b1,0x08b2,0x08b3,0x08b4,0x08b5,0x08b6,0x08b7,
+ 0x08b8,0x08b9,0x08ba,0x08bb,0x08bc,0x08bd,0x08be,0x08bf,
+ 0x08c0,0x08c1,0x08c2,0x08c3,0x08c4,0x08c5,0x08c6,0x08c7,
+ 0x08c8,0x08c9,0x08ca,0x08cb,0x08cc,0x08cd,0x08ce,0x08cf,
+ 0x08d0,0x08d1,0x08d2,0x08d3,0x08d4,0x08d5,0x08d6,0x08d7,
+ 0x08d8,0x08d9,0x08da,0x08db,0x08dc,0x08dd,0x08de,0x08df,
+ 0x08e0,0x08e1,0x08e2,0x08e3,0x08e4,0x08e5,0x08e6,0x08e7,
+ 0x08e8,0x08e9,0x08ea,0x08eb,0x08ec,0x08ed,0x08ee,0x08ef,
+ 0x08f0,0x08f1,0x08f2,0x08f3,0x08f4,0x08f5,0x08f6,0x08f7,
+ 0x08f8,0x08f9,0x08fa,0x08fb,0x08fc,0x08fd,0x08fe,0x08ff,
+ 0x0900,0x0901,0x0902,0x0903,0x0904,0x0905,0x0906,0x0907,
+ 0x0908,0x0909,0x090a,0x090b,0x090c,0x090d,0x090e,0x090f,
+ 0x0910,0x0911,0x0912,0x0913,0x0914,0x0915,0x0916,0x0917,
+ 0x0918,0x0919,0x091a,0x091b,0x091c,0x091d,0x091e,0x091f,
+ 0x0920,0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927,
+ 0x0928,0x0929,0x092a,0x092b,0x092c,0x092d,0x092e,0x092f,
+ 0x0930,0x0931,0x0932,0x0933,0x0934,0x0935,0x0936,0x0937,
+ 0x0938,0x0939,0x093a,0x093b,0x093c,0x093d,0x093e,0x093f,
+ 0x0940,0x0941,0x0942,0x0943,0x0944,0x0945,0x0946,0x0947,
+ 0x0948,0x0949,0x094a,0x094b,0x094c,0x094d,0x094e,0x094f,
+ 0x0950,0x0951,0x0952,0x0953,0x0954,0x0955,0x0956,0x0957,
+ 0x0958,0x0959,0x095a,0x095b,0x095c,0x095d,0x095e,0x095f,
+ 0x0960,0x0961,0x0962,0x0963,0x0964,0x0965,0x0966,0x0967,
+ 0x0968,0x0969,0x096a,0x096b,0x096c,0x096d,0x096e,0x096f,
+ 0x0970,0x0971,0x0972,0x0973,0x0974,0x0975,0x0976,0x0977,
+ 0x0978,0x0979,0x097a,0x097b,0x097c,0x097d,0x097e,0x097f,
+ 0x0980,0x0981,0x0982,0x0983,0x0984,0x0985,0x0986,0x0987,
+ 0x0988,0x0989,0x098a,0x098b,0x098c,0x098d,0x098e,0x098f,
+ 0x0990,0x0991,0x0992,0x0993,0x0994,0x0995,0x0996,0x0997,
+ 0x0998,0x0999,0x099a,0x099b,0x099c,0x099d,0x099e,0x099f,
+ 0x09a0,0x09a1,0x09a2,0x09a3,0x09a4,0x09a5,0x09a6,0x09a7,
+ 0x09a8,0x09a9,0x09aa,0x09ab,0x09ac,0x09ad,0x09ae,0x09af,
+ 0x09b0,0x09b1,0x09b2,0x09b3,0x09b4,0x09b5,0x09b6,0x09b7,
+ 0x09b8,0x09b9,0x09ba,0x09bb,0x09bc,0x09bd,0x09be,0x09bf,
+ 0x09c0,0x09c1,0x09c2,0x09c3,0x09c4,0x09c5,0x09c6,0x09c7,
+ 0x09c8,0x09c9,0x09ca,0x09cb,0x09cc,0x09cd,0x09ce,0x09cf,
+ 0x09d0,0x09d1,0x09d2,0x09d3,0x09d4,0x09d5,0x09d6,0x09d7,
+ 0x09d8,0x09d9,0x09da,0x09db,0x09dc,0x09dd,0x09de,0x09df,
+ 0x09e0,0x09e1,0x09e2,0x09e3,0x09e4,0x09e5,0x09e6,0x09e7,
+ 0x09e8,0x09e9,0x09ea,0x09eb,0x09ec,0x09ed,0x09ee,0x09ef,
+ 0x09f0,0x09f1,0x09f2,0x09f3,0x09f4,0x09f5,0x09f6,0x09f7,
+ 0x09f8,0x09f9,0x09fa,0x09fb,0x09fc,0x09fd,0x09fe,0x09ff,
+ 0x0a00,0x0a01,0x0a02,0x0a03,0x0a04,0x0a05,0x0a06,0x0a07,
+ 0x0a08,0x0a09,0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f,
+ 0x0a10,0x0a11,0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17,
+ 0x0a18,0x0a19,0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f,
+ 0x0a20,0x0a21,0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27,
+ 0x0a28,0x0a29,0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f,
+ 0x0a30,0x0a31,0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37,
+ 0x0a38,0x0a39,0x0a3a,0x0a3b,0x0a3c,0x0a3d,0x0a3e,0x0a3f,
+ 0x0a40,0x0a41,0x0a42,0x0a43,0x0a44,0x0a45,0x0a46,0x0a47,
+ 0x0a48,0x0a49,0x0a4a,0x0a4b,0x0a4c,0x0a4d,0x0a4e,0x0a4f,
+ 0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55,0x0a56,0x0a57,
+ 0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d,0x0a5e,0x0a5f,
+ 0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65,0x0a66,0x0a67,
+ 0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d,0x0a6e,0x0a6f,
+ 0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75,0x0a76,0x0a77,
+ 0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d,0x0a7e,0x0a7f,
+ 0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85,0x0a86,0x0a87,
+ 0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d,0x0a8e,0x0a8f,
+ 0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95,0x0a96,0x0a97,
+ 0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d,0x0a9e,0x0a9f,
+ 0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5,0x0aa6,0x0aa7,
+ 0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad,0x0aae,0x0aaf,
+ 0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5,0x0ab6,0x0ab7,
+ 0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd,0x0abe,0x0abf,
+ 0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5,0x0ac6,0x0ac7,
+ 0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd,0x0ace,0x0acf,
+ 0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5,0x0ad6,0x0ad7,
+ 0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add,0x0ade,0x0adf,
+ 0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5,0x0ae6,0x0ae7,
+ 0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed,0x0aee,0x0aef,
+ 0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5,0x0af6,0x0af7,
+ 0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd,0x0afe,0x0aff,
+ 0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05,0x0b06,0x0b07,
+ 0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d,0x0b0e,0x0b0f,
+ 0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15,0x0b16,0x0b17,
+ 0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d,0x0b1e,0x0b1f,
+ 0x0b20,0x0b21,0x0b22,0x0b23,0x0b24,0x0b25,0x0b26,0x0b27,
+ 0x0b28,0x0b29,0x0b2a,0x0b2b,0x0b2c,0x0b2d,0x0b2e,0x0b2f,
+ 0x0b30,0x0b31,0x0b32,0x0b33,0x0b34,0x0b35,0x0b36,0x0b37,
+ 0x0b38,0x0b39,0x0b3a,0x0b3b,0x0b3c,0x0b3d,0x0b3e,0x0b3f,
+ 0x0b40,0x0b41,0x0b42,0x0b43,0x0b44,0x0b45,0x0b46,0x0b47,
+ 0x0b48,0x0b49,0x0b4a,0x0b4b,0x0b4c,0x0b4d,0x0b4e,0x0b4f,
+ 0x0b50,0x0b51,0x0b52,0x0b53,0x0b54,0x0b55,0x0b56,0x0b57,
+ 0x0b58,0x0b59,0x0b5a,0x0b5b,0x0b5c,0x0b5d,0x0b5e,0x0b5f,
+ 0x0b60,0x0b61,0x0b62,0x0b63,0x0b64,0x0b65,0x0b66,0x0b67,
+ 0x0b68,0x0b69,0x0b6a,0x0b6b,0x0b6c,0x0b6d,0x0b6e,0x0b6f,
+ 0x0b70,0x0b71,0x0b72,0x0b73,0x0b74,0x0b75,0x0b76,0x0b77,
+ 0x0b78,0x0b79,0x0b7a,0x0b7b,0x0b7c,0x0b7d,0x0b7e,0x0b7f,
+ 0x0b80,0x0b81,0x0b82,0x0b83,0x0b84,0x0b85,0x0b86,0x0b87,
+ 0x0b88,0x0b89,0x0b8a,0x0b8b,0x0b8c,0x0b8d,0x0b8e,0x0b8f,
+ 0x0b90,0x0b91,0x0b92,0x0b93,0x0b94,0x0b95,0x0b96,0x0b97,
+ 0x0b98,0x0b99,0x0b9a,0x0b9b,0x0b9c,0x0b9d,0x0b9e,0x0b9f,
+ 0x0ba0,0x0ba1,0x0ba2,0x0ba3,0x0ba4,0x0ba5,0x0ba6,0x0ba7,
+ 0x0ba8,0x0ba9,0x0baa,0x0bab,0x0bac,0x0bad,0x0bae,0x0baf,
+ 0x0bb0,0x0bb1,0x0bb2,0x0bb3,0x0bb4,0x0bb5,0x0bb6,0x0bb7,
+ 0x0bb8,0x0bb9,0x0bba,0x0bbb,0x0bbc,0x0bbd,0x0bbe,0x0bbf,
+ 0x0bc0,0x0bc1,0x0bc2,0x0bc3,0x0bc4,0x0bc5,0x0bc6,0x0bc7,
+ 0x0bc8,0x0bc9,0x0bca,0x0bcb,0x0bcc,0x0bcd,0x0bce,0x0bcf,
+ 0x0bd0,0x0bd1,0x0bd2,0x0bd3,0x0bd4,0x0bd5,0x0bd6,0x0bd7,
+ 0x0bd8,0x0bd9,0x0bda,0x0bdb,0x0bdc,0x0bdd,0x0bde,0x0bdf,
+ 0x0be0,0x0be1,0x0be2,0x0be3,0x0be4,0x0be5,0x0be6,0x0be7,
+ 0x0be8,0x0be9,0x0bea,0x0beb,0x0bec,0x0bed,0x0bee,0x0bef,
+ 0x0bf0,0x0bf1,0x0bf2,0x0bf3,0x0bf4,0x0bf5,0x0bf6,0x0bf7,
+ 0x0bf8,0x0bf9,0x0bfa,0x0bfb,0x0bfc,0x0bfd,0x0bfe,0x0bff,
+ 0x0c00,0x0c01,0x0c02,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07,
+ 0x0c08,0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f,
+ 0x0c10,0x0c11,0x0c12,0x0c13,0x0c14,0x0c15,0x0c16,0x0c17,
+ 0x0c18,0x0c19,0x0c1a,0x0c1b,0x0c1c,0x0c1d,0x0c1e,0x0c1f,
+ 0x0c20,0x0c21,0x0c22,0x0c23,0x0c24,0x0c25,0x0c26,0x0c27,
+ 0x0c28,0x0c29,0x0c2a,0x0c2b,0x0c2c,0x0c2d,0x0c2e,0x0c2f,
+ 0x0c30,0x0c31,0x0c32,0x0c33,0x0c34,0x0c35,0x0c36,0x0c37,
+ 0x0c38,0x0c39,0x0c3a,0x0c3b,0x0c3c,0x0c3d,0x0c3e,0x0c3f,
+ 0x0c40,0x0c41,0x0c42,0x0c43,0x0c44,0x0c45,0x0c46,0x0c47,
+ 0x0c48,0x0c49,0x0c4a,0x0c4b,0x0c4c,0x0c4d,0x0c4e,0x0c4f,
+ 0x0c50,0x0c51,0x0c52,0x0c53,0x0c54,0x0c55,0x0c56,0x0c57,
+ 0x0c58,0x0c59,0x0c5a,0x0c5b,0x0c5c,0x0c5d,0x0c5e,0x0c5f,
+ 0x0c60,0x0c61,0x0c62,0x0c63,0x0c64,0x0c65,0x0c66,0x0c67,
+ 0x0c68,0x0c69,0x0c6a,0x0c6b,0x0c6c,0x0c6d,0x0c6e,0x0c6f,
+ 0x0c70,0x0c71,0x0c72,0x0c73,0x0c74,0x0c75,0x0c76,0x0c77,
+ 0x0c78,0x0c79,0x0c7a,0x0c7b,0x0c7c,0x0c7d,0x0c7e,0x0c7f,
+ 0x0c80,0x0c81,0x0c82,0x0c83,0x0c84,0x0c85,0x0c86,0x0c87,
+ 0x0c88,0x0c89,0x0c8a,0x0c8b,0x0c8c,0x0c8d,0x0c8e,0x0c8f,
+ 0x0c90,0x0c91,0x0c92,0x0c93,0x0c94,0x0c95,0x0c96,0x0c97,
+ 0x0c98,0x0c99,0x0c9a,0x0c9b,0x0c9c,0x0c9d,0x0c9e,0x0c9f,
+ 0x0ca0,0x0ca1,0x0ca2,0x0ca3,0x0ca4,0x0ca5,0x0ca6,0x0ca7,
+ 0x0ca8,0x0ca9,0x0caa,0x0cab,0x0cac,0x0cad,0x0cae,0x0caf,
+ 0x0cb0,0x0cb1,0x0cb2,0x0cb3,0x0cb4,0x0cb5,0x0cb6,0x0cb7,
+ 0x0cb8,0x0cb9,0x0cba,0x0cbb,0x0cbc,0x0cbd,0x0cbe,0x0cbf,
+ 0x0cc0,0x0cc1,0x0cc2,0x0cc3,0x0cc4,0x0cc5,0x0cc6,0x0cc7,
+ 0x0cc8,0x0cc9,0x0cca,0x0ccb,0x0ccc,0x0ccd,0x0cce,0x0ccf,
+ 0x0cd0,0x0cd1,0x0cd2,0x0cd3,0x0cd4,0x0cd5,0x0cd6,0x0cd7,
+ 0x0cd8,0x0cd9,0x0cda,0x0cdb,0x0cdc,0x0cdd,0x0cde,0x0cdf,
+ 0x0ce0,0x0ce1,0x0ce2,0x0ce3,0x0ce4,0x0ce5,0x0ce6,0x0ce7,
+ 0x0ce8,0x0ce9,0x0cea,0x0ceb,0x0cec,0x0ced,0x0cee,0x0cef,
+ 0x0cf0,0x0cf1,0x0cf2,0x0cf3,0x0cf4,0x0cf5,0x0cf6,0x0cf7,
+ 0x0cf8,0x0cf9,0x0cfa,0x0cfb,0x0cfc,0x0cfd,0x0cfe,0x0cff,
+ 0x0d00,0x0d01,0x0d02,0x0d03,0x0d04,0x0d05,0x0d06,0x0d07,
+ 0x0d08,0x0d09,0x0d0a,0x0d0b,0x0d0c,0x0d0d,0x0d0e,0x0d0f,
+ 0x0d10,0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17,
+ 0x0d18,0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x0d1f,
+ 0x0d20,0x0d21,0x0d22,0x0d23,0x0d24,0x0d25,0x0d26,0x0d27,
+ 0x0d28,0x0d29,0x0d2a,0x0d2b,0x0d2c,0x0d2d,0x0d2e,0x0d2f,
+ 0x0d30,0x0d31,0x0d32,0x0d33,0x0d34,0x0d35,0x0d36,0x0d37,
+ 0x0d38,0x0d39,0x0d3a,0x0d3b,0x0d3c,0x0d3d,0x0d3e,0x0d3f,
+ 0x0d40,0x0d41,0x0d42,0x0d43,0x0d44,0x0d45,0x0d46,0x0d47,
+ 0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d,0x0d4e,0x0d4f,
+ 0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55,0x0d56,0x0d57,
+ 0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d,0x0d5e,0x0d5f,
+ 0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65,0x0d66,0x0d67,
+ 0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d,0x0d6e,0x0d6f,
+ 0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75,0x0d76,0x0d77,
+ 0x0d78,0x0d79,0x0d7a,0x0d7b,0x0d7c,0x0d7d,0x0d7e,0x0d7f,
+ 0x0d80,0x0d81,0x0d82,0x0d83,0x0d84,0x0d85,0x0d86,0x0d87,
+ 0x0d88,0x0d89,0x0d8a,0x0d8b,0x0d8c,0x0d8d,0x0d8e,0x0d8f,
+ 0x0d90,0x0d91,0x0d92,0x0d93,0x0d94,0x0d95,0x0d96,0x0d97,
+ 0x0d98,0x0d99,0x0d9a,0x0d9b,0x0d9c,0x0d9d,0x0d9e,0x0d9f,
+ 0x0da0,0x0da1,0x0da2,0x0da3,0x0da4,0x0da5,0x0da6,0x0da7,
+ 0x0da8,0x0da9,0x0daa,0x0dab,0x0dac,0x0dad,0x0dae,0x0daf,
+ 0x0db0,0x0db1,0x0db2,0x0db3,0x0db4,0x0db5,0x0db6,0x0db7,
+ 0x0db8,0x0db9,0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf,
+ 0x0dc0,0x0dc1,0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7,
+ 0x0dc8,0x0dc9,0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf,
+ 0x0dd0,0x0dd1,0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7,
+ 0x0dd8,0x0dd9,0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf,
+ 0x0de0,0x0de1,0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7,
+ 0x0de8,0x0de9,0x0dea,0x0deb,0x0dec,0x0ded,0x0dee,0x0def,
+ 0x0df0,0x0df1,0x0df2,0x0df3,0x0df4,0x0df5,0x0df6,0x0df7,
+ 0x0df8,0x0df9,0x0dfa,0x0dfb,0x0dfc,0x0dfd,0x0dfe,0x0dff,
+ 0x0e00,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
+ 0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
+ 0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
+ 0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
+ 0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
+ 0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
+ 0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
+ 0x0e38,0x0e39,0x0e3a,0x0e3b,0x0e3c,0x0e3d,0x0e3e,0x0e3f,
+ 0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
+ 0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
+ 0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
+ 0x0e58,0x0e59,0x0e5a,0x0e5b,0x0e5c,0x0e5d,0x0e5e,0x0e5f,
+ 0x0e60,0x0e61,0x0e62,0x0e63,0x0e64,0x0e65,0x0e66,0x0e67,
+ 0x0e68,0x0e69,0x0e6a,0x0e6b,0x0e6c,0x0e6d,0x0e6e,0x0e6f,
+ 0x0e70,0x0e71,0x0e72,0x0e73,0x0e74,0x0e75,0x0e76,0x0e77,
+ 0x0e78,0x0e79,0x0e7a,0x0e7b,0x0e7c,0x0e7d,0x0e7e,0x0e7f,
+ 0x0e80,0x0e81,0x0e82,0x0e83,0x0e84,0x0e85,0x0e86,0x0e87,
+ 0x0e88,0x0e89,0x0e8a,0x0e8b,0x0e8c,0x0e8d,0x0e8e,0x0e8f,
+ 0x0e90,0x0e91,0x0e92,0x0e93,0x0e94,0x0e95,0x0e96,0x0e97,
+ 0x0e98,0x0e99,0x0e9a,0x0e9b,0x0e9c,0x0e9d,0x0e9e,0x0e9f,
+ 0x0ea0,0x0ea1,0x0ea2,0x0ea3,0x0ea4,0x0ea5,0x0ea6,0x0ea7,
+ 0x0ea8,0x0ea9,0x0eaa,0x0eab,0x0eac,0x0ead,0x0eae,0x0eaf,
+ 0x0eb0,0x0eb1,0x0eb2,0x0eb3,0x0eb4,0x0eb5,0x0eb6,0x0eb7,
+ 0x0eb8,0x0eb9,0x0eba,0x0ebb,0x0ebc,0x0ebd,0x0ebe,0x0ebf,
+ 0x0ec0,0x0ec1,0x0ec2,0x0ec3,0x0ec4,0x0ec5,0x0ec6,0x0ec7,
+ 0x0ec8,0x0ec9,0x0eca,0x0ecb,0x0ecc,0x0ecd,0x0ece,0x0ecf,
+ 0x0ed0,0x0ed1,0x0ed2,0x0ed3,0x0ed4,0x0ed5,0x0ed6,0x0ed7,
+ 0x0ed8,0x0ed9,0x0eda,0x0edb,0x0edc,0x0edd,0x0ede,0x0edf,
+ 0x0ee0,0x0ee1,0x0ee2,0x0ee3,0x0ee4,0x0ee5,0x0ee6,0x0ee7,
+ 0x0ee8,0x0ee9,0x0eea,0x0eeb,0x0eec,0x0eed,0x0eee,0x0eef,
+ 0x0ef0,0x0ef1,0x0ef2,0x0ef3,0x0ef4,0x0ef5,0x0ef6,0x0ef7,
+ 0x0ef8,0x0ef9,0x0efa,0x0efb,0x0efc,0x0efd,0x0efe,0x0eff,
+ 0x0f00,0x0f01,0x0f02,0x0f03,0x0f04,0x0f05,0x0f06,0x0f07,
+ 0x0f08,0x0f09,0x0f0a,0x0f0b,0x0f0c,0x0f0d,0x0f0e,0x0f0f,
+ 0x0f10,0x0f11,0x0f12,0x0f13,0x0f14,0x0f15,0x0f16,0x0f17,
+ 0x0f18,0x0f19,0x0f1a,0x0f1b,0x0f1c,0x0f1d,0x0f1e,0x0f1f,
+ 0x0f20,0x0f21,0x0f22,0x0f23,0x0f24,0x0f25,0x0f26,0x0f27,
+ 0x0f28,0x0f29,0x0f2a,0x0f2b,0x0f2c,0x0f2d,0x0f2e,0x0f2f,
+ 0x0f30,0x0f31,0x0f32,0x0f33,0x0f34,0x0f35,0x0f36,0x0f37,
+ 0x0f38,0x0f39,0x0f3a,0x0f3b,0x0f3c,0x0f3d,0x0f3e,0x0f3f,
+ 0x0f40,0x0f41,0x0f42,0x0f43,0x0f44,0x0f45,0x0f46,0x0f47,
+ 0x0f48,0x0f49,0x0f4a,0x0f4b,0x0f4c,0x0f4d,0x0f4e,0x0f4f,
+ 0x0f50,0x0f51,0x0f52,0x0f53,0x0f54,0x0f55,0x0f56,0x0f57,
+ 0x0f58,0x0f59,0x0f5a,0x0f5b,0x0f5c,0x0f5d,0x0f5e,0x0f5f,
+ 0x0f60,0x0f61,0x0f62,0x0f63,0x0f64,0x0f65,0x0f66,0x0f67,
+ 0x0f68,0x0f69,0x0f6a,0x0f6b,0x0f6c,0x0f6d,0x0f6e,0x0f6f,
+ 0x0f70,0x0f71,0x0f72,0x0f73,0x0f74,0x0f75,0x0f76,0x0f77,
+ 0x0f78,0x0f79,0x0f7a,0x0f7b,0x0f7c,0x0f7d,0x0f7e,0x0f7f,
+ 0x0f80,0x0f81,0x0f82,0x0f83,0x0f84,0x0f85,0x0f86,0x0f87,
+ 0x0f88,0x0f89,0x0f8a,0x0f8b,0x0f8c,0x0f8d,0x0f8e,0x0f8f,
+ 0x0f90,0x0f91,0x0f92,0x0f93,0x0f94,0x0f95,0x0f96,0x0f97,
+ 0x0f98,0x0f99,0x0f9a,0x0f9b,0x0f9c,0x0f9d,0x0f9e,0x0f9f,
+ 0x0fa0,0x0fa1,0x0fa2,0x0fa3,0x0fa4,0x0fa5,0x0fa6,0x0fa7,
+ 0x0fa8,0x0fa9,0x0faa,0x0fab,0x0fac,0x0fad,0x0fae,0x0faf,
+ 0x0fb0,0x0fb1,0x0fb2,0x0fb3,0x0fb4,0x0fb5,0x0fb6,0x0fb7,
+ 0x0fb8,0x0fb9,0x0fba,0x0fbb,0x0fbc,0x0fbd,0x0fbe,0x0fbf,
+ 0x0fc0,0x0fc1,0x0fc2,0x0fc3,0x0fc4,0x0fc5,0x0fc6,0x0fc7,
+ 0x0fc8,0x0fc9,0x0fca,0x0fcb,0x0fcc,0x0fcd,0x0fce,0x0fcf,
+ 0x0fd0,0x0fd1,0x0fd2,0x0fd3,0x0fd4,0x0fd5,0x0fd6,0x0fd7,
+ 0x0fd8,0x0fd9,0x0fda,0x0fdb,0x0fdc,0x0fdd,0x0fde,0x0fdf,
+ 0x0fe0,0x0fe1,0x0fe2,0x0fe3,0x0fe4,0x0fe5,0x0fe6,0x0fe7,
+ 0x0fe8,0x0fe9,0x0fea,0x0feb,0x0fec,0x0fed,0x0fee,0x0fef,
+ 0x0ff0,0x0ff1,0x0ff2,0x0ff3,0x0ff4,0x0ff5,0x0ff6,0x0ff7,
+ 0x0ff8,0x0ff9,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff,
+ 0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007,
+ 0x1008,0x1009,0x100a,0x100b,0x100c,0x100d,0x100e,0x100f,
+ 0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017,
+ 0x1018,0x1019,0x101a,0x101b,0x101c,0x101d,0x101e,0x101f,
+ 0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027,
+ 0x1028,0x1029,0x102a,0x102b,0x102c,0x102d,0x102e,0x102f,
+ 0x1030,0x1031,0x1032,0x1033,0x1034,0x1035,0x1036,0x1037,
+ 0x1038,0x1039,0x103a,0x103b,0x103c,0x103d,0x103e,0x103f,
+ 0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047,
+ 0x1048,0x1049,0x104a,0x104b,0x104c,0x104d,0x104e,0x104f,
+ 0x1050,0x1051,0x1052,0x1053,0x1054,0x1055,0x1056,0x1057,
+ 0x1058,0x1059,0x105a,0x105b,0x105c,0x105d,0x105e,0x105f,
+ 0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
+ 0x1068,0x1069,0x106a,0x106b,0x106c,0x106d,0x106e,0x106f,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x1078,0x1079,0x107a,0x107b,0x107c,0x107d,0x107e,0x107f,
+ 0x1080,0x1081,0x1082,0x1083,0x1084,0x1085,0x1086,0x1087,
+ 0x1088,0x1089,0x108a,0x108b,0x108c,0x108d,0x108e,0x108f,
+ 0x1090,0x1091,0x1092,0x1093,0x1094,0x1095,0x1096,0x1097,
+ 0x1098,0x1099,0x109a,0x109b,0x109c,0x109d,0x109e,0x109f,
+ 0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7,
+ 0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af,
+ 0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7,
+ 0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf,
+ 0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5,0x10c6,0x10c7,
+ 0x10c8,0x10c9,0x10ca,0x10cb,0x10cc,0x10cd,0x10ce,0x10cf,
+ 0x10d0,0x10d1,0x10d2,0x10d3,0x10d4,0x10d5,0x10d6,0x10d7,
+ 0x10d8,0x10d9,0x10da,0x10db,0x10dc,0x10dd,0x10de,0x10df,
+ 0x10e0,0x10e1,0x10e2,0x10e3,0x10e4,0x10e5,0x10e6,0x10e7,
+ 0x10e8,0x10e9,0x10ea,0x10eb,0x10ec,0x10ed,0x10ee,0x10ef,
+ 0x10f0,0x10f1,0x10f2,0x10f3,0x10f4,0x10f5,0x10f6,0x10f7,
+ 0x10f8,0x10f9,0x10fa,0x10fb,0x10fc,0x10fd,0x10fe,0x10ff,
+ 0x1100,0x1101,0x1102,0x1103,0x1104,0x1105,0x1106,0x1107,
+ 0x1108,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f,
+ 0x1110,0x1111,0x1112,0x1113,0x1114,0x1115,0x1116,0x1117,
+ 0x1118,0x1119,0x111a,0x111b,0x111c,0x111d,0x111e,0x111f,
+ 0x1120,0x1121,0x1122,0x1123,0x1124,0x1125,0x1126,0x1127,
+ 0x1128,0x1129,0x112a,0x112b,0x112c,0x112d,0x112e,0x112f,
+ 0x1130,0x1131,0x1132,0x1133,0x1134,0x1135,0x1136,0x1137,
+ 0x1138,0x1139,0x113a,0x113b,0x113c,0x113d,0x113e,0x113f,
+ 0x1140,0x1141,0x1142,0x1143,0x1144,0x1145,0x1146,0x1147,
+ 0x1148,0x1149,0x114a,0x114b,0x114c,0x114d,0x114e,0x114f,
+ 0x1150,0x1151,0x1152,0x1153,0x1154,0x1155,0x1156,0x1157,
+ 0x1158,0x1159,0x115a,0x115b,0x115c,0x115d,0x115e,0x115f,
+ 0x1160,0x1161,0x1162,0x1163,0x1164,0x1165,0x1166,0x1167,
+ 0x1168,0x1169,0x116a,0x116b,0x116c,0x116d,0x116e,0x116f,
+ 0x1170,0x1171,0x1172,0x1173,0x1174,0x1175,0x1176,0x1177,
+ 0x1178,0x1179,0x117a,0x117b,0x117c,0x117d,0x117e,0x117f,
+ 0x1180,0x1181,0x1182,0x1183,0x1184,0x1185,0x1186,0x1187,
+ 0x1188,0x1189,0x118a,0x118b,0x118c,0x118d,0x118e,0x118f,
+ 0x1190,0x1191,0x1192,0x1193,0x1194,0x1195,0x1196,0x1197,
+ 0x1198,0x1199,0x119a,0x119b,0x119c,0x119d,0x119e,0x119f,
+ 0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a7,
+ 0x11a8,0x11a9,0x11aa,0x11ab,0x11ac,0x11ad,0x11ae,0x11af,
+ 0x11b0,0x11b1,0x11b2,0x11b3,0x11b4,0x11b5,0x11b6,0x11b7,
+ 0x11b8,0x11b9,0x11ba,0x11bb,0x11bc,0x11bd,0x11be,0x11bf,
+ 0x11c0,0x11c1,0x11c2,0x11c3,0x11c4,0x11c5,0x11c6,0x11c7,
+ 0x11c8,0x11c9,0x11ca,0x11cb,0x11cc,0x11cd,0x11ce,0x11cf,
+ 0x11d0,0x11d1,0x11d2,0x11d3,0x11d4,0x11d5,0x11d6,0x11d7,
+ 0x11d8,0x11d9,0x11da,0x11db,0x11dc,0x11dd,0x11de,0x11df,
+ 0x11e0,0x11e1,0x11e2,0x11e3,0x11e4,0x11e5,0x11e6,0x11e7,
+ 0x11e8,0x11e9,0x11ea,0x11eb,0x11ec,0x11ed,0x11ee,0x11ef,
+ 0x11f0,0x11f1,0x11f2,0x11f3,0x11f4,0x11f5,0x11f6,0x11f7,
+ 0x11f8,0x11f9,0x11fa,0x11fb,0x11fc,0x11fd,0x11fe,0x11ff,
+ 0x1200,0x1201,0x1202,0x1203,0x1204,0x1205,0x1206,0x1207,
+ 0x1208,0x1209,0x120a,0x120b,0x120c,0x120d,0x120e,0x120f,
+ 0x1210,0x1211,0x1212,0x1213,0x1214,0x1215,0x1216,0x1217,
+ 0x1218,0x1219,0x121a,0x121b,0x121c,0x121d,0x121e,0x121f,
+ 0x1220,0x1221,0x1222,0x1223,0x1224,0x1225,0x1226,0x1227,
+ 0x1228,0x1229,0x122a,0x122b,0x122c,0x122d,0x122e,0x122f,
+ 0x1230,0x1231,0x1232,0x1233,0x1234,0x1235,0x1236,0x1237,
+ 0x1238,0x1239,0x123a,0x123b,0x123c,0x123d,0x123e,0x123f,
+ 0x1240,0x1241,0x1242,0x1243,0x1244,0x1245,0x1246,0x1247,
+ 0x1248,0x1249,0x124a,0x124b,0x124c,0x124d,0x124e,0x124f,
+ 0x1250,0x1251,0x1252,0x1253,0x1254,0x1255,0x1256,0x1257,
+ 0x1258,0x1259,0x125a,0x125b,0x125c,0x125d,0x125e,0x125f,
+ 0x1260,0x1261,0x1262,0x1263,0x1264,0x1265,0x1266,0x1267,
+ 0x1268,0x1269,0x126a,0x126b,0x126c,0x126d,0x126e,0x126f,
+ 0x1270,0x1271,0x1272,0x1273,0x1274,0x1275,0x1276,0x1277,
+ 0x1278,0x1279,0x127a,0x127b,0x127c,0x127d,0x127e,0x127f,
+ 0x1280,0x1281,0x1282,0x1283,0x1284,0x1285,0x1286,0x1287,
+ 0x1288,0x1289,0x128a,0x128b,0x128c,0x128d,0x128e,0x128f,
+ 0x1290,0x1291,0x1292,0x1293,0x1294,0x1295,0x1296,0x1297,
+ 0x1298,0x1299,0x129a,0x129b,0x129c,0x129d,0x129e,0x129f,
+ 0x12a0,0x12a1,0x12a2,0x12a3,0x12a4,0x12a5,0x12a6,0x12a7,
+ 0x12a8,0x12a9,0x12aa,0x12ab,0x12ac,0x12ad,0x12ae,0x12af,
+ 0x12b0,0x12b1,0x12b2,0x12b3,0x12b4,0x12b5,0x12b6,0x12b7,
+ 0x12b8,0x12b9,0x12ba,0x12bb,0x12bc,0x12bd,0x12be,0x12bf,
+ 0x12c0,0x12c1,0x12c2,0x12c3,0x12c4,0x12c5,0x12c6,0x12c7,
+ 0x12c8,0x12c9,0x12ca,0x12cb,0x12cc,0x12cd,0x12ce,0x12cf,
+ 0x12d0,0x12d1,0x12d2,0x12d3,0x12d4,0x12d5,0x12d6,0x12d7,
+ 0x12d8,0x12d9,0x12da,0x12db,0x12dc,0x12dd,0x12de,0x12df,
+ 0x12e0,0x12e1,0x12e2,0x12e3,0x12e4,0x12e5,0x12e6,0x12e7,
+ 0x12e8,0x12e9,0x12ea,0x12eb,0x12ec,0x12ed,0x12ee,0x12ef,
+ 0x12f0,0x12f1,0x12f2,0x12f3,0x12f4,0x12f5,0x12f6,0x12f7,
+ 0x12f8,0x12f9,0x12fa,0x12fb,0x12fc,0x12fd,0x12fe,0x12ff,
+ 0x1300,0x1301,0x1302,0x1303,0x1304,0x1305,0x1306,0x1307,
+ 0x1308,0x1309,0x130a,0x130b,0x130c,0x130d,0x130e,0x130f,
+ 0x1310,0x1311,0x1312,0x1313,0x1314,0x1315,0x1316,0x1317,
+ 0x1318,0x1319,0x131a,0x131b,0x131c,0x131d,0x131e,0x131f,
+ 0x1320,0x1321,0x1322,0x1323,0x1324,0x1325,0x1326,0x1327,
+ 0x1328,0x1329,0x132a,0x132b,0x132c,0x132d,0x132e,0x132f,
+ 0x1330,0x1331,0x1332,0x1333,0x1334,0x1335,0x1336,0x1337,
+ 0x1338,0x1339,0x133a,0x133b,0x133c,0x133d,0x133e,0x133f,
+ 0x1340,0x1341,0x1342,0x1343,0x1344,0x1345,0x1346,0x1347,
+ 0x1348,0x1349,0x134a,0x134b,0x134c,0x134d,0x134e,0x134f,
+ 0x1350,0x1351,0x1352,0x1353,0x1354,0x1355,0x1356,0x1357,
+ 0x1358,0x1359,0x135a,0x135b,0x135c,0x135d,0x135e,0x135f,
+ 0x1360,0x1361,0x1362,0x1363,0x1364,0x1365,0x1366,0x1367,
+ 0x1368,0x1369,0x136a,0x136b,0x136c,0x136d,0x136e,0x136f,
+ 0x1370,0x1371,0x1372,0x1373,0x1374,0x1375,0x1376,0x1377,
+ 0x1378,0x1379,0x137a,0x137b,0x137c,0x137d,0x137e,0x137f,
+ 0x1380,0x1381,0x1382,0x1383,0x1384,0x1385,0x1386,0x1387,
+ 0x1388,0x1389,0x138a,0x138b,0x138c,0x138d,0x138e,0x138f,
+ 0x1390,0x1391,0x1392,0x1393,0x1394,0x1395,0x1396,0x1397,
+ 0x1398,0x1399,0x139a,0x139b,0x139c,0x139d,0x139e,0x139f,
+ 0x13a0,0x13a1,0x13a2,0x13a3,0x13a4,0x13a5,0x13a6,0x13a7,
+ 0x13a8,0x13a9,0x13aa,0x13ab,0x13ac,0x13ad,0x13ae,0x13af,
+ 0x13b0,0x13b1,0x13b2,0x13b3,0x13b4,0x13b5,0x13b6,0x13b7,
+ 0x13b8,0x13b9,0x13ba,0x13bb,0x13bc,0x13bd,0x13be,0x13bf,
+ 0x13c0,0x13c1,0x13c2,0x13c3,0x13c4,0x13c5,0x13c6,0x13c7,
+ 0x13c8,0x13c9,0x13ca,0x13cb,0x13cc,0x13cd,0x13ce,0x13cf,
+ 0x13d0,0x13d1,0x13d2,0x13d3,0x13d4,0x13d5,0x13d6,0x13d7,
+ 0x13d8,0x13d9,0x13da,0x13db,0x13dc,0x13dd,0x13de,0x13df,
+ 0x13e0,0x13e1,0x13e2,0x13e3,0x13e4,0x13e5,0x13e6,0x13e7,
+ 0x13e8,0x13e9,0x13ea,0x13eb,0x13ec,0x13ed,0x13ee,0x13ef,
+ 0x13f0,0x13f1,0x13f2,0x13f3,0x13f4,0x13f5,0x13f6,0x13f7,
+ 0x13f8,0x13f9,0x13fa,0x13fb,0x13fc,0x13fd,0x13fe,0x13ff,
+ 0x1400,0x1401,0x1402,0x1403,0x1404,0x1405,0x1406,0x1407,
+ 0x1408,0x1409,0x140a,0x140b,0x140c,0x140d,0x140e,0x140f,
+ 0x1410,0x1411,0x1412,0x1413,0x1414,0x1415,0x1416,0x1417,
+ 0x1418,0x1419,0x141a,0x141b,0x141c,0x141d,0x141e,0x141f,
+ 0x1420,0x1421,0x1422,0x1423,0x1424,0x1425,0x1426,0x1427,
+ 0x1428,0x1429,0x142a,0x142b,0x142c,0x142d,0x142e,0x142f,
+ 0x1430,0x1431,0x1432,0x1433,0x1434,0x1435,0x1436,0x1437,
+ 0x1438,0x1439,0x143a,0x143b,0x143c,0x143d,0x143e,0x143f,
+ 0x1440,0x1441,0x1442,0x1443,0x1444,0x1445,0x1446,0x1447,
+ 0x1448,0x1449,0x144a,0x144b,0x144c,0x144d,0x144e,0x144f,
+ 0x1450,0x1451,0x1452,0x1453,0x1454,0x1455,0x1456,0x1457,
+ 0x1458,0x1459,0x145a,0x145b,0x145c,0x145d,0x145e,0x145f,
+ 0x1460,0x1461,0x1462,0x1463,0x1464,0x1465,0x1466,0x1467,
+ 0x1468,0x1469,0x146a,0x146b,0x146c,0x146d,0x146e,0x146f,
+ 0x1470,0x1471,0x1472,0x1473,0x1474,0x1475,0x1476,0x1477,
+ 0x1478,0x1479,0x147a,0x147b,0x147c,0x147d,0x147e,0x147f,
+ 0x1480,0x1481,0x1482,0x1483,0x1484,0x1485,0x1486,0x1487,
+ 0x1488,0x1489,0x148a,0x148b,0x148c,0x148d,0x148e,0x148f,
+ 0x1490,0x1491,0x1492,0x1493,0x1494,0x1495,0x1496,0x1497,
+ 0x1498,0x1499,0x149a,0x149b,0x149c,0x149d,0x149e,0x149f,
+ 0x14a0,0x14a1,0x14a2,0x14a3,0x14a4,0x14a5,0x14a6,0x14a7,
+ 0x14a8,0x14a9,0x14aa,0x14ab,0x14ac,0x14ad,0x14ae,0x14af,
+ 0x14b0,0x14b1,0x14b2,0x14b3,0x14b4,0x14b5,0x14b6,0x14b7,
+ 0x14b8,0x14b9,0x14ba,0x14bb,0x14bc,0x14bd,0x14be,0x14bf,
+ 0x14c0,0x14c1,0x14c2,0x14c3,0x14c4,0x14c5,0x14c6,0x14c7,
+ 0x14c8,0x14c9,0x14ca,0x14cb,0x14cc,0x14cd,0x14ce,0x14cf,
+ 0x14d0,0x14d1,0x14d2,0x14d3,0x14d4,0x14d5,0x14d6,0x14d7,
+ 0x14d8,0x14d9,0x14da,0x14db,0x14dc,0x14dd,0x14de,0x14df,
+ 0x14e0,0x14e1,0x14e2,0x14e3,0x14e4,0x14e5,0x14e6,0x14e7,
+ 0x14e8,0x14e9,0x14ea,0x14eb,0x14ec,0x14ed,0x14ee,0x14ef,
+ 0x14f0,0x14f1,0x14f2,0x14f3,0x14f4,0x14f5,0x14f6,0x14f7,
+ 0x14f8,0x14f9,0x14fa,0x14fb,0x14fc,0x14fd,0x14fe,0x14ff,
+ 0x1500,0x1501,0x1502,0x1503,0x1504,0x1505,0x1506,0x1507,
+ 0x1508,0x1509,0x150a,0x150b,0x150c,0x150d,0x150e,0x150f,
+ 0x1510,0x1511,0x1512,0x1513,0x1514,0x1515,0x1516,0x1517,
+ 0x1518,0x1519,0x151a,0x151b,0x151c,0x151d,0x151e,0x151f,
+ 0x1520,0x1521,0x1522,0x1523,0x1524,0x1525,0x1526,0x1527,
+ 0x1528,0x1529,0x152a,0x152b,0x152c,0x152d,0x152e,0x152f,
+ 0x1530,0x1531,0x1532,0x1533,0x1534,0x1535,0x1536,0x1537,
+ 0x1538,0x1539,0x153a,0x153b,0x153c,0x153d,0x153e,0x153f,
+ 0x1540,0x1541,0x1542,0x1543,0x1544,0x1545,0x1546,0x1547,
+ 0x1548,0x1549,0x154a,0x154b,0x154c,0x154d,0x154e,0x154f,
+ 0x1550,0x1551,0x1552,0x1553,0x1554,0x1555,0x1556,0x1557,
+ 0x1558,0x1559,0x155a,0x155b,0x155c,0x155d,0x155e,0x155f,
+ 0x1560,0x1561,0x1562,0x1563,0x1564,0x1565,0x1566,0x1567,
+ 0x1568,0x1569,0x156a,0x156b,0x156c,0x156d,0x156e,0x156f,
+ 0x1570,0x1571,0x1572,0x1573,0x1574,0x1575,0x1576,0x1577,
+ 0x1578,0x1579,0x157a,0x157b,0x157c,0x157d,0x157e,0x157f,
+ 0x1580,0x1581,0x1582,0x1583,0x1584,0x1585,0x1586,0x1587,
+ 0x1588,0x1589,0x158a,0x158b,0x158c,0x158d,0x158e,0x158f,
+ 0x1590,0x1591,0x1592,0x1593,0x1594,0x1595,0x1596,0x1597,
+ 0x1598,0x1599,0x159a,0x159b,0x159c,0x159d,0x159e,0x159f,
+ 0x15a0,0x15a1,0x15a2,0x15a3,0x15a4,0x15a5,0x15a6,0x15a7,
+ 0x15a8,0x15a9,0x15aa,0x15ab,0x15ac,0x15ad,0x15ae,0x15af,
+ 0x15b0,0x15b1,0x15b2,0x15b3,0x15b4,0x15b5,0x15b6,0x15b7,
+ 0x15b8,0x15b9,0x15ba,0x15bb,0x15bc,0x15bd,0x15be,0x15bf,
+ 0x15c0,0x15c1,0x15c2,0x15c3,0x15c4,0x15c5,0x15c6,0x15c7,
+ 0x15c8,0x15c9,0x15ca,0x15cb,0x15cc,0x15cd,0x15ce,0x15cf,
+ 0x15d0,0x15d1,0x15d2,0x15d3,0x15d4,0x15d5,0x15d6,0x15d7,
+ 0x15d8,0x15d9,0x15da,0x15db,0x15dc,0x15dd,0x15de,0x15df,
+ 0x15e0,0x15e1,0x15e2,0x15e3,0x15e4,0x15e5,0x15e6,0x15e7,
+ 0x15e8,0x15e9,0x15ea,0x15eb,0x15ec,0x15ed,0x15ee,0x15ef,
+ 0x15f0,0x15f1,0x15f2,0x15f3,0x15f4,0x15f5,0x15f6,0x15f7,
+ 0x15f8,0x15f9,0x15fa,0x15fb,0x15fc,0x15fd,0x15fe,0x15ff,
+ 0x1600,0x1601,0x1602,0x1603,0x1604,0x1605,0x1606,0x1607,
+ 0x1608,0x1609,0x160a,0x160b,0x160c,0x160d,0x160e,0x160f,
+ 0x1610,0x1611,0x1612,0x1613,0x1614,0x1615,0x1616,0x1617,
+ 0x1618,0x1619,0x161a,0x161b,0x161c,0x161d,0x161e,0x161f,
+ 0x1620,0x1621,0x1622,0x1623,0x1624,0x1625,0x1626,0x1627,
+ 0x1628,0x1629,0x162a,0x162b,0x162c,0x162d,0x162e,0x162f,
+ 0x1630,0x1631,0x1632,0x1633,0x1634,0x1635,0x1636,0x1637,
+ 0x1638,0x1639,0x163a,0x163b,0x163c,0x163d,0x163e,0x163f,
+ 0x1640,0x1641,0x1642,0x1643,0x1644,0x1645,0x1646,0x1647,
+ 0x1648,0x1649,0x164a,0x164b,0x164c,0x164d,0x164e,0x164f,
+ 0x1650,0x1651,0x1652,0x1653,0x1654,0x1655,0x1656,0x1657,
+ 0x1658,0x1659,0x165a,0x165b,0x165c,0x165d,0x165e,0x165f,
+ 0x1660,0x1661,0x1662,0x1663,0x1664,0x1665,0x1666,0x1667,
+ 0x1668,0x1669,0x166a,0x166b,0x166c,0x166d,0x166e,0x166f,
+ 0x1670,0x1671,0x1672,0x1673,0x1674,0x1675,0x1676,0x1677,
+ 0x1678,0x1679,0x167a,0x167b,0x167c,0x167d,0x167e,0x167f,
+ 0x1680,0x1681,0x1682,0x1683,0x1684,0x1685,0x1686,0x1687,
+ 0x1688,0x1689,0x168a,0x168b,0x168c,0x168d,0x168e,0x168f,
+ 0x1690,0x1691,0x1692,0x1693,0x1694,0x1695,0x1696,0x1697,
+ 0x1698,0x1699,0x169a,0x169b,0x169c,0x169d,0x169e,0x169f,
+ 0x16a0,0x16a1,0x16a2,0x16a3,0x16a4,0x16a5,0x16a6,0x16a7,
+ 0x16a8,0x16a9,0x16aa,0x16ab,0x16ac,0x16ad,0x16ae,0x16af,
+ 0x16b0,0x16b1,0x16b2,0x16b3,0x16b4,0x16b5,0x16b6,0x16b7,
+ 0x16b8,0x16b9,0x16ba,0x16bb,0x16bc,0x16bd,0x16be,0x16bf,
+ 0x16c0,0x16c1,0x16c2,0x16c3,0x16c4,0x16c5,0x16c6,0x16c7,
+ 0x16c8,0x16c9,0x16ca,0x16cb,0x16cc,0x16cd,0x16ce,0x16cf,
+ 0x16d0,0x16d1,0x16d2,0x16d3,0x16d4,0x16d5,0x16d6,0x16d7,
+ 0x16d8,0x16d9,0x16da,0x16db,0x16dc,0x16dd,0x16de,0x16df,
+ 0x16e0,0x16e1,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,
+ 0x16e8,0x16e9,0x16ea,0x16eb,0x16ec,0x16ed,0x16ee,0x16ef,
+ 0x16f0,0x16f1,0x16f2,0x16f3,0x16f4,0x16f5,0x16f6,0x16f7,
+ 0x16f8,0x16f9,0x16fa,0x16fb,0x16fc,0x16fd,0x16fe,0x16ff,
+ 0x1700,0x1701,0x1702,0x1703,0x1704,0x1705,0x1706,0x1707,
+ 0x1708,0x1709,0x170a,0x170b,0x170c,0x170d,0x170e,0x170f,
+ 0x1710,0x1711,0x1712,0x1713,0x1714,0x1715,0x1716,0x1717,
+ 0x1718,0x1719,0x171a,0x171b,0x171c,0x171d,0x171e,0x171f,
+ 0x1720,0x1721,0x1722,0x1723,0x1724,0x1725,0x1726,0x1727,
+ 0x1728,0x1729,0x172a,0x172b,0x172c,0x172d,0x172e,0x172f,
+ 0x1730,0x1731,0x1732,0x1733,0x1734,0x1735,0x1736,0x1737,
+ 0x1738,0x1739,0x173a,0x173b,0x173c,0x173d,0x173e,0x173f,
+ 0x1740,0x1741,0x1742,0x1743,0x1744,0x1745,0x1746,0x1747,
+ 0x1748,0x1749,0x174a,0x174b,0x174c,0x174d,0x174e,0x174f,
+ 0x1750,0x1751,0x1752,0x1753,0x1754,0x1755,0x1756,0x1757,
+ 0x1758,0x1759,0x175a,0x175b,0x175c,0x175d,0x175e,0x175f,
+ 0x1760,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,
+ 0x1768,0x1769,0x176a,0x176b,0x176c,0x176d,0x176e,0x176f,
+ 0x1770,0x1771,0x1772,0x1773,0x1774,0x1775,0x1776,0x1777,
+ 0x1778,0x1779,0x177a,0x177b,0x177c,0x177d,0x177e,0x177f,
+ 0x1780,0x1781,0x1782,0x1783,0x1784,0x1785,0x1786,0x1787,
+ 0x1788,0x1789,0x178a,0x178b,0x178c,0x178d,0x178e,0x178f,
+ 0x1790,0x1791,0x1792,0x1793,0x1794,0x1795,0x1796,0x1797,
+ 0x1798,0x1799,0x179a,0x179b,0x179c,0x179d,0x179e,0x179f,
+ 0x17a0,0x17a1,0x17a2,0x17a3,0x17a4,0x17a5,0x17a6,0x17a7,
+ 0x17a8,0x17a9,0x17aa,0x17ab,0x17ac,0x17ad,0x17ae,0x17af,
+ 0x17b0,0x17b1,0x17b2,0x17b3,0x17b4,0x17b5,0x17b6,0x17b7,
+ 0x17b8,0x17b9,0x17ba,0x17bb,0x17bc,0x17bd,0x17be,0x17bf,
+ 0x17c0,0x17c1,0x17c2,0x17c3,0x17c4,0x17c5,0x17c6,0x17c7,
+ 0x17c8,0x17c9,0x17ca,0x17cb,0x17cc,0x17cd,0x17ce,0x17cf,
+ 0x17d0,0x17d1,0x17d2,0x17d3,0x17d4,0x17d5,0x17d6,0x17d7,
+ 0x17d8,0x17d9,0x17da,0x17db,0x17dc,0x17dd,0x17de,0x17df,
+ 0x17e0,0x17e1,0x17e2,0x17e3,0x17e4,0x17e5,0x17e6,0x17e7,
+ 0x17e8,0x17e9,0x17ea,0x17eb,0x17ec,0x17ed,0x17ee,0x17ef,
+ 0x17f0,0x17f1,0x17f2,0x17f3,0x17f4,0x17f5,0x17f6,0x17f7,
+ 0x17f8,0x17f9,0x17fa,0x17fb,0x17fc,0x17fd,0x17fe,0x17ff,
+ 0x1800,0x1801,0x1802,0x1803,0x1804,0x1805,0x1806,0x1807,
+ 0x1808,0x1809,0x180a,0x180b,0x180c,0x180d,0x180e,0x180f,
+ 0x1810,0x1811,0x1812,0x1813,0x1814,0x1815,0x1816,0x1817,
+ 0x1818,0x1819,0x181a,0x181b,0x181c,0x181d,0x181e,0x181f,
+ 0x1820,0x1821,0x1822,0x1823,0x1824,0x1825,0x1826,0x1827,
+ 0x1828,0x1829,0x182a,0x182b,0x182c,0x182d,0x182e,0x182f,
+ 0x1830,0x1831,0x1832,0x1833,0x1834,0x1835,0x1836,0x1837,
+ 0x1838,0x1839,0x183a,0x183b,0x183c,0x183d,0x183e,0x183f,
+ 0x1840,0x1841,0x1842,0x1843,0x1844,0x1845,0x1846,0x1847,
+ 0x1848,0x1849,0x184a,0x184b,0x184c,0x184d,0x184e,0x184f,
+ 0x1850,0x1851,0x1852,0x1853,0x1854,0x1855,0x1856,0x1857,
+ 0x1858,0x1859,0x185a,0x185b,0x185c,0x185d,0x185e,0x185f,
+ 0x1860,0x1861,0x1862,0x1863,0x1864,0x1865,0x1866,0x1867,
+ 0x1868,0x1869,0x186a,0x186b,0x186c,0x186d,0x186e,0x186f,
+ 0x1870,0x1871,0x1872,0x1873,0x1874,0x1875,0x1876,0x1877,
+ 0x1878,0x1879,0x187a,0x187b,0x187c,0x187d,0x187e,0x187f,
+ 0x1880,0x1881,0x1882,0x1883,0x1884,0x1885,0x1886,0x1887,
+ 0x1888,0x1889,0x188a,0x188b,0x188c,0x188d,0x188e,0x188f,
+ 0x1890,0x1891,0x1892,0x1893,0x1894,0x1895,0x1896,0x1897,
+ 0x1898,0x1899,0x189a,0x189b,0x189c,0x189d,0x189e,0x189f,
+ 0x18a0,0x18a1,0x18a2,0x18a3,0x18a4,0x18a5,0x18a6,0x18a7,
+ 0x18a8,0x18a9,0x18aa,0x18ab,0x18ac,0x18ad,0x18ae,0x18af,
+ 0x18b0,0x18b1,0x18b2,0x18b3,0x18b4,0x18b5,0x18b6,0x18b7,
+ 0x18b8,0x18b9,0x18ba,0x18bb,0x18bc,0x18bd,0x18be,0x18bf,
+ 0x18c0,0x18c1,0x18c2,0x18c3,0x18c4,0x18c5,0x18c6,0x18c7,
+ 0x18c8,0x18c9,0x18ca,0x18cb,0x18cc,0x18cd,0x18ce,0x18cf,
+ 0x18d0,0x18d1,0x18d2,0x18d3,0x18d4,0x18d5,0x18d6,0x18d7,
+ 0x18d8,0x18d9,0x18da,0x18db,0x18dc,0x18dd,0x18de,0x18df,
+ 0x18e0,0x18e1,0x18e2,0x18e3,0x18e4,0x18e5,0x18e6,0x18e7,
+ 0x18e8,0x18e9,0x18ea,0x18eb,0x18ec,0x18ed,0x18ee,0x18ef,
+ 0x18f0,0x18f1,0x18f2,0x18f3,0x18f4,0x18f5,0x18f6,0x18f7,
+ 0x18f8,0x18f9,0x18fa,0x18fb,0x18fc,0x18fd,0x18fe,0x18ff,
+ 0x1900,0x1901,0x1902,0x1903,0x1904,0x1905,0x1906,0x1907,
+ 0x1908,0x1909,0x190a,0x190b,0x190c,0x190d,0x190e,0x190f,
+ 0x1910,0x1911,0x1912,0x1913,0x1914,0x1915,0x1916,0x1917,
+ 0x1918,0x1919,0x191a,0x191b,0x191c,0x191d,0x191e,0x191f,
+ 0x1920,0x1921,0x1922,0x1923,0x1924,0x1925,0x1926,0x1927,
+ 0x1928,0x1929,0x192a,0x192b,0x192c,0x192d,0x192e,0x192f,
+ 0x1930,0x1931,0x1932,0x1933,0x1934,0x1935,0x1936,0x1937,
+ 0x1938,0x1939,0x193a,0x193b,0x193c,0x193d,0x193e,0x193f,
+ 0x1940,0x1941,0x1942,0x1943,0x1944,0x1945,0x1946,0x1947,
+ 0x1948,0x1949,0x194a,0x194b,0x194c,0x194d,0x194e,0x194f,
+ 0x1950,0x1951,0x1952,0x1953,0x1954,0x1955,0x1956,0x1957,
+ 0x1958,0x1959,0x195a,0x195b,0x195c,0x195d,0x195e,0x195f,
+ 0x1960,0x1961,0x1962,0x1963,0x1964,0x1965,0x1966,0x1967,
+ 0x1968,0x1969,0x196a,0x196b,0x196c,0x196d,0x196e,0x196f,
+ 0x1970,0x1971,0x1972,0x1973,0x1974,0x1975,0x1976,0x1977,
+ 0x1978,0x1979,0x197a,0x197b,0x197c,0x197d,0x197e,0x197f,
+ 0x1980,0x1981,0x1982,0x1983,0x1984,0x1985,0x1986,0x1987,
+ 0x1988,0x1989,0x198a,0x198b,0x198c,0x198d,0x198e,0x198f,
+ 0x1990,0x1991,0x1992,0x1993,0x1994,0x1995,0x1996,0x1997,
+ 0x1998,0x1999,0x199a,0x199b,0x199c,0x199d,0x199e,0x199f,
+ 0x19a0,0x19a1,0x19a2,0x19a3,0x19a4,0x19a5,0x19a6,0x19a7,
+ 0x19a8,0x19a9,0x19aa,0x19ab,0x19ac,0x19ad,0x19ae,0x19af,
+ 0x19b0,0x19b1,0x19b2,0x19b3,0x19b4,0x19b5,0x19b6,0x19b7,
+ 0x19b8,0x19b9,0x19ba,0x19bb,0x19bc,0x19bd,0x19be,0x19bf,
+ 0x19c0,0x19c1,0x19c2,0x19c3,0x19c4,0x19c5,0x19c6,0x19c7,
+ 0x19c8,0x19c9,0x19ca,0x19cb,0x19cc,0x19cd,0x19ce,0x19cf,
+ 0x19d0,0x19d1,0x19d2,0x19d3,0x19d4,0x19d5,0x19d6,0x19d7,
+ 0x19d8,0x19d9,0x19da,0x19db,0x19dc,0x19dd,0x19de,0x19df,
+ 0x19e0,0x19e1,0x19e2,0x19e3,0x19e4,0x19e5,0x19e6,0x19e7,
+ 0x19e8,0x19e9,0x19ea,0x19eb,0x19ec,0x19ed,0x19ee,0x19ef,
+ 0x19f0,0x19f1,0x19f2,0x19f3,0x19f4,0x19f5,0x19f6,0x19f7,
+ 0x19f8,0x19f9,0x19fa,0x19fb,0x19fc,0x19fd,0x19fe,0x19ff,
+ 0x1a00,0x1a01,0x1a02,0x1a03,0x1a04,0x1a05,0x1a06,0x1a07,
+ 0x1a08,0x1a09,0x1a0a,0x1a0b,0x1a0c,0x1a0d,0x1a0e,0x1a0f,
+ 0x1a10,0x1a11,0x1a12,0x1a13,0x1a14,0x1a15,0x1a16,0x1a17,
+ 0x1a18,0x1a19,0x1a1a,0x1a1b,0x1a1c,0x1a1d,0x1a1e,0x1a1f,
+ 0x1a20,0x1a21,0x1a22,0x1a23,0x1a24,0x1a25,0x1a26,0x1a27,
+ 0x1a28,0x1a29,0x1a2a,0x1a2b,0x1a2c,0x1a2d,0x1a2e,0x1a2f,
+ 0x1a30,0x1a31,0x1a32,0x1a33,0x1a34,0x1a35,0x1a36,0x1a37,
+ 0x1a38,0x1a39,0x1a3a,0x1a3b,0x1a3c,0x1a3d,0x1a3e,0x1a3f,
+ 0x1a40,0x1a41,0x1a42,0x1a43,0x1a44,0x1a45,0x1a46,0x1a47,
+ 0x1a48,0x1a49,0x1a4a,0x1a4b,0x1a4c,0x1a4d,0x1a4e,0x1a4f,
+ 0x1a50,0x1a51,0x1a52,0x1a53,0x1a54,0x1a55,0x1a56,0x1a57,
+ 0x1a58,0x1a59,0x1a5a,0x1a5b,0x1a5c,0x1a5d,0x1a5e,0x1a5f,
+ 0x1a60,0x1a61,0x1a62,0x1a63,0x1a64,0x1a65,0x1a66,0x1a67,
+ 0x1a68,0x1a69,0x1a6a,0x1a6b,0x1a6c,0x1a6d,0x1a6e,0x1a6f,
+ 0x1a70,0x1a71,0x1a72,0x1a73,0x1a74,0x1a75,0x1a76,0x1a77,
+ 0x1a78,0x1a79,0x1a7a,0x1a7b,0x1a7c,0x1a7d,0x1a7e,0x1a7f,
+ 0x1a80,0x1a81,0x1a82,0x1a83,0x1a84,0x1a85,0x1a86,0x1a87,
+ 0x1a88,0x1a89,0x1a8a,0x1a8b,0x1a8c,0x1a8d,0x1a8e,0x1a8f,
+ 0x1a90,0x1a91,0x1a92,0x1a93,0x1a94,0x1a95,0x1a96,0x1a97,
+ 0x1a98,0x1a99,0x1a9a,0x1a9b,0x1a9c,0x1a9d,0x1a9e,0x1a9f,
+ 0x1aa0,0x1aa1,0x1aa2,0x1aa3,0x1aa4,0x1aa5,0x1aa6,0x1aa7,
+ 0x1aa8,0x1aa9,0x1aaa,0x1aab,0x1aac,0x1aad,0x1aae,0x1aaf,
+ 0x1ab0,0x1ab1,0x1ab2,0x1ab3,0x1ab4,0x1ab5,0x1ab6,0x1ab7,
+ 0x1ab8,0x1ab9,0x1aba,0x1abb,0x1abc,0x1abd,0x1abe,0x1abf,
+ 0x1ac0,0x1ac1,0x1ac2,0x1ac3,0x1ac4,0x1ac5,0x1ac6,0x1ac7,
+ 0x1ac8,0x1ac9,0x1aca,0x1acb,0x1acc,0x1acd,0x1ace,0x1acf,
+ 0x1ad0,0x1ad1,0x1ad2,0x1ad3,0x1ad4,0x1ad5,0x1ad6,0x1ad7,
+ 0x1ad8,0x1ad9,0x1ada,0x1adb,0x1adc,0x1add,0x1ade,0x1adf,
+ 0x1ae0,0x1ae1,0x1ae2,0x1ae3,0x1ae4,0x1ae5,0x1ae6,0x1ae7,
+ 0x1ae8,0x1ae9,0x1aea,0x1aeb,0x1aec,0x1aed,0x1aee,0x1aef,
+ 0x1af0,0x1af1,0x1af2,0x1af3,0x1af4,0x1af5,0x1af6,0x1af7,
+ 0x1af8,0x1af9,0x1afa,0x1afb,0x1afc,0x1afd,0x1afe,0x1aff,
+ 0x1b00,0x1b01,0x1b02,0x1b03,0x1b04,0x1b05,0x1b06,0x1b07,
+ 0x1b08,0x1b09,0x1b0a,0x1b0b,0x1b0c,0x1b0d,0x1b0e,0x1b0f,
+ 0x1b10,0x1b11,0x1b12,0x1b13,0x1b14,0x1b15,0x1b16,0x1b17,
+ 0x1b18,0x1b19,0x1b1a,0x1b1b,0x1b1c,0x1b1d,0x1b1e,0x1b1f,
+ 0x1b20,0x1b21,0x1b22,0x1b23,0x1b24,0x1b25,0x1b26,0x1b27,
+ 0x1b28,0x1b29,0x1b2a,0x1b2b,0x1b2c,0x1b2d,0x1b2e,0x1b2f,
+ 0x1b30,0x1b31,0x1b32,0x1b33,0x1b34,0x1b35,0x1b36,0x1b37,
+ 0x1b38,0x1b39,0x1b3a,0x1b3b,0x1b3c,0x1b3d,0x1b3e,0x1b3f,
+ 0x1b40,0x1b41,0x1b42,0x1b43,0x1b44,0x1b45,0x1b46,0x1b47,
+ 0x1b48,0x1b49,0x1b4a,0x1b4b,0x1b4c,0x1b4d,0x1b4e,0x1b4f,
+ 0x1b50,0x1b51,0x1b52,0x1b53,0x1b54,0x1b55,0x1b56,0x1b57,
+ 0x1b58,0x1b59,0x1b5a,0x1b5b,0x1b5c,0x1b5d,0x1b5e,0x1b5f,
+ 0x1b60,0x1b61,0x1b62,0x1b63,0x1b64,0x1b65,0x1b66,0x1b67,
+ 0x1b68,0x1b69,0x1b6a,0x1b6b,0x1b6c,0x1b6d,0x1b6e,0x1b6f,
+ 0x1b70,0x1b71,0x1b72,0x1b73,0x1b74,0x1b75,0x1b76,0x1b77,
+ 0x1b78,0x1b79,0x1b7a,0x1b7b,0x1b7c,0x1b7d,0x1b7e,0x1b7f,
+ 0x1b80,0x1b81,0x1b82,0x1b83,0x1b84,0x1b85,0x1b86,0x1b87,
+ 0x1b88,0x1b89,0x1b8a,0x1b8b,0x1b8c,0x1b8d,0x1b8e,0x1b8f,
+ 0x1b90,0x1b91,0x1b92,0x1b93,0x1b94,0x1b95,0x1b96,0x1b97,
+ 0x1b98,0x1b99,0x1b9a,0x1b9b,0x1b9c,0x1b9d,0x1b9e,0x1b9f,
+ 0x1ba0,0x1ba1,0x1ba2,0x1ba3,0x1ba4,0x1ba5,0x1ba6,0x1ba7,
+ 0x1ba8,0x1ba9,0x1baa,0x1bab,0x1bac,0x1bad,0x1bae,0x1baf,
+ 0x1bb0,0x1bb1,0x1bb2,0x1bb3,0x1bb4,0x1bb5,0x1bb6,0x1bb7,
+ 0x1bb8,0x1bb9,0x1bba,0x1bbb,0x1bbc,0x1bbd,0x1bbe,0x1bbf,
+ 0x1bc0,0x1bc1,0x1bc2,0x1bc3,0x1bc4,0x1bc5,0x1bc6,0x1bc7,
+ 0x1bc8,0x1bc9,0x1bca,0x1bcb,0x1bcc,0x1bcd,0x1bce,0x1bcf,
+ 0x1bd0,0x1bd1,0x1bd2,0x1bd3,0x1bd4,0x1bd5,0x1bd6,0x1bd7,
+ 0x1bd8,0x1bd9,0x1bda,0x1bdb,0x1bdc,0x1bdd,0x1bde,0x1bdf,
+ 0x1be0,0x1be1,0x1be2,0x1be3,0x1be4,0x1be5,0x1be6,0x1be7,
+ 0x1be8,0x1be9,0x1bea,0x1beb,0x1bec,0x1bed,0x1bee,0x1bef,
+ 0x1bf0,0x1bf1,0x1bf2,0x1bf3,0x1bf4,0x1bf5,0x1bf6,0x1bf7,
+ 0x1bf8,0x1bf9,0x1bfa,0x1bfb,0x1bfc,0x1bfd,0x1bfe,0x1bff,
+ 0x1c00,0x1c01,0x1c02,0x1c03,0x1c04,0x1c05,0x1c06,0x1c07,
+ 0x1c08,0x1c09,0x1c0a,0x1c0b,0x1c0c,0x1c0d,0x1c0e,0x1c0f,
+ 0x1c10,0x1c11,0x1c12,0x1c13,0x1c14,0x1c15,0x1c16,0x1c17,
+ 0x1c18,0x1c19,0x1c1a,0x1c1b,0x1c1c,0x1c1d,0x1c1e,0x1c1f,
+ 0x1c20,0x1c21,0x1c22,0x1c23,0x1c24,0x1c25,0x1c26,0x1c27,
+ 0x1c28,0x1c29,0x1c2a,0x1c2b,0x1c2c,0x1c2d,0x1c2e,0x1c2f,
+ 0x1c30,0x1c31,0x1c32,0x1c33,0x1c34,0x1c35,0x1c36,0x1c37,
+ 0x1c38,0x1c39,0x1c3a,0x1c3b,0x1c3c,0x1c3d,0x1c3e,0x1c3f,
+ 0x1c40,0x1c41,0x1c42,0x1c43,0x1c44,0x1c45,0x1c46,0x1c47,
+ 0x1c48,0x1c49,0x1c4a,0x1c4b,0x1c4c,0x1c4d,0x1c4e,0x1c4f,
+ 0x1c50,0x1c51,0x1c52,0x1c53,0x1c54,0x1c55,0x1c56,0x1c57,
+ 0x1c58,0x1c59,0x1c5a,0x1c5b,0x1c5c,0x1c5d,0x1c5e,0x1c5f,
+ 0x1c60,0x1c61,0x1c62,0x1c63,0x1c64,0x1c65,0x1c66,0x1c67,
+ 0x1c68,0x1c69,0x1c6a,0x1c6b,0x1c6c,0x1c6d,0x1c6e,0x1c6f,
+ 0x1c70,0x1c71,0x1c72,0x1c73,0x1c74,0x1c75,0x1c76,0x1c77,
+ 0x1c78,0x1c79,0x1c7a,0x1c7b,0x1c7c,0x1c7d,0x1c7e,0x1c7f,
+ 0x1c80,0x1c81,0x1c82,0x1c83,0x1c84,0x1c85,0x1c86,0x1c87,
+ 0x1c88,0x1c89,0x1c8a,0x1c8b,0x1c8c,0x1c8d,0x1c8e,0x1c8f,
+ 0x1c90,0x1c91,0x1c92,0x1c93,0x1c94,0x1c95,0x1c96,0x1c97,
+ 0x1c98,0x1c99,0x1c9a,0x1c9b,0x1c9c,0x1c9d,0x1c9e,0x1c9f,
+ 0x1ca0,0x1ca1,0x1ca2,0x1ca3,0x1ca4,0x1ca5,0x1ca6,0x1ca7,
+ 0x1ca8,0x1ca9,0x1caa,0x1cab,0x1cac,0x1cad,0x1cae,0x1caf,
+ 0x1cb0,0x1cb1,0x1cb2,0x1cb3,0x1cb4,0x1cb5,0x1cb6,0x1cb7,
+ 0x1cb8,0x1cb9,0x1cba,0x1cbb,0x1cbc,0x1cbd,0x1cbe,0x1cbf,
+ 0x1cc0,0x1cc1,0x1cc2,0x1cc3,0x1cc4,0x1cc5,0x1cc6,0x1cc7,
+ 0x1cc8,0x1cc9,0x1cca,0x1ccb,0x1ccc,0x1ccd,0x1cce,0x1ccf,
+ 0x1cd0,0x1cd1,0x1cd2,0x1cd3,0x1cd4,0x1cd5,0x1cd6,0x1cd7,
+ 0x1cd8,0x1cd9,0x1cda,0x1cdb,0x1cdc,0x1cdd,0x1cde,0x1cdf,
+ 0x1ce0,0x1ce1,0x1ce2,0x1ce3,0x1ce4,0x1ce5,0x1ce6,0x1ce7,
+ 0x1ce8,0x1ce9,0x1cea,0x1ceb,0x1cec,0x1ced,0x1cee,0x1cef,
+ 0x1cf0,0x1cf1,0x1cf2,0x1cf3,0x1cf4,0x1cf5,0x1cf6,0x1cf7,
+ 0x1cf8,0x1cf9,0x1cfa,0x1cfb,0x1cfc,0x1cfd,0x1cfe,0x1cff,
+ 0x1d00,0x1d01,0x1d02,0x1d03,0x1d04,0x1d05,0x1d06,0x1d07,
+ 0x1d08,0x1d09,0x1d0a,0x1d0b,0x1d0c,0x1d0d,0x1d0e,0x1d0f,
+ 0x1d10,0x1d11,0x1d12,0x1d13,0x1d14,0x1d15,0x1d16,0x1d17,
+ 0x1d18,0x1d19,0x1d1a,0x1d1b,0x1d1c,0x1d1d,0x1d1e,0x1d1f,
+ 0x1d20,0x1d21,0x1d22,0x1d23,0x1d24,0x1d25,0x1d26,0x1d27,
+ 0x1d28,0x1d29,0x1d2a,0x1d2b,0x1d2c,0x1d2d,0x1d2e,0x1d2f,
+ 0x1d30,0x1d31,0x1d32,0x1d33,0x1d34,0x1d35,0x1d36,0x1d37,
+ 0x1d38,0x1d39,0x1d3a,0x1d3b,0x1d3c,0x1d3d,0x1d3e,0x1d3f,
+ 0x1d40,0x1d41,0x1d42,0x1d43,0x1d44,0x1d45,0x1d46,0x1d47,
+ 0x1d48,0x1d49,0x1d4a,0x1d4b,0x1d4c,0x1d4d,0x1d4e,0x1d4f,
+ 0x1d50,0x1d51,0x1d52,0x1d53,0x1d54,0x1d55,0x1d56,0x1d57,
+ 0x1d58,0x1d59,0x1d5a,0x1d5b,0x1d5c,0x1d5d,0x1d5e,0x1d5f,
+ 0x1d60,0x1d61,0x1d62,0x1d63,0x1d64,0x1d65,0x1d66,0x1d67,
+ 0x1d68,0x1d69,0x1d6a,0x1d6b,0x1d6c,0x1d6d,0x1d6e,0x1d6f,
+ 0x1d70,0x1d71,0x1d72,0x1d73,0x1d74,0x1d75,0x1d76,0x1d77,
+ 0x1d78,0x1d79,0x1d7a,0x1d7b,0x1d7c,0x1d7d,0x1d7e,0x1d7f,
+ 0x1d80,0x1d81,0x1d82,0x1d83,0x1d84,0x1d85,0x1d86,0x1d87,
+ 0x1d88,0x1d89,0x1d8a,0x1d8b,0x1d8c,0x1d8d,0x1d8e,0x1d8f,
+ 0x1d90,0x1d91,0x1d92,0x1d93,0x1d94,0x1d95,0x1d96,0x1d97,
+ 0x1d98,0x1d99,0x1d9a,0x1d9b,0x1d9c,0x1d9d,0x1d9e,0x1d9f,
+ 0x1da0,0x1da1,0x1da2,0x1da3,0x1da4,0x1da5,0x1da6,0x1da7,
+ 0x1da8,0x1da9,0x1daa,0x1dab,0x1dac,0x1dad,0x1dae,0x1daf,
+ 0x1db0,0x1db1,0x1db2,0x1db3,0x1db4,0x1db5,0x1db6,0x1db7,
+ 0x1db8,0x1db9,0x1dba,0x1dbb,0x1dbc,0x1dbd,0x1dbe,0x1dbf,
+ 0x1dc0,0x1dc1,0x1dc2,0x1dc3,0x1dc4,0x1dc5,0x1dc6,0x1dc7,
+ 0x1dc8,0x1dc9,0x1dca,0x1dcb,0x1dcc,0x1dcd,0x1dce,0x1dcf,
+ 0x1dd0,0x1dd1,0x1dd2,0x1dd3,0x1dd4,0x1dd5,0x1dd6,0x1dd7,
+ 0x1dd8,0x1dd9,0x1dda,0x1ddb,0x1ddc,0x1ddd,0x1dde,0x1ddf,
+ 0x1de0,0x1de1,0x1de2,0x1de3,0x1de4,0x1de5,0x1de6,0x1de7,
+ 0x1de8,0x1de9,0x1dea,0x1deb,0x1dec,0x1ded,0x1dee,0x1def,
+ 0x1df0,0x1df1,0x1df2,0x1df3,0x1df4,0x1df5,0x1df6,0x1df7,
+ 0x1df8,0x1df9,0x1dfa,0x1dfb,0x1dfc,0x1dfd,0x1dfe,0x1dff,
+ 0x1e01,0x1e01,0x1e03,0x1e03,0x1e05,0x1e05,0x1e07,0x1e07,
+ 0x1e09,0x1e09,0x1e0b,0x1e0b,0x1e0d,0x1e0d,0x1e0f,0x1e0f,
+ 0x1e11,0x1e11,0x1e13,0x1e13,0x1e15,0x1e15,0x1e17,0x1e17,
+ 0x1e19,0x1e19,0x1e1b,0x1e1b,0x1e1d,0x1e1d,0x1e1f,0x1e1f,
+ 0x1e21,0x1e21,0x1e23,0x1e23,0x1e25,0x1e25,0x1e27,0x1e27,
+ 0x1e29,0x1e29,0x1e2b,0x1e2b,0x1e2d,0x1e2d,0x1e2f,0x1e2f,
+ 0x1e31,0x1e31,0x1e33,0x1e33,0x1e35,0x1e35,0x1e37,0x1e37,
+ 0x1e39,0x1e39,0x1e3b,0x1e3b,0x1e3d,0x1e3d,0x1e3f,0x1e3f,
+ 0x1e41,0x1e41,0x1e43,0x1e43,0x1e45,0x1e45,0x1e47,0x1e47,
+ 0x1e49,0x1e49,0x1e4b,0x1e4b,0x1e4d,0x1e4d,0x1e4f,0x1e4f,
+ 0x1e51,0x1e51,0x1e53,0x1e53,0x1e55,0x1e55,0x1e57,0x1e57,
+ 0x1e59,0x1e59,0x1e5b,0x1e5b,0x1e5d,0x1e5d,0x1e5f,0x1e5f,
+ 0x1e61,0x1e61,0x1e63,0x1e63,0x1e65,0x1e65,0x1e67,0x1e67,
+ 0x1e69,0x1e69,0x1e6b,0x1e6b,0x1e6d,0x1e6d,0x1e6f,0x1e6f,
+ 0x1e71,0x1e71,0x1e73,0x1e73,0x1e75,0x1e75,0x1e77,0x1e77,
+ 0x1e79,0x1e79,0x1e7b,0x1e7b,0x1e7d,0x1e7d,0x1e7f,0x1e7f,
+ 0x1e81,0x1e81,0x1e83,0x1e83,0x1e85,0x1e85,0x1e87,0x1e87,
+ 0x1e89,0x1e89,0x1e8b,0x1e8b,0x1e8d,0x1e8d,0x1e8f,0x1e8f,
+ 0x1e91,0x1e91,0x1e93,0x1e93,0x1e95,0x1e95,0x1e96,0x1e97,
+ 0x1e98,0x1e99,0x1e9a,0x1e9b,0x1e9c,0x1e9d,0x1e9e,0x1e9f,
+ 0x1ea1,0x1ea1,0x1ea3,0x1ea3,0x1ea5,0x1ea5,0x1ea7,0x1ea7,
+ 0x1ea9,0x1ea9,0x1eab,0x1eab,0x1ead,0x1ead,0x1eaf,0x1eaf,
+ 0x1eb1,0x1eb1,0x1eb3,0x1eb3,0x1eb5,0x1eb5,0x1eb7,0x1eb7,
+ 0x1eb9,0x1eb9,0x1ebb,0x1ebb,0x1ebd,0x1ebd,0x1ebf,0x1ebf,
+ 0x1ec1,0x1ec1,0x1ec3,0x1ec3,0x1ec5,0x1ec5,0x1ec7,0x1ec7,
+ 0x1ec9,0x1ec9,0x1ecb,0x1ecb,0x1ecd,0x1ecd,0x1ecf,0x1ecf,
+ 0x1ed1,0x1ed1,0x1ed3,0x1ed3,0x1ed5,0x1ed5,0x1ed7,0x1ed7,
+ 0x1ed9,0x1ed9,0x1edb,0x1edb,0x1edd,0x1edd,0x1edf,0x1edf,
+ 0x1ee1,0x1ee1,0x1ee3,0x1ee3,0x1ee5,0x1ee5,0x1ee7,0x1ee7,
+ 0x1ee9,0x1ee9,0x1eeb,0x1eeb,0x1eed,0x1eed,0x1eef,0x1eef,
+ 0x1ef1,0x1ef1,0x1ef3,0x1ef3,0x1ef5,0x1ef5,0x1ef7,0x1ef7,
+ 0x1ef9,0x1ef9,0x1efa,0x1efb,0x1efc,0x1efd,0x1efe,0x1eff,
+ 0x1f00,0x1f01,0x1f02,0x1f03,0x1f04,0x1f05,0x1f06,0x1f07,
+ 0x1f00,0x1f01,0x1f02,0x1f03,0x1f04,0x1f05,0x1f06,0x1f07,
+ 0x1f10,0x1f11,0x1f12,0x1f13,0x1f14,0x1f15,0x1f16,0x1f17,
+ 0x1f10,0x1f11,0x1f12,0x1f13,0x1f14,0x1f15,0x1f1e,0x1f1f,
+ 0x1f20,0x1f21,0x1f22,0x1f23,0x1f24,0x1f25,0x1f26,0x1f27,
+ 0x1f20,0x1f21,0x1f22,0x1f23,0x1f24,0x1f25,0x1f26,0x1f27,
+ 0x1f30,0x1f31,0x1f32,0x1f33,0x1f34,0x1f35,0x1f36,0x1f37,
+ 0x1f30,0x1f31,0x1f32,0x1f33,0x1f34,0x1f35,0x1f36,0x1f37,
+ 0x1f40,0x1f41,0x1f42,0x1f43,0x1f44,0x1f45,0x1f46,0x1f47,
+ 0x1f40,0x1f41,0x1f42,0x1f43,0x1f44,0x1f45,0x1f4e,0x1f4f,
+ 0x1f50,0x1f51,0x1f52,0x1f53,0x1f54,0x1f55,0x1f56,0x1f57,
+ 0x1f58,0x1f51,0x1f5a,0x1f53,0x1f5c,0x1f55,0x1f5e,0x1f57,
+ 0x1f60,0x1f61,0x1f62,0x1f63,0x1f64,0x1f65,0x1f66,0x1f67,
+ 0x1f60,0x1f61,0x1f62,0x1f63,0x1f64,0x1f65,0x1f66,0x1f67,
+ 0x1f70,0x1f71,0x1f72,0x1f73,0x1f74,0x1f75,0x1f76,0x1f77,
+ 0x1f78,0x1f79,0x1f7a,0x1f7b,0x1f7c,0x1f7d,0x1f7e,0x1f7f,
+ 0x1f80,0x1f81,0x1f82,0x1f83,0x1f84,0x1f85,0x1f86,0x1f87,
+ 0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f,
+ 0x1f90,0x1f91,0x1f92,0x1f93,0x1f94,0x1f95,0x1f96,0x1f97,
+ 0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f,
+ 0x1fa0,0x1fa1,0x1fa2,0x1fa3,0x1fa4,0x1fa5,0x1fa6,0x1fa7,
+ 0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf,
+ 0x1fb0,0x1fb1,0x1fb2,0x1fb3,0x1fb4,0x1fb5,0x1fb6,0x1fb7,
+ 0x1fb0,0x1fb1,0x1f70,0x1f71,0x1fbc,0x1fbd,0x1fbe,0x1fbf,
+ 0x1fc0,0x1fc1,0x1fc2,0x1fc3,0x1fc4,0x1fc5,0x1fc6,0x1fc7,
+ 0x1f72,0x1f73,0x1f74,0x1f75,0x1fcc,0x1fcd,0x1fce,0x1fcf,
+ 0x1fd0,0x1fd1,0x1fd2,0x1fd3,0x1fd4,0x1fd5,0x1fd6,0x1fd7,
+ 0x1fd0,0x1fd1,0x1f76,0x1f77,0x1fdc,0x1fdd,0x1fde,0x1fdf,
+ 0x1fe0,0x1fe1,0x1fe2,0x1fe3,0x1fe4,0x1fe5,0x1fe6,0x1fe7,
+ 0x1fe0,0x1fe1,0x1f7a,0x1f7b,0x1fe5,0x1fed,0x1fee,0x1fef,
+ 0x1ff0,0x1ff1,0x1ff2,0x1ff3,0x1ff4,0x1ff5,0x1ff6,0x1ff7,
+ 0x1f78,0x1f79,0x1f7c,0x1f7d,0x1ffc,0x1ffd,0x1ffe,0x1fff,
+ 0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,
+ 0x2008,0x2009,0x200a,0x200b,0x200c,0x200d,0x200e,0x200f,
+ 0x2010,0x2011,0x2012,0x2013,0x2014,0x2015,0x2016,0x2017,
+ 0x2018,0x2019,0x201a,0x201b,0x201c,0x201d,0x201e,0x201f,
+ 0x2020,0x2021,0x2022,0x2023,0x2024,0x2025,0x2026,0x2027,
+ 0x2028,0x2029,0x202a,0x202b,0x202c,0x202d,0x202e,0x202f,
+ 0x2030,0x2031,0x2032,0x2033,0x2034,0x2035,0x2036,0x2037,
+ 0x2038,0x2039,0x203a,0x203b,0x203c,0x203d,0x203e,0x203f,
+ 0x2040,0x2041,0x2042,0x2043,0x2044,0x2045,0x2046,0x2047,
+ 0x2048,0x2049,0x204a,0x204b,0x204c,0x204d,0x204e,0x204f,
+ 0x2050,0x2051,0x2052,0x2053,0x2054,0x2055,0x2056,0x2057,
+ 0x2058,0x2059,0x205a,0x205b,0x205c,0x205d,0x205e,0x205f,
+ 0x2060,0x2061,0x2062,0x2063,0x2064,0x2065,0x2066,0x2067,
+ 0x2068,0x2069,0x206a,0x206b,0x206c,0x206d,0x206e,0x206f,
+ 0x2070,0x2071,0x2072,0x2073,0x2074,0x2075,0x2076,0x2077,
+ 0x2078,0x2079,0x207a,0x207b,0x207c,0x207d,0x207e,0x207f,
+ 0x2080,0x2081,0x2082,0x2083,0x2084,0x2085,0x2086,0x2087,
+ 0x2088,0x2089,0x208a,0x208b,0x208c,0x208d,0x208e,0x208f,
+ 0x2090,0x2091,0x2092,0x2093,0x2094,0x2095,0x2096,0x2097,
+ 0x2098,0x2099,0x209a,0x209b,0x209c,0x209d,0x209e,0x209f,
+ 0x20a0,0x20a1,0x20a2,0x20a3,0x20a4,0x20a5,0x20a6,0x20a7,
+ 0x20a8,0x20a9,0x20aa,0x20ab,0x20ac,0x20ad,0x20ae,0x20af,
+ 0x20b0,0x20b1,0x20b2,0x20b3,0x20b4,0x20b5,0x20b6,0x20b7,
+ 0x20b8,0x20b9,0x20ba,0x20bb,0x20bc,0x20bd,0x20be,0x20bf,
+ 0x20c0,0x20c1,0x20c2,0x20c3,0x20c4,0x20c5,0x20c6,0x20c7,
+ 0x20c8,0x20c9,0x20ca,0x20cb,0x20cc,0x20cd,0x20ce,0x20cf,
+ 0x20d0,0x20d1,0x20d2,0x20d3,0x20d4,0x20d5,0x20d6,0x20d7,
+ 0x20d8,0x20d9,0x20da,0x20db,0x20dc,0x20dd,0x20de,0x20df,
+ 0x20e0,0x20e1,0x20e2,0x20e3,0x20e4,0x20e5,0x20e6,0x20e7,
+ 0x20e8,0x20e9,0x20ea,0x20eb,0x20ec,0x20ed,0x20ee,0x20ef,
+ 0x20f0,0x20f1,0x20f2,0x20f3,0x20f4,0x20f5,0x20f6,0x20f7,
+ 0x20f8,0x20f9,0x20fa,0x20fb,0x20fc,0x20fd,0x20fe,0x20ff,
+ 0x2100,0x2101,0x2102,0x2103,0x2104,0x2105,0x2106,0x2107,
+ 0x2108,0x2109,0x210a,0x210b,0x210c,0x210d,0x210e,0x210f,
+ 0x2110,0x2111,0x2112,0x2113,0x2114,0x2115,0x2116,0x2117,
+ 0x2118,0x2119,0x211a,0x211b,0x211c,0x211d,0x211e,0x211f,
+ 0x2120,0x2121,0x2122,0x2123,0x2124,0x2125,0x2126,0x2127,
+ 0x2128,0x2129,0x212a,0x212b,0x212c,0x212d,0x212e,0x212f,
+ 0x2130,0x2131,0x2132,0x2133,0x2134,0x2135,0x2136,0x2137,
+ 0x2138,0x2139,0x213a,0x213b,0x213c,0x213d,0x213e,0x213f,
+ 0x2140,0x2141,0x2142,0x2143,0x2144,0x2145,0x2146,0x2147,
+ 0x2148,0x2149,0x214a,0x214b,0x214c,0x214d,0x214e,0x214f,
+ 0x2150,0x2151,0x2152,0x2153,0x2154,0x2155,0x2156,0x2157,
+ 0x2158,0x2159,0x215a,0x215b,0x215c,0x215d,0x215e,0x215f,
+ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,
+ 0x2178,0x2179,0x217a,0x217b,0x217c,0x217d,0x217e,0x217f,
+ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,
+ 0x2178,0x2179,0x217a,0x217b,0x217c,0x217d,0x217e,0x217f,
+ 0x2180,0x2181,0x2182,0x2183,0x2184,0x2185,0x2186,0x2187,
+ 0x2188,0x2189,0x218a,0x218b,0x218c,0x218d,0x218e,0x218f,
+ 0x2190,0x2191,0x2192,0x2193,0x2194,0x2195,0x2196,0x2197,
+ 0x2198,0x2199,0x219a,0x219b,0x219c,0x219d,0x219e,0x219f,
+ 0x21a0,0x21a1,0x21a2,0x21a3,0x21a4,0x21a5,0x21a6,0x21a7,
+ 0x21a8,0x21a9,0x21aa,0x21ab,0x21ac,0x21ad,0x21ae,0x21af,
+ 0x21b0,0x21b1,0x21b2,0x21b3,0x21b4,0x21b5,0x21b6,0x21b7,
+ 0x21b8,0x21b9,0x21ba,0x21bb,0x21bc,0x21bd,0x21be,0x21bf,
+ 0x21c0,0x21c1,0x21c2,0x21c3,0x21c4,0x21c5,0x21c6,0x21c7,
+ 0x21c8,0x21c9,0x21ca,0x21cb,0x21cc,0x21cd,0x21ce,0x21cf,
+ 0x21d0,0x21d1,0x21d2,0x21d3,0x21d4,0x21d5,0x21d6,0x21d7,
+ 0x21d8,0x21d9,0x21da,0x21db,0x21dc,0x21dd,0x21de,0x21df,
+ 0x21e0,0x21e1,0x21e2,0x21e3,0x21e4,0x21e5,0x21e6,0x21e7,
+ 0x21e8,0x21e9,0x21ea,0x21eb,0x21ec,0x21ed,0x21ee,0x21ef,
+ 0x21f0,0x21f1,0x21f2,0x21f3,0x21f4,0x21f5,0x21f6,0x21f7,
+ 0x21f8,0x21f9,0x21fa,0x21fb,0x21fc,0x21fd,0x21fe,0x21ff,
+ 0x2200,0x2201,0x2202,0x2203,0x2204,0x2205,0x2206,0x2207,
+ 0x2208,0x2209,0x220a,0x220b,0x220c,0x220d,0x220e,0x220f,
+ 0x2210,0x2211,0x2212,0x2213,0x2214,0x2215,0x2216,0x2217,
+ 0x2218,0x2219,0x221a,0x221b,0x221c,0x221d,0x221e,0x221f,
+ 0x2220,0x2221,0x2222,0x2223,0x2224,0x2225,0x2226,0x2227,
+ 0x2228,0x2229,0x222a,0x222b,0x222c,0x222d,0x222e,0x222f,
+ 0x2230,0x2231,0x2232,0x2233,0x2234,0x2235,0x2236,0x2237,
+ 0x2238,0x2239,0x223a,0x223b,0x223c,0x223d,0x223e,0x223f,
+ 0x2240,0x2241,0x2242,0x2243,0x2244,0x2245,0x2246,0x2247,
+ 0x2248,0x2249,0x224a,0x224b,0x224c,0x224d,0x224e,0x224f,
+ 0x2250,0x2251,0x2252,0x2253,0x2254,0x2255,0x2256,0x2257,
+ 0x2258,0x2259,0x225a,0x225b,0x225c,0x225d,0x225e,0x225f,
+ 0x2260,0x2261,0x2262,0x2263,0x2264,0x2265,0x2266,0x2267,
+ 0x2268,0x2269,0x226a,0x226b,0x226c,0x226d,0x226e,0x226f,
+ 0x2270,0x2271,0x2272,0x2273,0x2274,0x2275,0x2276,0x2277,
+ 0x2278,0x2279,0x227a,0x227b,0x227c,0x227d,0x227e,0x227f,
+ 0x2280,0x2281,0x2282,0x2283,0x2284,0x2285,0x2286,0x2287,
+ 0x2288,0x2289,0x228a,0x228b,0x228c,0x228d,0x228e,0x228f,
+ 0x2290,0x2291,0x2292,0x2293,0x2294,0x2295,0x2296,0x2297,
+ 0x2298,0x2299,0x229a,0x229b,0x229c,0x229d,0x229e,0x229f,
+ 0x22a0,0x22a1,0x22a2,0x22a3,0x22a4,0x22a5,0x22a6,0x22a7,
+ 0x22a8,0x22a9,0x22aa,0x22ab,0x22ac,0x22ad,0x22ae,0x22af,
+ 0x22b0,0x22b1,0x22b2,0x22b3,0x22b4,0x22b5,0x22b6,0x22b7,
+ 0x22b8,0x22b9,0x22ba,0x22bb,0x22bc,0x22bd,0x22be,0x22bf,
+ 0x22c0,0x22c1,0x22c2,0x22c3,0x22c4,0x22c5,0x22c6,0x22c7,
+ 0x22c8,0x22c9,0x22ca,0x22cb,0x22cc,0x22cd,0x22ce,0x22cf,
+ 0x22d0,0x22d1,0x22d2,0x22d3,0x22d4,0x22d5,0x22d6,0x22d7,
+ 0x22d8,0x22d9,0x22da,0x22db,0x22dc,0x22dd,0x22de,0x22df,
+ 0x22e0,0x22e1,0x22e2,0x22e3,0x22e4,0x22e5,0x22e6,0x22e7,
+ 0x22e8,0x22e9,0x22ea,0x22eb,0x22ec,0x22ed,0x22ee,0x22ef,
+ 0x22f0,0x22f1,0x22f2,0x22f3,0x22f4,0x22f5,0x22f6,0x22f7,
+ 0x22f8,0x22f9,0x22fa,0x22fb,0x22fc,0x22fd,0x22fe,0x22ff,
+ 0x2300,0x2301,0x2302,0x2303,0x2304,0x2305,0x2306,0x2307,
+ 0x2308,0x2309,0x230a,0x230b,0x230c,0x230d,0x230e,0x230f,
+ 0x2310,0x2311,0x2312,0x2313,0x2314,0x2315,0x2316,0x2317,
+ 0x2318,0x2319,0x231a,0x231b,0x231c,0x231d,0x231e,0x231f,
+ 0x2320,0x2321,0x2322,0x2323,0x2324,0x2325,0x2326,0x2327,
+ 0x2328,0x2329,0x232a,0x232b,0x232c,0x232d,0x232e,0x232f,
+ 0x2330,0x2331,0x2332,0x2333,0x2334,0x2335,0x2336,0x2337,
+ 0x2338,0x2339,0x233a,0x233b,0x233c,0x233d,0x233e,0x233f,
+ 0x2340,0x2341,0x2342,0x2343,0x2344,0x2345,0x2346,0x2347,
+ 0x2348,0x2349,0x234a,0x234b,0x234c,0x234d,0x234e,0x234f,
+ 0x2350,0x2351,0x2352,0x2353,0x2354,0x2355,0x2356,0x2357,
+ 0x2358,0x2359,0x235a,0x235b,0x235c,0x235d,0x235e,0x235f,
+ 0x2360,0x2361,0x2362,0x2363,0x2364,0x2365,0x2366,0x2367,
+ 0x2368,0x2369,0x236a,0x236b,0x236c,0x236d,0x236e,0x236f,
+ 0x2370,0x2371,0x2372,0x2373,0x2374,0x2375,0x2376,0x2377,
+ 0x2378,0x2379,0x237a,0x237b,0x237c,0x237d,0x237e,0x237f,
+ 0x2380,0x2381,0x2382,0x2383,0x2384,0x2385,0x2386,0x2387,
+ 0x2388,0x2389,0x238a,0x238b,0x238c,0x238d,0x238e,0x238f,
+ 0x2390,0x2391,0x2392,0x2393,0x2394,0x2395,0x2396,0x2397,
+ 0x2398,0x2399,0x239a,0x239b,0x239c,0x239d,0x239e,0x239f,
+ 0x23a0,0x23a1,0x23a2,0x23a3,0x23a4,0x23a5,0x23a6,0x23a7,
+ 0x23a8,0x23a9,0x23aa,0x23ab,0x23ac,0x23ad,0x23ae,0x23af,
+ 0x23b0,0x23b1,0x23b2,0x23b3,0x23b4,0x23b5,0x23b6,0x23b7,
+ 0x23b8,0x23b9,0x23ba,0x23bb,0x23bc,0x23bd,0x23be,0x23bf,
+ 0x23c0,0x23c1,0x23c2,0x23c3,0x23c4,0x23c5,0x23c6,0x23c7,
+ 0x23c8,0x23c9,0x23ca,0x23cb,0x23cc,0x23cd,0x23ce,0x23cf,
+ 0x23d0,0x23d1,0x23d2,0x23d3,0x23d4,0x23d5,0x23d6,0x23d7,
+ 0x23d8,0x23d9,0x23da,0x23db,0x23dc,0x23dd,0x23de,0x23df,
+ 0x23e0,0x23e1,0x23e2,0x23e3,0x23e4,0x23e5,0x23e6,0x23e7,
+ 0x23e8,0x23e9,0x23ea,0x23eb,0x23ec,0x23ed,0x23ee,0x23ef,
+ 0x23f0,0x23f1,0x23f2,0x23f3,0x23f4,0x23f5,0x23f6,0x23f7,
+ 0x23f8,0x23f9,0x23fa,0x23fb,0x23fc,0x23fd,0x23fe,0x23ff,
+ 0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407,
+ 0x2408,0x2409,0x240a,0x240b,0x240c,0x240d,0x240e,0x240f,
+ 0x2410,0x2411,0x2412,0x2413,0x2414,0x2415,0x2416,0x2417,
+ 0x2418,0x2419,0x241a,0x241b,0x241c,0x241d,0x241e,0x241f,
+ 0x2420,0x2421,0x2422,0x2423,0x2424,0x2425,0x2426,0x2427,
+ 0x2428,0x2429,0x242a,0x242b,0x242c,0x242d,0x242e,0x242f,
+ 0x2430,0x2431,0x2432,0x2433,0x2434,0x2435,0x2436,0x2437,
+ 0x2438,0x2439,0x243a,0x243b,0x243c,0x243d,0x243e,0x243f,
+ 0x2440,0x2441,0x2442,0x2443,0x2444,0x2445,0x2446,0x2447,
+ 0x2448,0x2449,0x244a,0x244b,0x244c,0x244d,0x244e,0x244f,
+ 0x2450,0x2451,0x2452,0x2453,0x2454,0x2455,0x2456,0x2457,
+ 0x2458,0x2459,0x245a,0x245b,0x245c,0x245d,0x245e,0x245f,
+ 0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
+ 0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,
+ 0x2470,0x2471,0x2472,0x2473,0x2474,0x2475,0x2476,0x2477,
+ 0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,
+ 0x2480,0x2481,0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,
+ 0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e,0x248f,
+ 0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497,
+ 0x2498,0x2499,0x249a,0x249b,0x249c,0x249d,0x249e,0x249f,
+ 0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5,0x24a6,0x24a7,
+ 0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af,
+ 0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x24d0,0x24d1,
+ 0x24d2,0x24d3,0x24d4,0x24d5,0x24d6,0x24d7,0x24d8,0x24d9,
+ 0x24da,0x24db,0x24dc,0x24dd,0x24de,0x24df,0x24e0,0x24e1,
+ 0x24e2,0x24e3,0x24e4,0x24e5,0x24e6,0x24e7,0x24e8,0x24e9,
+ 0x24d0,0x24d1,0x24d2,0x24d3,0x24d4,0x24d5,0x24d6,0x24d7,
+ 0x24d8,0x24d9,0x24da,0x24db,0x24dc,0x24dd,0x24de,0x24df,
+ 0x24e0,0x24e1,0x24e2,0x24e3,0x24e4,0x24e5,0x24e6,0x24e7,
+ 0x24e8,0x24e9,0x24ea,0x24eb,0x24ec,0x24ed,0x24ee,0x24ef,
+ 0x24f0,0x24f1,0x24f2,0x24f3,0x24f4,0x24f5,0x24f6,0x24f7,
+ 0x24f8,0x24f9,0x24fa,0x24fb,0x24fc,0x24fd,0x24fe,0x24ff,
+ 0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507,
+ 0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,
+ 0x2510,0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517,
+ 0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,0x251e,0x251f,
+ 0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,
+ 0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,
+ 0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,
+ 0x2538,0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,
+ 0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547,
+ 0x2548,0x2549,0x254a,0x254b,0x254c,0x254d,0x254e,0x254f,
+ 0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,
+ 0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,
+ 0x2560,0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567,
+ 0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,0x256e,0x256f,
+ 0x2570,0x2571,0x2572,0x2573,0x2574,0x2575,0x2576,0x2577,
+ 0x2578,0x2579,0x257a,0x257b,0x257c,0x257d,0x257e,0x257f,
+ 0x2580,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,
+ 0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,0x258e,0x258f,
+ 0x2590,0x2591,0x2592,0x2593,0x2594,0x2595,0x2596,0x2597,
+ 0x2598,0x2599,0x259a,0x259b,0x259c,0x259d,0x259e,0x259f,
+ 0x25a0,0x25a1,0x25a2,0x25a3,0x25a4,0x25a5,0x25a6,0x25a7,
+ 0x25a8,0x25a9,0x25aa,0x25ab,0x25ac,0x25ad,0x25ae,0x25af,
+ 0x25b0,0x25b1,0x25b2,0x25b3,0x25b4,0x25b5,0x25b6,0x25b7,
+ 0x25b8,0x25b9,0x25ba,0x25bb,0x25bc,0x25bd,0x25be,0x25bf,
+ 0x25c0,0x25c1,0x25c2,0x25c3,0x25c4,0x25c5,0x25c6,0x25c7,
+ 0x25c8,0x25c9,0x25ca,0x25cb,0x25cc,0x25cd,0x25ce,0x25cf,
+ 0x25d0,0x25d1,0x25d2,0x25d3,0x25d4,0x25d5,0x25d6,0x25d7,
+ 0x25d8,0x25d9,0x25da,0x25db,0x25dc,0x25dd,0x25de,0x25df,
+ 0x25e0,0x25e1,0x25e2,0x25e3,0x25e4,0x25e5,0x25e6,0x25e7,
+ 0x25e8,0x25e9,0x25ea,0x25eb,0x25ec,0x25ed,0x25ee,0x25ef,
+ 0x25f0,0x25f1,0x25f2,0x25f3,0x25f4,0x25f5,0x25f6,0x25f7,
+ 0x25f8,0x25f9,0x25fa,0x25fb,0x25fc,0x25fd,0x25fe,0x25ff,
+ 0x2600,0x2601,0x2602,0x2603,0x2604,0x2605,0x2606,0x2607,
+ 0x2608,0x2609,0x260a,0x260b,0x260c,0x260d,0x260e,0x260f,
+ 0x2610,0x2611,0x2612,0x2613,0x2614,0x2615,0x2616,0x2617,
+ 0x2618,0x2619,0x261a,0x261b,0x261c,0x261d,0x261e,0x261f,
+ 0x2620,0x2621,0x2622,0x2623,0x2624,0x2625,0x2626,0x2627,
+ 0x2628,0x2629,0x262a,0x262b,0x262c,0x262d,0x262e,0x262f,
+ 0x2630,0x2631,0x2632,0x2633,0x2634,0x2635,0x2636,0x2637,
+ 0x2638,0x2639,0x263a,0x263b,0x263c,0x263d,0x263e,0x263f,
+ 0x2640,0x2641,0x2642,0x2643,0x2644,0x2645,0x2646,0x2647,
+ 0x2648,0x2649,0x264a,0x264b,0x264c,0x264d,0x264e,0x264f,
+ 0x2650,0x2651,0x2652,0x2653,0x2654,0x2655,0x2656,0x2657,
+ 0x2658,0x2659,0x265a,0x265b,0x265c,0x265d,0x265e,0x265f,
+ 0x2660,0x2661,0x2662,0x2663,0x2664,0x2665,0x2666,0x2667,
+ 0x2668,0x2669,0x266a,0x266b,0x266c,0x266d,0x266e,0x266f,
+ 0x2670,0x2671,0x2672,0x2673,0x2674,0x2675,0x2676,0x2677,
+ 0x2678,0x2679,0x267a,0x267b,0x267c,0x267d,0x267e,0x267f,
+ 0x2680,0x2681,0x2682,0x2683,0x2684,0x2685,0x2686,0x2687,
+ 0x2688,0x2689,0x268a,0x268b,0x268c,0x268d,0x268e,0x268f,
+ 0x2690,0x2691,0x2692,0x2693,0x2694,0x2695,0x2696,0x2697,
+ 0x2698,0x2699,0x269a,0x269b,0x269c,0x269d,0x269e,0x269f,
+ 0x26a0,0x26a1,0x26a2,0x26a3,0x26a4,0x26a5,0x26a6,0x26a7,
+ 0x26a8,0x26a9,0x26aa,0x26ab,0x26ac,0x26ad,0x26ae,0x26af,
+ 0x26b0,0x26b1,0x26b2,0x26b3,0x26b4,0x26b5,0x26b6,0x26b7,
+ 0x26b8,0x26b9,0x26ba,0x26bb,0x26bc,0x26bd,0x26be,0x26bf,
+ 0x26c0,0x26c1,0x26c2,0x26c3,0x26c4,0x26c5,0x26c6,0x26c7,
+ 0x26c8,0x26c9,0x26ca,0x26cb,0x26cc,0x26cd,0x26ce,0x26cf,
+ 0x26d0,0x26d1,0x26d2,0x26d3,0x26d4,0x26d5,0x26d6,0x26d7,
+ 0x26d8,0x26d9,0x26da,0x26db,0x26dc,0x26dd,0x26de,0x26df,
+ 0x26e0,0x26e1,0x26e2,0x26e3,0x26e4,0x26e5,0x26e6,0x26e7,
+ 0x26e8,0x26e9,0x26ea,0x26eb,0x26ec,0x26ed,0x26ee,0x26ef,
+ 0x26f0,0x26f1,0x26f2,0x26f3,0x26f4,0x26f5,0x26f6,0x26f7,
+ 0x26f8,0x26f9,0x26fa,0x26fb,0x26fc,0x26fd,0x26fe,0x26ff,
+ 0x2700,0x2701,0x2702,0x2703,0x2704,0x2705,0x2706,0x2707,
+ 0x2708,0x2709,0x270a,0x270b,0x270c,0x270d,0x270e,0x270f,
+ 0x2710,0x2711,0x2712,0x2713,0x2714,0x2715,0x2716,0x2717,
+ 0x2718,0x2719,0x271a,0x271b,0x271c,0x271d,0x271e,0x271f,
+ 0x2720,0x2721,0x2722,0x2723,0x2724,0x2725,0x2726,0x2727,
+ 0x2728,0x2729,0x272a,0x272b,0x272c,0x272d,0x272e,0x272f,
+ 0x2730,0x2731,0x2732,0x2733,0x2734,0x2735,0x2736,0x2737,
+ 0x2738,0x2739,0x273a,0x273b,0x273c,0x273d,0x273e,0x273f,
+ 0x2740,0x2741,0x2742,0x2743,0x2744,0x2745,0x2746,0x2747,
+ 0x2748,0x2749,0x274a,0x274b,0x274c,0x274d,0x274e,0x274f,
+ 0x2750,0x2751,0x2752,0x2753,0x2754,0x2755,0x2756,0x2757,
+ 0x2758,0x2759,0x275a,0x275b,0x275c,0x275d,0x275e,0x275f,
+ 0x2760,0x2761,0x2762,0x2763,0x2764,0x2765,0x2766,0x2767,
+ 0x2768,0x2769,0x276a,0x276b,0x276c,0x276d,0x276e,0x276f,
+ 0x2770,0x2771,0x2772,0x2773,0x2774,0x2775,0x2776,0x2777,
+ 0x2778,0x2779,0x277a,0x277b,0x277c,0x277d,0x277e,0x277f,
+ 0x2780,0x2781,0x2782,0x2783,0x2784,0x2785,0x2786,0x2787,
+ 0x2788,0x2789,0x278a,0x278b,0x278c,0x278d,0x278e,0x278f,
+ 0x2790,0x2791,0x2792,0x2793,0x2794,0x2795,0x2796,0x2797,
+ 0x2798,0x2799,0x279a,0x279b,0x279c,0x279d,0x279e,0x279f,
+ 0x27a0,0x27a1,0x27a2,0x27a3,0x27a4,0x27a5,0x27a6,0x27a7,
+ 0x27a8,0x27a9,0x27aa,0x27ab,0x27ac,0x27ad,0x27ae,0x27af,
+ 0x27b0,0x27b1,0x27b2,0x27b3,0x27b4,0x27b5,0x27b6,0x27b7,
+ 0x27b8,0x27b9,0x27ba,0x27bb,0x27bc,0x27bd,0x27be,0x27bf,
+ 0x27c0,0x27c1,0x27c2,0x27c3,0x27c4,0x27c5,0x27c6,0x27c7,
+ 0x27c8,0x27c9,0x27ca,0x27cb,0x27cc,0x27cd,0x27ce,0x27cf,
+ 0x27d0,0x27d1,0x27d2,0x27d3,0x27d4,0x27d5,0x27d6,0x27d7,
+ 0x27d8,0x27d9,0x27da,0x27db,0x27dc,0x27dd,0x27de,0x27df,
+ 0x27e0,0x27e1,0x27e2,0x27e3,0x27e4,0x27e5,0x27e6,0x27e7,
+ 0x27e8,0x27e9,0x27ea,0x27eb,0x27ec,0x27ed,0x27ee,0x27ef,
+ 0x27f0,0x27f1,0x27f2,0x27f3,0x27f4,0x27f5,0x27f6,0x27f7,
+ 0x27f8,0x27f9,0x27fa,0x27fb,0x27fc,0x27fd,0x27fe,0x27ff,
+ 0x2800,0x2801,0x2802,0x2803,0x2804,0x2805,0x2806,0x2807,
+ 0x2808,0x2809,0x280a,0x280b,0x280c,0x280d,0x280e,0x280f,
+ 0x2810,0x2811,0x2812,0x2813,0x2814,0x2815,0x2816,0x2817,
+ 0x2818,0x2819,0x281a,0x281b,0x281c,0x281d,0x281e,0x281f,
+ 0x2820,0x2821,0x2822,0x2823,0x2824,0x2825,0x2826,0x2827,
+ 0x2828,0x2829,0x282a,0x282b,0x282c,0x282d,0x282e,0x282f,
+ 0x2830,0x2831,0x2832,0x2833,0x2834,0x2835,0x2836,0x2837,
+ 0x2838,0x2839,0x283a,0x283b,0x283c,0x283d,0x283e,0x283f,
+ 0x2840,0x2841,0x2842,0x2843,0x2844,0x2845,0x2846,0x2847,
+ 0x2848,0x2849,0x284a,0x284b,0x284c,0x284d,0x284e,0x284f,
+ 0x2850,0x2851,0x2852,0x2853,0x2854,0x2855,0x2856,0x2857,
+ 0x2858,0x2859,0x285a,0x285b,0x285c,0x285d,0x285e,0x285f,
+ 0x2860,0x2861,0x2862,0x2863,0x2864,0x2865,0x2866,0x2867,
+ 0x2868,0x2869,0x286a,0x286b,0x286c,0x286d,0x286e,0x286f,
+ 0x2870,0x2871,0x2872,0x2873,0x2874,0x2875,0x2876,0x2877,
+ 0x2878,0x2879,0x287a,0x287b,0x287c,0x287d,0x287e,0x287f,
+ 0x2880,0x2881,0x2882,0x2883,0x2884,0x2885,0x2886,0x2887,
+ 0x2888,0x2889,0x288a,0x288b,0x288c,0x288d,0x288e,0x288f,
+ 0x2890,0x2891,0x2892,0x2893,0x2894,0x2895,0x2896,0x2897,
+ 0x2898,0x2899,0x289a,0x289b,0x289c,0x289d,0x289e,0x289f,
+ 0x28a0,0x28a1,0x28a2,0x28a3,0x28a4,0x28a5,0x28a6,0x28a7,
+ 0x28a8,0x28a9,0x28aa,0x28ab,0x28ac,0x28ad,0x28ae,0x28af,
+ 0x28b0,0x28b1,0x28b2,0x28b3,0x28b4,0x28b5,0x28b6,0x28b7,
+ 0x28b8,0x28b9,0x28ba,0x28bb,0x28bc,0x28bd,0x28be,0x28bf,
+ 0x28c0,0x28c1,0x28c2,0x28c3,0x28c4,0x28c5,0x28c6,0x28c7,
+ 0x28c8,0x28c9,0x28ca,0x28cb,0x28cc,0x28cd,0x28ce,0x28cf,
+ 0x28d0,0x28d1,0x28d2,0x28d3,0x28d4,0x28d5,0x28d6,0x28d7,
+ 0x28d8,0x28d9,0x28da,0x28db,0x28dc,0x28dd,0x28de,0x28df,
+ 0x28e0,0x28e1,0x28e2,0x28e3,0x28e4,0x28e5,0x28e6,0x28e7,
+ 0x28e8,0x28e9,0x28ea,0x28eb,0x28ec,0x28ed,0x28ee,0x28ef,
+ 0x28f0,0x28f1,0x28f2,0x28f3,0x28f4,0x28f5,0x28f6,0x28f7,
+ 0x28f8,0x28f9,0x28fa,0x28fb,0x28fc,0x28fd,0x28fe,0x28ff,
+ 0x2900,0x2901,0x2902,0x2903,0x2904,0x2905,0x2906,0x2907,
+ 0x2908,0x2909,0x290a,0x290b,0x290c,0x290d,0x290e,0x290f,
+ 0x2910,0x2911,0x2912,0x2913,0x2914,0x2915,0x2916,0x2917,
+ 0x2918,0x2919,0x291a,0x291b,0x291c,0x291d,0x291e,0x291f,
+ 0x2920,0x2921,0x2922,0x2923,0x2924,0x2925,0x2926,0x2927,
+ 0x2928,0x2929,0x292a,0x292b,0x292c,0x292d,0x292e,0x292f,
+ 0x2930,0x2931,0x2932,0x2933,0x2934,0x2935,0x2936,0x2937,
+ 0x2938,0x2939,0x293a,0x293b,0x293c,0x293d,0x293e,0x293f,
+ 0x2940,0x2941,0x2942,0x2943,0x2944,0x2945,0x2946,0x2947,
+ 0x2948,0x2949,0x294a,0x294b,0x294c,0x294d,0x294e,0x294f,
+ 0x2950,0x2951,0x2952,0x2953,0x2954,0x2955,0x2956,0x2957,
+ 0x2958,0x2959,0x295a,0x295b,0x295c,0x295d,0x295e,0x295f,
+ 0x2960,0x2961,0x2962,0x2963,0x2964,0x2965,0x2966,0x2967,
+ 0x2968,0x2969,0x296a,0x296b,0x296c,0x296d,0x296e,0x296f,
+ 0x2970,0x2971,0x2972,0x2973,0x2974,0x2975,0x2976,0x2977,
+ 0x2978,0x2979,0x297a,0x297b,0x297c,0x297d,0x297e,0x297f,
+ 0x2980,0x2981,0x2982,0x2983,0x2984,0x2985,0x2986,0x2987,
+ 0x2988,0x2989,0x298a,0x298b,0x298c,0x298d,0x298e,0x298f,
+ 0x2990,0x2991,0x2992,0x2993,0x2994,0x2995,0x2996,0x2997,
+ 0x2998,0x2999,0x299a,0x299b,0x299c,0x299d,0x299e,0x299f,
+ 0x29a0,0x29a1,0x29a2,0x29a3,0x29a4,0x29a5,0x29a6,0x29a7,
+ 0x29a8,0x29a9,0x29aa,0x29ab,0x29ac,0x29ad,0x29ae,0x29af,
+ 0x29b0,0x29b1,0x29b2,0x29b3,0x29b4,0x29b5,0x29b6,0x29b7,
+ 0x29b8,0x29b9,0x29ba,0x29bb,0x29bc,0x29bd,0x29be,0x29bf,
+ 0x29c0,0x29c1,0x29c2,0x29c3,0x29c4,0x29c5,0x29c6,0x29c7,
+ 0x29c8,0x29c9,0x29ca,0x29cb,0x29cc,0x29cd,0x29ce,0x29cf,
+ 0x29d0,0x29d1,0x29d2,0x29d3,0x29d4,0x29d5,0x29d6,0x29d7,
+ 0x29d8,0x29d9,0x29da,0x29db,0x29dc,0x29dd,0x29de,0x29df,
+ 0x29e0,0x29e1,0x29e2,0x29e3,0x29e4,0x29e5,0x29e6,0x29e7,
+ 0x29e8,0x29e9,0x29ea,0x29eb,0x29ec,0x29ed,0x29ee,0x29ef,
+ 0x29f0,0x29f1,0x29f2,0x29f3,0x29f4,0x29f5,0x29f6,0x29f7,
+ 0x29f8,0x29f9,0x29fa,0x29fb,0x29fc,0x29fd,0x29fe,0x29ff,
+ 0x2a00,0x2a01,0x2a02,0x2a03,0x2a04,0x2a05,0x2a06,0x2a07,
+ 0x2a08,0x2a09,0x2a0a,0x2a0b,0x2a0c,0x2a0d,0x2a0e,0x2a0f,
+ 0x2a10,0x2a11,0x2a12,0x2a13,0x2a14,0x2a15,0x2a16,0x2a17,
+ 0x2a18,0x2a19,0x2a1a,0x2a1b,0x2a1c,0x2a1d,0x2a1e,0x2a1f,
+ 0x2a20,0x2a21,0x2a22,0x2a23,0x2a24,0x2a25,0x2a26,0x2a27,
+ 0x2a28,0x2a29,0x2a2a,0x2a2b,0x2a2c,0x2a2d,0x2a2e,0x2a2f,
+ 0x2a30,0x2a31,0x2a32,0x2a33,0x2a34,0x2a35,0x2a36,0x2a37,
+ 0x2a38,0x2a39,0x2a3a,0x2a3b,0x2a3c,0x2a3d,0x2a3e,0x2a3f,
+ 0x2a40,0x2a41,0x2a42,0x2a43,0x2a44,0x2a45,0x2a46,0x2a47,
+ 0x2a48,0x2a49,0x2a4a,0x2a4b,0x2a4c,0x2a4d,0x2a4e,0x2a4f,
+ 0x2a50,0x2a51,0x2a52,0x2a53,0x2a54,0x2a55,0x2a56,0x2a57,
+ 0x2a58,0x2a59,0x2a5a,0x2a5b,0x2a5c,0x2a5d,0x2a5e,0x2a5f,
+ 0x2a60,0x2a61,0x2a62,0x2a63,0x2a64,0x2a65,0x2a66,0x2a67,
+ 0x2a68,0x2a69,0x2a6a,0x2a6b,0x2a6c,0x2a6d,0x2a6e,0x2a6f,
+ 0x2a70,0x2a71,0x2a72,0x2a73,0x2a74,0x2a75,0x2a76,0x2a77,
+ 0x2a78,0x2a79,0x2a7a,0x2a7b,0x2a7c,0x2a7d,0x2a7e,0x2a7f,
+ 0x2a80,0x2a81,0x2a82,0x2a83,0x2a84,0x2a85,0x2a86,0x2a87,
+ 0x2a88,0x2a89,0x2a8a,0x2a8b,0x2a8c,0x2a8d,0x2a8e,0x2a8f,
+ 0x2a90,0x2a91,0x2a92,0x2a93,0x2a94,0x2a95,0x2a96,0x2a97,
+ 0x2a98,0x2a99,0x2a9a,0x2a9b,0x2a9c,0x2a9d,0x2a9e,0x2a9f,
+ 0x2aa0,0x2aa1,0x2aa2,0x2aa3,0x2aa4,0x2aa5,0x2aa6,0x2aa7,
+ 0x2aa8,0x2aa9,0x2aaa,0x2aab,0x2aac,0x2aad,0x2aae,0x2aaf,
+ 0x2ab0,0x2ab1,0x2ab2,0x2ab3,0x2ab4,0x2ab5,0x2ab6,0x2ab7,
+ 0x2ab8,0x2ab9,0x2aba,0x2abb,0x2abc,0x2abd,0x2abe,0x2abf,
+ 0x2ac0,0x2ac1,0x2ac2,0x2ac3,0x2ac4,0x2ac5,0x2ac6,0x2ac7,
+ 0x2ac8,0x2ac9,0x2aca,0x2acb,0x2acc,0x2acd,0x2ace,0x2acf,
+ 0x2ad0,0x2ad1,0x2ad2,0x2ad3,0x2ad4,0x2ad5,0x2ad6,0x2ad7,
+ 0x2ad8,0x2ad9,0x2ada,0x2adb,0x2adc,0x2add,0x2ade,0x2adf,
+ 0x2ae0,0x2ae1,0x2ae2,0x2ae3,0x2ae4,0x2ae5,0x2ae6,0x2ae7,
+ 0x2ae8,0x2ae9,0x2aea,0x2aeb,0x2aec,0x2aed,0x2aee,0x2aef,
+ 0x2af0,0x2af1,0x2af2,0x2af3,0x2af4,0x2af5,0x2af6,0x2af7,
+ 0x2af8,0x2af9,0x2afa,0x2afb,0x2afc,0x2afd,0x2afe,0x2aff,
+ 0x2b00,0x2b01,0x2b02,0x2b03,0x2b04,0x2b05,0x2b06,0x2b07,
+ 0x2b08,0x2b09,0x2b0a,0x2b0b,0x2b0c,0x2b0d,0x2b0e,0x2b0f,
+ 0x2b10,0x2b11,0x2b12,0x2b13,0x2b14,0x2b15,0x2b16,0x2b17,
+ 0x2b18,0x2b19,0x2b1a,0x2b1b,0x2b1c,0x2b1d,0x2b1e,0x2b1f,
+ 0x2b20,0x2b21,0x2b22,0x2b23,0x2b24,0x2b25,0x2b26,0x2b27,
+ 0x2b28,0x2b29,0x2b2a,0x2b2b,0x2b2c,0x2b2d,0x2b2e,0x2b2f,
+ 0x2b30,0x2b31,0x2b32,0x2b33,0x2b34,0x2b35,0x2b36,0x2b37,
+ 0x2b38,0x2b39,0x2b3a,0x2b3b,0x2b3c,0x2b3d,0x2b3e,0x2b3f,
+ 0x2b40,0x2b41,0x2b42,0x2b43,0x2b44,0x2b45,0x2b46,0x2b47,
+ 0x2b48,0x2b49,0x2b4a,0x2b4b,0x2b4c,0x2b4d,0x2b4e,0x2b4f,
+ 0x2b50,0x2b51,0x2b52,0x2b53,0x2b54,0x2b55,0x2b56,0x2b57,
+ 0x2b58,0x2b59,0x2b5a,0x2b5b,0x2b5c,0x2b5d,0x2b5e,0x2b5f,
+ 0x2b60,0x2b61,0x2b62,0x2b63,0x2b64,0x2b65,0x2b66,0x2b67,
+ 0x2b68,0x2b69,0x2b6a,0x2b6b,0x2b6c,0x2b6d,0x2b6e,0x2b6f,
+ 0x2b70,0x2b71,0x2b72,0x2b73,0x2b74,0x2b75,0x2b76,0x2b77,
+ 0x2b78,0x2b79,0x2b7a,0x2b7b,0x2b7c,0x2b7d,0x2b7e,0x2b7f,
+ 0x2b80,0x2b81,0x2b82,0x2b83,0x2b84,0x2b85,0x2b86,0x2b87,
+ 0x2b88,0x2b89,0x2b8a,0x2b8b,0x2b8c,0x2b8d,0x2b8e,0x2b8f,
+ 0x2b90,0x2b91,0x2b92,0x2b93,0x2b94,0x2b95,0x2b96,0x2b97,
+ 0x2b98,0x2b99,0x2b9a,0x2b9b,0x2b9c,0x2b9d,0x2b9e,0x2b9f,
+ 0x2ba0,0x2ba1,0x2ba2,0x2ba3,0x2ba4,0x2ba5,0x2ba6,0x2ba7,
+ 0x2ba8,0x2ba9,0x2baa,0x2bab,0x2bac,0x2bad,0x2bae,0x2baf,
+ 0x2bb0,0x2bb1,0x2bb2,0x2bb3,0x2bb4,0x2bb5,0x2bb6,0x2bb7,
+ 0x2bb8,0x2bb9,0x2bba,0x2bbb,0x2bbc,0x2bbd,0x2bbe,0x2bbf,
+ 0x2bc0,0x2bc1,0x2bc2,0x2bc3,0x2bc4,0x2bc5,0x2bc6,0x2bc7,
+ 0x2bc8,0x2bc9,0x2bca,0x2bcb,0x2bcc,0x2bcd,0x2bce,0x2bcf,
+ 0x2bd0,0x2bd1,0x2bd2,0x2bd3,0x2bd4,0x2bd5,0x2bd6,0x2bd7,
+ 0x2bd8,0x2bd9,0x2bda,0x2bdb,0x2bdc,0x2bdd,0x2bde,0x2bdf,
+ 0x2be0,0x2be1,0x2be2,0x2be3,0x2be4,0x2be5,0x2be6,0x2be7,
+ 0x2be8,0x2be9,0x2bea,0x2beb,0x2bec,0x2bed,0x2bee,0x2bef,
+ 0x2bf0,0x2bf1,0x2bf2,0x2bf3,0x2bf4,0x2bf5,0x2bf6,0x2bf7,
+ 0x2bf8,0x2bf9,0x2bfa,0x2bfb,0x2bfc,0x2bfd,0x2bfe,0x2bff,
+ 0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07,
+ 0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f,
+ 0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17,
+ 0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f,
+ 0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27,
+ 0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c2f,
+ 0x2c30,0x2c31,0x2c32,0x2c33,0x2c34,0x2c35,0x2c36,0x2c37,
+ 0x2c38,0x2c39,0x2c3a,0x2c3b,0x2c3c,0x2c3d,0x2c3e,0x2c3f,
+ 0x2c40,0x2c41,0x2c42,0x2c43,0x2c44,0x2c45,0x2c46,0x2c47,
+ 0x2c48,0x2c49,0x2c4a,0x2c4b,0x2c4c,0x2c4d,0x2c4e,0x2c4f,
+ 0x2c50,0x2c51,0x2c52,0x2c53,0x2c54,0x2c55,0x2c56,0x2c57,
+ 0x2c58,0x2c59,0x2c5a,0x2c5b,0x2c5c,0x2c5d,0x2c5e,0x2c5f,
+ 0x2c60,0x2c61,0x2c62,0x2c63,0x2c64,0x2c65,0x2c66,0x2c67,
+ 0x2c68,0x2c69,0x2c6a,0x2c6b,0x2c6c,0x2c6d,0x2c6e,0x2c6f,
+ 0x2c70,0x2c71,0x2c72,0x2c73,0x2c74,0x2c75,0x2c76,0x2c77,
+ 0x2c78,0x2c79,0x2c7a,0x2c7b,0x2c7c,0x2c7d,0x2c7e,0x2c7f,
+ 0x2c80,0x2c81,0x2c82,0x2c83,0x2c84,0x2c85,0x2c86,0x2c87,
+ 0x2c88,0x2c89,0x2c8a,0x2c8b,0x2c8c,0x2c8d,0x2c8e,0x2c8f,
+ 0x2c90,0x2c91,0x2c92,0x2c93,0x2c94,0x2c95,0x2c96,0x2c97,
+ 0x2c98,0x2c99,0x2c9a,0x2c9b,0x2c9c,0x2c9d,0x2c9e,0x2c9f,
+ 0x2ca0,0x2ca1,0x2ca2,0x2ca3,0x2ca4,0x2ca5,0x2ca6,0x2ca7,
+ 0x2ca8,0x2ca9,0x2caa,0x2cab,0x2cac,0x2cad,0x2cae,0x2caf,
+ 0x2cb0,0x2cb1,0x2cb2,0x2cb3,0x2cb4,0x2cb5,0x2cb6,0x2cb7,
+ 0x2cb8,0x2cb9,0x2cba,0x2cbb,0x2cbc,0x2cbd,0x2cbe,0x2cbf,
+ 0x2cc0,0x2cc1,0x2cc2,0x2cc3,0x2cc4,0x2cc5,0x2cc6,0x2cc7,
+ 0x2cc8,0x2cc9,0x2cca,0x2ccb,0x2ccc,0x2ccd,0x2cce,0x2ccf,
+ 0x2cd0,0x2cd1,0x2cd2,0x2cd3,0x2cd4,0x2cd5,0x2cd6,0x2cd7,
+ 0x2cd8,0x2cd9,0x2cda,0x2cdb,0x2cdc,0x2cdd,0x2cde,0x2cdf,
+ 0x2ce0,0x2ce1,0x2ce2,0x2ce3,0x2ce4,0x2ce5,0x2ce6,0x2ce7,
+ 0x2ce8,0x2ce9,0x2cea,0x2ceb,0x2cec,0x2ced,0x2cee,0x2cef,
+ 0x2cf0,0x2cf1,0x2cf2,0x2cf3,0x2cf4,0x2cf5,0x2cf6,0x2cf7,
+ 0x2cf8,0x2cf9,0x2cfa,0x2cfb,0x2cfc,0x2cfd,0x2cfe,0x2cff,
+ 0x2d00,0x2d01,0x2d02,0x2d03,0x2d04,0x2d05,0x2d06,0x2d07,
+ 0x2d08,0x2d09,0x2d0a,0x2d0b,0x2d0c,0x2d0d,0x2d0e,0x2d0f,
+ 0x2d10,0x2d11,0x2d12,0x2d13,0x2d14,0x2d15,0x2d16,0x2d17,
+ 0x2d18,0x2d19,0x2d1a,0x2d1b,0x2d1c,0x2d1d,0x2d1e,0x2d1f,
+ 0x2d20,0x2d21,0x2d22,0x2d23,0x2d24,0x2d25,0x2d26,0x2d27,
+ 0x2d28,0x2d29,0x2d2a,0x2d2b,0x2d2c,0x2d2d,0x2d2e,0x2d2f,
+ 0x2d30,0x2d31,0x2d32,0x2d33,0x2d34,0x2d35,0x2d36,0x2d37,
+ 0x2d38,0x2d39,0x2d3a,0x2d3b,0x2d3c,0x2d3d,0x2d3e,0x2d3f,
+ 0x2d40,0x2d41,0x2d42,0x2d43,0x2d44,0x2d45,0x2d46,0x2d47,
+ 0x2d48,0x2d49,0x2d4a,0x2d4b,0x2d4c,0x2d4d,0x2d4e,0x2d4f,
+ 0x2d50,0x2d51,0x2d52,0x2d53,0x2d54,0x2d55,0x2d56,0x2d57,
+ 0x2d58,0x2d59,0x2d5a,0x2d5b,0x2d5c,0x2d5d,0x2d5e,0x2d5f,
+ 0x2d60,0x2d61,0x2d62,0x2d63,0x2d64,0x2d65,0x2d66,0x2d67,
+ 0x2d68,0x2d69,0x2d6a,0x2d6b,0x2d6c,0x2d6d,0x2d6e,0x2d6f,
+ 0x2d70,0x2d71,0x2d72,0x2d73,0x2d74,0x2d75,0x2d76,0x2d77,
+ 0x2d78,0x2d79,0x2d7a,0x2d7b,0x2d7c,0x2d7d,0x2d7e,0x2d7f,
+ 0x2d80,0x2d81,0x2d82,0x2d83,0x2d84,0x2d85,0x2d86,0x2d87,
+ 0x2d88,0x2d89,0x2d8a,0x2d8b,0x2d8c,0x2d8d,0x2d8e,0x2d8f,
+ 0x2d90,0x2d91,0x2d92,0x2d93,0x2d94,0x2d95,0x2d96,0x2d97,
+ 0x2d98,0x2d99,0x2d9a,0x2d9b,0x2d9c,0x2d9d,0x2d9e,0x2d9f,
+ 0x2da0,0x2da1,0x2da2,0x2da3,0x2da4,0x2da5,0x2da6,0x2da7,
+ 0x2da8,0x2da9,0x2daa,0x2dab,0x2dac,0x2dad,0x2dae,0x2daf,
+ 0x2db0,0x2db1,0x2db2,0x2db3,0x2db4,0x2db5,0x2db6,0x2db7,
+ 0x2db8,0x2db9,0x2dba,0x2dbb,0x2dbc,0x2dbd,0x2dbe,0x2dbf,
+ 0x2dc0,0x2dc1,0x2dc2,0x2dc3,0x2dc4,0x2dc5,0x2dc6,0x2dc7,
+ 0x2dc8,0x2dc9,0x2dca,0x2dcb,0x2dcc,0x2dcd,0x2dce,0x2dcf,
+ 0x2dd0,0x2dd1,0x2dd2,0x2dd3,0x2dd4,0x2dd5,0x2dd6,0x2dd7,
+ 0x2dd8,0x2dd9,0x2dda,0x2ddb,0x2ddc,0x2ddd,0x2dde,0x2ddf,
+ 0x2de0,0x2de1,0x2de2,0x2de3,0x2de4,0x2de5,0x2de6,0x2de7,
+ 0x2de8,0x2de9,0x2dea,0x2deb,0x2dec,0x2ded,0x2dee,0x2def,
+ 0x2df0,0x2df1,0x2df2,0x2df3,0x2df4,0x2df5,0x2df6,0x2df7,
+ 0x2df8,0x2df9,0x2dfa,0x2dfb,0x2dfc,0x2dfd,0x2dfe,0x2dff,
+ 0x2e00,0x2e01,0x2e02,0x2e03,0x2e04,0x2e05,0x2e06,0x2e07,
+ 0x2e08,0x2e09,0x2e0a,0x2e0b,0x2e0c,0x2e0d,0x2e0e,0x2e0f,
+ 0x2e10,0x2e11,0x2e12,0x2e13,0x2e14,0x2e15,0x2e16,0x2e17,
+ 0x2e18,0x2e19,0x2e1a,0x2e1b,0x2e1c,0x2e1d,0x2e1e,0x2e1f,
+ 0x2e20,0x2e21,0x2e22,0x2e23,0x2e24,0x2e25,0x2e26,0x2e27,
+ 0x2e28,0x2e29,0x2e2a,0x2e2b,0x2e2c,0x2e2d,0x2e2e,0x2e2f,
+ 0x2e30,0x2e31,0x2e32,0x2e33,0x2e34,0x2e35,0x2e36,0x2e37,
+ 0x2e38,0x2e39,0x2e3a,0x2e3b,0x2e3c,0x2e3d,0x2e3e,0x2e3f,
+ 0x2e40,0x2e41,0x2e42,0x2e43,0x2e44,0x2e45,0x2e46,0x2e47,
+ 0x2e48,0x2e49,0x2e4a,0x2e4b,0x2e4c,0x2e4d,0x2e4e,0x2e4f,
+ 0x2e50,0x2e51,0x2e52,0x2e53,0x2e54,0x2e55,0x2e56,0x2e57,
+ 0x2e58,0x2e59,0x2e5a,0x2e5b,0x2e5c,0x2e5d,0x2e5e,0x2e5f,
+ 0x2e60,0x2e61,0x2e62,0x2e63,0x2e64,0x2e65,0x2e66,0x2e67,
+ 0x2e68,0x2e69,0x2e6a,0x2e6b,0x2e6c,0x2e6d,0x2e6e,0x2e6f,
+ 0x2e70,0x2e71,0x2e72,0x2e73,0x2e74,0x2e75,0x2e76,0x2e77,
+ 0x2e78,0x2e79,0x2e7a,0x2e7b,0x2e7c,0x2e7d,0x2e7e,0x2e7f,
+ 0x2e80,0x2e81,0x2e82,0x2e83,0x2e84,0x2e85,0x2e86,0x2e87,
+ 0x2e88,0x2e89,0x2e8a,0x2e8b,0x2e8c,0x2e8d,0x2e8e,0x2e8f,
+ 0x2e90,0x2e91,0x2e92,0x2e93,0x2e94,0x2e95,0x2e96,0x2e97,
+ 0x2e98,0x2e99,0x2e9a,0x2e9b,0x2e9c,0x2e9d,0x2e9e,0x2e9f,
+ 0x2ea0,0x2ea1,0x2ea2,0x2ea3,0x2ea4,0x2ea5,0x2ea6,0x2ea7,
+ 0x2ea8,0x2ea9,0x2eaa,0x2eab,0x2eac,0x2ead,0x2eae,0x2eaf,
+ 0x2eb0,0x2eb1,0x2eb2,0x2eb3,0x2eb4,0x2eb5,0x2eb6,0x2eb7,
+ 0x2eb8,0x2eb9,0x2eba,0x2ebb,0x2ebc,0x2ebd,0x2ebe,0x2ebf,
+ 0x2ec0,0x2ec1,0x2ec2,0x2ec3,0x2ec4,0x2ec5,0x2ec6,0x2ec7,
+ 0x2ec8,0x2ec9,0x2eca,0x2ecb,0x2ecc,0x2ecd,0x2ece,0x2ecf,
+ 0x2ed0,0x2ed1,0x2ed2,0x2ed3,0x2ed4,0x2ed5,0x2ed6,0x2ed7,
+ 0x2ed8,0x2ed9,0x2eda,0x2edb,0x2edc,0x2edd,0x2ede,0x2edf,
+ 0x2ee0,0x2ee1,0x2ee2,0x2ee3,0x2ee4,0x2ee5,0x2ee6,0x2ee7,
+ 0x2ee8,0x2ee9,0x2eea,0x2eeb,0x2eec,0x2eed,0x2eee,0x2eef,
+ 0x2ef0,0x2ef1,0x2ef2,0x2ef3,0x2ef4,0x2ef5,0x2ef6,0x2ef7,
+ 0x2ef8,0x2ef9,0x2efa,0x2efb,0x2efc,0x2efd,0x2efe,0x2eff,
+ 0x2f00,0x2f01,0x2f02,0x2f03,0x2f04,0x2f05,0x2f06,0x2f07,
+ 0x2f08,0x2f09,0x2f0a,0x2f0b,0x2f0c,0x2f0d,0x2f0e,0x2f0f,
+ 0x2f10,0x2f11,0x2f12,0x2f13,0x2f14,0x2f15,0x2f16,0x2f17,
+ 0x2f18,0x2f19,0x2f1a,0x2f1b,0x2f1c,0x2f1d,0x2f1e,0x2f1f,
+ 0x2f20,0x2f21,0x2f22,0x2f23,0x2f24,0x2f25,0x2f26,0x2f27,
+ 0x2f28,0x2f29,0x2f2a,0x2f2b,0x2f2c,0x2f2d,0x2f2e,0x2f2f,
+ 0x2f30,0x2f31,0x2f32,0x2f33,0x2f34,0x2f35,0x2f36,0x2f37,
+ 0x2f38,0x2f39,0x2f3a,0x2f3b,0x2f3c,0x2f3d,0x2f3e,0x2f3f,
+ 0x2f40,0x2f41,0x2f42,0x2f43,0x2f44,0x2f45,0x2f46,0x2f47,
+ 0x2f48,0x2f49,0x2f4a,0x2f4b,0x2f4c,0x2f4d,0x2f4e,0x2f4f,
+ 0x2f50,0x2f51,0x2f52,0x2f53,0x2f54,0x2f55,0x2f56,0x2f57,
+ 0x2f58,0x2f59,0x2f5a,0x2f5b,0x2f5c,0x2f5d,0x2f5e,0x2f5f,
+ 0x2f60,0x2f61,0x2f62,0x2f63,0x2f64,0x2f65,0x2f66,0x2f67,
+ 0x2f68,0x2f69,0x2f6a,0x2f6b,0x2f6c,0x2f6d,0x2f6e,0x2f6f,
+ 0x2f70,0x2f71,0x2f72,0x2f73,0x2f74,0x2f75,0x2f76,0x2f77,
+ 0x2f78,0x2f79,0x2f7a,0x2f7b,0x2f7c,0x2f7d,0x2f7e,0x2f7f,
+ 0x2f80,0x2f81,0x2f82,0x2f83,0x2f84,0x2f85,0x2f86,0x2f87,
+ 0x2f88,0x2f89,0x2f8a,0x2f8b,0x2f8c,0x2f8d,0x2f8e,0x2f8f,
+ 0x2f90,0x2f91,0x2f92,0x2f93,0x2f94,0x2f95,0x2f96,0x2f97,
+ 0x2f98,0x2f99,0x2f9a,0x2f9b,0x2f9c,0x2f9d,0x2f9e,0x2f9f,
+ 0x2fa0,0x2fa1,0x2fa2,0x2fa3,0x2fa4,0x2fa5,0x2fa6,0x2fa7,
+ 0x2fa8,0x2fa9,0x2faa,0x2fab,0x2fac,0x2fad,0x2fae,0x2faf,
+ 0x2fb0,0x2fb1,0x2fb2,0x2fb3,0x2fb4,0x2fb5,0x2fb6,0x2fb7,
+ 0x2fb8,0x2fb9,0x2fba,0x2fbb,0x2fbc,0x2fbd,0x2fbe,0x2fbf,
+ 0x2fc0,0x2fc1,0x2fc2,0x2fc3,0x2fc4,0x2fc5,0x2fc6,0x2fc7,
+ 0x2fc8,0x2fc9,0x2fca,0x2fcb,0x2fcc,0x2fcd,0x2fce,0x2fcf,
+ 0x2fd0,0x2fd1,0x2fd2,0x2fd3,0x2fd4,0x2fd5,0x2fd6,0x2fd7,
+ 0x2fd8,0x2fd9,0x2fda,0x2fdb,0x2fdc,0x2fdd,0x2fde,0x2fdf,
+ 0x2fe0,0x2fe1,0x2fe2,0x2fe3,0x2fe4,0x2fe5,0x2fe6,0x2fe7,
+ 0x2fe8,0x2fe9,0x2fea,0x2feb,0x2fec,0x2fed,0x2fee,0x2fef,
+ 0x2ff0,0x2ff1,0x2ff2,0x2ff3,0x2ff4,0x2ff5,0x2ff6,0x2ff7,
+ 0x2ff8,0x2ff9,0x2ffa,0x2ffb,0x2ffc,0x2ffd,0x2ffe,0x2fff,
+ 0x3000,0x3001,0x3002,0x3003,0x3004,0x3005,0x3006,0x3007,
+ 0x3008,0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,
+ 0x3010,0x3011,0x3012,0x3013,0x3014,0x3015,0x3016,0x3017,
+ 0x3018,0x3019,0x301a,0x301b,0x301c,0x301d,0x301e,0x301f,
+ 0x3020,0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,
+ 0x3028,0x3029,0x302a,0x302b,0x302c,0x302d,0x302e,0x302f,
+ 0x3030,0x3031,0x3032,0x3033,0x3034,0x3035,0x3036,0x3037,
+ 0x3038,0x3039,0x303a,0x303b,0x303c,0x303d,0x303e,0x303f,
+ 0x3040,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,
+ 0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,0x304f,
+ 0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,
+ 0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,
+ 0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,
+ 0x3068,0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,
+ 0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,
+ 0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,
+ 0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,
+ 0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,
+ 0x3090,0x3091,0x3092,0x3093,0x3094,0x3095,0x3096,0x3097,
+ 0x3098,0x3099,0x309a,0x309b,0x309c,0x309d,0x309e,0x309f,
+ 0x30a0,0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,
+ 0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,0x30af,
+ 0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,
+ 0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,
+ 0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,
+ 0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,
+ 0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,
+ 0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,
+ 0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,
+ 0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,
+ 0x30f0,0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,0x30f7,
+ 0x30f8,0x30f9,0x30fa,0x30fb,0x30fc,0x30fd,0x30fe,0x30ff,
+ 0x3100,0x3101,0x3102,0x3103,0x3104,0x3105,0x3106,0x3107,
+ 0x3108,0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,
+ 0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,
+ 0x3118,0x3119,0x311a,0x311b,0x311c,0x311d,0x311e,0x311f,
+ 0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127,
+ 0x3128,0x3129,0x312a,0x312b,0x312c,0x312d,0x312e,0x312f,
+ 0x3130,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137,
+ 0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,0x313f,
+ 0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,
+ 0x3148,0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x314f,
+ 0x3150,0x3151,0x3152,0x3153,0x3154,0x3155,0x3156,0x3157,
+ 0x3158,0x3159,0x315a,0x315b,0x315c,0x315d,0x315e,0x315f,
+ 0x3160,0x3161,0x3162,0x3163,0x3164,0x3165,0x3166,0x3167,
+ 0x3168,0x3169,0x316a,0x316b,0x316c,0x316d,0x316e,0x316f,
+ 0x3170,0x3171,0x3172,0x3173,0x3174,0x3175,0x3176,0x3177,
+ 0x3178,0x3179,0x317a,0x317b,0x317c,0x317d,0x317e,0x317f,
+ 0x3180,0x3181,0x3182,0x3183,0x3184,0x3185,0x3186,0x3187,
+ 0x3188,0x3189,0x318a,0x318b,0x318c,0x318d,0x318e,0x318f,
+ 0x3190,0x3191,0x3192,0x3193,0x3194,0x3195,0x3196,0x3197,
+ 0x3198,0x3199,0x319a,0x319b,0x319c,0x319d,0x319e,0x319f,
+ 0x31a0,0x31a1,0x31a2,0x31a3,0x31a4,0x31a5,0x31a6,0x31a7,
+ 0x31a8,0x31a9,0x31aa,0x31ab,0x31ac,0x31ad,0x31ae,0x31af,
+ 0x31b0,0x31b1,0x31b2,0x31b3,0x31b4,0x31b5,0x31b6,0x31b7,
+ 0x31b8,0x31b9,0x31ba,0x31bb,0x31bc,0x31bd,0x31be,0x31bf,
+ 0x31c0,0x31c1,0x31c2,0x31c3,0x31c4,0x31c5,0x31c6,0x31c7,
+ 0x31c8,0x31c9,0x31ca,0x31cb,0x31cc,0x31cd,0x31ce,0x31cf,
+ 0x31d0,0x31d1,0x31d2,0x31d3,0x31d4,0x31d5,0x31d6,0x31d7,
+ 0x31d8,0x31d9,0x31da,0x31db,0x31dc,0x31dd,0x31de,0x31df,
+ 0x31e0,0x31e1,0x31e2,0x31e3,0x31e4,0x31e5,0x31e6,0x31e7,
+ 0x31e8,0x31e9,0x31ea,0x31eb,0x31ec,0x31ed,0x31ee,0x31ef,
+ 0x31f0,0x31f1,0x31f2,0x31f3,0x31f4,0x31f5,0x31f6,0x31f7,
+ 0x31f8,0x31f9,0x31fa,0x31fb,0x31fc,0x31fd,0x31fe,0x31ff,
+ 0x3200,0x3201,0x3202,0x3203,0x3204,0x3205,0x3206,0x3207,
+ 0x3208,0x3209,0x320a,0x320b,0x320c,0x320d,0x320e,0x320f,
+ 0x3210,0x3211,0x3212,0x3213,0x3214,0x3215,0x3216,0x3217,
+ 0x3218,0x3219,0x321a,0x321b,0x321c,0x321d,0x321e,0x321f,
+ 0x3220,0x3221,0x3222,0x3223,0x3224,0x3225,0x3226,0x3227,
+ 0x3228,0x3229,0x322a,0x322b,0x322c,0x322d,0x322e,0x322f,
+ 0x3230,0x3231,0x3232,0x3233,0x3234,0x3235,0x3236,0x3237,
+ 0x3238,0x3239,0x323a,0x323b,0x323c,0x323d,0x323e,0x323f,
+ 0x3240,0x3241,0x3242,0x3243,0x3244,0x3245,0x3246,0x3247,
+ 0x3248,0x3249,0x324a,0x324b,0x324c,0x324d,0x324e,0x324f,
+ 0x3250,0x3251,0x3252,0x3253,0x3254,0x3255,0x3256,0x3257,
+ 0x3258,0x3259,0x325a,0x325b,0x325c,0x325d,0x325e,0x325f,
+ 0x3260,0x3261,0x3262,0x3263,0x3264,0x3265,0x3266,0x3267,
+ 0x3268,0x3269,0x326a,0x326b,0x326c,0x326d,0x326e,0x326f,
+ 0x3270,0x3271,0x3272,0x3273,0x3274,0x3275,0x3276,0x3277,
+ 0x3278,0x3279,0x327a,0x327b,0x327c,0x327d,0x327e,0x327f,
+ 0x3280,0x3281,0x3282,0x3283,0x3284,0x3285,0x3286,0x3287,
+ 0x3288,0x3289,0x328a,0x328b,0x328c,0x328d,0x328e,0x328f,
+ 0x3290,0x3291,0x3292,0x3293,0x3294,0x3295,0x3296,0x3297,
+ 0x3298,0x3299,0x329a,0x329b,0x329c,0x329d,0x329e,0x329f,
+ 0x32a0,0x32a1,0x32a2,0x32a3,0x32a4,0x32a5,0x32a6,0x32a7,
+ 0x32a8,0x32a9,0x32aa,0x32ab,0x32ac,0x32ad,0x32ae,0x32af,
+ 0x32b0,0x32b1,0x32b2,0x32b3,0x32b4,0x32b5,0x32b6,0x32b7,
+ 0x32b8,0x32b9,0x32ba,0x32bb,0x32bc,0x32bd,0x32be,0x32bf,
+ 0x32c0,0x32c1,0x32c2,0x32c3,0x32c4,0x32c5,0x32c6,0x32c7,
+ 0x32c8,0x32c9,0x32ca,0x32cb,0x32cc,0x32cd,0x32ce,0x32cf,
+ 0x32d0,0x32d1,0x32d2,0x32d3,0x32d4,0x32d5,0x32d6,0x32d7,
+ 0x32d8,0x32d9,0x32da,0x32db,0x32dc,0x32dd,0x32de,0x32df,
+ 0x32e0,0x32e1,0x32e2,0x32e3,0x32e4,0x32e5,0x32e6,0x32e7,
+ 0x32e8,0x32e9,0x32ea,0x32eb,0x32ec,0x32ed,0x32ee,0x32ef,
+ 0x32f0,0x32f1,0x32f2,0x32f3,0x32f4,0x32f5,0x32f6,0x32f7,
+ 0x32f8,0x32f9,0x32fa,0x32fb,0x32fc,0x32fd,0x32fe,0x32ff,
+ 0x3300,0x3301,0x3302,0x3303,0x3304,0x3305,0x3306,0x3307,
+ 0x3308,0x3309,0x330a,0x330b,0x330c,0x330d,0x330e,0x330f,
+ 0x3310,0x3311,0x3312,0x3313,0x3314,0x3315,0x3316,0x3317,
+ 0x3318,0x3319,0x331a,0x331b,0x331c,0x331d,0x331e,0x331f,
+ 0x3320,0x3321,0x3322,0x3323,0x3324,0x3325,0x3326,0x3327,
+ 0x3328,0x3329,0x332a,0x332b,0x332c,0x332d,0x332e,0x332f,
+ 0x3330,0x3331,0x3332,0x3333,0x3334,0x3335,0x3336,0x3337,
+ 0x3338,0x3339,0x333a,0x333b,0x333c,0x333d,0x333e,0x333f,
+ 0x3340,0x3341,0x3342,0x3343,0x3344,0x3345,0x3346,0x3347,
+ 0x3348,0x3349,0x334a,0x334b,0x334c,0x334d,0x334e,0x334f,
+ 0x3350,0x3351,0x3352,0x3353,0x3354,0x3355,0x3356,0x3357,
+ 0x3358,0x3359,0x335a,0x335b,0x335c,0x335d,0x335e,0x335f,
+ 0x3360,0x3361,0x3362,0x3363,0x3364,0x3365,0x3366,0x3367,
+ 0x3368,0x3369,0x336a,0x336b,0x336c,0x336d,0x336e,0x336f,
+ 0x3370,0x3371,0x3372,0x3373,0x3374,0x3375,0x3376,0x3377,
+ 0x3378,0x3379,0x337a,0x337b,0x337c,0x337d,0x337e,0x337f,
+ 0x3380,0x3381,0x3382,0x3383,0x3384,0x3385,0x3386,0x3387,
+ 0x3388,0x3389,0x338a,0x338b,0x338c,0x338d,0x338e,0x338f,
+ 0x3390,0x3391,0x3392,0x3393,0x3394,0x3395,0x3396,0x3397,
+ 0x3398,0x3399,0x339a,0x339b,0x339c,0x339d,0x339e,0x339f,
+ 0x33a0,0x33a1,0x33a2,0x33a3,0x33a4,0x33a5,0x33a6,0x33a7,
+ 0x33a8,0x33a9,0x33aa,0x33ab,0x33ac,0x33ad,0x33ae,0x33af,
+ 0x33b0,0x33b1,0x33b2,0x33b3,0x33b4,0x33b5,0x33b6,0x33b7,
+ 0x33b8,0x33b9,0x33ba,0x33bb,0x33bc,0x33bd,0x33be,0x33bf,
+ 0x33c0,0x33c1,0x33c2,0x33c3,0x33c4,0x33c5,0x33c6,0x33c7,
+ 0x33c8,0x33c9,0x33ca,0x33cb,0x33cc,0x33cd,0x33ce,0x33cf,
+ 0x33d0,0x33d1,0x33d2,0x33d3,0x33d4,0x33d5,0x33d6,0x33d7,
+ 0x33d8,0x33d9,0x33da,0x33db,0x33dc,0x33dd,0x33de,0x33df,
+ 0x33e0,0x33e1,0x33e2,0x33e3,0x33e4,0x33e5,0x33e6,0x33e7,
+ 0x33e8,0x33e9,0x33ea,0x33eb,0x33ec,0x33ed,0x33ee,0x33ef,
+ 0x33f0,0x33f1,0x33f2,0x33f3,0x33f4,0x33f5,0x33f6,0x33f7,
+ 0x33f8,0x33f9,0x33fa,0x33fb,0x33fc,0x33fd,0x33fe,0x33ff,
+ 0x3400,0x3401,0x3402,0x3403,0x3404,0x3405,0x3406,0x3407,
+ 0x3408,0x3409,0x340a,0x340b,0x340c,0x340d,0x340e,0x340f,
+ 0x3410,0x3411,0x3412,0x3413,0x3414,0x3415,0x3416,0x3417,
+ 0x3418,0x3419,0x341a,0x341b,0x341c,0x341d,0x341e,0x341f,
+ 0x3420,0x3421,0x3422,0x3423,0x3424,0x3425,0x3426,0x3427,
+ 0x3428,0x3429,0x342a,0x342b,0x342c,0x342d,0x342e,0x342f,
+ 0x3430,0x3431,0x3432,0x3433,0x3434,0x3435,0x3436,0x3437,
+ 0x3438,0x3439,0x343a,0x343b,0x343c,0x343d,0x343e,0x343f,
+ 0x3440,0x3441,0x3442,0x3443,0x3444,0x3445,0x3446,0x3447,
+ 0x3448,0x3449,0x344a,0x344b,0x344c,0x344d,0x344e,0x344f,
+ 0x3450,0x3451,0x3452,0x3453,0x3454,0x3455,0x3456,0x3457,
+ 0x3458,0x3459,0x345a,0x345b,0x345c,0x345d,0x345e,0x345f,
+ 0x3460,0x3461,0x3462,0x3463,0x3464,0x3465,0x3466,0x3467,
+ 0x3468,0x3469,0x346a,0x346b,0x346c,0x346d,0x346e,0x346f,
+ 0x3470,0x3471,0x3472,0x3473,0x3474,0x3475,0x3476,0x3477,
+ 0x3478,0x3479,0x347a,0x347b,0x347c,0x347d,0x347e,0x347f,
+ 0x3480,0x3481,0x3482,0x3483,0x3484,0x3485,0x3486,0x3487,
+ 0x3488,0x3489,0x348a,0x348b,0x348c,0x348d,0x348e,0x348f,
+ 0x3490,0x3491,0x3492,0x3493,0x3494,0x3495,0x3496,0x3497,
+ 0x3498,0x3499,0x349a,0x349b,0x349c,0x349d,0x349e,0x349f,
+ 0x34a0,0x34a1,0x34a2,0x34a3,0x34a4,0x34a5,0x34a6,0x34a7,
+ 0x34a8,0x34a9,0x34aa,0x34ab,0x34ac,0x34ad,0x34ae,0x34af,
+ 0x34b0,0x34b1,0x34b2,0x34b3,0x34b4,0x34b5,0x34b6,0x34b7,
+ 0x34b8,0x34b9,0x34ba,0x34bb,0x34bc,0x34bd,0x34be,0x34bf,
+ 0x34c0,0x34c1,0x34c2,0x34c3,0x34c4,0x34c5,0x34c6,0x34c7,
+ 0x34c8,0x34c9,0x34ca,0x34cb,0x34cc,0x34cd,0x34ce,0x34cf,
+ 0x34d0,0x34d1,0x34d2,0x34d3,0x34d4,0x34d5,0x34d6,0x34d7,
+ 0x34d8,0x34d9,0x34da,0x34db,0x34dc,0x34dd,0x34de,0x34df,
+ 0x34e0,0x34e1,0x34e2,0x34e3,0x34e4,0x34e5,0x34e6,0x34e7,
+ 0x34e8,0x34e9,0x34ea,0x34eb,0x34ec,0x34ed,0x34ee,0x34ef,
+ 0x34f0,0x34f1,0x34f2,0x34f3,0x34f4,0x34f5,0x34f6,0x34f7,
+ 0x34f8,0x34f9,0x34fa,0x34fb,0x34fc,0x34fd,0x34fe,0x34ff,
+ 0x3500,0x3501,0x3502,0x3503,0x3504,0x3505,0x3506,0x3507,
+ 0x3508,0x3509,0x350a,0x350b,0x350c,0x350d,0x350e,0x350f,
+ 0x3510,0x3511,0x3512,0x3513,0x3514,0x3515,0x3516,0x3517,
+ 0x3518,0x3519,0x351a,0x351b,0x351c,0x351d,0x351e,0x351f,
+ 0x3520,0x3521,0x3522,0x3523,0x3524,0x3525,0x3526,0x3527,
+ 0x3528,0x3529,0x352a,0x352b,0x352c,0x352d,0x352e,0x352f,
+ 0x3530,0x3531,0x3532,0x3533,0x3534,0x3535,0x3536,0x3537,
+ 0x3538,0x3539,0x353a,0x353b,0x353c,0x353d,0x353e,0x353f,
+ 0x3540,0x3541,0x3542,0x3543,0x3544,0x3545,0x3546,0x3547,
+ 0x3548,0x3549,0x354a,0x354b,0x354c,0x354d,0x354e,0x354f,
+ 0x3550,0x3551,0x3552,0x3553,0x3554,0x3555,0x3556,0x3557,
+ 0x3558,0x3559,0x355a,0x355b,0x355c,0x355d,0x355e,0x355f,
+ 0x3560,0x3561,0x3562,0x3563,0x3564,0x3565,0x3566,0x3567,
+ 0x3568,0x3569,0x356a,0x356b,0x356c,0x356d,0x356e,0x356f,
+ 0x3570,0x3571,0x3572,0x3573,0x3574,0x3575,0x3576,0x3577,
+ 0x3578,0x3579,0x357a,0x357b,0x357c,0x357d,0x357e,0x357f,
+ 0x3580,0x3581,0x3582,0x3583,0x3584,0x3585,0x3586,0x3587,
+ 0x3588,0x3589,0x358a,0x358b,0x358c,0x358d,0x358e,0x358f,
+ 0x3590,0x3591,0x3592,0x3593,0x3594,0x3595,0x3596,0x3597,
+ 0x3598,0x3599,0x359a,0x359b,0x359c,0x359d,0x359e,0x359f,
+ 0x35a0,0x35a1,0x35a2,0x35a3,0x35a4,0x35a5,0x35a6,0x35a7,
+ 0x35a8,0x35a9,0x35aa,0x35ab,0x35ac,0x35ad,0x35ae,0x35af,
+ 0x35b0,0x35b1,0x35b2,0x35b3,0x35b4,0x35b5,0x35b6,0x35b7,
+ 0x35b8,0x35b9,0x35ba,0x35bb,0x35bc,0x35bd,0x35be,0x35bf,
+ 0x35c0,0x35c1,0x35c2,0x35c3,0x35c4,0x35c5,0x35c6,0x35c7,
+ 0x35c8,0x35c9,0x35ca,0x35cb,0x35cc,0x35cd,0x35ce,0x35cf,
+ 0x35d0,0x35d1,0x35d2,0x35d3,0x35d4,0x35d5,0x35d6,0x35d7,
+ 0x35d8,0x35d9,0x35da,0x35db,0x35dc,0x35dd,0x35de,0x35df,
+ 0x35e0,0x35e1,0x35e2,0x35e3,0x35e4,0x35e5,0x35e6,0x35e7,
+ 0x35e8,0x35e9,0x35ea,0x35eb,0x35ec,0x35ed,0x35ee,0x35ef,
+ 0x35f0,0x35f1,0x35f2,0x35f3,0x35f4,0x35f5,0x35f6,0x35f7,
+ 0x35f8,0x35f9,0x35fa,0x35fb,0x35fc,0x35fd,0x35fe,0x35ff,
+ 0x3600,0x3601,0x3602,0x3603,0x3604,0x3605,0x3606,0x3607,
+ 0x3608,0x3609,0x360a,0x360b,0x360c,0x360d,0x360e,0x360f,
+ 0x3610,0x3611,0x3612,0x3613,0x3614,0x3615,0x3616,0x3617,
+ 0x3618,0x3619,0x361a,0x361b,0x361c,0x361d,0x361e,0x361f,
+ 0x3620,0x3621,0x3622,0x3623,0x3624,0x3625,0x3626,0x3627,
+ 0x3628,0x3629,0x362a,0x362b,0x362c,0x362d,0x362e,0x362f,
+ 0x3630,0x3631,0x3632,0x3633,0x3634,0x3635,0x3636,0x3637,
+ 0x3638,0x3639,0x363a,0x363b,0x363c,0x363d,0x363e,0x363f,
+ 0x3640,0x3641,0x3642,0x3643,0x3644,0x3645,0x3646,0x3647,
+ 0x3648,0x3649,0x364a,0x364b,0x364c,0x364d,0x364e,0x364f,
+ 0x3650,0x3651,0x3652,0x3653,0x3654,0x3655,0x3656,0x3657,
+ 0x3658,0x3659,0x365a,0x365b,0x365c,0x365d,0x365e,0x365f,
+ 0x3660,0x3661,0x3662,0x3663,0x3664,0x3665,0x3666,0x3667,
+ 0x3668,0x3669,0x366a,0x366b,0x366c,0x366d,0x366e,0x366f,
+ 0x3670,0x3671,0x3672,0x3673,0x3674,0x3675,0x3676,0x3677,
+ 0x3678,0x3679,0x367a,0x367b,0x367c,0x367d,0x367e,0x367f,
+ 0x3680,0x3681,0x3682,0x3683,0x3684,0x3685,0x3686,0x3687,
+ 0x3688,0x3689,0x368a,0x368b,0x368c,0x368d,0x368e,0x368f,
+ 0x3690,0x3691,0x3692,0x3693,0x3694,0x3695,0x3696,0x3697,
+ 0x3698,0x3699,0x369a,0x369b,0x369c,0x369d,0x369e,0x369f,
+ 0x36a0,0x36a1,0x36a2,0x36a3,0x36a4,0x36a5,0x36a6,0x36a7,
+ 0x36a8,0x36a9,0x36aa,0x36ab,0x36ac,0x36ad,0x36ae,0x36af,
+ 0x36b0,0x36b1,0x36b2,0x36b3,0x36b4,0x36b5,0x36b6,0x36b7,
+ 0x36b8,0x36b9,0x36ba,0x36bb,0x36bc,0x36bd,0x36be,0x36bf,
+ 0x36c0,0x36c1,0x36c2,0x36c3,0x36c4,0x36c5,0x36c6,0x36c7,
+ 0x36c8,0x36c9,0x36ca,0x36cb,0x36cc,0x36cd,0x36ce,0x36cf,
+ 0x36d0,0x36d1,0x36d2,0x36d3,0x36d4,0x36d5,0x36d6,0x36d7,
+ 0x36d8,0x36d9,0x36da,0x36db,0x36dc,0x36dd,0x36de,0x36df,
+ 0x36e0,0x36e1,0x36e2,0x36e3,0x36e4,0x36e5,0x36e6,0x36e7,
+ 0x36e8,0x36e9,0x36ea,0x36eb,0x36ec,0x36ed,0x36ee,0x36ef,
+ 0x36f0,0x36f1,0x36f2,0x36f3,0x36f4,0x36f5,0x36f6,0x36f7,
+ 0x36f8,0x36f9,0x36fa,0x36fb,0x36fc,0x36fd,0x36fe,0x36ff,
+ 0x3700,0x3701,0x3702,0x3703,0x3704,0x3705,0x3706,0x3707,
+ 0x3708,0x3709,0x370a,0x370b,0x370c,0x370d,0x370e,0x370f,
+ 0x3710,0x3711,0x3712,0x3713,0x3714,0x3715,0x3716,0x3717,
+ 0x3718,0x3719,0x371a,0x371b,0x371c,0x371d,0x371e,0x371f,
+ 0x3720,0x3721,0x3722,0x3723,0x3724,0x3725,0x3726,0x3727,
+ 0x3728,0x3729,0x372a,0x372b,0x372c,0x372d,0x372e,0x372f,
+ 0x3730,0x3731,0x3732,0x3733,0x3734,0x3735,0x3736,0x3737,
+ 0x3738,0x3739,0x373a,0x373b,0x373c,0x373d,0x373e,0x373f,
+ 0x3740,0x3741,0x3742,0x3743,0x3744,0x3745,0x3746,0x3747,
+ 0x3748,0x3749,0x374a,0x374b,0x374c,0x374d,0x374e,0x374f,
+ 0x3750,0x3751,0x3752,0x3753,0x3754,0x3755,0x3756,0x3757,
+ 0x3758,0x3759,0x375a,0x375b,0x375c,0x375d,0x375e,0x375f,
+ 0x3760,0x3761,0x3762,0x3763,0x3764,0x3765,0x3766,0x3767,
+ 0x3768,0x3769,0x376a,0x376b,0x376c,0x376d,0x376e,0x376f,
+ 0x3770,0x3771,0x3772,0x3773,0x3774,0x3775,0x3776,0x3777,
+ 0x3778,0x3779,0x377a,0x377b,0x377c,0x377d,0x377e,0x377f,
+ 0x3780,0x3781,0x3782,0x3783,0x3784,0x3785,0x3786,0x3787,
+ 0x3788,0x3789,0x378a,0x378b,0x378c,0x378d,0x378e,0x378f,
+ 0x3790,0x3791,0x3792,0x3793,0x3794,0x3795,0x3796,0x3797,
+ 0x3798,0x3799,0x379a,0x379b,0x379c,0x379d,0x379e,0x379f,
+ 0x37a0,0x37a1,0x37a2,0x37a3,0x37a4,0x37a5,0x37a6,0x37a7,
+ 0x37a8,0x37a9,0x37aa,0x37ab,0x37ac,0x37ad,0x37ae,0x37af,
+ 0x37b0,0x37b1,0x37b2,0x37b3,0x37b4,0x37b5,0x37b6,0x37b7,
+ 0x37b8,0x37b9,0x37ba,0x37bb,0x37bc,0x37bd,0x37be,0x37bf,
+ 0x37c0,0x37c1,0x37c2,0x37c3,0x37c4,0x37c5,0x37c6,0x37c7,
+ 0x37c8,0x37c9,0x37ca,0x37cb,0x37cc,0x37cd,0x37ce,0x37cf,
+ 0x37d0,0x37d1,0x37d2,0x37d3,0x37d4,0x37d5,0x37d6,0x37d7,
+ 0x37d8,0x37d9,0x37da,0x37db,0x37dc,0x37dd,0x37de,0x37df,
+ 0x37e0,0x37e1,0x37e2,0x37e3,0x37e4,0x37e5,0x37e6,0x37e7,
+ 0x37e8,0x37e9,0x37ea,0x37eb,0x37ec,0x37ed,0x37ee,0x37ef,
+ 0x37f0,0x37f1,0x37f2,0x37f3,0x37f4,0x37f5,0x37f6,0x37f7,
+ 0x37f8,0x37f9,0x37fa,0x37fb,0x37fc,0x37fd,0x37fe,0x37ff,
+ 0x3800,0x3801,0x3802,0x3803,0x3804,0x3805,0x3806,0x3807,
+ 0x3808,0x3809,0x380a,0x380b,0x380c,0x380d,0x380e,0x380f,
+ 0x3810,0x3811,0x3812,0x3813,0x3814,0x3815,0x3816,0x3817,
+ 0x3818,0x3819,0x381a,0x381b,0x381c,0x381d,0x381e,0x381f,
+ 0x3820,0x3821,0x3822,0x3823,0x3824,0x3825,0x3826,0x3827,
+ 0x3828,0x3829,0x382a,0x382b,0x382c,0x382d,0x382e,0x382f,
+ 0x3830,0x3831,0x3832,0x3833,0x3834,0x3835,0x3836,0x3837,
+ 0x3838,0x3839,0x383a,0x383b,0x383c,0x383d,0x383e,0x383f,
+ 0x3840,0x3841,0x3842,0x3843,0x3844,0x3845,0x3846,0x3847,
+ 0x3848,0x3849,0x384a,0x384b,0x384c,0x384d,0x384e,0x384f,
+ 0x3850,0x3851,0x3852,0x3853,0x3854,0x3855,0x3856,0x3857,
+ 0x3858,0x3859,0x385a,0x385b,0x385c,0x385d,0x385e,0x385f,
+ 0x3860,0x3861,0x3862,0x3863,0x3864,0x3865,0x3866,0x3867,
+ 0x3868,0x3869,0x386a,0x386b,0x386c,0x386d,0x386e,0x386f,
+ 0x3870,0x3871,0x3872,0x3873,0x3874,0x3875,0x3876,0x3877,
+ 0x3878,0x3879,0x387a,0x387b,0x387c,0x387d,0x387e,0x387f,
+ 0x3880,0x3881,0x3882,0x3883,0x3884,0x3885,0x3886,0x3887,
+ 0x3888,0x3889,0x388a,0x388b,0x388c,0x388d,0x388e,0x388f,
+ 0x3890,0x3891,0x3892,0x3893,0x3894,0x3895,0x3896,0x3897,
+ 0x3898,0x3899,0x389a,0x389b,0x389c,0x389d,0x389e,0x389f,
+ 0x38a0,0x38a1,0x38a2,0x38a3,0x38a4,0x38a5,0x38a6,0x38a7,
+ 0x38a8,0x38a9,0x38aa,0x38ab,0x38ac,0x38ad,0x38ae,0x38af,
+ 0x38b0,0x38b1,0x38b2,0x38b3,0x38b4,0x38b5,0x38b6,0x38b7,
+ 0x38b8,0x38b9,0x38ba,0x38bb,0x38bc,0x38bd,0x38be,0x38bf,
+ 0x38c0,0x38c1,0x38c2,0x38c3,0x38c4,0x38c5,0x38c6,0x38c7,
+ 0x38c8,0x38c9,0x38ca,0x38cb,0x38cc,0x38cd,0x38ce,0x38cf,
+ 0x38d0,0x38d1,0x38d2,0x38d3,0x38d4,0x38d5,0x38d6,0x38d7,
+ 0x38d8,0x38d9,0x38da,0x38db,0x38dc,0x38dd,0x38de,0x38df,
+ 0x38e0,0x38e1,0x38e2,0x38e3,0x38e4,0x38e5,0x38e6,0x38e7,
+ 0x38e8,0x38e9,0x38ea,0x38eb,0x38ec,0x38ed,0x38ee,0x38ef,
+ 0x38f0,0x38f1,0x38f2,0x38f3,0x38f4,0x38f5,0x38f6,0x38f7,
+ 0x38f8,0x38f9,0x38fa,0x38fb,0x38fc,0x38fd,0x38fe,0x38ff,
+ 0x3900,0x3901,0x3902,0x3903,0x3904,0x3905,0x3906,0x3907,
+ 0x3908,0x3909,0x390a,0x390b,0x390c,0x390d,0x390e,0x390f,
+ 0x3910,0x3911,0x3912,0x3913,0x3914,0x3915,0x3916,0x3917,
+ 0x3918,0x3919,0x391a,0x391b,0x391c,0x391d,0x391e,0x391f,
+ 0x3920,0x3921,0x3922,0x3923,0x3924,0x3925,0x3926,0x3927,
+ 0x3928,0x3929,0x392a,0x392b,0x392c,0x392d,0x392e,0x392f,
+ 0x3930,0x3931,0x3932,0x3933,0x3934,0x3935,0x3936,0x3937,
+ 0x3938,0x3939,0x393a,0x393b,0x393c,0x393d,0x393e,0x393f,
+ 0x3940,0x3941,0x3942,0x3943,0x3944,0x3945,0x3946,0x3947,
+ 0x3948,0x3949,0x394a,0x394b,0x394c,0x394d,0x394e,0x394f,
+ 0x3950,0x3951,0x3952,0x3953,0x3954,0x3955,0x3956,0x3957,
+ 0x3958,0x3959,0x395a,0x395b,0x395c,0x395d,0x395e,0x395f,
+ 0x3960,0x3961,0x3962,0x3963,0x3964,0x3965,0x3966,0x3967,
+ 0x3968,0x3969,0x396a,0x396b,0x396c,0x396d,0x396e,0x396f,
+ 0x3970,0x3971,0x3972,0x3973,0x3974,0x3975,0x3976,0x3977,
+ 0x3978,0x3979,0x397a,0x397b,0x397c,0x397d,0x397e,0x397f,
+ 0x3980,0x3981,0x3982,0x3983,0x3984,0x3985,0x3986,0x3987,
+ 0x3988,0x3989,0x398a,0x398b,0x398c,0x398d,0x398e,0x398f,
+ 0x3990,0x3991,0x3992,0x3993,0x3994,0x3995,0x3996,0x3997,
+ 0x3998,0x3999,0x399a,0x399b,0x399c,0x399d,0x399e,0x399f,
+ 0x39a0,0x39a1,0x39a2,0x39a3,0x39a4,0x39a5,0x39a6,0x39a7,
+ 0x39a8,0x39a9,0x39aa,0x39ab,0x39ac,0x39ad,0x39ae,0x39af,
+ 0x39b0,0x39b1,0x39b2,0x39b3,0x39b4,0x39b5,0x39b6,0x39b7,
+ 0x39b8,0x39b9,0x39ba,0x39bb,0x39bc,0x39bd,0x39be,0x39bf,
+ 0x39c0,0x39c1,0x39c2,0x39c3,0x39c4,0x39c5,0x39c6,0x39c7,
+ 0x39c8,0x39c9,0x39ca,0x39cb,0x39cc,0x39cd,0x39ce,0x39cf,
+ 0x39d0,0x39d1,0x39d2,0x39d3,0x39d4,0x39d5,0x39d6,0x39d7,
+ 0x39d8,0x39d9,0x39da,0x39db,0x39dc,0x39dd,0x39de,0x39df,
+ 0x39e0,0x39e1,0x39e2,0x39e3,0x39e4,0x39e5,0x39e6,0x39e7,
+ 0x39e8,0x39e9,0x39ea,0x39eb,0x39ec,0x39ed,0x39ee,0x39ef,
+ 0x39f0,0x39f1,0x39f2,0x39f3,0x39f4,0x39f5,0x39f6,0x39f7,
+ 0x39f8,0x39f9,0x39fa,0x39fb,0x39fc,0x39fd,0x39fe,0x39ff,
+ 0x3a00,0x3a01,0x3a02,0x3a03,0x3a04,0x3a05,0x3a06,0x3a07,
+ 0x3a08,0x3a09,0x3a0a,0x3a0b,0x3a0c,0x3a0d,0x3a0e,0x3a0f,
+ 0x3a10,0x3a11,0x3a12,0x3a13,0x3a14,0x3a15,0x3a16,0x3a17,
+ 0x3a18,0x3a19,0x3a1a,0x3a1b,0x3a1c,0x3a1d,0x3a1e,0x3a1f,
+ 0x3a20,0x3a21,0x3a22,0x3a23,0x3a24,0x3a25,0x3a26,0x3a27,
+ 0x3a28,0x3a29,0x3a2a,0x3a2b,0x3a2c,0x3a2d,0x3a2e,0x3a2f,
+ 0x3a30,0x3a31,0x3a32,0x3a33,0x3a34,0x3a35,0x3a36,0x3a37,
+ 0x3a38,0x3a39,0x3a3a,0x3a3b,0x3a3c,0x3a3d,0x3a3e,0x3a3f,
+ 0x3a40,0x3a41,0x3a42,0x3a43,0x3a44,0x3a45,0x3a46,0x3a47,
+ 0x3a48,0x3a49,0x3a4a,0x3a4b,0x3a4c,0x3a4d,0x3a4e,0x3a4f,
+ 0x3a50,0x3a51,0x3a52,0x3a53,0x3a54,0x3a55,0x3a56,0x3a57,
+ 0x3a58,0x3a59,0x3a5a,0x3a5b,0x3a5c,0x3a5d,0x3a5e,0x3a5f,
+ 0x3a60,0x3a61,0x3a62,0x3a63,0x3a64,0x3a65,0x3a66,0x3a67,
+ 0x3a68,0x3a69,0x3a6a,0x3a6b,0x3a6c,0x3a6d,0x3a6e,0x3a6f,
+ 0x3a70,0x3a71,0x3a72,0x3a73,0x3a74,0x3a75,0x3a76,0x3a77,
+ 0x3a78,0x3a79,0x3a7a,0x3a7b,0x3a7c,0x3a7d,0x3a7e,0x3a7f,
+ 0x3a80,0x3a81,0x3a82,0x3a83,0x3a84,0x3a85,0x3a86,0x3a87,
+ 0x3a88,0x3a89,0x3a8a,0x3a8b,0x3a8c,0x3a8d,0x3a8e,0x3a8f,
+ 0x3a90,0x3a91,0x3a92,0x3a93,0x3a94,0x3a95,0x3a96,0x3a97,
+ 0x3a98,0x3a99,0x3a9a,0x3a9b,0x3a9c,0x3a9d,0x3a9e,0x3a9f,
+ 0x3aa0,0x3aa1,0x3aa2,0x3aa3,0x3aa4,0x3aa5,0x3aa6,0x3aa7,
+ 0x3aa8,0x3aa9,0x3aaa,0x3aab,0x3aac,0x3aad,0x3aae,0x3aaf,
+ 0x3ab0,0x3ab1,0x3ab2,0x3ab3,0x3ab4,0x3ab5,0x3ab6,0x3ab7,
+ 0x3ab8,0x3ab9,0x3aba,0x3abb,0x3abc,0x3abd,0x3abe,0x3abf,
+ 0x3ac0,0x3ac1,0x3ac2,0x3ac3,0x3ac4,0x3ac5,0x3ac6,0x3ac7,
+ 0x3ac8,0x3ac9,0x3aca,0x3acb,0x3acc,0x3acd,0x3ace,0x3acf,
+ 0x3ad0,0x3ad1,0x3ad2,0x3ad3,0x3ad4,0x3ad5,0x3ad6,0x3ad7,
+ 0x3ad8,0x3ad9,0x3ada,0x3adb,0x3adc,0x3add,0x3ade,0x3adf,
+ 0x3ae0,0x3ae1,0x3ae2,0x3ae3,0x3ae4,0x3ae5,0x3ae6,0x3ae7,
+ 0x3ae8,0x3ae9,0x3aea,0x3aeb,0x3aec,0x3aed,0x3aee,0x3aef,
+ 0x3af0,0x3af1,0x3af2,0x3af3,0x3af4,0x3af5,0x3af6,0x3af7,
+ 0x3af8,0x3af9,0x3afa,0x3afb,0x3afc,0x3afd,0x3afe,0x3aff,
+ 0x3b00,0x3b01,0x3b02,0x3b03,0x3b04,0x3b05,0x3b06,0x3b07,
+ 0x3b08,0x3b09,0x3b0a,0x3b0b,0x3b0c,0x3b0d,0x3b0e,0x3b0f,
+ 0x3b10,0x3b11,0x3b12,0x3b13,0x3b14,0x3b15,0x3b16,0x3b17,
+ 0x3b18,0x3b19,0x3b1a,0x3b1b,0x3b1c,0x3b1d,0x3b1e,0x3b1f,
+ 0x3b20,0x3b21,0x3b22,0x3b23,0x3b24,0x3b25,0x3b26,0x3b27,
+ 0x3b28,0x3b29,0x3b2a,0x3b2b,0x3b2c,0x3b2d,0x3b2e,0x3b2f,
+ 0x3b30,0x3b31,0x3b32,0x3b33,0x3b34,0x3b35,0x3b36,0x3b37,
+ 0x3b38,0x3b39,0x3b3a,0x3b3b,0x3b3c,0x3b3d,0x3b3e,0x3b3f,
+ 0x3b40,0x3b41,0x3b42,0x3b43,0x3b44,0x3b45,0x3b46,0x3b47,
+ 0x3b48,0x3b49,0x3b4a,0x3b4b,0x3b4c,0x3b4d,0x3b4e,0x3b4f,
+ 0x3b50,0x3b51,0x3b52,0x3b53,0x3b54,0x3b55,0x3b56,0x3b57,
+ 0x3b58,0x3b59,0x3b5a,0x3b5b,0x3b5c,0x3b5d,0x3b5e,0x3b5f,
+ 0x3b60,0x3b61,0x3b62,0x3b63,0x3b64,0x3b65,0x3b66,0x3b67,
+ 0x3b68,0x3b69,0x3b6a,0x3b6b,0x3b6c,0x3b6d,0x3b6e,0x3b6f,
+ 0x3b70,0x3b71,0x3b72,0x3b73,0x3b74,0x3b75,0x3b76,0x3b77,
+ 0x3b78,0x3b79,0x3b7a,0x3b7b,0x3b7c,0x3b7d,0x3b7e,0x3b7f,
+ 0x3b80,0x3b81,0x3b82,0x3b83,0x3b84,0x3b85,0x3b86,0x3b87,
+ 0x3b88,0x3b89,0x3b8a,0x3b8b,0x3b8c,0x3b8d,0x3b8e,0x3b8f,
+ 0x3b90,0x3b91,0x3b92,0x3b93,0x3b94,0x3b95,0x3b96,0x3b97,
+ 0x3b98,0x3b99,0x3b9a,0x3b9b,0x3b9c,0x3b9d,0x3b9e,0x3b9f,
+ 0x3ba0,0x3ba1,0x3ba2,0x3ba3,0x3ba4,0x3ba5,0x3ba6,0x3ba7,
+ 0x3ba8,0x3ba9,0x3baa,0x3bab,0x3bac,0x3bad,0x3bae,0x3baf,
+ 0x3bb0,0x3bb1,0x3bb2,0x3bb3,0x3bb4,0x3bb5,0x3bb6,0x3bb7,
+ 0x3bb8,0x3bb9,0x3bba,0x3bbb,0x3bbc,0x3bbd,0x3bbe,0x3bbf,
+ 0x3bc0,0x3bc1,0x3bc2,0x3bc3,0x3bc4,0x3bc5,0x3bc6,0x3bc7,
+ 0x3bc8,0x3bc9,0x3bca,0x3bcb,0x3bcc,0x3bcd,0x3bce,0x3bcf,
+ 0x3bd0,0x3bd1,0x3bd2,0x3bd3,0x3bd4,0x3bd5,0x3bd6,0x3bd7,
+ 0x3bd8,0x3bd9,0x3bda,0x3bdb,0x3bdc,0x3bdd,0x3bde,0x3bdf,
+ 0x3be0,0x3be1,0x3be2,0x3be3,0x3be4,0x3be5,0x3be6,0x3be7,
+ 0x3be8,0x3be9,0x3bea,0x3beb,0x3bec,0x3bed,0x3bee,0x3bef,
+ 0x3bf0,0x3bf1,0x3bf2,0x3bf3,0x3bf4,0x3bf5,0x3bf6,0x3bf7,
+ 0x3bf8,0x3bf9,0x3bfa,0x3bfb,0x3bfc,0x3bfd,0x3bfe,0x3bff,
+ 0x3c00,0x3c01,0x3c02,0x3c03,0x3c04,0x3c05,0x3c06,0x3c07,
+ 0x3c08,0x3c09,0x3c0a,0x3c0b,0x3c0c,0x3c0d,0x3c0e,0x3c0f,
+ 0x3c10,0x3c11,0x3c12,0x3c13,0x3c14,0x3c15,0x3c16,0x3c17,
+ 0x3c18,0x3c19,0x3c1a,0x3c1b,0x3c1c,0x3c1d,0x3c1e,0x3c1f,
+ 0x3c20,0x3c21,0x3c22,0x3c23,0x3c24,0x3c25,0x3c26,0x3c27,
+ 0x3c28,0x3c29,0x3c2a,0x3c2b,0x3c2c,0x3c2d,0x3c2e,0x3c2f,
+ 0x3c30,0x3c31,0x3c32,0x3c33,0x3c34,0x3c35,0x3c36,0x3c37,
+ 0x3c38,0x3c39,0x3c3a,0x3c3b,0x3c3c,0x3c3d,0x3c3e,0x3c3f,
+ 0x3c40,0x3c41,0x3c42,0x3c43,0x3c44,0x3c45,0x3c46,0x3c47,
+ 0x3c48,0x3c49,0x3c4a,0x3c4b,0x3c4c,0x3c4d,0x3c4e,0x3c4f,
+ 0x3c50,0x3c51,0x3c52,0x3c53,0x3c54,0x3c55,0x3c56,0x3c57,
+ 0x3c58,0x3c59,0x3c5a,0x3c5b,0x3c5c,0x3c5d,0x3c5e,0x3c5f,
+ 0x3c60,0x3c61,0x3c62,0x3c63,0x3c64,0x3c65,0x3c66,0x3c67,
+ 0x3c68,0x3c69,0x3c6a,0x3c6b,0x3c6c,0x3c6d,0x3c6e,0x3c6f,
+ 0x3c70,0x3c71,0x3c72,0x3c73,0x3c74,0x3c75,0x3c76,0x3c77,
+ 0x3c78,0x3c79,0x3c7a,0x3c7b,0x3c7c,0x3c7d,0x3c7e,0x3c7f,
+ 0x3c80,0x3c81,0x3c82,0x3c83,0x3c84,0x3c85,0x3c86,0x3c87,
+ 0x3c88,0x3c89,0x3c8a,0x3c8b,0x3c8c,0x3c8d,0x3c8e,0x3c8f,
+ 0x3c90,0x3c91,0x3c92,0x3c93,0x3c94,0x3c95,0x3c96,0x3c97,
+ 0x3c98,0x3c99,0x3c9a,0x3c9b,0x3c9c,0x3c9d,0x3c9e,0x3c9f,
+ 0x3ca0,0x3ca1,0x3ca2,0x3ca3,0x3ca4,0x3ca5,0x3ca6,0x3ca7,
+ 0x3ca8,0x3ca9,0x3caa,0x3cab,0x3cac,0x3cad,0x3cae,0x3caf,
+ 0x3cb0,0x3cb1,0x3cb2,0x3cb3,0x3cb4,0x3cb5,0x3cb6,0x3cb7,
+ 0x3cb8,0x3cb9,0x3cba,0x3cbb,0x3cbc,0x3cbd,0x3cbe,0x3cbf,
+ 0x3cc0,0x3cc1,0x3cc2,0x3cc3,0x3cc4,0x3cc5,0x3cc6,0x3cc7,
+ 0x3cc8,0x3cc9,0x3cca,0x3ccb,0x3ccc,0x3ccd,0x3cce,0x3ccf,
+ 0x3cd0,0x3cd1,0x3cd2,0x3cd3,0x3cd4,0x3cd5,0x3cd6,0x3cd7,
+ 0x3cd8,0x3cd9,0x3cda,0x3cdb,0x3cdc,0x3cdd,0x3cde,0x3cdf,
+ 0x3ce0,0x3ce1,0x3ce2,0x3ce3,0x3ce4,0x3ce5,0x3ce6,0x3ce7,
+ 0x3ce8,0x3ce9,0x3cea,0x3ceb,0x3cec,0x3ced,0x3cee,0x3cef,
+ 0x3cf0,0x3cf1,0x3cf2,0x3cf3,0x3cf4,0x3cf5,0x3cf6,0x3cf7,
+ 0x3cf8,0x3cf9,0x3cfa,0x3cfb,0x3cfc,0x3cfd,0x3cfe,0x3cff,
+ 0x3d00,0x3d01,0x3d02,0x3d03,0x3d04,0x3d05,0x3d06,0x3d07,
+ 0x3d08,0x3d09,0x3d0a,0x3d0b,0x3d0c,0x3d0d,0x3d0e,0x3d0f,
+ 0x3d10,0x3d11,0x3d12,0x3d13,0x3d14,0x3d15,0x3d16,0x3d17,
+ 0x3d18,0x3d19,0x3d1a,0x3d1b,0x3d1c,0x3d1d,0x3d1e,0x3d1f,
+ 0x3d20,0x3d21,0x3d22,0x3d23,0x3d24,0x3d25,0x3d26,0x3d27,
+ 0x3d28,0x3d29,0x3d2a,0x3d2b,0x3d2c,0x3d2d,0x3d2e,0x3d2f,
+ 0x3d30,0x3d31,0x3d32,0x3d33,0x3d34,0x3d35,0x3d36,0x3d37,
+ 0x3d38,0x3d39,0x3d3a,0x3d3b,0x3d3c,0x3d3d,0x3d3e,0x3d3f,
+ 0x3d40,0x3d41,0x3d42,0x3d43,0x3d44,0x3d45,0x3d46,0x3d47,
+ 0x3d48,0x3d49,0x3d4a,0x3d4b,0x3d4c,0x3d4d,0x3d4e,0x3d4f,
+ 0x3d50,0x3d51,0x3d52,0x3d53,0x3d54,0x3d55,0x3d56,0x3d57,
+ 0x3d58,0x3d59,0x3d5a,0x3d5b,0x3d5c,0x3d5d,0x3d5e,0x3d5f,
+ 0x3d60,0x3d61,0x3d62,0x3d63,0x3d64,0x3d65,0x3d66,0x3d67,
+ 0x3d68,0x3d69,0x3d6a,0x3d6b,0x3d6c,0x3d6d,0x3d6e,0x3d6f,
+ 0x3d70,0x3d71,0x3d72,0x3d73,0x3d74,0x3d75,0x3d76,0x3d77,
+ 0x3d78,0x3d79,0x3d7a,0x3d7b,0x3d7c,0x3d7d,0x3d7e,0x3d7f,
+ 0x3d80,0x3d81,0x3d82,0x3d83,0x3d84,0x3d85,0x3d86,0x3d87,
+ 0x3d88,0x3d89,0x3d8a,0x3d8b,0x3d8c,0x3d8d,0x3d8e,0x3d8f,
+ 0x3d90,0x3d91,0x3d92,0x3d93,0x3d94,0x3d95,0x3d96,0x3d97,
+ 0x3d98,0x3d99,0x3d9a,0x3d9b,0x3d9c,0x3d9d,0x3d9e,0x3d9f,
+ 0x3da0,0x3da1,0x3da2,0x3da3,0x3da4,0x3da5,0x3da6,0x3da7,
+ 0x3da8,0x3da9,0x3daa,0x3dab,0x3dac,0x3dad,0x3dae,0x3daf,
+ 0x3db0,0x3db1,0x3db2,0x3db3,0x3db4,0x3db5,0x3db6,0x3db7,
+ 0x3db8,0x3db9,0x3dba,0x3dbb,0x3dbc,0x3dbd,0x3dbe,0x3dbf,
+ 0x3dc0,0x3dc1,0x3dc2,0x3dc3,0x3dc4,0x3dc5,0x3dc6,0x3dc7,
+ 0x3dc8,0x3dc9,0x3dca,0x3dcb,0x3dcc,0x3dcd,0x3dce,0x3dcf,
+ 0x3dd0,0x3dd1,0x3dd2,0x3dd3,0x3dd4,0x3dd5,0x3dd6,0x3dd7,
+ 0x3dd8,0x3dd9,0x3dda,0x3ddb,0x3ddc,0x3ddd,0x3dde,0x3ddf,
+ 0x3de0,0x3de1,0x3de2,0x3de3,0x3de4,0x3de5,0x3de6,0x3de7,
+ 0x3de8,0x3de9,0x3dea,0x3deb,0x3dec,0x3ded,0x3dee,0x3def,
+ 0x3df0,0x3df1,0x3df2,0x3df3,0x3df4,0x3df5,0x3df6,0x3df7,
+ 0x3df8,0x3df9,0x3dfa,0x3dfb,0x3dfc,0x3dfd,0x3dfe,0x3dff,
+ 0x3e00,0x3e01,0x3e02,0x3e03,0x3e04,0x3e05,0x3e06,0x3e07,
+ 0x3e08,0x3e09,0x3e0a,0x3e0b,0x3e0c,0x3e0d,0x3e0e,0x3e0f,
+ 0x3e10,0x3e11,0x3e12,0x3e13,0x3e14,0x3e15,0x3e16,0x3e17,
+ 0x3e18,0x3e19,0x3e1a,0x3e1b,0x3e1c,0x3e1d,0x3e1e,0x3e1f,
+ 0x3e20,0x3e21,0x3e22,0x3e23,0x3e24,0x3e25,0x3e26,0x3e27,
+ 0x3e28,0x3e29,0x3e2a,0x3e2b,0x3e2c,0x3e2d,0x3e2e,0x3e2f,
+ 0x3e30,0x3e31,0x3e32,0x3e33,0x3e34,0x3e35,0x3e36,0x3e37,
+ 0x3e38,0x3e39,0x3e3a,0x3e3b,0x3e3c,0x3e3d,0x3e3e,0x3e3f,
+ 0x3e40,0x3e41,0x3e42,0x3e43,0x3e44,0x3e45,0x3e46,0x3e47,
+ 0x3e48,0x3e49,0x3e4a,0x3e4b,0x3e4c,0x3e4d,0x3e4e,0x3e4f,
+ 0x3e50,0x3e51,0x3e52,0x3e53,0x3e54,0x3e55,0x3e56,0x3e57,
+ 0x3e58,0x3e59,0x3e5a,0x3e5b,0x3e5c,0x3e5d,0x3e5e,0x3e5f,
+ 0x3e60,0x3e61,0x3e62,0x3e63,0x3e64,0x3e65,0x3e66,0x3e67,
+ 0x3e68,0x3e69,0x3e6a,0x3e6b,0x3e6c,0x3e6d,0x3e6e,0x3e6f,
+ 0x3e70,0x3e71,0x3e72,0x3e73,0x3e74,0x3e75,0x3e76,0x3e77,
+ 0x3e78,0x3e79,0x3e7a,0x3e7b,0x3e7c,0x3e7d,0x3e7e,0x3e7f,
+ 0x3e80,0x3e81,0x3e82,0x3e83,0x3e84,0x3e85,0x3e86,0x3e87,
+ 0x3e88,0x3e89,0x3e8a,0x3e8b,0x3e8c,0x3e8d,0x3e8e,0x3e8f,
+ 0x3e90,0x3e91,0x3e92,0x3e93,0x3e94,0x3e95,0x3e96,0x3e97,
+ 0x3e98,0x3e99,0x3e9a,0x3e9b,0x3e9c,0x3e9d,0x3e9e,0x3e9f,
+ 0x3ea0,0x3ea1,0x3ea2,0x3ea3,0x3ea4,0x3ea5,0x3ea6,0x3ea7,
+ 0x3ea8,0x3ea9,0x3eaa,0x3eab,0x3eac,0x3ead,0x3eae,0x3eaf,
+ 0x3eb0,0x3eb1,0x3eb2,0x3eb3,0x3eb4,0x3eb5,0x3eb6,0x3eb7,
+ 0x3eb8,0x3eb9,0x3eba,0x3ebb,0x3ebc,0x3ebd,0x3ebe,0x3ebf,
+ 0x3ec0,0x3ec1,0x3ec2,0x3ec3,0x3ec4,0x3ec5,0x3ec6,0x3ec7,
+ 0x3ec8,0x3ec9,0x3eca,0x3ecb,0x3ecc,0x3ecd,0x3ece,0x3ecf,
+ 0x3ed0,0x3ed1,0x3ed2,0x3ed3,0x3ed4,0x3ed5,0x3ed6,0x3ed7,
+ 0x3ed8,0x3ed9,0x3eda,0x3edb,0x3edc,0x3edd,0x3ede,0x3edf,
+ 0x3ee0,0x3ee1,0x3ee2,0x3ee3,0x3ee4,0x3ee5,0x3ee6,0x3ee7,
+ 0x3ee8,0x3ee9,0x3eea,0x3eeb,0x3eec,0x3eed,0x3eee,0x3eef,
+ 0x3ef0,0x3ef1,0x3ef2,0x3ef3,0x3ef4,0x3ef5,0x3ef6,0x3ef7,
+ 0x3ef8,0x3ef9,0x3efa,0x3efb,0x3efc,0x3efd,0x3efe,0x3eff,
+ 0x3f00,0x3f01,0x3f02,0x3f03,0x3f04,0x3f05,0x3f06,0x3f07,
+ 0x3f08,0x3f09,0x3f0a,0x3f0b,0x3f0c,0x3f0d,0x3f0e,0x3f0f,
+ 0x3f10,0x3f11,0x3f12,0x3f13,0x3f14,0x3f15,0x3f16,0x3f17,
+ 0x3f18,0x3f19,0x3f1a,0x3f1b,0x3f1c,0x3f1d,0x3f1e,0x3f1f,
+ 0x3f20,0x3f21,0x3f22,0x3f23,0x3f24,0x3f25,0x3f26,0x3f27,
+ 0x3f28,0x3f29,0x3f2a,0x3f2b,0x3f2c,0x3f2d,0x3f2e,0x3f2f,
+ 0x3f30,0x3f31,0x3f32,0x3f33,0x3f34,0x3f35,0x3f36,0x3f37,
+ 0x3f38,0x3f39,0x3f3a,0x3f3b,0x3f3c,0x3f3d,0x3f3e,0x3f3f,
+ 0x3f40,0x3f41,0x3f42,0x3f43,0x3f44,0x3f45,0x3f46,0x3f47,
+ 0x3f48,0x3f49,0x3f4a,0x3f4b,0x3f4c,0x3f4d,0x3f4e,0x3f4f,
+ 0x3f50,0x3f51,0x3f52,0x3f53,0x3f54,0x3f55,0x3f56,0x3f57,
+ 0x3f58,0x3f59,0x3f5a,0x3f5b,0x3f5c,0x3f5d,0x3f5e,0x3f5f,
+ 0x3f60,0x3f61,0x3f62,0x3f63,0x3f64,0x3f65,0x3f66,0x3f67,
+ 0x3f68,0x3f69,0x3f6a,0x3f6b,0x3f6c,0x3f6d,0x3f6e,0x3f6f,
+ 0x3f70,0x3f71,0x3f72,0x3f73,0x3f74,0x3f75,0x3f76,0x3f77,
+ 0x3f78,0x3f79,0x3f7a,0x3f7b,0x3f7c,0x3f7d,0x3f7e,0x3f7f,
+ 0x3f80,0x3f81,0x3f82,0x3f83,0x3f84,0x3f85,0x3f86,0x3f87,
+ 0x3f88,0x3f89,0x3f8a,0x3f8b,0x3f8c,0x3f8d,0x3f8e,0x3f8f,
+ 0x3f90,0x3f91,0x3f92,0x3f93,0x3f94,0x3f95,0x3f96,0x3f97,
+ 0x3f98,0x3f99,0x3f9a,0x3f9b,0x3f9c,0x3f9d,0x3f9e,0x3f9f,
+ 0x3fa0,0x3fa1,0x3fa2,0x3fa3,0x3fa4,0x3fa5,0x3fa6,0x3fa7,
+ 0x3fa8,0x3fa9,0x3faa,0x3fab,0x3fac,0x3fad,0x3fae,0x3faf,
+ 0x3fb0,0x3fb1,0x3fb2,0x3fb3,0x3fb4,0x3fb5,0x3fb6,0x3fb7,
+ 0x3fb8,0x3fb9,0x3fba,0x3fbb,0x3fbc,0x3fbd,0x3fbe,0x3fbf,
+ 0x3fc0,0x3fc1,0x3fc2,0x3fc3,0x3fc4,0x3fc5,0x3fc6,0x3fc7,
+ 0x3fc8,0x3fc9,0x3fca,0x3fcb,0x3fcc,0x3fcd,0x3fce,0x3fcf,
+ 0x3fd0,0x3fd1,0x3fd2,0x3fd3,0x3fd4,0x3fd5,0x3fd6,0x3fd7,
+ 0x3fd8,0x3fd9,0x3fda,0x3fdb,0x3fdc,0x3fdd,0x3fde,0x3fdf,
+ 0x3fe0,0x3fe1,0x3fe2,0x3fe3,0x3fe4,0x3fe5,0x3fe6,0x3fe7,
+ 0x3fe8,0x3fe9,0x3fea,0x3feb,0x3fec,0x3fed,0x3fee,0x3fef,
+ 0x3ff0,0x3ff1,0x3ff2,0x3ff3,0x3ff4,0x3ff5,0x3ff6,0x3ff7,
+ 0x3ff8,0x3ff9,0x3ffa,0x3ffb,0x3ffc,0x3ffd,0x3ffe,0x3fff,
+ 0x4000,0x4001,0x4002,0x4003,0x4004,0x4005,0x4006,0x4007,
+ 0x4008,0x4009,0x400a,0x400b,0x400c,0x400d,0x400e,0x400f,
+ 0x4010,0x4011,0x4012,0x4013,0x4014,0x4015,0x4016,0x4017,
+ 0x4018,0x4019,0x401a,0x401b,0x401c,0x401d,0x401e,0x401f,
+ 0x4020,0x4021,0x4022,0x4023,0x4024,0x4025,0x4026,0x4027,
+ 0x4028,0x4029,0x402a,0x402b,0x402c,0x402d,0x402e,0x402f,
+ 0x4030,0x4031,0x4032,0x4033,0x4034,0x4035,0x4036,0x4037,
+ 0x4038,0x4039,0x403a,0x403b,0x403c,0x403d,0x403e,0x403f,
+ 0x4040,0x4041,0x4042,0x4043,0x4044,0x4045,0x4046,0x4047,
+ 0x4048,0x4049,0x404a,0x404b,0x404c,0x404d,0x404e,0x404f,
+ 0x4050,0x4051,0x4052,0x4053,0x4054,0x4055,0x4056,0x4057,
+ 0x4058,0x4059,0x405a,0x405b,0x405c,0x405d,0x405e,0x405f,
+ 0x4060,0x4061,0x4062,0x4063,0x4064,0x4065,0x4066,0x4067,
+ 0x4068,0x4069,0x406a,0x406b,0x406c,0x406d,0x406e,0x406f,
+ 0x4070,0x4071,0x4072,0x4073,0x4074,0x4075,0x4076,0x4077,
+ 0x4078,0x4079,0x407a,0x407b,0x407c,0x407d,0x407e,0x407f,
+ 0x4080,0x4081,0x4082,0x4083,0x4084,0x4085,0x4086,0x4087,
+ 0x4088,0x4089,0x408a,0x408b,0x408c,0x408d,0x408e,0x408f,
+ 0x4090,0x4091,0x4092,0x4093,0x4094,0x4095,0x4096,0x4097,
+ 0x4098,0x4099,0x409a,0x409b,0x409c,0x409d,0x409e,0x409f,
+ 0x40a0,0x40a1,0x40a2,0x40a3,0x40a4,0x40a5,0x40a6,0x40a7,
+ 0x40a8,0x40a9,0x40aa,0x40ab,0x40ac,0x40ad,0x40ae,0x40af,
+ 0x40b0,0x40b1,0x40b2,0x40b3,0x40b4,0x40b5,0x40b6,0x40b7,
+ 0x40b8,0x40b9,0x40ba,0x40bb,0x40bc,0x40bd,0x40be,0x40bf,
+ 0x40c0,0x40c1,0x40c2,0x40c3,0x40c4,0x40c5,0x40c6,0x40c7,
+ 0x40c8,0x40c9,0x40ca,0x40cb,0x40cc,0x40cd,0x40ce,0x40cf,
+ 0x40d0,0x40d1,0x40d2,0x40d3,0x40d4,0x40d5,0x40d6,0x40d7,
+ 0x40d8,0x40d9,0x40da,0x40db,0x40dc,0x40dd,0x40de,0x40df,
+ 0x40e0,0x40e1,0x40e2,0x40e3,0x40e4,0x40e5,0x40e6,0x40e7,
+ 0x40e8,0x40e9,0x40ea,0x40eb,0x40ec,0x40ed,0x40ee,0x40ef,
+ 0x40f0,0x40f1,0x40f2,0x40f3,0x40f4,0x40f5,0x40f6,0x40f7,
+ 0x40f8,0x40f9,0x40fa,0x40fb,0x40fc,0x40fd,0x40fe,0x40ff,
+ 0x4100,0x4101,0x4102,0x4103,0x4104,0x4105,0x4106,0x4107,
+ 0x4108,0x4109,0x410a,0x410b,0x410c,0x410d,0x410e,0x410f,
+ 0x4110,0x4111,0x4112,0x4113,0x4114,0x4115,0x4116,0x4117,
+ 0x4118,0x4119,0x411a,0x411b,0x411c,0x411d,0x411e,0x411f,
+ 0x4120,0x4121,0x4122,0x4123,0x4124,0x4125,0x4126,0x4127,
+ 0x4128,0x4129,0x412a,0x412b,0x412c,0x412d,0x412e,0x412f,
+ 0x4130,0x4131,0x4132,0x4133,0x4134,0x4135,0x4136,0x4137,
+ 0x4138,0x4139,0x413a,0x413b,0x413c,0x413d,0x413e,0x413f,
+ 0x4140,0x4141,0x4142,0x4143,0x4144,0x4145,0x4146,0x4147,
+ 0x4148,0x4149,0x414a,0x414b,0x414c,0x414d,0x414e,0x414f,
+ 0x4150,0x4151,0x4152,0x4153,0x4154,0x4155,0x4156,0x4157,
+ 0x4158,0x4159,0x415a,0x415b,0x415c,0x415d,0x415e,0x415f,
+ 0x4160,0x4161,0x4162,0x4163,0x4164,0x4165,0x4166,0x4167,
+ 0x4168,0x4169,0x416a,0x416b,0x416c,0x416d,0x416e,0x416f,
+ 0x4170,0x4171,0x4172,0x4173,0x4174,0x4175,0x4176,0x4177,
+ 0x4178,0x4179,0x417a,0x417b,0x417c,0x417d,0x417e,0x417f,
+ 0x4180,0x4181,0x4182,0x4183,0x4184,0x4185,0x4186,0x4187,
+ 0x4188,0x4189,0x418a,0x418b,0x418c,0x418d,0x418e,0x418f,
+ 0x4190,0x4191,0x4192,0x4193,0x4194,0x4195,0x4196,0x4197,
+ 0x4198,0x4199,0x419a,0x419b,0x419c,0x419d,0x419e,0x419f,
+ 0x41a0,0x41a1,0x41a2,0x41a3,0x41a4,0x41a5,0x41a6,0x41a7,
+ 0x41a8,0x41a9,0x41aa,0x41ab,0x41ac,0x41ad,0x41ae,0x41af,
+ 0x41b0,0x41b1,0x41b2,0x41b3,0x41b4,0x41b5,0x41b6,0x41b7,
+ 0x41b8,0x41b9,0x41ba,0x41bb,0x41bc,0x41bd,0x41be,0x41bf,
+ 0x41c0,0x41c1,0x41c2,0x41c3,0x41c4,0x41c5,0x41c6,0x41c7,
+ 0x41c8,0x41c9,0x41ca,0x41cb,0x41cc,0x41cd,0x41ce,0x41cf,
+ 0x41d0,0x41d1,0x41d2,0x41d3,0x41d4,0x41d5,0x41d6,0x41d7,
+ 0x41d8,0x41d9,0x41da,0x41db,0x41dc,0x41dd,0x41de,0x41df,
+ 0x41e0,0x41e1,0x41e2,0x41e3,0x41e4,0x41e5,0x41e6,0x41e7,
+ 0x41e8,0x41e9,0x41ea,0x41eb,0x41ec,0x41ed,0x41ee,0x41ef,
+ 0x41f0,0x41f1,0x41f2,0x41f3,0x41f4,0x41f5,0x41f6,0x41f7,
+ 0x41f8,0x41f9,0x41fa,0x41fb,0x41fc,0x41fd,0x41fe,0x41ff,
+ 0x4200,0x4201,0x4202,0x4203,0x4204,0x4205,0x4206,0x4207,
+ 0x4208,0x4209,0x420a,0x420b,0x420c,0x420d,0x420e,0x420f,
+ 0x4210,0x4211,0x4212,0x4213,0x4214,0x4215,0x4216,0x4217,
+ 0x4218,0x4219,0x421a,0x421b,0x421c,0x421d,0x421e,0x421f,
+ 0x4220,0x4221,0x4222,0x4223,0x4224,0x4225,0x4226,0x4227,
+ 0x4228,0x4229,0x422a,0x422b,0x422c,0x422d,0x422e,0x422f,
+ 0x4230,0x4231,0x4232,0x4233,0x4234,0x4235,0x4236,0x4237,
+ 0x4238,0x4239,0x423a,0x423b,0x423c,0x423d,0x423e,0x423f,
+ 0x4240,0x4241,0x4242,0x4243,0x4244,0x4245,0x4246,0x4247,
+ 0x4248,0x4249,0x424a,0x424b,0x424c,0x424d,0x424e,0x424f,
+ 0x4250,0x4251,0x4252,0x4253,0x4254,0x4255,0x4256,0x4257,
+ 0x4258,0x4259,0x425a,0x425b,0x425c,0x425d,0x425e,0x425f,
+ 0x4260,0x4261,0x4262,0x4263,0x4264,0x4265,0x4266,0x4267,
+ 0x4268,0x4269,0x426a,0x426b,0x426c,0x426d,0x426e,0x426f,
+ 0x4270,0x4271,0x4272,0x4273,0x4274,0x4275,0x4276,0x4277,
+ 0x4278,0x4279,0x427a,0x427b,0x427c,0x427d,0x427e,0x427f,
+ 0x4280,0x4281,0x4282,0x4283,0x4284,0x4285,0x4286,0x4287,
+ 0x4288,0x4289,0x428a,0x428b,0x428c,0x428d,0x428e,0x428f,
+ 0x4290,0x4291,0x4292,0x4293,0x4294,0x4295,0x4296,0x4297,
+ 0x4298,0x4299,0x429a,0x429b,0x429c,0x429d,0x429e,0x429f,
+ 0x42a0,0x42a1,0x42a2,0x42a3,0x42a4,0x42a5,0x42a6,0x42a7,
+ 0x42a8,0x42a9,0x42aa,0x42ab,0x42ac,0x42ad,0x42ae,0x42af,
+ 0x42b0,0x42b1,0x42b2,0x42b3,0x42b4,0x42b5,0x42b6,0x42b7,
+ 0x42b8,0x42b9,0x42ba,0x42bb,0x42bc,0x42bd,0x42be,0x42bf,
+ 0x42c0,0x42c1,0x42c2,0x42c3,0x42c4,0x42c5,0x42c6,0x42c7,
+ 0x42c8,0x42c9,0x42ca,0x42cb,0x42cc,0x42cd,0x42ce,0x42cf,
+ 0x42d0,0x42d1,0x42d2,0x42d3,0x42d4,0x42d5,0x42d6,0x42d7,
+ 0x42d8,0x42d9,0x42da,0x42db,0x42dc,0x42dd,0x42de,0x42df,
+ 0x42e0,0x42e1,0x42e2,0x42e3,0x42e4,0x42e5,0x42e6,0x42e7,
+ 0x42e8,0x42e9,0x42ea,0x42eb,0x42ec,0x42ed,0x42ee,0x42ef,
+ 0x42f0,0x42f1,0x42f2,0x42f3,0x42f4,0x42f5,0x42f6,0x42f7,
+ 0x42f8,0x42f9,0x42fa,0x42fb,0x42fc,0x42fd,0x42fe,0x42ff,
+ 0x4300,0x4301,0x4302,0x4303,0x4304,0x4305,0x4306,0x4307,
+ 0x4308,0x4309,0x430a,0x430b,0x430c,0x430d,0x430e,0x430f,
+ 0x4310,0x4311,0x4312,0x4313,0x4314,0x4315,0x4316,0x4317,
+ 0x4318,0x4319,0x431a,0x431b,0x431c,0x431d,0x431e,0x431f,
+ 0x4320,0x4321,0x4322,0x4323,0x4324,0x4325,0x4326,0x4327,
+ 0x4328,0x4329,0x432a,0x432b,0x432c,0x432d,0x432e,0x432f,
+ 0x4330,0x4331,0x4332,0x4333,0x4334,0x4335,0x4336,0x4337,
+ 0x4338,0x4339,0x433a,0x433b,0x433c,0x433d,0x433e,0x433f,
+ 0x4340,0x4341,0x4342,0x4343,0x4344,0x4345,0x4346,0x4347,
+ 0x4348,0x4349,0x434a,0x434b,0x434c,0x434d,0x434e,0x434f,
+ 0x4350,0x4351,0x4352,0x4353,0x4354,0x4355,0x4356,0x4357,
+ 0x4358,0x4359,0x435a,0x435b,0x435c,0x435d,0x435e,0x435f,
+ 0x4360,0x4361,0x4362,0x4363,0x4364,0x4365,0x4366,0x4367,
+ 0x4368,0x4369,0x436a,0x436b,0x436c,0x436d,0x436e,0x436f,
+ 0x4370,0x4371,0x4372,0x4373,0x4374,0x4375,0x4376,0x4377,
+ 0x4378,0x4379,0x437a,0x437b,0x437c,0x437d,0x437e,0x437f,
+ 0x4380,0x4381,0x4382,0x4383,0x4384,0x4385,0x4386,0x4387,
+ 0x4388,0x4389,0x438a,0x438b,0x438c,0x438d,0x438e,0x438f,
+ 0x4390,0x4391,0x4392,0x4393,0x4394,0x4395,0x4396,0x4397,
+ 0x4398,0x4399,0x439a,0x439b,0x439c,0x439d,0x439e,0x439f,
+ 0x43a0,0x43a1,0x43a2,0x43a3,0x43a4,0x43a5,0x43a6,0x43a7,
+ 0x43a8,0x43a9,0x43aa,0x43ab,0x43ac,0x43ad,0x43ae,0x43af,
+ 0x43b0,0x43b1,0x43b2,0x43b3,0x43b4,0x43b5,0x43b6,0x43b7,
+ 0x43b8,0x43b9,0x43ba,0x43bb,0x43bc,0x43bd,0x43be,0x43bf,
+ 0x43c0,0x43c1,0x43c2,0x43c3,0x43c4,0x43c5,0x43c6,0x43c7,
+ 0x43c8,0x43c9,0x43ca,0x43cb,0x43cc,0x43cd,0x43ce,0x43cf,
+ 0x43d0,0x43d1,0x43d2,0x43d3,0x43d4,0x43d5,0x43d6,0x43d7,
+ 0x43d8,0x43d9,0x43da,0x43db,0x43dc,0x43dd,0x43de,0x43df,
+ 0x43e0,0x43e1,0x43e2,0x43e3,0x43e4,0x43e5,0x43e6,0x43e7,
+ 0x43e8,0x43e9,0x43ea,0x43eb,0x43ec,0x43ed,0x43ee,0x43ef,
+ 0x43f0,0x43f1,0x43f2,0x43f3,0x43f4,0x43f5,0x43f6,0x43f7,
+ 0x43f8,0x43f9,0x43fa,0x43fb,0x43fc,0x43fd,0x43fe,0x43ff,
+ 0x4400,0x4401,0x4402,0x4403,0x4404,0x4405,0x4406,0x4407,
+ 0x4408,0x4409,0x440a,0x440b,0x440c,0x440d,0x440e,0x440f,
+ 0x4410,0x4411,0x4412,0x4413,0x4414,0x4415,0x4416,0x4417,
+ 0x4418,0x4419,0x441a,0x441b,0x441c,0x441d,0x441e,0x441f,
+ 0x4420,0x4421,0x4422,0x4423,0x4424,0x4425,0x4426,0x4427,
+ 0x4428,0x4429,0x442a,0x442b,0x442c,0x442d,0x442e,0x442f,
+ 0x4430,0x4431,0x4432,0x4433,0x4434,0x4435,0x4436,0x4437,
+ 0x4438,0x4439,0x443a,0x443b,0x443c,0x443d,0x443e,0x443f,
+ 0x4440,0x4441,0x4442,0x4443,0x4444,0x4445,0x4446,0x4447,
+ 0x4448,0x4449,0x444a,0x444b,0x444c,0x444d,0x444e,0x444f,
+ 0x4450,0x4451,0x4452,0x4453,0x4454,0x4455,0x4456,0x4457,
+ 0x4458,0x4459,0x445a,0x445b,0x445c,0x445d,0x445e,0x445f,
+ 0x4460,0x4461,0x4462,0x4463,0x4464,0x4465,0x4466,0x4467,
+ 0x4468,0x4469,0x446a,0x446b,0x446c,0x446d,0x446e,0x446f,
+ 0x4470,0x4471,0x4472,0x4473,0x4474,0x4475,0x4476,0x4477,
+ 0x4478,0x4479,0x447a,0x447b,0x447c,0x447d,0x447e,0x447f,
+ 0x4480,0x4481,0x4482,0x4483,0x4484,0x4485,0x4486,0x4487,
+ 0x4488,0x4489,0x448a,0x448b,0x448c,0x448d,0x448e,0x448f,
+ 0x4490,0x4491,0x4492,0x4493,0x4494,0x4495,0x4496,0x4497,
+ 0x4498,0x4499,0x449a,0x449b,0x449c,0x449d,0x449e,0x449f,
+ 0x44a0,0x44a1,0x44a2,0x44a3,0x44a4,0x44a5,0x44a6,0x44a7,
+ 0x44a8,0x44a9,0x44aa,0x44ab,0x44ac,0x44ad,0x44ae,0x44af,
+ 0x44b0,0x44b1,0x44b2,0x44b3,0x44b4,0x44b5,0x44b6,0x44b7,
+ 0x44b8,0x44b9,0x44ba,0x44bb,0x44bc,0x44bd,0x44be,0x44bf,
+ 0x44c0,0x44c1,0x44c2,0x44c3,0x44c4,0x44c5,0x44c6,0x44c7,
+ 0x44c8,0x44c9,0x44ca,0x44cb,0x44cc,0x44cd,0x44ce,0x44cf,
+ 0x44d0,0x44d1,0x44d2,0x44d3,0x44d4,0x44d5,0x44d6,0x44d7,
+ 0x44d8,0x44d9,0x44da,0x44db,0x44dc,0x44dd,0x44de,0x44df,
+ 0x44e0,0x44e1,0x44e2,0x44e3,0x44e4,0x44e5,0x44e6,0x44e7,
+ 0x44e8,0x44e9,0x44ea,0x44eb,0x44ec,0x44ed,0x44ee,0x44ef,
+ 0x44f0,0x44f1,0x44f2,0x44f3,0x44f4,0x44f5,0x44f6,0x44f7,
+ 0x44f8,0x44f9,0x44fa,0x44fb,0x44fc,0x44fd,0x44fe,0x44ff,
+ 0x4500,0x4501,0x4502,0x4503,0x4504,0x4505,0x4506,0x4507,
+ 0x4508,0x4509,0x450a,0x450b,0x450c,0x450d,0x450e,0x450f,
+ 0x4510,0x4511,0x4512,0x4513,0x4514,0x4515,0x4516,0x4517,
+ 0x4518,0x4519,0x451a,0x451b,0x451c,0x451d,0x451e,0x451f,
+ 0x4520,0x4521,0x4522,0x4523,0x4524,0x4525,0x4526,0x4527,
+ 0x4528,0x4529,0x452a,0x452b,0x452c,0x452d,0x452e,0x452f,
+ 0x4530,0x4531,0x4532,0x4533,0x4534,0x4535,0x4536,0x4537,
+ 0x4538,0x4539,0x453a,0x453b,0x453c,0x453d,0x453e,0x453f,
+ 0x4540,0x4541,0x4542,0x4543,0x4544,0x4545,0x4546,0x4547,
+ 0x4548,0x4549,0x454a,0x454b,0x454c,0x454d,0x454e,0x454f,
+ 0x4550,0x4551,0x4552,0x4553,0x4554,0x4555,0x4556,0x4557,
+ 0x4558,0x4559,0x455a,0x455b,0x455c,0x455d,0x455e,0x455f,
+ 0x4560,0x4561,0x4562,0x4563,0x4564,0x4565,0x4566,0x4567,
+ 0x4568,0x4569,0x456a,0x456b,0x456c,0x456d,0x456e,0x456f,
+ 0x4570,0x4571,0x4572,0x4573,0x4574,0x4575,0x4576,0x4577,
+ 0x4578,0x4579,0x457a,0x457b,0x457c,0x457d,0x457e,0x457f,
+ 0x4580,0x4581,0x4582,0x4583,0x4584,0x4585,0x4586,0x4587,
+ 0x4588,0x4589,0x458a,0x458b,0x458c,0x458d,0x458e,0x458f,
+ 0x4590,0x4591,0x4592,0x4593,0x4594,0x4595,0x4596,0x4597,
+ 0x4598,0x4599,0x459a,0x459b,0x459c,0x459d,0x459e,0x459f,
+ 0x45a0,0x45a1,0x45a2,0x45a3,0x45a4,0x45a5,0x45a6,0x45a7,
+ 0x45a8,0x45a9,0x45aa,0x45ab,0x45ac,0x45ad,0x45ae,0x45af,
+ 0x45b0,0x45b1,0x45b2,0x45b3,0x45b4,0x45b5,0x45b6,0x45b7,
+ 0x45b8,0x45b9,0x45ba,0x45bb,0x45bc,0x45bd,0x45be,0x45bf,
+ 0x45c0,0x45c1,0x45c2,0x45c3,0x45c4,0x45c5,0x45c6,0x45c7,
+ 0x45c8,0x45c9,0x45ca,0x45cb,0x45cc,0x45cd,0x45ce,0x45cf,
+ 0x45d0,0x45d1,0x45d2,0x45d3,0x45d4,0x45d5,0x45d6,0x45d7,
+ 0x45d8,0x45d9,0x45da,0x45db,0x45dc,0x45dd,0x45de,0x45df,
+ 0x45e0,0x45e1,0x45e2,0x45e3,0x45e4,0x45e5,0x45e6,0x45e7,
+ 0x45e8,0x45e9,0x45ea,0x45eb,0x45ec,0x45ed,0x45ee,0x45ef,
+ 0x45f0,0x45f1,0x45f2,0x45f3,0x45f4,0x45f5,0x45f6,0x45f7,
+ 0x45f8,0x45f9,0x45fa,0x45fb,0x45fc,0x45fd,0x45fe,0x45ff,
+ 0x4600,0x4601,0x4602,0x4603,0x4604,0x4605,0x4606,0x4607,
+ 0x4608,0x4609,0x460a,0x460b,0x460c,0x460d,0x460e,0x460f,
+ 0x4610,0x4611,0x4612,0x4613,0x4614,0x4615,0x4616,0x4617,
+ 0x4618,0x4619,0x461a,0x461b,0x461c,0x461d,0x461e,0x461f,
+ 0x4620,0x4621,0x4622,0x4623,0x4624,0x4625,0x4626,0x4627,
+ 0x4628,0x4629,0x462a,0x462b,0x462c,0x462d,0x462e,0x462f,
+ 0x4630,0x4631,0x4632,0x4633,0x4634,0x4635,0x4636,0x4637,
+ 0x4638,0x4639,0x463a,0x463b,0x463c,0x463d,0x463e,0x463f,
+ 0x4640,0x4641,0x4642,0x4643,0x4644,0x4645,0x4646,0x4647,
+ 0x4648,0x4649,0x464a,0x464b,0x464c,0x464d,0x464e,0x464f,
+ 0x4650,0x4651,0x4652,0x4653,0x4654,0x4655,0x4656,0x4657,
+ 0x4658,0x4659,0x465a,0x465b,0x465c,0x465d,0x465e,0x465f,
+ 0x4660,0x4661,0x4662,0x4663,0x4664,0x4665,0x4666,0x4667,
+ 0x4668,0x4669,0x466a,0x466b,0x466c,0x466d,0x466e,0x466f,
+ 0x4670,0x4671,0x4672,0x4673,0x4674,0x4675,0x4676,0x4677,
+ 0x4678,0x4679,0x467a,0x467b,0x467c,0x467d,0x467e,0x467f,
+ 0x4680,0x4681,0x4682,0x4683,0x4684,0x4685,0x4686,0x4687,
+ 0x4688,0x4689,0x468a,0x468b,0x468c,0x468d,0x468e,0x468f,
+ 0x4690,0x4691,0x4692,0x4693,0x4694,0x4695,0x4696,0x4697,
+ 0x4698,0x4699,0x469a,0x469b,0x469c,0x469d,0x469e,0x469f,
+ 0x46a0,0x46a1,0x46a2,0x46a3,0x46a4,0x46a5,0x46a6,0x46a7,
+ 0x46a8,0x46a9,0x46aa,0x46ab,0x46ac,0x46ad,0x46ae,0x46af,
+ 0x46b0,0x46b1,0x46b2,0x46b3,0x46b4,0x46b5,0x46b6,0x46b7,
+ 0x46b8,0x46b9,0x46ba,0x46bb,0x46bc,0x46bd,0x46be,0x46bf,
+ 0x46c0,0x46c1,0x46c2,0x46c3,0x46c4,0x46c5,0x46c6,0x46c7,
+ 0x46c8,0x46c9,0x46ca,0x46cb,0x46cc,0x46cd,0x46ce,0x46cf,
+ 0x46d0,0x46d1,0x46d2,0x46d3,0x46d4,0x46d5,0x46d6,0x46d7,
+ 0x46d8,0x46d9,0x46da,0x46db,0x46dc,0x46dd,0x46de,0x46df,
+ 0x46e0,0x46e1,0x46e2,0x46e3,0x46e4,0x46e5,0x46e6,0x46e7,
+ 0x46e8,0x46e9,0x46ea,0x46eb,0x46ec,0x46ed,0x46ee,0x46ef,
+ 0x46f0,0x46f1,0x46f2,0x46f3,0x46f4,0x46f5,0x46f6,0x46f7,
+ 0x46f8,0x46f9,0x46fa,0x46fb,0x46fc,0x46fd,0x46fe,0x46ff,
+ 0x4700,0x4701,0x4702,0x4703,0x4704,0x4705,0x4706,0x4707,
+ 0x4708,0x4709,0x470a,0x470b,0x470c,0x470d,0x470e,0x470f,
+ 0x4710,0x4711,0x4712,0x4713,0x4714,0x4715,0x4716,0x4717,
+ 0x4718,0x4719,0x471a,0x471b,0x471c,0x471d,0x471e,0x471f,
+ 0x4720,0x4721,0x4722,0x4723,0x4724,0x4725,0x4726,0x4727,
+ 0x4728,0x4729,0x472a,0x472b,0x472c,0x472d,0x472e,0x472f,
+ 0x4730,0x4731,0x4732,0x4733,0x4734,0x4735,0x4736,0x4737,
+ 0x4738,0x4739,0x473a,0x473b,0x473c,0x473d,0x473e,0x473f,
+ 0x4740,0x4741,0x4742,0x4743,0x4744,0x4745,0x4746,0x4747,
+ 0x4748,0x4749,0x474a,0x474b,0x474c,0x474d,0x474e,0x474f,
+ 0x4750,0x4751,0x4752,0x4753,0x4754,0x4755,0x4756,0x4757,
+ 0x4758,0x4759,0x475a,0x475b,0x475c,0x475d,0x475e,0x475f,
+ 0x4760,0x4761,0x4762,0x4763,0x4764,0x4765,0x4766,0x4767,
+ 0x4768,0x4769,0x476a,0x476b,0x476c,0x476d,0x476e,0x476f,
+ 0x4770,0x4771,0x4772,0x4773,0x4774,0x4775,0x4776,0x4777,
+ 0x4778,0x4779,0x477a,0x477b,0x477c,0x477d,0x477e,0x477f,
+ 0x4780,0x4781,0x4782,0x4783,0x4784,0x4785,0x4786,0x4787,
+ 0x4788,0x4789,0x478a,0x478b,0x478c,0x478d,0x478e,0x478f,
+ 0x4790,0x4791,0x4792,0x4793,0x4794,0x4795,0x4796,0x4797,
+ 0x4798,0x4799,0x479a,0x479b,0x479c,0x479d,0x479e,0x479f,
+ 0x47a0,0x47a1,0x47a2,0x47a3,0x47a4,0x47a5,0x47a6,0x47a7,
+ 0x47a8,0x47a9,0x47aa,0x47ab,0x47ac,0x47ad,0x47ae,0x47af,
+ 0x47b0,0x47b1,0x47b2,0x47b3,0x47b4,0x47b5,0x47b6,0x47b7,
+ 0x47b8,0x47b9,0x47ba,0x47bb,0x47bc,0x47bd,0x47be,0x47bf,
+ 0x47c0,0x47c1,0x47c2,0x47c3,0x47c4,0x47c5,0x47c6,0x47c7,
+ 0x47c8,0x47c9,0x47ca,0x47cb,0x47cc,0x47cd,0x47ce,0x47cf,
+ 0x47d0,0x47d1,0x47d2,0x47d3,0x47d4,0x47d5,0x47d6,0x47d7,
+ 0x47d8,0x47d9,0x47da,0x47db,0x47dc,0x47dd,0x47de,0x47df,
+ 0x47e0,0x47e1,0x47e2,0x47e3,0x47e4,0x47e5,0x47e6,0x47e7,
+ 0x47e8,0x47e9,0x47ea,0x47eb,0x47ec,0x47ed,0x47ee,0x47ef,
+ 0x47f0,0x47f1,0x47f2,0x47f3,0x47f4,0x47f5,0x47f6,0x47f7,
+ 0x47f8,0x47f9,0x47fa,0x47fb,0x47fc,0x47fd,0x47fe,0x47ff,
+ 0x4800,0x4801,0x4802,0x4803,0x4804,0x4805,0x4806,0x4807,
+ 0x4808,0x4809,0x480a,0x480b,0x480c,0x480d,0x480e,0x480f,
+ 0x4810,0x4811,0x4812,0x4813,0x4814,0x4815,0x4816,0x4817,
+ 0x4818,0x4819,0x481a,0x481b,0x481c,0x481d,0x481e,0x481f,
+ 0x4820,0x4821,0x4822,0x4823,0x4824,0x4825,0x4826,0x4827,
+ 0x4828,0x4829,0x482a,0x482b,0x482c,0x482d,0x482e,0x482f,
+ 0x4830,0x4831,0x4832,0x4833,0x4834,0x4835,0x4836,0x4837,
+ 0x4838,0x4839,0x483a,0x483b,0x483c,0x483d,0x483e,0x483f,
+ 0x4840,0x4841,0x4842,0x4843,0x4844,0x4845,0x4846,0x4847,
+ 0x4848,0x4849,0x484a,0x484b,0x484c,0x484d,0x484e,0x484f,
+ 0x4850,0x4851,0x4852,0x4853,0x4854,0x4855,0x4856,0x4857,
+ 0x4858,0x4859,0x485a,0x485b,0x485c,0x485d,0x485e,0x485f,
+ 0x4860,0x4861,0x4862,0x4863,0x4864,0x4865,0x4866,0x4867,
+ 0x4868,0x4869,0x486a,0x486b,0x486c,0x486d,0x486e,0x486f,
+ 0x4870,0x4871,0x4872,0x4873,0x4874,0x4875,0x4876,0x4877,
+ 0x4878,0x4879,0x487a,0x487b,0x487c,0x487d,0x487e,0x487f,
+ 0x4880,0x4881,0x4882,0x4883,0x4884,0x4885,0x4886,0x4887,
+ 0x4888,0x4889,0x488a,0x488b,0x488c,0x488d,0x488e,0x488f,
+ 0x4890,0x4891,0x4892,0x4893,0x4894,0x4895,0x4896,0x4897,
+ 0x4898,0x4899,0x489a,0x489b,0x489c,0x489d,0x489e,0x489f,
+ 0x48a0,0x48a1,0x48a2,0x48a3,0x48a4,0x48a5,0x48a6,0x48a7,
+ 0x48a8,0x48a9,0x48aa,0x48ab,0x48ac,0x48ad,0x48ae,0x48af,
+ 0x48b0,0x48b1,0x48b2,0x48b3,0x48b4,0x48b5,0x48b6,0x48b7,
+ 0x48b8,0x48b9,0x48ba,0x48bb,0x48bc,0x48bd,0x48be,0x48bf,
+ 0x48c0,0x48c1,0x48c2,0x48c3,0x48c4,0x48c5,0x48c6,0x48c7,
+ 0x48c8,0x48c9,0x48ca,0x48cb,0x48cc,0x48cd,0x48ce,0x48cf,
+ 0x48d0,0x48d1,0x48d2,0x48d3,0x48d4,0x48d5,0x48d6,0x48d7,
+ 0x48d8,0x48d9,0x48da,0x48db,0x48dc,0x48dd,0x48de,0x48df,
+ 0x48e0,0x48e1,0x48e2,0x48e3,0x48e4,0x48e5,0x48e6,0x48e7,
+ 0x48e8,0x48e9,0x48ea,0x48eb,0x48ec,0x48ed,0x48ee,0x48ef,
+ 0x48f0,0x48f1,0x48f2,0x48f3,0x48f4,0x48f5,0x48f6,0x48f7,
+ 0x48f8,0x48f9,0x48fa,0x48fb,0x48fc,0x48fd,0x48fe,0x48ff,
+ 0x4900,0x4901,0x4902,0x4903,0x4904,0x4905,0x4906,0x4907,
+ 0x4908,0x4909,0x490a,0x490b,0x490c,0x490d,0x490e,0x490f,
+ 0x4910,0x4911,0x4912,0x4913,0x4914,0x4915,0x4916,0x4917,
+ 0x4918,0x4919,0x491a,0x491b,0x491c,0x491d,0x491e,0x491f,
+ 0x4920,0x4921,0x4922,0x4923,0x4924,0x4925,0x4926,0x4927,
+ 0x4928,0x4929,0x492a,0x492b,0x492c,0x492d,0x492e,0x492f,
+ 0x4930,0x4931,0x4932,0x4933,0x4934,0x4935,0x4936,0x4937,
+ 0x4938,0x4939,0x493a,0x493b,0x493c,0x493d,0x493e,0x493f,
+ 0x4940,0x4941,0x4942,0x4943,0x4944,0x4945,0x4946,0x4947,
+ 0x4948,0x4949,0x494a,0x494b,0x494c,0x494d,0x494e,0x494f,
+ 0x4950,0x4951,0x4952,0x4953,0x4954,0x4955,0x4956,0x4957,
+ 0x4958,0x4959,0x495a,0x495b,0x495c,0x495d,0x495e,0x495f,
+ 0x4960,0x4961,0x4962,0x4963,0x4964,0x4965,0x4966,0x4967,
+ 0x4968,0x4969,0x496a,0x496b,0x496c,0x496d,0x496e,0x496f,
+ 0x4970,0x4971,0x4972,0x4973,0x4974,0x4975,0x4976,0x4977,
+ 0x4978,0x4979,0x497a,0x497b,0x497c,0x497d,0x497e,0x497f,
+ 0x4980,0x4981,0x4982,0x4983,0x4984,0x4985,0x4986,0x4987,
+ 0x4988,0x4989,0x498a,0x498b,0x498c,0x498d,0x498e,0x498f,
+ 0x4990,0x4991,0x4992,0x4993,0x4994,0x4995,0x4996,0x4997,
+ 0x4998,0x4999,0x499a,0x499b,0x499c,0x499d,0x499e,0x499f,
+ 0x49a0,0x49a1,0x49a2,0x49a3,0x49a4,0x49a5,0x49a6,0x49a7,
+ 0x49a8,0x49a9,0x49aa,0x49ab,0x49ac,0x49ad,0x49ae,0x49af,
+ 0x49b0,0x49b1,0x49b2,0x49b3,0x49b4,0x49b5,0x49b6,0x49b7,
+ 0x49b8,0x49b9,0x49ba,0x49bb,0x49bc,0x49bd,0x49be,0x49bf,
+ 0x49c0,0x49c1,0x49c2,0x49c3,0x49c4,0x49c5,0x49c6,0x49c7,
+ 0x49c8,0x49c9,0x49ca,0x49cb,0x49cc,0x49cd,0x49ce,0x49cf,
+ 0x49d0,0x49d1,0x49d2,0x49d3,0x49d4,0x49d5,0x49d6,0x49d7,
+ 0x49d8,0x49d9,0x49da,0x49db,0x49dc,0x49dd,0x49de,0x49df,
+ 0x49e0,0x49e1,0x49e2,0x49e3,0x49e4,0x49e5,0x49e6,0x49e7,
+ 0x49e8,0x49e9,0x49ea,0x49eb,0x49ec,0x49ed,0x49ee,0x49ef,
+ 0x49f0,0x49f1,0x49f2,0x49f3,0x49f4,0x49f5,0x49f6,0x49f7,
+ 0x49f8,0x49f9,0x49fa,0x49fb,0x49fc,0x49fd,0x49fe,0x49ff,
+ 0x4a00,0x4a01,0x4a02,0x4a03,0x4a04,0x4a05,0x4a06,0x4a07,
+ 0x4a08,0x4a09,0x4a0a,0x4a0b,0x4a0c,0x4a0d,0x4a0e,0x4a0f,
+ 0x4a10,0x4a11,0x4a12,0x4a13,0x4a14,0x4a15,0x4a16,0x4a17,
+ 0x4a18,0x4a19,0x4a1a,0x4a1b,0x4a1c,0x4a1d,0x4a1e,0x4a1f,
+ 0x4a20,0x4a21,0x4a22,0x4a23,0x4a24,0x4a25,0x4a26,0x4a27,
+ 0x4a28,0x4a29,0x4a2a,0x4a2b,0x4a2c,0x4a2d,0x4a2e,0x4a2f,
+ 0x4a30,0x4a31,0x4a32,0x4a33,0x4a34,0x4a35,0x4a36,0x4a37,
+ 0x4a38,0x4a39,0x4a3a,0x4a3b,0x4a3c,0x4a3d,0x4a3e,0x4a3f,
+ 0x4a40,0x4a41,0x4a42,0x4a43,0x4a44,0x4a45,0x4a46,0x4a47,
+ 0x4a48,0x4a49,0x4a4a,0x4a4b,0x4a4c,0x4a4d,0x4a4e,0x4a4f,
+ 0x4a50,0x4a51,0x4a52,0x4a53,0x4a54,0x4a55,0x4a56,0x4a57,
+ 0x4a58,0x4a59,0x4a5a,0x4a5b,0x4a5c,0x4a5d,0x4a5e,0x4a5f,
+ 0x4a60,0x4a61,0x4a62,0x4a63,0x4a64,0x4a65,0x4a66,0x4a67,
+ 0x4a68,0x4a69,0x4a6a,0x4a6b,0x4a6c,0x4a6d,0x4a6e,0x4a6f,
+ 0x4a70,0x4a71,0x4a72,0x4a73,0x4a74,0x4a75,0x4a76,0x4a77,
+ 0x4a78,0x4a79,0x4a7a,0x4a7b,0x4a7c,0x4a7d,0x4a7e,0x4a7f,
+ 0x4a80,0x4a81,0x4a82,0x4a83,0x4a84,0x4a85,0x4a86,0x4a87,
+ 0x4a88,0x4a89,0x4a8a,0x4a8b,0x4a8c,0x4a8d,0x4a8e,0x4a8f,
+ 0x4a90,0x4a91,0x4a92,0x4a93,0x4a94,0x4a95,0x4a96,0x4a97,
+ 0x4a98,0x4a99,0x4a9a,0x4a9b,0x4a9c,0x4a9d,0x4a9e,0x4a9f,
+ 0x4aa0,0x4aa1,0x4aa2,0x4aa3,0x4aa4,0x4aa5,0x4aa6,0x4aa7,
+ 0x4aa8,0x4aa9,0x4aaa,0x4aab,0x4aac,0x4aad,0x4aae,0x4aaf,
+ 0x4ab0,0x4ab1,0x4ab2,0x4ab3,0x4ab4,0x4ab5,0x4ab6,0x4ab7,
+ 0x4ab8,0x4ab9,0x4aba,0x4abb,0x4abc,0x4abd,0x4abe,0x4abf,
+ 0x4ac0,0x4ac1,0x4ac2,0x4ac3,0x4ac4,0x4ac5,0x4ac6,0x4ac7,
+ 0x4ac8,0x4ac9,0x4aca,0x4acb,0x4acc,0x4acd,0x4ace,0x4acf,
+ 0x4ad0,0x4ad1,0x4ad2,0x4ad3,0x4ad4,0x4ad5,0x4ad6,0x4ad7,
+ 0x4ad8,0x4ad9,0x4ada,0x4adb,0x4adc,0x4add,0x4ade,0x4adf,
+ 0x4ae0,0x4ae1,0x4ae2,0x4ae3,0x4ae4,0x4ae5,0x4ae6,0x4ae7,
+ 0x4ae8,0x4ae9,0x4aea,0x4aeb,0x4aec,0x4aed,0x4aee,0x4aef,
+ 0x4af0,0x4af1,0x4af2,0x4af3,0x4af4,0x4af5,0x4af6,0x4af7,
+ 0x4af8,0x4af9,0x4afa,0x4afb,0x4afc,0x4afd,0x4afe,0x4aff,
+ 0x4b00,0x4b01,0x4b02,0x4b03,0x4b04,0x4b05,0x4b06,0x4b07,
+ 0x4b08,0x4b09,0x4b0a,0x4b0b,0x4b0c,0x4b0d,0x4b0e,0x4b0f,
+ 0x4b10,0x4b11,0x4b12,0x4b13,0x4b14,0x4b15,0x4b16,0x4b17,
+ 0x4b18,0x4b19,0x4b1a,0x4b1b,0x4b1c,0x4b1d,0x4b1e,0x4b1f,
+ 0x4b20,0x4b21,0x4b22,0x4b23,0x4b24,0x4b25,0x4b26,0x4b27,
+ 0x4b28,0x4b29,0x4b2a,0x4b2b,0x4b2c,0x4b2d,0x4b2e,0x4b2f,
+ 0x4b30,0x4b31,0x4b32,0x4b33,0x4b34,0x4b35,0x4b36,0x4b37,
+ 0x4b38,0x4b39,0x4b3a,0x4b3b,0x4b3c,0x4b3d,0x4b3e,0x4b3f,
+ 0x4b40,0x4b41,0x4b42,0x4b43,0x4b44,0x4b45,0x4b46,0x4b47,
+ 0x4b48,0x4b49,0x4b4a,0x4b4b,0x4b4c,0x4b4d,0x4b4e,0x4b4f,
+ 0x4b50,0x4b51,0x4b52,0x4b53,0x4b54,0x4b55,0x4b56,0x4b57,
+ 0x4b58,0x4b59,0x4b5a,0x4b5b,0x4b5c,0x4b5d,0x4b5e,0x4b5f,
+ 0x4b60,0x4b61,0x4b62,0x4b63,0x4b64,0x4b65,0x4b66,0x4b67,
+ 0x4b68,0x4b69,0x4b6a,0x4b6b,0x4b6c,0x4b6d,0x4b6e,0x4b6f,
+ 0x4b70,0x4b71,0x4b72,0x4b73,0x4b74,0x4b75,0x4b76,0x4b77,
+ 0x4b78,0x4b79,0x4b7a,0x4b7b,0x4b7c,0x4b7d,0x4b7e,0x4b7f,
+ 0x4b80,0x4b81,0x4b82,0x4b83,0x4b84,0x4b85,0x4b86,0x4b87,
+ 0x4b88,0x4b89,0x4b8a,0x4b8b,0x4b8c,0x4b8d,0x4b8e,0x4b8f,
+ 0x4b90,0x4b91,0x4b92,0x4b93,0x4b94,0x4b95,0x4b96,0x4b97,
+ 0x4b98,0x4b99,0x4b9a,0x4b9b,0x4b9c,0x4b9d,0x4b9e,0x4b9f,
+ 0x4ba0,0x4ba1,0x4ba2,0x4ba3,0x4ba4,0x4ba5,0x4ba6,0x4ba7,
+ 0x4ba8,0x4ba9,0x4baa,0x4bab,0x4bac,0x4bad,0x4bae,0x4baf,
+ 0x4bb0,0x4bb1,0x4bb2,0x4bb3,0x4bb4,0x4bb5,0x4bb6,0x4bb7,
+ 0x4bb8,0x4bb9,0x4bba,0x4bbb,0x4bbc,0x4bbd,0x4bbe,0x4bbf,
+ 0x4bc0,0x4bc1,0x4bc2,0x4bc3,0x4bc4,0x4bc5,0x4bc6,0x4bc7,
+ 0x4bc8,0x4bc9,0x4bca,0x4bcb,0x4bcc,0x4bcd,0x4bce,0x4bcf,
+ 0x4bd0,0x4bd1,0x4bd2,0x4bd3,0x4bd4,0x4bd5,0x4bd6,0x4bd7,
+ 0x4bd8,0x4bd9,0x4bda,0x4bdb,0x4bdc,0x4bdd,0x4bde,0x4bdf,
+ 0x4be0,0x4be1,0x4be2,0x4be3,0x4be4,0x4be5,0x4be6,0x4be7,
+ 0x4be8,0x4be9,0x4bea,0x4beb,0x4bec,0x4bed,0x4bee,0x4bef,
+ 0x4bf0,0x4bf1,0x4bf2,0x4bf3,0x4bf4,0x4bf5,0x4bf6,0x4bf7,
+ 0x4bf8,0x4bf9,0x4bfa,0x4bfb,0x4bfc,0x4bfd,0x4bfe,0x4bff,
+ 0x4c00,0x4c01,0x4c02,0x4c03,0x4c04,0x4c05,0x4c06,0x4c07,
+ 0x4c08,0x4c09,0x4c0a,0x4c0b,0x4c0c,0x4c0d,0x4c0e,0x4c0f,
+ 0x4c10,0x4c11,0x4c12,0x4c13,0x4c14,0x4c15,0x4c16,0x4c17,
+ 0x4c18,0x4c19,0x4c1a,0x4c1b,0x4c1c,0x4c1d,0x4c1e,0x4c1f,
+ 0x4c20,0x4c21,0x4c22,0x4c23,0x4c24,0x4c25,0x4c26,0x4c27,
+ 0x4c28,0x4c29,0x4c2a,0x4c2b,0x4c2c,0x4c2d,0x4c2e,0x4c2f,
+ 0x4c30,0x4c31,0x4c32,0x4c33,0x4c34,0x4c35,0x4c36,0x4c37,
+ 0x4c38,0x4c39,0x4c3a,0x4c3b,0x4c3c,0x4c3d,0x4c3e,0x4c3f,
+ 0x4c40,0x4c41,0x4c42,0x4c43,0x4c44,0x4c45,0x4c46,0x4c47,
+ 0x4c48,0x4c49,0x4c4a,0x4c4b,0x4c4c,0x4c4d,0x4c4e,0x4c4f,
+ 0x4c50,0x4c51,0x4c52,0x4c53,0x4c54,0x4c55,0x4c56,0x4c57,
+ 0x4c58,0x4c59,0x4c5a,0x4c5b,0x4c5c,0x4c5d,0x4c5e,0x4c5f,
+ 0x4c60,0x4c61,0x4c62,0x4c63,0x4c64,0x4c65,0x4c66,0x4c67,
+ 0x4c68,0x4c69,0x4c6a,0x4c6b,0x4c6c,0x4c6d,0x4c6e,0x4c6f,
+ 0x4c70,0x4c71,0x4c72,0x4c73,0x4c74,0x4c75,0x4c76,0x4c77,
+ 0x4c78,0x4c79,0x4c7a,0x4c7b,0x4c7c,0x4c7d,0x4c7e,0x4c7f,
+ 0x4c80,0x4c81,0x4c82,0x4c83,0x4c84,0x4c85,0x4c86,0x4c87,
+ 0x4c88,0x4c89,0x4c8a,0x4c8b,0x4c8c,0x4c8d,0x4c8e,0x4c8f,
+ 0x4c90,0x4c91,0x4c92,0x4c93,0x4c94,0x4c95,0x4c96,0x4c97,
+ 0x4c98,0x4c99,0x4c9a,0x4c9b,0x4c9c,0x4c9d,0x4c9e,0x4c9f,
+ 0x4ca0,0x4ca1,0x4ca2,0x4ca3,0x4ca4,0x4ca5,0x4ca6,0x4ca7,
+ 0x4ca8,0x4ca9,0x4caa,0x4cab,0x4cac,0x4cad,0x4cae,0x4caf,
+ 0x4cb0,0x4cb1,0x4cb2,0x4cb3,0x4cb4,0x4cb5,0x4cb6,0x4cb7,
+ 0x4cb8,0x4cb9,0x4cba,0x4cbb,0x4cbc,0x4cbd,0x4cbe,0x4cbf,
+ 0x4cc0,0x4cc1,0x4cc2,0x4cc3,0x4cc4,0x4cc5,0x4cc6,0x4cc7,
+ 0x4cc8,0x4cc9,0x4cca,0x4ccb,0x4ccc,0x4ccd,0x4cce,0x4ccf,
+ 0x4cd0,0x4cd1,0x4cd2,0x4cd3,0x4cd4,0x4cd5,0x4cd6,0x4cd7,
+ 0x4cd8,0x4cd9,0x4cda,0x4cdb,0x4cdc,0x4cdd,0x4cde,0x4cdf,
+ 0x4ce0,0x4ce1,0x4ce2,0x4ce3,0x4ce4,0x4ce5,0x4ce6,0x4ce7,
+ 0x4ce8,0x4ce9,0x4cea,0x4ceb,0x4cec,0x4ced,0x4cee,0x4cef,
+ 0x4cf0,0x4cf1,0x4cf2,0x4cf3,0x4cf4,0x4cf5,0x4cf6,0x4cf7,
+ 0x4cf8,0x4cf9,0x4cfa,0x4cfb,0x4cfc,0x4cfd,0x4cfe,0x4cff,
+ 0x4d00,0x4d01,0x4d02,0x4d03,0x4d04,0x4d05,0x4d06,0x4d07,
+ 0x4d08,0x4d09,0x4d0a,0x4d0b,0x4d0c,0x4d0d,0x4d0e,0x4d0f,
+ 0x4d10,0x4d11,0x4d12,0x4d13,0x4d14,0x4d15,0x4d16,0x4d17,
+ 0x4d18,0x4d19,0x4d1a,0x4d1b,0x4d1c,0x4d1d,0x4d1e,0x4d1f,
+ 0x4d20,0x4d21,0x4d22,0x4d23,0x4d24,0x4d25,0x4d26,0x4d27,
+ 0x4d28,0x4d29,0x4d2a,0x4d2b,0x4d2c,0x4d2d,0x4d2e,0x4d2f,
+ 0x4d30,0x4d31,0x4d32,0x4d33,0x4d34,0x4d35,0x4d36,0x4d37,
+ 0x4d38,0x4d39,0x4d3a,0x4d3b,0x4d3c,0x4d3d,0x4d3e,0x4d3f,
+ 0x4d40,0x4d41,0x4d42,0x4d43,0x4d44,0x4d45,0x4d46,0x4d47,
+ 0x4d48,0x4d49,0x4d4a,0x4d4b,0x4d4c,0x4d4d,0x4d4e,0x4d4f,
+ 0x4d50,0x4d51,0x4d52,0x4d53,0x4d54,0x4d55,0x4d56,0x4d57,
+ 0x4d58,0x4d59,0x4d5a,0x4d5b,0x4d5c,0x4d5d,0x4d5e,0x4d5f,
+ 0x4d60,0x4d61,0x4d62,0x4d63,0x4d64,0x4d65,0x4d66,0x4d67,
+ 0x4d68,0x4d69,0x4d6a,0x4d6b,0x4d6c,0x4d6d,0x4d6e,0x4d6f,
+ 0x4d70,0x4d71,0x4d72,0x4d73,0x4d74,0x4d75,0x4d76,0x4d77,
+ 0x4d78,0x4d79,0x4d7a,0x4d7b,0x4d7c,0x4d7d,0x4d7e,0x4d7f,
+ 0x4d80,0x4d81,0x4d82,0x4d83,0x4d84,0x4d85,0x4d86,0x4d87,
+ 0x4d88,0x4d89,0x4d8a,0x4d8b,0x4d8c,0x4d8d,0x4d8e,0x4d8f,
+ 0x4d90,0x4d91,0x4d92,0x4d93,0x4d94,0x4d95,0x4d96,0x4d97,
+ 0x4d98,0x4d99,0x4d9a,0x4d9b,0x4d9c,0x4d9d,0x4d9e,0x4d9f,
+ 0x4da0,0x4da1,0x4da2,0x4da3,0x4da4,0x4da5,0x4da6,0x4da7,
+ 0x4da8,0x4da9,0x4daa,0x4dab,0x4dac,0x4dad,0x4dae,0x4daf,
+ 0x4db0,0x4db1,0x4db2,0x4db3,0x4db4,0x4db5,0x4db6,0x4db7,
+ 0x4db8,0x4db9,0x4dba,0x4dbb,0x4dbc,0x4dbd,0x4dbe,0x4dbf,
+ 0x4dc0,0x4dc1,0x4dc2,0x4dc3,0x4dc4,0x4dc5,0x4dc6,0x4dc7,
+ 0x4dc8,0x4dc9,0x4dca,0x4dcb,0x4dcc,0x4dcd,0x4dce,0x4dcf,
+ 0x4dd0,0x4dd1,0x4dd2,0x4dd3,0x4dd4,0x4dd5,0x4dd6,0x4dd7,
+ 0x4dd8,0x4dd9,0x4dda,0x4ddb,0x4ddc,0x4ddd,0x4dde,0x4ddf,
+ 0x4de0,0x4de1,0x4de2,0x4de3,0x4de4,0x4de5,0x4de6,0x4de7,
+ 0x4de8,0x4de9,0x4dea,0x4deb,0x4dec,0x4ded,0x4dee,0x4def,
+ 0x4df0,0x4df1,0x4df2,0x4df3,0x4df4,0x4df5,0x4df6,0x4df7,
+ 0x4df8,0x4df9,0x4dfa,0x4dfb,0x4dfc,0x4dfd,0x4dfe,0x4dff,
+ 0x4e00,0x4e01,0x4e02,0x4e03,0x4e04,0x4e05,0x4e06,0x4e07,
+ 0x4e08,0x4e09,0x4e0a,0x4e0b,0x4e0c,0x4e0d,0x4e0e,0x4e0f,
+ 0x4e10,0x4e11,0x4e12,0x4e13,0x4e14,0x4e15,0x4e16,0x4e17,
+ 0x4e18,0x4e19,0x4e1a,0x4e1b,0x4e1c,0x4e1d,0x4e1e,0x4e1f,
+ 0x4e20,0x4e21,0x4e22,0x4e23,0x4e24,0x4e25,0x4e26,0x4e27,
+ 0x4e28,0x4e29,0x4e2a,0x4e2b,0x4e2c,0x4e2d,0x4e2e,0x4e2f,
+ 0x4e30,0x4e31,0x4e32,0x4e33,0x4e34,0x4e35,0x4e36,0x4e37,
+ 0x4e38,0x4e39,0x4e3a,0x4e3b,0x4e3c,0x4e3d,0x4e3e,0x4e3f,
+ 0x4e40,0x4e41,0x4e42,0x4e43,0x4e44,0x4e45,0x4e46,0x4e47,
+ 0x4e48,0x4e49,0x4e4a,0x4e4b,0x4e4c,0x4e4d,0x4e4e,0x4e4f,
+ 0x4e50,0x4e51,0x4e52,0x4e53,0x4e54,0x4e55,0x4e56,0x4e57,
+ 0x4e58,0x4e59,0x4e5a,0x4e5b,0x4e5c,0x4e5d,0x4e5e,0x4e5f,
+ 0x4e60,0x4e61,0x4e62,0x4e63,0x4e64,0x4e65,0x4e66,0x4e67,
+ 0x4e68,0x4e69,0x4e6a,0x4e6b,0x4e6c,0x4e6d,0x4e6e,0x4e6f,
+ 0x4e70,0x4e71,0x4e72,0x4e73,0x4e74,0x4e75,0x4e76,0x4e77,
+ 0x4e78,0x4e79,0x4e7a,0x4e7b,0x4e7c,0x4e7d,0x4e7e,0x4e7f,
+ 0x4e80,0x4e81,0x4e82,0x4e83,0x4e84,0x4e85,0x4e86,0x4e87,
+ 0x4e88,0x4e89,0x4e8a,0x4e8b,0x4e8c,0x4e8d,0x4e8e,0x4e8f,
+ 0x4e90,0x4e91,0x4e92,0x4e93,0x4e94,0x4e95,0x4e96,0x4e97,
+ 0x4e98,0x4e99,0x4e9a,0x4e9b,0x4e9c,0x4e9d,0x4e9e,0x4e9f,
+ 0x4ea0,0x4ea1,0x4ea2,0x4ea3,0x4ea4,0x4ea5,0x4ea6,0x4ea7,
+ 0x4ea8,0x4ea9,0x4eaa,0x4eab,0x4eac,0x4ead,0x4eae,0x4eaf,
+ 0x4eb0,0x4eb1,0x4eb2,0x4eb3,0x4eb4,0x4eb5,0x4eb6,0x4eb7,
+ 0x4eb8,0x4eb9,0x4eba,0x4ebb,0x4ebc,0x4ebd,0x4ebe,0x4ebf,
+ 0x4ec0,0x4ec1,0x4ec2,0x4ec3,0x4ec4,0x4ec5,0x4ec6,0x4ec7,
+ 0x4ec8,0x4ec9,0x4eca,0x4ecb,0x4ecc,0x4ecd,0x4ece,0x4ecf,
+ 0x4ed0,0x4ed1,0x4ed2,0x4ed3,0x4ed4,0x4ed5,0x4ed6,0x4ed7,
+ 0x4ed8,0x4ed9,0x4eda,0x4edb,0x4edc,0x4edd,0x4ede,0x4edf,
+ 0x4ee0,0x4ee1,0x4ee2,0x4ee3,0x4ee4,0x4ee5,0x4ee6,0x4ee7,
+ 0x4ee8,0x4ee9,0x4eea,0x4eeb,0x4eec,0x4eed,0x4eee,0x4eef,
+ 0x4ef0,0x4ef1,0x4ef2,0x4ef3,0x4ef4,0x4ef5,0x4ef6,0x4ef7,
+ 0x4ef8,0x4ef9,0x4efa,0x4efb,0x4efc,0x4efd,0x4efe,0x4eff,
+ 0x4f00,0x4f01,0x4f02,0x4f03,0x4f04,0x4f05,0x4f06,0x4f07,
+ 0x4f08,0x4f09,0x4f0a,0x4f0b,0x4f0c,0x4f0d,0x4f0e,0x4f0f,
+ 0x4f10,0x4f11,0x4f12,0x4f13,0x4f14,0x4f15,0x4f16,0x4f17,
+ 0x4f18,0x4f19,0x4f1a,0x4f1b,0x4f1c,0x4f1d,0x4f1e,0x4f1f,
+ 0x4f20,0x4f21,0x4f22,0x4f23,0x4f24,0x4f25,0x4f26,0x4f27,
+ 0x4f28,0x4f29,0x4f2a,0x4f2b,0x4f2c,0x4f2d,0x4f2e,0x4f2f,
+ 0x4f30,0x4f31,0x4f32,0x4f33,0x4f34,0x4f35,0x4f36,0x4f37,
+ 0x4f38,0x4f39,0x4f3a,0x4f3b,0x4f3c,0x4f3d,0x4f3e,0x4f3f,
+ 0x4f40,0x4f41,0x4f42,0x4f43,0x4f44,0x4f45,0x4f46,0x4f47,
+ 0x4f48,0x4f49,0x4f4a,0x4f4b,0x4f4c,0x4f4d,0x4f4e,0x4f4f,
+ 0x4f50,0x4f51,0x4f52,0x4f53,0x4f54,0x4f55,0x4f56,0x4f57,
+ 0x4f58,0x4f59,0x4f5a,0x4f5b,0x4f5c,0x4f5d,0x4f5e,0x4f5f,
+ 0x4f60,0x4f61,0x4f62,0x4f63,0x4f64,0x4f65,0x4f66,0x4f67,
+ 0x4f68,0x4f69,0x4f6a,0x4f6b,0x4f6c,0x4f6d,0x4f6e,0x4f6f,
+ 0x4f70,0x4f71,0x4f72,0x4f73,0x4f74,0x4f75,0x4f76,0x4f77,
+ 0x4f78,0x4f79,0x4f7a,0x4f7b,0x4f7c,0x4f7d,0x4f7e,0x4f7f,
+ 0x4f80,0x4f81,0x4f82,0x4f83,0x4f84,0x4f85,0x4f86,0x4f87,
+ 0x4f88,0x4f89,0x4f8a,0x4f8b,0x4f8c,0x4f8d,0x4f8e,0x4f8f,
+ 0x4f90,0x4f91,0x4f92,0x4f93,0x4f94,0x4f95,0x4f96,0x4f97,
+ 0x4f98,0x4f99,0x4f9a,0x4f9b,0x4f9c,0x4f9d,0x4f9e,0x4f9f,
+ 0x4fa0,0x4fa1,0x4fa2,0x4fa3,0x4fa4,0x4fa5,0x4fa6,0x4fa7,
+ 0x4fa8,0x4fa9,0x4faa,0x4fab,0x4fac,0x4fad,0x4fae,0x4faf,
+ 0x4fb0,0x4fb1,0x4fb2,0x4fb3,0x4fb4,0x4fb5,0x4fb6,0x4fb7,
+ 0x4fb8,0x4fb9,0x4fba,0x4fbb,0x4fbc,0x4fbd,0x4fbe,0x4fbf,
+ 0x4fc0,0x4fc1,0x4fc2,0x4fc3,0x4fc4,0x4fc5,0x4fc6,0x4fc7,
+ 0x4fc8,0x4fc9,0x4fca,0x4fcb,0x4fcc,0x4fcd,0x4fce,0x4fcf,
+ 0x4fd0,0x4fd1,0x4fd2,0x4fd3,0x4fd4,0x4fd5,0x4fd6,0x4fd7,
+ 0x4fd8,0x4fd9,0x4fda,0x4fdb,0x4fdc,0x4fdd,0x4fde,0x4fdf,
+ 0x4fe0,0x4fe1,0x4fe2,0x4fe3,0x4fe4,0x4fe5,0x4fe6,0x4fe7,
+ 0x4fe8,0x4fe9,0x4fea,0x4feb,0x4fec,0x4fed,0x4fee,0x4fef,
+ 0x4ff0,0x4ff1,0x4ff2,0x4ff3,0x4ff4,0x4ff5,0x4ff6,0x4ff7,
+ 0x4ff8,0x4ff9,0x4ffa,0x4ffb,0x4ffc,0x4ffd,0x4ffe,0x4fff,
+ 0x5000,0x5001,0x5002,0x5003,0x5004,0x5005,0x5006,0x5007,
+ 0x5008,0x5009,0x500a,0x500b,0x500c,0x500d,0x500e,0x500f,
+ 0x5010,0x5011,0x5012,0x5013,0x5014,0x5015,0x5016,0x5017,
+ 0x5018,0x5019,0x501a,0x501b,0x501c,0x501d,0x501e,0x501f,
+ 0x5020,0x5021,0x5022,0x5023,0x5024,0x5025,0x5026,0x5027,
+ 0x5028,0x5029,0x502a,0x502b,0x502c,0x502d,0x502e,0x502f,
+ 0x5030,0x5031,0x5032,0x5033,0x5034,0x5035,0x5036,0x5037,
+ 0x5038,0x5039,0x503a,0x503b,0x503c,0x503d,0x503e,0x503f,
+ 0x5040,0x5041,0x5042,0x5043,0x5044,0x5045,0x5046,0x5047,
+ 0x5048,0x5049,0x504a,0x504b,0x504c,0x504d,0x504e,0x504f,
+ 0x5050,0x5051,0x5052,0x5053,0x5054,0x5055,0x5056,0x5057,
+ 0x5058,0x5059,0x505a,0x505b,0x505c,0x505d,0x505e,0x505f,
+ 0x5060,0x5061,0x5062,0x5063,0x5064,0x5065,0x5066,0x5067,
+ 0x5068,0x5069,0x506a,0x506b,0x506c,0x506d,0x506e,0x506f,
+ 0x5070,0x5071,0x5072,0x5073,0x5074,0x5075,0x5076,0x5077,
+ 0x5078,0x5079,0x507a,0x507b,0x507c,0x507d,0x507e,0x507f,
+ 0x5080,0x5081,0x5082,0x5083,0x5084,0x5085,0x5086,0x5087,
+ 0x5088,0x5089,0x508a,0x508b,0x508c,0x508d,0x508e,0x508f,
+ 0x5090,0x5091,0x5092,0x5093,0x5094,0x5095,0x5096,0x5097,
+ 0x5098,0x5099,0x509a,0x509b,0x509c,0x509d,0x509e,0x509f,
+ 0x50a0,0x50a1,0x50a2,0x50a3,0x50a4,0x50a5,0x50a6,0x50a7,
+ 0x50a8,0x50a9,0x50aa,0x50ab,0x50ac,0x50ad,0x50ae,0x50af,
+ 0x50b0,0x50b1,0x50b2,0x50b3,0x50b4,0x50b5,0x50b6,0x50b7,
+ 0x50b8,0x50b9,0x50ba,0x50bb,0x50bc,0x50bd,0x50be,0x50bf,
+ 0x50c0,0x50c1,0x50c2,0x50c3,0x50c4,0x50c5,0x50c6,0x50c7,
+ 0x50c8,0x50c9,0x50ca,0x50cb,0x50cc,0x50cd,0x50ce,0x50cf,
+ 0x50d0,0x50d1,0x50d2,0x50d3,0x50d4,0x50d5,0x50d6,0x50d7,
+ 0x50d8,0x50d9,0x50da,0x50db,0x50dc,0x50dd,0x50de,0x50df,
+ 0x50e0,0x50e1,0x50e2,0x50e3,0x50e4,0x50e5,0x50e6,0x50e7,
+ 0x50e8,0x50e9,0x50ea,0x50eb,0x50ec,0x50ed,0x50ee,0x50ef,
+ 0x50f0,0x50f1,0x50f2,0x50f3,0x50f4,0x50f5,0x50f6,0x50f7,
+ 0x50f8,0x50f9,0x50fa,0x50fb,0x50fc,0x50fd,0x50fe,0x50ff,
+ 0x5100,0x5101,0x5102,0x5103,0x5104,0x5105,0x5106,0x5107,
+ 0x5108,0x5109,0x510a,0x510b,0x510c,0x510d,0x510e,0x510f,
+ 0x5110,0x5111,0x5112,0x5113,0x5114,0x5115,0x5116,0x5117,
+ 0x5118,0x5119,0x511a,0x511b,0x511c,0x511d,0x511e,0x511f,
+ 0x5120,0x5121,0x5122,0x5123,0x5124,0x5125,0x5126,0x5127,
+ 0x5128,0x5129,0x512a,0x512b,0x512c,0x512d,0x512e,0x512f,
+ 0x5130,0x5131,0x5132,0x5133,0x5134,0x5135,0x5136,0x5137,
+ 0x5138,0x5139,0x513a,0x513b,0x513c,0x513d,0x513e,0x513f,
+ 0x5140,0x5141,0x5142,0x5143,0x5144,0x5145,0x5146,0x5147,
+ 0x5148,0x5149,0x514a,0x514b,0x514c,0x514d,0x514e,0x514f,
+ 0x5150,0x5151,0x5152,0x5153,0x5154,0x5155,0x5156,0x5157,
+ 0x5158,0x5159,0x515a,0x515b,0x515c,0x515d,0x515e,0x515f,
+ 0x5160,0x5161,0x5162,0x5163,0x5164,0x5165,0x5166,0x5167,
+ 0x5168,0x5169,0x516a,0x516b,0x516c,0x516d,0x516e,0x516f,
+ 0x5170,0x5171,0x5172,0x5173,0x5174,0x5175,0x5176,0x5177,
+ 0x5178,0x5179,0x517a,0x517b,0x517c,0x517d,0x517e,0x517f,
+ 0x5180,0x5181,0x5182,0x5183,0x5184,0x5185,0x5186,0x5187,
+ 0x5188,0x5189,0x518a,0x518b,0x518c,0x518d,0x518e,0x518f,
+ 0x5190,0x5191,0x5192,0x5193,0x5194,0x5195,0x5196,0x5197,
+ 0x5198,0x5199,0x519a,0x519b,0x519c,0x519d,0x519e,0x519f,
+ 0x51a0,0x51a1,0x51a2,0x51a3,0x51a4,0x51a5,0x51a6,0x51a7,
+ 0x51a8,0x51a9,0x51aa,0x51ab,0x51ac,0x51ad,0x51ae,0x51af,
+ 0x51b0,0x51b1,0x51b2,0x51b3,0x51b4,0x51b5,0x51b6,0x51b7,
+ 0x51b8,0x51b9,0x51ba,0x51bb,0x51bc,0x51bd,0x51be,0x51bf,
+ 0x51c0,0x51c1,0x51c2,0x51c3,0x51c4,0x51c5,0x51c6,0x51c7,
+ 0x51c8,0x51c9,0x51ca,0x51cb,0x51cc,0x51cd,0x51ce,0x51cf,
+ 0x51d0,0x51d1,0x51d2,0x51d3,0x51d4,0x51d5,0x51d6,0x51d7,
+ 0x51d8,0x51d9,0x51da,0x51db,0x51dc,0x51dd,0x51de,0x51df,
+ 0x51e0,0x51e1,0x51e2,0x51e3,0x51e4,0x51e5,0x51e6,0x51e7,
+ 0x51e8,0x51e9,0x51ea,0x51eb,0x51ec,0x51ed,0x51ee,0x51ef,
+ 0x51f0,0x51f1,0x51f2,0x51f3,0x51f4,0x51f5,0x51f6,0x51f7,
+ 0x51f8,0x51f9,0x51fa,0x51fb,0x51fc,0x51fd,0x51fe,0x51ff,
+ 0x5200,0x5201,0x5202,0x5203,0x5204,0x5205,0x5206,0x5207,
+ 0x5208,0x5209,0x520a,0x520b,0x520c,0x520d,0x520e,0x520f,
+ 0x5210,0x5211,0x5212,0x5213,0x5214,0x5215,0x5216,0x5217,
+ 0x5218,0x5219,0x521a,0x521b,0x521c,0x521d,0x521e,0x521f,
+ 0x5220,0x5221,0x5222,0x5223,0x5224,0x5225,0x5226,0x5227,
+ 0x5228,0x5229,0x522a,0x522b,0x522c,0x522d,0x522e,0x522f,
+ 0x5230,0x5231,0x5232,0x5233,0x5234,0x5235,0x5236,0x5237,
+ 0x5238,0x5239,0x523a,0x523b,0x523c,0x523d,0x523e,0x523f,
+ 0x5240,0x5241,0x5242,0x5243,0x5244,0x5245,0x5246,0x5247,
+ 0x5248,0x5249,0x524a,0x524b,0x524c,0x524d,0x524e,0x524f,
+ 0x5250,0x5251,0x5252,0x5253,0x5254,0x5255,0x5256,0x5257,
+ 0x5258,0x5259,0x525a,0x525b,0x525c,0x525d,0x525e,0x525f,
+ 0x5260,0x5261,0x5262,0x5263,0x5264,0x5265,0x5266,0x5267,
+ 0x5268,0x5269,0x526a,0x526b,0x526c,0x526d,0x526e,0x526f,
+ 0x5270,0x5271,0x5272,0x5273,0x5274,0x5275,0x5276,0x5277,
+ 0x5278,0x5279,0x527a,0x527b,0x527c,0x527d,0x527e,0x527f,
+ 0x5280,0x5281,0x5282,0x5283,0x5284,0x5285,0x5286,0x5287,
+ 0x5288,0x5289,0x528a,0x528b,0x528c,0x528d,0x528e,0x528f,
+ 0x5290,0x5291,0x5292,0x5293,0x5294,0x5295,0x5296,0x5297,
+ 0x5298,0x5299,0x529a,0x529b,0x529c,0x529d,0x529e,0x529f,
+ 0x52a0,0x52a1,0x52a2,0x52a3,0x52a4,0x52a5,0x52a6,0x52a7,
+ 0x52a8,0x52a9,0x52aa,0x52ab,0x52ac,0x52ad,0x52ae,0x52af,
+ 0x52b0,0x52b1,0x52b2,0x52b3,0x52b4,0x52b5,0x52b6,0x52b7,
+ 0x52b8,0x52b9,0x52ba,0x52bb,0x52bc,0x52bd,0x52be,0x52bf,
+ 0x52c0,0x52c1,0x52c2,0x52c3,0x52c4,0x52c5,0x52c6,0x52c7,
+ 0x52c8,0x52c9,0x52ca,0x52cb,0x52cc,0x52cd,0x52ce,0x52cf,
+ 0x52d0,0x52d1,0x52d2,0x52d3,0x52d4,0x52d5,0x52d6,0x52d7,
+ 0x52d8,0x52d9,0x52da,0x52db,0x52dc,0x52dd,0x52de,0x52df,
+ 0x52e0,0x52e1,0x52e2,0x52e3,0x52e4,0x52e5,0x52e6,0x52e7,
+ 0x52e8,0x52e9,0x52ea,0x52eb,0x52ec,0x52ed,0x52ee,0x52ef,
+ 0x52f0,0x52f1,0x52f2,0x52f3,0x52f4,0x52f5,0x52f6,0x52f7,
+ 0x52f8,0x52f9,0x52fa,0x52fb,0x52fc,0x52fd,0x52fe,0x52ff,
+ 0x5300,0x5301,0x5302,0x5303,0x5304,0x5305,0x5306,0x5307,
+ 0x5308,0x5309,0x530a,0x530b,0x530c,0x530d,0x530e,0x530f,
+ 0x5310,0x5311,0x5312,0x5313,0x5314,0x5315,0x5316,0x5317,
+ 0x5318,0x5319,0x531a,0x531b,0x531c,0x531d,0x531e,0x531f,
+ 0x5320,0x5321,0x5322,0x5323,0x5324,0x5325,0x5326,0x5327,
+ 0x5328,0x5329,0x532a,0x532b,0x532c,0x532d,0x532e,0x532f,
+ 0x5330,0x5331,0x5332,0x5333,0x5334,0x5335,0x5336,0x5337,
+ 0x5338,0x5339,0x533a,0x533b,0x533c,0x533d,0x533e,0x533f,
+ 0x5340,0x5341,0x5342,0x5343,0x5344,0x5345,0x5346,0x5347,
+ 0x5348,0x5349,0x534a,0x534b,0x534c,0x534d,0x534e,0x534f,
+ 0x5350,0x5351,0x5352,0x5353,0x5354,0x5355,0x5356,0x5357,
+ 0x5358,0x5359,0x535a,0x535b,0x535c,0x535d,0x535e,0x535f,
+ 0x5360,0x5361,0x5362,0x5363,0x5364,0x5365,0x5366,0x5367,
+ 0x5368,0x5369,0x536a,0x536b,0x536c,0x536d,0x536e,0x536f,
+ 0x5370,0x5371,0x5372,0x5373,0x5374,0x5375,0x5376,0x5377,
+ 0x5378,0x5379,0x537a,0x537b,0x537c,0x537d,0x537e,0x537f,
+ 0x5380,0x5381,0x5382,0x5383,0x5384,0x5385,0x5386,0x5387,
+ 0x5388,0x5389,0x538a,0x538b,0x538c,0x538d,0x538e,0x538f,
+ 0x5390,0x5391,0x5392,0x5393,0x5394,0x5395,0x5396,0x5397,
+ 0x5398,0x5399,0x539a,0x539b,0x539c,0x539d,0x539e,0x539f,
+ 0x53a0,0x53a1,0x53a2,0x53a3,0x53a4,0x53a5,0x53a6,0x53a7,
+ 0x53a8,0x53a9,0x53aa,0x53ab,0x53ac,0x53ad,0x53ae,0x53af,
+ 0x53b0,0x53b1,0x53b2,0x53b3,0x53b4,0x53b5,0x53b6,0x53b7,
+ 0x53b8,0x53b9,0x53ba,0x53bb,0x53bc,0x53bd,0x53be,0x53bf,
+ 0x53c0,0x53c1,0x53c2,0x53c3,0x53c4,0x53c5,0x53c6,0x53c7,
+ 0x53c8,0x53c9,0x53ca,0x53cb,0x53cc,0x53cd,0x53ce,0x53cf,
+ 0x53d0,0x53d1,0x53d2,0x53d3,0x53d4,0x53d5,0x53d6,0x53d7,
+ 0x53d8,0x53d9,0x53da,0x53db,0x53dc,0x53dd,0x53de,0x53df,
+ 0x53e0,0x53e1,0x53e2,0x53e3,0x53e4,0x53e5,0x53e6,0x53e7,
+ 0x53e8,0x53e9,0x53ea,0x53eb,0x53ec,0x53ed,0x53ee,0x53ef,
+ 0x53f0,0x53f1,0x53f2,0x53f3,0x53f4,0x53f5,0x53f6,0x53f7,
+ 0x53f8,0x53f9,0x53fa,0x53fb,0x53fc,0x53fd,0x53fe,0x53ff,
+ 0x5400,0x5401,0x5402,0x5403,0x5404,0x5405,0x5406,0x5407,
+ 0x5408,0x5409,0x540a,0x540b,0x540c,0x540d,0x540e,0x540f,
+ 0x5410,0x5411,0x5412,0x5413,0x5414,0x5415,0x5416,0x5417,
+ 0x5418,0x5419,0x541a,0x541b,0x541c,0x541d,0x541e,0x541f,
+ 0x5420,0x5421,0x5422,0x5423,0x5424,0x5425,0x5426,0x5427,
+ 0x5428,0x5429,0x542a,0x542b,0x542c,0x542d,0x542e,0x542f,
+ 0x5430,0x5431,0x5432,0x5433,0x5434,0x5435,0x5436,0x5437,
+ 0x5438,0x5439,0x543a,0x543b,0x543c,0x543d,0x543e,0x543f,
+ 0x5440,0x5441,0x5442,0x5443,0x5444,0x5445,0x5446,0x5447,
+ 0x5448,0x5449,0x544a,0x544b,0x544c,0x544d,0x544e,0x544f,
+ 0x5450,0x5451,0x5452,0x5453,0x5454,0x5455,0x5456,0x5457,
+ 0x5458,0x5459,0x545a,0x545b,0x545c,0x545d,0x545e,0x545f,
+ 0x5460,0x5461,0x5462,0x5463,0x5464,0x5465,0x5466,0x5467,
+ 0x5468,0x5469,0x546a,0x546b,0x546c,0x546d,0x546e,0x546f,
+ 0x5470,0x5471,0x5472,0x5473,0x5474,0x5475,0x5476,0x5477,
+ 0x5478,0x5479,0x547a,0x547b,0x547c,0x547d,0x547e,0x547f,
+ 0x5480,0x5481,0x5482,0x5483,0x5484,0x5485,0x5486,0x5487,
+ 0x5488,0x5489,0x548a,0x548b,0x548c,0x548d,0x548e,0x548f,
+ 0x5490,0x5491,0x5492,0x5493,0x5494,0x5495,0x5496,0x5497,
+ 0x5498,0x5499,0x549a,0x549b,0x549c,0x549d,0x549e,0x549f,
+ 0x54a0,0x54a1,0x54a2,0x54a3,0x54a4,0x54a5,0x54a6,0x54a7,
+ 0x54a8,0x54a9,0x54aa,0x54ab,0x54ac,0x54ad,0x54ae,0x54af,
+ 0x54b0,0x54b1,0x54b2,0x54b3,0x54b4,0x54b5,0x54b6,0x54b7,
+ 0x54b8,0x54b9,0x54ba,0x54bb,0x54bc,0x54bd,0x54be,0x54bf,
+ 0x54c0,0x54c1,0x54c2,0x54c3,0x54c4,0x54c5,0x54c6,0x54c7,
+ 0x54c8,0x54c9,0x54ca,0x54cb,0x54cc,0x54cd,0x54ce,0x54cf,
+ 0x54d0,0x54d1,0x54d2,0x54d3,0x54d4,0x54d5,0x54d6,0x54d7,
+ 0x54d8,0x54d9,0x54da,0x54db,0x54dc,0x54dd,0x54de,0x54df,
+ 0x54e0,0x54e1,0x54e2,0x54e3,0x54e4,0x54e5,0x54e6,0x54e7,
+ 0x54e8,0x54e9,0x54ea,0x54eb,0x54ec,0x54ed,0x54ee,0x54ef,
+ 0x54f0,0x54f1,0x54f2,0x54f3,0x54f4,0x54f5,0x54f6,0x54f7,
+ 0x54f8,0x54f9,0x54fa,0x54fb,0x54fc,0x54fd,0x54fe,0x54ff,
+ 0x5500,0x5501,0x5502,0x5503,0x5504,0x5505,0x5506,0x5507,
+ 0x5508,0x5509,0x550a,0x550b,0x550c,0x550d,0x550e,0x550f,
+ 0x5510,0x5511,0x5512,0x5513,0x5514,0x5515,0x5516,0x5517,
+ 0x5518,0x5519,0x551a,0x551b,0x551c,0x551d,0x551e,0x551f,
+ 0x5520,0x5521,0x5522,0x5523,0x5524,0x5525,0x5526,0x5527,
+ 0x5528,0x5529,0x552a,0x552b,0x552c,0x552d,0x552e,0x552f,
+ 0x5530,0x5531,0x5532,0x5533,0x5534,0x5535,0x5536,0x5537,
+ 0x5538,0x5539,0x553a,0x553b,0x553c,0x553d,0x553e,0x553f,
+ 0x5540,0x5541,0x5542,0x5543,0x5544,0x5545,0x5546,0x5547,
+ 0x5548,0x5549,0x554a,0x554b,0x554c,0x554d,0x554e,0x554f,
+ 0x5550,0x5551,0x5552,0x5553,0x5554,0x5555,0x5556,0x5557,
+ 0x5558,0x5559,0x555a,0x555b,0x555c,0x555d,0x555e,0x555f,
+ 0x5560,0x5561,0x5562,0x5563,0x5564,0x5565,0x5566,0x5567,
+ 0x5568,0x5569,0x556a,0x556b,0x556c,0x556d,0x556e,0x556f,
+ 0x5570,0x5571,0x5572,0x5573,0x5574,0x5575,0x5576,0x5577,
+ 0x5578,0x5579,0x557a,0x557b,0x557c,0x557d,0x557e,0x557f,
+ 0x5580,0x5581,0x5582,0x5583,0x5584,0x5585,0x5586,0x5587,
+ 0x5588,0x5589,0x558a,0x558b,0x558c,0x558d,0x558e,0x558f,
+ 0x5590,0x5591,0x5592,0x5593,0x5594,0x5595,0x5596,0x5597,
+ 0x5598,0x5599,0x559a,0x559b,0x559c,0x559d,0x559e,0x559f,
+ 0x55a0,0x55a1,0x55a2,0x55a3,0x55a4,0x55a5,0x55a6,0x55a7,
+ 0x55a8,0x55a9,0x55aa,0x55ab,0x55ac,0x55ad,0x55ae,0x55af,
+ 0x55b0,0x55b1,0x55b2,0x55b3,0x55b4,0x55b5,0x55b6,0x55b7,
+ 0x55b8,0x55b9,0x55ba,0x55bb,0x55bc,0x55bd,0x55be,0x55bf,
+ 0x55c0,0x55c1,0x55c2,0x55c3,0x55c4,0x55c5,0x55c6,0x55c7,
+ 0x55c8,0x55c9,0x55ca,0x55cb,0x55cc,0x55cd,0x55ce,0x55cf,
+ 0x55d0,0x55d1,0x55d2,0x55d3,0x55d4,0x55d5,0x55d6,0x55d7,
+ 0x55d8,0x55d9,0x55da,0x55db,0x55dc,0x55dd,0x55de,0x55df,
+ 0x55e0,0x55e1,0x55e2,0x55e3,0x55e4,0x55e5,0x55e6,0x55e7,
+ 0x55e8,0x55e9,0x55ea,0x55eb,0x55ec,0x55ed,0x55ee,0x55ef,
+ 0x55f0,0x55f1,0x55f2,0x55f3,0x55f4,0x55f5,0x55f6,0x55f7,
+ 0x55f8,0x55f9,0x55fa,0x55fb,0x55fc,0x55fd,0x55fe,0x55ff,
+ 0x5600,0x5601,0x5602,0x5603,0x5604,0x5605,0x5606,0x5607,
+ 0x5608,0x5609,0x560a,0x560b,0x560c,0x560d,0x560e,0x560f,
+ 0x5610,0x5611,0x5612,0x5613,0x5614,0x5615,0x5616,0x5617,
+ 0x5618,0x5619,0x561a,0x561b,0x561c,0x561d,0x561e,0x561f,
+ 0x5620,0x5621,0x5622,0x5623,0x5624,0x5625,0x5626,0x5627,
+ 0x5628,0x5629,0x562a,0x562b,0x562c,0x562d,0x562e,0x562f,
+ 0x5630,0x5631,0x5632,0x5633,0x5634,0x5635,0x5636,0x5637,
+ 0x5638,0x5639,0x563a,0x563b,0x563c,0x563d,0x563e,0x563f,
+ 0x5640,0x5641,0x5642,0x5643,0x5644,0x5645,0x5646,0x5647,
+ 0x5648,0x5649,0x564a,0x564b,0x564c,0x564d,0x564e,0x564f,
+ 0x5650,0x5651,0x5652,0x5653,0x5654,0x5655,0x5656,0x5657,
+ 0x5658,0x5659,0x565a,0x565b,0x565c,0x565d,0x565e,0x565f,
+ 0x5660,0x5661,0x5662,0x5663,0x5664,0x5665,0x5666,0x5667,
+ 0x5668,0x5669,0x566a,0x566b,0x566c,0x566d,0x566e,0x566f,
+ 0x5670,0x5671,0x5672,0x5673,0x5674,0x5675,0x5676,0x5677,
+ 0x5678,0x5679,0x567a,0x567b,0x567c,0x567d,0x567e,0x567f,
+ 0x5680,0x5681,0x5682,0x5683,0x5684,0x5685,0x5686,0x5687,
+ 0x5688,0x5689,0x568a,0x568b,0x568c,0x568d,0x568e,0x568f,
+ 0x5690,0x5691,0x5692,0x5693,0x5694,0x5695,0x5696,0x5697,
+ 0x5698,0x5699,0x569a,0x569b,0x569c,0x569d,0x569e,0x569f,
+ 0x56a0,0x56a1,0x56a2,0x56a3,0x56a4,0x56a5,0x56a6,0x56a7,
+ 0x56a8,0x56a9,0x56aa,0x56ab,0x56ac,0x56ad,0x56ae,0x56af,
+ 0x56b0,0x56b1,0x56b2,0x56b3,0x56b4,0x56b5,0x56b6,0x56b7,
+ 0x56b8,0x56b9,0x56ba,0x56bb,0x56bc,0x56bd,0x56be,0x56bf,
+ 0x56c0,0x56c1,0x56c2,0x56c3,0x56c4,0x56c5,0x56c6,0x56c7,
+ 0x56c8,0x56c9,0x56ca,0x56cb,0x56cc,0x56cd,0x56ce,0x56cf,
+ 0x56d0,0x56d1,0x56d2,0x56d3,0x56d4,0x56d5,0x56d6,0x56d7,
+ 0x56d8,0x56d9,0x56da,0x56db,0x56dc,0x56dd,0x56de,0x56df,
+ 0x56e0,0x56e1,0x56e2,0x56e3,0x56e4,0x56e5,0x56e6,0x56e7,
+ 0x56e8,0x56e9,0x56ea,0x56eb,0x56ec,0x56ed,0x56ee,0x56ef,
+ 0x56f0,0x56f1,0x56f2,0x56f3,0x56f4,0x56f5,0x56f6,0x56f7,
+ 0x56f8,0x56f9,0x56fa,0x56fb,0x56fc,0x56fd,0x56fe,0x56ff,
+ 0x5700,0x5701,0x5702,0x5703,0x5704,0x5705,0x5706,0x5707,
+ 0x5708,0x5709,0x570a,0x570b,0x570c,0x570d,0x570e,0x570f,
+ 0x5710,0x5711,0x5712,0x5713,0x5714,0x5715,0x5716,0x5717,
+ 0x5718,0x5719,0x571a,0x571b,0x571c,0x571d,0x571e,0x571f,
+ 0x5720,0x5721,0x5722,0x5723,0x5724,0x5725,0x5726,0x5727,
+ 0x5728,0x5729,0x572a,0x572b,0x572c,0x572d,0x572e,0x572f,
+ 0x5730,0x5731,0x5732,0x5733,0x5734,0x5735,0x5736,0x5737,
+ 0x5738,0x5739,0x573a,0x573b,0x573c,0x573d,0x573e,0x573f,
+ 0x5740,0x5741,0x5742,0x5743,0x5744,0x5745,0x5746,0x5747,
+ 0x5748,0x5749,0x574a,0x574b,0x574c,0x574d,0x574e,0x574f,
+ 0x5750,0x5751,0x5752,0x5753,0x5754,0x5755,0x5756,0x5757,
+ 0x5758,0x5759,0x575a,0x575b,0x575c,0x575d,0x575e,0x575f,
+ 0x5760,0x5761,0x5762,0x5763,0x5764,0x5765,0x5766,0x5767,
+ 0x5768,0x5769,0x576a,0x576b,0x576c,0x576d,0x576e,0x576f,
+ 0x5770,0x5771,0x5772,0x5773,0x5774,0x5775,0x5776,0x5777,
+ 0x5778,0x5779,0x577a,0x577b,0x577c,0x577d,0x577e,0x577f,
+ 0x5780,0x5781,0x5782,0x5783,0x5784,0x5785,0x5786,0x5787,
+ 0x5788,0x5789,0x578a,0x578b,0x578c,0x578d,0x578e,0x578f,
+ 0x5790,0x5791,0x5792,0x5793,0x5794,0x5795,0x5796,0x5797,
+ 0x5798,0x5799,0x579a,0x579b,0x579c,0x579d,0x579e,0x579f,
+ 0x57a0,0x57a1,0x57a2,0x57a3,0x57a4,0x57a5,0x57a6,0x57a7,
+ 0x57a8,0x57a9,0x57aa,0x57ab,0x57ac,0x57ad,0x57ae,0x57af,
+ 0x57b0,0x57b1,0x57b2,0x57b3,0x57b4,0x57b5,0x57b6,0x57b7,
+ 0x57b8,0x57b9,0x57ba,0x57bb,0x57bc,0x57bd,0x57be,0x57bf,
+ 0x57c0,0x57c1,0x57c2,0x57c3,0x57c4,0x57c5,0x57c6,0x57c7,
+ 0x57c8,0x57c9,0x57ca,0x57cb,0x57cc,0x57cd,0x57ce,0x57cf,
+ 0x57d0,0x57d1,0x57d2,0x57d3,0x57d4,0x57d5,0x57d6,0x57d7,
+ 0x57d8,0x57d9,0x57da,0x57db,0x57dc,0x57dd,0x57de,0x57df,
+ 0x57e0,0x57e1,0x57e2,0x57e3,0x57e4,0x57e5,0x57e6,0x57e7,
+ 0x57e8,0x57e9,0x57ea,0x57eb,0x57ec,0x57ed,0x57ee,0x57ef,
+ 0x57f0,0x57f1,0x57f2,0x57f3,0x57f4,0x57f5,0x57f6,0x57f7,
+ 0x57f8,0x57f9,0x57fa,0x57fb,0x57fc,0x57fd,0x57fe,0x57ff,
+ 0x5800,0x5801,0x5802,0x5803,0x5804,0x5805,0x5806,0x5807,
+ 0x5808,0x5809,0x580a,0x580b,0x580c,0x580d,0x580e,0x580f,
+ 0x5810,0x5811,0x5812,0x5813,0x5814,0x5815,0x5816,0x5817,
+ 0x5818,0x5819,0x581a,0x581b,0x581c,0x581d,0x581e,0x581f,
+ 0x5820,0x5821,0x5822,0x5823,0x5824,0x5825,0x5826,0x5827,
+ 0x5828,0x5829,0x582a,0x582b,0x582c,0x582d,0x582e,0x582f,
+ 0x5830,0x5831,0x5832,0x5833,0x5834,0x5835,0x5836,0x5837,
+ 0x5838,0x5839,0x583a,0x583b,0x583c,0x583d,0x583e,0x583f,
+ 0x5840,0x5841,0x5842,0x5843,0x5844,0x5845,0x5846,0x5847,
+ 0x5848,0x5849,0x584a,0x584b,0x584c,0x584d,0x584e,0x584f,
+ 0x5850,0x5851,0x5852,0x5853,0x5854,0x5855,0x5856,0x5857,
+ 0x5858,0x5859,0x585a,0x585b,0x585c,0x585d,0x585e,0x585f,
+ 0x5860,0x5861,0x5862,0x5863,0x5864,0x5865,0x5866,0x5867,
+ 0x5868,0x5869,0x586a,0x586b,0x586c,0x586d,0x586e,0x586f,
+ 0x5870,0x5871,0x5872,0x5873,0x5874,0x5875,0x5876,0x5877,
+ 0x5878,0x5879,0x587a,0x587b,0x587c,0x587d,0x587e,0x587f,
+ 0x5880,0x5881,0x5882,0x5883,0x5884,0x5885,0x5886,0x5887,
+ 0x5888,0x5889,0x588a,0x588b,0x588c,0x588d,0x588e,0x588f,
+ 0x5890,0x5891,0x5892,0x5893,0x5894,0x5895,0x5896,0x5897,
+ 0x5898,0x5899,0x589a,0x589b,0x589c,0x589d,0x589e,0x589f,
+ 0x58a0,0x58a1,0x58a2,0x58a3,0x58a4,0x58a5,0x58a6,0x58a7,
+ 0x58a8,0x58a9,0x58aa,0x58ab,0x58ac,0x58ad,0x58ae,0x58af,
+ 0x58b0,0x58b1,0x58b2,0x58b3,0x58b4,0x58b5,0x58b6,0x58b7,
+ 0x58b8,0x58b9,0x58ba,0x58bb,0x58bc,0x58bd,0x58be,0x58bf,
+ 0x58c0,0x58c1,0x58c2,0x58c3,0x58c4,0x58c5,0x58c6,0x58c7,
+ 0x58c8,0x58c9,0x58ca,0x58cb,0x58cc,0x58cd,0x58ce,0x58cf,
+ 0x58d0,0x58d1,0x58d2,0x58d3,0x58d4,0x58d5,0x58d6,0x58d7,
+ 0x58d8,0x58d9,0x58da,0x58db,0x58dc,0x58dd,0x58de,0x58df,
+ 0x58e0,0x58e1,0x58e2,0x58e3,0x58e4,0x58e5,0x58e6,0x58e7,
+ 0x58e8,0x58e9,0x58ea,0x58eb,0x58ec,0x58ed,0x58ee,0x58ef,
+ 0x58f0,0x58f1,0x58f2,0x58f3,0x58f4,0x58f5,0x58f6,0x58f7,
+ 0x58f8,0x58f9,0x58fa,0x58fb,0x58fc,0x58fd,0x58fe,0x58ff,
+ 0x5900,0x5901,0x5902,0x5903,0x5904,0x5905,0x5906,0x5907,
+ 0x5908,0x5909,0x590a,0x590b,0x590c,0x590d,0x590e,0x590f,
+ 0x5910,0x5911,0x5912,0x5913,0x5914,0x5915,0x5916,0x5917,
+ 0x5918,0x5919,0x591a,0x591b,0x591c,0x591d,0x591e,0x591f,
+ 0x5920,0x5921,0x5922,0x5923,0x5924,0x5925,0x5926,0x5927,
+ 0x5928,0x5929,0x592a,0x592b,0x592c,0x592d,0x592e,0x592f,
+ 0x5930,0x5931,0x5932,0x5933,0x5934,0x5935,0x5936,0x5937,
+ 0x5938,0x5939,0x593a,0x593b,0x593c,0x593d,0x593e,0x593f,
+ 0x5940,0x5941,0x5942,0x5943,0x5944,0x5945,0x5946,0x5947,
+ 0x5948,0x5949,0x594a,0x594b,0x594c,0x594d,0x594e,0x594f,
+ 0x5950,0x5951,0x5952,0x5953,0x5954,0x5955,0x5956,0x5957,
+ 0x5958,0x5959,0x595a,0x595b,0x595c,0x595d,0x595e,0x595f,
+ 0x5960,0x5961,0x5962,0x5963,0x5964,0x5965,0x5966,0x5967,
+ 0x5968,0x5969,0x596a,0x596b,0x596c,0x596d,0x596e,0x596f,
+ 0x5970,0x5971,0x5972,0x5973,0x5974,0x5975,0x5976,0x5977,
+ 0x5978,0x5979,0x597a,0x597b,0x597c,0x597d,0x597e,0x597f,
+ 0x5980,0x5981,0x5982,0x5983,0x5984,0x5985,0x5986,0x5987,
+ 0x5988,0x5989,0x598a,0x598b,0x598c,0x598d,0x598e,0x598f,
+ 0x5990,0x5991,0x5992,0x5993,0x5994,0x5995,0x5996,0x5997,
+ 0x5998,0x5999,0x599a,0x599b,0x599c,0x599d,0x599e,0x599f,
+ 0x59a0,0x59a1,0x59a2,0x59a3,0x59a4,0x59a5,0x59a6,0x59a7,
+ 0x59a8,0x59a9,0x59aa,0x59ab,0x59ac,0x59ad,0x59ae,0x59af,
+ 0x59b0,0x59b1,0x59b2,0x59b3,0x59b4,0x59b5,0x59b6,0x59b7,
+ 0x59b8,0x59b9,0x59ba,0x59bb,0x59bc,0x59bd,0x59be,0x59bf,
+ 0x59c0,0x59c1,0x59c2,0x59c3,0x59c4,0x59c5,0x59c6,0x59c7,
+ 0x59c8,0x59c9,0x59ca,0x59cb,0x59cc,0x59cd,0x59ce,0x59cf,
+ 0x59d0,0x59d1,0x59d2,0x59d3,0x59d4,0x59d5,0x59d6,0x59d7,
+ 0x59d8,0x59d9,0x59da,0x59db,0x59dc,0x59dd,0x59de,0x59df,
+ 0x59e0,0x59e1,0x59e2,0x59e3,0x59e4,0x59e5,0x59e6,0x59e7,
+ 0x59e8,0x59e9,0x59ea,0x59eb,0x59ec,0x59ed,0x59ee,0x59ef,
+ 0x59f0,0x59f1,0x59f2,0x59f3,0x59f4,0x59f5,0x59f6,0x59f7,
+ 0x59f8,0x59f9,0x59fa,0x59fb,0x59fc,0x59fd,0x59fe,0x59ff,
+ 0x5a00,0x5a01,0x5a02,0x5a03,0x5a04,0x5a05,0x5a06,0x5a07,
+ 0x5a08,0x5a09,0x5a0a,0x5a0b,0x5a0c,0x5a0d,0x5a0e,0x5a0f,
+ 0x5a10,0x5a11,0x5a12,0x5a13,0x5a14,0x5a15,0x5a16,0x5a17,
+ 0x5a18,0x5a19,0x5a1a,0x5a1b,0x5a1c,0x5a1d,0x5a1e,0x5a1f,
+ 0x5a20,0x5a21,0x5a22,0x5a23,0x5a24,0x5a25,0x5a26,0x5a27,
+ 0x5a28,0x5a29,0x5a2a,0x5a2b,0x5a2c,0x5a2d,0x5a2e,0x5a2f,
+ 0x5a30,0x5a31,0x5a32,0x5a33,0x5a34,0x5a35,0x5a36,0x5a37,
+ 0x5a38,0x5a39,0x5a3a,0x5a3b,0x5a3c,0x5a3d,0x5a3e,0x5a3f,
+ 0x5a40,0x5a41,0x5a42,0x5a43,0x5a44,0x5a45,0x5a46,0x5a47,
+ 0x5a48,0x5a49,0x5a4a,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f,
+ 0x5a50,0x5a51,0x5a52,0x5a53,0x5a54,0x5a55,0x5a56,0x5a57,
+ 0x5a58,0x5a59,0x5a5a,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5a5f,
+ 0x5a60,0x5a61,0x5a62,0x5a63,0x5a64,0x5a65,0x5a66,0x5a67,
+ 0x5a68,0x5a69,0x5a6a,0x5a6b,0x5a6c,0x5a6d,0x5a6e,0x5a6f,
+ 0x5a70,0x5a71,0x5a72,0x5a73,0x5a74,0x5a75,0x5a76,0x5a77,
+ 0x5a78,0x5a79,0x5a7a,0x5a7b,0x5a7c,0x5a7d,0x5a7e,0x5a7f,
+ 0x5a80,0x5a81,0x5a82,0x5a83,0x5a84,0x5a85,0x5a86,0x5a87,
+ 0x5a88,0x5a89,0x5a8a,0x5a8b,0x5a8c,0x5a8d,0x5a8e,0x5a8f,
+ 0x5a90,0x5a91,0x5a92,0x5a93,0x5a94,0x5a95,0x5a96,0x5a97,
+ 0x5a98,0x5a99,0x5a9a,0x5a9b,0x5a9c,0x5a9d,0x5a9e,0x5a9f,
+ 0x5aa0,0x5aa1,0x5aa2,0x5aa3,0x5aa4,0x5aa5,0x5aa6,0x5aa7,
+ 0x5aa8,0x5aa9,0x5aaa,0x5aab,0x5aac,0x5aad,0x5aae,0x5aaf,
+ 0x5ab0,0x5ab1,0x5ab2,0x5ab3,0x5ab4,0x5ab5,0x5ab6,0x5ab7,
+ 0x5ab8,0x5ab9,0x5aba,0x5abb,0x5abc,0x5abd,0x5abe,0x5abf,
+ 0x5ac0,0x5ac1,0x5ac2,0x5ac3,0x5ac4,0x5ac5,0x5ac6,0x5ac7,
+ 0x5ac8,0x5ac9,0x5aca,0x5acb,0x5acc,0x5acd,0x5ace,0x5acf,
+ 0x5ad0,0x5ad1,0x5ad2,0x5ad3,0x5ad4,0x5ad5,0x5ad6,0x5ad7,
+ 0x5ad8,0x5ad9,0x5ada,0x5adb,0x5adc,0x5add,0x5ade,0x5adf,
+ 0x5ae0,0x5ae1,0x5ae2,0x5ae3,0x5ae4,0x5ae5,0x5ae6,0x5ae7,
+ 0x5ae8,0x5ae9,0x5aea,0x5aeb,0x5aec,0x5aed,0x5aee,0x5aef,
+ 0x5af0,0x5af1,0x5af2,0x5af3,0x5af4,0x5af5,0x5af6,0x5af7,
+ 0x5af8,0x5af9,0x5afa,0x5afb,0x5afc,0x5afd,0x5afe,0x5aff,
+ 0x5b00,0x5b01,0x5b02,0x5b03,0x5b04,0x5b05,0x5b06,0x5b07,
+ 0x5b08,0x5b09,0x5b0a,0x5b0b,0x5b0c,0x5b0d,0x5b0e,0x5b0f,
+ 0x5b10,0x5b11,0x5b12,0x5b13,0x5b14,0x5b15,0x5b16,0x5b17,
+ 0x5b18,0x5b19,0x5b1a,0x5b1b,0x5b1c,0x5b1d,0x5b1e,0x5b1f,
+ 0x5b20,0x5b21,0x5b22,0x5b23,0x5b24,0x5b25,0x5b26,0x5b27,
+ 0x5b28,0x5b29,0x5b2a,0x5b2b,0x5b2c,0x5b2d,0x5b2e,0x5b2f,
+ 0x5b30,0x5b31,0x5b32,0x5b33,0x5b34,0x5b35,0x5b36,0x5b37,
+ 0x5b38,0x5b39,0x5b3a,0x5b3b,0x5b3c,0x5b3d,0x5b3e,0x5b3f,
+ 0x5b40,0x5b41,0x5b42,0x5b43,0x5b44,0x5b45,0x5b46,0x5b47,
+ 0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f,
+ 0x5b50,0x5b51,0x5b52,0x5b53,0x5b54,0x5b55,0x5b56,0x5b57,
+ 0x5b58,0x5b59,0x5b5a,0x5b5b,0x5b5c,0x5b5d,0x5b5e,0x5b5f,
+ 0x5b60,0x5b61,0x5b62,0x5b63,0x5b64,0x5b65,0x5b66,0x5b67,
+ 0x5b68,0x5b69,0x5b6a,0x5b6b,0x5b6c,0x5b6d,0x5b6e,0x5b6f,
+ 0x5b70,0x5b71,0x5b72,0x5b73,0x5b74,0x5b75,0x5b76,0x5b77,
+ 0x5b78,0x5b79,0x5b7a,0x5b7b,0x5b7c,0x5b7d,0x5b7e,0x5b7f,
+ 0x5b80,0x5b81,0x5b82,0x5b83,0x5b84,0x5b85,0x5b86,0x5b87,
+ 0x5b88,0x5b89,0x5b8a,0x5b8b,0x5b8c,0x5b8d,0x5b8e,0x5b8f,
+ 0x5b90,0x5b91,0x5b92,0x5b93,0x5b94,0x5b95,0x5b96,0x5b97,
+ 0x5b98,0x5b99,0x5b9a,0x5b9b,0x5b9c,0x5b9d,0x5b9e,0x5b9f,
+ 0x5ba0,0x5ba1,0x5ba2,0x5ba3,0x5ba4,0x5ba5,0x5ba6,0x5ba7,
+ 0x5ba8,0x5ba9,0x5baa,0x5bab,0x5bac,0x5bad,0x5bae,0x5baf,
+ 0x5bb0,0x5bb1,0x5bb2,0x5bb3,0x5bb4,0x5bb5,0x5bb6,0x5bb7,
+ 0x5bb8,0x5bb9,0x5bba,0x5bbb,0x5bbc,0x5bbd,0x5bbe,0x5bbf,
+ 0x5bc0,0x5bc1,0x5bc2,0x5bc3,0x5bc4,0x5bc5,0x5bc6,0x5bc7,
+ 0x5bc8,0x5bc9,0x5bca,0x5bcb,0x5bcc,0x5bcd,0x5bce,0x5bcf,
+ 0x5bd0,0x5bd1,0x5bd2,0x5bd3,0x5bd4,0x5bd5,0x5bd6,0x5bd7,
+ 0x5bd8,0x5bd9,0x5bda,0x5bdb,0x5bdc,0x5bdd,0x5bde,0x5bdf,
+ 0x5be0,0x5be1,0x5be2,0x5be3,0x5be4,0x5be5,0x5be6,0x5be7,
+ 0x5be8,0x5be9,0x5bea,0x5beb,0x5bec,0x5bed,0x5bee,0x5bef,
+ 0x5bf0,0x5bf1,0x5bf2,0x5bf3,0x5bf4,0x5bf5,0x5bf6,0x5bf7,
+ 0x5bf8,0x5bf9,0x5bfa,0x5bfb,0x5bfc,0x5bfd,0x5bfe,0x5bff,
+ 0x5c00,0x5c01,0x5c02,0x5c03,0x5c04,0x5c05,0x5c06,0x5c07,
+ 0x5c08,0x5c09,0x5c0a,0x5c0b,0x5c0c,0x5c0d,0x5c0e,0x5c0f,
+ 0x5c10,0x5c11,0x5c12,0x5c13,0x5c14,0x5c15,0x5c16,0x5c17,
+ 0x5c18,0x5c19,0x5c1a,0x5c1b,0x5c1c,0x5c1d,0x5c1e,0x5c1f,
+ 0x5c20,0x5c21,0x5c22,0x5c23,0x5c24,0x5c25,0x5c26,0x5c27,
+ 0x5c28,0x5c29,0x5c2a,0x5c2b,0x5c2c,0x5c2d,0x5c2e,0x5c2f,
+ 0x5c30,0x5c31,0x5c32,0x5c33,0x5c34,0x5c35,0x5c36,0x5c37,
+ 0x5c38,0x5c39,0x5c3a,0x5c3b,0x5c3c,0x5c3d,0x5c3e,0x5c3f,
+ 0x5c40,0x5c41,0x5c42,0x5c43,0x5c44,0x5c45,0x5c46,0x5c47,
+ 0x5c48,0x5c49,0x5c4a,0x5c4b,0x5c4c,0x5c4d,0x5c4e,0x5c4f,
+ 0x5c50,0x5c51,0x5c52,0x5c53,0x5c54,0x5c55,0x5c56,0x5c57,
+ 0x5c58,0x5c59,0x5c5a,0x5c5b,0x5c5c,0x5c5d,0x5c5e,0x5c5f,
+ 0x5c60,0x5c61,0x5c62,0x5c63,0x5c64,0x5c65,0x5c66,0x5c67,
+ 0x5c68,0x5c69,0x5c6a,0x5c6b,0x5c6c,0x5c6d,0x5c6e,0x5c6f,
+ 0x5c70,0x5c71,0x5c72,0x5c73,0x5c74,0x5c75,0x5c76,0x5c77,
+ 0x5c78,0x5c79,0x5c7a,0x5c7b,0x5c7c,0x5c7d,0x5c7e,0x5c7f,
+ 0x5c80,0x5c81,0x5c82,0x5c83,0x5c84,0x5c85,0x5c86,0x5c87,
+ 0x5c88,0x5c89,0x5c8a,0x5c8b,0x5c8c,0x5c8d,0x5c8e,0x5c8f,
+ 0x5c90,0x5c91,0x5c92,0x5c93,0x5c94,0x5c95,0x5c96,0x5c97,
+ 0x5c98,0x5c99,0x5c9a,0x5c9b,0x5c9c,0x5c9d,0x5c9e,0x5c9f,
+ 0x5ca0,0x5ca1,0x5ca2,0x5ca3,0x5ca4,0x5ca5,0x5ca6,0x5ca7,
+ 0x5ca8,0x5ca9,0x5caa,0x5cab,0x5cac,0x5cad,0x5cae,0x5caf,
+ 0x5cb0,0x5cb1,0x5cb2,0x5cb3,0x5cb4,0x5cb5,0x5cb6,0x5cb7,
+ 0x5cb8,0x5cb9,0x5cba,0x5cbb,0x5cbc,0x5cbd,0x5cbe,0x5cbf,
+ 0x5cc0,0x5cc1,0x5cc2,0x5cc3,0x5cc4,0x5cc5,0x5cc6,0x5cc7,
+ 0x5cc8,0x5cc9,0x5cca,0x5ccb,0x5ccc,0x5ccd,0x5cce,0x5ccf,
+ 0x5cd0,0x5cd1,0x5cd2,0x5cd3,0x5cd4,0x5cd5,0x5cd6,0x5cd7,
+ 0x5cd8,0x5cd9,0x5cda,0x5cdb,0x5cdc,0x5cdd,0x5cde,0x5cdf,
+ 0x5ce0,0x5ce1,0x5ce2,0x5ce3,0x5ce4,0x5ce5,0x5ce6,0x5ce7,
+ 0x5ce8,0x5ce9,0x5cea,0x5ceb,0x5cec,0x5ced,0x5cee,0x5cef,
+ 0x5cf0,0x5cf1,0x5cf2,0x5cf3,0x5cf4,0x5cf5,0x5cf6,0x5cf7,
+ 0x5cf8,0x5cf9,0x5cfa,0x5cfb,0x5cfc,0x5cfd,0x5cfe,0x5cff,
+ 0x5d00,0x5d01,0x5d02,0x5d03,0x5d04,0x5d05,0x5d06,0x5d07,
+ 0x5d08,0x5d09,0x5d0a,0x5d0b,0x5d0c,0x5d0d,0x5d0e,0x5d0f,
+ 0x5d10,0x5d11,0x5d12,0x5d13,0x5d14,0x5d15,0x5d16,0x5d17,
+ 0x5d18,0x5d19,0x5d1a,0x5d1b,0x5d1c,0x5d1d,0x5d1e,0x5d1f,
+ 0x5d20,0x5d21,0x5d22,0x5d23,0x5d24,0x5d25,0x5d26,0x5d27,
+ 0x5d28,0x5d29,0x5d2a,0x5d2b,0x5d2c,0x5d2d,0x5d2e,0x5d2f,
+ 0x5d30,0x5d31,0x5d32,0x5d33,0x5d34,0x5d35,0x5d36,0x5d37,
+ 0x5d38,0x5d39,0x5d3a,0x5d3b,0x5d3c,0x5d3d,0x5d3e,0x5d3f,
+ 0x5d40,0x5d41,0x5d42,0x5d43,0x5d44,0x5d45,0x5d46,0x5d47,
+ 0x5d48,0x5d49,0x5d4a,0x5d4b,0x5d4c,0x5d4d,0x5d4e,0x5d4f,
+ 0x5d50,0x5d51,0x5d52,0x5d53,0x5d54,0x5d55,0x5d56,0x5d57,
+ 0x5d58,0x5d59,0x5d5a,0x5d5b,0x5d5c,0x5d5d,0x5d5e,0x5d5f,
+ 0x5d60,0x5d61,0x5d62,0x5d63,0x5d64,0x5d65,0x5d66,0x5d67,
+ 0x5d68,0x5d69,0x5d6a,0x5d6b,0x5d6c,0x5d6d,0x5d6e,0x5d6f,
+ 0x5d70,0x5d71,0x5d72,0x5d73,0x5d74,0x5d75,0x5d76,0x5d77,
+ 0x5d78,0x5d79,0x5d7a,0x5d7b,0x5d7c,0x5d7d,0x5d7e,0x5d7f,
+ 0x5d80,0x5d81,0x5d82,0x5d83,0x5d84,0x5d85,0x5d86,0x5d87,
+ 0x5d88,0x5d89,0x5d8a,0x5d8b,0x5d8c,0x5d8d,0x5d8e,0x5d8f,
+ 0x5d90,0x5d91,0x5d92,0x5d93,0x5d94,0x5d95,0x5d96,0x5d97,
+ 0x5d98,0x5d99,0x5d9a,0x5d9b,0x5d9c,0x5d9d,0x5d9e,0x5d9f,
+ 0x5da0,0x5da1,0x5da2,0x5da3,0x5da4,0x5da5,0x5da6,0x5da7,
+ 0x5da8,0x5da9,0x5daa,0x5dab,0x5dac,0x5dad,0x5dae,0x5daf,
+ 0x5db0,0x5db1,0x5db2,0x5db3,0x5db4,0x5db5,0x5db6,0x5db7,
+ 0x5db8,0x5db9,0x5dba,0x5dbb,0x5dbc,0x5dbd,0x5dbe,0x5dbf,
+ 0x5dc0,0x5dc1,0x5dc2,0x5dc3,0x5dc4,0x5dc5,0x5dc6,0x5dc7,
+ 0x5dc8,0x5dc9,0x5dca,0x5dcb,0x5dcc,0x5dcd,0x5dce,0x5dcf,
+ 0x5dd0,0x5dd1,0x5dd2,0x5dd3,0x5dd4,0x5dd5,0x5dd6,0x5dd7,
+ 0x5dd8,0x5dd9,0x5dda,0x5ddb,0x5ddc,0x5ddd,0x5dde,0x5ddf,
+ 0x5de0,0x5de1,0x5de2,0x5de3,0x5de4,0x5de5,0x5de6,0x5de7,
+ 0x5de8,0x5de9,0x5dea,0x5deb,0x5dec,0x5ded,0x5dee,0x5def,
+ 0x5df0,0x5df1,0x5df2,0x5df3,0x5df4,0x5df5,0x5df6,0x5df7,
+ 0x5df8,0x5df9,0x5dfa,0x5dfb,0x5dfc,0x5dfd,0x5dfe,0x5dff,
+ 0x5e00,0x5e01,0x5e02,0x5e03,0x5e04,0x5e05,0x5e06,0x5e07,
+ 0x5e08,0x5e09,0x5e0a,0x5e0b,0x5e0c,0x5e0d,0x5e0e,0x5e0f,
+ 0x5e10,0x5e11,0x5e12,0x5e13,0x5e14,0x5e15,0x5e16,0x5e17,
+ 0x5e18,0x5e19,0x5e1a,0x5e1b,0x5e1c,0x5e1d,0x5e1e,0x5e1f,
+ 0x5e20,0x5e21,0x5e22,0x5e23,0x5e24,0x5e25,0x5e26,0x5e27,
+ 0x5e28,0x5e29,0x5e2a,0x5e2b,0x5e2c,0x5e2d,0x5e2e,0x5e2f,
+ 0x5e30,0x5e31,0x5e32,0x5e33,0x5e34,0x5e35,0x5e36,0x5e37,
+ 0x5e38,0x5e39,0x5e3a,0x5e3b,0x5e3c,0x5e3d,0x5e3e,0x5e3f,
+ 0x5e40,0x5e41,0x5e42,0x5e43,0x5e44,0x5e45,0x5e46,0x5e47,
+ 0x5e48,0x5e49,0x5e4a,0x5e4b,0x5e4c,0x5e4d,0x5e4e,0x5e4f,
+ 0x5e50,0x5e51,0x5e52,0x5e53,0x5e54,0x5e55,0x5e56,0x5e57,
+ 0x5e58,0x5e59,0x5e5a,0x5e5b,0x5e5c,0x5e5d,0x5e5e,0x5e5f,
+ 0x5e60,0x5e61,0x5e62,0x5e63,0x5e64,0x5e65,0x5e66,0x5e67,
+ 0x5e68,0x5e69,0x5e6a,0x5e6b,0x5e6c,0x5e6d,0x5e6e,0x5e6f,
+ 0x5e70,0x5e71,0x5e72,0x5e73,0x5e74,0x5e75,0x5e76,0x5e77,
+ 0x5e78,0x5e79,0x5e7a,0x5e7b,0x5e7c,0x5e7d,0x5e7e,0x5e7f,
+ 0x5e80,0x5e81,0x5e82,0x5e83,0x5e84,0x5e85,0x5e86,0x5e87,
+ 0x5e88,0x5e89,0x5e8a,0x5e8b,0x5e8c,0x5e8d,0x5e8e,0x5e8f,
+ 0x5e90,0x5e91,0x5e92,0x5e93,0x5e94,0x5e95,0x5e96,0x5e97,
+ 0x5e98,0x5e99,0x5e9a,0x5e9b,0x5e9c,0x5e9d,0x5e9e,0x5e9f,
+ 0x5ea0,0x5ea1,0x5ea2,0x5ea3,0x5ea4,0x5ea5,0x5ea6,0x5ea7,
+ 0x5ea8,0x5ea9,0x5eaa,0x5eab,0x5eac,0x5ead,0x5eae,0x5eaf,
+ 0x5eb0,0x5eb1,0x5eb2,0x5eb3,0x5eb4,0x5eb5,0x5eb6,0x5eb7,
+ 0x5eb8,0x5eb9,0x5eba,0x5ebb,0x5ebc,0x5ebd,0x5ebe,0x5ebf,
+ 0x5ec0,0x5ec1,0x5ec2,0x5ec3,0x5ec4,0x5ec5,0x5ec6,0x5ec7,
+ 0x5ec8,0x5ec9,0x5eca,0x5ecb,0x5ecc,0x5ecd,0x5ece,0x5ecf,
+ 0x5ed0,0x5ed1,0x5ed2,0x5ed3,0x5ed4,0x5ed5,0x5ed6,0x5ed7,
+ 0x5ed8,0x5ed9,0x5eda,0x5edb,0x5edc,0x5edd,0x5ede,0x5edf,
+ 0x5ee0,0x5ee1,0x5ee2,0x5ee3,0x5ee4,0x5ee5,0x5ee6,0x5ee7,
+ 0x5ee8,0x5ee9,0x5eea,0x5eeb,0x5eec,0x5eed,0x5eee,0x5eef,
+ 0x5ef0,0x5ef1,0x5ef2,0x5ef3,0x5ef4,0x5ef5,0x5ef6,0x5ef7,
+ 0x5ef8,0x5ef9,0x5efa,0x5efb,0x5efc,0x5efd,0x5efe,0x5eff,
+ 0x5f00,0x5f01,0x5f02,0x5f03,0x5f04,0x5f05,0x5f06,0x5f07,
+ 0x5f08,0x5f09,0x5f0a,0x5f0b,0x5f0c,0x5f0d,0x5f0e,0x5f0f,
+ 0x5f10,0x5f11,0x5f12,0x5f13,0x5f14,0x5f15,0x5f16,0x5f17,
+ 0x5f18,0x5f19,0x5f1a,0x5f1b,0x5f1c,0x5f1d,0x5f1e,0x5f1f,
+ 0x5f20,0x5f21,0x5f22,0x5f23,0x5f24,0x5f25,0x5f26,0x5f27,
+ 0x5f28,0x5f29,0x5f2a,0x5f2b,0x5f2c,0x5f2d,0x5f2e,0x5f2f,
+ 0x5f30,0x5f31,0x5f32,0x5f33,0x5f34,0x5f35,0x5f36,0x5f37,
+ 0x5f38,0x5f39,0x5f3a,0x5f3b,0x5f3c,0x5f3d,0x5f3e,0x5f3f,
+ 0x5f40,0x5f41,0x5f42,0x5f43,0x5f44,0x5f45,0x5f46,0x5f47,
+ 0x5f48,0x5f49,0x5f4a,0x5f4b,0x5f4c,0x5f4d,0x5f4e,0x5f4f,
+ 0x5f50,0x5f51,0x5f52,0x5f53,0x5f54,0x5f55,0x5f56,0x5f57,
+ 0x5f58,0x5f59,0x5f5a,0x5f5b,0x5f5c,0x5f5d,0x5f5e,0x5f5f,
+ 0x5f60,0x5f61,0x5f62,0x5f63,0x5f64,0x5f65,0x5f66,0x5f67,
+ 0x5f68,0x5f69,0x5f6a,0x5f6b,0x5f6c,0x5f6d,0x5f6e,0x5f6f,
+ 0x5f70,0x5f71,0x5f72,0x5f73,0x5f74,0x5f75,0x5f76,0x5f77,
+ 0x5f78,0x5f79,0x5f7a,0x5f7b,0x5f7c,0x5f7d,0x5f7e,0x5f7f,
+ 0x5f80,0x5f81,0x5f82,0x5f83,0x5f84,0x5f85,0x5f86,0x5f87,
+ 0x5f88,0x5f89,0x5f8a,0x5f8b,0x5f8c,0x5f8d,0x5f8e,0x5f8f,
+ 0x5f90,0x5f91,0x5f92,0x5f93,0x5f94,0x5f95,0x5f96,0x5f97,
+ 0x5f98,0x5f99,0x5f9a,0x5f9b,0x5f9c,0x5f9d,0x5f9e,0x5f9f,
+ 0x5fa0,0x5fa1,0x5fa2,0x5fa3,0x5fa4,0x5fa5,0x5fa6,0x5fa7,
+ 0x5fa8,0x5fa9,0x5faa,0x5fab,0x5fac,0x5fad,0x5fae,0x5faf,
+ 0x5fb0,0x5fb1,0x5fb2,0x5fb3,0x5fb4,0x5fb5,0x5fb6,0x5fb7,
+ 0x5fb8,0x5fb9,0x5fba,0x5fbb,0x5fbc,0x5fbd,0x5fbe,0x5fbf,
+ 0x5fc0,0x5fc1,0x5fc2,0x5fc3,0x5fc4,0x5fc5,0x5fc6,0x5fc7,
+ 0x5fc8,0x5fc9,0x5fca,0x5fcb,0x5fcc,0x5fcd,0x5fce,0x5fcf,
+ 0x5fd0,0x5fd1,0x5fd2,0x5fd3,0x5fd4,0x5fd5,0x5fd6,0x5fd7,
+ 0x5fd8,0x5fd9,0x5fda,0x5fdb,0x5fdc,0x5fdd,0x5fde,0x5fdf,
+ 0x5fe0,0x5fe1,0x5fe2,0x5fe3,0x5fe4,0x5fe5,0x5fe6,0x5fe7,
+ 0x5fe8,0x5fe9,0x5fea,0x5feb,0x5fec,0x5fed,0x5fee,0x5fef,
+ 0x5ff0,0x5ff1,0x5ff2,0x5ff3,0x5ff4,0x5ff5,0x5ff6,0x5ff7,
+ 0x5ff8,0x5ff9,0x5ffa,0x5ffb,0x5ffc,0x5ffd,0x5ffe,0x5fff,
+ 0x6000,0x6001,0x6002,0x6003,0x6004,0x6005,0x6006,0x6007,
+ 0x6008,0x6009,0x600a,0x600b,0x600c,0x600d,0x600e,0x600f,
+ 0x6010,0x6011,0x6012,0x6013,0x6014,0x6015,0x6016,0x6017,
+ 0x6018,0x6019,0x601a,0x601b,0x601c,0x601d,0x601e,0x601f,
+ 0x6020,0x6021,0x6022,0x6023,0x6024,0x6025,0x6026,0x6027,
+ 0x6028,0x6029,0x602a,0x602b,0x602c,0x602d,0x602e,0x602f,
+ 0x6030,0x6031,0x6032,0x6033,0x6034,0x6035,0x6036,0x6037,
+ 0x6038,0x6039,0x603a,0x603b,0x603c,0x603d,0x603e,0x603f,
+ 0x6040,0x6041,0x6042,0x6043,0x6044,0x6045,0x6046,0x6047,
+ 0x6048,0x6049,0x604a,0x604b,0x604c,0x604d,0x604e,0x604f,
+ 0x6050,0x6051,0x6052,0x6053,0x6054,0x6055,0x6056,0x6057,
+ 0x6058,0x6059,0x605a,0x605b,0x605c,0x605d,0x605e,0x605f,
+ 0x6060,0x6061,0x6062,0x6063,0x6064,0x6065,0x6066,0x6067,
+ 0x6068,0x6069,0x606a,0x606b,0x606c,0x606d,0x606e,0x606f,
+ 0x6070,0x6071,0x6072,0x6073,0x6074,0x6075,0x6076,0x6077,
+ 0x6078,0x6079,0x607a,0x607b,0x607c,0x607d,0x607e,0x607f,
+ 0x6080,0x6081,0x6082,0x6083,0x6084,0x6085,0x6086,0x6087,
+ 0x6088,0x6089,0x608a,0x608b,0x608c,0x608d,0x608e,0x608f,
+ 0x6090,0x6091,0x6092,0x6093,0x6094,0x6095,0x6096,0x6097,
+ 0x6098,0x6099,0x609a,0x609b,0x609c,0x609d,0x609e,0x609f,
+ 0x60a0,0x60a1,0x60a2,0x60a3,0x60a4,0x60a5,0x60a6,0x60a7,
+ 0x60a8,0x60a9,0x60aa,0x60ab,0x60ac,0x60ad,0x60ae,0x60af,
+ 0x60b0,0x60b1,0x60b2,0x60b3,0x60b4,0x60b5,0x60b6,0x60b7,
+ 0x60b8,0x60b9,0x60ba,0x60bb,0x60bc,0x60bd,0x60be,0x60bf,
+ 0x60c0,0x60c1,0x60c2,0x60c3,0x60c4,0x60c5,0x60c6,0x60c7,
+ 0x60c8,0x60c9,0x60ca,0x60cb,0x60cc,0x60cd,0x60ce,0x60cf,
+ 0x60d0,0x60d1,0x60d2,0x60d3,0x60d4,0x60d5,0x60d6,0x60d7,
+ 0x60d8,0x60d9,0x60da,0x60db,0x60dc,0x60dd,0x60de,0x60df,
+ 0x60e0,0x60e1,0x60e2,0x60e3,0x60e4,0x60e5,0x60e6,0x60e7,
+ 0x60e8,0x60e9,0x60ea,0x60eb,0x60ec,0x60ed,0x60ee,0x60ef,
+ 0x60f0,0x60f1,0x60f2,0x60f3,0x60f4,0x60f5,0x60f6,0x60f7,
+ 0x60f8,0x60f9,0x60fa,0x60fb,0x60fc,0x60fd,0x60fe,0x60ff,
+ 0x6100,0x6101,0x6102,0x6103,0x6104,0x6105,0x6106,0x6107,
+ 0x6108,0x6109,0x610a,0x610b,0x610c,0x610d,0x610e,0x610f,
+ 0x6110,0x6111,0x6112,0x6113,0x6114,0x6115,0x6116,0x6117,
+ 0x6118,0x6119,0x611a,0x611b,0x611c,0x611d,0x611e,0x611f,
+ 0x6120,0x6121,0x6122,0x6123,0x6124,0x6125,0x6126,0x6127,
+ 0x6128,0x6129,0x612a,0x612b,0x612c,0x612d,0x612e,0x612f,
+ 0x6130,0x6131,0x6132,0x6133,0x6134,0x6135,0x6136,0x6137,
+ 0x6138,0x6139,0x613a,0x613b,0x613c,0x613d,0x613e,0x613f,
+ 0x6140,0x6141,0x6142,0x6143,0x6144,0x6145,0x6146,0x6147,
+ 0x6148,0x6149,0x614a,0x614b,0x614c,0x614d,0x614e,0x614f,
+ 0x6150,0x6151,0x6152,0x6153,0x6154,0x6155,0x6156,0x6157,
+ 0x6158,0x6159,0x615a,0x615b,0x615c,0x615d,0x615e,0x615f,
+ 0x6160,0x6161,0x6162,0x6163,0x6164,0x6165,0x6166,0x6167,
+ 0x6168,0x6169,0x616a,0x616b,0x616c,0x616d,0x616e,0x616f,
+ 0x6170,0x6171,0x6172,0x6173,0x6174,0x6175,0x6176,0x6177,
+ 0x6178,0x6179,0x617a,0x617b,0x617c,0x617d,0x617e,0x617f,
+ 0x6180,0x6181,0x6182,0x6183,0x6184,0x6185,0x6186,0x6187,
+ 0x6188,0x6189,0x618a,0x618b,0x618c,0x618d,0x618e,0x618f,
+ 0x6190,0x6191,0x6192,0x6193,0x6194,0x6195,0x6196,0x6197,
+ 0x6198,0x6199,0x619a,0x619b,0x619c,0x619d,0x619e,0x619f,
+ 0x61a0,0x61a1,0x61a2,0x61a3,0x61a4,0x61a5,0x61a6,0x61a7,
+ 0x61a8,0x61a9,0x61aa,0x61ab,0x61ac,0x61ad,0x61ae,0x61af,
+ 0x61b0,0x61b1,0x61b2,0x61b3,0x61b4,0x61b5,0x61b6,0x61b7,
+ 0x61b8,0x61b9,0x61ba,0x61bb,0x61bc,0x61bd,0x61be,0x61bf,
+ 0x61c0,0x61c1,0x61c2,0x61c3,0x61c4,0x61c5,0x61c6,0x61c7,
+ 0x61c8,0x61c9,0x61ca,0x61cb,0x61cc,0x61cd,0x61ce,0x61cf,
+ 0x61d0,0x61d1,0x61d2,0x61d3,0x61d4,0x61d5,0x61d6,0x61d7,
+ 0x61d8,0x61d9,0x61da,0x61db,0x61dc,0x61dd,0x61de,0x61df,
+ 0x61e0,0x61e1,0x61e2,0x61e3,0x61e4,0x61e5,0x61e6,0x61e7,
+ 0x61e8,0x61e9,0x61ea,0x61eb,0x61ec,0x61ed,0x61ee,0x61ef,
+ 0x61f0,0x61f1,0x61f2,0x61f3,0x61f4,0x61f5,0x61f6,0x61f7,
+ 0x61f8,0x61f9,0x61fa,0x61fb,0x61fc,0x61fd,0x61fe,0x61ff,
+ 0x6200,0x6201,0x6202,0x6203,0x6204,0x6205,0x6206,0x6207,
+ 0x6208,0x6209,0x620a,0x620b,0x620c,0x620d,0x620e,0x620f,
+ 0x6210,0x6211,0x6212,0x6213,0x6214,0x6215,0x6216,0x6217,
+ 0x6218,0x6219,0x621a,0x621b,0x621c,0x621d,0x621e,0x621f,
+ 0x6220,0x6221,0x6222,0x6223,0x6224,0x6225,0x6226,0x6227,
+ 0x6228,0x6229,0x622a,0x622b,0x622c,0x622d,0x622e,0x622f,
+ 0x6230,0x6231,0x6232,0x6233,0x6234,0x6235,0x6236,0x6237,
+ 0x6238,0x6239,0x623a,0x623b,0x623c,0x623d,0x623e,0x623f,
+ 0x6240,0x6241,0x6242,0x6243,0x6244,0x6245,0x6246,0x6247,
+ 0x6248,0x6249,0x624a,0x624b,0x624c,0x624d,0x624e,0x624f,
+ 0x6250,0x6251,0x6252,0x6253,0x6254,0x6255,0x6256,0x6257,
+ 0x6258,0x6259,0x625a,0x625b,0x625c,0x625d,0x625e,0x625f,
+ 0x6260,0x6261,0x6262,0x6263,0x6264,0x6265,0x6266,0x6267,
+ 0x6268,0x6269,0x626a,0x626b,0x626c,0x626d,0x626e,0x626f,
+ 0x6270,0x6271,0x6272,0x6273,0x6274,0x6275,0x6276,0x6277,
+ 0x6278,0x6279,0x627a,0x627b,0x627c,0x627d,0x627e,0x627f,
+ 0x6280,0x6281,0x6282,0x6283,0x6284,0x6285,0x6286,0x6287,
+ 0x6288,0x6289,0x628a,0x628b,0x628c,0x628d,0x628e,0x628f,
+ 0x6290,0x6291,0x6292,0x6293,0x6294,0x6295,0x6296,0x6297,
+ 0x6298,0x6299,0x629a,0x629b,0x629c,0x629d,0x629e,0x629f,
+ 0x62a0,0x62a1,0x62a2,0x62a3,0x62a4,0x62a5,0x62a6,0x62a7,
+ 0x62a8,0x62a9,0x62aa,0x62ab,0x62ac,0x62ad,0x62ae,0x62af,
+ 0x62b0,0x62b1,0x62b2,0x62b3,0x62b4,0x62b5,0x62b6,0x62b7,
+ 0x62b8,0x62b9,0x62ba,0x62bb,0x62bc,0x62bd,0x62be,0x62bf,
+ 0x62c0,0x62c1,0x62c2,0x62c3,0x62c4,0x62c5,0x62c6,0x62c7,
+ 0x62c8,0x62c9,0x62ca,0x62cb,0x62cc,0x62cd,0x62ce,0x62cf,
+ 0x62d0,0x62d1,0x62d2,0x62d3,0x62d4,0x62d5,0x62d6,0x62d7,
+ 0x62d8,0x62d9,0x62da,0x62db,0x62dc,0x62dd,0x62de,0x62df,
+ 0x62e0,0x62e1,0x62e2,0x62e3,0x62e4,0x62e5,0x62e6,0x62e7,
+ 0x62e8,0x62e9,0x62ea,0x62eb,0x62ec,0x62ed,0x62ee,0x62ef,
+ 0x62f0,0x62f1,0x62f2,0x62f3,0x62f4,0x62f5,0x62f6,0x62f7,
+ 0x62f8,0x62f9,0x62fa,0x62fb,0x62fc,0x62fd,0x62fe,0x62ff,
+ 0x6300,0x6301,0x6302,0x6303,0x6304,0x6305,0x6306,0x6307,
+ 0x6308,0x6309,0x630a,0x630b,0x630c,0x630d,0x630e,0x630f,
+ 0x6310,0x6311,0x6312,0x6313,0x6314,0x6315,0x6316,0x6317,
+ 0x6318,0x6319,0x631a,0x631b,0x631c,0x631d,0x631e,0x631f,
+ 0x6320,0x6321,0x6322,0x6323,0x6324,0x6325,0x6326,0x6327,
+ 0x6328,0x6329,0x632a,0x632b,0x632c,0x632d,0x632e,0x632f,
+ 0x6330,0x6331,0x6332,0x6333,0x6334,0x6335,0x6336,0x6337,
+ 0x6338,0x6339,0x633a,0x633b,0x633c,0x633d,0x633e,0x633f,
+ 0x6340,0x6341,0x6342,0x6343,0x6344,0x6345,0x6346,0x6347,
+ 0x6348,0x6349,0x634a,0x634b,0x634c,0x634d,0x634e,0x634f,
+ 0x6350,0x6351,0x6352,0x6353,0x6354,0x6355,0x6356,0x6357,
+ 0x6358,0x6359,0x635a,0x635b,0x635c,0x635d,0x635e,0x635f,
+ 0x6360,0x6361,0x6362,0x6363,0x6364,0x6365,0x6366,0x6367,
+ 0x6368,0x6369,0x636a,0x636b,0x636c,0x636d,0x636e,0x636f,
+ 0x6370,0x6371,0x6372,0x6373,0x6374,0x6375,0x6376,0x6377,
+ 0x6378,0x6379,0x637a,0x637b,0x637c,0x637d,0x637e,0x637f,
+ 0x6380,0x6381,0x6382,0x6383,0x6384,0x6385,0x6386,0x6387,
+ 0x6388,0x6389,0x638a,0x638b,0x638c,0x638d,0x638e,0x638f,
+ 0x6390,0x6391,0x6392,0x6393,0x6394,0x6395,0x6396,0x6397,
+ 0x6398,0x6399,0x639a,0x639b,0x639c,0x639d,0x639e,0x639f,
+ 0x63a0,0x63a1,0x63a2,0x63a3,0x63a4,0x63a5,0x63a6,0x63a7,
+ 0x63a8,0x63a9,0x63aa,0x63ab,0x63ac,0x63ad,0x63ae,0x63af,
+ 0x63b0,0x63b1,0x63b2,0x63b3,0x63b4,0x63b5,0x63b6,0x63b7,
+ 0x63b8,0x63b9,0x63ba,0x63bb,0x63bc,0x63bd,0x63be,0x63bf,
+ 0x63c0,0x63c1,0x63c2,0x63c3,0x63c4,0x63c5,0x63c6,0x63c7,
+ 0x63c8,0x63c9,0x63ca,0x63cb,0x63cc,0x63cd,0x63ce,0x63cf,
+ 0x63d0,0x63d1,0x63d2,0x63d3,0x63d4,0x63d5,0x63d6,0x63d7,
+ 0x63d8,0x63d9,0x63da,0x63db,0x63dc,0x63dd,0x63de,0x63df,
+ 0x63e0,0x63e1,0x63e2,0x63e3,0x63e4,0x63e5,0x63e6,0x63e7,
+ 0x63e8,0x63e9,0x63ea,0x63eb,0x63ec,0x63ed,0x63ee,0x63ef,
+ 0x63f0,0x63f1,0x63f2,0x63f3,0x63f4,0x63f5,0x63f6,0x63f7,
+ 0x63f8,0x63f9,0x63fa,0x63fb,0x63fc,0x63fd,0x63fe,0x63ff,
+ 0x6400,0x6401,0x6402,0x6403,0x6404,0x6405,0x6406,0x6407,
+ 0x6408,0x6409,0x640a,0x640b,0x640c,0x640d,0x640e,0x640f,
+ 0x6410,0x6411,0x6412,0x6413,0x6414,0x6415,0x6416,0x6417,
+ 0x6418,0x6419,0x641a,0x641b,0x641c,0x641d,0x641e,0x641f,
+ 0x6420,0x6421,0x6422,0x6423,0x6424,0x6425,0x6426,0x6427,
+ 0x6428,0x6429,0x642a,0x642b,0x642c,0x642d,0x642e,0x642f,
+ 0x6430,0x6431,0x6432,0x6433,0x6434,0x6435,0x6436,0x6437,
+ 0x6438,0x6439,0x643a,0x643b,0x643c,0x643d,0x643e,0x643f,
+ 0x6440,0x6441,0x6442,0x6443,0x6444,0x6445,0x6446,0x6447,
+ 0x6448,0x6449,0x644a,0x644b,0x644c,0x644d,0x644e,0x644f,
+ 0x6450,0x6451,0x6452,0x6453,0x6454,0x6455,0x6456,0x6457,
+ 0x6458,0x6459,0x645a,0x645b,0x645c,0x645d,0x645e,0x645f,
+ 0x6460,0x6461,0x6462,0x6463,0x6464,0x6465,0x6466,0x6467,
+ 0x6468,0x6469,0x646a,0x646b,0x646c,0x646d,0x646e,0x646f,
+ 0x6470,0x6471,0x6472,0x6473,0x6474,0x6475,0x6476,0x6477,
+ 0x6478,0x6479,0x647a,0x647b,0x647c,0x647d,0x647e,0x647f,
+ 0x6480,0x6481,0x6482,0x6483,0x6484,0x6485,0x6486,0x6487,
+ 0x6488,0x6489,0x648a,0x648b,0x648c,0x648d,0x648e,0x648f,
+ 0x6490,0x6491,0x6492,0x6493,0x6494,0x6495,0x6496,0x6497,
+ 0x6498,0x6499,0x649a,0x649b,0x649c,0x649d,0x649e,0x649f,
+ 0x64a0,0x64a1,0x64a2,0x64a3,0x64a4,0x64a5,0x64a6,0x64a7,
+ 0x64a8,0x64a9,0x64aa,0x64ab,0x64ac,0x64ad,0x64ae,0x64af,
+ 0x64b0,0x64b1,0x64b2,0x64b3,0x64b4,0x64b5,0x64b6,0x64b7,
+ 0x64b8,0x64b9,0x64ba,0x64bb,0x64bc,0x64bd,0x64be,0x64bf,
+ 0x64c0,0x64c1,0x64c2,0x64c3,0x64c4,0x64c5,0x64c6,0x64c7,
+ 0x64c8,0x64c9,0x64ca,0x64cb,0x64cc,0x64cd,0x64ce,0x64cf,
+ 0x64d0,0x64d1,0x64d2,0x64d3,0x64d4,0x64d5,0x64d6,0x64d7,
+ 0x64d8,0x64d9,0x64da,0x64db,0x64dc,0x64dd,0x64de,0x64df,
+ 0x64e0,0x64e1,0x64e2,0x64e3,0x64e4,0x64e5,0x64e6,0x64e7,
+ 0x64e8,0x64e9,0x64ea,0x64eb,0x64ec,0x64ed,0x64ee,0x64ef,
+ 0x64f0,0x64f1,0x64f2,0x64f3,0x64f4,0x64f5,0x64f6,0x64f7,
+ 0x64f8,0x64f9,0x64fa,0x64fb,0x64fc,0x64fd,0x64fe,0x64ff,
+ 0x6500,0x6501,0x6502,0x6503,0x6504,0x6505,0x6506,0x6507,
+ 0x6508,0x6509,0x650a,0x650b,0x650c,0x650d,0x650e,0x650f,
+ 0x6510,0x6511,0x6512,0x6513,0x6514,0x6515,0x6516,0x6517,
+ 0x6518,0x6519,0x651a,0x651b,0x651c,0x651d,0x651e,0x651f,
+ 0x6520,0x6521,0x6522,0x6523,0x6524,0x6525,0x6526,0x6527,
+ 0x6528,0x6529,0x652a,0x652b,0x652c,0x652d,0x652e,0x652f,
+ 0x6530,0x6531,0x6532,0x6533,0x6534,0x6535,0x6536,0x6537,
+ 0x6538,0x6539,0x653a,0x653b,0x653c,0x653d,0x653e,0x653f,
+ 0x6540,0x6541,0x6542,0x6543,0x6544,0x6545,0x6546,0x6547,
+ 0x6548,0x6549,0x654a,0x654b,0x654c,0x654d,0x654e,0x654f,
+ 0x6550,0x6551,0x6552,0x6553,0x6554,0x6555,0x6556,0x6557,
+ 0x6558,0x6559,0x655a,0x655b,0x655c,0x655d,0x655e,0x655f,
+ 0x6560,0x6561,0x6562,0x6563,0x6564,0x6565,0x6566,0x6567,
+ 0x6568,0x6569,0x656a,0x656b,0x656c,0x656d,0x656e,0x656f,
+ 0x6570,0x6571,0x6572,0x6573,0x6574,0x6575,0x6576,0x6577,
+ 0x6578,0x6579,0x657a,0x657b,0x657c,0x657d,0x657e,0x657f,
+ 0x6580,0x6581,0x6582,0x6583,0x6584,0x6585,0x6586,0x6587,
+ 0x6588,0x6589,0x658a,0x658b,0x658c,0x658d,0x658e,0x658f,
+ 0x6590,0x6591,0x6592,0x6593,0x6594,0x6595,0x6596,0x6597,
+ 0x6598,0x6599,0x659a,0x659b,0x659c,0x659d,0x659e,0x659f,
+ 0x65a0,0x65a1,0x65a2,0x65a3,0x65a4,0x65a5,0x65a6,0x65a7,
+ 0x65a8,0x65a9,0x65aa,0x65ab,0x65ac,0x65ad,0x65ae,0x65af,
+ 0x65b0,0x65b1,0x65b2,0x65b3,0x65b4,0x65b5,0x65b6,0x65b7,
+ 0x65b8,0x65b9,0x65ba,0x65bb,0x65bc,0x65bd,0x65be,0x65bf,
+ 0x65c0,0x65c1,0x65c2,0x65c3,0x65c4,0x65c5,0x65c6,0x65c7,
+ 0x65c8,0x65c9,0x65ca,0x65cb,0x65cc,0x65cd,0x65ce,0x65cf,
+ 0x65d0,0x65d1,0x65d2,0x65d3,0x65d4,0x65d5,0x65d6,0x65d7,
+ 0x65d8,0x65d9,0x65da,0x65db,0x65dc,0x65dd,0x65de,0x65df,
+ 0x65e0,0x65e1,0x65e2,0x65e3,0x65e4,0x65e5,0x65e6,0x65e7,
+ 0x65e8,0x65e9,0x65ea,0x65eb,0x65ec,0x65ed,0x65ee,0x65ef,
+ 0x65f0,0x65f1,0x65f2,0x65f3,0x65f4,0x65f5,0x65f6,0x65f7,
+ 0x65f8,0x65f9,0x65fa,0x65fb,0x65fc,0x65fd,0x65fe,0x65ff,
+ 0x6600,0x6601,0x6602,0x6603,0x6604,0x6605,0x6606,0x6607,
+ 0x6608,0x6609,0x660a,0x660b,0x660c,0x660d,0x660e,0x660f,
+ 0x6610,0x6611,0x6612,0x6613,0x6614,0x6615,0x6616,0x6617,
+ 0x6618,0x6619,0x661a,0x661b,0x661c,0x661d,0x661e,0x661f,
+ 0x6620,0x6621,0x6622,0x6623,0x6624,0x6625,0x6626,0x6627,
+ 0x6628,0x6629,0x662a,0x662b,0x662c,0x662d,0x662e,0x662f,
+ 0x6630,0x6631,0x6632,0x6633,0x6634,0x6635,0x6636,0x6637,
+ 0x6638,0x6639,0x663a,0x663b,0x663c,0x663d,0x663e,0x663f,
+ 0x6640,0x6641,0x6642,0x6643,0x6644,0x6645,0x6646,0x6647,
+ 0x6648,0x6649,0x664a,0x664b,0x664c,0x664d,0x664e,0x664f,
+ 0x6650,0x6651,0x6652,0x6653,0x6654,0x6655,0x6656,0x6657,
+ 0x6658,0x6659,0x665a,0x665b,0x665c,0x665d,0x665e,0x665f,
+ 0x6660,0x6661,0x6662,0x6663,0x6664,0x6665,0x6666,0x6667,
+ 0x6668,0x6669,0x666a,0x666b,0x666c,0x666d,0x666e,0x666f,
+ 0x6670,0x6671,0x6672,0x6673,0x6674,0x6675,0x6676,0x6677,
+ 0x6678,0x6679,0x667a,0x667b,0x667c,0x667d,0x667e,0x667f,
+ 0x6680,0x6681,0x6682,0x6683,0x6684,0x6685,0x6686,0x6687,
+ 0x6688,0x6689,0x668a,0x668b,0x668c,0x668d,0x668e,0x668f,
+ 0x6690,0x6691,0x6692,0x6693,0x6694,0x6695,0x6696,0x6697,
+ 0x6698,0x6699,0x669a,0x669b,0x669c,0x669d,0x669e,0x669f,
+ 0x66a0,0x66a1,0x66a2,0x66a3,0x66a4,0x66a5,0x66a6,0x66a7,
+ 0x66a8,0x66a9,0x66aa,0x66ab,0x66ac,0x66ad,0x66ae,0x66af,
+ 0x66b0,0x66b1,0x66b2,0x66b3,0x66b4,0x66b5,0x66b6,0x66b7,
+ 0x66b8,0x66b9,0x66ba,0x66bb,0x66bc,0x66bd,0x66be,0x66bf,
+ 0x66c0,0x66c1,0x66c2,0x66c3,0x66c4,0x66c5,0x66c6,0x66c7,
+ 0x66c8,0x66c9,0x66ca,0x66cb,0x66cc,0x66cd,0x66ce,0x66cf,
+ 0x66d0,0x66d1,0x66d2,0x66d3,0x66d4,0x66d5,0x66d6,0x66d7,
+ 0x66d8,0x66d9,0x66da,0x66db,0x66dc,0x66dd,0x66de,0x66df,
+ 0x66e0,0x66e1,0x66e2,0x66e3,0x66e4,0x66e5,0x66e6,0x66e7,
+ 0x66e8,0x66e9,0x66ea,0x66eb,0x66ec,0x66ed,0x66ee,0x66ef,
+ 0x66f0,0x66f1,0x66f2,0x66f3,0x66f4,0x66f5,0x66f6,0x66f7,
+ 0x66f8,0x66f9,0x66fa,0x66fb,0x66fc,0x66fd,0x66fe,0x66ff,
+ 0x6700,0x6701,0x6702,0x6703,0x6704,0x6705,0x6706,0x6707,
+ 0x6708,0x6709,0x670a,0x670b,0x670c,0x670d,0x670e,0x670f,
+ 0x6710,0x6711,0x6712,0x6713,0x6714,0x6715,0x6716,0x6717,
+ 0x6718,0x6719,0x671a,0x671b,0x671c,0x671d,0x671e,0x671f,
+ 0x6720,0x6721,0x6722,0x6723,0x6724,0x6725,0x6726,0x6727,
+ 0x6728,0x6729,0x672a,0x672b,0x672c,0x672d,0x672e,0x672f,
+ 0x6730,0x6731,0x6732,0x6733,0x6734,0x6735,0x6736,0x6737,
+ 0x6738,0x6739,0x673a,0x673b,0x673c,0x673d,0x673e,0x673f,
+ 0x6740,0x6741,0x6742,0x6743,0x6744,0x6745,0x6746,0x6747,
+ 0x6748,0x6749,0x674a,0x674b,0x674c,0x674d,0x674e,0x674f,
+ 0x6750,0x6751,0x6752,0x6753,0x6754,0x6755,0x6756,0x6757,
+ 0x6758,0x6759,0x675a,0x675b,0x675c,0x675d,0x675e,0x675f,
+ 0x6760,0x6761,0x6762,0x6763,0x6764,0x6765,0x6766,0x6767,
+ 0x6768,0x6769,0x676a,0x676b,0x676c,0x676d,0x676e,0x676f,
+ 0x6770,0x6771,0x6772,0x6773,0x6774,0x6775,0x6776,0x6777,
+ 0x6778,0x6779,0x677a,0x677b,0x677c,0x677d,0x677e,0x677f,
+ 0x6780,0x6781,0x6782,0x6783,0x6784,0x6785,0x6786,0x6787,
+ 0x6788,0x6789,0x678a,0x678b,0x678c,0x678d,0x678e,0x678f,
+ 0x6790,0x6791,0x6792,0x6793,0x6794,0x6795,0x6796,0x6797,
+ 0x6798,0x6799,0x679a,0x679b,0x679c,0x679d,0x679e,0x679f,
+ 0x67a0,0x67a1,0x67a2,0x67a3,0x67a4,0x67a5,0x67a6,0x67a7,
+ 0x67a8,0x67a9,0x67aa,0x67ab,0x67ac,0x67ad,0x67ae,0x67af,
+ 0x67b0,0x67b1,0x67b2,0x67b3,0x67b4,0x67b5,0x67b6,0x67b7,
+ 0x67b8,0x67b9,0x67ba,0x67bb,0x67bc,0x67bd,0x67be,0x67bf,
+ 0x67c0,0x67c1,0x67c2,0x67c3,0x67c4,0x67c5,0x67c6,0x67c7,
+ 0x67c8,0x67c9,0x67ca,0x67cb,0x67cc,0x67cd,0x67ce,0x67cf,
+ 0x67d0,0x67d1,0x67d2,0x67d3,0x67d4,0x67d5,0x67d6,0x67d7,
+ 0x67d8,0x67d9,0x67da,0x67db,0x67dc,0x67dd,0x67de,0x67df,
+ 0x67e0,0x67e1,0x67e2,0x67e3,0x67e4,0x67e5,0x67e6,0x67e7,
+ 0x67e8,0x67e9,0x67ea,0x67eb,0x67ec,0x67ed,0x67ee,0x67ef,
+ 0x67f0,0x67f1,0x67f2,0x67f3,0x67f4,0x67f5,0x67f6,0x67f7,
+ 0x67f8,0x67f9,0x67fa,0x67fb,0x67fc,0x67fd,0x67fe,0x67ff,
+ 0x6800,0x6801,0x6802,0x6803,0x6804,0x6805,0x6806,0x6807,
+ 0x6808,0x6809,0x680a,0x680b,0x680c,0x680d,0x680e,0x680f,
+ 0x6810,0x6811,0x6812,0x6813,0x6814,0x6815,0x6816,0x6817,
+ 0x6818,0x6819,0x681a,0x681b,0x681c,0x681d,0x681e,0x681f,
+ 0x6820,0x6821,0x6822,0x6823,0x6824,0x6825,0x6826,0x6827,
+ 0x6828,0x6829,0x682a,0x682b,0x682c,0x682d,0x682e,0x682f,
+ 0x6830,0x6831,0x6832,0x6833,0x6834,0x6835,0x6836,0x6837,
+ 0x6838,0x6839,0x683a,0x683b,0x683c,0x683d,0x683e,0x683f,
+ 0x6840,0x6841,0x6842,0x6843,0x6844,0x6845,0x6846,0x6847,
+ 0x6848,0x6849,0x684a,0x684b,0x684c,0x684d,0x684e,0x684f,
+ 0x6850,0x6851,0x6852,0x6853,0x6854,0x6855,0x6856,0x6857,
+ 0x6858,0x6859,0x685a,0x685b,0x685c,0x685d,0x685e,0x685f,
+ 0x6860,0x6861,0x6862,0x6863,0x6864,0x6865,0x6866,0x6867,
+ 0x6868,0x6869,0x686a,0x686b,0x686c,0x686d,0x686e,0x686f,
+ 0x6870,0x6871,0x6872,0x6873,0x6874,0x6875,0x6876,0x6877,
+ 0x6878,0x6879,0x687a,0x687b,0x687c,0x687d,0x687e,0x687f,
+ 0x6880,0x6881,0x6882,0x6883,0x6884,0x6885,0x6886,0x6887,
+ 0x6888,0x6889,0x688a,0x688b,0x688c,0x688d,0x688e,0x688f,
+ 0x6890,0x6891,0x6892,0x6893,0x6894,0x6895,0x6896,0x6897,
+ 0x6898,0x6899,0x689a,0x689b,0x689c,0x689d,0x689e,0x689f,
+ 0x68a0,0x68a1,0x68a2,0x68a3,0x68a4,0x68a5,0x68a6,0x68a7,
+ 0x68a8,0x68a9,0x68aa,0x68ab,0x68ac,0x68ad,0x68ae,0x68af,
+ 0x68b0,0x68b1,0x68b2,0x68b3,0x68b4,0x68b5,0x68b6,0x68b7,
+ 0x68b8,0x68b9,0x68ba,0x68bb,0x68bc,0x68bd,0x68be,0x68bf,
+ 0x68c0,0x68c1,0x68c2,0x68c3,0x68c4,0x68c5,0x68c6,0x68c7,
+ 0x68c8,0x68c9,0x68ca,0x68cb,0x68cc,0x68cd,0x68ce,0x68cf,
+ 0x68d0,0x68d1,0x68d2,0x68d3,0x68d4,0x68d5,0x68d6,0x68d7,
+ 0x68d8,0x68d9,0x68da,0x68db,0x68dc,0x68dd,0x68de,0x68df,
+ 0x68e0,0x68e1,0x68e2,0x68e3,0x68e4,0x68e5,0x68e6,0x68e7,
+ 0x68e8,0x68e9,0x68ea,0x68eb,0x68ec,0x68ed,0x68ee,0x68ef,
+ 0x68f0,0x68f1,0x68f2,0x68f3,0x68f4,0x68f5,0x68f6,0x68f7,
+ 0x68f8,0x68f9,0x68fa,0x68fb,0x68fc,0x68fd,0x68fe,0x68ff,
+ 0x6900,0x6901,0x6902,0x6903,0x6904,0x6905,0x6906,0x6907,
+ 0x6908,0x6909,0x690a,0x690b,0x690c,0x690d,0x690e,0x690f,
+ 0x6910,0x6911,0x6912,0x6913,0x6914,0x6915,0x6916,0x6917,
+ 0x6918,0x6919,0x691a,0x691b,0x691c,0x691d,0x691e,0x691f,
+ 0x6920,0x6921,0x6922,0x6923,0x6924,0x6925,0x6926,0x6927,
+ 0x6928,0x6929,0x692a,0x692b,0x692c,0x692d,0x692e,0x692f,
+ 0x6930,0x6931,0x6932,0x6933,0x6934,0x6935,0x6936,0x6937,
+ 0x6938,0x6939,0x693a,0x693b,0x693c,0x693d,0x693e,0x693f,
+ 0x6940,0x6941,0x6942,0x6943,0x6944,0x6945,0x6946,0x6947,
+ 0x6948,0x6949,0x694a,0x694b,0x694c,0x694d,0x694e,0x694f,
+ 0x6950,0x6951,0x6952,0x6953,0x6954,0x6955,0x6956,0x6957,
+ 0x6958,0x6959,0x695a,0x695b,0x695c,0x695d,0x695e,0x695f,
+ 0x6960,0x6961,0x6962,0x6963,0x6964,0x6965,0x6966,0x6967,
+ 0x6968,0x6969,0x696a,0x696b,0x696c,0x696d,0x696e,0x696f,
+ 0x6970,0x6971,0x6972,0x6973,0x6974,0x6975,0x6976,0x6977,
+ 0x6978,0x6979,0x697a,0x697b,0x697c,0x697d,0x697e,0x697f,
+ 0x6980,0x6981,0x6982,0x6983,0x6984,0x6985,0x6986,0x6987,
+ 0x6988,0x6989,0x698a,0x698b,0x698c,0x698d,0x698e,0x698f,
+ 0x6990,0x6991,0x6992,0x6993,0x6994,0x6995,0x6996,0x6997,
+ 0x6998,0x6999,0x699a,0x699b,0x699c,0x699d,0x699e,0x699f,
+ 0x69a0,0x69a1,0x69a2,0x69a3,0x69a4,0x69a5,0x69a6,0x69a7,
+ 0x69a8,0x69a9,0x69aa,0x69ab,0x69ac,0x69ad,0x69ae,0x69af,
+ 0x69b0,0x69b1,0x69b2,0x69b3,0x69b4,0x69b5,0x69b6,0x69b7,
+ 0x69b8,0x69b9,0x69ba,0x69bb,0x69bc,0x69bd,0x69be,0x69bf,
+ 0x69c0,0x69c1,0x69c2,0x69c3,0x69c4,0x69c5,0x69c6,0x69c7,
+ 0x69c8,0x69c9,0x69ca,0x69cb,0x69cc,0x69cd,0x69ce,0x69cf,
+ 0x69d0,0x69d1,0x69d2,0x69d3,0x69d4,0x69d5,0x69d6,0x69d7,
+ 0x69d8,0x69d9,0x69da,0x69db,0x69dc,0x69dd,0x69de,0x69df,
+ 0x69e0,0x69e1,0x69e2,0x69e3,0x69e4,0x69e5,0x69e6,0x69e7,
+ 0x69e8,0x69e9,0x69ea,0x69eb,0x69ec,0x69ed,0x69ee,0x69ef,
+ 0x69f0,0x69f1,0x69f2,0x69f3,0x69f4,0x69f5,0x69f6,0x69f7,
+ 0x69f8,0x69f9,0x69fa,0x69fb,0x69fc,0x69fd,0x69fe,0x69ff,
+ 0x6a00,0x6a01,0x6a02,0x6a03,0x6a04,0x6a05,0x6a06,0x6a07,
+ 0x6a08,0x6a09,0x6a0a,0x6a0b,0x6a0c,0x6a0d,0x6a0e,0x6a0f,
+ 0x6a10,0x6a11,0x6a12,0x6a13,0x6a14,0x6a15,0x6a16,0x6a17,
+ 0x6a18,0x6a19,0x6a1a,0x6a1b,0x6a1c,0x6a1d,0x6a1e,0x6a1f,
+ 0x6a20,0x6a21,0x6a22,0x6a23,0x6a24,0x6a25,0x6a26,0x6a27,
+ 0x6a28,0x6a29,0x6a2a,0x6a2b,0x6a2c,0x6a2d,0x6a2e,0x6a2f,
+ 0x6a30,0x6a31,0x6a32,0x6a33,0x6a34,0x6a35,0x6a36,0x6a37,
+ 0x6a38,0x6a39,0x6a3a,0x6a3b,0x6a3c,0x6a3d,0x6a3e,0x6a3f,
+ 0x6a40,0x6a41,0x6a42,0x6a43,0x6a44,0x6a45,0x6a46,0x6a47,
+ 0x6a48,0x6a49,0x6a4a,0x6a4b,0x6a4c,0x6a4d,0x6a4e,0x6a4f,
+ 0x6a50,0x6a51,0x6a52,0x6a53,0x6a54,0x6a55,0x6a56,0x6a57,
+ 0x6a58,0x6a59,0x6a5a,0x6a5b,0x6a5c,0x6a5d,0x6a5e,0x6a5f,
+ 0x6a60,0x6a61,0x6a62,0x6a63,0x6a64,0x6a65,0x6a66,0x6a67,
+ 0x6a68,0x6a69,0x6a6a,0x6a6b,0x6a6c,0x6a6d,0x6a6e,0x6a6f,
+ 0x6a70,0x6a71,0x6a72,0x6a73,0x6a74,0x6a75,0x6a76,0x6a77,
+ 0x6a78,0x6a79,0x6a7a,0x6a7b,0x6a7c,0x6a7d,0x6a7e,0x6a7f,
+ 0x6a80,0x6a81,0x6a82,0x6a83,0x6a84,0x6a85,0x6a86,0x6a87,
+ 0x6a88,0x6a89,0x6a8a,0x6a8b,0x6a8c,0x6a8d,0x6a8e,0x6a8f,
+ 0x6a90,0x6a91,0x6a92,0x6a93,0x6a94,0x6a95,0x6a96,0x6a97,
+ 0x6a98,0x6a99,0x6a9a,0x6a9b,0x6a9c,0x6a9d,0x6a9e,0x6a9f,
+ 0x6aa0,0x6aa1,0x6aa2,0x6aa3,0x6aa4,0x6aa5,0x6aa6,0x6aa7,
+ 0x6aa8,0x6aa9,0x6aaa,0x6aab,0x6aac,0x6aad,0x6aae,0x6aaf,
+ 0x6ab0,0x6ab1,0x6ab2,0x6ab3,0x6ab4,0x6ab5,0x6ab6,0x6ab7,
+ 0x6ab8,0x6ab9,0x6aba,0x6abb,0x6abc,0x6abd,0x6abe,0x6abf,
+ 0x6ac0,0x6ac1,0x6ac2,0x6ac3,0x6ac4,0x6ac5,0x6ac6,0x6ac7,
+ 0x6ac8,0x6ac9,0x6aca,0x6acb,0x6acc,0x6acd,0x6ace,0x6acf,
+ 0x6ad0,0x6ad1,0x6ad2,0x6ad3,0x6ad4,0x6ad5,0x6ad6,0x6ad7,
+ 0x6ad8,0x6ad9,0x6ada,0x6adb,0x6adc,0x6add,0x6ade,0x6adf,
+ 0x6ae0,0x6ae1,0x6ae2,0x6ae3,0x6ae4,0x6ae5,0x6ae6,0x6ae7,
+ 0x6ae8,0x6ae9,0x6aea,0x6aeb,0x6aec,0x6aed,0x6aee,0x6aef,
+ 0x6af0,0x6af1,0x6af2,0x6af3,0x6af4,0x6af5,0x6af6,0x6af7,
+ 0x6af8,0x6af9,0x6afa,0x6afb,0x6afc,0x6afd,0x6afe,0x6aff,
+ 0x6b00,0x6b01,0x6b02,0x6b03,0x6b04,0x6b05,0x6b06,0x6b07,
+ 0x6b08,0x6b09,0x6b0a,0x6b0b,0x6b0c,0x6b0d,0x6b0e,0x6b0f,
+ 0x6b10,0x6b11,0x6b12,0x6b13,0x6b14,0x6b15,0x6b16,0x6b17,
+ 0x6b18,0x6b19,0x6b1a,0x6b1b,0x6b1c,0x6b1d,0x6b1e,0x6b1f,
+ 0x6b20,0x6b21,0x6b22,0x6b23,0x6b24,0x6b25,0x6b26,0x6b27,
+ 0x6b28,0x6b29,0x6b2a,0x6b2b,0x6b2c,0x6b2d,0x6b2e,0x6b2f,
+ 0x6b30,0x6b31,0x6b32,0x6b33,0x6b34,0x6b35,0x6b36,0x6b37,
+ 0x6b38,0x6b39,0x6b3a,0x6b3b,0x6b3c,0x6b3d,0x6b3e,0x6b3f,
+ 0x6b40,0x6b41,0x6b42,0x6b43,0x6b44,0x6b45,0x6b46,0x6b47,
+ 0x6b48,0x6b49,0x6b4a,0x6b4b,0x6b4c,0x6b4d,0x6b4e,0x6b4f,
+ 0x6b50,0x6b51,0x6b52,0x6b53,0x6b54,0x6b55,0x6b56,0x6b57,
+ 0x6b58,0x6b59,0x6b5a,0x6b5b,0x6b5c,0x6b5d,0x6b5e,0x6b5f,
+ 0x6b60,0x6b61,0x6b62,0x6b63,0x6b64,0x6b65,0x6b66,0x6b67,
+ 0x6b68,0x6b69,0x6b6a,0x6b6b,0x6b6c,0x6b6d,0x6b6e,0x6b6f,
+ 0x6b70,0x6b71,0x6b72,0x6b73,0x6b74,0x6b75,0x6b76,0x6b77,
+ 0x6b78,0x6b79,0x6b7a,0x6b7b,0x6b7c,0x6b7d,0x6b7e,0x6b7f,
+ 0x6b80,0x6b81,0x6b82,0x6b83,0x6b84,0x6b85,0x6b86,0x6b87,
+ 0x6b88,0x6b89,0x6b8a,0x6b8b,0x6b8c,0x6b8d,0x6b8e,0x6b8f,
+ 0x6b90,0x6b91,0x6b92,0x6b93,0x6b94,0x6b95,0x6b96,0x6b97,
+ 0x6b98,0x6b99,0x6b9a,0x6b9b,0x6b9c,0x6b9d,0x6b9e,0x6b9f,
+ 0x6ba0,0x6ba1,0x6ba2,0x6ba3,0x6ba4,0x6ba5,0x6ba6,0x6ba7,
+ 0x6ba8,0x6ba9,0x6baa,0x6bab,0x6bac,0x6bad,0x6bae,0x6baf,
+ 0x6bb0,0x6bb1,0x6bb2,0x6bb3,0x6bb4,0x6bb5,0x6bb6,0x6bb7,
+ 0x6bb8,0x6bb9,0x6bba,0x6bbb,0x6bbc,0x6bbd,0x6bbe,0x6bbf,
+ 0x6bc0,0x6bc1,0x6bc2,0x6bc3,0x6bc4,0x6bc5,0x6bc6,0x6bc7,
+ 0x6bc8,0x6bc9,0x6bca,0x6bcb,0x6bcc,0x6bcd,0x6bce,0x6bcf,
+ 0x6bd0,0x6bd1,0x6bd2,0x6bd3,0x6bd4,0x6bd5,0x6bd6,0x6bd7,
+ 0x6bd8,0x6bd9,0x6bda,0x6bdb,0x6bdc,0x6bdd,0x6bde,0x6bdf,
+ 0x6be0,0x6be1,0x6be2,0x6be3,0x6be4,0x6be5,0x6be6,0x6be7,
+ 0x6be8,0x6be9,0x6bea,0x6beb,0x6bec,0x6bed,0x6bee,0x6bef,
+ 0x6bf0,0x6bf1,0x6bf2,0x6bf3,0x6bf4,0x6bf5,0x6bf6,0x6bf7,
+ 0x6bf8,0x6bf9,0x6bfa,0x6bfb,0x6bfc,0x6bfd,0x6bfe,0x6bff,
+ 0x6c00,0x6c01,0x6c02,0x6c03,0x6c04,0x6c05,0x6c06,0x6c07,
+ 0x6c08,0x6c09,0x6c0a,0x6c0b,0x6c0c,0x6c0d,0x6c0e,0x6c0f,
+ 0x6c10,0x6c11,0x6c12,0x6c13,0x6c14,0x6c15,0x6c16,0x6c17,
+ 0x6c18,0x6c19,0x6c1a,0x6c1b,0x6c1c,0x6c1d,0x6c1e,0x6c1f,
+ 0x6c20,0x6c21,0x6c22,0x6c23,0x6c24,0x6c25,0x6c26,0x6c27,
+ 0x6c28,0x6c29,0x6c2a,0x6c2b,0x6c2c,0x6c2d,0x6c2e,0x6c2f,
+ 0x6c30,0x6c31,0x6c32,0x6c33,0x6c34,0x6c35,0x6c36,0x6c37,
+ 0x6c38,0x6c39,0x6c3a,0x6c3b,0x6c3c,0x6c3d,0x6c3e,0x6c3f,
+ 0x6c40,0x6c41,0x6c42,0x6c43,0x6c44,0x6c45,0x6c46,0x6c47,
+ 0x6c48,0x6c49,0x6c4a,0x6c4b,0x6c4c,0x6c4d,0x6c4e,0x6c4f,
+ 0x6c50,0x6c51,0x6c52,0x6c53,0x6c54,0x6c55,0x6c56,0x6c57,
+ 0x6c58,0x6c59,0x6c5a,0x6c5b,0x6c5c,0x6c5d,0x6c5e,0x6c5f,
+ 0x6c60,0x6c61,0x6c62,0x6c63,0x6c64,0x6c65,0x6c66,0x6c67,
+ 0x6c68,0x6c69,0x6c6a,0x6c6b,0x6c6c,0x6c6d,0x6c6e,0x6c6f,
+ 0x6c70,0x6c71,0x6c72,0x6c73,0x6c74,0x6c75,0x6c76,0x6c77,
+ 0x6c78,0x6c79,0x6c7a,0x6c7b,0x6c7c,0x6c7d,0x6c7e,0x6c7f,
+ 0x6c80,0x6c81,0x6c82,0x6c83,0x6c84,0x6c85,0x6c86,0x6c87,
+ 0x6c88,0x6c89,0x6c8a,0x6c8b,0x6c8c,0x6c8d,0x6c8e,0x6c8f,
+ 0x6c90,0x6c91,0x6c92,0x6c93,0x6c94,0x6c95,0x6c96,0x6c97,
+ 0x6c98,0x6c99,0x6c9a,0x6c9b,0x6c9c,0x6c9d,0x6c9e,0x6c9f,
+ 0x6ca0,0x6ca1,0x6ca2,0x6ca3,0x6ca4,0x6ca5,0x6ca6,0x6ca7,
+ 0x6ca8,0x6ca9,0x6caa,0x6cab,0x6cac,0x6cad,0x6cae,0x6caf,
+ 0x6cb0,0x6cb1,0x6cb2,0x6cb3,0x6cb4,0x6cb5,0x6cb6,0x6cb7,
+ 0x6cb8,0x6cb9,0x6cba,0x6cbb,0x6cbc,0x6cbd,0x6cbe,0x6cbf,
+ 0x6cc0,0x6cc1,0x6cc2,0x6cc3,0x6cc4,0x6cc5,0x6cc6,0x6cc7,
+ 0x6cc8,0x6cc9,0x6cca,0x6ccb,0x6ccc,0x6ccd,0x6cce,0x6ccf,
+ 0x6cd0,0x6cd1,0x6cd2,0x6cd3,0x6cd4,0x6cd5,0x6cd6,0x6cd7,
+ 0x6cd8,0x6cd9,0x6cda,0x6cdb,0x6cdc,0x6cdd,0x6cde,0x6cdf,
+ 0x6ce0,0x6ce1,0x6ce2,0x6ce3,0x6ce4,0x6ce5,0x6ce6,0x6ce7,
+ 0x6ce8,0x6ce9,0x6cea,0x6ceb,0x6cec,0x6ced,0x6cee,0x6cef,
+ 0x6cf0,0x6cf1,0x6cf2,0x6cf3,0x6cf4,0x6cf5,0x6cf6,0x6cf7,
+ 0x6cf8,0x6cf9,0x6cfa,0x6cfb,0x6cfc,0x6cfd,0x6cfe,0x6cff,
+ 0x6d00,0x6d01,0x6d02,0x6d03,0x6d04,0x6d05,0x6d06,0x6d07,
+ 0x6d08,0x6d09,0x6d0a,0x6d0b,0x6d0c,0x6d0d,0x6d0e,0x6d0f,
+ 0x6d10,0x6d11,0x6d12,0x6d13,0x6d14,0x6d15,0x6d16,0x6d17,
+ 0x6d18,0x6d19,0x6d1a,0x6d1b,0x6d1c,0x6d1d,0x6d1e,0x6d1f,
+ 0x6d20,0x6d21,0x6d22,0x6d23,0x6d24,0x6d25,0x6d26,0x6d27,
+ 0x6d28,0x6d29,0x6d2a,0x6d2b,0x6d2c,0x6d2d,0x6d2e,0x6d2f,
+ 0x6d30,0x6d31,0x6d32,0x6d33,0x6d34,0x6d35,0x6d36,0x6d37,
+ 0x6d38,0x6d39,0x6d3a,0x6d3b,0x6d3c,0x6d3d,0x6d3e,0x6d3f,
+ 0x6d40,0x6d41,0x6d42,0x6d43,0x6d44,0x6d45,0x6d46,0x6d47,
+ 0x6d48,0x6d49,0x6d4a,0x6d4b,0x6d4c,0x6d4d,0x6d4e,0x6d4f,
+ 0x6d50,0x6d51,0x6d52,0x6d53,0x6d54,0x6d55,0x6d56,0x6d57,
+ 0x6d58,0x6d59,0x6d5a,0x6d5b,0x6d5c,0x6d5d,0x6d5e,0x6d5f,
+ 0x6d60,0x6d61,0x6d62,0x6d63,0x6d64,0x6d65,0x6d66,0x6d67,
+ 0x6d68,0x6d69,0x6d6a,0x6d6b,0x6d6c,0x6d6d,0x6d6e,0x6d6f,
+ 0x6d70,0x6d71,0x6d72,0x6d73,0x6d74,0x6d75,0x6d76,0x6d77,
+ 0x6d78,0x6d79,0x6d7a,0x6d7b,0x6d7c,0x6d7d,0x6d7e,0x6d7f,
+ 0x6d80,0x6d81,0x6d82,0x6d83,0x6d84,0x6d85,0x6d86,0x6d87,
+ 0x6d88,0x6d89,0x6d8a,0x6d8b,0x6d8c,0x6d8d,0x6d8e,0x6d8f,
+ 0x6d90,0x6d91,0x6d92,0x6d93,0x6d94,0x6d95,0x6d96,0x6d97,
+ 0x6d98,0x6d99,0x6d9a,0x6d9b,0x6d9c,0x6d9d,0x6d9e,0x6d9f,
+ 0x6da0,0x6da1,0x6da2,0x6da3,0x6da4,0x6da5,0x6da6,0x6da7,
+ 0x6da8,0x6da9,0x6daa,0x6dab,0x6dac,0x6dad,0x6dae,0x6daf,
+ 0x6db0,0x6db1,0x6db2,0x6db3,0x6db4,0x6db5,0x6db6,0x6db7,
+ 0x6db8,0x6db9,0x6dba,0x6dbb,0x6dbc,0x6dbd,0x6dbe,0x6dbf,
+ 0x6dc0,0x6dc1,0x6dc2,0x6dc3,0x6dc4,0x6dc5,0x6dc6,0x6dc7,
+ 0x6dc8,0x6dc9,0x6dca,0x6dcb,0x6dcc,0x6dcd,0x6dce,0x6dcf,
+ 0x6dd0,0x6dd1,0x6dd2,0x6dd3,0x6dd4,0x6dd5,0x6dd6,0x6dd7,
+ 0x6dd8,0x6dd9,0x6dda,0x6ddb,0x6ddc,0x6ddd,0x6dde,0x6ddf,
+ 0x6de0,0x6de1,0x6de2,0x6de3,0x6de4,0x6de5,0x6de6,0x6de7,
+ 0x6de8,0x6de9,0x6dea,0x6deb,0x6dec,0x6ded,0x6dee,0x6def,
+ 0x6df0,0x6df1,0x6df2,0x6df3,0x6df4,0x6df5,0x6df6,0x6df7,
+ 0x6df8,0x6df9,0x6dfa,0x6dfb,0x6dfc,0x6dfd,0x6dfe,0x6dff,
+ 0x6e00,0x6e01,0x6e02,0x6e03,0x6e04,0x6e05,0x6e06,0x6e07,
+ 0x6e08,0x6e09,0x6e0a,0x6e0b,0x6e0c,0x6e0d,0x6e0e,0x6e0f,
+ 0x6e10,0x6e11,0x6e12,0x6e13,0x6e14,0x6e15,0x6e16,0x6e17,
+ 0x6e18,0x6e19,0x6e1a,0x6e1b,0x6e1c,0x6e1d,0x6e1e,0x6e1f,
+ 0x6e20,0x6e21,0x6e22,0x6e23,0x6e24,0x6e25,0x6e26,0x6e27,
+ 0x6e28,0x6e29,0x6e2a,0x6e2b,0x6e2c,0x6e2d,0x6e2e,0x6e2f,
+ 0x6e30,0x6e31,0x6e32,0x6e33,0x6e34,0x6e35,0x6e36,0x6e37,
+ 0x6e38,0x6e39,0x6e3a,0x6e3b,0x6e3c,0x6e3d,0x6e3e,0x6e3f,
+ 0x6e40,0x6e41,0x6e42,0x6e43,0x6e44,0x6e45,0x6e46,0x6e47,
+ 0x6e48,0x6e49,0x6e4a,0x6e4b,0x6e4c,0x6e4d,0x6e4e,0x6e4f,
+ 0x6e50,0x6e51,0x6e52,0x6e53,0x6e54,0x6e55,0x6e56,0x6e57,
+ 0x6e58,0x6e59,0x6e5a,0x6e5b,0x6e5c,0x6e5d,0x6e5e,0x6e5f,
+ 0x6e60,0x6e61,0x6e62,0x6e63,0x6e64,0x6e65,0x6e66,0x6e67,
+ 0x6e68,0x6e69,0x6e6a,0x6e6b,0x6e6c,0x6e6d,0x6e6e,0x6e6f,
+ 0x6e70,0x6e71,0x6e72,0x6e73,0x6e74,0x6e75,0x6e76,0x6e77,
+ 0x6e78,0x6e79,0x6e7a,0x6e7b,0x6e7c,0x6e7d,0x6e7e,0x6e7f,
+ 0x6e80,0x6e81,0x6e82,0x6e83,0x6e84,0x6e85,0x6e86,0x6e87,
+ 0x6e88,0x6e89,0x6e8a,0x6e8b,0x6e8c,0x6e8d,0x6e8e,0x6e8f,
+ 0x6e90,0x6e91,0x6e92,0x6e93,0x6e94,0x6e95,0x6e96,0x6e97,
+ 0x6e98,0x6e99,0x6e9a,0x6e9b,0x6e9c,0x6e9d,0x6e9e,0x6e9f,
+ 0x6ea0,0x6ea1,0x6ea2,0x6ea3,0x6ea4,0x6ea5,0x6ea6,0x6ea7,
+ 0x6ea8,0x6ea9,0x6eaa,0x6eab,0x6eac,0x6ead,0x6eae,0x6eaf,
+ 0x6eb0,0x6eb1,0x6eb2,0x6eb3,0x6eb4,0x6eb5,0x6eb6,0x6eb7,
+ 0x6eb8,0x6eb9,0x6eba,0x6ebb,0x6ebc,0x6ebd,0x6ebe,0x6ebf,
+ 0x6ec0,0x6ec1,0x6ec2,0x6ec3,0x6ec4,0x6ec5,0x6ec6,0x6ec7,
+ 0x6ec8,0x6ec9,0x6eca,0x6ecb,0x6ecc,0x6ecd,0x6ece,0x6ecf,
+ 0x6ed0,0x6ed1,0x6ed2,0x6ed3,0x6ed4,0x6ed5,0x6ed6,0x6ed7,
+ 0x6ed8,0x6ed9,0x6eda,0x6edb,0x6edc,0x6edd,0x6ede,0x6edf,
+ 0x6ee0,0x6ee1,0x6ee2,0x6ee3,0x6ee4,0x6ee5,0x6ee6,0x6ee7,
+ 0x6ee8,0x6ee9,0x6eea,0x6eeb,0x6eec,0x6eed,0x6eee,0x6eef,
+ 0x6ef0,0x6ef1,0x6ef2,0x6ef3,0x6ef4,0x6ef5,0x6ef6,0x6ef7,
+ 0x6ef8,0x6ef9,0x6efa,0x6efb,0x6efc,0x6efd,0x6efe,0x6eff,
+ 0x6f00,0x6f01,0x6f02,0x6f03,0x6f04,0x6f05,0x6f06,0x6f07,
+ 0x6f08,0x6f09,0x6f0a,0x6f0b,0x6f0c,0x6f0d,0x6f0e,0x6f0f,
+ 0x6f10,0x6f11,0x6f12,0x6f13,0x6f14,0x6f15,0x6f16,0x6f17,
+ 0x6f18,0x6f19,0x6f1a,0x6f1b,0x6f1c,0x6f1d,0x6f1e,0x6f1f,
+ 0x6f20,0x6f21,0x6f22,0x6f23,0x6f24,0x6f25,0x6f26,0x6f27,
+ 0x6f28,0x6f29,0x6f2a,0x6f2b,0x6f2c,0x6f2d,0x6f2e,0x6f2f,
+ 0x6f30,0x6f31,0x6f32,0x6f33,0x6f34,0x6f35,0x6f36,0x6f37,
+ 0x6f38,0x6f39,0x6f3a,0x6f3b,0x6f3c,0x6f3d,0x6f3e,0x6f3f,
+ 0x6f40,0x6f41,0x6f42,0x6f43,0x6f44,0x6f45,0x6f46,0x6f47,
+ 0x6f48,0x6f49,0x6f4a,0x6f4b,0x6f4c,0x6f4d,0x6f4e,0x6f4f,
+ 0x6f50,0x6f51,0x6f52,0x6f53,0x6f54,0x6f55,0x6f56,0x6f57,
+ 0x6f58,0x6f59,0x6f5a,0x6f5b,0x6f5c,0x6f5d,0x6f5e,0x6f5f,
+ 0x6f60,0x6f61,0x6f62,0x6f63,0x6f64,0x6f65,0x6f66,0x6f67,
+ 0x6f68,0x6f69,0x6f6a,0x6f6b,0x6f6c,0x6f6d,0x6f6e,0x6f6f,
+ 0x6f70,0x6f71,0x6f72,0x6f73,0x6f74,0x6f75,0x6f76,0x6f77,
+ 0x6f78,0x6f79,0x6f7a,0x6f7b,0x6f7c,0x6f7d,0x6f7e,0x6f7f,
+ 0x6f80,0x6f81,0x6f82,0x6f83,0x6f84,0x6f85,0x6f86,0x6f87,
+ 0x6f88,0x6f89,0x6f8a,0x6f8b,0x6f8c,0x6f8d,0x6f8e,0x6f8f,
+ 0x6f90,0x6f91,0x6f92,0x6f93,0x6f94,0x6f95,0x6f96,0x6f97,
+ 0x6f98,0x6f99,0x6f9a,0x6f9b,0x6f9c,0x6f9d,0x6f9e,0x6f9f,
+ 0x6fa0,0x6fa1,0x6fa2,0x6fa3,0x6fa4,0x6fa5,0x6fa6,0x6fa7,
+ 0x6fa8,0x6fa9,0x6faa,0x6fab,0x6fac,0x6fad,0x6fae,0x6faf,
+ 0x6fb0,0x6fb1,0x6fb2,0x6fb3,0x6fb4,0x6fb5,0x6fb6,0x6fb7,
+ 0x6fb8,0x6fb9,0x6fba,0x6fbb,0x6fbc,0x6fbd,0x6fbe,0x6fbf,
+ 0x6fc0,0x6fc1,0x6fc2,0x6fc3,0x6fc4,0x6fc5,0x6fc6,0x6fc7,
+ 0x6fc8,0x6fc9,0x6fca,0x6fcb,0x6fcc,0x6fcd,0x6fce,0x6fcf,
+ 0x6fd0,0x6fd1,0x6fd2,0x6fd3,0x6fd4,0x6fd5,0x6fd6,0x6fd7,
+ 0x6fd8,0x6fd9,0x6fda,0x6fdb,0x6fdc,0x6fdd,0x6fde,0x6fdf,
+ 0x6fe0,0x6fe1,0x6fe2,0x6fe3,0x6fe4,0x6fe5,0x6fe6,0x6fe7,
+ 0x6fe8,0x6fe9,0x6fea,0x6feb,0x6fec,0x6fed,0x6fee,0x6fef,
+ 0x6ff0,0x6ff1,0x6ff2,0x6ff3,0x6ff4,0x6ff5,0x6ff6,0x6ff7,
+ 0x6ff8,0x6ff9,0x6ffa,0x6ffb,0x6ffc,0x6ffd,0x6ffe,0x6fff,
+ 0x7000,0x7001,0x7002,0x7003,0x7004,0x7005,0x7006,0x7007,
+ 0x7008,0x7009,0x700a,0x700b,0x700c,0x700d,0x700e,0x700f,
+ 0x7010,0x7011,0x7012,0x7013,0x7014,0x7015,0x7016,0x7017,
+ 0x7018,0x7019,0x701a,0x701b,0x701c,0x701d,0x701e,0x701f,
+ 0x7020,0x7021,0x7022,0x7023,0x7024,0x7025,0x7026,0x7027,
+ 0x7028,0x7029,0x702a,0x702b,0x702c,0x702d,0x702e,0x702f,
+ 0x7030,0x7031,0x7032,0x7033,0x7034,0x7035,0x7036,0x7037,
+ 0x7038,0x7039,0x703a,0x703b,0x703c,0x703d,0x703e,0x703f,
+ 0x7040,0x7041,0x7042,0x7043,0x7044,0x7045,0x7046,0x7047,
+ 0x7048,0x7049,0x704a,0x704b,0x704c,0x704d,0x704e,0x704f,
+ 0x7050,0x7051,0x7052,0x7053,0x7054,0x7055,0x7056,0x7057,
+ 0x7058,0x7059,0x705a,0x705b,0x705c,0x705d,0x705e,0x705f,
+ 0x7060,0x7061,0x7062,0x7063,0x7064,0x7065,0x7066,0x7067,
+ 0x7068,0x7069,0x706a,0x706b,0x706c,0x706d,0x706e,0x706f,
+ 0x7070,0x7071,0x7072,0x7073,0x7074,0x7075,0x7076,0x7077,
+ 0x7078,0x7079,0x707a,0x707b,0x707c,0x707d,0x707e,0x707f,
+ 0x7080,0x7081,0x7082,0x7083,0x7084,0x7085,0x7086,0x7087,
+ 0x7088,0x7089,0x708a,0x708b,0x708c,0x708d,0x708e,0x708f,
+ 0x7090,0x7091,0x7092,0x7093,0x7094,0x7095,0x7096,0x7097,
+ 0x7098,0x7099,0x709a,0x709b,0x709c,0x709d,0x709e,0x709f,
+ 0x70a0,0x70a1,0x70a2,0x70a3,0x70a4,0x70a5,0x70a6,0x70a7,
+ 0x70a8,0x70a9,0x70aa,0x70ab,0x70ac,0x70ad,0x70ae,0x70af,
+ 0x70b0,0x70b1,0x70b2,0x70b3,0x70b4,0x70b5,0x70b6,0x70b7,
+ 0x70b8,0x70b9,0x70ba,0x70bb,0x70bc,0x70bd,0x70be,0x70bf,
+ 0x70c0,0x70c1,0x70c2,0x70c3,0x70c4,0x70c5,0x70c6,0x70c7,
+ 0x70c8,0x70c9,0x70ca,0x70cb,0x70cc,0x70cd,0x70ce,0x70cf,
+ 0x70d0,0x70d1,0x70d2,0x70d3,0x70d4,0x70d5,0x70d6,0x70d7,
+ 0x70d8,0x70d9,0x70da,0x70db,0x70dc,0x70dd,0x70de,0x70df,
+ 0x70e0,0x70e1,0x70e2,0x70e3,0x70e4,0x70e5,0x70e6,0x70e7,
+ 0x70e8,0x70e9,0x70ea,0x70eb,0x70ec,0x70ed,0x70ee,0x70ef,
+ 0x70f0,0x70f1,0x70f2,0x70f3,0x70f4,0x70f5,0x70f6,0x70f7,
+ 0x70f8,0x70f9,0x70fa,0x70fb,0x70fc,0x70fd,0x70fe,0x70ff,
+ 0x7100,0x7101,0x7102,0x7103,0x7104,0x7105,0x7106,0x7107,
+ 0x7108,0x7109,0x710a,0x710b,0x710c,0x710d,0x710e,0x710f,
+ 0x7110,0x7111,0x7112,0x7113,0x7114,0x7115,0x7116,0x7117,
+ 0x7118,0x7119,0x711a,0x711b,0x711c,0x711d,0x711e,0x711f,
+ 0x7120,0x7121,0x7122,0x7123,0x7124,0x7125,0x7126,0x7127,
+ 0x7128,0x7129,0x712a,0x712b,0x712c,0x712d,0x712e,0x712f,
+ 0x7130,0x7131,0x7132,0x7133,0x7134,0x7135,0x7136,0x7137,
+ 0x7138,0x7139,0x713a,0x713b,0x713c,0x713d,0x713e,0x713f,
+ 0x7140,0x7141,0x7142,0x7143,0x7144,0x7145,0x7146,0x7147,
+ 0x7148,0x7149,0x714a,0x714b,0x714c,0x714d,0x714e,0x714f,
+ 0x7150,0x7151,0x7152,0x7153,0x7154,0x7155,0x7156,0x7157,
+ 0x7158,0x7159,0x715a,0x715b,0x715c,0x715d,0x715e,0x715f,
+ 0x7160,0x7161,0x7162,0x7163,0x7164,0x7165,0x7166,0x7167,
+ 0x7168,0x7169,0x716a,0x716b,0x716c,0x716d,0x716e,0x716f,
+ 0x7170,0x7171,0x7172,0x7173,0x7174,0x7175,0x7176,0x7177,
+ 0x7178,0x7179,0x717a,0x717b,0x717c,0x717d,0x717e,0x717f,
+ 0x7180,0x7181,0x7182,0x7183,0x7184,0x7185,0x7186,0x7187,
+ 0x7188,0x7189,0x718a,0x718b,0x718c,0x718d,0x718e,0x718f,
+ 0x7190,0x7191,0x7192,0x7193,0x7194,0x7195,0x7196,0x7197,
+ 0x7198,0x7199,0x719a,0x719b,0x719c,0x719d,0x719e,0x719f,
+ 0x71a0,0x71a1,0x71a2,0x71a3,0x71a4,0x71a5,0x71a6,0x71a7,
+ 0x71a8,0x71a9,0x71aa,0x71ab,0x71ac,0x71ad,0x71ae,0x71af,
+ 0x71b0,0x71b1,0x71b2,0x71b3,0x71b4,0x71b5,0x71b6,0x71b7,
+ 0x71b8,0x71b9,0x71ba,0x71bb,0x71bc,0x71bd,0x71be,0x71bf,
+ 0x71c0,0x71c1,0x71c2,0x71c3,0x71c4,0x71c5,0x71c6,0x71c7,
+ 0x71c8,0x71c9,0x71ca,0x71cb,0x71cc,0x71cd,0x71ce,0x71cf,
+ 0x71d0,0x71d1,0x71d2,0x71d3,0x71d4,0x71d5,0x71d6,0x71d7,
+ 0x71d8,0x71d9,0x71da,0x71db,0x71dc,0x71dd,0x71de,0x71df,
+ 0x71e0,0x71e1,0x71e2,0x71e3,0x71e4,0x71e5,0x71e6,0x71e7,
+ 0x71e8,0x71e9,0x71ea,0x71eb,0x71ec,0x71ed,0x71ee,0x71ef,
+ 0x71f0,0x71f1,0x71f2,0x71f3,0x71f4,0x71f5,0x71f6,0x71f7,
+ 0x71f8,0x71f9,0x71fa,0x71fb,0x71fc,0x71fd,0x71fe,0x71ff,
+ 0x7200,0x7201,0x7202,0x7203,0x7204,0x7205,0x7206,0x7207,
+ 0x7208,0x7209,0x720a,0x720b,0x720c,0x720d,0x720e,0x720f,
+ 0x7210,0x7211,0x7212,0x7213,0x7214,0x7215,0x7216,0x7217,
+ 0x7218,0x7219,0x721a,0x721b,0x721c,0x721d,0x721e,0x721f,
+ 0x7220,0x7221,0x7222,0x7223,0x7224,0x7225,0x7226,0x7227,
+ 0x7228,0x7229,0x722a,0x722b,0x722c,0x722d,0x722e,0x722f,
+ 0x7230,0x7231,0x7232,0x7233,0x7234,0x7235,0x7236,0x7237,
+ 0x7238,0x7239,0x723a,0x723b,0x723c,0x723d,0x723e,0x723f,
+ 0x7240,0x7241,0x7242,0x7243,0x7244,0x7245,0x7246,0x7247,
+ 0x7248,0x7249,0x724a,0x724b,0x724c,0x724d,0x724e,0x724f,
+ 0x7250,0x7251,0x7252,0x7253,0x7254,0x7255,0x7256,0x7257,
+ 0x7258,0x7259,0x725a,0x725b,0x725c,0x725d,0x725e,0x725f,
+ 0x7260,0x7261,0x7262,0x7263,0x7264,0x7265,0x7266,0x7267,
+ 0x7268,0x7269,0x726a,0x726b,0x726c,0x726d,0x726e,0x726f,
+ 0x7270,0x7271,0x7272,0x7273,0x7274,0x7275,0x7276,0x7277,
+ 0x7278,0x7279,0x727a,0x727b,0x727c,0x727d,0x727e,0x727f,
+ 0x7280,0x7281,0x7282,0x7283,0x7284,0x7285,0x7286,0x7287,
+ 0x7288,0x7289,0x728a,0x728b,0x728c,0x728d,0x728e,0x728f,
+ 0x7290,0x7291,0x7292,0x7293,0x7294,0x7295,0x7296,0x7297,
+ 0x7298,0x7299,0x729a,0x729b,0x729c,0x729d,0x729e,0x729f,
+ 0x72a0,0x72a1,0x72a2,0x72a3,0x72a4,0x72a5,0x72a6,0x72a7,
+ 0x72a8,0x72a9,0x72aa,0x72ab,0x72ac,0x72ad,0x72ae,0x72af,
+ 0x72b0,0x72b1,0x72b2,0x72b3,0x72b4,0x72b5,0x72b6,0x72b7,
+ 0x72b8,0x72b9,0x72ba,0x72bb,0x72bc,0x72bd,0x72be,0x72bf,
+ 0x72c0,0x72c1,0x72c2,0x72c3,0x72c4,0x72c5,0x72c6,0x72c7,
+ 0x72c8,0x72c9,0x72ca,0x72cb,0x72cc,0x72cd,0x72ce,0x72cf,
+ 0x72d0,0x72d1,0x72d2,0x72d3,0x72d4,0x72d5,0x72d6,0x72d7,
+ 0x72d8,0x72d9,0x72da,0x72db,0x72dc,0x72dd,0x72de,0x72df,
+ 0x72e0,0x72e1,0x72e2,0x72e3,0x72e4,0x72e5,0x72e6,0x72e7,
+ 0x72e8,0x72e9,0x72ea,0x72eb,0x72ec,0x72ed,0x72ee,0x72ef,
+ 0x72f0,0x72f1,0x72f2,0x72f3,0x72f4,0x72f5,0x72f6,0x72f7,
+ 0x72f8,0x72f9,0x72fa,0x72fb,0x72fc,0x72fd,0x72fe,0x72ff,
+ 0x7300,0x7301,0x7302,0x7303,0x7304,0x7305,0x7306,0x7307,
+ 0x7308,0x7309,0x730a,0x730b,0x730c,0x730d,0x730e,0x730f,
+ 0x7310,0x7311,0x7312,0x7313,0x7314,0x7315,0x7316,0x7317,
+ 0x7318,0x7319,0x731a,0x731b,0x731c,0x731d,0x731e,0x731f,
+ 0x7320,0x7321,0x7322,0x7323,0x7324,0x7325,0x7326,0x7327,
+ 0x7328,0x7329,0x732a,0x732b,0x732c,0x732d,0x732e,0x732f,
+ 0x7330,0x7331,0x7332,0x7333,0x7334,0x7335,0x7336,0x7337,
+ 0x7338,0x7339,0x733a,0x733b,0x733c,0x733d,0x733e,0x733f,
+ 0x7340,0x7341,0x7342,0x7343,0x7344,0x7345,0x7346,0x7347,
+ 0x7348,0x7349,0x734a,0x734b,0x734c,0x734d,0x734e,0x734f,
+ 0x7350,0x7351,0x7352,0x7353,0x7354,0x7355,0x7356,0x7357,
+ 0x7358,0x7359,0x735a,0x735b,0x735c,0x735d,0x735e,0x735f,
+ 0x7360,0x7361,0x7362,0x7363,0x7364,0x7365,0x7366,0x7367,
+ 0x7368,0x7369,0x736a,0x736b,0x736c,0x736d,0x736e,0x736f,
+ 0x7370,0x7371,0x7372,0x7373,0x7374,0x7375,0x7376,0x7377,
+ 0x7378,0x7379,0x737a,0x737b,0x737c,0x737d,0x737e,0x737f,
+ 0x7380,0x7381,0x7382,0x7383,0x7384,0x7385,0x7386,0x7387,
+ 0x7388,0x7389,0x738a,0x738b,0x738c,0x738d,0x738e,0x738f,
+ 0x7390,0x7391,0x7392,0x7393,0x7394,0x7395,0x7396,0x7397,
+ 0x7398,0x7399,0x739a,0x739b,0x739c,0x739d,0x739e,0x739f,
+ 0x73a0,0x73a1,0x73a2,0x73a3,0x73a4,0x73a5,0x73a6,0x73a7,
+ 0x73a8,0x73a9,0x73aa,0x73ab,0x73ac,0x73ad,0x73ae,0x73af,
+ 0x73b0,0x73b1,0x73b2,0x73b3,0x73b4,0x73b5,0x73b6,0x73b7,
+ 0x73b8,0x73b9,0x73ba,0x73bb,0x73bc,0x73bd,0x73be,0x73bf,
+ 0x73c0,0x73c1,0x73c2,0x73c3,0x73c4,0x73c5,0x73c6,0x73c7,
+ 0x73c8,0x73c9,0x73ca,0x73cb,0x73cc,0x73cd,0x73ce,0x73cf,
+ 0x73d0,0x73d1,0x73d2,0x73d3,0x73d4,0x73d5,0x73d6,0x73d7,
+ 0x73d8,0x73d9,0x73da,0x73db,0x73dc,0x73dd,0x73de,0x73df,
+ 0x73e0,0x73e1,0x73e2,0x73e3,0x73e4,0x73e5,0x73e6,0x73e7,
+ 0x73e8,0x73e9,0x73ea,0x73eb,0x73ec,0x73ed,0x73ee,0x73ef,
+ 0x73f0,0x73f1,0x73f2,0x73f3,0x73f4,0x73f5,0x73f6,0x73f7,
+ 0x73f8,0x73f9,0x73fa,0x73fb,0x73fc,0x73fd,0x73fe,0x73ff,
+ 0x7400,0x7401,0x7402,0x7403,0x7404,0x7405,0x7406,0x7407,
+ 0x7408,0x7409,0x740a,0x740b,0x740c,0x740d,0x740e,0x740f,
+ 0x7410,0x7411,0x7412,0x7413,0x7414,0x7415,0x7416,0x7417,
+ 0x7418,0x7419,0x741a,0x741b,0x741c,0x741d,0x741e,0x741f,
+ 0x7420,0x7421,0x7422,0x7423,0x7424,0x7425,0x7426,0x7427,
+ 0x7428,0x7429,0x742a,0x742b,0x742c,0x742d,0x742e,0x742f,
+ 0x7430,0x7431,0x7432,0x7433,0x7434,0x7435,0x7436,0x7437,
+ 0x7438,0x7439,0x743a,0x743b,0x743c,0x743d,0x743e,0x743f,
+ 0x7440,0x7441,0x7442,0x7443,0x7444,0x7445,0x7446,0x7447,
+ 0x7448,0x7449,0x744a,0x744b,0x744c,0x744d,0x744e,0x744f,
+ 0x7450,0x7451,0x7452,0x7453,0x7454,0x7455,0x7456,0x7457,
+ 0x7458,0x7459,0x745a,0x745b,0x745c,0x745d,0x745e,0x745f,
+ 0x7460,0x7461,0x7462,0x7463,0x7464,0x7465,0x7466,0x7467,
+ 0x7468,0x7469,0x746a,0x746b,0x746c,0x746d,0x746e,0x746f,
+ 0x7470,0x7471,0x7472,0x7473,0x7474,0x7475,0x7476,0x7477,
+ 0x7478,0x7479,0x747a,0x747b,0x747c,0x747d,0x747e,0x747f,
+ 0x7480,0x7481,0x7482,0x7483,0x7484,0x7485,0x7486,0x7487,
+ 0x7488,0x7489,0x748a,0x748b,0x748c,0x748d,0x748e,0x748f,
+ 0x7490,0x7491,0x7492,0x7493,0x7494,0x7495,0x7496,0x7497,
+ 0x7498,0x7499,0x749a,0x749b,0x749c,0x749d,0x749e,0x749f,
+ 0x74a0,0x74a1,0x74a2,0x74a3,0x74a4,0x74a5,0x74a6,0x74a7,
+ 0x74a8,0x74a9,0x74aa,0x74ab,0x74ac,0x74ad,0x74ae,0x74af,
+ 0x74b0,0x74b1,0x74b2,0x74b3,0x74b4,0x74b5,0x74b6,0x74b7,
+ 0x74b8,0x74b9,0x74ba,0x74bb,0x74bc,0x74bd,0x74be,0x74bf,
+ 0x74c0,0x74c1,0x74c2,0x74c3,0x74c4,0x74c5,0x74c6,0x74c7,
+ 0x74c8,0x74c9,0x74ca,0x74cb,0x74cc,0x74cd,0x74ce,0x74cf,
+ 0x74d0,0x74d1,0x74d2,0x74d3,0x74d4,0x74d5,0x74d6,0x74d7,
+ 0x74d8,0x74d9,0x74da,0x74db,0x74dc,0x74dd,0x74de,0x74df,
+ 0x74e0,0x74e1,0x74e2,0x74e3,0x74e4,0x74e5,0x74e6,0x74e7,
+ 0x74e8,0x74e9,0x74ea,0x74eb,0x74ec,0x74ed,0x74ee,0x74ef,
+ 0x74f0,0x74f1,0x74f2,0x74f3,0x74f4,0x74f5,0x74f6,0x74f7,
+ 0x74f8,0x74f9,0x74fa,0x74fb,0x74fc,0x74fd,0x74fe,0x74ff,
+ 0x7500,0x7501,0x7502,0x7503,0x7504,0x7505,0x7506,0x7507,
+ 0x7508,0x7509,0x750a,0x750b,0x750c,0x750d,0x750e,0x750f,
+ 0x7510,0x7511,0x7512,0x7513,0x7514,0x7515,0x7516,0x7517,
+ 0x7518,0x7519,0x751a,0x751b,0x751c,0x751d,0x751e,0x751f,
+ 0x7520,0x7521,0x7522,0x7523,0x7524,0x7525,0x7526,0x7527,
+ 0x7528,0x7529,0x752a,0x752b,0x752c,0x752d,0x752e,0x752f,
+ 0x7530,0x7531,0x7532,0x7533,0x7534,0x7535,0x7536,0x7537,
+ 0x7538,0x7539,0x753a,0x753b,0x753c,0x753d,0x753e,0x753f,
+ 0x7540,0x7541,0x7542,0x7543,0x7544,0x7545,0x7546,0x7547,
+ 0x7548,0x7549,0x754a,0x754b,0x754c,0x754d,0x754e,0x754f,
+ 0x7550,0x7551,0x7552,0x7553,0x7554,0x7555,0x7556,0x7557,
+ 0x7558,0x7559,0x755a,0x755b,0x755c,0x755d,0x755e,0x755f,
+ 0x7560,0x7561,0x7562,0x7563,0x7564,0x7565,0x7566,0x7567,
+ 0x7568,0x7569,0x756a,0x756b,0x756c,0x756d,0x756e,0x756f,
+ 0x7570,0x7571,0x7572,0x7573,0x7574,0x7575,0x7576,0x7577,
+ 0x7578,0x7579,0x757a,0x757b,0x757c,0x757d,0x757e,0x757f,
+ 0x7580,0x7581,0x7582,0x7583,0x7584,0x7585,0x7586,0x7587,
+ 0x7588,0x7589,0x758a,0x758b,0x758c,0x758d,0x758e,0x758f,
+ 0x7590,0x7591,0x7592,0x7593,0x7594,0x7595,0x7596,0x7597,
+ 0x7598,0x7599,0x759a,0x759b,0x759c,0x759d,0x759e,0x759f,
+ 0x75a0,0x75a1,0x75a2,0x75a3,0x75a4,0x75a5,0x75a6,0x75a7,
+ 0x75a8,0x75a9,0x75aa,0x75ab,0x75ac,0x75ad,0x75ae,0x75af,
+ 0x75b0,0x75b1,0x75b2,0x75b3,0x75b4,0x75b5,0x75b6,0x75b7,
+ 0x75b8,0x75b9,0x75ba,0x75bb,0x75bc,0x75bd,0x75be,0x75bf,
+ 0x75c0,0x75c1,0x75c2,0x75c3,0x75c4,0x75c5,0x75c6,0x75c7,
+ 0x75c8,0x75c9,0x75ca,0x75cb,0x75cc,0x75cd,0x75ce,0x75cf,
+ 0x75d0,0x75d1,0x75d2,0x75d3,0x75d4,0x75d5,0x75d6,0x75d7,
+ 0x75d8,0x75d9,0x75da,0x75db,0x75dc,0x75dd,0x75de,0x75df,
+ 0x75e0,0x75e1,0x75e2,0x75e3,0x75e4,0x75e5,0x75e6,0x75e7,
+ 0x75e8,0x75e9,0x75ea,0x75eb,0x75ec,0x75ed,0x75ee,0x75ef,
+ 0x75f0,0x75f1,0x75f2,0x75f3,0x75f4,0x75f5,0x75f6,0x75f7,
+ 0x75f8,0x75f9,0x75fa,0x75fb,0x75fc,0x75fd,0x75fe,0x75ff,
+ 0x7600,0x7601,0x7602,0x7603,0x7604,0x7605,0x7606,0x7607,
+ 0x7608,0x7609,0x760a,0x760b,0x760c,0x760d,0x760e,0x760f,
+ 0x7610,0x7611,0x7612,0x7613,0x7614,0x7615,0x7616,0x7617,
+ 0x7618,0x7619,0x761a,0x761b,0x761c,0x761d,0x761e,0x761f,
+ 0x7620,0x7621,0x7622,0x7623,0x7624,0x7625,0x7626,0x7627,
+ 0x7628,0x7629,0x762a,0x762b,0x762c,0x762d,0x762e,0x762f,
+ 0x7630,0x7631,0x7632,0x7633,0x7634,0x7635,0x7636,0x7637,
+ 0x7638,0x7639,0x763a,0x763b,0x763c,0x763d,0x763e,0x763f,
+ 0x7640,0x7641,0x7642,0x7643,0x7644,0x7645,0x7646,0x7647,
+ 0x7648,0x7649,0x764a,0x764b,0x764c,0x764d,0x764e,0x764f,
+ 0x7650,0x7651,0x7652,0x7653,0x7654,0x7655,0x7656,0x7657,
+ 0x7658,0x7659,0x765a,0x765b,0x765c,0x765d,0x765e,0x765f,
+ 0x7660,0x7661,0x7662,0x7663,0x7664,0x7665,0x7666,0x7667,
+ 0x7668,0x7669,0x766a,0x766b,0x766c,0x766d,0x766e,0x766f,
+ 0x7670,0x7671,0x7672,0x7673,0x7674,0x7675,0x7676,0x7677,
+ 0x7678,0x7679,0x767a,0x767b,0x767c,0x767d,0x767e,0x767f,
+ 0x7680,0x7681,0x7682,0x7683,0x7684,0x7685,0x7686,0x7687,
+ 0x7688,0x7689,0x768a,0x768b,0x768c,0x768d,0x768e,0x768f,
+ 0x7690,0x7691,0x7692,0x7693,0x7694,0x7695,0x7696,0x7697,
+ 0x7698,0x7699,0x769a,0x769b,0x769c,0x769d,0x769e,0x769f,
+ 0x76a0,0x76a1,0x76a2,0x76a3,0x76a4,0x76a5,0x76a6,0x76a7,
+ 0x76a8,0x76a9,0x76aa,0x76ab,0x76ac,0x76ad,0x76ae,0x76af,
+ 0x76b0,0x76b1,0x76b2,0x76b3,0x76b4,0x76b5,0x76b6,0x76b7,
+ 0x76b8,0x76b9,0x76ba,0x76bb,0x76bc,0x76bd,0x76be,0x76bf,
+ 0x76c0,0x76c1,0x76c2,0x76c3,0x76c4,0x76c5,0x76c6,0x76c7,
+ 0x76c8,0x76c9,0x76ca,0x76cb,0x76cc,0x76cd,0x76ce,0x76cf,
+ 0x76d0,0x76d1,0x76d2,0x76d3,0x76d4,0x76d5,0x76d6,0x76d7,
+ 0x76d8,0x76d9,0x76da,0x76db,0x76dc,0x76dd,0x76de,0x76df,
+ 0x76e0,0x76e1,0x76e2,0x76e3,0x76e4,0x76e5,0x76e6,0x76e7,
+ 0x76e8,0x76e9,0x76ea,0x76eb,0x76ec,0x76ed,0x76ee,0x76ef,
+ 0x76f0,0x76f1,0x76f2,0x76f3,0x76f4,0x76f5,0x76f6,0x76f7,
+ 0x76f8,0x76f9,0x76fa,0x76fb,0x76fc,0x76fd,0x76fe,0x76ff,
+ 0x7700,0x7701,0x7702,0x7703,0x7704,0x7705,0x7706,0x7707,
+ 0x7708,0x7709,0x770a,0x770b,0x770c,0x770d,0x770e,0x770f,
+ 0x7710,0x7711,0x7712,0x7713,0x7714,0x7715,0x7716,0x7717,
+ 0x7718,0x7719,0x771a,0x771b,0x771c,0x771d,0x771e,0x771f,
+ 0x7720,0x7721,0x7722,0x7723,0x7724,0x7725,0x7726,0x7727,
+ 0x7728,0x7729,0x772a,0x772b,0x772c,0x772d,0x772e,0x772f,
+ 0x7730,0x7731,0x7732,0x7733,0x7734,0x7735,0x7736,0x7737,
+ 0x7738,0x7739,0x773a,0x773b,0x773c,0x773d,0x773e,0x773f,
+ 0x7740,0x7741,0x7742,0x7743,0x7744,0x7745,0x7746,0x7747,
+ 0x7748,0x7749,0x774a,0x774b,0x774c,0x774d,0x774e,0x774f,
+ 0x7750,0x7751,0x7752,0x7753,0x7754,0x7755,0x7756,0x7757,
+ 0x7758,0x7759,0x775a,0x775b,0x775c,0x775d,0x775e,0x775f,
+ 0x7760,0x7761,0x7762,0x7763,0x7764,0x7765,0x7766,0x7767,
+ 0x7768,0x7769,0x776a,0x776b,0x776c,0x776d,0x776e,0x776f,
+ 0x7770,0x7771,0x7772,0x7773,0x7774,0x7775,0x7776,0x7777,
+ 0x7778,0x7779,0x777a,0x777b,0x777c,0x777d,0x777e,0x777f,
+ 0x7780,0x7781,0x7782,0x7783,0x7784,0x7785,0x7786,0x7787,
+ 0x7788,0x7789,0x778a,0x778b,0x778c,0x778d,0x778e,0x778f,
+ 0x7790,0x7791,0x7792,0x7793,0x7794,0x7795,0x7796,0x7797,
+ 0x7798,0x7799,0x779a,0x779b,0x779c,0x779d,0x779e,0x779f,
+ 0x77a0,0x77a1,0x77a2,0x77a3,0x77a4,0x77a5,0x77a6,0x77a7,
+ 0x77a8,0x77a9,0x77aa,0x77ab,0x77ac,0x77ad,0x77ae,0x77af,
+ 0x77b0,0x77b1,0x77b2,0x77b3,0x77b4,0x77b5,0x77b6,0x77b7,
+ 0x77b8,0x77b9,0x77ba,0x77bb,0x77bc,0x77bd,0x77be,0x77bf,
+ 0x77c0,0x77c1,0x77c2,0x77c3,0x77c4,0x77c5,0x77c6,0x77c7,
+ 0x77c8,0x77c9,0x77ca,0x77cb,0x77cc,0x77cd,0x77ce,0x77cf,
+ 0x77d0,0x77d1,0x77d2,0x77d3,0x77d4,0x77d5,0x77d6,0x77d7,
+ 0x77d8,0x77d9,0x77da,0x77db,0x77dc,0x77dd,0x77de,0x77df,
+ 0x77e0,0x77e1,0x77e2,0x77e3,0x77e4,0x77e5,0x77e6,0x77e7,
+ 0x77e8,0x77e9,0x77ea,0x77eb,0x77ec,0x77ed,0x77ee,0x77ef,
+ 0x77f0,0x77f1,0x77f2,0x77f3,0x77f4,0x77f5,0x77f6,0x77f7,
+ 0x77f8,0x77f9,0x77fa,0x77fb,0x77fc,0x77fd,0x77fe,0x77ff,
+ 0x7800,0x7801,0x7802,0x7803,0x7804,0x7805,0x7806,0x7807,
+ 0x7808,0x7809,0x780a,0x780b,0x780c,0x780d,0x780e,0x780f,
+ 0x7810,0x7811,0x7812,0x7813,0x7814,0x7815,0x7816,0x7817,
+ 0x7818,0x7819,0x781a,0x781b,0x781c,0x781d,0x781e,0x781f,
+ 0x7820,0x7821,0x7822,0x7823,0x7824,0x7825,0x7826,0x7827,
+ 0x7828,0x7829,0x782a,0x782b,0x782c,0x782d,0x782e,0x782f,
+ 0x7830,0x7831,0x7832,0x7833,0x7834,0x7835,0x7836,0x7837,
+ 0x7838,0x7839,0x783a,0x783b,0x783c,0x783d,0x783e,0x783f,
+ 0x7840,0x7841,0x7842,0x7843,0x7844,0x7845,0x7846,0x7847,
+ 0x7848,0x7849,0x784a,0x784b,0x784c,0x784d,0x784e,0x784f,
+ 0x7850,0x7851,0x7852,0x7853,0x7854,0x7855,0x7856,0x7857,
+ 0x7858,0x7859,0x785a,0x785b,0x785c,0x785d,0x785e,0x785f,
+ 0x7860,0x7861,0x7862,0x7863,0x7864,0x7865,0x7866,0x7867,
+ 0x7868,0x7869,0x786a,0x786b,0x786c,0x786d,0x786e,0x786f,
+ 0x7870,0x7871,0x7872,0x7873,0x7874,0x7875,0x7876,0x7877,
+ 0x7878,0x7879,0x787a,0x787b,0x787c,0x787d,0x787e,0x787f,
+ 0x7880,0x7881,0x7882,0x7883,0x7884,0x7885,0x7886,0x7887,
+ 0x7888,0x7889,0x788a,0x788b,0x788c,0x788d,0x788e,0x788f,
+ 0x7890,0x7891,0x7892,0x7893,0x7894,0x7895,0x7896,0x7897,
+ 0x7898,0x7899,0x789a,0x789b,0x789c,0x789d,0x789e,0x789f,
+ 0x78a0,0x78a1,0x78a2,0x78a3,0x78a4,0x78a5,0x78a6,0x78a7,
+ 0x78a8,0x78a9,0x78aa,0x78ab,0x78ac,0x78ad,0x78ae,0x78af,
+ 0x78b0,0x78b1,0x78b2,0x78b3,0x78b4,0x78b5,0x78b6,0x78b7,
+ 0x78b8,0x78b9,0x78ba,0x78bb,0x78bc,0x78bd,0x78be,0x78bf,
+ 0x78c0,0x78c1,0x78c2,0x78c3,0x78c4,0x78c5,0x78c6,0x78c7,
+ 0x78c8,0x78c9,0x78ca,0x78cb,0x78cc,0x78cd,0x78ce,0x78cf,
+ 0x78d0,0x78d1,0x78d2,0x78d3,0x78d4,0x78d5,0x78d6,0x78d7,
+ 0x78d8,0x78d9,0x78da,0x78db,0x78dc,0x78dd,0x78de,0x78df,
+ 0x78e0,0x78e1,0x78e2,0x78e3,0x78e4,0x78e5,0x78e6,0x78e7,
+ 0x78e8,0x78e9,0x78ea,0x78eb,0x78ec,0x78ed,0x78ee,0x78ef,
+ 0x78f0,0x78f1,0x78f2,0x78f3,0x78f4,0x78f5,0x78f6,0x78f7,
+ 0x78f8,0x78f9,0x78fa,0x78fb,0x78fc,0x78fd,0x78fe,0x78ff,
+ 0x7900,0x7901,0x7902,0x7903,0x7904,0x7905,0x7906,0x7907,
+ 0x7908,0x7909,0x790a,0x790b,0x790c,0x790d,0x790e,0x790f,
+ 0x7910,0x7911,0x7912,0x7913,0x7914,0x7915,0x7916,0x7917,
+ 0x7918,0x7919,0x791a,0x791b,0x791c,0x791d,0x791e,0x791f,
+ 0x7920,0x7921,0x7922,0x7923,0x7924,0x7925,0x7926,0x7927,
+ 0x7928,0x7929,0x792a,0x792b,0x792c,0x792d,0x792e,0x792f,
+ 0x7930,0x7931,0x7932,0x7933,0x7934,0x7935,0x7936,0x7937,
+ 0x7938,0x7939,0x793a,0x793b,0x793c,0x793d,0x793e,0x793f,
+ 0x7940,0x7941,0x7942,0x7943,0x7944,0x7945,0x7946,0x7947,
+ 0x7948,0x7949,0x794a,0x794b,0x794c,0x794d,0x794e,0x794f,
+ 0x7950,0x7951,0x7952,0x7953,0x7954,0x7955,0x7956,0x7957,
+ 0x7958,0x7959,0x795a,0x795b,0x795c,0x795d,0x795e,0x795f,
+ 0x7960,0x7961,0x7962,0x7963,0x7964,0x7965,0x7966,0x7967,
+ 0x7968,0x7969,0x796a,0x796b,0x796c,0x796d,0x796e,0x796f,
+ 0x7970,0x7971,0x7972,0x7973,0x7974,0x7975,0x7976,0x7977,
+ 0x7978,0x7979,0x797a,0x797b,0x797c,0x797d,0x797e,0x797f,
+ 0x7980,0x7981,0x7982,0x7983,0x7984,0x7985,0x7986,0x7987,
+ 0x7988,0x7989,0x798a,0x798b,0x798c,0x798d,0x798e,0x798f,
+ 0x7990,0x7991,0x7992,0x7993,0x7994,0x7995,0x7996,0x7997,
+ 0x7998,0x7999,0x799a,0x799b,0x799c,0x799d,0x799e,0x799f,
+ 0x79a0,0x79a1,0x79a2,0x79a3,0x79a4,0x79a5,0x79a6,0x79a7,
+ 0x79a8,0x79a9,0x79aa,0x79ab,0x79ac,0x79ad,0x79ae,0x79af,
+ 0x79b0,0x79b1,0x79b2,0x79b3,0x79b4,0x79b5,0x79b6,0x79b7,
+ 0x79b8,0x79b9,0x79ba,0x79bb,0x79bc,0x79bd,0x79be,0x79bf,
+ 0x79c0,0x79c1,0x79c2,0x79c3,0x79c4,0x79c5,0x79c6,0x79c7,
+ 0x79c8,0x79c9,0x79ca,0x79cb,0x79cc,0x79cd,0x79ce,0x79cf,
+ 0x79d0,0x79d1,0x79d2,0x79d3,0x79d4,0x79d5,0x79d6,0x79d7,
+ 0x79d8,0x79d9,0x79da,0x79db,0x79dc,0x79dd,0x79de,0x79df,
+ 0x79e0,0x79e1,0x79e2,0x79e3,0x79e4,0x79e5,0x79e6,0x79e7,
+ 0x79e8,0x79e9,0x79ea,0x79eb,0x79ec,0x79ed,0x79ee,0x79ef,
+ 0x79f0,0x79f1,0x79f2,0x79f3,0x79f4,0x79f5,0x79f6,0x79f7,
+ 0x79f8,0x79f9,0x79fa,0x79fb,0x79fc,0x79fd,0x79fe,0x79ff,
+ 0x7a00,0x7a01,0x7a02,0x7a03,0x7a04,0x7a05,0x7a06,0x7a07,
+ 0x7a08,0x7a09,0x7a0a,0x7a0b,0x7a0c,0x7a0d,0x7a0e,0x7a0f,
+ 0x7a10,0x7a11,0x7a12,0x7a13,0x7a14,0x7a15,0x7a16,0x7a17,
+ 0x7a18,0x7a19,0x7a1a,0x7a1b,0x7a1c,0x7a1d,0x7a1e,0x7a1f,
+ 0x7a20,0x7a21,0x7a22,0x7a23,0x7a24,0x7a25,0x7a26,0x7a27,
+ 0x7a28,0x7a29,0x7a2a,0x7a2b,0x7a2c,0x7a2d,0x7a2e,0x7a2f,
+ 0x7a30,0x7a31,0x7a32,0x7a33,0x7a34,0x7a35,0x7a36,0x7a37,
+ 0x7a38,0x7a39,0x7a3a,0x7a3b,0x7a3c,0x7a3d,0x7a3e,0x7a3f,
+ 0x7a40,0x7a41,0x7a42,0x7a43,0x7a44,0x7a45,0x7a46,0x7a47,
+ 0x7a48,0x7a49,0x7a4a,0x7a4b,0x7a4c,0x7a4d,0x7a4e,0x7a4f,
+ 0x7a50,0x7a51,0x7a52,0x7a53,0x7a54,0x7a55,0x7a56,0x7a57,
+ 0x7a58,0x7a59,0x7a5a,0x7a5b,0x7a5c,0x7a5d,0x7a5e,0x7a5f,
+ 0x7a60,0x7a61,0x7a62,0x7a63,0x7a64,0x7a65,0x7a66,0x7a67,
+ 0x7a68,0x7a69,0x7a6a,0x7a6b,0x7a6c,0x7a6d,0x7a6e,0x7a6f,
+ 0x7a70,0x7a71,0x7a72,0x7a73,0x7a74,0x7a75,0x7a76,0x7a77,
+ 0x7a78,0x7a79,0x7a7a,0x7a7b,0x7a7c,0x7a7d,0x7a7e,0x7a7f,
+ 0x7a80,0x7a81,0x7a82,0x7a83,0x7a84,0x7a85,0x7a86,0x7a87,
+ 0x7a88,0x7a89,0x7a8a,0x7a8b,0x7a8c,0x7a8d,0x7a8e,0x7a8f,
+ 0x7a90,0x7a91,0x7a92,0x7a93,0x7a94,0x7a95,0x7a96,0x7a97,
+ 0x7a98,0x7a99,0x7a9a,0x7a9b,0x7a9c,0x7a9d,0x7a9e,0x7a9f,
+ 0x7aa0,0x7aa1,0x7aa2,0x7aa3,0x7aa4,0x7aa5,0x7aa6,0x7aa7,
+ 0x7aa8,0x7aa9,0x7aaa,0x7aab,0x7aac,0x7aad,0x7aae,0x7aaf,
+ 0x7ab0,0x7ab1,0x7ab2,0x7ab3,0x7ab4,0x7ab5,0x7ab6,0x7ab7,
+ 0x7ab8,0x7ab9,0x7aba,0x7abb,0x7abc,0x7abd,0x7abe,0x7abf,
+ 0x7ac0,0x7ac1,0x7ac2,0x7ac3,0x7ac4,0x7ac5,0x7ac6,0x7ac7,
+ 0x7ac8,0x7ac9,0x7aca,0x7acb,0x7acc,0x7acd,0x7ace,0x7acf,
+ 0x7ad0,0x7ad1,0x7ad2,0x7ad3,0x7ad4,0x7ad5,0x7ad6,0x7ad7,
+ 0x7ad8,0x7ad9,0x7ada,0x7adb,0x7adc,0x7add,0x7ade,0x7adf,
+ 0x7ae0,0x7ae1,0x7ae2,0x7ae3,0x7ae4,0x7ae5,0x7ae6,0x7ae7,
+ 0x7ae8,0x7ae9,0x7aea,0x7aeb,0x7aec,0x7aed,0x7aee,0x7aef,
+ 0x7af0,0x7af1,0x7af2,0x7af3,0x7af4,0x7af5,0x7af6,0x7af7,
+ 0x7af8,0x7af9,0x7afa,0x7afb,0x7afc,0x7afd,0x7afe,0x7aff,
+ 0x7b00,0x7b01,0x7b02,0x7b03,0x7b04,0x7b05,0x7b06,0x7b07,
+ 0x7b08,0x7b09,0x7b0a,0x7b0b,0x7b0c,0x7b0d,0x7b0e,0x7b0f,
+ 0x7b10,0x7b11,0x7b12,0x7b13,0x7b14,0x7b15,0x7b16,0x7b17,
+ 0x7b18,0x7b19,0x7b1a,0x7b1b,0x7b1c,0x7b1d,0x7b1e,0x7b1f,
+ 0x7b20,0x7b21,0x7b22,0x7b23,0x7b24,0x7b25,0x7b26,0x7b27,
+ 0x7b28,0x7b29,0x7b2a,0x7b2b,0x7b2c,0x7b2d,0x7b2e,0x7b2f,
+ 0x7b30,0x7b31,0x7b32,0x7b33,0x7b34,0x7b35,0x7b36,0x7b37,
+ 0x7b38,0x7b39,0x7b3a,0x7b3b,0x7b3c,0x7b3d,0x7b3e,0x7b3f,
+ 0x7b40,0x7b41,0x7b42,0x7b43,0x7b44,0x7b45,0x7b46,0x7b47,
+ 0x7b48,0x7b49,0x7b4a,0x7b4b,0x7b4c,0x7b4d,0x7b4e,0x7b4f,
+ 0x7b50,0x7b51,0x7b52,0x7b53,0x7b54,0x7b55,0x7b56,0x7b57,
+ 0x7b58,0x7b59,0x7b5a,0x7b5b,0x7b5c,0x7b5d,0x7b5e,0x7b5f,
+ 0x7b60,0x7b61,0x7b62,0x7b63,0x7b64,0x7b65,0x7b66,0x7b67,
+ 0x7b68,0x7b69,0x7b6a,0x7b6b,0x7b6c,0x7b6d,0x7b6e,0x7b6f,
+ 0x7b70,0x7b71,0x7b72,0x7b73,0x7b74,0x7b75,0x7b76,0x7b77,
+ 0x7b78,0x7b79,0x7b7a,0x7b7b,0x7b7c,0x7b7d,0x7b7e,0x7b7f,
+ 0x7b80,0x7b81,0x7b82,0x7b83,0x7b84,0x7b85,0x7b86,0x7b87,
+ 0x7b88,0x7b89,0x7b8a,0x7b8b,0x7b8c,0x7b8d,0x7b8e,0x7b8f,
+ 0x7b90,0x7b91,0x7b92,0x7b93,0x7b94,0x7b95,0x7b96,0x7b97,
+ 0x7b98,0x7b99,0x7b9a,0x7b9b,0x7b9c,0x7b9d,0x7b9e,0x7b9f,
+ 0x7ba0,0x7ba1,0x7ba2,0x7ba3,0x7ba4,0x7ba5,0x7ba6,0x7ba7,
+ 0x7ba8,0x7ba9,0x7baa,0x7bab,0x7bac,0x7bad,0x7bae,0x7baf,
+ 0x7bb0,0x7bb1,0x7bb2,0x7bb3,0x7bb4,0x7bb5,0x7bb6,0x7bb7,
+ 0x7bb8,0x7bb9,0x7bba,0x7bbb,0x7bbc,0x7bbd,0x7bbe,0x7bbf,
+ 0x7bc0,0x7bc1,0x7bc2,0x7bc3,0x7bc4,0x7bc5,0x7bc6,0x7bc7,
+ 0x7bc8,0x7bc9,0x7bca,0x7bcb,0x7bcc,0x7bcd,0x7bce,0x7bcf,
+ 0x7bd0,0x7bd1,0x7bd2,0x7bd3,0x7bd4,0x7bd5,0x7bd6,0x7bd7,
+ 0x7bd8,0x7bd9,0x7bda,0x7bdb,0x7bdc,0x7bdd,0x7bde,0x7bdf,
+ 0x7be0,0x7be1,0x7be2,0x7be3,0x7be4,0x7be5,0x7be6,0x7be7,
+ 0x7be8,0x7be9,0x7bea,0x7beb,0x7bec,0x7bed,0x7bee,0x7bef,
+ 0x7bf0,0x7bf1,0x7bf2,0x7bf3,0x7bf4,0x7bf5,0x7bf6,0x7bf7,
+ 0x7bf8,0x7bf9,0x7bfa,0x7bfb,0x7bfc,0x7bfd,0x7bfe,0x7bff,
+ 0x7c00,0x7c01,0x7c02,0x7c03,0x7c04,0x7c05,0x7c06,0x7c07,
+ 0x7c08,0x7c09,0x7c0a,0x7c0b,0x7c0c,0x7c0d,0x7c0e,0x7c0f,
+ 0x7c10,0x7c11,0x7c12,0x7c13,0x7c14,0x7c15,0x7c16,0x7c17,
+ 0x7c18,0x7c19,0x7c1a,0x7c1b,0x7c1c,0x7c1d,0x7c1e,0x7c1f,
+ 0x7c20,0x7c21,0x7c22,0x7c23,0x7c24,0x7c25,0x7c26,0x7c27,
+ 0x7c28,0x7c29,0x7c2a,0x7c2b,0x7c2c,0x7c2d,0x7c2e,0x7c2f,
+ 0x7c30,0x7c31,0x7c32,0x7c33,0x7c34,0x7c35,0x7c36,0x7c37,
+ 0x7c38,0x7c39,0x7c3a,0x7c3b,0x7c3c,0x7c3d,0x7c3e,0x7c3f,
+ 0x7c40,0x7c41,0x7c42,0x7c43,0x7c44,0x7c45,0x7c46,0x7c47,
+ 0x7c48,0x7c49,0x7c4a,0x7c4b,0x7c4c,0x7c4d,0x7c4e,0x7c4f,
+ 0x7c50,0x7c51,0x7c52,0x7c53,0x7c54,0x7c55,0x7c56,0x7c57,
+ 0x7c58,0x7c59,0x7c5a,0x7c5b,0x7c5c,0x7c5d,0x7c5e,0x7c5f,
+ 0x7c60,0x7c61,0x7c62,0x7c63,0x7c64,0x7c65,0x7c66,0x7c67,
+ 0x7c68,0x7c69,0x7c6a,0x7c6b,0x7c6c,0x7c6d,0x7c6e,0x7c6f,
+ 0x7c70,0x7c71,0x7c72,0x7c73,0x7c74,0x7c75,0x7c76,0x7c77,
+ 0x7c78,0x7c79,0x7c7a,0x7c7b,0x7c7c,0x7c7d,0x7c7e,0x7c7f,
+ 0x7c80,0x7c81,0x7c82,0x7c83,0x7c84,0x7c85,0x7c86,0x7c87,
+ 0x7c88,0x7c89,0x7c8a,0x7c8b,0x7c8c,0x7c8d,0x7c8e,0x7c8f,
+ 0x7c90,0x7c91,0x7c92,0x7c93,0x7c94,0x7c95,0x7c96,0x7c97,
+ 0x7c98,0x7c99,0x7c9a,0x7c9b,0x7c9c,0x7c9d,0x7c9e,0x7c9f,
+ 0x7ca0,0x7ca1,0x7ca2,0x7ca3,0x7ca4,0x7ca5,0x7ca6,0x7ca7,
+ 0x7ca8,0x7ca9,0x7caa,0x7cab,0x7cac,0x7cad,0x7cae,0x7caf,
+ 0x7cb0,0x7cb1,0x7cb2,0x7cb3,0x7cb4,0x7cb5,0x7cb6,0x7cb7,
+ 0x7cb8,0x7cb9,0x7cba,0x7cbb,0x7cbc,0x7cbd,0x7cbe,0x7cbf,
+ 0x7cc0,0x7cc1,0x7cc2,0x7cc3,0x7cc4,0x7cc5,0x7cc6,0x7cc7,
+ 0x7cc8,0x7cc9,0x7cca,0x7ccb,0x7ccc,0x7ccd,0x7cce,0x7ccf,
+ 0x7cd0,0x7cd1,0x7cd2,0x7cd3,0x7cd4,0x7cd5,0x7cd6,0x7cd7,
+ 0x7cd8,0x7cd9,0x7cda,0x7cdb,0x7cdc,0x7cdd,0x7cde,0x7cdf,
+ 0x7ce0,0x7ce1,0x7ce2,0x7ce3,0x7ce4,0x7ce5,0x7ce6,0x7ce7,
+ 0x7ce8,0x7ce9,0x7cea,0x7ceb,0x7cec,0x7ced,0x7cee,0x7cef,
+ 0x7cf0,0x7cf1,0x7cf2,0x7cf3,0x7cf4,0x7cf5,0x7cf6,0x7cf7,
+ 0x7cf8,0x7cf9,0x7cfa,0x7cfb,0x7cfc,0x7cfd,0x7cfe,0x7cff,
+ 0x7d00,0x7d01,0x7d02,0x7d03,0x7d04,0x7d05,0x7d06,0x7d07,
+ 0x7d08,0x7d09,0x7d0a,0x7d0b,0x7d0c,0x7d0d,0x7d0e,0x7d0f,
+ 0x7d10,0x7d11,0x7d12,0x7d13,0x7d14,0x7d15,0x7d16,0x7d17,
+ 0x7d18,0x7d19,0x7d1a,0x7d1b,0x7d1c,0x7d1d,0x7d1e,0x7d1f,
+ 0x7d20,0x7d21,0x7d22,0x7d23,0x7d24,0x7d25,0x7d26,0x7d27,
+ 0x7d28,0x7d29,0x7d2a,0x7d2b,0x7d2c,0x7d2d,0x7d2e,0x7d2f,
+ 0x7d30,0x7d31,0x7d32,0x7d33,0x7d34,0x7d35,0x7d36,0x7d37,
+ 0x7d38,0x7d39,0x7d3a,0x7d3b,0x7d3c,0x7d3d,0x7d3e,0x7d3f,
+ 0x7d40,0x7d41,0x7d42,0x7d43,0x7d44,0x7d45,0x7d46,0x7d47,
+ 0x7d48,0x7d49,0x7d4a,0x7d4b,0x7d4c,0x7d4d,0x7d4e,0x7d4f,
+ 0x7d50,0x7d51,0x7d52,0x7d53,0x7d54,0x7d55,0x7d56,0x7d57,
+ 0x7d58,0x7d59,0x7d5a,0x7d5b,0x7d5c,0x7d5d,0x7d5e,0x7d5f,
+ 0x7d60,0x7d61,0x7d62,0x7d63,0x7d64,0x7d65,0x7d66,0x7d67,
+ 0x7d68,0x7d69,0x7d6a,0x7d6b,0x7d6c,0x7d6d,0x7d6e,0x7d6f,
+ 0x7d70,0x7d71,0x7d72,0x7d73,0x7d74,0x7d75,0x7d76,0x7d77,
+ 0x7d78,0x7d79,0x7d7a,0x7d7b,0x7d7c,0x7d7d,0x7d7e,0x7d7f,
+ 0x7d80,0x7d81,0x7d82,0x7d83,0x7d84,0x7d85,0x7d86,0x7d87,
+ 0x7d88,0x7d89,0x7d8a,0x7d8b,0x7d8c,0x7d8d,0x7d8e,0x7d8f,
+ 0x7d90,0x7d91,0x7d92,0x7d93,0x7d94,0x7d95,0x7d96,0x7d97,
+ 0x7d98,0x7d99,0x7d9a,0x7d9b,0x7d9c,0x7d9d,0x7d9e,0x7d9f,
+ 0x7da0,0x7da1,0x7da2,0x7da3,0x7da4,0x7da5,0x7da6,0x7da7,
+ 0x7da8,0x7da9,0x7daa,0x7dab,0x7dac,0x7dad,0x7dae,0x7daf,
+ 0x7db0,0x7db1,0x7db2,0x7db3,0x7db4,0x7db5,0x7db6,0x7db7,
+ 0x7db8,0x7db9,0x7dba,0x7dbb,0x7dbc,0x7dbd,0x7dbe,0x7dbf,
+ 0x7dc0,0x7dc1,0x7dc2,0x7dc3,0x7dc4,0x7dc5,0x7dc6,0x7dc7,
+ 0x7dc8,0x7dc9,0x7dca,0x7dcb,0x7dcc,0x7dcd,0x7dce,0x7dcf,
+ 0x7dd0,0x7dd1,0x7dd2,0x7dd3,0x7dd4,0x7dd5,0x7dd6,0x7dd7,
+ 0x7dd8,0x7dd9,0x7dda,0x7ddb,0x7ddc,0x7ddd,0x7dde,0x7ddf,
+ 0x7de0,0x7de1,0x7de2,0x7de3,0x7de4,0x7de5,0x7de6,0x7de7,
+ 0x7de8,0x7de9,0x7dea,0x7deb,0x7dec,0x7ded,0x7dee,0x7def,
+ 0x7df0,0x7df1,0x7df2,0x7df3,0x7df4,0x7df5,0x7df6,0x7df7,
+ 0x7df8,0x7df9,0x7dfa,0x7dfb,0x7dfc,0x7dfd,0x7dfe,0x7dff,
+ 0x7e00,0x7e01,0x7e02,0x7e03,0x7e04,0x7e05,0x7e06,0x7e07,
+ 0x7e08,0x7e09,0x7e0a,0x7e0b,0x7e0c,0x7e0d,0x7e0e,0x7e0f,
+ 0x7e10,0x7e11,0x7e12,0x7e13,0x7e14,0x7e15,0x7e16,0x7e17,
+ 0x7e18,0x7e19,0x7e1a,0x7e1b,0x7e1c,0x7e1d,0x7e1e,0x7e1f,
+ 0x7e20,0x7e21,0x7e22,0x7e23,0x7e24,0x7e25,0x7e26,0x7e27,
+ 0x7e28,0x7e29,0x7e2a,0x7e2b,0x7e2c,0x7e2d,0x7e2e,0x7e2f,
+ 0x7e30,0x7e31,0x7e32,0x7e33,0x7e34,0x7e35,0x7e36,0x7e37,
+ 0x7e38,0x7e39,0x7e3a,0x7e3b,0x7e3c,0x7e3d,0x7e3e,0x7e3f,
+ 0x7e40,0x7e41,0x7e42,0x7e43,0x7e44,0x7e45,0x7e46,0x7e47,
+ 0x7e48,0x7e49,0x7e4a,0x7e4b,0x7e4c,0x7e4d,0x7e4e,0x7e4f,
+ 0x7e50,0x7e51,0x7e52,0x7e53,0x7e54,0x7e55,0x7e56,0x7e57,
+ 0x7e58,0x7e59,0x7e5a,0x7e5b,0x7e5c,0x7e5d,0x7e5e,0x7e5f,
+ 0x7e60,0x7e61,0x7e62,0x7e63,0x7e64,0x7e65,0x7e66,0x7e67,
+ 0x7e68,0x7e69,0x7e6a,0x7e6b,0x7e6c,0x7e6d,0x7e6e,0x7e6f,
+ 0x7e70,0x7e71,0x7e72,0x7e73,0x7e74,0x7e75,0x7e76,0x7e77,
+ 0x7e78,0x7e79,0x7e7a,0x7e7b,0x7e7c,0x7e7d,0x7e7e,0x7e7f,
+ 0x7e80,0x7e81,0x7e82,0x7e83,0x7e84,0x7e85,0x7e86,0x7e87,
+ 0x7e88,0x7e89,0x7e8a,0x7e8b,0x7e8c,0x7e8d,0x7e8e,0x7e8f,
+ 0x7e90,0x7e91,0x7e92,0x7e93,0x7e94,0x7e95,0x7e96,0x7e97,
+ 0x7e98,0x7e99,0x7e9a,0x7e9b,0x7e9c,0x7e9d,0x7e9e,0x7e9f,
+ 0x7ea0,0x7ea1,0x7ea2,0x7ea3,0x7ea4,0x7ea5,0x7ea6,0x7ea7,
+ 0x7ea8,0x7ea9,0x7eaa,0x7eab,0x7eac,0x7ead,0x7eae,0x7eaf,
+ 0x7eb0,0x7eb1,0x7eb2,0x7eb3,0x7eb4,0x7eb5,0x7eb6,0x7eb7,
+ 0x7eb8,0x7eb9,0x7eba,0x7ebb,0x7ebc,0x7ebd,0x7ebe,0x7ebf,
+ 0x7ec0,0x7ec1,0x7ec2,0x7ec3,0x7ec4,0x7ec5,0x7ec6,0x7ec7,
+ 0x7ec8,0x7ec9,0x7eca,0x7ecb,0x7ecc,0x7ecd,0x7ece,0x7ecf,
+ 0x7ed0,0x7ed1,0x7ed2,0x7ed3,0x7ed4,0x7ed5,0x7ed6,0x7ed7,
+ 0x7ed8,0x7ed9,0x7eda,0x7edb,0x7edc,0x7edd,0x7ede,0x7edf,
+ 0x7ee0,0x7ee1,0x7ee2,0x7ee3,0x7ee4,0x7ee5,0x7ee6,0x7ee7,
+ 0x7ee8,0x7ee9,0x7eea,0x7eeb,0x7eec,0x7eed,0x7eee,0x7eef,
+ 0x7ef0,0x7ef1,0x7ef2,0x7ef3,0x7ef4,0x7ef5,0x7ef6,0x7ef7,
+ 0x7ef8,0x7ef9,0x7efa,0x7efb,0x7efc,0x7efd,0x7efe,0x7eff,
+ 0x7f00,0x7f01,0x7f02,0x7f03,0x7f04,0x7f05,0x7f06,0x7f07,
+ 0x7f08,0x7f09,0x7f0a,0x7f0b,0x7f0c,0x7f0d,0x7f0e,0x7f0f,
+ 0x7f10,0x7f11,0x7f12,0x7f13,0x7f14,0x7f15,0x7f16,0x7f17,
+ 0x7f18,0x7f19,0x7f1a,0x7f1b,0x7f1c,0x7f1d,0x7f1e,0x7f1f,
+ 0x7f20,0x7f21,0x7f22,0x7f23,0x7f24,0x7f25,0x7f26,0x7f27,
+ 0x7f28,0x7f29,0x7f2a,0x7f2b,0x7f2c,0x7f2d,0x7f2e,0x7f2f,
+ 0x7f30,0x7f31,0x7f32,0x7f33,0x7f34,0x7f35,0x7f36,0x7f37,
+ 0x7f38,0x7f39,0x7f3a,0x7f3b,0x7f3c,0x7f3d,0x7f3e,0x7f3f,
+ 0x7f40,0x7f41,0x7f42,0x7f43,0x7f44,0x7f45,0x7f46,0x7f47,
+ 0x7f48,0x7f49,0x7f4a,0x7f4b,0x7f4c,0x7f4d,0x7f4e,0x7f4f,
+ 0x7f50,0x7f51,0x7f52,0x7f53,0x7f54,0x7f55,0x7f56,0x7f57,
+ 0x7f58,0x7f59,0x7f5a,0x7f5b,0x7f5c,0x7f5d,0x7f5e,0x7f5f,
+ 0x7f60,0x7f61,0x7f62,0x7f63,0x7f64,0x7f65,0x7f66,0x7f67,
+ 0x7f68,0x7f69,0x7f6a,0x7f6b,0x7f6c,0x7f6d,0x7f6e,0x7f6f,
+ 0x7f70,0x7f71,0x7f72,0x7f73,0x7f74,0x7f75,0x7f76,0x7f77,
+ 0x7f78,0x7f79,0x7f7a,0x7f7b,0x7f7c,0x7f7d,0x7f7e,0x7f7f,
+ 0x7f80,0x7f81,0x7f82,0x7f83,0x7f84,0x7f85,0x7f86,0x7f87,
+ 0x7f88,0x7f89,0x7f8a,0x7f8b,0x7f8c,0x7f8d,0x7f8e,0x7f8f,
+ 0x7f90,0x7f91,0x7f92,0x7f93,0x7f94,0x7f95,0x7f96,0x7f97,
+ 0x7f98,0x7f99,0x7f9a,0x7f9b,0x7f9c,0x7f9d,0x7f9e,0x7f9f,
+ 0x7fa0,0x7fa1,0x7fa2,0x7fa3,0x7fa4,0x7fa5,0x7fa6,0x7fa7,
+ 0x7fa8,0x7fa9,0x7faa,0x7fab,0x7fac,0x7fad,0x7fae,0x7faf,
+ 0x7fb0,0x7fb1,0x7fb2,0x7fb3,0x7fb4,0x7fb5,0x7fb6,0x7fb7,
+ 0x7fb8,0x7fb9,0x7fba,0x7fbb,0x7fbc,0x7fbd,0x7fbe,0x7fbf,
+ 0x7fc0,0x7fc1,0x7fc2,0x7fc3,0x7fc4,0x7fc5,0x7fc6,0x7fc7,
+ 0x7fc8,0x7fc9,0x7fca,0x7fcb,0x7fcc,0x7fcd,0x7fce,0x7fcf,
+ 0x7fd0,0x7fd1,0x7fd2,0x7fd3,0x7fd4,0x7fd5,0x7fd6,0x7fd7,
+ 0x7fd8,0x7fd9,0x7fda,0x7fdb,0x7fdc,0x7fdd,0x7fde,0x7fdf,
+ 0x7fe0,0x7fe1,0x7fe2,0x7fe3,0x7fe4,0x7fe5,0x7fe6,0x7fe7,
+ 0x7fe8,0x7fe9,0x7fea,0x7feb,0x7fec,0x7fed,0x7fee,0x7fef,
+ 0x7ff0,0x7ff1,0x7ff2,0x7ff3,0x7ff4,0x7ff5,0x7ff6,0x7ff7,
+ 0x7ff8,0x7ff9,0x7ffa,0x7ffb,0x7ffc,0x7ffd,0x7ffe,0x7fff,
+ 0x8000,0x8001,0x8002,0x8003,0x8004,0x8005,0x8006,0x8007,
+ 0x8008,0x8009,0x800a,0x800b,0x800c,0x800d,0x800e,0x800f,
+ 0x8010,0x8011,0x8012,0x8013,0x8014,0x8015,0x8016,0x8017,
+ 0x8018,0x8019,0x801a,0x801b,0x801c,0x801d,0x801e,0x801f,
+ 0x8020,0x8021,0x8022,0x8023,0x8024,0x8025,0x8026,0x8027,
+ 0x8028,0x8029,0x802a,0x802b,0x802c,0x802d,0x802e,0x802f,
+ 0x8030,0x8031,0x8032,0x8033,0x8034,0x8035,0x8036,0x8037,
+ 0x8038,0x8039,0x803a,0x803b,0x803c,0x803d,0x803e,0x803f,
+ 0x8040,0x8041,0x8042,0x8043,0x8044,0x8045,0x8046,0x8047,
+ 0x8048,0x8049,0x804a,0x804b,0x804c,0x804d,0x804e,0x804f,
+ 0x8050,0x8051,0x8052,0x8053,0x8054,0x8055,0x8056,0x8057,
+ 0x8058,0x8059,0x805a,0x805b,0x805c,0x805d,0x805e,0x805f,
+ 0x8060,0x8061,0x8062,0x8063,0x8064,0x8065,0x8066,0x8067,
+ 0x8068,0x8069,0x806a,0x806b,0x806c,0x806d,0x806e,0x806f,
+ 0x8070,0x8071,0x8072,0x8073,0x8074,0x8075,0x8076,0x8077,
+ 0x8078,0x8079,0x807a,0x807b,0x807c,0x807d,0x807e,0x807f,
+ 0x8080,0x8081,0x8082,0x8083,0x8084,0x8085,0x8086,0x8087,
+ 0x8088,0x8089,0x808a,0x808b,0x808c,0x808d,0x808e,0x808f,
+ 0x8090,0x8091,0x8092,0x8093,0x8094,0x8095,0x8096,0x8097,
+ 0x8098,0x8099,0x809a,0x809b,0x809c,0x809d,0x809e,0x809f,
+ 0x80a0,0x80a1,0x80a2,0x80a3,0x80a4,0x80a5,0x80a6,0x80a7,
+ 0x80a8,0x80a9,0x80aa,0x80ab,0x80ac,0x80ad,0x80ae,0x80af,
+ 0x80b0,0x80b1,0x80b2,0x80b3,0x80b4,0x80b5,0x80b6,0x80b7,
+ 0x80b8,0x80b9,0x80ba,0x80bb,0x80bc,0x80bd,0x80be,0x80bf,
+ 0x80c0,0x80c1,0x80c2,0x80c3,0x80c4,0x80c5,0x80c6,0x80c7,
+ 0x80c8,0x80c9,0x80ca,0x80cb,0x80cc,0x80cd,0x80ce,0x80cf,
+ 0x80d0,0x80d1,0x80d2,0x80d3,0x80d4,0x80d5,0x80d6,0x80d7,
+ 0x80d8,0x80d9,0x80da,0x80db,0x80dc,0x80dd,0x80de,0x80df,
+ 0x80e0,0x80e1,0x80e2,0x80e3,0x80e4,0x80e5,0x80e6,0x80e7,
+ 0x80e8,0x80e9,0x80ea,0x80eb,0x80ec,0x80ed,0x80ee,0x80ef,
+ 0x80f0,0x80f1,0x80f2,0x80f3,0x80f4,0x80f5,0x80f6,0x80f7,
+ 0x80f8,0x80f9,0x80fa,0x80fb,0x80fc,0x80fd,0x80fe,0x80ff,
+ 0x8100,0x8101,0x8102,0x8103,0x8104,0x8105,0x8106,0x8107,
+ 0x8108,0x8109,0x810a,0x810b,0x810c,0x810d,0x810e,0x810f,
+ 0x8110,0x8111,0x8112,0x8113,0x8114,0x8115,0x8116,0x8117,
+ 0x8118,0x8119,0x811a,0x811b,0x811c,0x811d,0x811e,0x811f,
+ 0x8120,0x8121,0x8122,0x8123,0x8124,0x8125,0x8126,0x8127,
+ 0x8128,0x8129,0x812a,0x812b,0x812c,0x812d,0x812e,0x812f,
+ 0x8130,0x8131,0x8132,0x8133,0x8134,0x8135,0x8136,0x8137,
+ 0x8138,0x8139,0x813a,0x813b,0x813c,0x813d,0x813e,0x813f,
+ 0x8140,0x8141,0x8142,0x8143,0x8144,0x8145,0x8146,0x8147,
+ 0x8148,0x8149,0x814a,0x814b,0x814c,0x814d,0x814e,0x814f,
+ 0x8150,0x8151,0x8152,0x8153,0x8154,0x8155,0x8156,0x8157,
+ 0x8158,0x8159,0x815a,0x815b,0x815c,0x815d,0x815e,0x815f,
+ 0x8160,0x8161,0x8162,0x8163,0x8164,0x8165,0x8166,0x8167,
+ 0x8168,0x8169,0x816a,0x816b,0x816c,0x816d,0x816e,0x816f,
+ 0x8170,0x8171,0x8172,0x8173,0x8174,0x8175,0x8176,0x8177,
+ 0x8178,0x8179,0x817a,0x817b,0x817c,0x817d,0x817e,0x817f,
+ 0x8180,0x8181,0x8182,0x8183,0x8184,0x8185,0x8186,0x8187,
+ 0x8188,0x8189,0x818a,0x818b,0x818c,0x818d,0x818e,0x818f,
+ 0x8190,0x8191,0x8192,0x8193,0x8194,0x8195,0x8196,0x8197,
+ 0x8198,0x8199,0x819a,0x819b,0x819c,0x819d,0x819e,0x819f,
+ 0x81a0,0x81a1,0x81a2,0x81a3,0x81a4,0x81a5,0x81a6,0x81a7,
+ 0x81a8,0x81a9,0x81aa,0x81ab,0x81ac,0x81ad,0x81ae,0x81af,
+ 0x81b0,0x81b1,0x81b2,0x81b3,0x81b4,0x81b5,0x81b6,0x81b7,
+ 0x81b8,0x81b9,0x81ba,0x81bb,0x81bc,0x81bd,0x81be,0x81bf,
+ 0x81c0,0x81c1,0x81c2,0x81c3,0x81c4,0x81c5,0x81c6,0x81c7,
+ 0x81c8,0x81c9,0x81ca,0x81cb,0x81cc,0x81cd,0x81ce,0x81cf,
+ 0x81d0,0x81d1,0x81d2,0x81d3,0x81d4,0x81d5,0x81d6,0x81d7,
+ 0x81d8,0x81d9,0x81da,0x81db,0x81dc,0x81dd,0x81de,0x81df,
+ 0x81e0,0x81e1,0x81e2,0x81e3,0x81e4,0x81e5,0x81e6,0x81e7,
+ 0x81e8,0x81e9,0x81ea,0x81eb,0x81ec,0x81ed,0x81ee,0x81ef,
+ 0x81f0,0x81f1,0x81f2,0x81f3,0x81f4,0x81f5,0x81f6,0x81f7,
+ 0x81f8,0x81f9,0x81fa,0x81fb,0x81fc,0x81fd,0x81fe,0x81ff,
+ 0x8200,0x8201,0x8202,0x8203,0x8204,0x8205,0x8206,0x8207,
+ 0x8208,0x8209,0x820a,0x820b,0x820c,0x820d,0x820e,0x820f,
+ 0x8210,0x8211,0x8212,0x8213,0x8214,0x8215,0x8216,0x8217,
+ 0x8218,0x8219,0x821a,0x821b,0x821c,0x821d,0x821e,0x821f,
+ 0x8220,0x8221,0x8222,0x8223,0x8224,0x8225,0x8226,0x8227,
+ 0x8228,0x8229,0x822a,0x822b,0x822c,0x822d,0x822e,0x822f,
+ 0x8230,0x8231,0x8232,0x8233,0x8234,0x8235,0x8236,0x8237,
+ 0x8238,0x8239,0x823a,0x823b,0x823c,0x823d,0x823e,0x823f,
+ 0x8240,0x8241,0x8242,0x8243,0x8244,0x8245,0x8246,0x8247,
+ 0x8248,0x8249,0x824a,0x824b,0x824c,0x824d,0x824e,0x824f,
+ 0x8250,0x8251,0x8252,0x8253,0x8254,0x8255,0x8256,0x8257,
+ 0x8258,0x8259,0x825a,0x825b,0x825c,0x825d,0x825e,0x825f,
+ 0x8260,0x8261,0x8262,0x8263,0x8264,0x8265,0x8266,0x8267,
+ 0x8268,0x8269,0x826a,0x826b,0x826c,0x826d,0x826e,0x826f,
+ 0x8270,0x8271,0x8272,0x8273,0x8274,0x8275,0x8276,0x8277,
+ 0x8278,0x8279,0x827a,0x827b,0x827c,0x827d,0x827e,0x827f,
+ 0x8280,0x8281,0x8282,0x8283,0x8284,0x8285,0x8286,0x8287,
+ 0x8288,0x8289,0x828a,0x828b,0x828c,0x828d,0x828e,0x828f,
+ 0x8290,0x8291,0x8292,0x8293,0x8294,0x8295,0x8296,0x8297,
+ 0x8298,0x8299,0x829a,0x829b,0x829c,0x829d,0x829e,0x829f,
+ 0x82a0,0x82a1,0x82a2,0x82a3,0x82a4,0x82a5,0x82a6,0x82a7,
+ 0x82a8,0x82a9,0x82aa,0x82ab,0x82ac,0x82ad,0x82ae,0x82af,
+ 0x82b0,0x82b1,0x82b2,0x82b3,0x82b4,0x82b5,0x82b6,0x82b7,
+ 0x82b8,0x82b9,0x82ba,0x82bb,0x82bc,0x82bd,0x82be,0x82bf,
+ 0x82c0,0x82c1,0x82c2,0x82c3,0x82c4,0x82c5,0x82c6,0x82c7,
+ 0x82c8,0x82c9,0x82ca,0x82cb,0x82cc,0x82cd,0x82ce,0x82cf,
+ 0x82d0,0x82d1,0x82d2,0x82d3,0x82d4,0x82d5,0x82d6,0x82d7,
+ 0x82d8,0x82d9,0x82da,0x82db,0x82dc,0x82dd,0x82de,0x82df,
+ 0x82e0,0x82e1,0x82e2,0x82e3,0x82e4,0x82e5,0x82e6,0x82e7,
+ 0x82e8,0x82e9,0x82ea,0x82eb,0x82ec,0x82ed,0x82ee,0x82ef,
+ 0x82f0,0x82f1,0x82f2,0x82f3,0x82f4,0x82f5,0x82f6,0x82f7,
+ 0x82f8,0x82f9,0x82fa,0x82fb,0x82fc,0x82fd,0x82fe,0x82ff,
+ 0x8300,0x8301,0x8302,0x8303,0x8304,0x8305,0x8306,0x8307,
+ 0x8308,0x8309,0x830a,0x830b,0x830c,0x830d,0x830e,0x830f,
+ 0x8310,0x8311,0x8312,0x8313,0x8314,0x8315,0x8316,0x8317,
+ 0x8318,0x8319,0x831a,0x831b,0x831c,0x831d,0x831e,0x831f,
+ 0x8320,0x8321,0x8322,0x8323,0x8324,0x8325,0x8326,0x8327,
+ 0x8328,0x8329,0x832a,0x832b,0x832c,0x832d,0x832e,0x832f,
+ 0x8330,0x8331,0x8332,0x8333,0x8334,0x8335,0x8336,0x8337,
+ 0x8338,0x8339,0x833a,0x833b,0x833c,0x833d,0x833e,0x833f,
+ 0x8340,0x8341,0x8342,0x8343,0x8344,0x8345,0x8346,0x8347,
+ 0x8348,0x8349,0x834a,0x834b,0x834c,0x834d,0x834e,0x834f,
+ 0x8350,0x8351,0x8352,0x8353,0x8354,0x8355,0x8356,0x8357,
+ 0x8358,0x8359,0x835a,0x835b,0x835c,0x835d,0x835e,0x835f,
+ 0x8360,0x8361,0x8362,0x8363,0x8364,0x8365,0x8366,0x8367,
+ 0x8368,0x8369,0x836a,0x836b,0x836c,0x836d,0x836e,0x836f,
+ 0x8370,0x8371,0x8372,0x8373,0x8374,0x8375,0x8376,0x8377,
+ 0x8378,0x8379,0x837a,0x837b,0x837c,0x837d,0x837e,0x837f,
+ 0x8380,0x8381,0x8382,0x8383,0x8384,0x8385,0x8386,0x8387,
+ 0x8388,0x8389,0x838a,0x838b,0x838c,0x838d,0x838e,0x838f,
+ 0x8390,0x8391,0x8392,0x8393,0x8394,0x8395,0x8396,0x8397,
+ 0x8398,0x8399,0x839a,0x839b,0x839c,0x839d,0x839e,0x839f,
+ 0x83a0,0x83a1,0x83a2,0x83a3,0x83a4,0x83a5,0x83a6,0x83a7,
+ 0x83a8,0x83a9,0x83aa,0x83ab,0x83ac,0x83ad,0x83ae,0x83af,
+ 0x83b0,0x83b1,0x83b2,0x83b3,0x83b4,0x83b5,0x83b6,0x83b7,
+ 0x83b8,0x83b9,0x83ba,0x83bb,0x83bc,0x83bd,0x83be,0x83bf,
+ 0x83c0,0x83c1,0x83c2,0x83c3,0x83c4,0x83c5,0x83c6,0x83c7,
+ 0x83c8,0x83c9,0x83ca,0x83cb,0x83cc,0x83cd,0x83ce,0x83cf,
+ 0x83d0,0x83d1,0x83d2,0x83d3,0x83d4,0x83d5,0x83d6,0x83d7,
+ 0x83d8,0x83d9,0x83da,0x83db,0x83dc,0x83dd,0x83de,0x83df,
+ 0x83e0,0x83e1,0x83e2,0x83e3,0x83e4,0x83e5,0x83e6,0x83e7,
+ 0x83e8,0x83e9,0x83ea,0x83eb,0x83ec,0x83ed,0x83ee,0x83ef,
+ 0x83f0,0x83f1,0x83f2,0x83f3,0x83f4,0x83f5,0x83f6,0x83f7,
+ 0x83f8,0x83f9,0x83fa,0x83fb,0x83fc,0x83fd,0x83fe,0x83ff,
+ 0x8400,0x8401,0x8402,0x8403,0x8404,0x8405,0x8406,0x8407,
+ 0x8408,0x8409,0x840a,0x840b,0x840c,0x840d,0x840e,0x840f,
+ 0x8410,0x8411,0x8412,0x8413,0x8414,0x8415,0x8416,0x8417,
+ 0x8418,0x8419,0x841a,0x841b,0x841c,0x841d,0x841e,0x841f,
+ 0x8420,0x8421,0x8422,0x8423,0x8424,0x8425,0x8426,0x8427,
+ 0x8428,0x8429,0x842a,0x842b,0x842c,0x842d,0x842e,0x842f,
+ 0x8430,0x8431,0x8432,0x8433,0x8434,0x8435,0x8436,0x8437,
+ 0x8438,0x8439,0x843a,0x843b,0x843c,0x843d,0x843e,0x843f,
+ 0x8440,0x8441,0x8442,0x8443,0x8444,0x8445,0x8446,0x8447,
+ 0x8448,0x8449,0x844a,0x844b,0x844c,0x844d,0x844e,0x844f,
+ 0x8450,0x8451,0x8452,0x8453,0x8454,0x8455,0x8456,0x8457,
+ 0x8458,0x8459,0x845a,0x845b,0x845c,0x845d,0x845e,0x845f,
+ 0x8460,0x8461,0x8462,0x8463,0x8464,0x8465,0x8466,0x8467,
+ 0x8468,0x8469,0x846a,0x846b,0x846c,0x846d,0x846e,0x846f,
+ 0x8470,0x8471,0x8472,0x8473,0x8474,0x8475,0x8476,0x8477,
+ 0x8478,0x8479,0x847a,0x847b,0x847c,0x847d,0x847e,0x847f,
+ 0x8480,0x8481,0x8482,0x8483,0x8484,0x8485,0x8486,0x8487,
+ 0x8488,0x8489,0x848a,0x848b,0x848c,0x848d,0x848e,0x848f,
+ 0x8490,0x8491,0x8492,0x8493,0x8494,0x8495,0x8496,0x8497,
+ 0x8498,0x8499,0x849a,0x849b,0x849c,0x849d,0x849e,0x849f,
+ 0x84a0,0x84a1,0x84a2,0x84a3,0x84a4,0x84a5,0x84a6,0x84a7,
+ 0x84a8,0x84a9,0x84aa,0x84ab,0x84ac,0x84ad,0x84ae,0x84af,
+ 0x84b0,0x84b1,0x84b2,0x84b3,0x84b4,0x84b5,0x84b6,0x84b7,
+ 0x84b8,0x84b9,0x84ba,0x84bb,0x84bc,0x84bd,0x84be,0x84bf,
+ 0x84c0,0x84c1,0x84c2,0x84c3,0x84c4,0x84c5,0x84c6,0x84c7,
+ 0x84c8,0x84c9,0x84ca,0x84cb,0x84cc,0x84cd,0x84ce,0x84cf,
+ 0x84d0,0x84d1,0x84d2,0x84d3,0x84d4,0x84d5,0x84d6,0x84d7,
+ 0x84d8,0x84d9,0x84da,0x84db,0x84dc,0x84dd,0x84de,0x84df,
+ 0x84e0,0x84e1,0x84e2,0x84e3,0x84e4,0x84e5,0x84e6,0x84e7,
+ 0x84e8,0x84e9,0x84ea,0x84eb,0x84ec,0x84ed,0x84ee,0x84ef,
+ 0x84f0,0x84f1,0x84f2,0x84f3,0x84f4,0x84f5,0x84f6,0x84f7,
+ 0x84f8,0x84f9,0x84fa,0x84fb,0x84fc,0x84fd,0x84fe,0x84ff,
+ 0x8500,0x8501,0x8502,0x8503,0x8504,0x8505,0x8506,0x8507,
+ 0x8508,0x8509,0x850a,0x850b,0x850c,0x850d,0x850e,0x850f,
+ 0x8510,0x8511,0x8512,0x8513,0x8514,0x8515,0x8516,0x8517,
+ 0x8518,0x8519,0x851a,0x851b,0x851c,0x851d,0x851e,0x851f,
+ 0x8520,0x8521,0x8522,0x8523,0x8524,0x8525,0x8526,0x8527,
+ 0x8528,0x8529,0x852a,0x852b,0x852c,0x852d,0x852e,0x852f,
+ 0x8530,0x8531,0x8532,0x8533,0x8534,0x8535,0x8536,0x8537,
+ 0x8538,0x8539,0x853a,0x853b,0x853c,0x853d,0x853e,0x853f,
+ 0x8540,0x8541,0x8542,0x8543,0x8544,0x8545,0x8546,0x8547,
+ 0x8548,0x8549,0x854a,0x854b,0x854c,0x854d,0x854e,0x854f,
+ 0x8550,0x8551,0x8552,0x8553,0x8554,0x8555,0x8556,0x8557,
+ 0x8558,0x8559,0x855a,0x855b,0x855c,0x855d,0x855e,0x855f,
+ 0x8560,0x8561,0x8562,0x8563,0x8564,0x8565,0x8566,0x8567,
+ 0x8568,0x8569,0x856a,0x856b,0x856c,0x856d,0x856e,0x856f,
+ 0x8570,0x8571,0x8572,0x8573,0x8574,0x8575,0x8576,0x8577,
+ 0x8578,0x8579,0x857a,0x857b,0x857c,0x857d,0x857e,0x857f,
+ 0x8580,0x8581,0x8582,0x8583,0x8584,0x8585,0x8586,0x8587,
+ 0x8588,0x8589,0x858a,0x858b,0x858c,0x858d,0x858e,0x858f,
+ 0x8590,0x8591,0x8592,0x8593,0x8594,0x8595,0x8596,0x8597,
+ 0x8598,0x8599,0x859a,0x859b,0x859c,0x859d,0x859e,0x859f,
+ 0x85a0,0x85a1,0x85a2,0x85a3,0x85a4,0x85a5,0x85a6,0x85a7,
+ 0x85a8,0x85a9,0x85aa,0x85ab,0x85ac,0x85ad,0x85ae,0x85af,
+ 0x85b0,0x85b1,0x85b2,0x85b3,0x85b4,0x85b5,0x85b6,0x85b7,
+ 0x85b8,0x85b9,0x85ba,0x85bb,0x85bc,0x85bd,0x85be,0x85bf,
+ 0x85c0,0x85c1,0x85c2,0x85c3,0x85c4,0x85c5,0x85c6,0x85c7,
+ 0x85c8,0x85c9,0x85ca,0x85cb,0x85cc,0x85cd,0x85ce,0x85cf,
+ 0x85d0,0x85d1,0x85d2,0x85d3,0x85d4,0x85d5,0x85d6,0x85d7,
+ 0x85d8,0x85d9,0x85da,0x85db,0x85dc,0x85dd,0x85de,0x85df,
+ 0x85e0,0x85e1,0x85e2,0x85e3,0x85e4,0x85e5,0x85e6,0x85e7,
+ 0x85e8,0x85e9,0x85ea,0x85eb,0x85ec,0x85ed,0x85ee,0x85ef,
+ 0x85f0,0x85f1,0x85f2,0x85f3,0x85f4,0x85f5,0x85f6,0x85f7,
+ 0x85f8,0x85f9,0x85fa,0x85fb,0x85fc,0x85fd,0x85fe,0x85ff,
+ 0x8600,0x8601,0x8602,0x8603,0x8604,0x8605,0x8606,0x8607,
+ 0x8608,0x8609,0x860a,0x860b,0x860c,0x860d,0x860e,0x860f,
+ 0x8610,0x8611,0x8612,0x8613,0x8614,0x8615,0x8616,0x8617,
+ 0x8618,0x8619,0x861a,0x861b,0x861c,0x861d,0x861e,0x861f,
+ 0x8620,0x8621,0x8622,0x8623,0x8624,0x8625,0x8626,0x8627,
+ 0x8628,0x8629,0x862a,0x862b,0x862c,0x862d,0x862e,0x862f,
+ 0x8630,0x8631,0x8632,0x8633,0x8634,0x8635,0x8636,0x8637,
+ 0x8638,0x8639,0x863a,0x863b,0x863c,0x863d,0x863e,0x863f,
+ 0x8640,0x8641,0x8642,0x8643,0x8644,0x8645,0x8646,0x8647,
+ 0x8648,0x8649,0x864a,0x864b,0x864c,0x864d,0x864e,0x864f,
+ 0x8650,0x8651,0x8652,0x8653,0x8654,0x8655,0x8656,0x8657,
+ 0x8658,0x8659,0x865a,0x865b,0x865c,0x865d,0x865e,0x865f,
+ 0x8660,0x8661,0x8662,0x8663,0x8664,0x8665,0x8666,0x8667,
+ 0x8668,0x8669,0x866a,0x866b,0x866c,0x866d,0x866e,0x866f,
+ 0x8670,0x8671,0x8672,0x8673,0x8674,0x8675,0x8676,0x8677,
+ 0x8678,0x8679,0x867a,0x867b,0x867c,0x867d,0x867e,0x867f,
+ 0x8680,0x8681,0x8682,0x8683,0x8684,0x8685,0x8686,0x8687,
+ 0x8688,0x8689,0x868a,0x868b,0x868c,0x868d,0x868e,0x868f,
+ 0x8690,0x8691,0x8692,0x8693,0x8694,0x8695,0x8696,0x8697,
+ 0x8698,0x8699,0x869a,0x869b,0x869c,0x869d,0x869e,0x869f,
+ 0x86a0,0x86a1,0x86a2,0x86a3,0x86a4,0x86a5,0x86a6,0x86a7,
+ 0x86a8,0x86a9,0x86aa,0x86ab,0x86ac,0x86ad,0x86ae,0x86af,
+ 0x86b0,0x86b1,0x86b2,0x86b3,0x86b4,0x86b5,0x86b6,0x86b7,
+ 0x86b8,0x86b9,0x86ba,0x86bb,0x86bc,0x86bd,0x86be,0x86bf,
+ 0x86c0,0x86c1,0x86c2,0x86c3,0x86c4,0x86c5,0x86c6,0x86c7,
+ 0x86c8,0x86c9,0x86ca,0x86cb,0x86cc,0x86cd,0x86ce,0x86cf,
+ 0x86d0,0x86d1,0x86d2,0x86d3,0x86d4,0x86d5,0x86d6,0x86d7,
+ 0x86d8,0x86d9,0x86da,0x86db,0x86dc,0x86dd,0x86de,0x86df,
+ 0x86e0,0x86e1,0x86e2,0x86e3,0x86e4,0x86e5,0x86e6,0x86e7,
+ 0x86e8,0x86e9,0x86ea,0x86eb,0x86ec,0x86ed,0x86ee,0x86ef,
+ 0x86f0,0x86f1,0x86f2,0x86f3,0x86f4,0x86f5,0x86f6,0x86f7,
+ 0x86f8,0x86f9,0x86fa,0x86fb,0x86fc,0x86fd,0x86fe,0x86ff,
+ 0x8700,0x8701,0x8702,0x8703,0x8704,0x8705,0x8706,0x8707,
+ 0x8708,0x8709,0x870a,0x870b,0x870c,0x870d,0x870e,0x870f,
+ 0x8710,0x8711,0x8712,0x8713,0x8714,0x8715,0x8716,0x8717,
+ 0x8718,0x8719,0x871a,0x871b,0x871c,0x871d,0x871e,0x871f,
+ 0x8720,0x8721,0x8722,0x8723,0x8724,0x8725,0x8726,0x8727,
+ 0x8728,0x8729,0x872a,0x872b,0x872c,0x872d,0x872e,0x872f,
+ 0x8730,0x8731,0x8732,0x8733,0x8734,0x8735,0x8736,0x8737,
+ 0x8738,0x8739,0x873a,0x873b,0x873c,0x873d,0x873e,0x873f,
+ 0x8740,0x8741,0x8742,0x8743,0x8744,0x8745,0x8746,0x8747,
+ 0x8748,0x8749,0x874a,0x874b,0x874c,0x874d,0x874e,0x874f,
+ 0x8750,0x8751,0x8752,0x8753,0x8754,0x8755,0x8756,0x8757,
+ 0x8758,0x8759,0x875a,0x875b,0x875c,0x875d,0x875e,0x875f,
+ 0x8760,0x8761,0x8762,0x8763,0x8764,0x8765,0x8766,0x8767,
+ 0x8768,0x8769,0x876a,0x876b,0x876c,0x876d,0x876e,0x876f,
+ 0x8770,0x8771,0x8772,0x8773,0x8774,0x8775,0x8776,0x8777,
+ 0x8778,0x8779,0x877a,0x877b,0x877c,0x877d,0x877e,0x877f,
+ 0x8780,0x8781,0x8782,0x8783,0x8784,0x8785,0x8786,0x8787,
+ 0x8788,0x8789,0x878a,0x878b,0x878c,0x878d,0x878e,0x878f,
+ 0x8790,0x8791,0x8792,0x8793,0x8794,0x8795,0x8796,0x8797,
+ 0x8798,0x8799,0x879a,0x879b,0x879c,0x879d,0x879e,0x879f,
+ 0x87a0,0x87a1,0x87a2,0x87a3,0x87a4,0x87a5,0x87a6,0x87a7,
+ 0x87a8,0x87a9,0x87aa,0x87ab,0x87ac,0x87ad,0x87ae,0x87af,
+ 0x87b0,0x87b1,0x87b2,0x87b3,0x87b4,0x87b5,0x87b6,0x87b7,
+ 0x87b8,0x87b9,0x87ba,0x87bb,0x87bc,0x87bd,0x87be,0x87bf,
+ 0x87c0,0x87c1,0x87c2,0x87c3,0x87c4,0x87c5,0x87c6,0x87c7,
+ 0x87c8,0x87c9,0x87ca,0x87cb,0x87cc,0x87cd,0x87ce,0x87cf,
+ 0x87d0,0x87d1,0x87d2,0x87d3,0x87d4,0x87d5,0x87d6,0x87d7,
+ 0x87d8,0x87d9,0x87da,0x87db,0x87dc,0x87dd,0x87de,0x87df,
+ 0x87e0,0x87e1,0x87e2,0x87e3,0x87e4,0x87e5,0x87e6,0x87e7,
+ 0x87e8,0x87e9,0x87ea,0x87eb,0x87ec,0x87ed,0x87ee,0x87ef,
+ 0x87f0,0x87f1,0x87f2,0x87f3,0x87f4,0x87f5,0x87f6,0x87f7,
+ 0x87f8,0x87f9,0x87fa,0x87fb,0x87fc,0x87fd,0x87fe,0x87ff,
+ 0x8800,0x8801,0x8802,0x8803,0x8804,0x8805,0x8806,0x8807,
+ 0x8808,0x8809,0x880a,0x880b,0x880c,0x880d,0x880e,0x880f,
+ 0x8810,0x8811,0x8812,0x8813,0x8814,0x8815,0x8816,0x8817,
+ 0x8818,0x8819,0x881a,0x881b,0x881c,0x881d,0x881e,0x881f,
+ 0x8820,0x8821,0x8822,0x8823,0x8824,0x8825,0x8826,0x8827,
+ 0x8828,0x8829,0x882a,0x882b,0x882c,0x882d,0x882e,0x882f,
+ 0x8830,0x8831,0x8832,0x8833,0x8834,0x8835,0x8836,0x8837,
+ 0x8838,0x8839,0x883a,0x883b,0x883c,0x883d,0x883e,0x883f,
+ 0x8840,0x8841,0x8842,0x8843,0x8844,0x8845,0x8846,0x8847,
+ 0x8848,0x8849,0x884a,0x884b,0x884c,0x884d,0x884e,0x884f,
+ 0x8850,0x8851,0x8852,0x8853,0x8854,0x8855,0x8856,0x8857,
+ 0x8858,0x8859,0x885a,0x885b,0x885c,0x885d,0x885e,0x885f,
+ 0x8860,0x8861,0x8862,0x8863,0x8864,0x8865,0x8866,0x8867,
+ 0x8868,0x8869,0x886a,0x886b,0x886c,0x886d,0x886e,0x886f,
+ 0x8870,0x8871,0x8872,0x8873,0x8874,0x8875,0x8876,0x8877,
+ 0x8878,0x8879,0x887a,0x887b,0x887c,0x887d,0x887e,0x887f,
+ 0x8880,0x8881,0x8882,0x8883,0x8884,0x8885,0x8886,0x8887,
+ 0x8888,0x8889,0x888a,0x888b,0x888c,0x888d,0x888e,0x888f,
+ 0x8890,0x8891,0x8892,0x8893,0x8894,0x8895,0x8896,0x8897,
+ 0x8898,0x8899,0x889a,0x889b,0x889c,0x889d,0x889e,0x889f,
+ 0x88a0,0x88a1,0x88a2,0x88a3,0x88a4,0x88a5,0x88a6,0x88a7,
+ 0x88a8,0x88a9,0x88aa,0x88ab,0x88ac,0x88ad,0x88ae,0x88af,
+ 0x88b0,0x88b1,0x88b2,0x88b3,0x88b4,0x88b5,0x88b6,0x88b7,
+ 0x88b8,0x88b9,0x88ba,0x88bb,0x88bc,0x88bd,0x88be,0x88bf,
+ 0x88c0,0x88c1,0x88c2,0x88c3,0x88c4,0x88c5,0x88c6,0x88c7,
+ 0x88c8,0x88c9,0x88ca,0x88cb,0x88cc,0x88cd,0x88ce,0x88cf,
+ 0x88d0,0x88d1,0x88d2,0x88d3,0x88d4,0x88d5,0x88d6,0x88d7,
+ 0x88d8,0x88d9,0x88da,0x88db,0x88dc,0x88dd,0x88de,0x88df,
+ 0x88e0,0x88e1,0x88e2,0x88e3,0x88e4,0x88e5,0x88e6,0x88e7,
+ 0x88e8,0x88e9,0x88ea,0x88eb,0x88ec,0x88ed,0x88ee,0x88ef,
+ 0x88f0,0x88f1,0x88f2,0x88f3,0x88f4,0x88f5,0x88f6,0x88f7,
+ 0x88f8,0x88f9,0x88fa,0x88fb,0x88fc,0x88fd,0x88fe,0x88ff,
+ 0x8900,0x8901,0x8902,0x8903,0x8904,0x8905,0x8906,0x8907,
+ 0x8908,0x8909,0x890a,0x890b,0x890c,0x890d,0x890e,0x890f,
+ 0x8910,0x8911,0x8912,0x8913,0x8914,0x8915,0x8916,0x8917,
+ 0x8918,0x8919,0x891a,0x891b,0x891c,0x891d,0x891e,0x891f,
+ 0x8920,0x8921,0x8922,0x8923,0x8924,0x8925,0x8926,0x8927,
+ 0x8928,0x8929,0x892a,0x892b,0x892c,0x892d,0x892e,0x892f,
+ 0x8930,0x8931,0x8932,0x8933,0x8934,0x8935,0x8936,0x8937,
+ 0x8938,0x8939,0x893a,0x893b,0x893c,0x893d,0x893e,0x893f,
+ 0x8940,0x8941,0x8942,0x8943,0x8944,0x8945,0x8946,0x8947,
+ 0x8948,0x8949,0x894a,0x894b,0x894c,0x894d,0x894e,0x894f,
+ 0x8950,0x8951,0x8952,0x8953,0x8954,0x8955,0x8956,0x8957,
+ 0x8958,0x8959,0x895a,0x895b,0x895c,0x895d,0x895e,0x895f,
+ 0x8960,0x8961,0x8962,0x8963,0x8964,0x8965,0x8966,0x8967,
+ 0x8968,0x8969,0x896a,0x896b,0x896c,0x896d,0x896e,0x896f,
+ 0x8970,0x8971,0x8972,0x8973,0x8974,0x8975,0x8976,0x8977,
+ 0x8978,0x8979,0x897a,0x897b,0x897c,0x897d,0x897e,0x897f,
+ 0x8980,0x8981,0x8982,0x8983,0x8984,0x8985,0x8986,0x8987,
+ 0x8988,0x8989,0x898a,0x898b,0x898c,0x898d,0x898e,0x898f,
+ 0x8990,0x8991,0x8992,0x8993,0x8994,0x8995,0x8996,0x8997,
+ 0x8998,0x8999,0x899a,0x899b,0x899c,0x899d,0x899e,0x899f,
+ 0x89a0,0x89a1,0x89a2,0x89a3,0x89a4,0x89a5,0x89a6,0x89a7,
+ 0x89a8,0x89a9,0x89aa,0x89ab,0x89ac,0x89ad,0x89ae,0x89af,
+ 0x89b0,0x89b1,0x89b2,0x89b3,0x89b4,0x89b5,0x89b6,0x89b7,
+ 0x89b8,0x89b9,0x89ba,0x89bb,0x89bc,0x89bd,0x89be,0x89bf,
+ 0x89c0,0x89c1,0x89c2,0x89c3,0x89c4,0x89c5,0x89c6,0x89c7,
+ 0x89c8,0x89c9,0x89ca,0x89cb,0x89cc,0x89cd,0x89ce,0x89cf,
+ 0x89d0,0x89d1,0x89d2,0x89d3,0x89d4,0x89d5,0x89d6,0x89d7,
+ 0x89d8,0x89d9,0x89da,0x89db,0x89dc,0x89dd,0x89de,0x89df,
+ 0x89e0,0x89e1,0x89e2,0x89e3,0x89e4,0x89e5,0x89e6,0x89e7,
+ 0x89e8,0x89e9,0x89ea,0x89eb,0x89ec,0x89ed,0x89ee,0x89ef,
+ 0x89f0,0x89f1,0x89f2,0x89f3,0x89f4,0x89f5,0x89f6,0x89f7,
+ 0x89f8,0x89f9,0x89fa,0x89fb,0x89fc,0x89fd,0x89fe,0x89ff,
+ 0x8a00,0x8a01,0x8a02,0x8a03,0x8a04,0x8a05,0x8a06,0x8a07,
+ 0x8a08,0x8a09,0x8a0a,0x8a0b,0x8a0c,0x8a0d,0x8a0e,0x8a0f,
+ 0x8a10,0x8a11,0x8a12,0x8a13,0x8a14,0x8a15,0x8a16,0x8a17,
+ 0x8a18,0x8a19,0x8a1a,0x8a1b,0x8a1c,0x8a1d,0x8a1e,0x8a1f,
+ 0x8a20,0x8a21,0x8a22,0x8a23,0x8a24,0x8a25,0x8a26,0x8a27,
+ 0x8a28,0x8a29,0x8a2a,0x8a2b,0x8a2c,0x8a2d,0x8a2e,0x8a2f,
+ 0x8a30,0x8a31,0x8a32,0x8a33,0x8a34,0x8a35,0x8a36,0x8a37,
+ 0x8a38,0x8a39,0x8a3a,0x8a3b,0x8a3c,0x8a3d,0x8a3e,0x8a3f,
+ 0x8a40,0x8a41,0x8a42,0x8a43,0x8a44,0x8a45,0x8a46,0x8a47,
+ 0x8a48,0x8a49,0x8a4a,0x8a4b,0x8a4c,0x8a4d,0x8a4e,0x8a4f,
+ 0x8a50,0x8a51,0x8a52,0x8a53,0x8a54,0x8a55,0x8a56,0x8a57,
+ 0x8a58,0x8a59,0x8a5a,0x8a5b,0x8a5c,0x8a5d,0x8a5e,0x8a5f,
+ 0x8a60,0x8a61,0x8a62,0x8a63,0x8a64,0x8a65,0x8a66,0x8a67,
+ 0x8a68,0x8a69,0x8a6a,0x8a6b,0x8a6c,0x8a6d,0x8a6e,0x8a6f,
+ 0x8a70,0x8a71,0x8a72,0x8a73,0x8a74,0x8a75,0x8a76,0x8a77,
+ 0x8a78,0x8a79,0x8a7a,0x8a7b,0x8a7c,0x8a7d,0x8a7e,0x8a7f,
+ 0x8a80,0x8a81,0x8a82,0x8a83,0x8a84,0x8a85,0x8a86,0x8a87,
+ 0x8a88,0x8a89,0x8a8a,0x8a8b,0x8a8c,0x8a8d,0x8a8e,0x8a8f,
+ 0x8a90,0x8a91,0x8a92,0x8a93,0x8a94,0x8a95,0x8a96,0x8a97,
+ 0x8a98,0x8a99,0x8a9a,0x8a9b,0x8a9c,0x8a9d,0x8a9e,0x8a9f,
+ 0x8aa0,0x8aa1,0x8aa2,0x8aa3,0x8aa4,0x8aa5,0x8aa6,0x8aa7,
+ 0x8aa8,0x8aa9,0x8aaa,0x8aab,0x8aac,0x8aad,0x8aae,0x8aaf,
+ 0x8ab0,0x8ab1,0x8ab2,0x8ab3,0x8ab4,0x8ab5,0x8ab6,0x8ab7,
+ 0x8ab8,0x8ab9,0x8aba,0x8abb,0x8abc,0x8abd,0x8abe,0x8abf,
+ 0x8ac0,0x8ac1,0x8ac2,0x8ac3,0x8ac4,0x8ac5,0x8ac6,0x8ac7,
+ 0x8ac8,0x8ac9,0x8aca,0x8acb,0x8acc,0x8acd,0x8ace,0x8acf,
+ 0x8ad0,0x8ad1,0x8ad2,0x8ad3,0x8ad4,0x8ad5,0x8ad6,0x8ad7,
+ 0x8ad8,0x8ad9,0x8ada,0x8adb,0x8adc,0x8add,0x8ade,0x8adf,
+ 0x8ae0,0x8ae1,0x8ae2,0x8ae3,0x8ae4,0x8ae5,0x8ae6,0x8ae7,
+ 0x8ae8,0x8ae9,0x8aea,0x8aeb,0x8aec,0x8aed,0x8aee,0x8aef,
+ 0x8af0,0x8af1,0x8af2,0x8af3,0x8af4,0x8af5,0x8af6,0x8af7,
+ 0x8af8,0x8af9,0x8afa,0x8afb,0x8afc,0x8afd,0x8afe,0x8aff,
+ 0x8b00,0x8b01,0x8b02,0x8b03,0x8b04,0x8b05,0x8b06,0x8b07,
+ 0x8b08,0x8b09,0x8b0a,0x8b0b,0x8b0c,0x8b0d,0x8b0e,0x8b0f,
+ 0x8b10,0x8b11,0x8b12,0x8b13,0x8b14,0x8b15,0x8b16,0x8b17,
+ 0x8b18,0x8b19,0x8b1a,0x8b1b,0x8b1c,0x8b1d,0x8b1e,0x8b1f,
+ 0x8b20,0x8b21,0x8b22,0x8b23,0x8b24,0x8b25,0x8b26,0x8b27,
+ 0x8b28,0x8b29,0x8b2a,0x8b2b,0x8b2c,0x8b2d,0x8b2e,0x8b2f,
+ 0x8b30,0x8b31,0x8b32,0x8b33,0x8b34,0x8b35,0x8b36,0x8b37,
+ 0x8b38,0x8b39,0x8b3a,0x8b3b,0x8b3c,0x8b3d,0x8b3e,0x8b3f,
+ 0x8b40,0x8b41,0x8b42,0x8b43,0x8b44,0x8b45,0x8b46,0x8b47,
+ 0x8b48,0x8b49,0x8b4a,0x8b4b,0x8b4c,0x8b4d,0x8b4e,0x8b4f,
+ 0x8b50,0x8b51,0x8b52,0x8b53,0x8b54,0x8b55,0x8b56,0x8b57,
+ 0x8b58,0x8b59,0x8b5a,0x8b5b,0x8b5c,0x8b5d,0x8b5e,0x8b5f,
+ 0x8b60,0x8b61,0x8b62,0x8b63,0x8b64,0x8b65,0x8b66,0x8b67,
+ 0x8b68,0x8b69,0x8b6a,0x8b6b,0x8b6c,0x8b6d,0x8b6e,0x8b6f,
+ 0x8b70,0x8b71,0x8b72,0x8b73,0x8b74,0x8b75,0x8b76,0x8b77,
+ 0x8b78,0x8b79,0x8b7a,0x8b7b,0x8b7c,0x8b7d,0x8b7e,0x8b7f,
+ 0x8b80,0x8b81,0x8b82,0x8b83,0x8b84,0x8b85,0x8b86,0x8b87,
+ 0x8b88,0x8b89,0x8b8a,0x8b8b,0x8b8c,0x8b8d,0x8b8e,0x8b8f,
+ 0x8b90,0x8b91,0x8b92,0x8b93,0x8b94,0x8b95,0x8b96,0x8b97,
+ 0x8b98,0x8b99,0x8b9a,0x8b9b,0x8b9c,0x8b9d,0x8b9e,0x8b9f,
+ 0x8ba0,0x8ba1,0x8ba2,0x8ba3,0x8ba4,0x8ba5,0x8ba6,0x8ba7,
+ 0x8ba8,0x8ba9,0x8baa,0x8bab,0x8bac,0x8bad,0x8bae,0x8baf,
+ 0x8bb0,0x8bb1,0x8bb2,0x8bb3,0x8bb4,0x8bb5,0x8bb6,0x8bb7,
+ 0x8bb8,0x8bb9,0x8bba,0x8bbb,0x8bbc,0x8bbd,0x8bbe,0x8bbf,
+ 0x8bc0,0x8bc1,0x8bc2,0x8bc3,0x8bc4,0x8bc5,0x8bc6,0x8bc7,
+ 0x8bc8,0x8bc9,0x8bca,0x8bcb,0x8bcc,0x8bcd,0x8bce,0x8bcf,
+ 0x8bd0,0x8bd1,0x8bd2,0x8bd3,0x8bd4,0x8bd5,0x8bd6,0x8bd7,
+ 0x8bd8,0x8bd9,0x8bda,0x8bdb,0x8bdc,0x8bdd,0x8bde,0x8bdf,
+ 0x8be0,0x8be1,0x8be2,0x8be3,0x8be4,0x8be5,0x8be6,0x8be7,
+ 0x8be8,0x8be9,0x8bea,0x8beb,0x8bec,0x8bed,0x8bee,0x8bef,
+ 0x8bf0,0x8bf1,0x8bf2,0x8bf3,0x8bf4,0x8bf5,0x8bf6,0x8bf7,
+ 0x8bf8,0x8bf9,0x8bfa,0x8bfb,0x8bfc,0x8bfd,0x8bfe,0x8bff,
+ 0x8c00,0x8c01,0x8c02,0x8c03,0x8c04,0x8c05,0x8c06,0x8c07,
+ 0x8c08,0x8c09,0x8c0a,0x8c0b,0x8c0c,0x8c0d,0x8c0e,0x8c0f,
+ 0x8c10,0x8c11,0x8c12,0x8c13,0x8c14,0x8c15,0x8c16,0x8c17,
+ 0x8c18,0x8c19,0x8c1a,0x8c1b,0x8c1c,0x8c1d,0x8c1e,0x8c1f,
+ 0x8c20,0x8c21,0x8c22,0x8c23,0x8c24,0x8c25,0x8c26,0x8c27,
+ 0x8c28,0x8c29,0x8c2a,0x8c2b,0x8c2c,0x8c2d,0x8c2e,0x8c2f,
+ 0x8c30,0x8c31,0x8c32,0x8c33,0x8c34,0x8c35,0x8c36,0x8c37,
+ 0x8c38,0x8c39,0x8c3a,0x8c3b,0x8c3c,0x8c3d,0x8c3e,0x8c3f,
+ 0x8c40,0x8c41,0x8c42,0x8c43,0x8c44,0x8c45,0x8c46,0x8c47,
+ 0x8c48,0x8c49,0x8c4a,0x8c4b,0x8c4c,0x8c4d,0x8c4e,0x8c4f,
+ 0x8c50,0x8c51,0x8c52,0x8c53,0x8c54,0x8c55,0x8c56,0x8c57,
+ 0x8c58,0x8c59,0x8c5a,0x8c5b,0x8c5c,0x8c5d,0x8c5e,0x8c5f,
+ 0x8c60,0x8c61,0x8c62,0x8c63,0x8c64,0x8c65,0x8c66,0x8c67,
+ 0x8c68,0x8c69,0x8c6a,0x8c6b,0x8c6c,0x8c6d,0x8c6e,0x8c6f,
+ 0x8c70,0x8c71,0x8c72,0x8c73,0x8c74,0x8c75,0x8c76,0x8c77,
+ 0x8c78,0x8c79,0x8c7a,0x8c7b,0x8c7c,0x8c7d,0x8c7e,0x8c7f,
+ 0x8c80,0x8c81,0x8c82,0x8c83,0x8c84,0x8c85,0x8c86,0x8c87,
+ 0x8c88,0x8c89,0x8c8a,0x8c8b,0x8c8c,0x8c8d,0x8c8e,0x8c8f,
+ 0x8c90,0x8c91,0x8c92,0x8c93,0x8c94,0x8c95,0x8c96,0x8c97,
+ 0x8c98,0x8c99,0x8c9a,0x8c9b,0x8c9c,0x8c9d,0x8c9e,0x8c9f,
+ 0x8ca0,0x8ca1,0x8ca2,0x8ca3,0x8ca4,0x8ca5,0x8ca6,0x8ca7,
+ 0x8ca8,0x8ca9,0x8caa,0x8cab,0x8cac,0x8cad,0x8cae,0x8caf,
+ 0x8cb0,0x8cb1,0x8cb2,0x8cb3,0x8cb4,0x8cb5,0x8cb6,0x8cb7,
+ 0x8cb8,0x8cb9,0x8cba,0x8cbb,0x8cbc,0x8cbd,0x8cbe,0x8cbf,
+ 0x8cc0,0x8cc1,0x8cc2,0x8cc3,0x8cc4,0x8cc5,0x8cc6,0x8cc7,
+ 0x8cc8,0x8cc9,0x8cca,0x8ccb,0x8ccc,0x8ccd,0x8cce,0x8ccf,
+ 0x8cd0,0x8cd1,0x8cd2,0x8cd3,0x8cd4,0x8cd5,0x8cd6,0x8cd7,
+ 0x8cd8,0x8cd9,0x8cda,0x8cdb,0x8cdc,0x8cdd,0x8cde,0x8cdf,
+ 0x8ce0,0x8ce1,0x8ce2,0x8ce3,0x8ce4,0x8ce5,0x8ce6,0x8ce7,
+ 0x8ce8,0x8ce9,0x8cea,0x8ceb,0x8cec,0x8ced,0x8cee,0x8cef,
+ 0x8cf0,0x8cf1,0x8cf2,0x8cf3,0x8cf4,0x8cf5,0x8cf6,0x8cf7,
+ 0x8cf8,0x8cf9,0x8cfa,0x8cfb,0x8cfc,0x8cfd,0x8cfe,0x8cff,
+ 0x8d00,0x8d01,0x8d02,0x8d03,0x8d04,0x8d05,0x8d06,0x8d07,
+ 0x8d08,0x8d09,0x8d0a,0x8d0b,0x8d0c,0x8d0d,0x8d0e,0x8d0f,
+ 0x8d10,0x8d11,0x8d12,0x8d13,0x8d14,0x8d15,0x8d16,0x8d17,
+ 0x8d18,0x8d19,0x8d1a,0x8d1b,0x8d1c,0x8d1d,0x8d1e,0x8d1f,
+ 0x8d20,0x8d21,0x8d22,0x8d23,0x8d24,0x8d25,0x8d26,0x8d27,
+ 0x8d28,0x8d29,0x8d2a,0x8d2b,0x8d2c,0x8d2d,0x8d2e,0x8d2f,
+ 0x8d30,0x8d31,0x8d32,0x8d33,0x8d34,0x8d35,0x8d36,0x8d37,
+ 0x8d38,0x8d39,0x8d3a,0x8d3b,0x8d3c,0x8d3d,0x8d3e,0x8d3f,
+ 0x8d40,0x8d41,0x8d42,0x8d43,0x8d44,0x8d45,0x8d46,0x8d47,
+ 0x8d48,0x8d49,0x8d4a,0x8d4b,0x8d4c,0x8d4d,0x8d4e,0x8d4f,
+ 0x8d50,0x8d51,0x8d52,0x8d53,0x8d54,0x8d55,0x8d56,0x8d57,
+ 0x8d58,0x8d59,0x8d5a,0x8d5b,0x8d5c,0x8d5d,0x8d5e,0x8d5f,
+ 0x8d60,0x8d61,0x8d62,0x8d63,0x8d64,0x8d65,0x8d66,0x8d67,
+ 0x8d68,0x8d69,0x8d6a,0x8d6b,0x8d6c,0x8d6d,0x8d6e,0x8d6f,
+ 0x8d70,0x8d71,0x8d72,0x8d73,0x8d74,0x8d75,0x8d76,0x8d77,
+ 0x8d78,0x8d79,0x8d7a,0x8d7b,0x8d7c,0x8d7d,0x8d7e,0x8d7f,
+ 0x8d80,0x8d81,0x8d82,0x8d83,0x8d84,0x8d85,0x8d86,0x8d87,
+ 0x8d88,0x8d89,0x8d8a,0x8d8b,0x8d8c,0x8d8d,0x8d8e,0x8d8f,
+ 0x8d90,0x8d91,0x8d92,0x8d93,0x8d94,0x8d95,0x8d96,0x8d97,
+ 0x8d98,0x8d99,0x8d9a,0x8d9b,0x8d9c,0x8d9d,0x8d9e,0x8d9f,
+ 0x8da0,0x8da1,0x8da2,0x8da3,0x8da4,0x8da5,0x8da6,0x8da7,
+ 0x8da8,0x8da9,0x8daa,0x8dab,0x8dac,0x8dad,0x8dae,0x8daf,
+ 0x8db0,0x8db1,0x8db2,0x8db3,0x8db4,0x8db5,0x8db6,0x8db7,
+ 0x8db8,0x8db9,0x8dba,0x8dbb,0x8dbc,0x8dbd,0x8dbe,0x8dbf,
+ 0x8dc0,0x8dc1,0x8dc2,0x8dc3,0x8dc4,0x8dc5,0x8dc6,0x8dc7,
+ 0x8dc8,0x8dc9,0x8dca,0x8dcb,0x8dcc,0x8dcd,0x8dce,0x8dcf,
+ 0x8dd0,0x8dd1,0x8dd2,0x8dd3,0x8dd4,0x8dd5,0x8dd6,0x8dd7,
+ 0x8dd8,0x8dd9,0x8dda,0x8ddb,0x8ddc,0x8ddd,0x8dde,0x8ddf,
+ 0x8de0,0x8de1,0x8de2,0x8de3,0x8de4,0x8de5,0x8de6,0x8de7,
+ 0x8de8,0x8de9,0x8dea,0x8deb,0x8dec,0x8ded,0x8dee,0x8def,
+ 0x8df0,0x8df1,0x8df2,0x8df3,0x8df4,0x8df5,0x8df6,0x8df7,
+ 0x8df8,0x8df9,0x8dfa,0x8dfb,0x8dfc,0x8dfd,0x8dfe,0x8dff,
+ 0x8e00,0x8e01,0x8e02,0x8e03,0x8e04,0x8e05,0x8e06,0x8e07,
+ 0x8e08,0x8e09,0x8e0a,0x8e0b,0x8e0c,0x8e0d,0x8e0e,0x8e0f,
+ 0x8e10,0x8e11,0x8e12,0x8e13,0x8e14,0x8e15,0x8e16,0x8e17,
+ 0x8e18,0x8e19,0x8e1a,0x8e1b,0x8e1c,0x8e1d,0x8e1e,0x8e1f,
+ 0x8e20,0x8e21,0x8e22,0x8e23,0x8e24,0x8e25,0x8e26,0x8e27,
+ 0x8e28,0x8e29,0x8e2a,0x8e2b,0x8e2c,0x8e2d,0x8e2e,0x8e2f,
+ 0x8e30,0x8e31,0x8e32,0x8e33,0x8e34,0x8e35,0x8e36,0x8e37,
+ 0x8e38,0x8e39,0x8e3a,0x8e3b,0x8e3c,0x8e3d,0x8e3e,0x8e3f,
+ 0x8e40,0x8e41,0x8e42,0x8e43,0x8e44,0x8e45,0x8e46,0x8e47,
+ 0x8e48,0x8e49,0x8e4a,0x8e4b,0x8e4c,0x8e4d,0x8e4e,0x8e4f,
+ 0x8e50,0x8e51,0x8e52,0x8e53,0x8e54,0x8e55,0x8e56,0x8e57,
+ 0x8e58,0x8e59,0x8e5a,0x8e5b,0x8e5c,0x8e5d,0x8e5e,0x8e5f,
+ 0x8e60,0x8e61,0x8e62,0x8e63,0x8e64,0x8e65,0x8e66,0x8e67,
+ 0x8e68,0x8e69,0x8e6a,0x8e6b,0x8e6c,0x8e6d,0x8e6e,0x8e6f,
+ 0x8e70,0x8e71,0x8e72,0x8e73,0x8e74,0x8e75,0x8e76,0x8e77,
+ 0x8e78,0x8e79,0x8e7a,0x8e7b,0x8e7c,0x8e7d,0x8e7e,0x8e7f,
+ 0x8e80,0x8e81,0x8e82,0x8e83,0x8e84,0x8e85,0x8e86,0x8e87,
+ 0x8e88,0x8e89,0x8e8a,0x8e8b,0x8e8c,0x8e8d,0x8e8e,0x8e8f,
+ 0x8e90,0x8e91,0x8e92,0x8e93,0x8e94,0x8e95,0x8e96,0x8e97,
+ 0x8e98,0x8e99,0x8e9a,0x8e9b,0x8e9c,0x8e9d,0x8e9e,0x8e9f,
+ 0x8ea0,0x8ea1,0x8ea2,0x8ea3,0x8ea4,0x8ea5,0x8ea6,0x8ea7,
+ 0x8ea8,0x8ea9,0x8eaa,0x8eab,0x8eac,0x8ead,0x8eae,0x8eaf,
+ 0x8eb0,0x8eb1,0x8eb2,0x8eb3,0x8eb4,0x8eb5,0x8eb6,0x8eb7,
+ 0x8eb8,0x8eb9,0x8eba,0x8ebb,0x8ebc,0x8ebd,0x8ebe,0x8ebf,
+ 0x8ec0,0x8ec1,0x8ec2,0x8ec3,0x8ec4,0x8ec5,0x8ec6,0x8ec7,
+ 0x8ec8,0x8ec9,0x8eca,0x8ecb,0x8ecc,0x8ecd,0x8ece,0x8ecf,
+ 0x8ed0,0x8ed1,0x8ed2,0x8ed3,0x8ed4,0x8ed5,0x8ed6,0x8ed7,
+ 0x8ed8,0x8ed9,0x8eda,0x8edb,0x8edc,0x8edd,0x8ede,0x8edf,
+ 0x8ee0,0x8ee1,0x8ee2,0x8ee3,0x8ee4,0x8ee5,0x8ee6,0x8ee7,
+ 0x8ee8,0x8ee9,0x8eea,0x8eeb,0x8eec,0x8eed,0x8eee,0x8eef,
+ 0x8ef0,0x8ef1,0x8ef2,0x8ef3,0x8ef4,0x8ef5,0x8ef6,0x8ef7,
+ 0x8ef8,0x8ef9,0x8efa,0x8efb,0x8efc,0x8efd,0x8efe,0x8eff,
+ 0x8f00,0x8f01,0x8f02,0x8f03,0x8f04,0x8f05,0x8f06,0x8f07,
+ 0x8f08,0x8f09,0x8f0a,0x8f0b,0x8f0c,0x8f0d,0x8f0e,0x8f0f,
+ 0x8f10,0x8f11,0x8f12,0x8f13,0x8f14,0x8f15,0x8f16,0x8f17,
+ 0x8f18,0x8f19,0x8f1a,0x8f1b,0x8f1c,0x8f1d,0x8f1e,0x8f1f,
+ 0x8f20,0x8f21,0x8f22,0x8f23,0x8f24,0x8f25,0x8f26,0x8f27,
+ 0x8f28,0x8f29,0x8f2a,0x8f2b,0x8f2c,0x8f2d,0x8f2e,0x8f2f,
+ 0x8f30,0x8f31,0x8f32,0x8f33,0x8f34,0x8f35,0x8f36,0x8f37,
+ 0x8f38,0x8f39,0x8f3a,0x8f3b,0x8f3c,0x8f3d,0x8f3e,0x8f3f,
+ 0x8f40,0x8f41,0x8f42,0x8f43,0x8f44,0x8f45,0x8f46,0x8f47,
+ 0x8f48,0x8f49,0x8f4a,0x8f4b,0x8f4c,0x8f4d,0x8f4e,0x8f4f,
+ 0x8f50,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f56,0x8f57,
+ 0x8f58,0x8f59,0x8f5a,0x8f5b,0x8f5c,0x8f5d,0x8f5e,0x8f5f,
+ 0x8f60,0x8f61,0x8f62,0x8f63,0x8f64,0x8f65,0x8f66,0x8f67,
+ 0x8f68,0x8f69,0x8f6a,0x8f6b,0x8f6c,0x8f6d,0x8f6e,0x8f6f,
+ 0x8f70,0x8f71,0x8f72,0x8f73,0x8f74,0x8f75,0x8f76,0x8f77,
+ 0x8f78,0x8f79,0x8f7a,0x8f7b,0x8f7c,0x8f7d,0x8f7e,0x8f7f,
+ 0x8f80,0x8f81,0x8f82,0x8f83,0x8f84,0x8f85,0x8f86,0x8f87,
+ 0x8f88,0x8f89,0x8f8a,0x8f8b,0x8f8c,0x8f8d,0x8f8e,0x8f8f,
+ 0x8f90,0x8f91,0x8f92,0x8f93,0x8f94,0x8f95,0x8f96,0x8f97,
+ 0x8f98,0x8f99,0x8f9a,0x8f9b,0x8f9c,0x8f9d,0x8f9e,0x8f9f,
+ 0x8fa0,0x8fa1,0x8fa2,0x8fa3,0x8fa4,0x8fa5,0x8fa6,0x8fa7,
+ 0x8fa8,0x8fa9,0x8faa,0x8fab,0x8fac,0x8fad,0x8fae,0x8faf,
+ 0x8fb0,0x8fb1,0x8fb2,0x8fb3,0x8fb4,0x8fb5,0x8fb6,0x8fb7,
+ 0x8fb8,0x8fb9,0x8fba,0x8fbb,0x8fbc,0x8fbd,0x8fbe,0x8fbf,
+ 0x8fc0,0x8fc1,0x8fc2,0x8fc3,0x8fc4,0x8fc5,0x8fc6,0x8fc7,
+ 0x8fc8,0x8fc9,0x8fca,0x8fcb,0x8fcc,0x8fcd,0x8fce,0x8fcf,
+ 0x8fd0,0x8fd1,0x8fd2,0x8fd3,0x8fd4,0x8fd5,0x8fd6,0x8fd7,
+ 0x8fd8,0x8fd9,0x8fda,0x8fdb,0x8fdc,0x8fdd,0x8fde,0x8fdf,
+ 0x8fe0,0x8fe1,0x8fe2,0x8fe3,0x8fe4,0x8fe5,0x8fe6,0x8fe7,
+ 0x8fe8,0x8fe9,0x8fea,0x8feb,0x8fec,0x8fed,0x8fee,0x8fef,
+ 0x8ff0,0x8ff1,0x8ff2,0x8ff3,0x8ff4,0x8ff5,0x8ff6,0x8ff7,
+ 0x8ff8,0x8ff9,0x8ffa,0x8ffb,0x8ffc,0x8ffd,0x8ffe,0x8fff,
+ 0x9000,0x9001,0x9002,0x9003,0x9004,0x9005,0x9006,0x9007,
+ 0x9008,0x9009,0x900a,0x900b,0x900c,0x900d,0x900e,0x900f,
+ 0x9010,0x9011,0x9012,0x9013,0x9014,0x9015,0x9016,0x9017,
+ 0x9018,0x9019,0x901a,0x901b,0x901c,0x901d,0x901e,0x901f,
+ 0x9020,0x9021,0x9022,0x9023,0x9024,0x9025,0x9026,0x9027,
+ 0x9028,0x9029,0x902a,0x902b,0x902c,0x902d,0x902e,0x902f,
+ 0x9030,0x9031,0x9032,0x9033,0x9034,0x9035,0x9036,0x9037,
+ 0x9038,0x9039,0x903a,0x903b,0x903c,0x903d,0x903e,0x903f,
+ 0x9040,0x9041,0x9042,0x9043,0x9044,0x9045,0x9046,0x9047,
+ 0x9048,0x9049,0x904a,0x904b,0x904c,0x904d,0x904e,0x904f,
+ 0x9050,0x9051,0x9052,0x9053,0x9054,0x9055,0x9056,0x9057,
+ 0x9058,0x9059,0x905a,0x905b,0x905c,0x905d,0x905e,0x905f,
+ 0x9060,0x9061,0x9062,0x9063,0x9064,0x9065,0x9066,0x9067,
+ 0x9068,0x9069,0x906a,0x906b,0x906c,0x906d,0x906e,0x906f,
+ 0x9070,0x9071,0x9072,0x9073,0x9074,0x9075,0x9076,0x9077,
+ 0x9078,0x9079,0x907a,0x907b,0x907c,0x907d,0x907e,0x907f,
+ 0x9080,0x9081,0x9082,0x9083,0x9084,0x9085,0x9086,0x9087,
+ 0x9088,0x9089,0x908a,0x908b,0x908c,0x908d,0x908e,0x908f,
+ 0x9090,0x9091,0x9092,0x9093,0x9094,0x9095,0x9096,0x9097,
+ 0x9098,0x9099,0x909a,0x909b,0x909c,0x909d,0x909e,0x909f,
+ 0x90a0,0x90a1,0x90a2,0x90a3,0x90a4,0x90a5,0x90a6,0x90a7,
+ 0x90a8,0x90a9,0x90aa,0x90ab,0x90ac,0x90ad,0x90ae,0x90af,
+ 0x90b0,0x90b1,0x90b2,0x90b3,0x90b4,0x90b5,0x90b6,0x90b7,
+ 0x90b8,0x90b9,0x90ba,0x90bb,0x90bc,0x90bd,0x90be,0x90bf,
+ 0x90c0,0x90c1,0x90c2,0x90c3,0x90c4,0x90c5,0x90c6,0x90c7,
+ 0x90c8,0x90c9,0x90ca,0x90cb,0x90cc,0x90cd,0x90ce,0x90cf,
+ 0x90d0,0x90d1,0x90d2,0x90d3,0x90d4,0x90d5,0x90d6,0x90d7,
+ 0x90d8,0x90d9,0x90da,0x90db,0x90dc,0x90dd,0x90de,0x90df,
+ 0x90e0,0x90e1,0x90e2,0x90e3,0x90e4,0x90e5,0x90e6,0x90e7,
+ 0x90e8,0x90e9,0x90ea,0x90eb,0x90ec,0x90ed,0x90ee,0x90ef,
+ 0x90f0,0x90f1,0x90f2,0x90f3,0x90f4,0x90f5,0x90f6,0x90f7,
+ 0x90f8,0x90f9,0x90fa,0x90fb,0x90fc,0x90fd,0x90fe,0x90ff,
+ 0x9100,0x9101,0x9102,0x9103,0x9104,0x9105,0x9106,0x9107,
+ 0x9108,0x9109,0x910a,0x910b,0x910c,0x910d,0x910e,0x910f,
+ 0x9110,0x9111,0x9112,0x9113,0x9114,0x9115,0x9116,0x9117,
+ 0x9118,0x9119,0x911a,0x911b,0x911c,0x911d,0x911e,0x911f,
+ 0x9120,0x9121,0x9122,0x9123,0x9124,0x9125,0x9126,0x9127,
+ 0x9128,0x9129,0x912a,0x912b,0x912c,0x912d,0x912e,0x912f,
+ 0x9130,0x9131,0x9132,0x9133,0x9134,0x9135,0x9136,0x9137,
+ 0x9138,0x9139,0x913a,0x913b,0x913c,0x913d,0x913e,0x913f,
+ 0x9140,0x9141,0x9142,0x9143,0x9144,0x9145,0x9146,0x9147,
+ 0x9148,0x9149,0x914a,0x914b,0x914c,0x914d,0x914e,0x914f,
+ 0x9150,0x9151,0x9152,0x9153,0x9154,0x9155,0x9156,0x9157,
+ 0x9158,0x9159,0x915a,0x915b,0x915c,0x915d,0x915e,0x915f,
+ 0x9160,0x9161,0x9162,0x9163,0x9164,0x9165,0x9166,0x9167,
+ 0x9168,0x9169,0x916a,0x916b,0x916c,0x916d,0x916e,0x916f,
+ 0x9170,0x9171,0x9172,0x9173,0x9174,0x9175,0x9176,0x9177,
+ 0x9178,0x9179,0x917a,0x917b,0x917c,0x917d,0x917e,0x917f,
+ 0x9180,0x9181,0x9182,0x9183,0x9184,0x9185,0x9186,0x9187,
+ 0x9188,0x9189,0x918a,0x918b,0x918c,0x918d,0x918e,0x918f,
+ 0x9190,0x9191,0x9192,0x9193,0x9194,0x9195,0x9196,0x9197,
+ 0x9198,0x9199,0x919a,0x919b,0x919c,0x919d,0x919e,0x919f,
+ 0x91a0,0x91a1,0x91a2,0x91a3,0x91a4,0x91a5,0x91a6,0x91a7,
+ 0x91a8,0x91a9,0x91aa,0x91ab,0x91ac,0x91ad,0x91ae,0x91af,
+ 0x91b0,0x91b1,0x91b2,0x91b3,0x91b4,0x91b5,0x91b6,0x91b7,
+ 0x91b8,0x91b9,0x91ba,0x91bb,0x91bc,0x91bd,0x91be,0x91bf,
+ 0x91c0,0x91c1,0x91c2,0x91c3,0x91c4,0x91c5,0x91c6,0x91c7,
+ 0x91c8,0x91c9,0x91ca,0x91cb,0x91cc,0x91cd,0x91ce,0x91cf,
+ 0x91d0,0x91d1,0x91d2,0x91d3,0x91d4,0x91d5,0x91d6,0x91d7,
+ 0x91d8,0x91d9,0x91da,0x91db,0x91dc,0x91dd,0x91de,0x91df,
+ 0x91e0,0x91e1,0x91e2,0x91e3,0x91e4,0x91e5,0x91e6,0x91e7,
+ 0x91e8,0x91e9,0x91ea,0x91eb,0x91ec,0x91ed,0x91ee,0x91ef,
+ 0x91f0,0x91f1,0x91f2,0x91f3,0x91f4,0x91f5,0x91f6,0x91f7,
+ 0x91f8,0x91f9,0x91fa,0x91fb,0x91fc,0x91fd,0x91fe,0x91ff,
+ 0x9200,0x9201,0x9202,0x9203,0x9204,0x9205,0x9206,0x9207,
+ 0x9208,0x9209,0x920a,0x920b,0x920c,0x920d,0x920e,0x920f,
+ 0x9210,0x9211,0x9212,0x9213,0x9214,0x9215,0x9216,0x9217,
+ 0x9218,0x9219,0x921a,0x921b,0x921c,0x921d,0x921e,0x921f,
+ 0x9220,0x9221,0x9222,0x9223,0x9224,0x9225,0x9226,0x9227,
+ 0x9228,0x9229,0x922a,0x922b,0x922c,0x922d,0x922e,0x922f,
+ 0x9230,0x9231,0x9232,0x9233,0x9234,0x9235,0x9236,0x9237,
+ 0x9238,0x9239,0x923a,0x923b,0x923c,0x923d,0x923e,0x923f,
+ 0x9240,0x9241,0x9242,0x9243,0x9244,0x9245,0x9246,0x9247,
+ 0x9248,0x9249,0x924a,0x924b,0x924c,0x924d,0x924e,0x924f,
+ 0x9250,0x9251,0x9252,0x9253,0x9254,0x9255,0x9256,0x9257,
+ 0x9258,0x9259,0x925a,0x925b,0x925c,0x925d,0x925e,0x925f,
+ 0x9260,0x9261,0x9262,0x9263,0x9264,0x9265,0x9266,0x9267,
+ 0x9268,0x9269,0x926a,0x926b,0x926c,0x926d,0x926e,0x926f,
+ 0x9270,0x9271,0x9272,0x9273,0x9274,0x9275,0x9276,0x9277,
+ 0x9278,0x9279,0x927a,0x927b,0x927c,0x927d,0x927e,0x927f,
+ 0x9280,0x9281,0x9282,0x9283,0x9284,0x9285,0x9286,0x9287,
+ 0x9288,0x9289,0x928a,0x928b,0x928c,0x928d,0x928e,0x928f,
+ 0x9290,0x9291,0x9292,0x9293,0x9294,0x9295,0x9296,0x9297,
+ 0x9298,0x9299,0x929a,0x929b,0x929c,0x929d,0x929e,0x929f,
+ 0x92a0,0x92a1,0x92a2,0x92a3,0x92a4,0x92a5,0x92a6,0x92a7,
+ 0x92a8,0x92a9,0x92aa,0x92ab,0x92ac,0x92ad,0x92ae,0x92af,
+ 0x92b0,0x92b1,0x92b2,0x92b3,0x92b4,0x92b5,0x92b6,0x92b7,
+ 0x92b8,0x92b9,0x92ba,0x92bb,0x92bc,0x92bd,0x92be,0x92bf,
+ 0x92c0,0x92c1,0x92c2,0x92c3,0x92c4,0x92c5,0x92c6,0x92c7,
+ 0x92c8,0x92c9,0x92ca,0x92cb,0x92cc,0x92cd,0x92ce,0x92cf,
+ 0x92d0,0x92d1,0x92d2,0x92d3,0x92d4,0x92d5,0x92d6,0x92d7,
+ 0x92d8,0x92d9,0x92da,0x92db,0x92dc,0x92dd,0x92de,0x92df,
+ 0x92e0,0x92e1,0x92e2,0x92e3,0x92e4,0x92e5,0x92e6,0x92e7,
+ 0x92e8,0x92e9,0x92ea,0x92eb,0x92ec,0x92ed,0x92ee,0x92ef,
+ 0x92f0,0x92f1,0x92f2,0x92f3,0x92f4,0x92f5,0x92f6,0x92f7,
+ 0x92f8,0x92f9,0x92fa,0x92fb,0x92fc,0x92fd,0x92fe,0x92ff,
+ 0x9300,0x9301,0x9302,0x9303,0x9304,0x9305,0x9306,0x9307,
+ 0x9308,0x9309,0x930a,0x930b,0x930c,0x930d,0x930e,0x930f,
+ 0x9310,0x9311,0x9312,0x9313,0x9314,0x9315,0x9316,0x9317,
+ 0x9318,0x9319,0x931a,0x931b,0x931c,0x931d,0x931e,0x931f,
+ 0x9320,0x9321,0x9322,0x9323,0x9324,0x9325,0x9326,0x9327,
+ 0x9328,0x9329,0x932a,0x932b,0x932c,0x932d,0x932e,0x932f,
+ 0x9330,0x9331,0x9332,0x9333,0x9334,0x9335,0x9336,0x9337,
+ 0x9338,0x9339,0x933a,0x933b,0x933c,0x933d,0x933e,0x933f,
+ 0x9340,0x9341,0x9342,0x9343,0x9344,0x9345,0x9346,0x9347,
+ 0x9348,0x9349,0x934a,0x934b,0x934c,0x934d,0x934e,0x934f,
+ 0x9350,0x9351,0x9352,0x9353,0x9354,0x9355,0x9356,0x9357,
+ 0x9358,0x9359,0x935a,0x935b,0x935c,0x935d,0x935e,0x935f,
+ 0x9360,0x9361,0x9362,0x9363,0x9364,0x9365,0x9366,0x9367,
+ 0x9368,0x9369,0x936a,0x936b,0x936c,0x936d,0x936e,0x936f,
+ 0x9370,0x9371,0x9372,0x9373,0x9374,0x9375,0x9376,0x9377,
+ 0x9378,0x9379,0x937a,0x937b,0x937c,0x937d,0x937e,0x937f,
+ 0x9380,0x9381,0x9382,0x9383,0x9384,0x9385,0x9386,0x9387,
+ 0x9388,0x9389,0x938a,0x938b,0x938c,0x938d,0x938e,0x938f,
+ 0x9390,0x9391,0x9392,0x9393,0x9394,0x9395,0x9396,0x9397,
+ 0x9398,0x9399,0x939a,0x939b,0x939c,0x939d,0x939e,0x939f,
+ 0x93a0,0x93a1,0x93a2,0x93a3,0x93a4,0x93a5,0x93a6,0x93a7,
+ 0x93a8,0x93a9,0x93aa,0x93ab,0x93ac,0x93ad,0x93ae,0x93af,
+ 0x93b0,0x93b1,0x93b2,0x93b3,0x93b4,0x93b5,0x93b6,0x93b7,
+ 0x93b8,0x93b9,0x93ba,0x93bb,0x93bc,0x93bd,0x93be,0x93bf,
+ 0x93c0,0x93c1,0x93c2,0x93c3,0x93c4,0x93c5,0x93c6,0x93c7,
+ 0x93c8,0x93c9,0x93ca,0x93cb,0x93cc,0x93cd,0x93ce,0x93cf,
+ 0x93d0,0x93d1,0x93d2,0x93d3,0x93d4,0x93d5,0x93d6,0x93d7,
+ 0x93d8,0x93d9,0x93da,0x93db,0x93dc,0x93dd,0x93de,0x93df,
+ 0x93e0,0x93e1,0x93e2,0x93e3,0x93e4,0x93e5,0x93e6,0x93e7,
+ 0x93e8,0x93e9,0x93ea,0x93eb,0x93ec,0x93ed,0x93ee,0x93ef,
+ 0x93f0,0x93f1,0x93f2,0x93f3,0x93f4,0x93f5,0x93f6,0x93f7,
+ 0x93f8,0x93f9,0x93fa,0x93fb,0x93fc,0x93fd,0x93fe,0x93ff,
+ 0x9400,0x9401,0x9402,0x9403,0x9404,0x9405,0x9406,0x9407,
+ 0x9408,0x9409,0x940a,0x940b,0x940c,0x940d,0x940e,0x940f,
+ 0x9410,0x9411,0x9412,0x9413,0x9414,0x9415,0x9416,0x9417,
+ 0x9418,0x9419,0x941a,0x941b,0x941c,0x941d,0x941e,0x941f,
+ 0x9420,0x9421,0x9422,0x9423,0x9424,0x9425,0x9426,0x9427,
+ 0x9428,0x9429,0x942a,0x942b,0x942c,0x942d,0x942e,0x942f,
+ 0x9430,0x9431,0x9432,0x9433,0x9434,0x9435,0x9436,0x9437,
+ 0x9438,0x9439,0x943a,0x943b,0x943c,0x943d,0x943e,0x943f,
+ 0x9440,0x9441,0x9442,0x9443,0x9444,0x9445,0x9446,0x9447,
+ 0x9448,0x9449,0x944a,0x944b,0x944c,0x944d,0x944e,0x944f,
+ 0x9450,0x9451,0x9452,0x9453,0x9454,0x9455,0x9456,0x9457,
+ 0x9458,0x9459,0x945a,0x945b,0x945c,0x945d,0x945e,0x945f,
+ 0x9460,0x9461,0x9462,0x9463,0x9464,0x9465,0x9466,0x9467,
+ 0x9468,0x9469,0x946a,0x946b,0x946c,0x946d,0x946e,0x946f,
+ 0x9470,0x9471,0x9472,0x9473,0x9474,0x9475,0x9476,0x9477,
+ 0x9478,0x9479,0x947a,0x947b,0x947c,0x947d,0x947e,0x947f,
+ 0x9480,0x9481,0x9482,0x9483,0x9484,0x9485,0x9486,0x9487,
+ 0x9488,0x9489,0x948a,0x948b,0x948c,0x948d,0x948e,0x948f,
+ 0x9490,0x9491,0x9492,0x9493,0x9494,0x9495,0x9496,0x9497,
+ 0x9498,0x9499,0x949a,0x949b,0x949c,0x949d,0x949e,0x949f,
+ 0x94a0,0x94a1,0x94a2,0x94a3,0x94a4,0x94a5,0x94a6,0x94a7,
+ 0x94a8,0x94a9,0x94aa,0x94ab,0x94ac,0x94ad,0x94ae,0x94af,
+ 0x94b0,0x94b1,0x94b2,0x94b3,0x94b4,0x94b5,0x94b6,0x94b7,
+ 0x94b8,0x94b9,0x94ba,0x94bb,0x94bc,0x94bd,0x94be,0x94bf,
+ 0x94c0,0x94c1,0x94c2,0x94c3,0x94c4,0x94c5,0x94c6,0x94c7,
+ 0x94c8,0x94c9,0x94ca,0x94cb,0x94cc,0x94cd,0x94ce,0x94cf,
+ 0x94d0,0x94d1,0x94d2,0x94d3,0x94d4,0x94d5,0x94d6,0x94d7,
+ 0x94d8,0x94d9,0x94da,0x94db,0x94dc,0x94dd,0x94de,0x94df,
+ 0x94e0,0x94e1,0x94e2,0x94e3,0x94e4,0x94e5,0x94e6,0x94e7,
+ 0x94e8,0x94e9,0x94ea,0x94eb,0x94ec,0x94ed,0x94ee,0x94ef,
+ 0x94f0,0x94f1,0x94f2,0x94f3,0x94f4,0x94f5,0x94f6,0x94f7,
+ 0x94f8,0x94f9,0x94fa,0x94fb,0x94fc,0x94fd,0x94fe,0x94ff,
+ 0x9500,0x9501,0x9502,0x9503,0x9504,0x9505,0x9506,0x9507,
+ 0x9508,0x9509,0x950a,0x950b,0x950c,0x950d,0x950e,0x950f,
+ 0x9510,0x9511,0x9512,0x9513,0x9514,0x9515,0x9516,0x9517,
+ 0x9518,0x9519,0x951a,0x951b,0x951c,0x951d,0x951e,0x951f,
+ 0x9520,0x9521,0x9522,0x9523,0x9524,0x9525,0x9526,0x9527,
+ 0x9528,0x9529,0x952a,0x952b,0x952c,0x952d,0x952e,0x952f,
+ 0x9530,0x9531,0x9532,0x9533,0x9534,0x9535,0x9536,0x9537,
+ 0x9538,0x9539,0x953a,0x953b,0x953c,0x953d,0x953e,0x953f,
+ 0x9540,0x9541,0x9542,0x9543,0x9544,0x9545,0x9546,0x9547,
+ 0x9548,0x9549,0x954a,0x954b,0x954c,0x954d,0x954e,0x954f,
+ 0x9550,0x9551,0x9552,0x9553,0x9554,0x9555,0x9556,0x9557,
+ 0x9558,0x9559,0x955a,0x955b,0x955c,0x955d,0x955e,0x955f,
+ 0x9560,0x9561,0x9562,0x9563,0x9564,0x9565,0x9566,0x9567,
+ 0x9568,0x9569,0x956a,0x956b,0x956c,0x956d,0x956e,0x956f,
+ 0x9570,0x9571,0x9572,0x9573,0x9574,0x9575,0x9576,0x9577,
+ 0x9578,0x9579,0x957a,0x957b,0x957c,0x957d,0x957e,0x957f,
+ 0x9580,0x9581,0x9582,0x9583,0x9584,0x9585,0x9586,0x9587,
+ 0x9588,0x9589,0x958a,0x958b,0x958c,0x958d,0x958e,0x958f,
+ 0x9590,0x9591,0x9592,0x9593,0x9594,0x9595,0x9596,0x9597,
+ 0x9598,0x9599,0x959a,0x959b,0x959c,0x959d,0x959e,0x959f,
+ 0x95a0,0x95a1,0x95a2,0x95a3,0x95a4,0x95a5,0x95a6,0x95a7,
+ 0x95a8,0x95a9,0x95aa,0x95ab,0x95ac,0x95ad,0x95ae,0x95af,
+ 0x95b0,0x95b1,0x95b2,0x95b3,0x95b4,0x95b5,0x95b6,0x95b7,
+ 0x95b8,0x95b9,0x95ba,0x95bb,0x95bc,0x95bd,0x95be,0x95bf,
+ 0x95c0,0x95c1,0x95c2,0x95c3,0x95c4,0x95c5,0x95c6,0x95c7,
+ 0x95c8,0x95c9,0x95ca,0x95cb,0x95cc,0x95cd,0x95ce,0x95cf,
+ 0x95d0,0x95d1,0x95d2,0x95d3,0x95d4,0x95d5,0x95d6,0x95d7,
+ 0x95d8,0x95d9,0x95da,0x95db,0x95dc,0x95dd,0x95de,0x95df,
+ 0x95e0,0x95e1,0x95e2,0x95e3,0x95e4,0x95e5,0x95e6,0x95e7,
+ 0x95e8,0x95e9,0x95ea,0x95eb,0x95ec,0x95ed,0x95ee,0x95ef,
+ 0x95f0,0x95f1,0x95f2,0x95f3,0x95f4,0x95f5,0x95f6,0x95f7,
+ 0x95f8,0x95f9,0x95fa,0x95fb,0x95fc,0x95fd,0x95fe,0x95ff,
+ 0x9600,0x9601,0x9602,0x9603,0x9604,0x9605,0x9606,0x9607,
+ 0x9608,0x9609,0x960a,0x960b,0x960c,0x960d,0x960e,0x960f,
+ 0x9610,0x9611,0x9612,0x9613,0x9614,0x9615,0x9616,0x9617,
+ 0x9618,0x9619,0x961a,0x961b,0x961c,0x961d,0x961e,0x961f,
+ 0x9620,0x9621,0x9622,0x9623,0x9624,0x9625,0x9626,0x9627,
+ 0x9628,0x9629,0x962a,0x962b,0x962c,0x962d,0x962e,0x962f,
+ 0x9630,0x9631,0x9632,0x9633,0x9634,0x9635,0x9636,0x9637,
+ 0x9638,0x9639,0x963a,0x963b,0x963c,0x963d,0x963e,0x963f,
+ 0x9640,0x9641,0x9642,0x9643,0x9644,0x9645,0x9646,0x9647,
+ 0x9648,0x9649,0x964a,0x964b,0x964c,0x964d,0x964e,0x964f,
+ 0x9650,0x9651,0x9652,0x9653,0x9654,0x9655,0x9656,0x9657,
+ 0x9658,0x9659,0x965a,0x965b,0x965c,0x965d,0x965e,0x965f,
+ 0x9660,0x9661,0x9662,0x9663,0x9664,0x9665,0x9666,0x9667,
+ 0x9668,0x9669,0x966a,0x966b,0x966c,0x966d,0x966e,0x966f,
+ 0x9670,0x9671,0x9672,0x9673,0x9674,0x9675,0x9676,0x9677,
+ 0x9678,0x9679,0x967a,0x967b,0x967c,0x967d,0x967e,0x967f,
+ 0x9680,0x9681,0x9682,0x9683,0x9684,0x9685,0x9686,0x9687,
+ 0x9688,0x9689,0x968a,0x968b,0x968c,0x968d,0x968e,0x968f,
+ 0x9690,0x9691,0x9692,0x9693,0x9694,0x9695,0x9696,0x9697,
+ 0x9698,0x9699,0x969a,0x969b,0x969c,0x969d,0x969e,0x969f,
+ 0x96a0,0x96a1,0x96a2,0x96a3,0x96a4,0x96a5,0x96a6,0x96a7,
+ 0x96a8,0x96a9,0x96aa,0x96ab,0x96ac,0x96ad,0x96ae,0x96af,
+ 0x96b0,0x96b1,0x96b2,0x96b3,0x96b4,0x96b5,0x96b6,0x96b7,
+ 0x96b8,0x96b9,0x96ba,0x96bb,0x96bc,0x96bd,0x96be,0x96bf,
+ 0x96c0,0x96c1,0x96c2,0x96c3,0x96c4,0x96c5,0x96c6,0x96c7,
+ 0x96c8,0x96c9,0x96ca,0x96cb,0x96cc,0x96cd,0x96ce,0x96cf,
+ 0x96d0,0x96d1,0x96d2,0x96d3,0x96d4,0x96d5,0x96d6,0x96d7,
+ 0x96d8,0x96d9,0x96da,0x96db,0x96dc,0x96dd,0x96de,0x96df,
+ 0x96e0,0x96e1,0x96e2,0x96e3,0x96e4,0x96e5,0x96e6,0x96e7,
+ 0x96e8,0x96e9,0x96ea,0x96eb,0x96ec,0x96ed,0x96ee,0x96ef,
+ 0x96f0,0x96f1,0x96f2,0x96f3,0x96f4,0x96f5,0x96f6,0x96f7,
+ 0x96f8,0x96f9,0x96fa,0x96fb,0x96fc,0x96fd,0x96fe,0x96ff,
+ 0x9700,0x9701,0x9702,0x9703,0x9704,0x9705,0x9706,0x9707,
+ 0x9708,0x9709,0x970a,0x970b,0x970c,0x970d,0x970e,0x970f,
+ 0x9710,0x9711,0x9712,0x9713,0x9714,0x9715,0x9716,0x9717,
+ 0x9718,0x9719,0x971a,0x971b,0x971c,0x971d,0x971e,0x971f,
+ 0x9720,0x9721,0x9722,0x9723,0x9724,0x9725,0x9726,0x9727,
+ 0x9728,0x9729,0x972a,0x972b,0x972c,0x972d,0x972e,0x972f,
+ 0x9730,0x9731,0x9732,0x9733,0x9734,0x9735,0x9736,0x9737,
+ 0x9738,0x9739,0x973a,0x973b,0x973c,0x973d,0x973e,0x973f,
+ 0x9740,0x9741,0x9742,0x9743,0x9744,0x9745,0x9746,0x9747,
+ 0x9748,0x9749,0x974a,0x974b,0x974c,0x974d,0x974e,0x974f,
+ 0x9750,0x9751,0x9752,0x9753,0x9754,0x9755,0x9756,0x9757,
+ 0x9758,0x9759,0x975a,0x975b,0x975c,0x975d,0x975e,0x975f,
+ 0x9760,0x9761,0x9762,0x9763,0x9764,0x9765,0x9766,0x9767,
+ 0x9768,0x9769,0x976a,0x976b,0x976c,0x976d,0x976e,0x976f,
+ 0x9770,0x9771,0x9772,0x9773,0x9774,0x9775,0x9776,0x9777,
+ 0x9778,0x9779,0x977a,0x977b,0x977c,0x977d,0x977e,0x977f,
+ 0x9780,0x9781,0x9782,0x9783,0x9784,0x9785,0x9786,0x9787,
+ 0x9788,0x9789,0x978a,0x978b,0x978c,0x978d,0x978e,0x978f,
+ 0x9790,0x9791,0x9792,0x9793,0x9794,0x9795,0x9796,0x9797,
+ 0x9798,0x9799,0x979a,0x979b,0x979c,0x979d,0x979e,0x979f,
+ 0x97a0,0x97a1,0x97a2,0x97a3,0x97a4,0x97a5,0x97a6,0x97a7,
+ 0x97a8,0x97a9,0x97aa,0x97ab,0x97ac,0x97ad,0x97ae,0x97af,
+ 0x97b0,0x97b1,0x97b2,0x97b3,0x97b4,0x97b5,0x97b6,0x97b7,
+ 0x97b8,0x97b9,0x97ba,0x97bb,0x97bc,0x97bd,0x97be,0x97bf,
+ 0x97c0,0x97c1,0x97c2,0x97c3,0x97c4,0x97c5,0x97c6,0x97c7,
+ 0x97c8,0x97c9,0x97ca,0x97cb,0x97cc,0x97cd,0x97ce,0x97cf,
+ 0x97d0,0x97d1,0x97d2,0x97d3,0x97d4,0x97d5,0x97d6,0x97d7,
+ 0x97d8,0x97d9,0x97da,0x97db,0x97dc,0x97dd,0x97de,0x97df,
+ 0x97e0,0x97e1,0x97e2,0x97e3,0x97e4,0x97e5,0x97e6,0x97e7,
+ 0x97e8,0x97e9,0x97ea,0x97eb,0x97ec,0x97ed,0x97ee,0x97ef,
+ 0x97f0,0x97f1,0x97f2,0x97f3,0x97f4,0x97f5,0x97f6,0x97f7,
+ 0x97f8,0x97f9,0x97fa,0x97fb,0x97fc,0x97fd,0x97fe,0x97ff,
+ 0x9800,0x9801,0x9802,0x9803,0x9804,0x9805,0x9806,0x9807,
+ 0x9808,0x9809,0x980a,0x980b,0x980c,0x980d,0x980e,0x980f,
+ 0x9810,0x9811,0x9812,0x9813,0x9814,0x9815,0x9816,0x9817,
+ 0x9818,0x9819,0x981a,0x981b,0x981c,0x981d,0x981e,0x981f,
+ 0x9820,0x9821,0x9822,0x9823,0x9824,0x9825,0x9826,0x9827,
+ 0x9828,0x9829,0x982a,0x982b,0x982c,0x982d,0x982e,0x982f,
+ 0x9830,0x9831,0x9832,0x9833,0x9834,0x9835,0x9836,0x9837,
+ 0x9838,0x9839,0x983a,0x983b,0x983c,0x983d,0x983e,0x983f,
+ 0x9840,0x9841,0x9842,0x9843,0x9844,0x9845,0x9846,0x9847,
+ 0x9848,0x9849,0x984a,0x984b,0x984c,0x984d,0x984e,0x984f,
+ 0x9850,0x9851,0x9852,0x9853,0x9854,0x9855,0x9856,0x9857,
+ 0x9858,0x9859,0x985a,0x985b,0x985c,0x985d,0x985e,0x985f,
+ 0x9860,0x9861,0x9862,0x9863,0x9864,0x9865,0x9866,0x9867,
+ 0x9868,0x9869,0x986a,0x986b,0x986c,0x986d,0x986e,0x986f,
+ 0x9870,0x9871,0x9872,0x9873,0x9874,0x9875,0x9876,0x9877,
+ 0x9878,0x9879,0x987a,0x987b,0x987c,0x987d,0x987e,0x987f,
+ 0x9880,0x9881,0x9882,0x9883,0x9884,0x9885,0x9886,0x9887,
+ 0x9888,0x9889,0x988a,0x988b,0x988c,0x988d,0x988e,0x988f,
+ 0x9890,0x9891,0x9892,0x9893,0x9894,0x9895,0x9896,0x9897,
+ 0x9898,0x9899,0x989a,0x989b,0x989c,0x989d,0x989e,0x989f,
+ 0x98a0,0x98a1,0x98a2,0x98a3,0x98a4,0x98a5,0x98a6,0x98a7,
+ 0x98a8,0x98a9,0x98aa,0x98ab,0x98ac,0x98ad,0x98ae,0x98af,
+ 0x98b0,0x98b1,0x98b2,0x98b3,0x98b4,0x98b5,0x98b6,0x98b7,
+ 0x98b8,0x98b9,0x98ba,0x98bb,0x98bc,0x98bd,0x98be,0x98bf,
+ 0x98c0,0x98c1,0x98c2,0x98c3,0x98c4,0x98c5,0x98c6,0x98c7,
+ 0x98c8,0x98c9,0x98ca,0x98cb,0x98cc,0x98cd,0x98ce,0x98cf,
+ 0x98d0,0x98d1,0x98d2,0x98d3,0x98d4,0x98d5,0x98d6,0x98d7,
+ 0x98d8,0x98d9,0x98da,0x98db,0x98dc,0x98dd,0x98de,0x98df,
+ 0x98e0,0x98e1,0x98e2,0x98e3,0x98e4,0x98e5,0x98e6,0x98e7,
+ 0x98e8,0x98e9,0x98ea,0x98eb,0x98ec,0x98ed,0x98ee,0x98ef,
+ 0x98f0,0x98f1,0x98f2,0x98f3,0x98f4,0x98f5,0x98f6,0x98f7,
+ 0x98f8,0x98f9,0x98fa,0x98fb,0x98fc,0x98fd,0x98fe,0x98ff,
+ 0x9900,0x9901,0x9902,0x9903,0x9904,0x9905,0x9906,0x9907,
+ 0x9908,0x9909,0x990a,0x990b,0x990c,0x990d,0x990e,0x990f,
+ 0x9910,0x9911,0x9912,0x9913,0x9914,0x9915,0x9916,0x9917,
+ 0x9918,0x9919,0x991a,0x991b,0x991c,0x991d,0x991e,0x991f,
+ 0x9920,0x9921,0x9922,0x9923,0x9924,0x9925,0x9926,0x9927,
+ 0x9928,0x9929,0x992a,0x992b,0x992c,0x992d,0x992e,0x992f,
+ 0x9930,0x9931,0x9932,0x9933,0x9934,0x9935,0x9936,0x9937,
+ 0x9938,0x9939,0x993a,0x993b,0x993c,0x993d,0x993e,0x993f,
+ 0x9940,0x9941,0x9942,0x9943,0x9944,0x9945,0x9946,0x9947,
+ 0x9948,0x9949,0x994a,0x994b,0x994c,0x994d,0x994e,0x994f,
+ 0x9950,0x9951,0x9952,0x9953,0x9954,0x9955,0x9956,0x9957,
+ 0x9958,0x9959,0x995a,0x995b,0x995c,0x995d,0x995e,0x995f,
+ 0x9960,0x9961,0x9962,0x9963,0x9964,0x9965,0x9966,0x9967,
+ 0x9968,0x9969,0x996a,0x996b,0x996c,0x996d,0x996e,0x996f,
+ 0x9970,0x9971,0x9972,0x9973,0x9974,0x9975,0x9976,0x9977,
+ 0x9978,0x9979,0x997a,0x997b,0x997c,0x997d,0x997e,0x997f,
+ 0x9980,0x9981,0x9982,0x9983,0x9984,0x9985,0x9986,0x9987,
+ 0x9988,0x9989,0x998a,0x998b,0x998c,0x998d,0x998e,0x998f,
+ 0x9990,0x9991,0x9992,0x9993,0x9994,0x9995,0x9996,0x9997,
+ 0x9998,0x9999,0x999a,0x999b,0x999c,0x999d,0x999e,0x999f,
+ 0x99a0,0x99a1,0x99a2,0x99a3,0x99a4,0x99a5,0x99a6,0x99a7,
+ 0x99a8,0x99a9,0x99aa,0x99ab,0x99ac,0x99ad,0x99ae,0x99af,
+ 0x99b0,0x99b1,0x99b2,0x99b3,0x99b4,0x99b5,0x99b6,0x99b7,
+ 0x99b8,0x99b9,0x99ba,0x99bb,0x99bc,0x99bd,0x99be,0x99bf,
+ 0x99c0,0x99c1,0x99c2,0x99c3,0x99c4,0x99c5,0x99c6,0x99c7,
+ 0x99c8,0x99c9,0x99ca,0x99cb,0x99cc,0x99cd,0x99ce,0x99cf,
+ 0x99d0,0x99d1,0x99d2,0x99d3,0x99d4,0x99d5,0x99d6,0x99d7,
+ 0x99d8,0x99d9,0x99da,0x99db,0x99dc,0x99dd,0x99de,0x99df,
+ 0x99e0,0x99e1,0x99e2,0x99e3,0x99e4,0x99e5,0x99e6,0x99e7,
+ 0x99e8,0x99e9,0x99ea,0x99eb,0x99ec,0x99ed,0x99ee,0x99ef,
+ 0x99f0,0x99f1,0x99f2,0x99f3,0x99f4,0x99f5,0x99f6,0x99f7,
+ 0x99f8,0x99f9,0x99fa,0x99fb,0x99fc,0x99fd,0x99fe,0x99ff,
+ 0x9a00,0x9a01,0x9a02,0x9a03,0x9a04,0x9a05,0x9a06,0x9a07,
+ 0x9a08,0x9a09,0x9a0a,0x9a0b,0x9a0c,0x9a0d,0x9a0e,0x9a0f,
+ 0x9a10,0x9a11,0x9a12,0x9a13,0x9a14,0x9a15,0x9a16,0x9a17,
+ 0x9a18,0x9a19,0x9a1a,0x9a1b,0x9a1c,0x9a1d,0x9a1e,0x9a1f,
+ 0x9a20,0x9a21,0x9a22,0x9a23,0x9a24,0x9a25,0x9a26,0x9a27,
+ 0x9a28,0x9a29,0x9a2a,0x9a2b,0x9a2c,0x9a2d,0x9a2e,0x9a2f,
+ 0x9a30,0x9a31,0x9a32,0x9a33,0x9a34,0x9a35,0x9a36,0x9a37,
+ 0x9a38,0x9a39,0x9a3a,0x9a3b,0x9a3c,0x9a3d,0x9a3e,0x9a3f,
+ 0x9a40,0x9a41,0x9a42,0x9a43,0x9a44,0x9a45,0x9a46,0x9a47,
+ 0x9a48,0x9a49,0x9a4a,0x9a4b,0x9a4c,0x9a4d,0x9a4e,0x9a4f,
+ 0x9a50,0x9a51,0x9a52,0x9a53,0x9a54,0x9a55,0x9a56,0x9a57,
+ 0x9a58,0x9a59,0x9a5a,0x9a5b,0x9a5c,0x9a5d,0x9a5e,0x9a5f,
+ 0x9a60,0x9a61,0x9a62,0x9a63,0x9a64,0x9a65,0x9a66,0x9a67,
+ 0x9a68,0x9a69,0x9a6a,0x9a6b,0x9a6c,0x9a6d,0x9a6e,0x9a6f,
+ 0x9a70,0x9a71,0x9a72,0x9a73,0x9a74,0x9a75,0x9a76,0x9a77,
+ 0x9a78,0x9a79,0x9a7a,0x9a7b,0x9a7c,0x9a7d,0x9a7e,0x9a7f,
+ 0x9a80,0x9a81,0x9a82,0x9a83,0x9a84,0x9a85,0x9a86,0x9a87,
+ 0x9a88,0x9a89,0x9a8a,0x9a8b,0x9a8c,0x9a8d,0x9a8e,0x9a8f,
+ 0x9a90,0x9a91,0x9a92,0x9a93,0x9a94,0x9a95,0x9a96,0x9a97,
+ 0x9a98,0x9a99,0x9a9a,0x9a9b,0x9a9c,0x9a9d,0x9a9e,0x9a9f,
+ 0x9aa0,0x9aa1,0x9aa2,0x9aa3,0x9aa4,0x9aa5,0x9aa6,0x9aa7,
+ 0x9aa8,0x9aa9,0x9aaa,0x9aab,0x9aac,0x9aad,0x9aae,0x9aaf,
+ 0x9ab0,0x9ab1,0x9ab2,0x9ab3,0x9ab4,0x9ab5,0x9ab6,0x9ab7,
+ 0x9ab8,0x9ab9,0x9aba,0x9abb,0x9abc,0x9abd,0x9abe,0x9abf,
+ 0x9ac0,0x9ac1,0x9ac2,0x9ac3,0x9ac4,0x9ac5,0x9ac6,0x9ac7,
+ 0x9ac8,0x9ac9,0x9aca,0x9acb,0x9acc,0x9acd,0x9ace,0x9acf,
+ 0x9ad0,0x9ad1,0x9ad2,0x9ad3,0x9ad4,0x9ad5,0x9ad6,0x9ad7,
+ 0x9ad8,0x9ad9,0x9ada,0x9adb,0x9adc,0x9add,0x9ade,0x9adf,
+ 0x9ae0,0x9ae1,0x9ae2,0x9ae3,0x9ae4,0x9ae5,0x9ae6,0x9ae7,
+ 0x9ae8,0x9ae9,0x9aea,0x9aeb,0x9aec,0x9aed,0x9aee,0x9aef,
+ 0x9af0,0x9af1,0x9af2,0x9af3,0x9af4,0x9af5,0x9af6,0x9af7,
+ 0x9af8,0x9af9,0x9afa,0x9afb,0x9afc,0x9afd,0x9afe,0x9aff,
+ 0x9b00,0x9b01,0x9b02,0x9b03,0x9b04,0x9b05,0x9b06,0x9b07,
+ 0x9b08,0x9b09,0x9b0a,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b0f,
+ 0x9b10,0x9b11,0x9b12,0x9b13,0x9b14,0x9b15,0x9b16,0x9b17,
+ 0x9b18,0x9b19,0x9b1a,0x9b1b,0x9b1c,0x9b1d,0x9b1e,0x9b1f,
+ 0x9b20,0x9b21,0x9b22,0x9b23,0x9b24,0x9b25,0x9b26,0x9b27,
+ 0x9b28,0x9b29,0x9b2a,0x9b2b,0x9b2c,0x9b2d,0x9b2e,0x9b2f,
+ 0x9b30,0x9b31,0x9b32,0x9b33,0x9b34,0x9b35,0x9b36,0x9b37,
+ 0x9b38,0x9b39,0x9b3a,0x9b3b,0x9b3c,0x9b3d,0x9b3e,0x9b3f,
+ 0x9b40,0x9b41,0x9b42,0x9b43,0x9b44,0x9b45,0x9b46,0x9b47,
+ 0x9b48,0x9b49,0x9b4a,0x9b4b,0x9b4c,0x9b4d,0x9b4e,0x9b4f,
+ 0x9b50,0x9b51,0x9b52,0x9b53,0x9b54,0x9b55,0x9b56,0x9b57,
+ 0x9b58,0x9b59,0x9b5a,0x9b5b,0x9b5c,0x9b5d,0x9b5e,0x9b5f,
+ 0x9b60,0x9b61,0x9b62,0x9b63,0x9b64,0x9b65,0x9b66,0x9b67,
+ 0x9b68,0x9b69,0x9b6a,0x9b6b,0x9b6c,0x9b6d,0x9b6e,0x9b6f,
+ 0x9b70,0x9b71,0x9b72,0x9b73,0x9b74,0x9b75,0x9b76,0x9b77,
+ 0x9b78,0x9b79,0x9b7a,0x9b7b,0x9b7c,0x9b7d,0x9b7e,0x9b7f,
+ 0x9b80,0x9b81,0x9b82,0x9b83,0x9b84,0x9b85,0x9b86,0x9b87,
+ 0x9b88,0x9b89,0x9b8a,0x9b8b,0x9b8c,0x9b8d,0x9b8e,0x9b8f,
+ 0x9b90,0x9b91,0x9b92,0x9b93,0x9b94,0x9b95,0x9b96,0x9b97,
+ 0x9b98,0x9b99,0x9b9a,0x9b9b,0x9b9c,0x9b9d,0x9b9e,0x9b9f,
+ 0x9ba0,0x9ba1,0x9ba2,0x9ba3,0x9ba4,0x9ba5,0x9ba6,0x9ba7,
+ 0x9ba8,0x9ba9,0x9baa,0x9bab,0x9bac,0x9bad,0x9bae,0x9baf,
+ 0x9bb0,0x9bb1,0x9bb2,0x9bb3,0x9bb4,0x9bb5,0x9bb6,0x9bb7,
+ 0x9bb8,0x9bb9,0x9bba,0x9bbb,0x9bbc,0x9bbd,0x9bbe,0x9bbf,
+ 0x9bc0,0x9bc1,0x9bc2,0x9bc3,0x9bc4,0x9bc5,0x9bc6,0x9bc7,
+ 0x9bc8,0x9bc9,0x9bca,0x9bcb,0x9bcc,0x9bcd,0x9bce,0x9bcf,
+ 0x9bd0,0x9bd1,0x9bd2,0x9bd3,0x9bd4,0x9bd5,0x9bd6,0x9bd7,
+ 0x9bd8,0x9bd9,0x9bda,0x9bdb,0x9bdc,0x9bdd,0x9bde,0x9bdf,
+ 0x9be0,0x9be1,0x9be2,0x9be3,0x9be4,0x9be5,0x9be6,0x9be7,
+ 0x9be8,0x9be9,0x9bea,0x9beb,0x9bec,0x9bed,0x9bee,0x9bef,
+ 0x9bf0,0x9bf1,0x9bf2,0x9bf3,0x9bf4,0x9bf5,0x9bf6,0x9bf7,
+ 0x9bf8,0x9bf9,0x9bfa,0x9bfb,0x9bfc,0x9bfd,0x9bfe,0x9bff,
+ 0x9c00,0x9c01,0x9c02,0x9c03,0x9c04,0x9c05,0x9c06,0x9c07,
+ 0x9c08,0x9c09,0x9c0a,0x9c0b,0x9c0c,0x9c0d,0x9c0e,0x9c0f,
+ 0x9c10,0x9c11,0x9c12,0x9c13,0x9c14,0x9c15,0x9c16,0x9c17,
+ 0x9c18,0x9c19,0x9c1a,0x9c1b,0x9c1c,0x9c1d,0x9c1e,0x9c1f,
+ 0x9c20,0x9c21,0x9c22,0x9c23,0x9c24,0x9c25,0x9c26,0x9c27,
+ 0x9c28,0x9c29,0x9c2a,0x9c2b,0x9c2c,0x9c2d,0x9c2e,0x9c2f,
+ 0x9c30,0x9c31,0x9c32,0x9c33,0x9c34,0x9c35,0x9c36,0x9c37,
+ 0x9c38,0x9c39,0x9c3a,0x9c3b,0x9c3c,0x9c3d,0x9c3e,0x9c3f,
+ 0x9c40,0x9c41,0x9c42,0x9c43,0x9c44,0x9c45,0x9c46,0x9c47,
+ 0x9c48,0x9c49,0x9c4a,0x9c4b,0x9c4c,0x9c4d,0x9c4e,0x9c4f,
+ 0x9c50,0x9c51,0x9c52,0x9c53,0x9c54,0x9c55,0x9c56,0x9c57,
+ 0x9c58,0x9c59,0x9c5a,0x9c5b,0x9c5c,0x9c5d,0x9c5e,0x9c5f,
+ 0x9c60,0x9c61,0x9c62,0x9c63,0x9c64,0x9c65,0x9c66,0x9c67,
+ 0x9c68,0x9c69,0x9c6a,0x9c6b,0x9c6c,0x9c6d,0x9c6e,0x9c6f,
+ 0x9c70,0x9c71,0x9c72,0x9c73,0x9c74,0x9c75,0x9c76,0x9c77,
+ 0x9c78,0x9c79,0x9c7a,0x9c7b,0x9c7c,0x9c7d,0x9c7e,0x9c7f,
+ 0x9c80,0x9c81,0x9c82,0x9c83,0x9c84,0x9c85,0x9c86,0x9c87,
+ 0x9c88,0x9c89,0x9c8a,0x9c8b,0x9c8c,0x9c8d,0x9c8e,0x9c8f,
+ 0x9c90,0x9c91,0x9c92,0x9c93,0x9c94,0x9c95,0x9c96,0x9c97,
+ 0x9c98,0x9c99,0x9c9a,0x9c9b,0x9c9c,0x9c9d,0x9c9e,0x9c9f,
+ 0x9ca0,0x9ca1,0x9ca2,0x9ca3,0x9ca4,0x9ca5,0x9ca6,0x9ca7,
+ 0x9ca8,0x9ca9,0x9caa,0x9cab,0x9cac,0x9cad,0x9cae,0x9caf,
+ 0x9cb0,0x9cb1,0x9cb2,0x9cb3,0x9cb4,0x9cb5,0x9cb6,0x9cb7,
+ 0x9cb8,0x9cb9,0x9cba,0x9cbb,0x9cbc,0x9cbd,0x9cbe,0x9cbf,
+ 0x9cc0,0x9cc1,0x9cc2,0x9cc3,0x9cc4,0x9cc5,0x9cc6,0x9cc7,
+ 0x9cc8,0x9cc9,0x9cca,0x9ccb,0x9ccc,0x9ccd,0x9cce,0x9ccf,
+ 0x9cd0,0x9cd1,0x9cd2,0x9cd3,0x9cd4,0x9cd5,0x9cd6,0x9cd7,
+ 0x9cd8,0x9cd9,0x9cda,0x9cdb,0x9cdc,0x9cdd,0x9cde,0x9cdf,
+ 0x9ce0,0x9ce1,0x9ce2,0x9ce3,0x9ce4,0x9ce5,0x9ce6,0x9ce7,
+ 0x9ce8,0x9ce9,0x9cea,0x9ceb,0x9cec,0x9ced,0x9cee,0x9cef,
+ 0x9cf0,0x9cf1,0x9cf2,0x9cf3,0x9cf4,0x9cf5,0x9cf6,0x9cf7,
+ 0x9cf8,0x9cf9,0x9cfa,0x9cfb,0x9cfc,0x9cfd,0x9cfe,0x9cff,
+ 0x9d00,0x9d01,0x9d02,0x9d03,0x9d04,0x9d05,0x9d06,0x9d07,
+ 0x9d08,0x9d09,0x9d0a,0x9d0b,0x9d0c,0x9d0d,0x9d0e,0x9d0f,
+ 0x9d10,0x9d11,0x9d12,0x9d13,0x9d14,0x9d15,0x9d16,0x9d17,
+ 0x9d18,0x9d19,0x9d1a,0x9d1b,0x9d1c,0x9d1d,0x9d1e,0x9d1f,
+ 0x9d20,0x9d21,0x9d22,0x9d23,0x9d24,0x9d25,0x9d26,0x9d27,
+ 0x9d28,0x9d29,0x9d2a,0x9d2b,0x9d2c,0x9d2d,0x9d2e,0x9d2f,
+ 0x9d30,0x9d31,0x9d32,0x9d33,0x9d34,0x9d35,0x9d36,0x9d37,
+ 0x9d38,0x9d39,0x9d3a,0x9d3b,0x9d3c,0x9d3d,0x9d3e,0x9d3f,
+ 0x9d40,0x9d41,0x9d42,0x9d43,0x9d44,0x9d45,0x9d46,0x9d47,
+ 0x9d48,0x9d49,0x9d4a,0x9d4b,0x9d4c,0x9d4d,0x9d4e,0x9d4f,
+ 0x9d50,0x9d51,0x9d52,0x9d53,0x9d54,0x9d55,0x9d56,0x9d57,
+ 0x9d58,0x9d59,0x9d5a,0x9d5b,0x9d5c,0x9d5d,0x9d5e,0x9d5f,
+ 0x9d60,0x9d61,0x9d62,0x9d63,0x9d64,0x9d65,0x9d66,0x9d67,
+ 0x9d68,0x9d69,0x9d6a,0x9d6b,0x9d6c,0x9d6d,0x9d6e,0x9d6f,
+ 0x9d70,0x9d71,0x9d72,0x9d73,0x9d74,0x9d75,0x9d76,0x9d77,
+ 0x9d78,0x9d79,0x9d7a,0x9d7b,0x9d7c,0x9d7d,0x9d7e,0x9d7f,
+ 0x9d80,0x9d81,0x9d82,0x9d83,0x9d84,0x9d85,0x9d86,0x9d87,
+ 0x9d88,0x9d89,0x9d8a,0x9d8b,0x9d8c,0x9d8d,0x9d8e,0x9d8f,
+ 0x9d90,0x9d91,0x9d92,0x9d93,0x9d94,0x9d95,0x9d96,0x9d97,
+ 0x9d98,0x9d99,0x9d9a,0x9d9b,0x9d9c,0x9d9d,0x9d9e,0x9d9f,
+ 0x9da0,0x9da1,0x9da2,0x9da3,0x9da4,0x9da5,0x9da6,0x9da7,
+ 0x9da8,0x9da9,0x9daa,0x9dab,0x9dac,0x9dad,0x9dae,0x9daf,
+ 0x9db0,0x9db1,0x9db2,0x9db3,0x9db4,0x9db5,0x9db6,0x9db7,
+ 0x9db8,0x9db9,0x9dba,0x9dbb,0x9dbc,0x9dbd,0x9dbe,0x9dbf,
+ 0x9dc0,0x9dc1,0x9dc2,0x9dc3,0x9dc4,0x9dc5,0x9dc6,0x9dc7,
+ 0x9dc8,0x9dc9,0x9dca,0x9dcb,0x9dcc,0x9dcd,0x9dce,0x9dcf,
+ 0x9dd0,0x9dd1,0x9dd2,0x9dd3,0x9dd4,0x9dd5,0x9dd6,0x9dd7,
+ 0x9dd8,0x9dd9,0x9dda,0x9ddb,0x9ddc,0x9ddd,0x9dde,0x9ddf,
+ 0x9de0,0x9de1,0x9de2,0x9de3,0x9de4,0x9de5,0x9de6,0x9de7,
+ 0x9de8,0x9de9,0x9dea,0x9deb,0x9dec,0x9ded,0x9dee,0x9def,
+ 0x9df0,0x9df1,0x9df2,0x9df3,0x9df4,0x9df5,0x9df6,0x9df7,
+ 0x9df8,0x9df9,0x9dfa,0x9dfb,0x9dfc,0x9dfd,0x9dfe,0x9dff,
+ 0x9e00,0x9e01,0x9e02,0x9e03,0x9e04,0x9e05,0x9e06,0x9e07,
+ 0x9e08,0x9e09,0x9e0a,0x9e0b,0x9e0c,0x9e0d,0x9e0e,0x9e0f,
+ 0x9e10,0x9e11,0x9e12,0x9e13,0x9e14,0x9e15,0x9e16,0x9e17,
+ 0x9e18,0x9e19,0x9e1a,0x9e1b,0x9e1c,0x9e1d,0x9e1e,0x9e1f,
+ 0x9e20,0x9e21,0x9e22,0x9e23,0x9e24,0x9e25,0x9e26,0x9e27,
+ 0x9e28,0x9e29,0x9e2a,0x9e2b,0x9e2c,0x9e2d,0x9e2e,0x9e2f,
+ 0x9e30,0x9e31,0x9e32,0x9e33,0x9e34,0x9e35,0x9e36,0x9e37,
+ 0x9e38,0x9e39,0x9e3a,0x9e3b,0x9e3c,0x9e3d,0x9e3e,0x9e3f,
+ 0x9e40,0x9e41,0x9e42,0x9e43,0x9e44,0x9e45,0x9e46,0x9e47,
+ 0x9e48,0x9e49,0x9e4a,0x9e4b,0x9e4c,0x9e4d,0x9e4e,0x9e4f,
+ 0x9e50,0x9e51,0x9e52,0x9e53,0x9e54,0x9e55,0x9e56,0x9e57,
+ 0x9e58,0x9e59,0x9e5a,0x9e5b,0x9e5c,0x9e5d,0x9e5e,0x9e5f,
+ 0x9e60,0x9e61,0x9e62,0x9e63,0x9e64,0x9e65,0x9e66,0x9e67,
+ 0x9e68,0x9e69,0x9e6a,0x9e6b,0x9e6c,0x9e6d,0x9e6e,0x9e6f,
+ 0x9e70,0x9e71,0x9e72,0x9e73,0x9e74,0x9e75,0x9e76,0x9e77,
+ 0x9e78,0x9e79,0x9e7a,0x9e7b,0x9e7c,0x9e7d,0x9e7e,0x9e7f,
+ 0x9e80,0x9e81,0x9e82,0x9e83,0x9e84,0x9e85,0x9e86,0x9e87,
+ 0x9e88,0x9e89,0x9e8a,0x9e8b,0x9e8c,0x9e8d,0x9e8e,0x9e8f,
+ 0x9e90,0x9e91,0x9e92,0x9e93,0x9e94,0x9e95,0x9e96,0x9e97,
+ 0x9e98,0x9e99,0x9e9a,0x9e9b,0x9e9c,0x9e9d,0x9e9e,0x9e9f,
+ 0x9ea0,0x9ea1,0x9ea2,0x9ea3,0x9ea4,0x9ea5,0x9ea6,0x9ea7,
+ 0x9ea8,0x9ea9,0x9eaa,0x9eab,0x9eac,0x9ead,0x9eae,0x9eaf,
+ 0x9eb0,0x9eb1,0x9eb2,0x9eb3,0x9eb4,0x9eb5,0x9eb6,0x9eb7,
+ 0x9eb8,0x9eb9,0x9eba,0x9ebb,0x9ebc,0x9ebd,0x9ebe,0x9ebf,
+ 0x9ec0,0x9ec1,0x9ec2,0x9ec3,0x9ec4,0x9ec5,0x9ec6,0x9ec7,
+ 0x9ec8,0x9ec9,0x9eca,0x9ecb,0x9ecc,0x9ecd,0x9ece,0x9ecf,
+ 0x9ed0,0x9ed1,0x9ed2,0x9ed3,0x9ed4,0x9ed5,0x9ed6,0x9ed7,
+ 0x9ed8,0x9ed9,0x9eda,0x9edb,0x9edc,0x9edd,0x9ede,0x9edf,
+ 0x9ee0,0x9ee1,0x9ee2,0x9ee3,0x9ee4,0x9ee5,0x9ee6,0x9ee7,
+ 0x9ee8,0x9ee9,0x9eea,0x9eeb,0x9eec,0x9eed,0x9eee,0x9eef,
+ 0x9ef0,0x9ef1,0x9ef2,0x9ef3,0x9ef4,0x9ef5,0x9ef6,0x9ef7,
+ 0x9ef8,0x9ef9,0x9efa,0x9efb,0x9efc,0x9efd,0x9efe,0x9eff,
+ 0x9f00,0x9f01,0x9f02,0x9f03,0x9f04,0x9f05,0x9f06,0x9f07,
+ 0x9f08,0x9f09,0x9f0a,0x9f0b,0x9f0c,0x9f0d,0x9f0e,0x9f0f,
+ 0x9f10,0x9f11,0x9f12,0x9f13,0x9f14,0x9f15,0x9f16,0x9f17,
+ 0x9f18,0x9f19,0x9f1a,0x9f1b,0x9f1c,0x9f1d,0x9f1e,0x9f1f,
+ 0x9f20,0x9f21,0x9f22,0x9f23,0x9f24,0x9f25,0x9f26,0x9f27,
+ 0x9f28,0x9f29,0x9f2a,0x9f2b,0x9f2c,0x9f2d,0x9f2e,0x9f2f,
+ 0x9f30,0x9f31,0x9f32,0x9f33,0x9f34,0x9f35,0x9f36,0x9f37,
+ 0x9f38,0x9f39,0x9f3a,0x9f3b,0x9f3c,0x9f3d,0x9f3e,0x9f3f,
+ 0x9f40,0x9f41,0x9f42,0x9f43,0x9f44,0x9f45,0x9f46,0x9f47,
+ 0x9f48,0x9f49,0x9f4a,0x9f4b,0x9f4c,0x9f4d,0x9f4e,0x9f4f,
+ 0x9f50,0x9f51,0x9f52,0x9f53,0x9f54,0x9f55,0x9f56,0x9f57,
+ 0x9f58,0x9f59,0x9f5a,0x9f5b,0x9f5c,0x9f5d,0x9f5e,0x9f5f,
+ 0x9f60,0x9f61,0x9f62,0x9f63,0x9f64,0x9f65,0x9f66,0x9f67,
+ 0x9f68,0x9f69,0x9f6a,0x9f6b,0x9f6c,0x9f6d,0x9f6e,0x9f6f,
+ 0x9f70,0x9f71,0x9f72,0x9f73,0x9f74,0x9f75,0x9f76,0x9f77,
+ 0x9f78,0x9f79,0x9f7a,0x9f7b,0x9f7c,0x9f7d,0x9f7e,0x9f7f,
+ 0x9f80,0x9f81,0x9f82,0x9f83,0x9f84,0x9f85,0x9f86,0x9f87,
+ 0x9f88,0x9f89,0x9f8a,0x9f8b,0x9f8c,0x9f8d,0x9f8e,0x9f8f,
+ 0x9f90,0x9f91,0x9f92,0x9f93,0x9f94,0x9f95,0x9f96,0x9f97,
+ 0x9f98,0x9f99,0x9f9a,0x9f9b,0x9f9c,0x9f9d,0x9f9e,0x9f9f,
+ 0x9fa0,0x9fa1,0x9fa2,0x9fa3,0x9fa4,0x9fa5,0x9fa6,0x9fa7,
+ 0x9fa8,0x9fa9,0x9faa,0x9fab,0x9fac,0x9fad,0x9fae,0x9faf,
+ 0x9fb0,0x9fb1,0x9fb2,0x9fb3,0x9fb4,0x9fb5,0x9fb6,0x9fb7,
+ 0x9fb8,0x9fb9,0x9fba,0x9fbb,0x9fbc,0x9fbd,0x9fbe,0x9fbf,
+ 0x9fc0,0x9fc1,0x9fc2,0x9fc3,0x9fc4,0x9fc5,0x9fc6,0x9fc7,
+ 0x9fc8,0x9fc9,0x9fca,0x9fcb,0x9fcc,0x9fcd,0x9fce,0x9fcf,
+ 0x9fd0,0x9fd1,0x9fd2,0x9fd3,0x9fd4,0x9fd5,0x9fd6,0x9fd7,
+ 0x9fd8,0x9fd9,0x9fda,0x9fdb,0x9fdc,0x9fdd,0x9fde,0x9fdf,
+ 0x9fe0,0x9fe1,0x9fe2,0x9fe3,0x9fe4,0x9fe5,0x9fe6,0x9fe7,
+ 0x9fe8,0x9fe9,0x9fea,0x9feb,0x9fec,0x9fed,0x9fee,0x9fef,
+ 0x9ff0,0x9ff1,0x9ff2,0x9ff3,0x9ff4,0x9ff5,0x9ff6,0x9ff7,
+ 0x9ff8,0x9ff9,0x9ffa,0x9ffb,0x9ffc,0x9ffd,0x9ffe,0x9fff,
+ 0xa000,0xa001,0xa002,0xa003,0xa004,0xa005,0xa006,0xa007,
+ 0xa008,0xa009,0xa00a,0xa00b,0xa00c,0xa00d,0xa00e,0xa00f,
+ 0xa010,0xa011,0xa012,0xa013,0xa014,0xa015,0xa016,0xa017,
+ 0xa018,0xa019,0xa01a,0xa01b,0xa01c,0xa01d,0xa01e,0xa01f,
+ 0xa020,0xa021,0xa022,0xa023,0xa024,0xa025,0xa026,0xa027,
+ 0xa028,0xa029,0xa02a,0xa02b,0xa02c,0xa02d,0xa02e,0xa02f,
+ 0xa030,0xa031,0xa032,0xa033,0xa034,0xa035,0xa036,0xa037,
+ 0xa038,0xa039,0xa03a,0xa03b,0xa03c,0xa03d,0xa03e,0xa03f,
+ 0xa040,0xa041,0xa042,0xa043,0xa044,0xa045,0xa046,0xa047,
+ 0xa048,0xa049,0xa04a,0xa04b,0xa04c,0xa04d,0xa04e,0xa04f,
+ 0xa050,0xa051,0xa052,0xa053,0xa054,0xa055,0xa056,0xa057,
+ 0xa058,0xa059,0xa05a,0xa05b,0xa05c,0xa05d,0xa05e,0xa05f,
+ 0xa060,0xa061,0xa062,0xa063,0xa064,0xa065,0xa066,0xa067,
+ 0xa068,0xa069,0xa06a,0xa06b,0xa06c,0xa06d,0xa06e,0xa06f,
+ 0xa070,0xa071,0xa072,0xa073,0xa074,0xa075,0xa076,0xa077,
+ 0xa078,0xa079,0xa07a,0xa07b,0xa07c,0xa07d,0xa07e,0xa07f,
+ 0xa080,0xa081,0xa082,0xa083,0xa084,0xa085,0xa086,0xa087,
+ 0xa088,0xa089,0xa08a,0xa08b,0xa08c,0xa08d,0xa08e,0xa08f,
+ 0xa090,0xa091,0xa092,0xa093,0xa094,0xa095,0xa096,0xa097,
+ 0xa098,0xa099,0xa09a,0xa09b,0xa09c,0xa09d,0xa09e,0xa09f,
+ 0xa0a0,0xa0a1,0xa0a2,0xa0a3,0xa0a4,0xa0a5,0xa0a6,0xa0a7,
+ 0xa0a8,0xa0a9,0xa0aa,0xa0ab,0xa0ac,0xa0ad,0xa0ae,0xa0af,
+ 0xa0b0,0xa0b1,0xa0b2,0xa0b3,0xa0b4,0xa0b5,0xa0b6,0xa0b7,
+ 0xa0b8,0xa0b9,0xa0ba,0xa0bb,0xa0bc,0xa0bd,0xa0be,0xa0bf,
+ 0xa0c0,0xa0c1,0xa0c2,0xa0c3,0xa0c4,0xa0c5,0xa0c6,0xa0c7,
+ 0xa0c8,0xa0c9,0xa0ca,0xa0cb,0xa0cc,0xa0cd,0xa0ce,0xa0cf,
+ 0xa0d0,0xa0d1,0xa0d2,0xa0d3,0xa0d4,0xa0d5,0xa0d6,0xa0d7,
+ 0xa0d8,0xa0d9,0xa0da,0xa0db,0xa0dc,0xa0dd,0xa0de,0xa0df,
+ 0xa0e0,0xa0e1,0xa0e2,0xa0e3,0xa0e4,0xa0e5,0xa0e6,0xa0e7,
+ 0xa0e8,0xa0e9,0xa0ea,0xa0eb,0xa0ec,0xa0ed,0xa0ee,0xa0ef,
+ 0xa0f0,0xa0f1,0xa0f2,0xa0f3,0xa0f4,0xa0f5,0xa0f6,0xa0f7,
+ 0xa0f8,0xa0f9,0xa0fa,0xa0fb,0xa0fc,0xa0fd,0xa0fe,0xa0ff,
+ 0xa100,0xa101,0xa102,0xa103,0xa104,0xa105,0xa106,0xa107,
+ 0xa108,0xa109,0xa10a,0xa10b,0xa10c,0xa10d,0xa10e,0xa10f,
+ 0xa110,0xa111,0xa112,0xa113,0xa114,0xa115,0xa116,0xa117,
+ 0xa118,0xa119,0xa11a,0xa11b,0xa11c,0xa11d,0xa11e,0xa11f,
+ 0xa120,0xa121,0xa122,0xa123,0xa124,0xa125,0xa126,0xa127,
+ 0xa128,0xa129,0xa12a,0xa12b,0xa12c,0xa12d,0xa12e,0xa12f,
+ 0xa130,0xa131,0xa132,0xa133,0xa134,0xa135,0xa136,0xa137,
+ 0xa138,0xa139,0xa13a,0xa13b,0xa13c,0xa13d,0xa13e,0xa13f,
+ 0xa140,0xa141,0xa142,0xa143,0xa144,0xa145,0xa146,0xa147,
+ 0xa148,0xa149,0xa14a,0xa14b,0xa14c,0xa14d,0xa14e,0xa14f,
+ 0xa150,0xa151,0xa152,0xa153,0xa154,0xa155,0xa156,0xa157,
+ 0xa158,0xa159,0xa15a,0xa15b,0xa15c,0xa15d,0xa15e,0xa15f,
+ 0xa160,0xa161,0xa162,0xa163,0xa164,0xa165,0xa166,0xa167,
+ 0xa168,0xa169,0xa16a,0xa16b,0xa16c,0xa16d,0xa16e,0xa16f,
+ 0xa170,0xa171,0xa172,0xa173,0xa174,0xa175,0xa176,0xa177,
+ 0xa178,0xa179,0xa17a,0xa17b,0xa17c,0xa17d,0xa17e,0xa17f,
+ 0xa180,0xa181,0xa182,0xa183,0xa184,0xa185,0xa186,0xa187,
+ 0xa188,0xa189,0xa18a,0xa18b,0xa18c,0xa18d,0xa18e,0xa18f,
+ 0xa190,0xa191,0xa192,0xa193,0xa194,0xa195,0xa196,0xa197,
+ 0xa198,0xa199,0xa19a,0xa19b,0xa19c,0xa19d,0xa19e,0xa19f,
+ 0xa1a0,0xa1a1,0xa1a2,0xa1a3,0xa1a4,0xa1a5,0xa1a6,0xa1a7,
+ 0xa1a8,0xa1a9,0xa1aa,0xa1ab,0xa1ac,0xa1ad,0xa1ae,0xa1af,
+ 0xa1b0,0xa1b1,0xa1b2,0xa1b3,0xa1b4,0xa1b5,0xa1b6,0xa1b7,
+ 0xa1b8,0xa1b9,0xa1ba,0xa1bb,0xa1bc,0xa1bd,0xa1be,0xa1bf,
+ 0xa1c0,0xa1c1,0xa1c2,0xa1c3,0xa1c4,0xa1c5,0xa1c6,0xa1c7,
+ 0xa1c8,0xa1c9,0xa1ca,0xa1cb,0xa1cc,0xa1cd,0xa1ce,0xa1cf,
+ 0xa1d0,0xa1d1,0xa1d2,0xa1d3,0xa1d4,0xa1d5,0xa1d6,0xa1d7,
+ 0xa1d8,0xa1d9,0xa1da,0xa1db,0xa1dc,0xa1dd,0xa1de,0xa1df,
+ 0xa1e0,0xa1e1,0xa1e2,0xa1e3,0xa1e4,0xa1e5,0xa1e6,0xa1e7,
+ 0xa1e8,0xa1e9,0xa1ea,0xa1eb,0xa1ec,0xa1ed,0xa1ee,0xa1ef,
+ 0xa1f0,0xa1f1,0xa1f2,0xa1f3,0xa1f4,0xa1f5,0xa1f6,0xa1f7,
+ 0xa1f8,0xa1f9,0xa1fa,0xa1fb,0xa1fc,0xa1fd,0xa1fe,0xa1ff,
+ 0xa200,0xa201,0xa202,0xa203,0xa204,0xa205,0xa206,0xa207,
+ 0xa208,0xa209,0xa20a,0xa20b,0xa20c,0xa20d,0xa20e,0xa20f,
+ 0xa210,0xa211,0xa212,0xa213,0xa214,0xa215,0xa216,0xa217,
+ 0xa218,0xa219,0xa21a,0xa21b,0xa21c,0xa21d,0xa21e,0xa21f,
+ 0xa220,0xa221,0xa222,0xa223,0xa224,0xa225,0xa226,0xa227,
+ 0xa228,0xa229,0xa22a,0xa22b,0xa22c,0xa22d,0xa22e,0xa22f,
+ 0xa230,0xa231,0xa232,0xa233,0xa234,0xa235,0xa236,0xa237,
+ 0xa238,0xa239,0xa23a,0xa23b,0xa23c,0xa23d,0xa23e,0xa23f,
+ 0xa240,0xa241,0xa242,0xa243,0xa244,0xa245,0xa246,0xa247,
+ 0xa248,0xa249,0xa24a,0xa24b,0xa24c,0xa24d,0xa24e,0xa24f,
+ 0xa250,0xa251,0xa252,0xa253,0xa254,0xa255,0xa256,0xa257,
+ 0xa258,0xa259,0xa25a,0xa25b,0xa25c,0xa25d,0xa25e,0xa25f,
+ 0xa260,0xa261,0xa262,0xa263,0xa264,0xa265,0xa266,0xa267,
+ 0xa268,0xa269,0xa26a,0xa26b,0xa26c,0xa26d,0xa26e,0xa26f,
+ 0xa270,0xa271,0xa272,0xa273,0xa274,0xa275,0xa276,0xa277,
+ 0xa278,0xa279,0xa27a,0xa27b,0xa27c,0xa27d,0xa27e,0xa27f,
+ 0xa280,0xa281,0xa282,0xa283,0xa284,0xa285,0xa286,0xa287,
+ 0xa288,0xa289,0xa28a,0xa28b,0xa28c,0xa28d,0xa28e,0xa28f,
+ 0xa290,0xa291,0xa292,0xa293,0xa294,0xa295,0xa296,0xa297,
+ 0xa298,0xa299,0xa29a,0xa29b,0xa29c,0xa29d,0xa29e,0xa29f,
+ 0xa2a0,0xa2a1,0xa2a2,0xa2a3,0xa2a4,0xa2a5,0xa2a6,0xa2a7,
+ 0xa2a8,0xa2a9,0xa2aa,0xa2ab,0xa2ac,0xa2ad,0xa2ae,0xa2af,
+ 0xa2b0,0xa2b1,0xa2b2,0xa2b3,0xa2b4,0xa2b5,0xa2b6,0xa2b7,
+ 0xa2b8,0xa2b9,0xa2ba,0xa2bb,0xa2bc,0xa2bd,0xa2be,0xa2bf,
+ 0xa2c0,0xa2c1,0xa2c2,0xa2c3,0xa2c4,0xa2c5,0xa2c6,0xa2c7,
+ 0xa2c8,0xa2c9,0xa2ca,0xa2cb,0xa2cc,0xa2cd,0xa2ce,0xa2cf,
+ 0xa2d0,0xa2d1,0xa2d2,0xa2d3,0xa2d4,0xa2d5,0xa2d6,0xa2d7,
+ 0xa2d8,0xa2d9,0xa2da,0xa2db,0xa2dc,0xa2dd,0xa2de,0xa2df,
+ 0xa2e0,0xa2e1,0xa2e2,0xa2e3,0xa2e4,0xa2e5,0xa2e6,0xa2e7,
+ 0xa2e8,0xa2e9,0xa2ea,0xa2eb,0xa2ec,0xa2ed,0xa2ee,0xa2ef,
+ 0xa2f0,0xa2f1,0xa2f2,0xa2f3,0xa2f4,0xa2f5,0xa2f6,0xa2f7,
+ 0xa2f8,0xa2f9,0xa2fa,0xa2fb,0xa2fc,0xa2fd,0xa2fe,0xa2ff,
+ 0xa300,0xa301,0xa302,0xa303,0xa304,0xa305,0xa306,0xa307,
+ 0xa308,0xa309,0xa30a,0xa30b,0xa30c,0xa30d,0xa30e,0xa30f,
+ 0xa310,0xa311,0xa312,0xa313,0xa314,0xa315,0xa316,0xa317,
+ 0xa318,0xa319,0xa31a,0xa31b,0xa31c,0xa31d,0xa31e,0xa31f,
+ 0xa320,0xa321,0xa322,0xa323,0xa324,0xa325,0xa326,0xa327,
+ 0xa328,0xa329,0xa32a,0xa32b,0xa32c,0xa32d,0xa32e,0xa32f,
+ 0xa330,0xa331,0xa332,0xa333,0xa334,0xa335,0xa336,0xa337,
+ 0xa338,0xa339,0xa33a,0xa33b,0xa33c,0xa33d,0xa33e,0xa33f,
+ 0xa340,0xa341,0xa342,0xa343,0xa344,0xa345,0xa346,0xa347,
+ 0xa348,0xa349,0xa34a,0xa34b,0xa34c,0xa34d,0xa34e,0xa34f,
+ 0xa350,0xa351,0xa352,0xa353,0xa354,0xa355,0xa356,0xa357,
+ 0xa358,0xa359,0xa35a,0xa35b,0xa35c,0xa35d,0xa35e,0xa35f,
+ 0xa360,0xa361,0xa362,0xa363,0xa364,0xa365,0xa366,0xa367,
+ 0xa368,0xa369,0xa36a,0xa36b,0xa36c,0xa36d,0xa36e,0xa36f,
+ 0xa370,0xa371,0xa372,0xa373,0xa374,0xa375,0xa376,0xa377,
+ 0xa378,0xa379,0xa37a,0xa37b,0xa37c,0xa37d,0xa37e,0xa37f,
+ 0xa380,0xa381,0xa382,0xa383,0xa384,0xa385,0xa386,0xa387,
+ 0xa388,0xa389,0xa38a,0xa38b,0xa38c,0xa38d,0xa38e,0xa38f,
+ 0xa390,0xa391,0xa392,0xa393,0xa394,0xa395,0xa396,0xa397,
+ 0xa398,0xa399,0xa39a,0xa39b,0xa39c,0xa39d,0xa39e,0xa39f,
+ 0xa3a0,0xa3a1,0xa3a2,0xa3a3,0xa3a4,0xa3a5,0xa3a6,0xa3a7,
+ 0xa3a8,0xa3a9,0xa3aa,0xa3ab,0xa3ac,0xa3ad,0xa3ae,0xa3af,
+ 0xa3b0,0xa3b1,0xa3b2,0xa3b3,0xa3b4,0xa3b5,0xa3b6,0xa3b7,
+ 0xa3b8,0xa3b9,0xa3ba,0xa3bb,0xa3bc,0xa3bd,0xa3be,0xa3bf,
+ 0xa3c0,0xa3c1,0xa3c2,0xa3c3,0xa3c4,0xa3c5,0xa3c6,0xa3c7,
+ 0xa3c8,0xa3c9,0xa3ca,0xa3cb,0xa3cc,0xa3cd,0xa3ce,0xa3cf,
+ 0xa3d0,0xa3d1,0xa3d2,0xa3d3,0xa3d4,0xa3d5,0xa3d6,0xa3d7,
+ 0xa3d8,0xa3d9,0xa3da,0xa3db,0xa3dc,0xa3dd,0xa3de,0xa3df,
+ 0xa3e0,0xa3e1,0xa3e2,0xa3e3,0xa3e4,0xa3e5,0xa3e6,0xa3e7,
+ 0xa3e8,0xa3e9,0xa3ea,0xa3eb,0xa3ec,0xa3ed,0xa3ee,0xa3ef,
+ 0xa3f0,0xa3f1,0xa3f2,0xa3f3,0xa3f4,0xa3f5,0xa3f6,0xa3f7,
+ 0xa3f8,0xa3f9,0xa3fa,0xa3fb,0xa3fc,0xa3fd,0xa3fe,0xa3ff,
+ 0xa400,0xa401,0xa402,0xa403,0xa404,0xa405,0xa406,0xa407,
+ 0xa408,0xa409,0xa40a,0xa40b,0xa40c,0xa40d,0xa40e,0xa40f,
+ 0xa410,0xa411,0xa412,0xa413,0xa414,0xa415,0xa416,0xa417,
+ 0xa418,0xa419,0xa41a,0xa41b,0xa41c,0xa41d,0xa41e,0xa41f,
+ 0xa420,0xa421,0xa422,0xa423,0xa424,0xa425,0xa426,0xa427,
+ 0xa428,0xa429,0xa42a,0xa42b,0xa42c,0xa42d,0xa42e,0xa42f,
+ 0xa430,0xa431,0xa432,0xa433,0xa434,0xa435,0xa436,0xa437,
+ 0xa438,0xa439,0xa43a,0xa43b,0xa43c,0xa43d,0xa43e,0xa43f,
+ 0xa440,0xa441,0xa442,0xa443,0xa444,0xa445,0xa446,0xa447,
+ 0xa448,0xa449,0xa44a,0xa44b,0xa44c,0xa44d,0xa44e,0xa44f,
+ 0xa450,0xa451,0xa452,0xa453,0xa454,0xa455,0xa456,0xa457,
+ 0xa458,0xa459,0xa45a,0xa45b,0xa45c,0xa45d,0xa45e,0xa45f,
+ 0xa460,0xa461,0xa462,0xa463,0xa464,0xa465,0xa466,0xa467,
+ 0xa468,0xa469,0xa46a,0xa46b,0xa46c,0xa46d,0xa46e,0xa46f,
+ 0xa470,0xa471,0xa472,0xa473,0xa474,0xa475,0xa476,0xa477,
+ 0xa478,0xa479,0xa47a,0xa47b,0xa47c,0xa47d,0xa47e,0xa47f,
+ 0xa480,0xa481,0xa482,0xa483,0xa484,0xa485,0xa486,0xa487,
+ 0xa488,0xa489,0xa48a,0xa48b,0xa48c,0xa48d,0xa48e,0xa48f,
+ 0xa490,0xa491,0xa492,0xa493,0xa494,0xa495,0xa496,0xa497,
+ 0xa498,0xa499,0xa49a,0xa49b,0xa49c,0xa49d,0xa49e,0xa49f,
+ 0xa4a0,0xa4a1,0xa4a2,0xa4a3,0xa4a4,0xa4a5,0xa4a6,0xa4a7,
+ 0xa4a8,0xa4a9,0xa4aa,0xa4ab,0xa4ac,0xa4ad,0xa4ae,0xa4af,
+ 0xa4b0,0xa4b1,0xa4b2,0xa4b3,0xa4b4,0xa4b5,0xa4b6,0xa4b7,
+ 0xa4b8,0xa4b9,0xa4ba,0xa4bb,0xa4bc,0xa4bd,0xa4be,0xa4bf,
+ 0xa4c0,0xa4c1,0xa4c2,0xa4c3,0xa4c4,0xa4c5,0xa4c6,0xa4c7,
+ 0xa4c8,0xa4c9,0xa4ca,0xa4cb,0xa4cc,0xa4cd,0xa4ce,0xa4cf,
+ 0xa4d0,0xa4d1,0xa4d2,0xa4d3,0xa4d4,0xa4d5,0xa4d6,0xa4d7,
+ 0xa4d8,0xa4d9,0xa4da,0xa4db,0xa4dc,0xa4dd,0xa4de,0xa4df,
+ 0xa4e0,0xa4e1,0xa4e2,0xa4e3,0xa4e4,0xa4e5,0xa4e6,0xa4e7,
+ 0xa4e8,0xa4e9,0xa4ea,0xa4eb,0xa4ec,0xa4ed,0xa4ee,0xa4ef,
+ 0xa4f0,0xa4f1,0xa4f2,0xa4f3,0xa4f4,0xa4f5,0xa4f6,0xa4f7,
+ 0xa4f8,0xa4f9,0xa4fa,0xa4fb,0xa4fc,0xa4fd,0xa4fe,0xa4ff,
+ 0xa500,0xa501,0xa502,0xa503,0xa504,0xa505,0xa506,0xa507,
+ 0xa508,0xa509,0xa50a,0xa50b,0xa50c,0xa50d,0xa50e,0xa50f,
+ 0xa510,0xa511,0xa512,0xa513,0xa514,0xa515,0xa516,0xa517,
+ 0xa518,0xa519,0xa51a,0xa51b,0xa51c,0xa51d,0xa51e,0xa51f,
+ 0xa520,0xa521,0xa522,0xa523,0xa524,0xa525,0xa526,0xa527,
+ 0xa528,0xa529,0xa52a,0xa52b,0xa52c,0xa52d,0xa52e,0xa52f,
+ 0xa530,0xa531,0xa532,0xa533,0xa534,0xa535,0xa536,0xa537,
+ 0xa538,0xa539,0xa53a,0xa53b,0xa53c,0xa53d,0xa53e,0xa53f,
+ 0xa540,0xa541,0xa542,0xa543,0xa544,0xa545,0xa546,0xa547,
+ 0xa548,0xa549,0xa54a,0xa54b,0xa54c,0xa54d,0xa54e,0xa54f,
+ 0xa550,0xa551,0xa552,0xa553,0xa554,0xa555,0xa556,0xa557,
+ 0xa558,0xa559,0xa55a,0xa55b,0xa55c,0xa55d,0xa55e,0xa55f,
+ 0xa560,0xa561,0xa562,0xa563,0xa564,0xa565,0xa566,0xa567,
+ 0xa568,0xa569,0xa56a,0xa56b,0xa56c,0xa56d,0xa56e,0xa56f,
+ 0xa570,0xa571,0xa572,0xa573,0xa574,0xa575,0xa576,0xa577,
+ 0xa578,0xa579,0xa57a,0xa57b,0xa57c,0xa57d,0xa57e,0xa57f,
+ 0xa580,0xa581,0xa582,0xa583,0xa584,0xa585,0xa586,0xa587,
+ 0xa588,0xa589,0xa58a,0xa58b,0xa58c,0xa58d,0xa58e,0xa58f,
+ 0xa590,0xa591,0xa592,0xa593,0xa594,0xa595,0xa596,0xa597,
+ 0xa598,0xa599,0xa59a,0xa59b,0xa59c,0xa59d,0xa59e,0xa59f,
+ 0xa5a0,0xa5a1,0xa5a2,0xa5a3,0xa5a4,0xa5a5,0xa5a6,0xa5a7,
+ 0xa5a8,0xa5a9,0xa5aa,0xa5ab,0xa5ac,0xa5ad,0xa5ae,0xa5af,
+ 0xa5b0,0xa5b1,0xa5b2,0xa5b3,0xa5b4,0xa5b5,0xa5b6,0xa5b7,
+ 0xa5b8,0xa5b9,0xa5ba,0xa5bb,0xa5bc,0xa5bd,0xa5be,0xa5bf,
+ 0xa5c0,0xa5c1,0xa5c2,0xa5c3,0xa5c4,0xa5c5,0xa5c6,0xa5c7,
+ 0xa5c8,0xa5c9,0xa5ca,0xa5cb,0xa5cc,0xa5cd,0xa5ce,0xa5cf,
+ 0xa5d0,0xa5d1,0xa5d2,0xa5d3,0xa5d4,0xa5d5,0xa5d6,0xa5d7,
+ 0xa5d8,0xa5d9,0xa5da,0xa5db,0xa5dc,0xa5dd,0xa5de,0xa5df,
+ 0xa5e0,0xa5e1,0xa5e2,0xa5e3,0xa5e4,0xa5e5,0xa5e6,0xa5e7,
+ 0xa5e8,0xa5e9,0xa5ea,0xa5eb,0xa5ec,0xa5ed,0xa5ee,0xa5ef,
+ 0xa5f0,0xa5f1,0xa5f2,0xa5f3,0xa5f4,0xa5f5,0xa5f6,0xa5f7,
+ 0xa5f8,0xa5f9,0xa5fa,0xa5fb,0xa5fc,0xa5fd,0xa5fe,0xa5ff,
+ 0xa600,0xa601,0xa602,0xa603,0xa604,0xa605,0xa606,0xa607,
+ 0xa608,0xa609,0xa60a,0xa60b,0xa60c,0xa60d,0xa60e,0xa60f,
+ 0xa610,0xa611,0xa612,0xa613,0xa614,0xa615,0xa616,0xa617,
+ 0xa618,0xa619,0xa61a,0xa61b,0xa61c,0xa61d,0xa61e,0xa61f,
+ 0xa620,0xa621,0xa622,0xa623,0xa624,0xa625,0xa626,0xa627,
+ 0xa628,0xa629,0xa62a,0xa62b,0xa62c,0xa62d,0xa62e,0xa62f,
+ 0xa630,0xa631,0xa632,0xa633,0xa634,0xa635,0xa636,0xa637,
+ 0xa638,0xa639,0xa63a,0xa63b,0xa63c,0xa63d,0xa63e,0xa63f,
+ 0xa640,0xa641,0xa642,0xa643,0xa644,0xa645,0xa646,0xa647,
+ 0xa648,0xa649,0xa64a,0xa64b,0xa64c,0xa64d,0xa64e,0xa64f,
+ 0xa650,0xa651,0xa652,0xa653,0xa654,0xa655,0xa656,0xa657,
+ 0xa658,0xa659,0xa65a,0xa65b,0xa65c,0xa65d,0xa65e,0xa65f,
+ 0xa660,0xa661,0xa662,0xa663,0xa664,0xa665,0xa666,0xa667,
+ 0xa668,0xa669,0xa66a,0xa66b,0xa66c,0xa66d,0xa66e,0xa66f,
+ 0xa670,0xa671,0xa672,0xa673,0xa674,0xa675,0xa676,0xa677,
+ 0xa678,0xa679,0xa67a,0xa67b,0xa67c,0xa67d,0xa67e,0xa67f,
+ 0xa680,0xa681,0xa682,0xa683,0xa684,0xa685,0xa686,0xa687,
+ 0xa688,0xa689,0xa68a,0xa68b,0xa68c,0xa68d,0xa68e,0xa68f,
+ 0xa690,0xa691,0xa692,0xa693,0xa694,0xa695,0xa696,0xa697,
+ 0xa698,0xa699,0xa69a,0xa69b,0xa69c,0xa69d,0xa69e,0xa69f,
+ 0xa6a0,0xa6a1,0xa6a2,0xa6a3,0xa6a4,0xa6a5,0xa6a6,0xa6a7,
+ 0xa6a8,0xa6a9,0xa6aa,0xa6ab,0xa6ac,0xa6ad,0xa6ae,0xa6af,
+ 0xa6b0,0xa6b1,0xa6b2,0xa6b3,0xa6b4,0xa6b5,0xa6b6,0xa6b7,
+ 0xa6b8,0xa6b9,0xa6ba,0xa6bb,0xa6bc,0xa6bd,0xa6be,0xa6bf,
+ 0xa6c0,0xa6c1,0xa6c2,0xa6c3,0xa6c4,0xa6c5,0xa6c6,0xa6c7,
+ 0xa6c8,0xa6c9,0xa6ca,0xa6cb,0xa6cc,0xa6cd,0xa6ce,0xa6cf,
+ 0xa6d0,0xa6d1,0xa6d2,0xa6d3,0xa6d4,0xa6d5,0xa6d6,0xa6d7,
+ 0xa6d8,0xa6d9,0xa6da,0xa6db,0xa6dc,0xa6dd,0xa6de,0xa6df,
+ 0xa6e0,0xa6e1,0xa6e2,0xa6e3,0xa6e4,0xa6e5,0xa6e6,0xa6e7,
+ 0xa6e8,0xa6e9,0xa6ea,0xa6eb,0xa6ec,0xa6ed,0xa6ee,0xa6ef,
+ 0xa6f0,0xa6f1,0xa6f2,0xa6f3,0xa6f4,0xa6f5,0xa6f6,0xa6f7,
+ 0xa6f8,0xa6f9,0xa6fa,0xa6fb,0xa6fc,0xa6fd,0xa6fe,0xa6ff,
+ 0xa700,0xa701,0xa702,0xa703,0xa704,0xa705,0xa706,0xa707,
+ 0xa708,0xa709,0xa70a,0xa70b,0xa70c,0xa70d,0xa70e,0xa70f,
+ 0xa710,0xa711,0xa712,0xa713,0xa714,0xa715,0xa716,0xa717,
+ 0xa718,0xa719,0xa71a,0xa71b,0xa71c,0xa71d,0xa71e,0xa71f,
+ 0xa720,0xa721,0xa722,0xa723,0xa724,0xa725,0xa726,0xa727,
+ 0xa728,0xa729,0xa72a,0xa72b,0xa72c,0xa72d,0xa72e,0xa72f,
+ 0xa730,0xa731,0xa732,0xa733,0xa734,0xa735,0xa736,0xa737,
+ 0xa738,0xa739,0xa73a,0xa73b,0xa73c,0xa73d,0xa73e,0xa73f,
+ 0xa740,0xa741,0xa742,0xa743,0xa744,0xa745,0xa746,0xa747,
+ 0xa748,0xa749,0xa74a,0xa74b,0xa74c,0xa74d,0xa74e,0xa74f,
+ 0xa750,0xa751,0xa752,0xa753,0xa754,0xa755,0xa756,0xa757,
+ 0xa758,0xa759,0xa75a,0xa75b,0xa75c,0xa75d,0xa75e,0xa75f,
+ 0xa760,0xa761,0xa762,0xa763,0xa764,0xa765,0xa766,0xa767,
+ 0xa768,0xa769,0xa76a,0xa76b,0xa76c,0xa76d,0xa76e,0xa76f,
+ 0xa770,0xa771,0xa772,0xa773,0xa774,0xa775,0xa776,0xa777,
+ 0xa778,0xa779,0xa77a,0xa77b,0xa77c,0xa77d,0xa77e,0xa77f,
+ 0xa780,0xa781,0xa782,0xa783,0xa784,0xa785,0xa786,0xa787,
+ 0xa788,0xa789,0xa78a,0xa78b,0xa78c,0xa78d,0xa78e,0xa78f,
+ 0xa790,0xa791,0xa792,0xa793,0xa794,0xa795,0xa796,0xa797,
+ 0xa798,0xa799,0xa79a,0xa79b,0xa79c,0xa79d,0xa79e,0xa79f,
+ 0xa7a0,0xa7a1,0xa7a2,0xa7a3,0xa7a4,0xa7a5,0xa7a6,0xa7a7,
+ 0xa7a8,0xa7a9,0xa7aa,0xa7ab,0xa7ac,0xa7ad,0xa7ae,0xa7af,
+ 0xa7b0,0xa7b1,0xa7b2,0xa7b3,0xa7b4,0xa7b5,0xa7b6,0xa7b7,
+ 0xa7b8,0xa7b9,0xa7ba,0xa7bb,0xa7bc,0xa7bd,0xa7be,0xa7bf,
+ 0xa7c0,0xa7c1,0xa7c2,0xa7c3,0xa7c4,0xa7c5,0xa7c6,0xa7c7,
+ 0xa7c8,0xa7c9,0xa7ca,0xa7cb,0xa7cc,0xa7cd,0xa7ce,0xa7cf,
+ 0xa7d0,0xa7d1,0xa7d2,0xa7d3,0xa7d4,0xa7d5,0xa7d6,0xa7d7,
+ 0xa7d8,0xa7d9,0xa7da,0xa7db,0xa7dc,0xa7dd,0xa7de,0xa7df,
+ 0xa7e0,0xa7e1,0xa7e2,0xa7e3,0xa7e4,0xa7e5,0xa7e6,0xa7e7,
+ 0xa7e8,0xa7e9,0xa7ea,0xa7eb,0xa7ec,0xa7ed,0xa7ee,0xa7ef,
+ 0xa7f0,0xa7f1,0xa7f2,0xa7f3,0xa7f4,0xa7f5,0xa7f6,0xa7f7,
+ 0xa7f8,0xa7f9,0xa7fa,0xa7fb,0xa7fc,0xa7fd,0xa7fe,0xa7ff,
+ 0xa800,0xa801,0xa802,0xa803,0xa804,0xa805,0xa806,0xa807,
+ 0xa808,0xa809,0xa80a,0xa80b,0xa80c,0xa80d,0xa80e,0xa80f,
+ 0xa810,0xa811,0xa812,0xa813,0xa814,0xa815,0xa816,0xa817,
+ 0xa818,0xa819,0xa81a,0xa81b,0xa81c,0xa81d,0xa81e,0xa81f,
+ 0xa820,0xa821,0xa822,0xa823,0xa824,0xa825,0xa826,0xa827,
+ 0xa828,0xa829,0xa82a,0xa82b,0xa82c,0xa82d,0xa82e,0xa82f,
+ 0xa830,0xa831,0xa832,0xa833,0xa834,0xa835,0xa836,0xa837,
+ 0xa838,0xa839,0xa83a,0xa83b,0xa83c,0xa83d,0xa83e,0xa83f,
+ 0xa840,0xa841,0xa842,0xa843,0xa844,0xa845,0xa846,0xa847,
+ 0xa848,0xa849,0xa84a,0xa84b,0xa84c,0xa84d,0xa84e,0xa84f,
+ 0xa850,0xa851,0xa852,0xa853,0xa854,0xa855,0xa856,0xa857,
+ 0xa858,0xa859,0xa85a,0xa85b,0xa85c,0xa85d,0xa85e,0xa85f,
+ 0xa860,0xa861,0xa862,0xa863,0xa864,0xa865,0xa866,0xa867,
+ 0xa868,0xa869,0xa86a,0xa86b,0xa86c,0xa86d,0xa86e,0xa86f,
+ 0xa870,0xa871,0xa872,0xa873,0xa874,0xa875,0xa876,0xa877,
+ 0xa878,0xa879,0xa87a,0xa87b,0xa87c,0xa87d,0xa87e,0xa87f,
+ 0xa880,0xa881,0xa882,0xa883,0xa884,0xa885,0xa886,0xa887,
+ 0xa888,0xa889,0xa88a,0xa88b,0xa88c,0xa88d,0xa88e,0xa88f,
+ 0xa890,0xa891,0xa892,0xa893,0xa894,0xa895,0xa896,0xa897,
+ 0xa898,0xa899,0xa89a,0xa89b,0xa89c,0xa89d,0xa89e,0xa89f,
+ 0xa8a0,0xa8a1,0xa8a2,0xa8a3,0xa8a4,0xa8a5,0xa8a6,0xa8a7,
+ 0xa8a8,0xa8a9,0xa8aa,0xa8ab,0xa8ac,0xa8ad,0xa8ae,0xa8af,
+ 0xa8b0,0xa8b1,0xa8b2,0xa8b3,0xa8b4,0xa8b5,0xa8b6,0xa8b7,
+ 0xa8b8,0xa8b9,0xa8ba,0xa8bb,0xa8bc,0xa8bd,0xa8be,0xa8bf,
+ 0xa8c0,0xa8c1,0xa8c2,0xa8c3,0xa8c4,0xa8c5,0xa8c6,0xa8c7,
+ 0xa8c8,0xa8c9,0xa8ca,0xa8cb,0xa8cc,0xa8cd,0xa8ce,0xa8cf,
+ 0xa8d0,0xa8d1,0xa8d2,0xa8d3,0xa8d4,0xa8d5,0xa8d6,0xa8d7,
+ 0xa8d8,0xa8d9,0xa8da,0xa8db,0xa8dc,0xa8dd,0xa8de,0xa8df,
+ 0xa8e0,0xa8e1,0xa8e2,0xa8e3,0xa8e4,0xa8e5,0xa8e6,0xa8e7,
+ 0xa8e8,0xa8e9,0xa8ea,0xa8eb,0xa8ec,0xa8ed,0xa8ee,0xa8ef,
+ 0xa8f0,0xa8f1,0xa8f2,0xa8f3,0xa8f4,0xa8f5,0xa8f6,0xa8f7,
+ 0xa8f8,0xa8f9,0xa8fa,0xa8fb,0xa8fc,0xa8fd,0xa8fe,0xa8ff,
+ 0xa900,0xa901,0xa902,0xa903,0xa904,0xa905,0xa906,0xa907,
+ 0xa908,0xa909,0xa90a,0xa90b,0xa90c,0xa90d,0xa90e,0xa90f,
+ 0xa910,0xa911,0xa912,0xa913,0xa914,0xa915,0xa916,0xa917,
+ 0xa918,0xa919,0xa91a,0xa91b,0xa91c,0xa91d,0xa91e,0xa91f,
+ 0xa920,0xa921,0xa922,0xa923,0xa924,0xa925,0xa926,0xa927,
+ 0xa928,0xa929,0xa92a,0xa92b,0xa92c,0xa92d,0xa92e,0xa92f,
+ 0xa930,0xa931,0xa932,0xa933,0xa934,0xa935,0xa936,0xa937,
+ 0xa938,0xa939,0xa93a,0xa93b,0xa93c,0xa93d,0xa93e,0xa93f,
+ 0xa940,0xa941,0xa942,0xa943,0xa944,0xa945,0xa946,0xa947,
+ 0xa948,0xa949,0xa94a,0xa94b,0xa94c,0xa94d,0xa94e,0xa94f,
+ 0xa950,0xa951,0xa952,0xa953,0xa954,0xa955,0xa956,0xa957,
+ 0xa958,0xa959,0xa95a,0xa95b,0xa95c,0xa95d,0xa95e,0xa95f,
+ 0xa960,0xa961,0xa962,0xa963,0xa964,0xa965,0xa966,0xa967,
+ 0xa968,0xa969,0xa96a,0xa96b,0xa96c,0xa96d,0xa96e,0xa96f,
+ 0xa970,0xa971,0xa972,0xa973,0xa974,0xa975,0xa976,0xa977,
+ 0xa978,0xa979,0xa97a,0xa97b,0xa97c,0xa97d,0xa97e,0xa97f,
+ 0xa980,0xa981,0xa982,0xa983,0xa984,0xa985,0xa986,0xa987,
+ 0xa988,0xa989,0xa98a,0xa98b,0xa98c,0xa98d,0xa98e,0xa98f,
+ 0xa990,0xa991,0xa992,0xa993,0xa994,0xa995,0xa996,0xa997,
+ 0xa998,0xa999,0xa99a,0xa99b,0xa99c,0xa99d,0xa99e,0xa99f,
+ 0xa9a0,0xa9a1,0xa9a2,0xa9a3,0xa9a4,0xa9a5,0xa9a6,0xa9a7,
+ 0xa9a8,0xa9a9,0xa9aa,0xa9ab,0xa9ac,0xa9ad,0xa9ae,0xa9af,
+ 0xa9b0,0xa9b1,0xa9b2,0xa9b3,0xa9b4,0xa9b5,0xa9b6,0xa9b7,
+ 0xa9b8,0xa9b9,0xa9ba,0xa9bb,0xa9bc,0xa9bd,0xa9be,0xa9bf,
+ 0xa9c0,0xa9c1,0xa9c2,0xa9c3,0xa9c4,0xa9c5,0xa9c6,0xa9c7,
+ 0xa9c8,0xa9c9,0xa9ca,0xa9cb,0xa9cc,0xa9cd,0xa9ce,0xa9cf,
+ 0xa9d0,0xa9d1,0xa9d2,0xa9d3,0xa9d4,0xa9d5,0xa9d6,0xa9d7,
+ 0xa9d8,0xa9d9,0xa9da,0xa9db,0xa9dc,0xa9dd,0xa9de,0xa9df,
+ 0xa9e0,0xa9e1,0xa9e2,0xa9e3,0xa9e4,0xa9e5,0xa9e6,0xa9e7,
+ 0xa9e8,0xa9e9,0xa9ea,0xa9eb,0xa9ec,0xa9ed,0xa9ee,0xa9ef,
+ 0xa9f0,0xa9f1,0xa9f2,0xa9f3,0xa9f4,0xa9f5,0xa9f6,0xa9f7,
+ 0xa9f8,0xa9f9,0xa9fa,0xa9fb,0xa9fc,0xa9fd,0xa9fe,0xa9ff,
+ 0xaa00,0xaa01,0xaa02,0xaa03,0xaa04,0xaa05,0xaa06,0xaa07,
+ 0xaa08,0xaa09,0xaa0a,0xaa0b,0xaa0c,0xaa0d,0xaa0e,0xaa0f,
+ 0xaa10,0xaa11,0xaa12,0xaa13,0xaa14,0xaa15,0xaa16,0xaa17,
+ 0xaa18,0xaa19,0xaa1a,0xaa1b,0xaa1c,0xaa1d,0xaa1e,0xaa1f,
+ 0xaa20,0xaa21,0xaa22,0xaa23,0xaa24,0xaa25,0xaa26,0xaa27,
+ 0xaa28,0xaa29,0xaa2a,0xaa2b,0xaa2c,0xaa2d,0xaa2e,0xaa2f,
+ 0xaa30,0xaa31,0xaa32,0xaa33,0xaa34,0xaa35,0xaa36,0xaa37,
+ 0xaa38,0xaa39,0xaa3a,0xaa3b,0xaa3c,0xaa3d,0xaa3e,0xaa3f,
+ 0xaa40,0xaa41,0xaa42,0xaa43,0xaa44,0xaa45,0xaa46,0xaa47,
+ 0xaa48,0xaa49,0xaa4a,0xaa4b,0xaa4c,0xaa4d,0xaa4e,0xaa4f,
+ 0xaa50,0xaa51,0xaa52,0xaa53,0xaa54,0xaa55,0xaa56,0xaa57,
+ 0xaa58,0xaa59,0xaa5a,0xaa5b,0xaa5c,0xaa5d,0xaa5e,0xaa5f,
+ 0xaa60,0xaa61,0xaa62,0xaa63,0xaa64,0xaa65,0xaa66,0xaa67,
+ 0xaa68,0xaa69,0xaa6a,0xaa6b,0xaa6c,0xaa6d,0xaa6e,0xaa6f,
+ 0xaa70,0xaa71,0xaa72,0xaa73,0xaa74,0xaa75,0xaa76,0xaa77,
+ 0xaa78,0xaa79,0xaa7a,0xaa7b,0xaa7c,0xaa7d,0xaa7e,0xaa7f,
+ 0xaa80,0xaa81,0xaa82,0xaa83,0xaa84,0xaa85,0xaa86,0xaa87,
+ 0xaa88,0xaa89,0xaa8a,0xaa8b,0xaa8c,0xaa8d,0xaa8e,0xaa8f,
+ 0xaa90,0xaa91,0xaa92,0xaa93,0xaa94,0xaa95,0xaa96,0xaa97,
+ 0xaa98,0xaa99,0xaa9a,0xaa9b,0xaa9c,0xaa9d,0xaa9e,0xaa9f,
+ 0xaaa0,0xaaa1,0xaaa2,0xaaa3,0xaaa4,0xaaa5,0xaaa6,0xaaa7,
+ 0xaaa8,0xaaa9,0xaaaa,0xaaab,0xaaac,0xaaad,0xaaae,0xaaaf,
+ 0xaab0,0xaab1,0xaab2,0xaab3,0xaab4,0xaab5,0xaab6,0xaab7,
+ 0xaab8,0xaab9,0xaaba,0xaabb,0xaabc,0xaabd,0xaabe,0xaabf,
+ 0xaac0,0xaac1,0xaac2,0xaac3,0xaac4,0xaac5,0xaac6,0xaac7,
+ 0xaac8,0xaac9,0xaaca,0xaacb,0xaacc,0xaacd,0xaace,0xaacf,
+ 0xaad0,0xaad1,0xaad2,0xaad3,0xaad4,0xaad5,0xaad6,0xaad7,
+ 0xaad8,0xaad9,0xaada,0xaadb,0xaadc,0xaadd,0xaade,0xaadf,
+ 0xaae0,0xaae1,0xaae2,0xaae3,0xaae4,0xaae5,0xaae6,0xaae7,
+ 0xaae8,0xaae9,0xaaea,0xaaeb,0xaaec,0xaaed,0xaaee,0xaaef,
+ 0xaaf0,0xaaf1,0xaaf2,0xaaf3,0xaaf4,0xaaf5,0xaaf6,0xaaf7,
+ 0xaaf8,0xaaf9,0xaafa,0xaafb,0xaafc,0xaafd,0xaafe,0xaaff,
+ 0xab00,0xab01,0xab02,0xab03,0xab04,0xab05,0xab06,0xab07,
+ 0xab08,0xab09,0xab0a,0xab0b,0xab0c,0xab0d,0xab0e,0xab0f,
+ 0xab10,0xab11,0xab12,0xab13,0xab14,0xab15,0xab16,0xab17,
+ 0xab18,0xab19,0xab1a,0xab1b,0xab1c,0xab1d,0xab1e,0xab1f,
+ 0xab20,0xab21,0xab22,0xab23,0xab24,0xab25,0xab26,0xab27,
+ 0xab28,0xab29,0xab2a,0xab2b,0xab2c,0xab2d,0xab2e,0xab2f,
+ 0xab30,0xab31,0xab32,0xab33,0xab34,0xab35,0xab36,0xab37,
+ 0xab38,0xab39,0xab3a,0xab3b,0xab3c,0xab3d,0xab3e,0xab3f,
+ 0xab40,0xab41,0xab42,0xab43,0xab44,0xab45,0xab46,0xab47,
+ 0xab48,0xab49,0xab4a,0xab4b,0xab4c,0xab4d,0xab4e,0xab4f,
+ 0xab50,0xab51,0xab52,0xab53,0xab54,0xab55,0xab56,0xab57,
+ 0xab58,0xab59,0xab5a,0xab5b,0xab5c,0xab5d,0xab5e,0xab5f,
+ 0xab60,0xab61,0xab62,0xab63,0xab64,0xab65,0xab66,0xab67,
+ 0xab68,0xab69,0xab6a,0xab6b,0xab6c,0xab6d,0xab6e,0xab6f,
+ 0xab70,0xab71,0xab72,0xab73,0xab74,0xab75,0xab76,0xab77,
+ 0xab78,0xab79,0xab7a,0xab7b,0xab7c,0xab7d,0xab7e,0xab7f,
+ 0xab80,0xab81,0xab82,0xab83,0xab84,0xab85,0xab86,0xab87,
+ 0xab88,0xab89,0xab8a,0xab8b,0xab8c,0xab8d,0xab8e,0xab8f,
+ 0xab90,0xab91,0xab92,0xab93,0xab94,0xab95,0xab96,0xab97,
+ 0xab98,0xab99,0xab9a,0xab9b,0xab9c,0xab9d,0xab9e,0xab9f,
+ 0xaba0,0xaba1,0xaba2,0xaba3,0xaba4,0xaba5,0xaba6,0xaba7,
+ 0xaba8,0xaba9,0xabaa,0xabab,0xabac,0xabad,0xabae,0xabaf,
+ 0xabb0,0xabb1,0xabb2,0xabb3,0xabb4,0xabb5,0xabb6,0xabb7,
+ 0xabb8,0xabb9,0xabba,0xabbb,0xabbc,0xabbd,0xabbe,0xabbf,
+ 0xabc0,0xabc1,0xabc2,0xabc3,0xabc4,0xabc5,0xabc6,0xabc7,
+ 0xabc8,0xabc9,0xabca,0xabcb,0xabcc,0xabcd,0xabce,0xabcf,
+ 0xabd0,0xabd1,0xabd2,0xabd3,0xabd4,0xabd5,0xabd6,0xabd7,
+ 0xabd8,0xabd9,0xabda,0xabdb,0xabdc,0xabdd,0xabde,0xabdf,
+ 0xabe0,0xabe1,0xabe2,0xabe3,0xabe4,0xabe5,0xabe6,0xabe7,
+ 0xabe8,0xabe9,0xabea,0xabeb,0xabec,0xabed,0xabee,0xabef,
+ 0xabf0,0xabf1,0xabf2,0xabf3,0xabf4,0xabf5,0xabf6,0xabf7,
+ 0xabf8,0xabf9,0xabfa,0xabfb,0xabfc,0xabfd,0xabfe,0xabff,
+ 0xac00,0xac01,0xac02,0xac03,0xac04,0xac05,0xac06,0xac07,
+ 0xac08,0xac09,0xac0a,0xac0b,0xac0c,0xac0d,0xac0e,0xac0f,
+ 0xac10,0xac11,0xac12,0xac13,0xac14,0xac15,0xac16,0xac17,
+ 0xac18,0xac19,0xac1a,0xac1b,0xac1c,0xac1d,0xac1e,0xac1f,
+ 0xac20,0xac21,0xac22,0xac23,0xac24,0xac25,0xac26,0xac27,
+ 0xac28,0xac29,0xac2a,0xac2b,0xac2c,0xac2d,0xac2e,0xac2f,
+ 0xac30,0xac31,0xac32,0xac33,0xac34,0xac35,0xac36,0xac37,
+ 0xac38,0xac39,0xac3a,0xac3b,0xac3c,0xac3d,0xac3e,0xac3f,
+ 0xac40,0xac41,0xac42,0xac43,0xac44,0xac45,0xac46,0xac47,
+ 0xac48,0xac49,0xac4a,0xac4b,0xac4c,0xac4d,0xac4e,0xac4f,
+ 0xac50,0xac51,0xac52,0xac53,0xac54,0xac55,0xac56,0xac57,
+ 0xac58,0xac59,0xac5a,0xac5b,0xac5c,0xac5d,0xac5e,0xac5f,
+ 0xac60,0xac61,0xac62,0xac63,0xac64,0xac65,0xac66,0xac67,
+ 0xac68,0xac69,0xac6a,0xac6b,0xac6c,0xac6d,0xac6e,0xac6f,
+ 0xac70,0xac71,0xac72,0xac73,0xac74,0xac75,0xac76,0xac77,
+ 0xac78,0xac79,0xac7a,0xac7b,0xac7c,0xac7d,0xac7e,0xac7f,
+ 0xac80,0xac81,0xac82,0xac83,0xac84,0xac85,0xac86,0xac87,
+ 0xac88,0xac89,0xac8a,0xac8b,0xac8c,0xac8d,0xac8e,0xac8f,
+ 0xac90,0xac91,0xac92,0xac93,0xac94,0xac95,0xac96,0xac97,
+ 0xac98,0xac99,0xac9a,0xac9b,0xac9c,0xac9d,0xac9e,0xac9f,
+ 0xaca0,0xaca1,0xaca2,0xaca3,0xaca4,0xaca5,0xaca6,0xaca7,
+ 0xaca8,0xaca9,0xacaa,0xacab,0xacac,0xacad,0xacae,0xacaf,
+ 0xacb0,0xacb1,0xacb2,0xacb3,0xacb4,0xacb5,0xacb6,0xacb7,
+ 0xacb8,0xacb9,0xacba,0xacbb,0xacbc,0xacbd,0xacbe,0xacbf,
+ 0xacc0,0xacc1,0xacc2,0xacc3,0xacc4,0xacc5,0xacc6,0xacc7,
+ 0xacc8,0xacc9,0xacca,0xaccb,0xaccc,0xaccd,0xacce,0xaccf,
+ 0xacd0,0xacd1,0xacd2,0xacd3,0xacd4,0xacd5,0xacd6,0xacd7,
+ 0xacd8,0xacd9,0xacda,0xacdb,0xacdc,0xacdd,0xacde,0xacdf,
+ 0xace0,0xace1,0xace2,0xace3,0xace4,0xace5,0xace6,0xace7,
+ 0xace8,0xace9,0xacea,0xaceb,0xacec,0xaced,0xacee,0xacef,
+ 0xacf0,0xacf1,0xacf2,0xacf3,0xacf4,0xacf5,0xacf6,0xacf7,
+ 0xacf8,0xacf9,0xacfa,0xacfb,0xacfc,0xacfd,0xacfe,0xacff,
+ 0xad00,0xad01,0xad02,0xad03,0xad04,0xad05,0xad06,0xad07,
+ 0xad08,0xad09,0xad0a,0xad0b,0xad0c,0xad0d,0xad0e,0xad0f,
+ 0xad10,0xad11,0xad12,0xad13,0xad14,0xad15,0xad16,0xad17,
+ 0xad18,0xad19,0xad1a,0xad1b,0xad1c,0xad1d,0xad1e,0xad1f,
+ 0xad20,0xad21,0xad22,0xad23,0xad24,0xad25,0xad26,0xad27,
+ 0xad28,0xad29,0xad2a,0xad2b,0xad2c,0xad2d,0xad2e,0xad2f,
+ 0xad30,0xad31,0xad32,0xad33,0xad34,0xad35,0xad36,0xad37,
+ 0xad38,0xad39,0xad3a,0xad3b,0xad3c,0xad3d,0xad3e,0xad3f,
+ 0xad40,0xad41,0xad42,0xad43,0xad44,0xad45,0xad46,0xad47,
+ 0xad48,0xad49,0xad4a,0xad4b,0xad4c,0xad4d,0xad4e,0xad4f,
+ 0xad50,0xad51,0xad52,0xad53,0xad54,0xad55,0xad56,0xad57,
+ 0xad58,0xad59,0xad5a,0xad5b,0xad5c,0xad5d,0xad5e,0xad5f,
+ 0xad60,0xad61,0xad62,0xad63,0xad64,0xad65,0xad66,0xad67,
+ 0xad68,0xad69,0xad6a,0xad6b,0xad6c,0xad6d,0xad6e,0xad6f,
+ 0xad70,0xad71,0xad72,0xad73,0xad74,0xad75,0xad76,0xad77,
+ 0xad78,0xad79,0xad7a,0xad7b,0xad7c,0xad7d,0xad7e,0xad7f,
+ 0xad80,0xad81,0xad82,0xad83,0xad84,0xad85,0xad86,0xad87,
+ 0xad88,0xad89,0xad8a,0xad8b,0xad8c,0xad8d,0xad8e,0xad8f,
+ 0xad90,0xad91,0xad92,0xad93,0xad94,0xad95,0xad96,0xad97,
+ 0xad98,0xad99,0xad9a,0xad9b,0xad9c,0xad9d,0xad9e,0xad9f,
+ 0xada0,0xada1,0xada2,0xada3,0xada4,0xada5,0xada6,0xada7,
+ 0xada8,0xada9,0xadaa,0xadab,0xadac,0xadad,0xadae,0xadaf,
+ 0xadb0,0xadb1,0xadb2,0xadb3,0xadb4,0xadb5,0xadb6,0xadb7,
+ 0xadb8,0xadb9,0xadba,0xadbb,0xadbc,0xadbd,0xadbe,0xadbf,
+ 0xadc0,0xadc1,0xadc2,0xadc3,0xadc4,0xadc5,0xadc6,0xadc7,
+ 0xadc8,0xadc9,0xadca,0xadcb,0xadcc,0xadcd,0xadce,0xadcf,
+ 0xadd0,0xadd1,0xadd2,0xadd3,0xadd4,0xadd5,0xadd6,0xadd7,
+ 0xadd8,0xadd9,0xadda,0xaddb,0xaddc,0xaddd,0xadde,0xaddf,
+ 0xade0,0xade1,0xade2,0xade3,0xade4,0xade5,0xade6,0xade7,
+ 0xade8,0xade9,0xadea,0xadeb,0xadec,0xaded,0xadee,0xadef,
+ 0xadf0,0xadf1,0xadf2,0xadf3,0xadf4,0xadf5,0xadf6,0xadf7,
+ 0xadf8,0xadf9,0xadfa,0xadfb,0xadfc,0xadfd,0xadfe,0xadff,
+ 0xae00,0xae01,0xae02,0xae03,0xae04,0xae05,0xae06,0xae07,
+ 0xae08,0xae09,0xae0a,0xae0b,0xae0c,0xae0d,0xae0e,0xae0f,
+ 0xae10,0xae11,0xae12,0xae13,0xae14,0xae15,0xae16,0xae17,
+ 0xae18,0xae19,0xae1a,0xae1b,0xae1c,0xae1d,0xae1e,0xae1f,
+ 0xae20,0xae21,0xae22,0xae23,0xae24,0xae25,0xae26,0xae27,
+ 0xae28,0xae29,0xae2a,0xae2b,0xae2c,0xae2d,0xae2e,0xae2f,
+ 0xae30,0xae31,0xae32,0xae33,0xae34,0xae35,0xae36,0xae37,
+ 0xae38,0xae39,0xae3a,0xae3b,0xae3c,0xae3d,0xae3e,0xae3f,
+ 0xae40,0xae41,0xae42,0xae43,0xae44,0xae45,0xae46,0xae47,
+ 0xae48,0xae49,0xae4a,0xae4b,0xae4c,0xae4d,0xae4e,0xae4f,
+ 0xae50,0xae51,0xae52,0xae53,0xae54,0xae55,0xae56,0xae57,
+ 0xae58,0xae59,0xae5a,0xae5b,0xae5c,0xae5d,0xae5e,0xae5f,
+ 0xae60,0xae61,0xae62,0xae63,0xae64,0xae65,0xae66,0xae67,
+ 0xae68,0xae69,0xae6a,0xae6b,0xae6c,0xae6d,0xae6e,0xae6f,
+ 0xae70,0xae71,0xae72,0xae73,0xae74,0xae75,0xae76,0xae77,
+ 0xae78,0xae79,0xae7a,0xae7b,0xae7c,0xae7d,0xae7e,0xae7f,
+ 0xae80,0xae81,0xae82,0xae83,0xae84,0xae85,0xae86,0xae87,
+ 0xae88,0xae89,0xae8a,0xae8b,0xae8c,0xae8d,0xae8e,0xae8f,
+ 0xae90,0xae91,0xae92,0xae93,0xae94,0xae95,0xae96,0xae97,
+ 0xae98,0xae99,0xae9a,0xae9b,0xae9c,0xae9d,0xae9e,0xae9f,
+ 0xaea0,0xaea1,0xaea2,0xaea3,0xaea4,0xaea5,0xaea6,0xaea7,
+ 0xaea8,0xaea9,0xaeaa,0xaeab,0xaeac,0xaead,0xaeae,0xaeaf,
+ 0xaeb0,0xaeb1,0xaeb2,0xaeb3,0xaeb4,0xaeb5,0xaeb6,0xaeb7,
+ 0xaeb8,0xaeb9,0xaeba,0xaebb,0xaebc,0xaebd,0xaebe,0xaebf,
+ 0xaec0,0xaec1,0xaec2,0xaec3,0xaec4,0xaec5,0xaec6,0xaec7,
+ 0xaec8,0xaec9,0xaeca,0xaecb,0xaecc,0xaecd,0xaece,0xaecf,
+ 0xaed0,0xaed1,0xaed2,0xaed3,0xaed4,0xaed5,0xaed6,0xaed7,
+ 0xaed8,0xaed9,0xaeda,0xaedb,0xaedc,0xaedd,0xaede,0xaedf,
+ 0xaee0,0xaee1,0xaee2,0xaee3,0xaee4,0xaee5,0xaee6,0xaee7,
+ 0xaee8,0xaee9,0xaeea,0xaeeb,0xaeec,0xaeed,0xaeee,0xaeef,
+ 0xaef0,0xaef1,0xaef2,0xaef3,0xaef4,0xaef5,0xaef6,0xaef7,
+ 0xaef8,0xaef9,0xaefa,0xaefb,0xaefc,0xaefd,0xaefe,0xaeff,
+ 0xaf00,0xaf01,0xaf02,0xaf03,0xaf04,0xaf05,0xaf06,0xaf07,
+ 0xaf08,0xaf09,0xaf0a,0xaf0b,0xaf0c,0xaf0d,0xaf0e,0xaf0f,
+ 0xaf10,0xaf11,0xaf12,0xaf13,0xaf14,0xaf15,0xaf16,0xaf17,
+ 0xaf18,0xaf19,0xaf1a,0xaf1b,0xaf1c,0xaf1d,0xaf1e,0xaf1f,
+ 0xaf20,0xaf21,0xaf22,0xaf23,0xaf24,0xaf25,0xaf26,0xaf27,
+ 0xaf28,0xaf29,0xaf2a,0xaf2b,0xaf2c,0xaf2d,0xaf2e,0xaf2f,
+ 0xaf30,0xaf31,0xaf32,0xaf33,0xaf34,0xaf35,0xaf36,0xaf37,
+ 0xaf38,0xaf39,0xaf3a,0xaf3b,0xaf3c,0xaf3d,0xaf3e,0xaf3f,
+ 0xaf40,0xaf41,0xaf42,0xaf43,0xaf44,0xaf45,0xaf46,0xaf47,
+ 0xaf48,0xaf49,0xaf4a,0xaf4b,0xaf4c,0xaf4d,0xaf4e,0xaf4f,
+ 0xaf50,0xaf51,0xaf52,0xaf53,0xaf54,0xaf55,0xaf56,0xaf57,
+ 0xaf58,0xaf59,0xaf5a,0xaf5b,0xaf5c,0xaf5d,0xaf5e,0xaf5f,
+ 0xaf60,0xaf61,0xaf62,0xaf63,0xaf64,0xaf65,0xaf66,0xaf67,
+ 0xaf68,0xaf69,0xaf6a,0xaf6b,0xaf6c,0xaf6d,0xaf6e,0xaf6f,
+ 0xaf70,0xaf71,0xaf72,0xaf73,0xaf74,0xaf75,0xaf76,0xaf77,
+ 0xaf78,0xaf79,0xaf7a,0xaf7b,0xaf7c,0xaf7d,0xaf7e,0xaf7f,
+ 0xaf80,0xaf81,0xaf82,0xaf83,0xaf84,0xaf85,0xaf86,0xaf87,
+ 0xaf88,0xaf89,0xaf8a,0xaf8b,0xaf8c,0xaf8d,0xaf8e,0xaf8f,
+ 0xaf90,0xaf91,0xaf92,0xaf93,0xaf94,0xaf95,0xaf96,0xaf97,
+ 0xaf98,0xaf99,0xaf9a,0xaf9b,0xaf9c,0xaf9d,0xaf9e,0xaf9f,
+ 0xafa0,0xafa1,0xafa2,0xafa3,0xafa4,0xafa5,0xafa6,0xafa7,
+ 0xafa8,0xafa9,0xafaa,0xafab,0xafac,0xafad,0xafae,0xafaf,
+ 0xafb0,0xafb1,0xafb2,0xafb3,0xafb4,0xafb5,0xafb6,0xafb7,
+ 0xafb8,0xafb9,0xafba,0xafbb,0xafbc,0xafbd,0xafbe,0xafbf,
+ 0xafc0,0xafc1,0xafc2,0xafc3,0xafc4,0xafc5,0xafc6,0xafc7,
+ 0xafc8,0xafc9,0xafca,0xafcb,0xafcc,0xafcd,0xafce,0xafcf,
+ 0xafd0,0xafd1,0xafd2,0xafd3,0xafd4,0xafd5,0xafd6,0xafd7,
+ 0xafd8,0xafd9,0xafda,0xafdb,0xafdc,0xafdd,0xafde,0xafdf,
+ 0xafe0,0xafe1,0xafe2,0xafe3,0xafe4,0xafe5,0xafe6,0xafe7,
+ 0xafe8,0xafe9,0xafea,0xafeb,0xafec,0xafed,0xafee,0xafef,
+ 0xaff0,0xaff1,0xaff2,0xaff3,0xaff4,0xaff5,0xaff6,0xaff7,
+ 0xaff8,0xaff9,0xaffa,0xaffb,0xaffc,0xaffd,0xaffe,0xafff,
+ 0xb000,0xb001,0xb002,0xb003,0xb004,0xb005,0xb006,0xb007,
+ 0xb008,0xb009,0xb00a,0xb00b,0xb00c,0xb00d,0xb00e,0xb00f,
+ 0xb010,0xb011,0xb012,0xb013,0xb014,0xb015,0xb016,0xb017,
+ 0xb018,0xb019,0xb01a,0xb01b,0xb01c,0xb01d,0xb01e,0xb01f,
+ 0xb020,0xb021,0xb022,0xb023,0xb024,0xb025,0xb026,0xb027,
+ 0xb028,0xb029,0xb02a,0xb02b,0xb02c,0xb02d,0xb02e,0xb02f,
+ 0xb030,0xb031,0xb032,0xb033,0xb034,0xb035,0xb036,0xb037,
+ 0xb038,0xb039,0xb03a,0xb03b,0xb03c,0xb03d,0xb03e,0xb03f,
+ 0xb040,0xb041,0xb042,0xb043,0xb044,0xb045,0xb046,0xb047,
+ 0xb048,0xb049,0xb04a,0xb04b,0xb04c,0xb04d,0xb04e,0xb04f,
+ 0xb050,0xb051,0xb052,0xb053,0xb054,0xb055,0xb056,0xb057,
+ 0xb058,0xb059,0xb05a,0xb05b,0xb05c,0xb05d,0xb05e,0xb05f,
+ 0xb060,0xb061,0xb062,0xb063,0xb064,0xb065,0xb066,0xb067,
+ 0xb068,0xb069,0xb06a,0xb06b,0xb06c,0xb06d,0xb06e,0xb06f,
+ 0xb070,0xb071,0xb072,0xb073,0xb074,0xb075,0xb076,0xb077,
+ 0xb078,0xb079,0xb07a,0xb07b,0xb07c,0xb07d,0xb07e,0xb07f,
+ 0xb080,0xb081,0xb082,0xb083,0xb084,0xb085,0xb086,0xb087,
+ 0xb088,0xb089,0xb08a,0xb08b,0xb08c,0xb08d,0xb08e,0xb08f,
+ 0xb090,0xb091,0xb092,0xb093,0xb094,0xb095,0xb096,0xb097,
+ 0xb098,0xb099,0xb09a,0xb09b,0xb09c,0xb09d,0xb09e,0xb09f,
+ 0xb0a0,0xb0a1,0xb0a2,0xb0a3,0xb0a4,0xb0a5,0xb0a6,0xb0a7,
+ 0xb0a8,0xb0a9,0xb0aa,0xb0ab,0xb0ac,0xb0ad,0xb0ae,0xb0af,
+ 0xb0b0,0xb0b1,0xb0b2,0xb0b3,0xb0b4,0xb0b5,0xb0b6,0xb0b7,
+ 0xb0b8,0xb0b9,0xb0ba,0xb0bb,0xb0bc,0xb0bd,0xb0be,0xb0bf,
+ 0xb0c0,0xb0c1,0xb0c2,0xb0c3,0xb0c4,0xb0c5,0xb0c6,0xb0c7,
+ 0xb0c8,0xb0c9,0xb0ca,0xb0cb,0xb0cc,0xb0cd,0xb0ce,0xb0cf,
+ 0xb0d0,0xb0d1,0xb0d2,0xb0d3,0xb0d4,0xb0d5,0xb0d6,0xb0d7,
+ 0xb0d8,0xb0d9,0xb0da,0xb0db,0xb0dc,0xb0dd,0xb0de,0xb0df,
+ 0xb0e0,0xb0e1,0xb0e2,0xb0e3,0xb0e4,0xb0e5,0xb0e6,0xb0e7,
+ 0xb0e8,0xb0e9,0xb0ea,0xb0eb,0xb0ec,0xb0ed,0xb0ee,0xb0ef,
+ 0xb0f0,0xb0f1,0xb0f2,0xb0f3,0xb0f4,0xb0f5,0xb0f6,0xb0f7,
+ 0xb0f8,0xb0f9,0xb0fa,0xb0fb,0xb0fc,0xb0fd,0xb0fe,0xb0ff,
+ 0xb100,0xb101,0xb102,0xb103,0xb104,0xb105,0xb106,0xb107,
+ 0xb108,0xb109,0xb10a,0xb10b,0xb10c,0xb10d,0xb10e,0xb10f,
+ 0xb110,0xb111,0xb112,0xb113,0xb114,0xb115,0xb116,0xb117,
+ 0xb118,0xb119,0xb11a,0xb11b,0xb11c,0xb11d,0xb11e,0xb11f,
+ 0xb120,0xb121,0xb122,0xb123,0xb124,0xb125,0xb126,0xb127,
+ 0xb128,0xb129,0xb12a,0xb12b,0xb12c,0xb12d,0xb12e,0xb12f,
+ 0xb130,0xb131,0xb132,0xb133,0xb134,0xb135,0xb136,0xb137,
+ 0xb138,0xb139,0xb13a,0xb13b,0xb13c,0xb13d,0xb13e,0xb13f,
+ 0xb140,0xb141,0xb142,0xb143,0xb144,0xb145,0xb146,0xb147,
+ 0xb148,0xb149,0xb14a,0xb14b,0xb14c,0xb14d,0xb14e,0xb14f,
+ 0xb150,0xb151,0xb152,0xb153,0xb154,0xb155,0xb156,0xb157,
+ 0xb158,0xb159,0xb15a,0xb15b,0xb15c,0xb15d,0xb15e,0xb15f,
+ 0xb160,0xb161,0xb162,0xb163,0xb164,0xb165,0xb166,0xb167,
+ 0xb168,0xb169,0xb16a,0xb16b,0xb16c,0xb16d,0xb16e,0xb16f,
+ 0xb170,0xb171,0xb172,0xb173,0xb174,0xb175,0xb176,0xb177,
+ 0xb178,0xb179,0xb17a,0xb17b,0xb17c,0xb17d,0xb17e,0xb17f,
+ 0xb180,0xb181,0xb182,0xb183,0xb184,0xb185,0xb186,0xb187,
+ 0xb188,0xb189,0xb18a,0xb18b,0xb18c,0xb18d,0xb18e,0xb18f,
+ 0xb190,0xb191,0xb192,0xb193,0xb194,0xb195,0xb196,0xb197,
+ 0xb198,0xb199,0xb19a,0xb19b,0xb19c,0xb19d,0xb19e,0xb19f,
+ 0xb1a0,0xb1a1,0xb1a2,0xb1a3,0xb1a4,0xb1a5,0xb1a6,0xb1a7,
+ 0xb1a8,0xb1a9,0xb1aa,0xb1ab,0xb1ac,0xb1ad,0xb1ae,0xb1af,
+ 0xb1b0,0xb1b1,0xb1b2,0xb1b3,0xb1b4,0xb1b5,0xb1b6,0xb1b7,
+ 0xb1b8,0xb1b9,0xb1ba,0xb1bb,0xb1bc,0xb1bd,0xb1be,0xb1bf,
+ 0xb1c0,0xb1c1,0xb1c2,0xb1c3,0xb1c4,0xb1c5,0xb1c6,0xb1c7,
+ 0xb1c8,0xb1c9,0xb1ca,0xb1cb,0xb1cc,0xb1cd,0xb1ce,0xb1cf,
+ 0xb1d0,0xb1d1,0xb1d2,0xb1d3,0xb1d4,0xb1d5,0xb1d6,0xb1d7,
+ 0xb1d8,0xb1d9,0xb1da,0xb1db,0xb1dc,0xb1dd,0xb1de,0xb1df,
+ 0xb1e0,0xb1e1,0xb1e2,0xb1e3,0xb1e4,0xb1e5,0xb1e6,0xb1e7,
+ 0xb1e8,0xb1e9,0xb1ea,0xb1eb,0xb1ec,0xb1ed,0xb1ee,0xb1ef,
+ 0xb1f0,0xb1f1,0xb1f2,0xb1f3,0xb1f4,0xb1f5,0xb1f6,0xb1f7,
+ 0xb1f8,0xb1f9,0xb1fa,0xb1fb,0xb1fc,0xb1fd,0xb1fe,0xb1ff,
+ 0xb200,0xb201,0xb202,0xb203,0xb204,0xb205,0xb206,0xb207,
+ 0xb208,0xb209,0xb20a,0xb20b,0xb20c,0xb20d,0xb20e,0xb20f,
+ 0xb210,0xb211,0xb212,0xb213,0xb214,0xb215,0xb216,0xb217,
+ 0xb218,0xb219,0xb21a,0xb21b,0xb21c,0xb21d,0xb21e,0xb21f,
+ 0xb220,0xb221,0xb222,0xb223,0xb224,0xb225,0xb226,0xb227,
+ 0xb228,0xb229,0xb22a,0xb22b,0xb22c,0xb22d,0xb22e,0xb22f,
+ 0xb230,0xb231,0xb232,0xb233,0xb234,0xb235,0xb236,0xb237,
+ 0xb238,0xb239,0xb23a,0xb23b,0xb23c,0xb23d,0xb23e,0xb23f,
+ 0xb240,0xb241,0xb242,0xb243,0xb244,0xb245,0xb246,0xb247,
+ 0xb248,0xb249,0xb24a,0xb24b,0xb24c,0xb24d,0xb24e,0xb24f,
+ 0xb250,0xb251,0xb252,0xb253,0xb254,0xb255,0xb256,0xb257,
+ 0xb258,0xb259,0xb25a,0xb25b,0xb25c,0xb25d,0xb25e,0xb25f,
+ 0xb260,0xb261,0xb262,0xb263,0xb264,0xb265,0xb266,0xb267,
+ 0xb268,0xb269,0xb26a,0xb26b,0xb26c,0xb26d,0xb26e,0xb26f,
+ 0xb270,0xb271,0xb272,0xb273,0xb274,0xb275,0xb276,0xb277,
+ 0xb278,0xb279,0xb27a,0xb27b,0xb27c,0xb27d,0xb27e,0xb27f,
+ 0xb280,0xb281,0xb282,0xb283,0xb284,0xb285,0xb286,0xb287,
+ 0xb288,0xb289,0xb28a,0xb28b,0xb28c,0xb28d,0xb28e,0xb28f,
+ 0xb290,0xb291,0xb292,0xb293,0xb294,0xb295,0xb296,0xb297,
+ 0xb298,0xb299,0xb29a,0xb29b,0xb29c,0xb29d,0xb29e,0xb29f,
+ 0xb2a0,0xb2a1,0xb2a2,0xb2a3,0xb2a4,0xb2a5,0xb2a6,0xb2a7,
+ 0xb2a8,0xb2a9,0xb2aa,0xb2ab,0xb2ac,0xb2ad,0xb2ae,0xb2af,
+ 0xb2b0,0xb2b1,0xb2b2,0xb2b3,0xb2b4,0xb2b5,0xb2b6,0xb2b7,
+ 0xb2b8,0xb2b9,0xb2ba,0xb2bb,0xb2bc,0xb2bd,0xb2be,0xb2bf,
+ 0xb2c0,0xb2c1,0xb2c2,0xb2c3,0xb2c4,0xb2c5,0xb2c6,0xb2c7,
+ 0xb2c8,0xb2c9,0xb2ca,0xb2cb,0xb2cc,0xb2cd,0xb2ce,0xb2cf,
+ 0xb2d0,0xb2d1,0xb2d2,0xb2d3,0xb2d4,0xb2d5,0xb2d6,0xb2d7,
+ 0xb2d8,0xb2d9,0xb2da,0xb2db,0xb2dc,0xb2dd,0xb2de,0xb2df,
+ 0xb2e0,0xb2e1,0xb2e2,0xb2e3,0xb2e4,0xb2e5,0xb2e6,0xb2e7,
+ 0xb2e8,0xb2e9,0xb2ea,0xb2eb,0xb2ec,0xb2ed,0xb2ee,0xb2ef,
+ 0xb2f0,0xb2f1,0xb2f2,0xb2f3,0xb2f4,0xb2f5,0xb2f6,0xb2f7,
+ 0xb2f8,0xb2f9,0xb2fa,0xb2fb,0xb2fc,0xb2fd,0xb2fe,0xb2ff,
+ 0xb300,0xb301,0xb302,0xb303,0xb304,0xb305,0xb306,0xb307,
+ 0xb308,0xb309,0xb30a,0xb30b,0xb30c,0xb30d,0xb30e,0xb30f,
+ 0xb310,0xb311,0xb312,0xb313,0xb314,0xb315,0xb316,0xb317,
+ 0xb318,0xb319,0xb31a,0xb31b,0xb31c,0xb31d,0xb31e,0xb31f,
+ 0xb320,0xb321,0xb322,0xb323,0xb324,0xb325,0xb326,0xb327,
+ 0xb328,0xb329,0xb32a,0xb32b,0xb32c,0xb32d,0xb32e,0xb32f,
+ 0xb330,0xb331,0xb332,0xb333,0xb334,0xb335,0xb336,0xb337,
+ 0xb338,0xb339,0xb33a,0xb33b,0xb33c,0xb33d,0xb33e,0xb33f,
+ 0xb340,0xb341,0xb342,0xb343,0xb344,0xb345,0xb346,0xb347,
+ 0xb348,0xb349,0xb34a,0xb34b,0xb34c,0xb34d,0xb34e,0xb34f,
+ 0xb350,0xb351,0xb352,0xb353,0xb354,0xb355,0xb356,0xb357,
+ 0xb358,0xb359,0xb35a,0xb35b,0xb35c,0xb35d,0xb35e,0xb35f,
+ 0xb360,0xb361,0xb362,0xb363,0xb364,0xb365,0xb366,0xb367,
+ 0xb368,0xb369,0xb36a,0xb36b,0xb36c,0xb36d,0xb36e,0xb36f,
+ 0xb370,0xb371,0xb372,0xb373,0xb374,0xb375,0xb376,0xb377,
+ 0xb378,0xb379,0xb37a,0xb37b,0xb37c,0xb37d,0xb37e,0xb37f,
+ 0xb380,0xb381,0xb382,0xb383,0xb384,0xb385,0xb386,0xb387,
+ 0xb388,0xb389,0xb38a,0xb38b,0xb38c,0xb38d,0xb38e,0xb38f,
+ 0xb390,0xb391,0xb392,0xb393,0xb394,0xb395,0xb396,0xb397,
+ 0xb398,0xb399,0xb39a,0xb39b,0xb39c,0xb39d,0xb39e,0xb39f,
+ 0xb3a0,0xb3a1,0xb3a2,0xb3a3,0xb3a4,0xb3a5,0xb3a6,0xb3a7,
+ 0xb3a8,0xb3a9,0xb3aa,0xb3ab,0xb3ac,0xb3ad,0xb3ae,0xb3af,
+ 0xb3b0,0xb3b1,0xb3b2,0xb3b3,0xb3b4,0xb3b5,0xb3b6,0xb3b7,
+ 0xb3b8,0xb3b9,0xb3ba,0xb3bb,0xb3bc,0xb3bd,0xb3be,0xb3bf,
+ 0xb3c0,0xb3c1,0xb3c2,0xb3c3,0xb3c4,0xb3c5,0xb3c6,0xb3c7,
+ 0xb3c8,0xb3c9,0xb3ca,0xb3cb,0xb3cc,0xb3cd,0xb3ce,0xb3cf,
+ 0xb3d0,0xb3d1,0xb3d2,0xb3d3,0xb3d4,0xb3d5,0xb3d6,0xb3d7,
+ 0xb3d8,0xb3d9,0xb3da,0xb3db,0xb3dc,0xb3dd,0xb3de,0xb3df,
+ 0xb3e0,0xb3e1,0xb3e2,0xb3e3,0xb3e4,0xb3e5,0xb3e6,0xb3e7,
+ 0xb3e8,0xb3e9,0xb3ea,0xb3eb,0xb3ec,0xb3ed,0xb3ee,0xb3ef,
+ 0xb3f0,0xb3f1,0xb3f2,0xb3f3,0xb3f4,0xb3f5,0xb3f6,0xb3f7,
+ 0xb3f8,0xb3f9,0xb3fa,0xb3fb,0xb3fc,0xb3fd,0xb3fe,0xb3ff,
+ 0xb400,0xb401,0xb402,0xb403,0xb404,0xb405,0xb406,0xb407,
+ 0xb408,0xb409,0xb40a,0xb40b,0xb40c,0xb40d,0xb40e,0xb40f,
+ 0xb410,0xb411,0xb412,0xb413,0xb414,0xb415,0xb416,0xb417,
+ 0xb418,0xb419,0xb41a,0xb41b,0xb41c,0xb41d,0xb41e,0xb41f,
+ 0xb420,0xb421,0xb422,0xb423,0xb424,0xb425,0xb426,0xb427,
+ 0xb428,0xb429,0xb42a,0xb42b,0xb42c,0xb42d,0xb42e,0xb42f,
+ 0xb430,0xb431,0xb432,0xb433,0xb434,0xb435,0xb436,0xb437,
+ 0xb438,0xb439,0xb43a,0xb43b,0xb43c,0xb43d,0xb43e,0xb43f,
+ 0xb440,0xb441,0xb442,0xb443,0xb444,0xb445,0xb446,0xb447,
+ 0xb448,0xb449,0xb44a,0xb44b,0xb44c,0xb44d,0xb44e,0xb44f,
+ 0xb450,0xb451,0xb452,0xb453,0xb454,0xb455,0xb456,0xb457,
+ 0xb458,0xb459,0xb45a,0xb45b,0xb45c,0xb45d,0xb45e,0xb45f,
+ 0xb460,0xb461,0xb462,0xb463,0xb464,0xb465,0xb466,0xb467,
+ 0xb468,0xb469,0xb46a,0xb46b,0xb46c,0xb46d,0xb46e,0xb46f,
+ 0xb470,0xb471,0xb472,0xb473,0xb474,0xb475,0xb476,0xb477,
+ 0xb478,0xb479,0xb47a,0xb47b,0xb47c,0xb47d,0xb47e,0xb47f,
+ 0xb480,0xb481,0xb482,0xb483,0xb484,0xb485,0xb486,0xb487,
+ 0xb488,0xb489,0xb48a,0xb48b,0xb48c,0xb48d,0xb48e,0xb48f,
+ 0xb490,0xb491,0xb492,0xb493,0xb494,0xb495,0xb496,0xb497,
+ 0xb498,0xb499,0xb49a,0xb49b,0xb49c,0xb49d,0xb49e,0xb49f,
+ 0xb4a0,0xb4a1,0xb4a2,0xb4a3,0xb4a4,0xb4a5,0xb4a6,0xb4a7,
+ 0xb4a8,0xb4a9,0xb4aa,0xb4ab,0xb4ac,0xb4ad,0xb4ae,0xb4af,
+ 0xb4b0,0xb4b1,0xb4b2,0xb4b3,0xb4b4,0xb4b5,0xb4b6,0xb4b7,
+ 0xb4b8,0xb4b9,0xb4ba,0xb4bb,0xb4bc,0xb4bd,0xb4be,0xb4bf,
+ 0xb4c0,0xb4c1,0xb4c2,0xb4c3,0xb4c4,0xb4c5,0xb4c6,0xb4c7,
+ 0xb4c8,0xb4c9,0xb4ca,0xb4cb,0xb4cc,0xb4cd,0xb4ce,0xb4cf,
+ 0xb4d0,0xb4d1,0xb4d2,0xb4d3,0xb4d4,0xb4d5,0xb4d6,0xb4d7,
+ 0xb4d8,0xb4d9,0xb4da,0xb4db,0xb4dc,0xb4dd,0xb4de,0xb4df,
+ 0xb4e0,0xb4e1,0xb4e2,0xb4e3,0xb4e4,0xb4e5,0xb4e6,0xb4e7,
+ 0xb4e8,0xb4e9,0xb4ea,0xb4eb,0xb4ec,0xb4ed,0xb4ee,0xb4ef,
+ 0xb4f0,0xb4f1,0xb4f2,0xb4f3,0xb4f4,0xb4f5,0xb4f6,0xb4f7,
+ 0xb4f8,0xb4f9,0xb4fa,0xb4fb,0xb4fc,0xb4fd,0xb4fe,0xb4ff,
+ 0xb500,0xb501,0xb502,0xb503,0xb504,0xb505,0xb506,0xb507,
+ 0xb508,0xb509,0xb50a,0xb50b,0xb50c,0xb50d,0xb50e,0xb50f,
+ 0xb510,0xb511,0xb512,0xb513,0xb514,0xb515,0xb516,0xb517,
+ 0xb518,0xb519,0xb51a,0xb51b,0xb51c,0xb51d,0xb51e,0xb51f,
+ 0xb520,0xb521,0xb522,0xb523,0xb524,0xb525,0xb526,0xb527,
+ 0xb528,0xb529,0xb52a,0xb52b,0xb52c,0xb52d,0xb52e,0xb52f,
+ 0xb530,0xb531,0xb532,0xb533,0xb534,0xb535,0xb536,0xb537,
+ 0xb538,0xb539,0xb53a,0xb53b,0xb53c,0xb53d,0xb53e,0xb53f,
+ 0xb540,0xb541,0xb542,0xb543,0xb544,0xb545,0xb546,0xb547,
+ 0xb548,0xb549,0xb54a,0xb54b,0xb54c,0xb54d,0xb54e,0xb54f,
+ 0xb550,0xb551,0xb552,0xb553,0xb554,0xb555,0xb556,0xb557,
+ 0xb558,0xb559,0xb55a,0xb55b,0xb55c,0xb55d,0xb55e,0xb55f,
+ 0xb560,0xb561,0xb562,0xb563,0xb564,0xb565,0xb566,0xb567,
+ 0xb568,0xb569,0xb56a,0xb56b,0xb56c,0xb56d,0xb56e,0xb56f,
+ 0xb570,0xb571,0xb572,0xb573,0xb574,0xb575,0xb576,0xb577,
+ 0xb578,0xb579,0xb57a,0xb57b,0xb57c,0xb57d,0xb57e,0xb57f,
+ 0xb580,0xb581,0xb582,0xb583,0xb584,0xb585,0xb586,0xb587,
+ 0xb588,0xb589,0xb58a,0xb58b,0xb58c,0xb58d,0xb58e,0xb58f,
+ 0xb590,0xb591,0xb592,0xb593,0xb594,0xb595,0xb596,0xb597,
+ 0xb598,0xb599,0xb59a,0xb59b,0xb59c,0xb59d,0xb59e,0xb59f,
+ 0xb5a0,0xb5a1,0xb5a2,0xb5a3,0xb5a4,0xb5a5,0xb5a6,0xb5a7,
+ 0xb5a8,0xb5a9,0xb5aa,0xb5ab,0xb5ac,0xb5ad,0xb5ae,0xb5af,
+ 0xb5b0,0xb5b1,0xb5b2,0xb5b3,0xb5b4,0xb5b5,0xb5b6,0xb5b7,
+ 0xb5b8,0xb5b9,0xb5ba,0xb5bb,0xb5bc,0xb5bd,0xb5be,0xb5bf,
+ 0xb5c0,0xb5c1,0xb5c2,0xb5c3,0xb5c4,0xb5c5,0xb5c6,0xb5c7,
+ 0xb5c8,0xb5c9,0xb5ca,0xb5cb,0xb5cc,0xb5cd,0xb5ce,0xb5cf,
+ 0xb5d0,0xb5d1,0xb5d2,0xb5d3,0xb5d4,0xb5d5,0xb5d6,0xb5d7,
+ 0xb5d8,0xb5d9,0xb5da,0xb5db,0xb5dc,0xb5dd,0xb5de,0xb5df,
+ 0xb5e0,0xb5e1,0xb5e2,0xb5e3,0xb5e4,0xb5e5,0xb5e6,0xb5e7,
+ 0xb5e8,0xb5e9,0xb5ea,0xb5eb,0xb5ec,0xb5ed,0xb5ee,0xb5ef,
+ 0xb5f0,0xb5f1,0xb5f2,0xb5f3,0xb5f4,0xb5f5,0xb5f6,0xb5f7,
+ 0xb5f8,0xb5f9,0xb5fa,0xb5fb,0xb5fc,0xb5fd,0xb5fe,0xb5ff,
+ 0xb600,0xb601,0xb602,0xb603,0xb604,0xb605,0xb606,0xb607,
+ 0xb608,0xb609,0xb60a,0xb60b,0xb60c,0xb60d,0xb60e,0xb60f,
+ 0xb610,0xb611,0xb612,0xb613,0xb614,0xb615,0xb616,0xb617,
+ 0xb618,0xb619,0xb61a,0xb61b,0xb61c,0xb61d,0xb61e,0xb61f,
+ 0xb620,0xb621,0xb622,0xb623,0xb624,0xb625,0xb626,0xb627,
+ 0xb628,0xb629,0xb62a,0xb62b,0xb62c,0xb62d,0xb62e,0xb62f,
+ 0xb630,0xb631,0xb632,0xb633,0xb634,0xb635,0xb636,0xb637,
+ 0xb638,0xb639,0xb63a,0xb63b,0xb63c,0xb63d,0xb63e,0xb63f,
+ 0xb640,0xb641,0xb642,0xb643,0xb644,0xb645,0xb646,0xb647,
+ 0xb648,0xb649,0xb64a,0xb64b,0xb64c,0xb64d,0xb64e,0xb64f,
+ 0xb650,0xb651,0xb652,0xb653,0xb654,0xb655,0xb656,0xb657,
+ 0xb658,0xb659,0xb65a,0xb65b,0xb65c,0xb65d,0xb65e,0xb65f,
+ 0xb660,0xb661,0xb662,0xb663,0xb664,0xb665,0xb666,0xb667,
+ 0xb668,0xb669,0xb66a,0xb66b,0xb66c,0xb66d,0xb66e,0xb66f,
+ 0xb670,0xb671,0xb672,0xb673,0xb674,0xb675,0xb676,0xb677,
+ 0xb678,0xb679,0xb67a,0xb67b,0xb67c,0xb67d,0xb67e,0xb67f,
+ 0xb680,0xb681,0xb682,0xb683,0xb684,0xb685,0xb686,0xb687,
+ 0xb688,0xb689,0xb68a,0xb68b,0xb68c,0xb68d,0xb68e,0xb68f,
+ 0xb690,0xb691,0xb692,0xb693,0xb694,0xb695,0xb696,0xb697,
+ 0xb698,0xb699,0xb69a,0xb69b,0xb69c,0xb69d,0xb69e,0xb69f,
+ 0xb6a0,0xb6a1,0xb6a2,0xb6a3,0xb6a4,0xb6a5,0xb6a6,0xb6a7,
+ 0xb6a8,0xb6a9,0xb6aa,0xb6ab,0xb6ac,0xb6ad,0xb6ae,0xb6af,
+ 0xb6b0,0xb6b1,0xb6b2,0xb6b3,0xb6b4,0xb6b5,0xb6b6,0xb6b7,
+ 0xb6b8,0xb6b9,0xb6ba,0xb6bb,0xb6bc,0xb6bd,0xb6be,0xb6bf,
+ 0xb6c0,0xb6c1,0xb6c2,0xb6c3,0xb6c4,0xb6c5,0xb6c6,0xb6c7,
+ 0xb6c8,0xb6c9,0xb6ca,0xb6cb,0xb6cc,0xb6cd,0xb6ce,0xb6cf,
+ 0xb6d0,0xb6d1,0xb6d2,0xb6d3,0xb6d4,0xb6d5,0xb6d6,0xb6d7,
+ 0xb6d8,0xb6d9,0xb6da,0xb6db,0xb6dc,0xb6dd,0xb6de,0xb6df,
+ 0xb6e0,0xb6e1,0xb6e2,0xb6e3,0xb6e4,0xb6e5,0xb6e6,0xb6e7,
+ 0xb6e8,0xb6e9,0xb6ea,0xb6eb,0xb6ec,0xb6ed,0xb6ee,0xb6ef,
+ 0xb6f0,0xb6f1,0xb6f2,0xb6f3,0xb6f4,0xb6f5,0xb6f6,0xb6f7,
+ 0xb6f8,0xb6f9,0xb6fa,0xb6fb,0xb6fc,0xb6fd,0xb6fe,0xb6ff,
+ 0xb700,0xb701,0xb702,0xb703,0xb704,0xb705,0xb706,0xb707,
+ 0xb708,0xb709,0xb70a,0xb70b,0xb70c,0xb70d,0xb70e,0xb70f,
+ 0xb710,0xb711,0xb712,0xb713,0xb714,0xb715,0xb716,0xb717,
+ 0xb718,0xb719,0xb71a,0xb71b,0xb71c,0xb71d,0xb71e,0xb71f,
+ 0xb720,0xb721,0xb722,0xb723,0xb724,0xb725,0xb726,0xb727,
+ 0xb728,0xb729,0xb72a,0xb72b,0xb72c,0xb72d,0xb72e,0xb72f,
+ 0xb730,0xb731,0xb732,0xb733,0xb734,0xb735,0xb736,0xb737,
+ 0xb738,0xb739,0xb73a,0xb73b,0xb73c,0xb73d,0xb73e,0xb73f,
+ 0xb740,0xb741,0xb742,0xb743,0xb744,0xb745,0xb746,0xb747,
+ 0xb748,0xb749,0xb74a,0xb74b,0xb74c,0xb74d,0xb74e,0xb74f,
+ 0xb750,0xb751,0xb752,0xb753,0xb754,0xb755,0xb756,0xb757,
+ 0xb758,0xb759,0xb75a,0xb75b,0xb75c,0xb75d,0xb75e,0xb75f,
+ 0xb760,0xb761,0xb762,0xb763,0xb764,0xb765,0xb766,0xb767,
+ 0xb768,0xb769,0xb76a,0xb76b,0xb76c,0xb76d,0xb76e,0xb76f,
+ 0xb770,0xb771,0xb772,0xb773,0xb774,0xb775,0xb776,0xb777,
+ 0xb778,0xb779,0xb77a,0xb77b,0xb77c,0xb77d,0xb77e,0xb77f,
+ 0xb780,0xb781,0xb782,0xb783,0xb784,0xb785,0xb786,0xb787,
+ 0xb788,0xb789,0xb78a,0xb78b,0xb78c,0xb78d,0xb78e,0xb78f,
+ 0xb790,0xb791,0xb792,0xb793,0xb794,0xb795,0xb796,0xb797,
+ 0xb798,0xb799,0xb79a,0xb79b,0xb79c,0xb79d,0xb79e,0xb79f,
+ 0xb7a0,0xb7a1,0xb7a2,0xb7a3,0xb7a4,0xb7a5,0xb7a6,0xb7a7,
+ 0xb7a8,0xb7a9,0xb7aa,0xb7ab,0xb7ac,0xb7ad,0xb7ae,0xb7af,
+ 0xb7b0,0xb7b1,0xb7b2,0xb7b3,0xb7b4,0xb7b5,0xb7b6,0xb7b7,
+ 0xb7b8,0xb7b9,0xb7ba,0xb7bb,0xb7bc,0xb7bd,0xb7be,0xb7bf,
+ 0xb7c0,0xb7c1,0xb7c2,0xb7c3,0xb7c4,0xb7c5,0xb7c6,0xb7c7,
+ 0xb7c8,0xb7c9,0xb7ca,0xb7cb,0xb7cc,0xb7cd,0xb7ce,0xb7cf,
+ 0xb7d0,0xb7d1,0xb7d2,0xb7d3,0xb7d4,0xb7d5,0xb7d6,0xb7d7,
+ 0xb7d8,0xb7d9,0xb7da,0xb7db,0xb7dc,0xb7dd,0xb7de,0xb7df,
+ 0xb7e0,0xb7e1,0xb7e2,0xb7e3,0xb7e4,0xb7e5,0xb7e6,0xb7e7,
+ 0xb7e8,0xb7e9,0xb7ea,0xb7eb,0xb7ec,0xb7ed,0xb7ee,0xb7ef,
+ 0xb7f0,0xb7f1,0xb7f2,0xb7f3,0xb7f4,0xb7f5,0xb7f6,0xb7f7,
+ 0xb7f8,0xb7f9,0xb7fa,0xb7fb,0xb7fc,0xb7fd,0xb7fe,0xb7ff,
+ 0xb800,0xb801,0xb802,0xb803,0xb804,0xb805,0xb806,0xb807,
+ 0xb808,0xb809,0xb80a,0xb80b,0xb80c,0xb80d,0xb80e,0xb80f,
+ 0xb810,0xb811,0xb812,0xb813,0xb814,0xb815,0xb816,0xb817,
+ 0xb818,0xb819,0xb81a,0xb81b,0xb81c,0xb81d,0xb81e,0xb81f,
+ 0xb820,0xb821,0xb822,0xb823,0xb824,0xb825,0xb826,0xb827,
+ 0xb828,0xb829,0xb82a,0xb82b,0xb82c,0xb82d,0xb82e,0xb82f,
+ 0xb830,0xb831,0xb832,0xb833,0xb834,0xb835,0xb836,0xb837,
+ 0xb838,0xb839,0xb83a,0xb83b,0xb83c,0xb83d,0xb83e,0xb83f,
+ 0xb840,0xb841,0xb842,0xb843,0xb844,0xb845,0xb846,0xb847,
+ 0xb848,0xb849,0xb84a,0xb84b,0xb84c,0xb84d,0xb84e,0xb84f,
+ 0xb850,0xb851,0xb852,0xb853,0xb854,0xb855,0xb856,0xb857,
+ 0xb858,0xb859,0xb85a,0xb85b,0xb85c,0xb85d,0xb85e,0xb85f,
+ 0xb860,0xb861,0xb862,0xb863,0xb864,0xb865,0xb866,0xb867,
+ 0xb868,0xb869,0xb86a,0xb86b,0xb86c,0xb86d,0xb86e,0xb86f,
+ 0xb870,0xb871,0xb872,0xb873,0xb874,0xb875,0xb876,0xb877,
+ 0xb878,0xb879,0xb87a,0xb87b,0xb87c,0xb87d,0xb87e,0xb87f,
+ 0xb880,0xb881,0xb882,0xb883,0xb884,0xb885,0xb886,0xb887,
+ 0xb888,0xb889,0xb88a,0xb88b,0xb88c,0xb88d,0xb88e,0xb88f,
+ 0xb890,0xb891,0xb892,0xb893,0xb894,0xb895,0xb896,0xb897,
+ 0xb898,0xb899,0xb89a,0xb89b,0xb89c,0xb89d,0xb89e,0xb89f,
+ 0xb8a0,0xb8a1,0xb8a2,0xb8a3,0xb8a4,0xb8a5,0xb8a6,0xb8a7,
+ 0xb8a8,0xb8a9,0xb8aa,0xb8ab,0xb8ac,0xb8ad,0xb8ae,0xb8af,
+ 0xb8b0,0xb8b1,0xb8b2,0xb8b3,0xb8b4,0xb8b5,0xb8b6,0xb8b7,
+ 0xb8b8,0xb8b9,0xb8ba,0xb8bb,0xb8bc,0xb8bd,0xb8be,0xb8bf,
+ 0xb8c0,0xb8c1,0xb8c2,0xb8c3,0xb8c4,0xb8c5,0xb8c6,0xb8c7,
+ 0xb8c8,0xb8c9,0xb8ca,0xb8cb,0xb8cc,0xb8cd,0xb8ce,0xb8cf,
+ 0xb8d0,0xb8d1,0xb8d2,0xb8d3,0xb8d4,0xb8d5,0xb8d6,0xb8d7,
+ 0xb8d8,0xb8d9,0xb8da,0xb8db,0xb8dc,0xb8dd,0xb8de,0xb8df,
+ 0xb8e0,0xb8e1,0xb8e2,0xb8e3,0xb8e4,0xb8e5,0xb8e6,0xb8e7,
+ 0xb8e8,0xb8e9,0xb8ea,0xb8eb,0xb8ec,0xb8ed,0xb8ee,0xb8ef,
+ 0xb8f0,0xb8f1,0xb8f2,0xb8f3,0xb8f4,0xb8f5,0xb8f6,0xb8f7,
+ 0xb8f8,0xb8f9,0xb8fa,0xb8fb,0xb8fc,0xb8fd,0xb8fe,0xb8ff,
+ 0xb900,0xb901,0xb902,0xb903,0xb904,0xb905,0xb906,0xb907,
+ 0xb908,0xb909,0xb90a,0xb90b,0xb90c,0xb90d,0xb90e,0xb90f,
+ 0xb910,0xb911,0xb912,0xb913,0xb914,0xb915,0xb916,0xb917,
+ 0xb918,0xb919,0xb91a,0xb91b,0xb91c,0xb91d,0xb91e,0xb91f,
+ 0xb920,0xb921,0xb922,0xb923,0xb924,0xb925,0xb926,0xb927,
+ 0xb928,0xb929,0xb92a,0xb92b,0xb92c,0xb92d,0xb92e,0xb92f,
+ 0xb930,0xb931,0xb932,0xb933,0xb934,0xb935,0xb936,0xb937,
+ 0xb938,0xb939,0xb93a,0xb93b,0xb93c,0xb93d,0xb93e,0xb93f,
+ 0xb940,0xb941,0xb942,0xb943,0xb944,0xb945,0xb946,0xb947,
+ 0xb948,0xb949,0xb94a,0xb94b,0xb94c,0xb94d,0xb94e,0xb94f,
+ 0xb950,0xb951,0xb952,0xb953,0xb954,0xb955,0xb956,0xb957,
+ 0xb958,0xb959,0xb95a,0xb95b,0xb95c,0xb95d,0xb95e,0xb95f,
+ 0xb960,0xb961,0xb962,0xb963,0xb964,0xb965,0xb966,0xb967,
+ 0xb968,0xb969,0xb96a,0xb96b,0xb96c,0xb96d,0xb96e,0xb96f,
+ 0xb970,0xb971,0xb972,0xb973,0xb974,0xb975,0xb976,0xb977,
+ 0xb978,0xb979,0xb97a,0xb97b,0xb97c,0xb97d,0xb97e,0xb97f,
+ 0xb980,0xb981,0xb982,0xb983,0xb984,0xb985,0xb986,0xb987,
+ 0xb988,0xb989,0xb98a,0xb98b,0xb98c,0xb98d,0xb98e,0xb98f,
+ 0xb990,0xb991,0xb992,0xb993,0xb994,0xb995,0xb996,0xb997,
+ 0xb998,0xb999,0xb99a,0xb99b,0xb99c,0xb99d,0xb99e,0xb99f,
+ 0xb9a0,0xb9a1,0xb9a2,0xb9a3,0xb9a4,0xb9a5,0xb9a6,0xb9a7,
+ 0xb9a8,0xb9a9,0xb9aa,0xb9ab,0xb9ac,0xb9ad,0xb9ae,0xb9af,
+ 0xb9b0,0xb9b1,0xb9b2,0xb9b3,0xb9b4,0xb9b5,0xb9b6,0xb9b7,
+ 0xb9b8,0xb9b9,0xb9ba,0xb9bb,0xb9bc,0xb9bd,0xb9be,0xb9bf,
+ 0xb9c0,0xb9c1,0xb9c2,0xb9c3,0xb9c4,0xb9c5,0xb9c6,0xb9c7,
+ 0xb9c8,0xb9c9,0xb9ca,0xb9cb,0xb9cc,0xb9cd,0xb9ce,0xb9cf,
+ 0xb9d0,0xb9d1,0xb9d2,0xb9d3,0xb9d4,0xb9d5,0xb9d6,0xb9d7,
+ 0xb9d8,0xb9d9,0xb9da,0xb9db,0xb9dc,0xb9dd,0xb9de,0xb9df,
+ 0xb9e0,0xb9e1,0xb9e2,0xb9e3,0xb9e4,0xb9e5,0xb9e6,0xb9e7,
+ 0xb9e8,0xb9e9,0xb9ea,0xb9eb,0xb9ec,0xb9ed,0xb9ee,0xb9ef,
+ 0xb9f0,0xb9f1,0xb9f2,0xb9f3,0xb9f4,0xb9f5,0xb9f6,0xb9f7,
+ 0xb9f8,0xb9f9,0xb9fa,0xb9fb,0xb9fc,0xb9fd,0xb9fe,0xb9ff,
+ 0xba00,0xba01,0xba02,0xba03,0xba04,0xba05,0xba06,0xba07,
+ 0xba08,0xba09,0xba0a,0xba0b,0xba0c,0xba0d,0xba0e,0xba0f,
+ 0xba10,0xba11,0xba12,0xba13,0xba14,0xba15,0xba16,0xba17,
+ 0xba18,0xba19,0xba1a,0xba1b,0xba1c,0xba1d,0xba1e,0xba1f,
+ 0xba20,0xba21,0xba22,0xba23,0xba24,0xba25,0xba26,0xba27,
+ 0xba28,0xba29,0xba2a,0xba2b,0xba2c,0xba2d,0xba2e,0xba2f,
+ 0xba30,0xba31,0xba32,0xba33,0xba34,0xba35,0xba36,0xba37,
+ 0xba38,0xba39,0xba3a,0xba3b,0xba3c,0xba3d,0xba3e,0xba3f,
+ 0xba40,0xba41,0xba42,0xba43,0xba44,0xba45,0xba46,0xba47,
+ 0xba48,0xba49,0xba4a,0xba4b,0xba4c,0xba4d,0xba4e,0xba4f,
+ 0xba50,0xba51,0xba52,0xba53,0xba54,0xba55,0xba56,0xba57,
+ 0xba58,0xba59,0xba5a,0xba5b,0xba5c,0xba5d,0xba5e,0xba5f,
+ 0xba60,0xba61,0xba62,0xba63,0xba64,0xba65,0xba66,0xba67,
+ 0xba68,0xba69,0xba6a,0xba6b,0xba6c,0xba6d,0xba6e,0xba6f,
+ 0xba70,0xba71,0xba72,0xba73,0xba74,0xba75,0xba76,0xba77,
+ 0xba78,0xba79,0xba7a,0xba7b,0xba7c,0xba7d,0xba7e,0xba7f,
+ 0xba80,0xba81,0xba82,0xba83,0xba84,0xba85,0xba86,0xba87,
+ 0xba88,0xba89,0xba8a,0xba8b,0xba8c,0xba8d,0xba8e,0xba8f,
+ 0xba90,0xba91,0xba92,0xba93,0xba94,0xba95,0xba96,0xba97,
+ 0xba98,0xba99,0xba9a,0xba9b,0xba9c,0xba9d,0xba9e,0xba9f,
+ 0xbaa0,0xbaa1,0xbaa2,0xbaa3,0xbaa4,0xbaa5,0xbaa6,0xbaa7,
+ 0xbaa8,0xbaa9,0xbaaa,0xbaab,0xbaac,0xbaad,0xbaae,0xbaaf,
+ 0xbab0,0xbab1,0xbab2,0xbab3,0xbab4,0xbab5,0xbab6,0xbab7,
+ 0xbab8,0xbab9,0xbaba,0xbabb,0xbabc,0xbabd,0xbabe,0xbabf,
+ 0xbac0,0xbac1,0xbac2,0xbac3,0xbac4,0xbac5,0xbac6,0xbac7,
+ 0xbac8,0xbac9,0xbaca,0xbacb,0xbacc,0xbacd,0xbace,0xbacf,
+ 0xbad0,0xbad1,0xbad2,0xbad3,0xbad4,0xbad5,0xbad6,0xbad7,
+ 0xbad8,0xbad9,0xbada,0xbadb,0xbadc,0xbadd,0xbade,0xbadf,
+ 0xbae0,0xbae1,0xbae2,0xbae3,0xbae4,0xbae5,0xbae6,0xbae7,
+ 0xbae8,0xbae9,0xbaea,0xbaeb,0xbaec,0xbaed,0xbaee,0xbaef,
+ 0xbaf0,0xbaf1,0xbaf2,0xbaf3,0xbaf4,0xbaf5,0xbaf6,0xbaf7,
+ 0xbaf8,0xbaf9,0xbafa,0xbafb,0xbafc,0xbafd,0xbafe,0xbaff,
+ 0xbb00,0xbb01,0xbb02,0xbb03,0xbb04,0xbb05,0xbb06,0xbb07,
+ 0xbb08,0xbb09,0xbb0a,0xbb0b,0xbb0c,0xbb0d,0xbb0e,0xbb0f,
+ 0xbb10,0xbb11,0xbb12,0xbb13,0xbb14,0xbb15,0xbb16,0xbb17,
+ 0xbb18,0xbb19,0xbb1a,0xbb1b,0xbb1c,0xbb1d,0xbb1e,0xbb1f,
+ 0xbb20,0xbb21,0xbb22,0xbb23,0xbb24,0xbb25,0xbb26,0xbb27,
+ 0xbb28,0xbb29,0xbb2a,0xbb2b,0xbb2c,0xbb2d,0xbb2e,0xbb2f,
+ 0xbb30,0xbb31,0xbb32,0xbb33,0xbb34,0xbb35,0xbb36,0xbb37,
+ 0xbb38,0xbb39,0xbb3a,0xbb3b,0xbb3c,0xbb3d,0xbb3e,0xbb3f,
+ 0xbb40,0xbb41,0xbb42,0xbb43,0xbb44,0xbb45,0xbb46,0xbb47,
+ 0xbb48,0xbb49,0xbb4a,0xbb4b,0xbb4c,0xbb4d,0xbb4e,0xbb4f,
+ 0xbb50,0xbb51,0xbb52,0xbb53,0xbb54,0xbb55,0xbb56,0xbb57,
+ 0xbb58,0xbb59,0xbb5a,0xbb5b,0xbb5c,0xbb5d,0xbb5e,0xbb5f,
+ 0xbb60,0xbb61,0xbb62,0xbb63,0xbb64,0xbb65,0xbb66,0xbb67,
+ 0xbb68,0xbb69,0xbb6a,0xbb6b,0xbb6c,0xbb6d,0xbb6e,0xbb6f,
+ 0xbb70,0xbb71,0xbb72,0xbb73,0xbb74,0xbb75,0xbb76,0xbb77,
+ 0xbb78,0xbb79,0xbb7a,0xbb7b,0xbb7c,0xbb7d,0xbb7e,0xbb7f,
+ 0xbb80,0xbb81,0xbb82,0xbb83,0xbb84,0xbb85,0xbb86,0xbb87,
+ 0xbb88,0xbb89,0xbb8a,0xbb8b,0xbb8c,0xbb8d,0xbb8e,0xbb8f,
+ 0xbb90,0xbb91,0xbb92,0xbb93,0xbb94,0xbb95,0xbb96,0xbb97,
+ 0xbb98,0xbb99,0xbb9a,0xbb9b,0xbb9c,0xbb9d,0xbb9e,0xbb9f,
+ 0xbba0,0xbba1,0xbba2,0xbba3,0xbba4,0xbba5,0xbba6,0xbba7,
+ 0xbba8,0xbba9,0xbbaa,0xbbab,0xbbac,0xbbad,0xbbae,0xbbaf,
+ 0xbbb0,0xbbb1,0xbbb2,0xbbb3,0xbbb4,0xbbb5,0xbbb6,0xbbb7,
+ 0xbbb8,0xbbb9,0xbbba,0xbbbb,0xbbbc,0xbbbd,0xbbbe,0xbbbf,
+ 0xbbc0,0xbbc1,0xbbc2,0xbbc3,0xbbc4,0xbbc5,0xbbc6,0xbbc7,
+ 0xbbc8,0xbbc9,0xbbca,0xbbcb,0xbbcc,0xbbcd,0xbbce,0xbbcf,
+ 0xbbd0,0xbbd1,0xbbd2,0xbbd3,0xbbd4,0xbbd5,0xbbd6,0xbbd7,
+ 0xbbd8,0xbbd9,0xbbda,0xbbdb,0xbbdc,0xbbdd,0xbbde,0xbbdf,
+ 0xbbe0,0xbbe1,0xbbe2,0xbbe3,0xbbe4,0xbbe5,0xbbe6,0xbbe7,
+ 0xbbe8,0xbbe9,0xbbea,0xbbeb,0xbbec,0xbbed,0xbbee,0xbbef,
+ 0xbbf0,0xbbf1,0xbbf2,0xbbf3,0xbbf4,0xbbf5,0xbbf6,0xbbf7,
+ 0xbbf8,0xbbf9,0xbbfa,0xbbfb,0xbbfc,0xbbfd,0xbbfe,0xbbff,
+ 0xbc00,0xbc01,0xbc02,0xbc03,0xbc04,0xbc05,0xbc06,0xbc07,
+ 0xbc08,0xbc09,0xbc0a,0xbc0b,0xbc0c,0xbc0d,0xbc0e,0xbc0f,
+ 0xbc10,0xbc11,0xbc12,0xbc13,0xbc14,0xbc15,0xbc16,0xbc17,
+ 0xbc18,0xbc19,0xbc1a,0xbc1b,0xbc1c,0xbc1d,0xbc1e,0xbc1f,
+ 0xbc20,0xbc21,0xbc22,0xbc23,0xbc24,0xbc25,0xbc26,0xbc27,
+ 0xbc28,0xbc29,0xbc2a,0xbc2b,0xbc2c,0xbc2d,0xbc2e,0xbc2f,
+ 0xbc30,0xbc31,0xbc32,0xbc33,0xbc34,0xbc35,0xbc36,0xbc37,
+ 0xbc38,0xbc39,0xbc3a,0xbc3b,0xbc3c,0xbc3d,0xbc3e,0xbc3f,
+ 0xbc40,0xbc41,0xbc42,0xbc43,0xbc44,0xbc45,0xbc46,0xbc47,
+ 0xbc48,0xbc49,0xbc4a,0xbc4b,0xbc4c,0xbc4d,0xbc4e,0xbc4f,
+ 0xbc50,0xbc51,0xbc52,0xbc53,0xbc54,0xbc55,0xbc56,0xbc57,
+ 0xbc58,0xbc59,0xbc5a,0xbc5b,0xbc5c,0xbc5d,0xbc5e,0xbc5f,
+ 0xbc60,0xbc61,0xbc62,0xbc63,0xbc64,0xbc65,0xbc66,0xbc67,
+ 0xbc68,0xbc69,0xbc6a,0xbc6b,0xbc6c,0xbc6d,0xbc6e,0xbc6f,
+ 0xbc70,0xbc71,0xbc72,0xbc73,0xbc74,0xbc75,0xbc76,0xbc77,
+ 0xbc78,0xbc79,0xbc7a,0xbc7b,0xbc7c,0xbc7d,0xbc7e,0xbc7f,
+ 0xbc80,0xbc81,0xbc82,0xbc83,0xbc84,0xbc85,0xbc86,0xbc87,
+ 0xbc88,0xbc89,0xbc8a,0xbc8b,0xbc8c,0xbc8d,0xbc8e,0xbc8f,
+ 0xbc90,0xbc91,0xbc92,0xbc93,0xbc94,0xbc95,0xbc96,0xbc97,
+ 0xbc98,0xbc99,0xbc9a,0xbc9b,0xbc9c,0xbc9d,0xbc9e,0xbc9f,
+ 0xbca0,0xbca1,0xbca2,0xbca3,0xbca4,0xbca5,0xbca6,0xbca7,
+ 0xbca8,0xbca9,0xbcaa,0xbcab,0xbcac,0xbcad,0xbcae,0xbcaf,
+ 0xbcb0,0xbcb1,0xbcb2,0xbcb3,0xbcb4,0xbcb5,0xbcb6,0xbcb7,
+ 0xbcb8,0xbcb9,0xbcba,0xbcbb,0xbcbc,0xbcbd,0xbcbe,0xbcbf,
+ 0xbcc0,0xbcc1,0xbcc2,0xbcc3,0xbcc4,0xbcc5,0xbcc6,0xbcc7,
+ 0xbcc8,0xbcc9,0xbcca,0xbccb,0xbccc,0xbccd,0xbcce,0xbccf,
+ 0xbcd0,0xbcd1,0xbcd2,0xbcd3,0xbcd4,0xbcd5,0xbcd6,0xbcd7,
+ 0xbcd8,0xbcd9,0xbcda,0xbcdb,0xbcdc,0xbcdd,0xbcde,0xbcdf,
+ 0xbce0,0xbce1,0xbce2,0xbce3,0xbce4,0xbce5,0xbce6,0xbce7,
+ 0xbce8,0xbce9,0xbcea,0xbceb,0xbcec,0xbced,0xbcee,0xbcef,
+ 0xbcf0,0xbcf1,0xbcf2,0xbcf3,0xbcf4,0xbcf5,0xbcf6,0xbcf7,
+ 0xbcf8,0xbcf9,0xbcfa,0xbcfb,0xbcfc,0xbcfd,0xbcfe,0xbcff,
+ 0xbd00,0xbd01,0xbd02,0xbd03,0xbd04,0xbd05,0xbd06,0xbd07,
+ 0xbd08,0xbd09,0xbd0a,0xbd0b,0xbd0c,0xbd0d,0xbd0e,0xbd0f,
+ 0xbd10,0xbd11,0xbd12,0xbd13,0xbd14,0xbd15,0xbd16,0xbd17,
+ 0xbd18,0xbd19,0xbd1a,0xbd1b,0xbd1c,0xbd1d,0xbd1e,0xbd1f,
+ 0xbd20,0xbd21,0xbd22,0xbd23,0xbd24,0xbd25,0xbd26,0xbd27,
+ 0xbd28,0xbd29,0xbd2a,0xbd2b,0xbd2c,0xbd2d,0xbd2e,0xbd2f,
+ 0xbd30,0xbd31,0xbd32,0xbd33,0xbd34,0xbd35,0xbd36,0xbd37,
+ 0xbd38,0xbd39,0xbd3a,0xbd3b,0xbd3c,0xbd3d,0xbd3e,0xbd3f,
+ 0xbd40,0xbd41,0xbd42,0xbd43,0xbd44,0xbd45,0xbd46,0xbd47,
+ 0xbd48,0xbd49,0xbd4a,0xbd4b,0xbd4c,0xbd4d,0xbd4e,0xbd4f,
+ 0xbd50,0xbd51,0xbd52,0xbd53,0xbd54,0xbd55,0xbd56,0xbd57,
+ 0xbd58,0xbd59,0xbd5a,0xbd5b,0xbd5c,0xbd5d,0xbd5e,0xbd5f,
+ 0xbd60,0xbd61,0xbd62,0xbd63,0xbd64,0xbd65,0xbd66,0xbd67,
+ 0xbd68,0xbd69,0xbd6a,0xbd6b,0xbd6c,0xbd6d,0xbd6e,0xbd6f,
+ 0xbd70,0xbd71,0xbd72,0xbd73,0xbd74,0xbd75,0xbd76,0xbd77,
+ 0xbd78,0xbd79,0xbd7a,0xbd7b,0xbd7c,0xbd7d,0xbd7e,0xbd7f,
+ 0xbd80,0xbd81,0xbd82,0xbd83,0xbd84,0xbd85,0xbd86,0xbd87,
+ 0xbd88,0xbd89,0xbd8a,0xbd8b,0xbd8c,0xbd8d,0xbd8e,0xbd8f,
+ 0xbd90,0xbd91,0xbd92,0xbd93,0xbd94,0xbd95,0xbd96,0xbd97,
+ 0xbd98,0xbd99,0xbd9a,0xbd9b,0xbd9c,0xbd9d,0xbd9e,0xbd9f,
+ 0xbda0,0xbda1,0xbda2,0xbda3,0xbda4,0xbda5,0xbda6,0xbda7,
+ 0xbda8,0xbda9,0xbdaa,0xbdab,0xbdac,0xbdad,0xbdae,0xbdaf,
+ 0xbdb0,0xbdb1,0xbdb2,0xbdb3,0xbdb4,0xbdb5,0xbdb6,0xbdb7,
+ 0xbdb8,0xbdb9,0xbdba,0xbdbb,0xbdbc,0xbdbd,0xbdbe,0xbdbf,
+ 0xbdc0,0xbdc1,0xbdc2,0xbdc3,0xbdc4,0xbdc5,0xbdc6,0xbdc7,
+ 0xbdc8,0xbdc9,0xbdca,0xbdcb,0xbdcc,0xbdcd,0xbdce,0xbdcf,
+ 0xbdd0,0xbdd1,0xbdd2,0xbdd3,0xbdd4,0xbdd5,0xbdd6,0xbdd7,
+ 0xbdd8,0xbdd9,0xbdda,0xbddb,0xbddc,0xbddd,0xbdde,0xbddf,
+ 0xbde0,0xbde1,0xbde2,0xbde3,0xbde4,0xbde5,0xbde6,0xbde7,
+ 0xbde8,0xbde9,0xbdea,0xbdeb,0xbdec,0xbded,0xbdee,0xbdef,
+ 0xbdf0,0xbdf1,0xbdf2,0xbdf3,0xbdf4,0xbdf5,0xbdf6,0xbdf7,
+ 0xbdf8,0xbdf9,0xbdfa,0xbdfb,0xbdfc,0xbdfd,0xbdfe,0xbdff,
+ 0xbe00,0xbe01,0xbe02,0xbe03,0xbe04,0xbe05,0xbe06,0xbe07,
+ 0xbe08,0xbe09,0xbe0a,0xbe0b,0xbe0c,0xbe0d,0xbe0e,0xbe0f,
+ 0xbe10,0xbe11,0xbe12,0xbe13,0xbe14,0xbe15,0xbe16,0xbe17,
+ 0xbe18,0xbe19,0xbe1a,0xbe1b,0xbe1c,0xbe1d,0xbe1e,0xbe1f,
+ 0xbe20,0xbe21,0xbe22,0xbe23,0xbe24,0xbe25,0xbe26,0xbe27,
+ 0xbe28,0xbe29,0xbe2a,0xbe2b,0xbe2c,0xbe2d,0xbe2e,0xbe2f,
+ 0xbe30,0xbe31,0xbe32,0xbe33,0xbe34,0xbe35,0xbe36,0xbe37,
+ 0xbe38,0xbe39,0xbe3a,0xbe3b,0xbe3c,0xbe3d,0xbe3e,0xbe3f,
+ 0xbe40,0xbe41,0xbe42,0xbe43,0xbe44,0xbe45,0xbe46,0xbe47,
+ 0xbe48,0xbe49,0xbe4a,0xbe4b,0xbe4c,0xbe4d,0xbe4e,0xbe4f,
+ 0xbe50,0xbe51,0xbe52,0xbe53,0xbe54,0xbe55,0xbe56,0xbe57,
+ 0xbe58,0xbe59,0xbe5a,0xbe5b,0xbe5c,0xbe5d,0xbe5e,0xbe5f,
+ 0xbe60,0xbe61,0xbe62,0xbe63,0xbe64,0xbe65,0xbe66,0xbe67,
+ 0xbe68,0xbe69,0xbe6a,0xbe6b,0xbe6c,0xbe6d,0xbe6e,0xbe6f,
+ 0xbe70,0xbe71,0xbe72,0xbe73,0xbe74,0xbe75,0xbe76,0xbe77,
+ 0xbe78,0xbe79,0xbe7a,0xbe7b,0xbe7c,0xbe7d,0xbe7e,0xbe7f,
+ 0xbe80,0xbe81,0xbe82,0xbe83,0xbe84,0xbe85,0xbe86,0xbe87,
+ 0xbe88,0xbe89,0xbe8a,0xbe8b,0xbe8c,0xbe8d,0xbe8e,0xbe8f,
+ 0xbe90,0xbe91,0xbe92,0xbe93,0xbe94,0xbe95,0xbe96,0xbe97,
+ 0xbe98,0xbe99,0xbe9a,0xbe9b,0xbe9c,0xbe9d,0xbe9e,0xbe9f,
+ 0xbea0,0xbea1,0xbea2,0xbea3,0xbea4,0xbea5,0xbea6,0xbea7,
+ 0xbea8,0xbea9,0xbeaa,0xbeab,0xbeac,0xbead,0xbeae,0xbeaf,
+ 0xbeb0,0xbeb1,0xbeb2,0xbeb3,0xbeb4,0xbeb5,0xbeb6,0xbeb7,
+ 0xbeb8,0xbeb9,0xbeba,0xbebb,0xbebc,0xbebd,0xbebe,0xbebf,
+ 0xbec0,0xbec1,0xbec2,0xbec3,0xbec4,0xbec5,0xbec6,0xbec7,
+ 0xbec8,0xbec9,0xbeca,0xbecb,0xbecc,0xbecd,0xbece,0xbecf,
+ 0xbed0,0xbed1,0xbed2,0xbed3,0xbed4,0xbed5,0xbed6,0xbed7,
+ 0xbed8,0xbed9,0xbeda,0xbedb,0xbedc,0xbedd,0xbede,0xbedf,
+ 0xbee0,0xbee1,0xbee2,0xbee3,0xbee4,0xbee5,0xbee6,0xbee7,
+ 0xbee8,0xbee9,0xbeea,0xbeeb,0xbeec,0xbeed,0xbeee,0xbeef,
+ 0xbef0,0xbef1,0xbef2,0xbef3,0xbef4,0xbef5,0xbef6,0xbef7,
+ 0xbef8,0xbef9,0xbefa,0xbefb,0xbefc,0xbefd,0xbefe,0xbeff,
+ 0xbf00,0xbf01,0xbf02,0xbf03,0xbf04,0xbf05,0xbf06,0xbf07,
+ 0xbf08,0xbf09,0xbf0a,0xbf0b,0xbf0c,0xbf0d,0xbf0e,0xbf0f,
+ 0xbf10,0xbf11,0xbf12,0xbf13,0xbf14,0xbf15,0xbf16,0xbf17,
+ 0xbf18,0xbf19,0xbf1a,0xbf1b,0xbf1c,0xbf1d,0xbf1e,0xbf1f,
+ 0xbf20,0xbf21,0xbf22,0xbf23,0xbf24,0xbf25,0xbf26,0xbf27,
+ 0xbf28,0xbf29,0xbf2a,0xbf2b,0xbf2c,0xbf2d,0xbf2e,0xbf2f,
+ 0xbf30,0xbf31,0xbf32,0xbf33,0xbf34,0xbf35,0xbf36,0xbf37,
+ 0xbf38,0xbf39,0xbf3a,0xbf3b,0xbf3c,0xbf3d,0xbf3e,0xbf3f,
+ 0xbf40,0xbf41,0xbf42,0xbf43,0xbf44,0xbf45,0xbf46,0xbf47,
+ 0xbf48,0xbf49,0xbf4a,0xbf4b,0xbf4c,0xbf4d,0xbf4e,0xbf4f,
+ 0xbf50,0xbf51,0xbf52,0xbf53,0xbf54,0xbf55,0xbf56,0xbf57,
+ 0xbf58,0xbf59,0xbf5a,0xbf5b,0xbf5c,0xbf5d,0xbf5e,0xbf5f,
+ 0xbf60,0xbf61,0xbf62,0xbf63,0xbf64,0xbf65,0xbf66,0xbf67,
+ 0xbf68,0xbf69,0xbf6a,0xbf6b,0xbf6c,0xbf6d,0xbf6e,0xbf6f,
+ 0xbf70,0xbf71,0xbf72,0xbf73,0xbf74,0xbf75,0xbf76,0xbf77,
+ 0xbf78,0xbf79,0xbf7a,0xbf7b,0xbf7c,0xbf7d,0xbf7e,0xbf7f,
+ 0xbf80,0xbf81,0xbf82,0xbf83,0xbf84,0xbf85,0xbf86,0xbf87,
+ 0xbf88,0xbf89,0xbf8a,0xbf8b,0xbf8c,0xbf8d,0xbf8e,0xbf8f,
+ 0xbf90,0xbf91,0xbf92,0xbf93,0xbf94,0xbf95,0xbf96,0xbf97,
+ 0xbf98,0xbf99,0xbf9a,0xbf9b,0xbf9c,0xbf9d,0xbf9e,0xbf9f,
+ 0xbfa0,0xbfa1,0xbfa2,0xbfa3,0xbfa4,0xbfa5,0xbfa6,0xbfa7,
+ 0xbfa8,0xbfa9,0xbfaa,0xbfab,0xbfac,0xbfad,0xbfae,0xbfaf,
+ 0xbfb0,0xbfb1,0xbfb2,0xbfb3,0xbfb4,0xbfb5,0xbfb6,0xbfb7,
+ 0xbfb8,0xbfb9,0xbfba,0xbfbb,0xbfbc,0xbfbd,0xbfbe,0xbfbf,
+ 0xbfc0,0xbfc1,0xbfc2,0xbfc3,0xbfc4,0xbfc5,0xbfc6,0xbfc7,
+ 0xbfc8,0xbfc9,0xbfca,0xbfcb,0xbfcc,0xbfcd,0xbfce,0xbfcf,
+ 0xbfd0,0xbfd1,0xbfd2,0xbfd3,0xbfd4,0xbfd5,0xbfd6,0xbfd7,
+ 0xbfd8,0xbfd9,0xbfda,0xbfdb,0xbfdc,0xbfdd,0xbfde,0xbfdf,
+ 0xbfe0,0xbfe1,0xbfe2,0xbfe3,0xbfe4,0xbfe5,0xbfe6,0xbfe7,
+ 0xbfe8,0xbfe9,0xbfea,0xbfeb,0xbfec,0xbfed,0xbfee,0xbfef,
+ 0xbff0,0xbff1,0xbff2,0xbff3,0xbff4,0xbff5,0xbff6,0xbff7,
+ 0xbff8,0xbff9,0xbffa,0xbffb,0xbffc,0xbffd,0xbffe,0xbfff,
+ 0xc000,0xc001,0xc002,0xc003,0xc004,0xc005,0xc006,0xc007,
+ 0xc008,0xc009,0xc00a,0xc00b,0xc00c,0xc00d,0xc00e,0xc00f,
+ 0xc010,0xc011,0xc012,0xc013,0xc014,0xc015,0xc016,0xc017,
+ 0xc018,0xc019,0xc01a,0xc01b,0xc01c,0xc01d,0xc01e,0xc01f,
+ 0xc020,0xc021,0xc022,0xc023,0xc024,0xc025,0xc026,0xc027,
+ 0xc028,0xc029,0xc02a,0xc02b,0xc02c,0xc02d,0xc02e,0xc02f,
+ 0xc030,0xc031,0xc032,0xc033,0xc034,0xc035,0xc036,0xc037,
+ 0xc038,0xc039,0xc03a,0xc03b,0xc03c,0xc03d,0xc03e,0xc03f,
+ 0xc040,0xc041,0xc042,0xc043,0xc044,0xc045,0xc046,0xc047,
+ 0xc048,0xc049,0xc04a,0xc04b,0xc04c,0xc04d,0xc04e,0xc04f,
+ 0xc050,0xc051,0xc052,0xc053,0xc054,0xc055,0xc056,0xc057,
+ 0xc058,0xc059,0xc05a,0xc05b,0xc05c,0xc05d,0xc05e,0xc05f,
+ 0xc060,0xc061,0xc062,0xc063,0xc064,0xc065,0xc066,0xc067,
+ 0xc068,0xc069,0xc06a,0xc06b,0xc06c,0xc06d,0xc06e,0xc06f,
+ 0xc070,0xc071,0xc072,0xc073,0xc074,0xc075,0xc076,0xc077,
+ 0xc078,0xc079,0xc07a,0xc07b,0xc07c,0xc07d,0xc07e,0xc07f,
+ 0xc080,0xc081,0xc082,0xc083,0xc084,0xc085,0xc086,0xc087,
+ 0xc088,0xc089,0xc08a,0xc08b,0xc08c,0xc08d,0xc08e,0xc08f,
+ 0xc090,0xc091,0xc092,0xc093,0xc094,0xc095,0xc096,0xc097,
+ 0xc098,0xc099,0xc09a,0xc09b,0xc09c,0xc09d,0xc09e,0xc09f,
+ 0xc0a0,0xc0a1,0xc0a2,0xc0a3,0xc0a4,0xc0a5,0xc0a6,0xc0a7,
+ 0xc0a8,0xc0a9,0xc0aa,0xc0ab,0xc0ac,0xc0ad,0xc0ae,0xc0af,
+ 0xc0b0,0xc0b1,0xc0b2,0xc0b3,0xc0b4,0xc0b5,0xc0b6,0xc0b7,
+ 0xc0b8,0xc0b9,0xc0ba,0xc0bb,0xc0bc,0xc0bd,0xc0be,0xc0bf,
+ 0xc0c0,0xc0c1,0xc0c2,0xc0c3,0xc0c4,0xc0c5,0xc0c6,0xc0c7,
+ 0xc0c8,0xc0c9,0xc0ca,0xc0cb,0xc0cc,0xc0cd,0xc0ce,0xc0cf,
+ 0xc0d0,0xc0d1,0xc0d2,0xc0d3,0xc0d4,0xc0d5,0xc0d6,0xc0d7,
+ 0xc0d8,0xc0d9,0xc0da,0xc0db,0xc0dc,0xc0dd,0xc0de,0xc0df,
+ 0xc0e0,0xc0e1,0xc0e2,0xc0e3,0xc0e4,0xc0e5,0xc0e6,0xc0e7,
+ 0xc0e8,0xc0e9,0xc0ea,0xc0eb,0xc0ec,0xc0ed,0xc0ee,0xc0ef,
+ 0xc0f0,0xc0f1,0xc0f2,0xc0f3,0xc0f4,0xc0f5,0xc0f6,0xc0f7,
+ 0xc0f8,0xc0f9,0xc0fa,0xc0fb,0xc0fc,0xc0fd,0xc0fe,0xc0ff,
+ 0xc100,0xc101,0xc102,0xc103,0xc104,0xc105,0xc106,0xc107,
+ 0xc108,0xc109,0xc10a,0xc10b,0xc10c,0xc10d,0xc10e,0xc10f,
+ 0xc110,0xc111,0xc112,0xc113,0xc114,0xc115,0xc116,0xc117,
+ 0xc118,0xc119,0xc11a,0xc11b,0xc11c,0xc11d,0xc11e,0xc11f,
+ 0xc120,0xc121,0xc122,0xc123,0xc124,0xc125,0xc126,0xc127,
+ 0xc128,0xc129,0xc12a,0xc12b,0xc12c,0xc12d,0xc12e,0xc12f,
+ 0xc130,0xc131,0xc132,0xc133,0xc134,0xc135,0xc136,0xc137,
+ 0xc138,0xc139,0xc13a,0xc13b,0xc13c,0xc13d,0xc13e,0xc13f,
+ 0xc140,0xc141,0xc142,0xc143,0xc144,0xc145,0xc146,0xc147,
+ 0xc148,0xc149,0xc14a,0xc14b,0xc14c,0xc14d,0xc14e,0xc14f,
+ 0xc150,0xc151,0xc152,0xc153,0xc154,0xc155,0xc156,0xc157,
+ 0xc158,0xc159,0xc15a,0xc15b,0xc15c,0xc15d,0xc15e,0xc15f,
+ 0xc160,0xc161,0xc162,0xc163,0xc164,0xc165,0xc166,0xc167,
+ 0xc168,0xc169,0xc16a,0xc16b,0xc16c,0xc16d,0xc16e,0xc16f,
+ 0xc170,0xc171,0xc172,0xc173,0xc174,0xc175,0xc176,0xc177,
+ 0xc178,0xc179,0xc17a,0xc17b,0xc17c,0xc17d,0xc17e,0xc17f,
+ 0xc180,0xc181,0xc182,0xc183,0xc184,0xc185,0xc186,0xc187,
+ 0xc188,0xc189,0xc18a,0xc18b,0xc18c,0xc18d,0xc18e,0xc18f,
+ 0xc190,0xc191,0xc192,0xc193,0xc194,0xc195,0xc196,0xc197,
+ 0xc198,0xc199,0xc19a,0xc19b,0xc19c,0xc19d,0xc19e,0xc19f,
+ 0xc1a0,0xc1a1,0xc1a2,0xc1a3,0xc1a4,0xc1a5,0xc1a6,0xc1a7,
+ 0xc1a8,0xc1a9,0xc1aa,0xc1ab,0xc1ac,0xc1ad,0xc1ae,0xc1af,
+ 0xc1b0,0xc1b1,0xc1b2,0xc1b3,0xc1b4,0xc1b5,0xc1b6,0xc1b7,
+ 0xc1b8,0xc1b9,0xc1ba,0xc1bb,0xc1bc,0xc1bd,0xc1be,0xc1bf,
+ 0xc1c0,0xc1c1,0xc1c2,0xc1c3,0xc1c4,0xc1c5,0xc1c6,0xc1c7,
+ 0xc1c8,0xc1c9,0xc1ca,0xc1cb,0xc1cc,0xc1cd,0xc1ce,0xc1cf,
+ 0xc1d0,0xc1d1,0xc1d2,0xc1d3,0xc1d4,0xc1d5,0xc1d6,0xc1d7,
+ 0xc1d8,0xc1d9,0xc1da,0xc1db,0xc1dc,0xc1dd,0xc1de,0xc1df,
+ 0xc1e0,0xc1e1,0xc1e2,0xc1e3,0xc1e4,0xc1e5,0xc1e6,0xc1e7,
+ 0xc1e8,0xc1e9,0xc1ea,0xc1eb,0xc1ec,0xc1ed,0xc1ee,0xc1ef,
+ 0xc1f0,0xc1f1,0xc1f2,0xc1f3,0xc1f4,0xc1f5,0xc1f6,0xc1f7,
+ 0xc1f8,0xc1f9,0xc1fa,0xc1fb,0xc1fc,0xc1fd,0xc1fe,0xc1ff,
+ 0xc200,0xc201,0xc202,0xc203,0xc204,0xc205,0xc206,0xc207,
+ 0xc208,0xc209,0xc20a,0xc20b,0xc20c,0xc20d,0xc20e,0xc20f,
+ 0xc210,0xc211,0xc212,0xc213,0xc214,0xc215,0xc216,0xc217,
+ 0xc218,0xc219,0xc21a,0xc21b,0xc21c,0xc21d,0xc21e,0xc21f,
+ 0xc220,0xc221,0xc222,0xc223,0xc224,0xc225,0xc226,0xc227,
+ 0xc228,0xc229,0xc22a,0xc22b,0xc22c,0xc22d,0xc22e,0xc22f,
+ 0xc230,0xc231,0xc232,0xc233,0xc234,0xc235,0xc236,0xc237,
+ 0xc238,0xc239,0xc23a,0xc23b,0xc23c,0xc23d,0xc23e,0xc23f,
+ 0xc240,0xc241,0xc242,0xc243,0xc244,0xc245,0xc246,0xc247,
+ 0xc248,0xc249,0xc24a,0xc24b,0xc24c,0xc24d,0xc24e,0xc24f,
+ 0xc250,0xc251,0xc252,0xc253,0xc254,0xc255,0xc256,0xc257,
+ 0xc258,0xc259,0xc25a,0xc25b,0xc25c,0xc25d,0xc25e,0xc25f,
+ 0xc260,0xc261,0xc262,0xc263,0xc264,0xc265,0xc266,0xc267,
+ 0xc268,0xc269,0xc26a,0xc26b,0xc26c,0xc26d,0xc26e,0xc26f,
+ 0xc270,0xc271,0xc272,0xc273,0xc274,0xc275,0xc276,0xc277,
+ 0xc278,0xc279,0xc27a,0xc27b,0xc27c,0xc27d,0xc27e,0xc27f,
+ 0xc280,0xc281,0xc282,0xc283,0xc284,0xc285,0xc286,0xc287,
+ 0xc288,0xc289,0xc28a,0xc28b,0xc28c,0xc28d,0xc28e,0xc28f,
+ 0xc290,0xc291,0xc292,0xc293,0xc294,0xc295,0xc296,0xc297,
+ 0xc298,0xc299,0xc29a,0xc29b,0xc29c,0xc29d,0xc29e,0xc29f,
+ 0xc2a0,0xc2a1,0xc2a2,0xc2a3,0xc2a4,0xc2a5,0xc2a6,0xc2a7,
+ 0xc2a8,0xc2a9,0xc2aa,0xc2ab,0xc2ac,0xc2ad,0xc2ae,0xc2af,
+ 0xc2b0,0xc2b1,0xc2b2,0xc2b3,0xc2b4,0xc2b5,0xc2b6,0xc2b7,
+ 0xc2b8,0xc2b9,0xc2ba,0xc2bb,0xc2bc,0xc2bd,0xc2be,0xc2bf,
+ 0xc2c0,0xc2c1,0xc2c2,0xc2c3,0xc2c4,0xc2c5,0xc2c6,0xc2c7,
+ 0xc2c8,0xc2c9,0xc2ca,0xc2cb,0xc2cc,0xc2cd,0xc2ce,0xc2cf,
+ 0xc2d0,0xc2d1,0xc2d2,0xc2d3,0xc2d4,0xc2d5,0xc2d6,0xc2d7,
+ 0xc2d8,0xc2d9,0xc2da,0xc2db,0xc2dc,0xc2dd,0xc2de,0xc2df,
+ 0xc2e0,0xc2e1,0xc2e2,0xc2e3,0xc2e4,0xc2e5,0xc2e6,0xc2e7,
+ 0xc2e8,0xc2e9,0xc2ea,0xc2eb,0xc2ec,0xc2ed,0xc2ee,0xc2ef,
+ 0xc2f0,0xc2f1,0xc2f2,0xc2f3,0xc2f4,0xc2f5,0xc2f6,0xc2f7,
+ 0xc2f8,0xc2f9,0xc2fa,0xc2fb,0xc2fc,0xc2fd,0xc2fe,0xc2ff,
+ 0xc300,0xc301,0xc302,0xc303,0xc304,0xc305,0xc306,0xc307,
+ 0xc308,0xc309,0xc30a,0xc30b,0xc30c,0xc30d,0xc30e,0xc30f,
+ 0xc310,0xc311,0xc312,0xc313,0xc314,0xc315,0xc316,0xc317,
+ 0xc318,0xc319,0xc31a,0xc31b,0xc31c,0xc31d,0xc31e,0xc31f,
+ 0xc320,0xc321,0xc322,0xc323,0xc324,0xc325,0xc326,0xc327,
+ 0xc328,0xc329,0xc32a,0xc32b,0xc32c,0xc32d,0xc32e,0xc32f,
+ 0xc330,0xc331,0xc332,0xc333,0xc334,0xc335,0xc336,0xc337,
+ 0xc338,0xc339,0xc33a,0xc33b,0xc33c,0xc33d,0xc33e,0xc33f,
+ 0xc340,0xc341,0xc342,0xc343,0xc344,0xc345,0xc346,0xc347,
+ 0xc348,0xc349,0xc34a,0xc34b,0xc34c,0xc34d,0xc34e,0xc34f,
+ 0xc350,0xc351,0xc352,0xc353,0xc354,0xc355,0xc356,0xc357,
+ 0xc358,0xc359,0xc35a,0xc35b,0xc35c,0xc35d,0xc35e,0xc35f,
+ 0xc360,0xc361,0xc362,0xc363,0xc364,0xc365,0xc366,0xc367,
+ 0xc368,0xc369,0xc36a,0xc36b,0xc36c,0xc36d,0xc36e,0xc36f,
+ 0xc370,0xc371,0xc372,0xc373,0xc374,0xc375,0xc376,0xc377,
+ 0xc378,0xc379,0xc37a,0xc37b,0xc37c,0xc37d,0xc37e,0xc37f,
+ 0xc380,0xc381,0xc382,0xc383,0xc384,0xc385,0xc386,0xc387,
+ 0xc388,0xc389,0xc38a,0xc38b,0xc38c,0xc38d,0xc38e,0xc38f,
+ 0xc390,0xc391,0xc392,0xc393,0xc394,0xc395,0xc396,0xc397,
+ 0xc398,0xc399,0xc39a,0xc39b,0xc39c,0xc39d,0xc39e,0xc39f,
+ 0xc3a0,0xc3a1,0xc3a2,0xc3a3,0xc3a4,0xc3a5,0xc3a6,0xc3a7,
+ 0xc3a8,0xc3a9,0xc3aa,0xc3ab,0xc3ac,0xc3ad,0xc3ae,0xc3af,
+ 0xc3b0,0xc3b1,0xc3b2,0xc3b3,0xc3b4,0xc3b5,0xc3b6,0xc3b7,
+ 0xc3b8,0xc3b9,0xc3ba,0xc3bb,0xc3bc,0xc3bd,0xc3be,0xc3bf,
+ 0xc3c0,0xc3c1,0xc3c2,0xc3c3,0xc3c4,0xc3c5,0xc3c6,0xc3c7,
+ 0xc3c8,0xc3c9,0xc3ca,0xc3cb,0xc3cc,0xc3cd,0xc3ce,0xc3cf,
+ 0xc3d0,0xc3d1,0xc3d2,0xc3d3,0xc3d4,0xc3d5,0xc3d6,0xc3d7,
+ 0xc3d8,0xc3d9,0xc3da,0xc3db,0xc3dc,0xc3dd,0xc3de,0xc3df,
+ 0xc3e0,0xc3e1,0xc3e2,0xc3e3,0xc3e4,0xc3e5,0xc3e6,0xc3e7,
+ 0xc3e8,0xc3e9,0xc3ea,0xc3eb,0xc3ec,0xc3ed,0xc3ee,0xc3ef,
+ 0xc3f0,0xc3f1,0xc3f2,0xc3f3,0xc3f4,0xc3f5,0xc3f6,0xc3f7,
+ 0xc3f8,0xc3f9,0xc3fa,0xc3fb,0xc3fc,0xc3fd,0xc3fe,0xc3ff,
+ 0xc400,0xc401,0xc402,0xc403,0xc404,0xc405,0xc406,0xc407,
+ 0xc408,0xc409,0xc40a,0xc40b,0xc40c,0xc40d,0xc40e,0xc40f,
+ 0xc410,0xc411,0xc412,0xc413,0xc414,0xc415,0xc416,0xc417,
+ 0xc418,0xc419,0xc41a,0xc41b,0xc41c,0xc41d,0xc41e,0xc41f,
+ 0xc420,0xc421,0xc422,0xc423,0xc424,0xc425,0xc426,0xc427,
+ 0xc428,0xc429,0xc42a,0xc42b,0xc42c,0xc42d,0xc42e,0xc42f,
+ 0xc430,0xc431,0xc432,0xc433,0xc434,0xc435,0xc436,0xc437,
+ 0xc438,0xc439,0xc43a,0xc43b,0xc43c,0xc43d,0xc43e,0xc43f,
+ 0xc440,0xc441,0xc442,0xc443,0xc444,0xc445,0xc446,0xc447,
+ 0xc448,0xc449,0xc44a,0xc44b,0xc44c,0xc44d,0xc44e,0xc44f,
+ 0xc450,0xc451,0xc452,0xc453,0xc454,0xc455,0xc456,0xc457,
+ 0xc458,0xc459,0xc45a,0xc45b,0xc45c,0xc45d,0xc45e,0xc45f,
+ 0xc460,0xc461,0xc462,0xc463,0xc464,0xc465,0xc466,0xc467,
+ 0xc468,0xc469,0xc46a,0xc46b,0xc46c,0xc46d,0xc46e,0xc46f,
+ 0xc470,0xc471,0xc472,0xc473,0xc474,0xc475,0xc476,0xc477,
+ 0xc478,0xc479,0xc47a,0xc47b,0xc47c,0xc47d,0xc47e,0xc47f,
+ 0xc480,0xc481,0xc482,0xc483,0xc484,0xc485,0xc486,0xc487,
+ 0xc488,0xc489,0xc48a,0xc48b,0xc48c,0xc48d,0xc48e,0xc48f,
+ 0xc490,0xc491,0xc492,0xc493,0xc494,0xc495,0xc496,0xc497,
+ 0xc498,0xc499,0xc49a,0xc49b,0xc49c,0xc49d,0xc49e,0xc49f,
+ 0xc4a0,0xc4a1,0xc4a2,0xc4a3,0xc4a4,0xc4a5,0xc4a6,0xc4a7,
+ 0xc4a8,0xc4a9,0xc4aa,0xc4ab,0xc4ac,0xc4ad,0xc4ae,0xc4af,
+ 0xc4b0,0xc4b1,0xc4b2,0xc4b3,0xc4b4,0xc4b5,0xc4b6,0xc4b7,
+ 0xc4b8,0xc4b9,0xc4ba,0xc4bb,0xc4bc,0xc4bd,0xc4be,0xc4bf,
+ 0xc4c0,0xc4c1,0xc4c2,0xc4c3,0xc4c4,0xc4c5,0xc4c6,0xc4c7,
+ 0xc4c8,0xc4c9,0xc4ca,0xc4cb,0xc4cc,0xc4cd,0xc4ce,0xc4cf,
+ 0xc4d0,0xc4d1,0xc4d2,0xc4d3,0xc4d4,0xc4d5,0xc4d6,0xc4d7,
+ 0xc4d8,0xc4d9,0xc4da,0xc4db,0xc4dc,0xc4dd,0xc4de,0xc4df,
+ 0xc4e0,0xc4e1,0xc4e2,0xc4e3,0xc4e4,0xc4e5,0xc4e6,0xc4e7,
+ 0xc4e8,0xc4e9,0xc4ea,0xc4eb,0xc4ec,0xc4ed,0xc4ee,0xc4ef,
+ 0xc4f0,0xc4f1,0xc4f2,0xc4f3,0xc4f4,0xc4f5,0xc4f6,0xc4f7,
+ 0xc4f8,0xc4f9,0xc4fa,0xc4fb,0xc4fc,0xc4fd,0xc4fe,0xc4ff,
+ 0xc500,0xc501,0xc502,0xc503,0xc504,0xc505,0xc506,0xc507,
+ 0xc508,0xc509,0xc50a,0xc50b,0xc50c,0xc50d,0xc50e,0xc50f,
+ 0xc510,0xc511,0xc512,0xc513,0xc514,0xc515,0xc516,0xc517,
+ 0xc518,0xc519,0xc51a,0xc51b,0xc51c,0xc51d,0xc51e,0xc51f,
+ 0xc520,0xc521,0xc522,0xc523,0xc524,0xc525,0xc526,0xc527,
+ 0xc528,0xc529,0xc52a,0xc52b,0xc52c,0xc52d,0xc52e,0xc52f,
+ 0xc530,0xc531,0xc532,0xc533,0xc534,0xc535,0xc536,0xc537,
+ 0xc538,0xc539,0xc53a,0xc53b,0xc53c,0xc53d,0xc53e,0xc53f,
+ 0xc540,0xc541,0xc542,0xc543,0xc544,0xc545,0xc546,0xc547,
+ 0xc548,0xc549,0xc54a,0xc54b,0xc54c,0xc54d,0xc54e,0xc54f,
+ 0xc550,0xc551,0xc552,0xc553,0xc554,0xc555,0xc556,0xc557,
+ 0xc558,0xc559,0xc55a,0xc55b,0xc55c,0xc55d,0xc55e,0xc55f,
+ 0xc560,0xc561,0xc562,0xc563,0xc564,0xc565,0xc566,0xc567,
+ 0xc568,0xc569,0xc56a,0xc56b,0xc56c,0xc56d,0xc56e,0xc56f,
+ 0xc570,0xc571,0xc572,0xc573,0xc574,0xc575,0xc576,0xc577,
+ 0xc578,0xc579,0xc57a,0xc57b,0xc57c,0xc57d,0xc57e,0xc57f,
+ 0xc580,0xc581,0xc582,0xc583,0xc584,0xc585,0xc586,0xc587,
+ 0xc588,0xc589,0xc58a,0xc58b,0xc58c,0xc58d,0xc58e,0xc58f,
+ 0xc590,0xc591,0xc592,0xc593,0xc594,0xc595,0xc596,0xc597,
+ 0xc598,0xc599,0xc59a,0xc59b,0xc59c,0xc59d,0xc59e,0xc59f,
+ 0xc5a0,0xc5a1,0xc5a2,0xc5a3,0xc5a4,0xc5a5,0xc5a6,0xc5a7,
+ 0xc5a8,0xc5a9,0xc5aa,0xc5ab,0xc5ac,0xc5ad,0xc5ae,0xc5af,
+ 0xc5b0,0xc5b1,0xc5b2,0xc5b3,0xc5b4,0xc5b5,0xc5b6,0xc5b7,
+ 0xc5b8,0xc5b9,0xc5ba,0xc5bb,0xc5bc,0xc5bd,0xc5be,0xc5bf,
+ 0xc5c0,0xc5c1,0xc5c2,0xc5c3,0xc5c4,0xc5c5,0xc5c6,0xc5c7,
+ 0xc5c8,0xc5c9,0xc5ca,0xc5cb,0xc5cc,0xc5cd,0xc5ce,0xc5cf,
+ 0xc5d0,0xc5d1,0xc5d2,0xc5d3,0xc5d4,0xc5d5,0xc5d6,0xc5d7,
+ 0xc5d8,0xc5d9,0xc5da,0xc5db,0xc5dc,0xc5dd,0xc5de,0xc5df,
+ 0xc5e0,0xc5e1,0xc5e2,0xc5e3,0xc5e4,0xc5e5,0xc5e6,0xc5e7,
+ 0xc5e8,0xc5e9,0xc5ea,0xc5eb,0xc5ec,0xc5ed,0xc5ee,0xc5ef,
+ 0xc5f0,0xc5f1,0xc5f2,0xc5f3,0xc5f4,0xc5f5,0xc5f6,0xc5f7,
+ 0xc5f8,0xc5f9,0xc5fa,0xc5fb,0xc5fc,0xc5fd,0xc5fe,0xc5ff,
+ 0xc600,0xc601,0xc602,0xc603,0xc604,0xc605,0xc606,0xc607,
+ 0xc608,0xc609,0xc60a,0xc60b,0xc60c,0xc60d,0xc60e,0xc60f,
+ 0xc610,0xc611,0xc612,0xc613,0xc614,0xc615,0xc616,0xc617,
+ 0xc618,0xc619,0xc61a,0xc61b,0xc61c,0xc61d,0xc61e,0xc61f,
+ 0xc620,0xc621,0xc622,0xc623,0xc624,0xc625,0xc626,0xc627,
+ 0xc628,0xc629,0xc62a,0xc62b,0xc62c,0xc62d,0xc62e,0xc62f,
+ 0xc630,0xc631,0xc632,0xc633,0xc634,0xc635,0xc636,0xc637,
+ 0xc638,0xc639,0xc63a,0xc63b,0xc63c,0xc63d,0xc63e,0xc63f,
+ 0xc640,0xc641,0xc642,0xc643,0xc644,0xc645,0xc646,0xc647,
+ 0xc648,0xc649,0xc64a,0xc64b,0xc64c,0xc64d,0xc64e,0xc64f,
+ 0xc650,0xc651,0xc652,0xc653,0xc654,0xc655,0xc656,0xc657,
+ 0xc658,0xc659,0xc65a,0xc65b,0xc65c,0xc65d,0xc65e,0xc65f,
+ 0xc660,0xc661,0xc662,0xc663,0xc664,0xc665,0xc666,0xc667,
+ 0xc668,0xc669,0xc66a,0xc66b,0xc66c,0xc66d,0xc66e,0xc66f,
+ 0xc670,0xc671,0xc672,0xc673,0xc674,0xc675,0xc676,0xc677,
+ 0xc678,0xc679,0xc67a,0xc67b,0xc67c,0xc67d,0xc67e,0xc67f,
+ 0xc680,0xc681,0xc682,0xc683,0xc684,0xc685,0xc686,0xc687,
+ 0xc688,0xc689,0xc68a,0xc68b,0xc68c,0xc68d,0xc68e,0xc68f,
+ 0xc690,0xc691,0xc692,0xc693,0xc694,0xc695,0xc696,0xc697,
+ 0xc698,0xc699,0xc69a,0xc69b,0xc69c,0xc69d,0xc69e,0xc69f,
+ 0xc6a0,0xc6a1,0xc6a2,0xc6a3,0xc6a4,0xc6a5,0xc6a6,0xc6a7,
+ 0xc6a8,0xc6a9,0xc6aa,0xc6ab,0xc6ac,0xc6ad,0xc6ae,0xc6af,
+ 0xc6b0,0xc6b1,0xc6b2,0xc6b3,0xc6b4,0xc6b5,0xc6b6,0xc6b7,
+ 0xc6b8,0xc6b9,0xc6ba,0xc6bb,0xc6bc,0xc6bd,0xc6be,0xc6bf,
+ 0xc6c0,0xc6c1,0xc6c2,0xc6c3,0xc6c4,0xc6c5,0xc6c6,0xc6c7,
+ 0xc6c8,0xc6c9,0xc6ca,0xc6cb,0xc6cc,0xc6cd,0xc6ce,0xc6cf,
+ 0xc6d0,0xc6d1,0xc6d2,0xc6d3,0xc6d4,0xc6d5,0xc6d6,0xc6d7,
+ 0xc6d8,0xc6d9,0xc6da,0xc6db,0xc6dc,0xc6dd,0xc6de,0xc6df,
+ 0xc6e0,0xc6e1,0xc6e2,0xc6e3,0xc6e4,0xc6e5,0xc6e6,0xc6e7,
+ 0xc6e8,0xc6e9,0xc6ea,0xc6eb,0xc6ec,0xc6ed,0xc6ee,0xc6ef,
+ 0xc6f0,0xc6f1,0xc6f2,0xc6f3,0xc6f4,0xc6f5,0xc6f6,0xc6f7,
+ 0xc6f8,0xc6f9,0xc6fa,0xc6fb,0xc6fc,0xc6fd,0xc6fe,0xc6ff,
+ 0xc700,0xc701,0xc702,0xc703,0xc704,0xc705,0xc706,0xc707,
+ 0xc708,0xc709,0xc70a,0xc70b,0xc70c,0xc70d,0xc70e,0xc70f,
+ 0xc710,0xc711,0xc712,0xc713,0xc714,0xc715,0xc716,0xc717,
+ 0xc718,0xc719,0xc71a,0xc71b,0xc71c,0xc71d,0xc71e,0xc71f,
+ 0xc720,0xc721,0xc722,0xc723,0xc724,0xc725,0xc726,0xc727,
+ 0xc728,0xc729,0xc72a,0xc72b,0xc72c,0xc72d,0xc72e,0xc72f,
+ 0xc730,0xc731,0xc732,0xc733,0xc734,0xc735,0xc736,0xc737,
+ 0xc738,0xc739,0xc73a,0xc73b,0xc73c,0xc73d,0xc73e,0xc73f,
+ 0xc740,0xc741,0xc742,0xc743,0xc744,0xc745,0xc746,0xc747,
+ 0xc748,0xc749,0xc74a,0xc74b,0xc74c,0xc74d,0xc74e,0xc74f,
+ 0xc750,0xc751,0xc752,0xc753,0xc754,0xc755,0xc756,0xc757,
+ 0xc758,0xc759,0xc75a,0xc75b,0xc75c,0xc75d,0xc75e,0xc75f,
+ 0xc760,0xc761,0xc762,0xc763,0xc764,0xc765,0xc766,0xc767,
+ 0xc768,0xc769,0xc76a,0xc76b,0xc76c,0xc76d,0xc76e,0xc76f,
+ 0xc770,0xc771,0xc772,0xc773,0xc774,0xc775,0xc776,0xc777,
+ 0xc778,0xc779,0xc77a,0xc77b,0xc77c,0xc77d,0xc77e,0xc77f,
+ 0xc780,0xc781,0xc782,0xc783,0xc784,0xc785,0xc786,0xc787,
+ 0xc788,0xc789,0xc78a,0xc78b,0xc78c,0xc78d,0xc78e,0xc78f,
+ 0xc790,0xc791,0xc792,0xc793,0xc794,0xc795,0xc796,0xc797,
+ 0xc798,0xc799,0xc79a,0xc79b,0xc79c,0xc79d,0xc79e,0xc79f,
+ 0xc7a0,0xc7a1,0xc7a2,0xc7a3,0xc7a4,0xc7a5,0xc7a6,0xc7a7,
+ 0xc7a8,0xc7a9,0xc7aa,0xc7ab,0xc7ac,0xc7ad,0xc7ae,0xc7af,
+ 0xc7b0,0xc7b1,0xc7b2,0xc7b3,0xc7b4,0xc7b5,0xc7b6,0xc7b7,
+ 0xc7b8,0xc7b9,0xc7ba,0xc7bb,0xc7bc,0xc7bd,0xc7be,0xc7bf,
+ 0xc7c0,0xc7c1,0xc7c2,0xc7c3,0xc7c4,0xc7c5,0xc7c6,0xc7c7,
+ 0xc7c8,0xc7c9,0xc7ca,0xc7cb,0xc7cc,0xc7cd,0xc7ce,0xc7cf,
+ 0xc7d0,0xc7d1,0xc7d2,0xc7d3,0xc7d4,0xc7d5,0xc7d6,0xc7d7,
+ 0xc7d8,0xc7d9,0xc7da,0xc7db,0xc7dc,0xc7dd,0xc7de,0xc7df,
+ 0xc7e0,0xc7e1,0xc7e2,0xc7e3,0xc7e4,0xc7e5,0xc7e6,0xc7e7,
+ 0xc7e8,0xc7e9,0xc7ea,0xc7eb,0xc7ec,0xc7ed,0xc7ee,0xc7ef,
+ 0xc7f0,0xc7f1,0xc7f2,0xc7f3,0xc7f4,0xc7f5,0xc7f6,0xc7f7,
+ 0xc7f8,0xc7f9,0xc7fa,0xc7fb,0xc7fc,0xc7fd,0xc7fe,0xc7ff,
+ 0xc800,0xc801,0xc802,0xc803,0xc804,0xc805,0xc806,0xc807,
+ 0xc808,0xc809,0xc80a,0xc80b,0xc80c,0xc80d,0xc80e,0xc80f,
+ 0xc810,0xc811,0xc812,0xc813,0xc814,0xc815,0xc816,0xc817,
+ 0xc818,0xc819,0xc81a,0xc81b,0xc81c,0xc81d,0xc81e,0xc81f,
+ 0xc820,0xc821,0xc822,0xc823,0xc824,0xc825,0xc826,0xc827,
+ 0xc828,0xc829,0xc82a,0xc82b,0xc82c,0xc82d,0xc82e,0xc82f,
+ 0xc830,0xc831,0xc832,0xc833,0xc834,0xc835,0xc836,0xc837,
+ 0xc838,0xc839,0xc83a,0xc83b,0xc83c,0xc83d,0xc83e,0xc83f,
+ 0xc840,0xc841,0xc842,0xc843,0xc844,0xc845,0xc846,0xc847,
+ 0xc848,0xc849,0xc84a,0xc84b,0xc84c,0xc84d,0xc84e,0xc84f,
+ 0xc850,0xc851,0xc852,0xc853,0xc854,0xc855,0xc856,0xc857,
+ 0xc858,0xc859,0xc85a,0xc85b,0xc85c,0xc85d,0xc85e,0xc85f,
+ 0xc860,0xc861,0xc862,0xc863,0xc864,0xc865,0xc866,0xc867,
+ 0xc868,0xc869,0xc86a,0xc86b,0xc86c,0xc86d,0xc86e,0xc86f,
+ 0xc870,0xc871,0xc872,0xc873,0xc874,0xc875,0xc876,0xc877,
+ 0xc878,0xc879,0xc87a,0xc87b,0xc87c,0xc87d,0xc87e,0xc87f,
+ 0xc880,0xc881,0xc882,0xc883,0xc884,0xc885,0xc886,0xc887,
+ 0xc888,0xc889,0xc88a,0xc88b,0xc88c,0xc88d,0xc88e,0xc88f,
+ 0xc890,0xc891,0xc892,0xc893,0xc894,0xc895,0xc896,0xc897,
+ 0xc898,0xc899,0xc89a,0xc89b,0xc89c,0xc89d,0xc89e,0xc89f,
+ 0xc8a0,0xc8a1,0xc8a2,0xc8a3,0xc8a4,0xc8a5,0xc8a6,0xc8a7,
+ 0xc8a8,0xc8a9,0xc8aa,0xc8ab,0xc8ac,0xc8ad,0xc8ae,0xc8af,
+ 0xc8b0,0xc8b1,0xc8b2,0xc8b3,0xc8b4,0xc8b5,0xc8b6,0xc8b7,
+ 0xc8b8,0xc8b9,0xc8ba,0xc8bb,0xc8bc,0xc8bd,0xc8be,0xc8bf,
+ 0xc8c0,0xc8c1,0xc8c2,0xc8c3,0xc8c4,0xc8c5,0xc8c6,0xc8c7,
+ 0xc8c8,0xc8c9,0xc8ca,0xc8cb,0xc8cc,0xc8cd,0xc8ce,0xc8cf,
+ 0xc8d0,0xc8d1,0xc8d2,0xc8d3,0xc8d4,0xc8d5,0xc8d6,0xc8d7,
+ 0xc8d8,0xc8d9,0xc8da,0xc8db,0xc8dc,0xc8dd,0xc8de,0xc8df,
+ 0xc8e0,0xc8e1,0xc8e2,0xc8e3,0xc8e4,0xc8e5,0xc8e6,0xc8e7,
+ 0xc8e8,0xc8e9,0xc8ea,0xc8eb,0xc8ec,0xc8ed,0xc8ee,0xc8ef,
+ 0xc8f0,0xc8f1,0xc8f2,0xc8f3,0xc8f4,0xc8f5,0xc8f6,0xc8f7,
+ 0xc8f8,0xc8f9,0xc8fa,0xc8fb,0xc8fc,0xc8fd,0xc8fe,0xc8ff,
+ 0xc900,0xc901,0xc902,0xc903,0xc904,0xc905,0xc906,0xc907,
+ 0xc908,0xc909,0xc90a,0xc90b,0xc90c,0xc90d,0xc90e,0xc90f,
+ 0xc910,0xc911,0xc912,0xc913,0xc914,0xc915,0xc916,0xc917,
+ 0xc918,0xc919,0xc91a,0xc91b,0xc91c,0xc91d,0xc91e,0xc91f,
+ 0xc920,0xc921,0xc922,0xc923,0xc924,0xc925,0xc926,0xc927,
+ 0xc928,0xc929,0xc92a,0xc92b,0xc92c,0xc92d,0xc92e,0xc92f,
+ 0xc930,0xc931,0xc932,0xc933,0xc934,0xc935,0xc936,0xc937,
+ 0xc938,0xc939,0xc93a,0xc93b,0xc93c,0xc93d,0xc93e,0xc93f,
+ 0xc940,0xc941,0xc942,0xc943,0xc944,0xc945,0xc946,0xc947,
+ 0xc948,0xc949,0xc94a,0xc94b,0xc94c,0xc94d,0xc94e,0xc94f,
+ 0xc950,0xc951,0xc952,0xc953,0xc954,0xc955,0xc956,0xc957,
+ 0xc958,0xc959,0xc95a,0xc95b,0xc95c,0xc95d,0xc95e,0xc95f,
+ 0xc960,0xc961,0xc962,0xc963,0xc964,0xc965,0xc966,0xc967,
+ 0xc968,0xc969,0xc96a,0xc96b,0xc96c,0xc96d,0xc96e,0xc96f,
+ 0xc970,0xc971,0xc972,0xc973,0xc974,0xc975,0xc976,0xc977,
+ 0xc978,0xc979,0xc97a,0xc97b,0xc97c,0xc97d,0xc97e,0xc97f,
+ 0xc980,0xc981,0xc982,0xc983,0xc984,0xc985,0xc986,0xc987,
+ 0xc988,0xc989,0xc98a,0xc98b,0xc98c,0xc98d,0xc98e,0xc98f,
+ 0xc990,0xc991,0xc992,0xc993,0xc994,0xc995,0xc996,0xc997,
+ 0xc998,0xc999,0xc99a,0xc99b,0xc99c,0xc99d,0xc99e,0xc99f,
+ 0xc9a0,0xc9a1,0xc9a2,0xc9a3,0xc9a4,0xc9a5,0xc9a6,0xc9a7,
+ 0xc9a8,0xc9a9,0xc9aa,0xc9ab,0xc9ac,0xc9ad,0xc9ae,0xc9af,
+ 0xc9b0,0xc9b1,0xc9b2,0xc9b3,0xc9b4,0xc9b5,0xc9b6,0xc9b7,
+ 0xc9b8,0xc9b9,0xc9ba,0xc9bb,0xc9bc,0xc9bd,0xc9be,0xc9bf,
+ 0xc9c0,0xc9c1,0xc9c2,0xc9c3,0xc9c4,0xc9c5,0xc9c6,0xc9c7,
+ 0xc9c8,0xc9c9,0xc9ca,0xc9cb,0xc9cc,0xc9cd,0xc9ce,0xc9cf,
+ 0xc9d0,0xc9d1,0xc9d2,0xc9d3,0xc9d4,0xc9d5,0xc9d6,0xc9d7,
+ 0xc9d8,0xc9d9,0xc9da,0xc9db,0xc9dc,0xc9dd,0xc9de,0xc9df,
+ 0xc9e0,0xc9e1,0xc9e2,0xc9e3,0xc9e4,0xc9e5,0xc9e6,0xc9e7,
+ 0xc9e8,0xc9e9,0xc9ea,0xc9eb,0xc9ec,0xc9ed,0xc9ee,0xc9ef,
+ 0xc9f0,0xc9f1,0xc9f2,0xc9f3,0xc9f4,0xc9f5,0xc9f6,0xc9f7,
+ 0xc9f8,0xc9f9,0xc9fa,0xc9fb,0xc9fc,0xc9fd,0xc9fe,0xc9ff,
+ 0xca00,0xca01,0xca02,0xca03,0xca04,0xca05,0xca06,0xca07,
+ 0xca08,0xca09,0xca0a,0xca0b,0xca0c,0xca0d,0xca0e,0xca0f,
+ 0xca10,0xca11,0xca12,0xca13,0xca14,0xca15,0xca16,0xca17,
+ 0xca18,0xca19,0xca1a,0xca1b,0xca1c,0xca1d,0xca1e,0xca1f,
+ 0xca20,0xca21,0xca22,0xca23,0xca24,0xca25,0xca26,0xca27,
+ 0xca28,0xca29,0xca2a,0xca2b,0xca2c,0xca2d,0xca2e,0xca2f,
+ 0xca30,0xca31,0xca32,0xca33,0xca34,0xca35,0xca36,0xca37,
+ 0xca38,0xca39,0xca3a,0xca3b,0xca3c,0xca3d,0xca3e,0xca3f,
+ 0xca40,0xca41,0xca42,0xca43,0xca44,0xca45,0xca46,0xca47,
+ 0xca48,0xca49,0xca4a,0xca4b,0xca4c,0xca4d,0xca4e,0xca4f,
+ 0xca50,0xca51,0xca52,0xca53,0xca54,0xca55,0xca56,0xca57,
+ 0xca58,0xca59,0xca5a,0xca5b,0xca5c,0xca5d,0xca5e,0xca5f,
+ 0xca60,0xca61,0xca62,0xca63,0xca64,0xca65,0xca66,0xca67,
+ 0xca68,0xca69,0xca6a,0xca6b,0xca6c,0xca6d,0xca6e,0xca6f,
+ 0xca70,0xca71,0xca72,0xca73,0xca74,0xca75,0xca76,0xca77,
+ 0xca78,0xca79,0xca7a,0xca7b,0xca7c,0xca7d,0xca7e,0xca7f,
+ 0xca80,0xca81,0xca82,0xca83,0xca84,0xca85,0xca86,0xca87,
+ 0xca88,0xca89,0xca8a,0xca8b,0xca8c,0xca8d,0xca8e,0xca8f,
+ 0xca90,0xca91,0xca92,0xca93,0xca94,0xca95,0xca96,0xca97,
+ 0xca98,0xca99,0xca9a,0xca9b,0xca9c,0xca9d,0xca9e,0xca9f,
+ 0xcaa0,0xcaa1,0xcaa2,0xcaa3,0xcaa4,0xcaa5,0xcaa6,0xcaa7,
+ 0xcaa8,0xcaa9,0xcaaa,0xcaab,0xcaac,0xcaad,0xcaae,0xcaaf,
+ 0xcab0,0xcab1,0xcab2,0xcab3,0xcab4,0xcab5,0xcab6,0xcab7,
+ 0xcab8,0xcab9,0xcaba,0xcabb,0xcabc,0xcabd,0xcabe,0xcabf,
+ 0xcac0,0xcac1,0xcac2,0xcac3,0xcac4,0xcac5,0xcac6,0xcac7,
+ 0xcac8,0xcac9,0xcaca,0xcacb,0xcacc,0xcacd,0xcace,0xcacf,
+ 0xcad0,0xcad1,0xcad2,0xcad3,0xcad4,0xcad5,0xcad6,0xcad7,
+ 0xcad8,0xcad9,0xcada,0xcadb,0xcadc,0xcadd,0xcade,0xcadf,
+ 0xcae0,0xcae1,0xcae2,0xcae3,0xcae4,0xcae5,0xcae6,0xcae7,
+ 0xcae8,0xcae9,0xcaea,0xcaeb,0xcaec,0xcaed,0xcaee,0xcaef,
+ 0xcaf0,0xcaf1,0xcaf2,0xcaf3,0xcaf4,0xcaf5,0xcaf6,0xcaf7,
+ 0xcaf8,0xcaf9,0xcafa,0xcafb,0xcafc,0xcafd,0xcafe,0xcaff,
+ 0xcb00,0xcb01,0xcb02,0xcb03,0xcb04,0xcb05,0xcb06,0xcb07,
+ 0xcb08,0xcb09,0xcb0a,0xcb0b,0xcb0c,0xcb0d,0xcb0e,0xcb0f,
+ 0xcb10,0xcb11,0xcb12,0xcb13,0xcb14,0xcb15,0xcb16,0xcb17,
+ 0xcb18,0xcb19,0xcb1a,0xcb1b,0xcb1c,0xcb1d,0xcb1e,0xcb1f,
+ 0xcb20,0xcb21,0xcb22,0xcb23,0xcb24,0xcb25,0xcb26,0xcb27,
+ 0xcb28,0xcb29,0xcb2a,0xcb2b,0xcb2c,0xcb2d,0xcb2e,0xcb2f,
+ 0xcb30,0xcb31,0xcb32,0xcb33,0xcb34,0xcb35,0xcb36,0xcb37,
+ 0xcb38,0xcb39,0xcb3a,0xcb3b,0xcb3c,0xcb3d,0xcb3e,0xcb3f,
+ 0xcb40,0xcb41,0xcb42,0xcb43,0xcb44,0xcb45,0xcb46,0xcb47,
+ 0xcb48,0xcb49,0xcb4a,0xcb4b,0xcb4c,0xcb4d,0xcb4e,0xcb4f,
+ 0xcb50,0xcb51,0xcb52,0xcb53,0xcb54,0xcb55,0xcb56,0xcb57,
+ 0xcb58,0xcb59,0xcb5a,0xcb5b,0xcb5c,0xcb5d,0xcb5e,0xcb5f,
+ 0xcb60,0xcb61,0xcb62,0xcb63,0xcb64,0xcb65,0xcb66,0xcb67,
+ 0xcb68,0xcb69,0xcb6a,0xcb6b,0xcb6c,0xcb6d,0xcb6e,0xcb6f,
+ 0xcb70,0xcb71,0xcb72,0xcb73,0xcb74,0xcb75,0xcb76,0xcb77,
+ 0xcb78,0xcb79,0xcb7a,0xcb7b,0xcb7c,0xcb7d,0xcb7e,0xcb7f,
+ 0xcb80,0xcb81,0xcb82,0xcb83,0xcb84,0xcb85,0xcb86,0xcb87,
+ 0xcb88,0xcb89,0xcb8a,0xcb8b,0xcb8c,0xcb8d,0xcb8e,0xcb8f,
+ 0xcb90,0xcb91,0xcb92,0xcb93,0xcb94,0xcb95,0xcb96,0xcb97,
+ 0xcb98,0xcb99,0xcb9a,0xcb9b,0xcb9c,0xcb9d,0xcb9e,0xcb9f,
+ 0xcba0,0xcba1,0xcba2,0xcba3,0xcba4,0xcba5,0xcba6,0xcba7,
+ 0xcba8,0xcba9,0xcbaa,0xcbab,0xcbac,0xcbad,0xcbae,0xcbaf,
+ 0xcbb0,0xcbb1,0xcbb2,0xcbb3,0xcbb4,0xcbb5,0xcbb6,0xcbb7,
+ 0xcbb8,0xcbb9,0xcbba,0xcbbb,0xcbbc,0xcbbd,0xcbbe,0xcbbf,
+ 0xcbc0,0xcbc1,0xcbc2,0xcbc3,0xcbc4,0xcbc5,0xcbc6,0xcbc7,
+ 0xcbc8,0xcbc9,0xcbca,0xcbcb,0xcbcc,0xcbcd,0xcbce,0xcbcf,
+ 0xcbd0,0xcbd1,0xcbd2,0xcbd3,0xcbd4,0xcbd5,0xcbd6,0xcbd7,
+ 0xcbd8,0xcbd9,0xcbda,0xcbdb,0xcbdc,0xcbdd,0xcbde,0xcbdf,
+ 0xcbe0,0xcbe1,0xcbe2,0xcbe3,0xcbe4,0xcbe5,0xcbe6,0xcbe7,
+ 0xcbe8,0xcbe9,0xcbea,0xcbeb,0xcbec,0xcbed,0xcbee,0xcbef,
+ 0xcbf0,0xcbf1,0xcbf2,0xcbf3,0xcbf4,0xcbf5,0xcbf6,0xcbf7,
+ 0xcbf8,0xcbf9,0xcbfa,0xcbfb,0xcbfc,0xcbfd,0xcbfe,0xcbff,
+ 0xcc00,0xcc01,0xcc02,0xcc03,0xcc04,0xcc05,0xcc06,0xcc07,
+ 0xcc08,0xcc09,0xcc0a,0xcc0b,0xcc0c,0xcc0d,0xcc0e,0xcc0f,
+ 0xcc10,0xcc11,0xcc12,0xcc13,0xcc14,0xcc15,0xcc16,0xcc17,
+ 0xcc18,0xcc19,0xcc1a,0xcc1b,0xcc1c,0xcc1d,0xcc1e,0xcc1f,
+ 0xcc20,0xcc21,0xcc22,0xcc23,0xcc24,0xcc25,0xcc26,0xcc27,
+ 0xcc28,0xcc29,0xcc2a,0xcc2b,0xcc2c,0xcc2d,0xcc2e,0xcc2f,
+ 0xcc30,0xcc31,0xcc32,0xcc33,0xcc34,0xcc35,0xcc36,0xcc37,
+ 0xcc38,0xcc39,0xcc3a,0xcc3b,0xcc3c,0xcc3d,0xcc3e,0xcc3f,
+ 0xcc40,0xcc41,0xcc42,0xcc43,0xcc44,0xcc45,0xcc46,0xcc47,
+ 0xcc48,0xcc49,0xcc4a,0xcc4b,0xcc4c,0xcc4d,0xcc4e,0xcc4f,
+ 0xcc50,0xcc51,0xcc52,0xcc53,0xcc54,0xcc55,0xcc56,0xcc57,
+ 0xcc58,0xcc59,0xcc5a,0xcc5b,0xcc5c,0xcc5d,0xcc5e,0xcc5f,
+ 0xcc60,0xcc61,0xcc62,0xcc63,0xcc64,0xcc65,0xcc66,0xcc67,
+ 0xcc68,0xcc69,0xcc6a,0xcc6b,0xcc6c,0xcc6d,0xcc6e,0xcc6f,
+ 0xcc70,0xcc71,0xcc72,0xcc73,0xcc74,0xcc75,0xcc76,0xcc77,
+ 0xcc78,0xcc79,0xcc7a,0xcc7b,0xcc7c,0xcc7d,0xcc7e,0xcc7f,
+ 0xcc80,0xcc81,0xcc82,0xcc83,0xcc84,0xcc85,0xcc86,0xcc87,
+ 0xcc88,0xcc89,0xcc8a,0xcc8b,0xcc8c,0xcc8d,0xcc8e,0xcc8f,
+ 0xcc90,0xcc91,0xcc92,0xcc93,0xcc94,0xcc95,0xcc96,0xcc97,
+ 0xcc98,0xcc99,0xcc9a,0xcc9b,0xcc9c,0xcc9d,0xcc9e,0xcc9f,
+ 0xcca0,0xcca1,0xcca2,0xcca3,0xcca4,0xcca5,0xcca6,0xcca7,
+ 0xcca8,0xcca9,0xccaa,0xccab,0xccac,0xccad,0xccae,0xccaf,
+ 0xccb0,0xccb1,0xccb2,0xccb3,0xccb4,0xccb5,0xccb6,0xccb7,
+ 0xccb8,0xccb9,0xccba,0xccbb,0xccbc,0xccbd,0xccbe,0xccbf,
+ 0xccc0,0xccc1,0xccc2,0xccc3,0xccc4,0xccc5,0xccc6,0xccc7,
+ 0xccc8,0xccc9,0xccca,0xcccb,0xcccc,0xcccd,0xccce,0xcccf,
+ 0xccd0,0xccd1,0xccd2,0xccd3,0xccd4,0xccd5,0xccd6,0xccd7,
+ 0xccd8,0xccd9,0xccda,0xccdb,0xccdc,0xccdd,0xccde,0xccdf,
+ 0xcce0,0xcce1,0xcce2,0xcce3,0xcce4,0xcce5,0xcce6,0xcce7,
+ 0xcce8,0xcce9,0xccea,0xcceb,0xccec,0xcced,0xccee,0xccef,
+ 0xccf0,0xccf1,0xccf2,0xccf3,0xccf4,0xccf5,0xccf6,0xccf7,
+ 0xccf8,0xccf9,0xccfa,0xccfb,0xccfc,0xccfd,0xccfe,0xccff,
+ 0xcd00,0xcd01,0xcd02,0xcd03,0xcd04,0xcd05,0xcd06,0xcd07,
+ 0xcd08,0xcd09,0xcd0a,0xcd0b,0xcd0c,0xcd0d,0xcd0e,0xcd0f,
+ 0xcd10,0xcd11,0xcd12,0xcd13,0xcd14,0xcd15,0xcd16,0xcd17,
+ 0xcd18,0xcd19,0xcd1a,0xcd1b,0xcd1c,0xcd1d,0xcd1e,0xcd1f,
+ 0xcd20,0xcd21,0xcd22,0xcd23,0xcd24,0xcd25,0xcd26,0xcd27,
+ 0xcd28,0xcd29,0xcd2a,0xcd2b,0xcd2c,0xcd2d,0xcd2e,0xcd2f,
+ 0xcd30,0xcd31,0xcd32,0xcd33,0xcd34,0xcd35,0xcd36,0xcd37,
+ 0xcd38,0xcd39,0xcd3a,0xcd3b,0xcd3c,0xcd3d,0xcd3e,0xcd3f,
+ 0xcd40,0xcd41,0xcd42,0xcd43,0xcd44,0xcd45,0xcd46,0xcd47,
+ 0xcd48,0xcd49,0xcd4a,0xcd4b,0xcd4c,0xcd4d,0xcd4e,0xcd4f,
+ 0xcd50,0xcd51,0xcd52,0xcd53,0xcd54,0xcd55,0xcd56,0xcd57,
+ 0xcd58,0xcd59,0xcd5a,0xcd5b,0xcd5c,0xcd5d,0xcd5e,0xcd5f,
+ 0xcd60,0xcd61,0xcd62,0xcd63,0xcd64,0xcd65,0xcd66,0xcd67,
+ 0xcd68,0xcd69,0xcd6a,0xcd6b,0xcd6c,0xcd6d,0xcd6e,0xcd6f,
+ 0xcd70,0xcd71,0xcd72,0xcd73,0xcd74,0xcd75,0xcd76,0xcd77,
+ 0xcd78,0xcd79,0xcd7a,0xcd7b,0xcd7c,0xcd7d,0xcd7e,0xcd7f,
+ 0xcd80,0xcd81,0xcd82,0xcd83,0xcd84,0xcd85,0xcd86,0xcd87,
+ 0xcd88,0xcd89,0xcd8a,0xcd8b,0xcd8c,0xcd8d,0xcd8e,0xcd8f,
+ 0xcd90,0xcd91,0xcd92,0xcd93,0xcd94,0xcd95,0xcd96,0xcd97,
+ 0xcd98,0xcd99,0xcd9a,0xcd9b,0xcd9c,0xcd9d,0xcd9e,0xcd9f,
+ 0xcda0,0xcda1,0xcda2,0xcda3,0xcda4,0xcda5,0xcda6,0xcda7,
+ 0xcda8,0xcda9,0xcdaa,0xcdab,0xcdac,0xcdad,0xcdae,0xcdaf,
+ 0xcdb0,0xcdb1,0xcdb2,0xcdb3,0xcdb4,0xcdb5,0xcdb6,0xcdb7,
+ 0xcdb8,0xcdb9,0xcdba,0xcdbb,0xcdbc,0xcdbd,0xcdbe,0xcdbf,
+ 0xcdc0,0xcdc1,0xcdc2,0xcdc3,0xcdc4,0xcdc5,0xcdc6,0xcdc7,
+ 0xcdc8,0xcdc9,0xcdca,0xcdcb,0xcdcc,0xcdcd,0xcdce,0xcdcf,
+ 0xcdd0,0xcdd1,0xcdd2,0xcdd3,0xcdd4,0xcdd5,0xcdd6,0xcdd7,
+ 0xcdd8,0xcdd9,0xcdda,0xcddb,0xcddc,0xcddd,0xcdde,0xcddf,
+ 0xcde0,0xcde1,0xcde2,0xcde3,0xcde4,0xcde5,0xcde6,0xcde7,
+ 0xcde8,0xcde9,0xcdea,0xcdeb,0xcdec,0xcded,0xcdee,0xcdef,
+ 0xcdf0,0xcdf1,0xcdf2,0xcdf3,0xcdf4,0xcdf5,0xcdf6,0xcdf7,
+ 0xcdf8,0xcdf9,0xcdfa,0xcdfb,0xcdfc,0xcdfd,0xcdfe,0xcdff,
+ 0xce00,0xce01,0xce02,0xce03,0xce04,0xce05,0xce06,0xce07,
+ 0xce08,0xce09,0xce0a,0xce0b,0xce0c,0xce0d,0xce0e,0xce0f,
+ 0xce10,0xce11,0xce12,0xce13,0xce14,0xce15,0xce16,0xce17,
+ 0xce18,0xce19,0xce1a,0xce1b,0xce1c,0xce1d,0xce1e,0xce1f,
+ 0xce20,0xce21,0xce22,0xce23,0xce24,0xce25,0xce26,0xce27,
+ 0xce28,0xce29,0xce2a,0xce2b,0xce2c,0xce2d,0xce2e,0xce2f,
+ 0xce30,0xce31,0xce32,0xce33,0xce34,0xce35,0xce36,0xce37,
+ 0xce38,0xce39,0xce3a,0xce3b,0xce3c,0xce3d,0xce3e,0xce3f,
+ 0xce40,0xce41,0xce42,0xce43,0xce44,0xce45,0xce46,0xce47,
+ 0xce48,0xce49,0xce4a,0xce4b,0xce4c,0xce4d,0xce4e,0xce4f,
+ 0xce50,0xce51,0xce52,0xce53,0xce54,0xce55,0xce56,0xce57,
+ 0xce58,0xce59,0xce5a,0xce5b,0xce5c,0xce5d,0xce5e,0xce5f,
+ 0xce60,0xce61,0xce62,0xce63,0xce64,0xce65,0xce66,0xce67,
+ 0xce68,0xce69,0xce6a,0xce6b,0xce6c,0xce6d,0xce6e,0xce6f,
+ 0xce70,0xce71,0xce72,0xce73,0xce74,0xce75,0xce76,0xce77,
+ 0xce78,0xce79,0xce7a,0xce7b,0xce7c,0xce7d,0xce7e,0xce7f,
+ 0xce80,0xce81,0xce82,0xce83,0xce84,0xce85,0xce86,0xce87,
+ 0xce88,0xce89,0xce8a,0xce8b,0xce8c,0xce8d,0xce8e,0xce8f,
+ 0xce90,0xce91,0xce92,0xce93,0xce94,0xce95,0xce96,0xce97,
+ 0xce98,0xce99,0xce9a,0xce9b,0xce9c,0xce9d,0xce9e,0xce9f,
+ 0xcea0,0xcea1,0xcea2,0xcea3,0xcea4,0xcea5,0xcea6,0xcea7,
+ 0xcea8,0xcea9,0xceaa,0xceab,0xceac,0xcead,0xceae,0xceaf,
+ 0xceb0,0xceb1,0xceb2,0xceb3,0xceb4,0xceb5,0xceb6,0xceb7,
+ 0xceb8,0xceb9,0xceba,0xcebb,0xcebc,0xcebd,0xcebe,0xcebf,
+ 0xcec0,0xcec1,0xcec2,0xcec3,0xcec4,0xcec5,0xcec6,0xcec7,
+ 0xcec8,0xcec9,0xceca,0xcecb,0xcecc,0xcecd,0xcece,0xcecf,
+ 0xced0,0xced1,0xced2,0xced3,0xced4,0xced5,0xced6,0xced7,
+ 0xced8,0xced9,0xceda,0xcedb,0xcedc,0xcedd,0xcede,0xcedf,
+ 0xcee0,0xcee1,0xcee2,0xcee3,0xcee4,0xcee5,0xcee6,0xcee7,
+ 0xcee8,0xcee9,0xceea,0xceeb,0xceec,0xceed,0xceee,0xceef,
+ 0xcef0,0xcef1,0xcef2,0xcef3,0xcef4,0xcef5,0xcef6,0xcef7,
+ 0xcef8,0xcef9,0xcefa,0xcefb,0xcefc,0xcefd,0xcefe,0xceff,
+ 0xcf00,0xcf01,0xcf02,0xcf03,0xcf04,0xcf05,0xcf06,0xcf07,
+ 0xcf08,0xcf09,0xcf0a,0xcf0b,0xcf0c,0xcf0d,0xcf0e,0xcf0f,
+ 0xcf10,0xcf11,0xcf12,0xcf13,0xcf14,0xcf15,0xcf16,0xcf17,
+ 0xcf18,0xcf19,0xcf1a,0xcf1b,0xcf1c,0xcf1d,0xcf1e,0xcf1f,
+ 0xcf20,0xcf21,0xcf22,0xcf23,0xcf24,0xcf25,0xcf26,0xcf27,
+ 0xcf28,0xcf29,0xcf2a,0xcf2b,0xcf2c,0xcf2d,0xcf2e,0xcf2f,
+ 0xcf30,0xcf31,0xcf32,0xcf33,0xcf34,0xcf35,0xcf36,0xcf37,
+ 0xcf38,0xcf39,0xcf3a,0xcf3b,0xcf3c,0xcf3d,0xcf3e,0xcf3f,
+ 0xcf40,0xcf41,0xcf42,0xcf43,0xcf44,0xcf45,0xcf46,0xcf47,
+ 0xcf48,0xcf49,0xcf4a,0xcf4b,0xcf4c,0xcf4d,0xcf4e,0xcf4f,
+ 0xcf50,0xcf51,0xcf52,0xcf53,0xcf54,0xcf55,0xcf56,0xcf57,
+ 0xcf58,0xcf59,0xcf5a,0xcf5b,0xcf5c,0xcf5d,0xcf5e,0xcf5f,
+ 0xcf60,0xcf61,0xcf62,0xcf63,0xcf64,0xcf65,0xcf66,0xcf67,
+ 0xcf68,0xcf69,0xcf6a,0xcf6b,0xcf6c,0xcf6d,0xcf6e,0xcf6f,
+ 0xcf70,0xcf71,0xcf72,0xcf73,0xcf74,0xcf75,0xcf76,0xcf77,
+ 0xcf78,0xcf79,0xcf7a,0xcf7b,0xcf7c,0xcf7d,0xcf7e,0xcf7f,
+ 0xcf80,0xcf81,0xcf82,0xcf83,0xcf84,0xcf85,0xcf86,0xcf87,
+ 0xcf88,0xcf89,0xcf8a,0xcf8b,0xcf8c,0xcf8d,0xcf8e,0xcf8f,
+ 0xcf90,0xcf91,0xcf92,0xcf93,0xcf94,0xcf95,0xcf96,0xcf97,
+ 0xcf98,0xcf99,0xcf9a,0xcf9b,0xcf9c,0xcf9d,0xcf9e,0xcf9f,
+ 0xcfa0,0xcfa1,0xcfa2,0xcfa3,0xcfa4,0xcfa5,0xcfa6,0xcfa7,
+ 0xcfa8,0xcfa9,0xcfaa,0xcfab,0xcfac,0xcfad,0xcfae,0xcfaf,
+ 0xcfb0,0xcfb1,0xcfb2,0xcfb3,0xcfb4,0xcfb5,0xcfb6,0xcfb7,
+ 0xcfb8,0xcfb9,0xcfba,0xcfbb,0xcfbc,0xcfbd,0xcfbe,0xcfbf,
+ 0xcfc0,0xcfc1,0xcfc2,0xcfc3,0xcfc4,0xcfc5,0xcfc6,0xcfc7,
+ 0xcfc8,0xcfc9,0xcfca,0xcfcb,0xcfcc,0xcfcd,0xcfce,0xcfcf,
+ 0xcfd0,0xcfd1,0xcfd2,0xcfd3,0xcfd4,0xcfd5,0xcfd6,0xcfd7,
+ 0xcfd8,0xcfd9,0xcfda,0xcfdb,0xcfdc,0xcfdd,0xcfde,0xcfdf,
+ 0xcfe0,0xcfe1,0xcfe2,0xcfe3,0xcfe4,0xcfe5,0xcfe6,0xcfe7,
+ 0xcfe8,0xcfe9,0xcfea,0xcfeb,0xcfec,0xcfed,0xcfee,0xcfef,
+ 0xcff0,0xcff1,0xcff2,0xcff3,0xcff4,0xcff5,0xcff6,0xcff7,
+ 0xcff8,0xcff9,0xcffa,0xcffb,0xcffc,0xcffd,0xcffe,0xcfff,
+ 0xd000,0xd001,0xd002,0xd003,0xd004,0xd005,0xd006,0xd007,
+ 0xd008,0xd009,0xd00a,0xd00b,0xd00c,0xd00d,0xd00e,0xd00f,
+ 0xd010,0xd011,0xd012,0xd013,0xd014,0xd015,0xd016,0xd017,
+ 0xd018,0xd019,0xd01a,0xd01b,0xd01c,0xd01d,0xd01e,0xd01f,
+ 0xd020,0xd021,0xd022,0xd023,0xd024,0xd025,0xd026,0xd027,
+ 0xd028,0xd029,0xd02a,0xd02b,0xd02c,0xd02d,0xd02e,0xd02f,
+ 0xd030,0xd031,0xd032,0xd033,0xd034,0xd035,0xd036,0xd037,
+ 0xd038,0xd039,0xd03a,0xd03b,0xd03c,0xd03d,0xd03e,0xd03f,
+ 0xd040,0xd041,0xd042,0xd043,0xd044,0xd045,0xd046,0xd047,
+ 0xd048,0xd049,0xd04a,0xd04b,0xd04c,0xd04d,0xd04e,0xd04f,
+ 0xd050,0xd051,0xd052,0xd053,0xd054,0xd055,0xd056,0xd057,
+ 0xd058,0xd059,0xd05a,0xd05b,0xd05c,0xd05d,0xd05e,0xd05f,
+ 0xd060,0xd061,0xd062,0xd063,0xd064,0xd065,0xd066,0xd067,
+ 0xd068,0xd069,0xd06a,0xd06b,0xd06c,0xd06d,0xd06e,0xd06f,
+ 0xd070,0xd071,0xd072,0xd073,0xd074,0xd075,0xd076,0xd077,
+ 0xd078,0xd079,0xd07a,0xd07b,0xd07c,0xd07d,0xd07e,0xd07f,
+ 0xd080,0xd081,0xd082,0xd083,0xd084,0xd085,0xd086,0xd087,
+ 0xd088,0xd089,0xd08a,0xd08b,0xd08c,0xd08d,0xd08e,0xd08f,
+ 0xd090,0xd091,0xd092,0xd093,0xd094,0xd095,0xd096,0xd097,
+ 0xd098,0xd099,0xd09a,0xd09b,0xd09c,0xd09d,0xd09e,0xd09f,
+ 0xd0a0,0xd0a1,0xd0a2,0xd0a3,0xd0a4,0xd0a5,0xd0a6,0xd0a7,
+ 0xd0a8,0xd0a9,0xd0aa,0xd0ab,0xd0ac,0xd0ad,0xd0ae,0xd0af,
+ 0xd0b0,0xd0b1,0xd0b2,0xd0b3,0xd0b4,0xd0b5,0xd0b6,0xd0b7,
+ 0xd0b8,0xd0b9,0xd0ba,0xd0bb,0xd0bc,0xd0bd,0xd0be,0xd0bf,
+ 0xd0c0,0xd0c1,0xd0c2,0xd0c3,0xd0c4,0xd0c5,0xd0c6,0xd0c7,
+ 0xd0c8,0xd0c9,0xd0ca,0xd0cb,0xd0cc,0xd0cd,0xd0ce,0xd0cf,
+ 0xd0d0,0xd0d1,0xd0d2,0xd0d3,0xd0d4,0xd0d5,0xd0d6,0xd0d7,
+ 0xd0d8,0xd0d9,0xd0da,0xd0db,0xd0dc,0xd0dd,0xd0de,0xd0df,
+ 0xd0e0,0xd0e1,0xd0e2,0xd0e3,0xd0e4,0xd0e5,0xd0e6,0xd0e7,
+ 0xd0e8,0xd0e9,0xd0ea,0xd0eb,0xd0ec,0xd0ed,0xd0ee,0xd0ef,
+ 0xd0f0,0xd0f1,0xd0f2,0xd0f3,0xd0f4,0xd0f5,0xd0f6,0xd0f7,
+ 0xd0f8,0xd0f9,0xd0fa,0xd0fb,0xd0fc,0xd0fd,0xd0fe,0xd0ff,
+ 0xd100,0xd101,0xd102,0xd103,0xd104,0xd105,0xd106,0xd107,
+ 0xd108,0xd109,0xd10a,0xd10b,0xd10c,0xd10d,0xd10e,0xd10f,
+ 0xd110,0xd111,0xd112,0xd113,0xd114,0xd115,0xd116,0xd117,
+ 0xd118,0xd119,0xd11a,0xd11b,0xd11c,0xd11d,0xd11e,0xd11f,
+ 0xd120,0xd121,0xd122,0xd123,0xd124,0xd125,0xd126,0xd127,
+ 0xd128,0xd129,0xd12a,0xd12b,0xd12c,0xd12d,0xd12e,0xd12f,
+ 0xd130,0xd131,0xd132,0xd133,0xd134,0xd135,0xd136,0xd137,
+ 0xd138,0xd139,0xd13a,0xd13b,0xd13c,0xd13d,0xd13e,0xd13f,
+ 0xd140,0xd141,0xd142,0xd143,0xd144,0xd145,0xd146,0xd147,
+ 0xd148,0xd149,0xd14a,0xd14b,0xd14c,0xd14d,0xd14e,0xd14f,
+ 0xd150,0xd151,0xd152,0xd153,0xd154,0xd155,0xd156,0xd157,
+ 0xd158,0xd159,0xd15a,0xd15b,0xd15c,0xd15d,0xd15e,0xd15f,
+ 0xd160,0xd161,0xd162,0xd163,0xd164,0xd165,0xd166,0xd167,
+ 0xd168,0xd169,0xd16a,0xd16b,0xd16c,0xd16d,0xd16e,0xd16f,
+ 0xd170,0xd171,0xd172,0xd173,0xd174,0xd175,0xd176,0xd177,
+ 0xd178,0xd179,0xd17a,0xd17b,0xd17c,0xd17d,0xd17e,0xd17f,
+ 0xd180,0xd181,0xd182,0xd183,0xd184,0xd185,0xd186,0xd187,
+ 0xd188,0xd189,0xd18a,0xd18b,0xd18c,0xd18d,0xd18e,0xd18f,
+ 0xd190,0xd191,0xd192,0xd193,0xd194,0xd195,0xd196,0xd197,
+ 0xd198,0xd199,0xd19a,0xd19b,0xd19c,0xd19d,0xd19e,0xd19f,
+ 0xd1a0,0xd1a1,0xd1a2,0xd1a3,0xd1a4,0xd1a5,0xd1a6,0xd1a7,
+ 0xd1a8,0xd1a9,0xd1aa,0xd1ab,0xd1ac,0xd1ad,0xd1ae,0xd1af,
+ 0xd1b0,0xd1b1,0xd1b2,0xd1b3,0xd1b4,0xd1b5,0xd1b6,0xd1b7,
+ 0xd1b8,0xd1b9,0xd1ba,0xd1bb,0xd1bc,0xd1bd,0xd1be,0xd1bf,
+ 0xd1c0,0xd1c1,0xd1c2,0xd1c3,0xd1c4,0xd1c5,0xd1c6,0xd1c7,
+ 0xd1c8,0xd1c9,0xd1ca,0xd1cb,0xd1cc,0xd1cd,0xd1ce,0xd1cf,
+ 0xd1d0,0xd1d1,0xd1d2,0xd1d3,0xd1d4,0xd1d5,0xd1d6,0xd1d7,
+ 0xd1d8,0xd1d9,0xd1da,0xd1db,0xd1dc,0xd1dd,0xd1de,0xd1df,
+ 0xd1e0,0xd1e1,0xd1e2,0xd1e3,0xd1e4,0xd1e5,0xd1e6,0xd1e7,
+ 0xd1e8,0xd1e9,0xd1ea,0xd1eb,0xd1ec,0xd1ed,0xd1ee,0xd1ef,
+ 0xd1f0,0xd1f1,0xd1f2,0xd1f3,0xd1f4,0xd1f5,0xd1f6,0xd1f7,
+ 0xd1f8,0xd1f9,0xd1fa,0xd1fb,0xd1fc,0xd1fd,0xd1fe,0xd1ff,
+ 0xd200,0xd201,0xd202,0xd203,0xd204,0xd205,0xd206,0xd207,
+ 0xd208,0xd209,0xd20a,0xd20b,0xd20c,0xd20d,0xd20e,0xd20f,
+ 0xd210,0xd211,0xd212,0xd213,0xd214,0xd215,0xd216,0xd217,
+ 0xd218,0xd219,0xd21a,0xd21b,0xd21c,0xd21d,0xd21e,0xd21f,
+ 0xd220,0xd221,0xd222,0xd223,0xd224,0xd225,0xd226,0xd227,
+ 0xd228,0xd229,0xd22a,0xd22b,0xd22c,0xd22d,0xd22e,0xd22f,
+ 0xd230,0xd231,0xd232,0xd233,0xd234,0xd235,0xd236,0xd237,
+ 0xd238,0xd239,0xd23a,0xd23b,0xd23c,0xd23d,0xd23e,0xd23f,
+ 0xd240,0xd241,0xd242,0xd243,0xd244,0xd245,0xd246,0xd247,
+ 0xd248,0xd249,0xd24a,0xd24b,0xd24c,0xd24d,0xd24e,0xd24f,
+ 0xd250,0xd251,0xd252,0xd253,0xd254,0xd255,0xd256,0xd257,
+ 0xd258,0xd259,0xd25a,0xd25b,0xd25c,0xd25d,0xd25e,0xd25f,
+ 0xd260,0xd261,0xd262,0xd263,0xd264,0xd265,0xd266,0xd267,
+ 0xd268,0xd269,0xd26a,0xd26b,0xd26c,0xd26d,0xd26e,0xd26f,
+ 0xd270,0xd271,0xd272,0xd273,0xd274,0xd275,0xd276,0xd277,
+ 0xd278,0xd279,0xd27a,0xd27b,0xd27c,0xd27d,0xd27e,0xd27f,
+ 0xd280,0xd281,0xd282,0xd283,0xd284,0xd285,0xd286,0xd287,
+ 0xd288,0xd289,0xd28a,0xd28b,0xd28c,0xd28d,0xd28e,0xd28f,
+ 0xd290,0xd291,0xd292,0xd293,0xd294,0xd295,0xd296,0xd297,
+ 0xd298,0xd299,0xd29a,0xd29b,0xd29c,0xd29d,0xd29e,0xd29f,
+ 0xd2a0,0xd2a1,0xd2a2,0xd2a3,0xd2a4,0xd2a5,0xd2a6,0xd2a7,
+ 0xd2a8,0xd2a9,0xd2aa,0xd2ab,0xd2ac,0xd2ad,0xd2ae,0xd2af,
+ 0xd2b0,0xd2b1,0xd2b2,0xd2b3,0xd2b4,0xd2b5,0xd2b6,0xd2b7,
+ 0xd2b8,0xd2b9,0xd2ba,0xd2bb,0xd2bc,0xd2bd,0xd2be,0xd2bf,
+ 0xd2c0,0xd2c1,0xd2c2,0xd2c3,0xd2c4,0xd2c5,0xd2c6,0xd2c7,
+ 0xd2c8,0xd2c9,0xd2ca,0xd2cb,0xd2cc,0xd2cd,0xd2ce,0xd2cf,
+ 0xd2d0,0xd2d1,0xd2d2,0xd2d3,0xd2d4,0xd2d5,0xd2d6,0xd2d7,
+ 0xd2d8,0xd2d9,0xd2da,0xd2db,0xd2dc,0xd2dd,0xd2de,0xd2df,
+ 0xd2e0,0xd2e1,0xd2e2,0xd2e3,0xd2e4,0xd2e5,0xd2e6,0xd2e7,
+ 0xd2e8,0xd2e9,0xd2ea,0xd2eb,0xd2ec,0xd2ed,0xd2ee,0xd2ef,
+ 0xd2f0,0xd2f1,0xd2f2,0xd2f3,0xd2f4,0xd2f5,0xd2f6,0xd2f7,
+ 0xd2f8,0xd2f9,0xd2fa,0xd2fb,0xd2fc,0xd2fd,0xd2fe,0xd2ff,
+ 0xd300,0xd301,0xd302,0xd303,0xd304,0xd305,0xd306,0xd307,
+ 0xd308,0xd309,0xd30a,0xd30b,0xd30c,0xd30d,0xd30e,0xd30f,
+ 0xd310,0xd311,0xd312,0xd313,0xd314,0xd315,0xd316,0xd317,
+ 0xd318,0xd319,0xd31a,0xd31b,0xd31c,0xd31d,0xd31e,0xd31f,
+ 0xd320,0xd321,0xd322,0xd323,0xd324,0xd325,0xd326,0xd327,
+ 0xd328,0xd329,0xd32a,0xd32b,0xd32c,0xd32d,0xd32e,0xd32f,
+ 0xd330,0xd331,0xd332,0xd333,0xd334,0xd335,0xd336,0xd337,
+ 0xd338,0xd339,0xd33a,0xd33b,0xd33c,0xd33d,0xd33e,0xd33f,
+ 0xd340,0xd341,0xd342,0xd343,0xd344,0xd345,0xd346,0xd347,
+ 0xd348,0xd349,0xd34a,0xd34b,0xd34c,0xd34d,0xd34e,0xd34f,
+ 0xd350,0xd351,0xd352,0xd353,0xd354,0xd355,0xd356,0xd357,
+ 0xd358,0xd359,0xd35a,0xd35b,0xd35c,0xd35d,0xd35e,0xd35f,
+ 0xd360,0xd361,0xd362,0xd363,0xd364,0xd365,0xd366,0xd367,
+ 0xd368,0xd369,0xd36a,0xd36b,0xd36c,0xd36d,0xd36e,0xd36f,
+ 0xd370,0xd371,0xd372,0xd373,0xd374,0xd375,0xd376,0xd377,
+ 0xd378,0xd379,0xd37a,0xd37b,0xd37c,0xd37d,0xd37e,0xd37f,
+ 0xd380,0xd381,0xd382,0xd383,0xd384,0xd385,0xd386,0xd387,
+ 0xd388,0xd389,0xd38a,0xd38b,0xd38c,0xd38d,0xd38e,0xd38f,
+ 0xd390,0xd391,0xd392,0xd393,0xd394,0xd395,0xd396,0xd397,
+ 0xd398,0xd399,0xd39a,0xd39b,0xd39c,0xd39d,0xd39e,0xd39f,
+ 0xd3a0,0xd3a1,0xd3a2,0xd3a3,0xd3a4,0xd3a5,0xd3a6,0xd3a7,
+ 0xd3a8,0xd3a9,0xd3aa,0xd3ab,0xd3ac,0xd3ad,0xd3ae,0xd3af,
+ 0xd3b0,0xd3b1,0xd3b2,0xd3b3,0xd3b4,0xd3b5,0xd3b6,0xd3b7,
+ 0xd3b8,0xd3b9,0xd3ba,0xd3bb,0xd3bc,0xd3bd,0xd3be,0xd3bf,
+ 0xd3c0,0xd3c1,0xd3c2,0xd3c3,0xd3c4,0xd3c5,0xd3c6,0xd3c7,
+ 0xd3c8,0xd3c9,0xd3ca,0xd3cb,0xd3cc,0xd3cd,0xd3ce,0xd3cf,
+ 0xd3d0,0xd3d1,0xd3d2,0xd3d3,0xd3d4,0xd3d5,0xd3d6,0xd3d7,
+ 0xd3d8,0xd3d9,0xd3da,0xd3db,0xd3dc,0xd3dd,0xd3de,0xd3df,
+ 0xd3e0,0xd3e1,0xd3e2,0xd3e3,0xd3e4,0xd3e5,0xd3e6,0xd3e7,
+ 0xd3e8,0xd3e9,0xd3ea,0xd3eb,0xd3ec,0xd3ed,0xd3ee,0xd3ef,
+ 0xd3f0,0xd3f1,0xd3f2,0xd3f3,0xd3f4,0xd3f5,0xd3f6,0xd3f7,
+ 0xd3f8,0xd3f9,0xd3fa,0xd3fb,0xd3fc,0xd3fd,0xd3fe,0xd3ff,
+ 0xd400,0xd401,0xd402,0xd403,0xd404,0xd405,0xd406,0xd407,
+ 0xd408,0xd409,0xd40a,0xd40b,0xd40c,0xd40d,0xd40e,0xd40f,
+ 0xd410,0xd411,0xd412,0xd413,0xd414,0xd415,0xd416,0xd417,
+ 0xd418,0xd419,0xd41a,0xd41b,0xd41c,0xd41d,0xd41e,0xd41f,
+ 0xd420,0xd421,0xd422,0xd423,0xd424,0xd425,0xd426,0xd427,
+ 0xd428,0xd429,0xd42a,0xd42b,0xd42c,0xd42d,0xd42e,0xd42f,
+ 0xd430,0xd431,0xd432,0xd433,0xd434,0xd435,0xd436,0xd437,
+ 0xd438,0xd439,0xd43a,0xd43b,0xd43c,0xd43d,0xd43e,0xd43f,
+ 0xd440,0xd441,0xd442,0xd443,0xd444,0xd445,0xd446,0xd447,
+ 0xd448,0xd449,0xd44a,0xd44b,0xd44c,0xd44d,0xd44e,0xd44f,
+ 0xd450,0xd451,0xd452,0xd453,0xd454,0xd455,0xd456,0xd457,
+ 0xd458,0xd459,0xd45a,0xd45b,0xd45c,0xd45d,0xd45e,0xd45f,
+ 0xd460,0xd461,0xd462,0xd463,0xd464,0xd465,0xd466,0xd467,
+ 0xd468,0xd469,0xd46a,0xd46b,0xd46c,0xd46d,0xd46e,0xd46f,
+ 0xd470,0xd471,0xd472,0xd473,0xd474,0xd475,0xd476,0xd477,
+ 0xd478,0xd479,0xd47a,0xd47b,0xd47c,0xd47d,0xd47e,0xd47f,
+ 0xd480,0xd481,0xd482,0xd483,0xd484,0xd485,0xd486,0xd487,
+ 0xd488,0xd489,0xd48a,0xd48b,0xd48c,0xd48d,0xd48e,0xd48f,
+ 0xd490,0xd491,0xd492,0xd493,0xd494,0xd495,0xd496,0xd497,
+ 0xd498,0xd499,0xd49a,0xd49b,0xd49c,0xd49d,0xd49e,0xd49f,
+ 0xd4a0,0xd4a1,0xd4a2,0xd4a3,0xd4a4,0xd4a5,0xd4a6,0xd4a7,
+ 0xd4a8,0xd4a9,0xd4aa,0xd4ab,0xd4ac,0xd4ad,0xd4ae,0xd4af,
+ 0xd4b0,0xd4b1,0xd4b2,0xd4b3,0xd4b4,0xd4b5,0xd4b6,0xd4b7,
+ 0xd4b8,0xd4b9,0xd4ba,0xd4bb,0xd4bc,0xd4bd,0xd4be,0xd4bf,
+ 0xd4c0,0xd4c1,0xd4c2,0xd4c3,0xd4c4,0xd4c5,0xd4c6,0xd4c7,
+ 0xd4c8,0xd4c9,0xd4ca,0xd4cb,0xd4cc,0xd4cd,0xd4ce,0xd4cf,
+ 0xd4d0,0xd4d1,0xd4d2,0xd4d3,0xd4d4,0xd4d5,0xd4d6,0xd4d7,
+ 0xd4d8,0xd4d9,0xd4da,0xd4db,0xd4dc,0xd4dd,0xd4de,0xd4df,
+ 0xd4e0,0xd4e1,0xd4e2,0xd4e3,0xd4e4,0xd4e5,0xd4e6,0xd4e7,
+ 0xd4e8,0xd4e9,0xd4ea,0xd4eb,0xd4ec,0xd4ed,0xd4ee,0xd4ef,
+ 0xd4f0,0xd4f1,0xd4f2,0xd4f3,0xd4f4,0xd4f5,0xd4f6,0xd4f7,
+ 0xd4f8,0xd4f9,0xd4fa,0xd4fb,0xd4fc,0xd4fd,0xd4fe,0xd4ff,
+ 0xd500,0xd501,0xd502,0xd503,0xd504,0xd505,0xd506,0xd507,
+ 0xd508,0xd509,0xd50a,0xd50b,0xd50c,0xd50d,0xd50e,0xd50f,
+ 0xd510,0xd511,0xd512,0xd513,0xd514,0xd515,0xd516,0xd517,
+ 0xd518,0xd519,0xd51a,0xd51b,0xd51c,0xd51d,0xd51e,0xd51f,
+ 0xd520,0xd521,0xd522,0xd523,0xd524,0xd525,0xd526,0xd527,
+ 0xd528,0xd529,0xd52a,0xd52b,0xd52c,0xd52d,0xd52e,0xd52f,
+ 0xd530,0xd531,0xd532,0xd533,0xd534,0xd535,0xd536,0xd537,
+ 0xd538,0xd539,0xd53a,0xd53b,0xd53c,0xd53d,0xd53e,0xd53f,
+ 0xd540,0xd541,0xd542,0xd543,0xd544,0xd545,0xd546,0xd547,
+ 0xd548,0xd549,0xd54a,0xd54b,0xd54c,0xd54d,0xd54e,0xd54f,
+ 0xd550,0xd551,0xd552,0xd553,0xd554,0xd555,0xd556,0xd557,
+ 0xd558,0xd559,0xd55a,0xd55b,0xd55c,0xd55d,0xd55e,0xd55f,
+ 0xd560,0xd561,0xd562,0xd563,0xd564,0xd565,0xd566,0xd567,
+ 0xd568,0xd569,0xd56a,0xd56b,0xd56c,0xd56d,0xd56e,0xd56f,
+ 0xd570,0xd571,0xd572,0xd573,0xd574,0xd575,0xd576,0xd577,
+ 0xd578,0xd579,0xd57a,0xd57b,0xd57c,0xd57d,0xd57e,0xd57f,
+ 0xd580,0xd581,0xd582,0xd583,0xd584,0xd585,0xd586,0xd587,
+ 0xd588,0xd589,0xd58a,0xd58b,0xd58c,0xd58d,0xd58e,0xd58f,
+ 0xd590,0xd591,0xd592,0xd593,0xd594,0xd595,0xd596,0xd597,
+ 0xd598,0xd599,0xd59a,0xd59b,0xd59c,0xd59d,0xd59e,0xd59f,
+ 0xd5a0,0xd5a1,0xd5a2,0xd5a3,0xd5a4,0xd5a5,0xd5a6,0xd5a7,
+ 0xd5a8,0xd5a9,0xd5aa,0xd5ab,0xd5ac,0xd5ad,0xd5ae,0xd5af,
+ 0xd5b0,0xd5b1,0xd5b2,0xd5b3,0xd5b4,0xd5b5,0xd5b6,0xd5b7,
+ 0xd5b8,0xd5b9,0xd5ba,0xd5bb,0xd5bc,0xd5bd,0xd5be,0xd5bf,
+ 0xd5c0,0xd5c1,0xd5c2,0xd5c3,0xd5c4,0xd5c5,0xd5c6,0xd5c7,
+ 0xd5c8,0xd5c9,0xd5ca,0xd5cb,0xd5cc,0xd5cd,0xd5ce,0xd5cf,
+ 0xd5d0,0xd5d1,0xd5d2,0xd5d3,0xd5d4,0xd5d5,0xd5d6,0xd5d7,
+ 0xd5d8,0xd5d9,0xd5da,0xd5db,0xd5dc,0xd5dd,0xd5de,0xd5df,
+ 0xd5e0,0xd5e1,0xd5e2,0xd5e3,0xd5e4,0xd5e5,0xd5e6,0xd5e7,
+ 0xd5e8,0xd5e9,0xd5ea,0xd5eb,0xd5ec,0xd5ed,0xd5ee,0xd5ef,
+ 0xd5f0,0xd5f1,0xd5f2,0xd5f3,0xd5f4,0xd5f5,0xd5f6,0xd5f7,
+ 0xd5f8,0xd5f9,0xd5fa,0xd5fb,0xd5fc,0xd5fd,0xd5fe,0xd5ff,
+ 0xd600,0xd601,0xd602,0xd603,0xd604,0xd605,0xd606,0xd607,
+ 0xd608,0xd609,0xd60a,0xd60b,0xd60c,0xd60d,0xd60e,0xd60f,
+ 0xd610,0xd611,0xd612,0xd613,0xd614,0xd615,0xd616,0xd617,
+ 0xd618,0xd619,0xd61a,0xd61b,0xd61c,0xd61d,0xd61e,0xd61f,
+ 0xd620,0xd621,0xd622,0xd623,0xd624,0xd625,0xd626,0xd627,
+ 0xd628,0xd629,0xd62a,0xd62b,0xd62c,0xd62d,0xd62e,0xd62f,
+ 0xd630,0xd631,0xd632,0xd633,0xd634,0xd635,0xd636,0xd637,
+ 0xd638,0xd639,0xd63a,0xd63b,0xd63c,0xd63d,0xd63e,0xd63f,
+ 0xd640,0xd641,0xd642,0xd643,0xd644,0xd645,0xd646,0xd647,
+ 0xd648,0xd649,0xd64a,0xd64b,0xd64c,0xd64d,0xd64e,0xd64f,
+ 0xd650,0xd651,0xd652,0xd653,0xd654,0xd655,0xd656,0xd657,
+ 0xd658,0xd659,0xd65a,0xd65b,0xd65c,0xd65d,0xd65e,0xd65f,
+ 0xd660,0xd661,0xd662,0xd663,0xd664,0xd665,0xd666,0xd667,
+ 0xd668,0xd669,0xd66a,0xd66b,0xd66c,0xd66d,0xd66e,0xd66f,
+ 0xd670,0xd671,0xd672,0xd673,0xd674,0xd675,0xd676,0xd677,
+ 0xd678,0xd679,0xd67a,0xd67b,0xd67c,0xd67d,0xd67e,0xd67f,
+ 0xd680,0xd681,0xd682,0xd683,0xd684,0xd685,0xd686,0xd687,
+ 0xd688,0xd689,0xd68a,0xd68b,0xd68c,0xd68d,0xd68e,0xd68f,
+ 0xd690,0xd691,0xd692,0xd693,0xd694,0xd695,0xd696,0xd697,
+ 0xd698,0xd699,0xd69a,0xd69b,0xd69c,0xd69d,0xd69e,0xd69f,
+ 0xd6a0,0xd6a1,0xd6a2,0xd6a3,0xd6a4,0xd6a5,0xd6a6,0xd6a7,
+ 0xd6a8,0xd6a9,0xd6aa,0xd6ab,0xd6ac,0xd6ad,0xd6ae,0xd6af,
+ 0xd6b0,0xd6b1,0xd6b2,0xd6b3,0xd6b4,0xd6b5,0xd6b6,0xd6b7,
+ 0xd6b8,0xd6b9,0xd6ba,0xd6bb,0xd6bc,0xd6bd,0xd6be,0xd6bf,
+ 0xd6c0,0xd6c1,0xd6c2,0xd6c3,0xd6c4,0xd6c5,0xd6c6,0xd6c7,
+ 0xd6c8,0xd6c9,0xd6ca,0xd6cb,0xd6cc,0xd6cd,0xd6ce,0xd6cf,
+ 0xd6d0,0xd6d1,0xd6d2,0xd6d3,0xd6d4,0xd6d5,0xd6d6,0xd6d7,
+ 0xd6d8,0xd6d9,0xd6da,0xd6db,0xd6dc,0xd6dd,0xd6de,0xd6df,
+ 0xd6e0,0xd6e1,0xd6e2,0xd6e3,0xd6e4,0xd6e5,0xd6e6,0xd6e7,
+ 0xd6e8,0xd6e9,0xd6ea,0xd6eb,0xd6ec,0xd6ed,0xd6ee,0xd6ef,
+ 0xd6f0,0xd6f1,0xd6f2,0xd6f3,0xd6f4,0xd6f5,0xd6f6,0xd6f7,
+ 0xd6f8,0xd6f9,0xd6fa,0xd6fb,0xd6fc,0xd6fd,0xd6fe,0xd6ff,
+ 0xd700,0xd701,0xd702,0xd703,0xd704,0xd705,0xd706,0xd707,
+ 0xd708,0xd709,0xd70a,0xd70b,0xd70c,0xd70d,0xd70e,0xd70f,
+ 0xd710,0xd711,0xd712,0xd713,0xd714,0xd715,0xd716,0xd717,
+ 0xd718,0xd719,0xd71a,0xd71b,0xd71c,0xd71d,0xd71e,0xd71f,
+ 0xd720,0xd721,0xd722,0xd723,0xd724,0xd725,0xd726,0xd727,
+ 0xd728,0xd729,0xd72a,0xd72b,0xd72c,0xd72d,0xd72e,0xd72f,
+ 0xd730,0xd731,0xd732,0xd733,0xd734,0xd735,0xd736,0xd737,
+ 0xd738,0xd739,0xd73a,0xd73b,0xd73c,0xd73d,0xd73e,0xd73f,
+ 0xd740,0xd741,0xd742,0xd743,0xd744,0xd745,0xd746,0xd747,
+ 0xd748,0xd749,0xd74a,0xd74b,0xd74c,0xd74d,0xd74e,0xd74f,
+ 0xd750,0xd751,0xd752,0xd753,0xd754,0xd755,0xd756,0xd757,
+ 0xd758,0xd759,0xd75a,0xd75b,0xd75c,0xd75d,0xd75e,0xd75f,
+ 0xd760,0xd761,0xd762,0xd763,0xd764,0xd765,0xd766,0xd767,
+ 0xd768,0xd769,0xd76a,0xd76b,0xd76c,0xd76d,0xd76e,0xd76f,
+ 0xd770,0xd771,0xd772,0xd773,0xd774,0xd775,0xd776,0xd777,
+ 0xd778,0xd779,0xd77a,0xd77b,0xd77c,0xd77d,0xd77e,0xd77f,
+ 0xd780,0xd781,0xd782,0xd783,0xd784,0xd785,0xd786,0xd787,
+ 0xd788,0xd789,0xd78a,0xd78b,0xd78c,0xd78d,0xd78e,0xd78f,
+ 0xd790,0xd791,0xd792,0xd793,0xd794,0xd795,0xd796,0xd797,
+ 0xd798,0xd799,0xd79a,0xd79b,0xd79c,0xd79d,0xd79e,0xd79f,
+ 0xd7a0,0xd7a1,0xd7a2,0xd7a3,0xd7a4,0xd7a5,0xd7a6,0xd7a7,
+ 0xd7a8,0xd7a9,0xd7aa,0xd7ab,0xd7ac,0xd7ad,0xd7ae,0xd7af,
+ 0xd7b0,0xd7b1,0xd7b2,0xd7b3,0xd7b4,0xd7b5,0xd7b6,0xd7b7,
+ 0xd7b8,0xd7b9,0xd7ba,0xd7bb,0xd7bc,0xd7bd,0xd7be,0xd7bf,
+ 0xd7c0,0xd7c1,0xd7c2,0xd7c3,0xd7c4,0xd7c5,0xd7c6,0xd7c7,
+ 0xd7c8,0xd7c9,0xd7ca,0xd7cb,0xd7cc,0xd7cd,0xd7ce,0xd7cf,
+ 0xd7d0,0xd7d1,0xd7d2,0xd7d3,0xd7d4,0xd7d5,0xd7d6,0xd7d7,
+ 0xd7d8,0xd7d9,0xd7da,0xd7db,0xd7dc,0xd7dd,0xd7de,0xd7df,
+ 0xd7e0,0xd7e1,0xd7e2,0xd7e3,0xd7e4,0xd7e5,0xd7e6,0xd7e7,
+ 0xd7e8,0xd7e9,0xd7ea,0xd7eb,0xd7ec,0xd7ed,0xd7ee,0xd7ef,
+ 0xd7f0,0xd7f1,0xd7f2,0xd7f3,0xd7f4,0xd7f5,0xd7f6,0xd7f7,
+ 0xd7f8,0xd7f9,0xd7fa,0xd7fb,0xd7fc,0xd7fd,0xd7fe,0xd7ff,
+ 0xd800,0xd801,0xd802,0xd803,0xd804,0xd805,0xd806,0xd807,
+ 0xd808,0xd809,0xd80a,0xd80b,0xd80c,0xd80d,0xd80e,0xd80f,
+ 0xd810,0xd811,0xd812,0xd813,0xd814,0xd815,0xd816,0xd817,
+ 0xd818,0xd819,0xd81a,0xd81b,0xd81c,0xd81d,0xd81e,0xd81f,
+ 0xd820,0xd821,0xd822,0xd823,0xd824,0xd825,0xd826,0xd827,
+ 0xd828,0xd829,0xd82a,0xd82b,0xd82c,0xd82d,0xd82e,0xd82f,
+ 0xd830,0xd831,0xd832,0xd833,0xd834,0xd835,0xd836,0xd837,
+ 0xd838,0xd839,0xd83a,0xd83b,0xd83c,0xd83d,0xd83e,0xd83f,
+ 0xd840,0xd841,0xd842,0xd843,0xd844,0xd845,0xd846,0xd847,
+ 0xd848,0xd849,0xd84a,0xd84b,0xd84c,0xd84d,0xd84e,0xd84f,
+ 0xd850,0xd851,0xd852,0xd853,0xd854,0xd855,0xd856,0xd857,
+ 0xd858,0xd859,0xd85a,0xd85b,0xd85c,0xd85d,0xd85e,0xd85f,
+ 0xd860,0xd861,0xd862,0xd863,0xd864,0xd865,0xd866,0xd867,
+ 0xd868,0xd869,0xd86a,0xd86b,0xd86c,0xd86d,0xd86e,0xd86f,
+ 0xd870,0xd871,0xd872,0xd873,0xd874,0xd875,0xd876,0xd877,
+ 0xd878,0xd879,0xd87a,0xd87b,0xd87c,0xd87d,0xd87e,0xd87f,
+ 0xd880,0xd881,0xd882,0xd883,0xd884,0xd885,0xd886,0xd887,
+ 0xd888,0xd889,0xd88a,0xd88b,0xd88c,0xd88d,0xd88e,0xd88f,
+ 0xd890,0xd891,0xd892,0xd893,0xd894,0xd895,0xd896,0xd897,
+ 0xd898,0xd899,0xd89a,0xd89b,0xd89c,0xd89d,0xd89e,0xd89f,
+ 0xd8a0,0xd8a1,0xd8a2,0xd8a3,0xd8a4,0xd8a5,0xd8a6,0xd8a7,
+ 0xd8a8,0xd8a9,0xd8aa,0xd8ab,0xd8ac,0xd8ad,0xd8ae,0xd8af,
+ 0xd8b0,0xd8b1,0xd8b2,0xd8b3,0xd8b4,0xd8b5,0xd8b6,0xd8b7,
+ 0xd8b8,0xd8b9,0xd8ba,0xd8bb,0xd8bc,0xd8bd,0xd8be,0xd8bf,
+ 0xd8c0,0xd8c1,0xd8c2,0xd8c3,0xd8c4,0xd8c5,0xd8c6,0xd8c7,
+ 0xd8c8,0xd8c9,0xd8ca,0xd8cb,0xd8cc,0xd8cd,0xd8ce,0xd8cf,
+ 0xd8d0,0xd8d1,0xd8d2,0xd8d3,0xd8d4,0xd8d5,0xd8d6,0xd8d7,
+ 0xd8d8,0xd8d9,0xd8da,0xd8db,0xd8dc,0xd8dd,0xd8de,0xd8df,
+ 0xd8e0,0xd8e1,0xd8e2,0xd8e3,0xd8e4,0xd8e5,0xd8e6,0xd8e7,
+ 0xd8e8,0xd8e9,0xd8ea,0xd8eb,0xd8ec,0xd8ed,0xd8ee,0xd8ef,
+ 0xd8f0,0xd8f1,0xd8f2,0xd8f3,0xd8f4,0xd8f5,0xd8f6,0xd8f7,
+ 0xd8f8,0xd8f9,0xd8fa,0xd8fb,0xd8fc,0xd8fd,0xd8fe,0xd8ff,
+ 0xd900,0xd901,0xd902,0xd903,0xd904,0xd905,0xd906,0xd907,
+ 0xd908,0xd909,0xd90a,0xd90b,0xd90c,0xd90d,0xd90e,0xd90f,
+ 0xd910,0xd911,0xd912,0xd913,0xd914,0xd915,0xd916,0xd917,
+ 0xd918,0xd919,0xd91a,0xd91b,0xd91c,0xd91d,0xd91e,0xd91f,
+ 0xd920,0xd921,0xd922,0xd923,0xd924,0xd925,0xd926,0xd927,
+ 0xd928,0xd929,0xd92a,0xd92b,0xd92c,0xd92d,0xd92e,0xd92f,
+ 0xd930,0xd931,0xd932,0xd933,0xd934,0xd935,0xd936,0xd937,
+ 0xd938,0xd939,0xd93a,0xd93b,0xd93c,0xd93d,0xd93e,0xd93f,
+ 0xd940,0xd941,0xd942,0xd943,0xd944,0xd945,0xd946,0xd947,
+ 0xd948,0xd949,0xd94a,0xd94b,0xd94c,0xd94d,0xd94e,0xd94f,
+ 0xd950,0xd951,0xd952,0xd953,0xd954,0xd955,0xd956,0xd957,
+ 0xd958,0xd959,0xd95a,0xd95b,0xd95c,0xd95d,0xd95e,0xd95f,
+ 0xd960,0xd961,0xd962,0xd963,0xd964,0xd965,0xd966,0xd967,
+ 0xd968,0xd969,0xd96a,0xd96b,0xd96c,0xd96d,0xd96e,0xd96f,
+ 0xd970,0xd971,0xd972,0xd973,0xd974,0xd975,0xd976,0xd977,
+ 0xd978,0xd979,0xd97a,0xd97b,0xd97c,0xd97d,0xd97e,0xd97f,
+ 0xd980,0xd981,0xd982,0xd983,0xd984,0xd985,0xd986,0xd987,
+ 0xd988,0xd989,0xd98a,0xd98b,0xd98c,0xd98d,0xd98e,0xd98f,
+ 0xd990,0xd991,0xd992,0xd993,0xd994,0xd995,0xd996,0xd997,
+ 0xd998,0xd999,0xd99a,0xd99b,0xd99c,0xd99d,0xd99e,0xd99f,
+ 0xd9a0,0xd9a1,0xd9a2,0xd9a3,0xd9a4,0xd9a5,0xd9a6,0xd9a7,
+ 0xd9a8,0xd9a9,0xd9aa,0xd9ab,0xd9ac,0xd9ad,0xd9ae,0xd9af,
+ 0xd9b0,0xd9b1,0xd9b2,0xd9b3,0xd9b4,0xd9b5,0xd9b6,0xd9b7,
+ 0xd9b8,0xd9b9,0xd9ba,0xd9bb,0xd9bc,0xd9bd,0xd9be,0xd9bf,
+ 0xd9c0,0xd9c1,0xd9c2,0xd9c3,0xd9c4,0xd9c5,0xd9c6,0xd9c7,
+ 0xd9c8,0xd9c9,0xd9ca,0xd9cb,0xd9cc,0xd9cd,0xd9ce,0xd9cf,
+ 0xd9d0,0xd9d1,0xd9d2,0xd9d3,0xd9d4,0xd9d5,0xd9d6,0xd9d7,
+ 0xd9d8,0xd9d9,0xd9da,0xd9db,0xd9dc,0xd9dd,0xd9de,0xd9df,
+ 0xd9e0,0xd9e1,0xd9e2,0xd9e3,0xd9e4,0xd9e5,0xd9e6,0xd9e7,
+ 0xd9e8,0xd9e9,0xd9ea,0xd9eb,0xd9ec,0xd9ed,0xd9ee,0xd9ef,
+ 0xd9f0,0xd9f1,0xd9f2,0xd9f3,0xd9f4,0xd9f5,0xd9f6,0xd9f7,
+ 0xd9f8,0xd9f9,0xd9fa,0xd9fb,0xd9fc,0xd9fd,0xd9fe,0xd9ff,
+ 0xda00,0xda01,0xda02,0xda03,0xda04,0xda05,0xda06,0xda07,
+ 0xda08,0xda09,0xda0a,0xda0b,0xda0c,0xda0d,0xda0e,0xda0f,
+ 0xda10,0xda11,0xda12,0xda13,0xda14,0xda15,0xda16,0xda17,
+ 0xda18,0xda19,0xda1a,0xda1b,0xda1c,0xda1d,0xda1e,0xda1f,
+ 0xda20,0xda21,0xda22,0xda23,0xda24,0xda25,0xda26,0xda27,
+ 0xda28,0xda29,0xda2a,0xda2b,0xda2c,0xda2d,0xda2e,0xda2f,
+ 0xda30,0xda31,0xda32,0xda33,0xda34,0xda35,0xda36,0xda37,
+ 0xda38,0xda39,0xda3a,0xda3b,0xda3c,0xda3d,0xda3e,0xda3f,
+ 0xda40,0xda41,0xda42,0xda43,0xda44,0xda45,0xda46,0xda47,
+ 0xda48,0xda49,0xda4a,0xda4b,0xda4c,0xda4d,0xda4e,0xda4f,
+ 0xda50,0xda51,0xda52,0xda53,0xda54,0xda55,0xda56,0xda57,
+ 0xda58,0xda59,0xda5a,0xda5b,0xda5c,0xda5d,0xda5e,0xda5f,
+ 0xda60,0xda61,0xda62,0xda63,0xda64,0xda65,0xda66,0xda67,
+ 0xda68,0xda69,0xda6a,0xda6b,0xda6c,0xda6d,0xda6e,0xda6f,
+ 0xda70,0xda71,0xda72,0xda73,0xda74,0xda75,0xda76,0xda77,
+ 0xda78,0xda79,0xda7a,0xda7b,0xda7c,0xda7d,0xda7e,0xda7f,
+ 0xda80,0xda81,0xda82,0xda83,0xda84,0xda85,0xda86,0xda87,
+ 0xda88,0xda89,0xda8a,0xda8b,0xda8c,0xda8d,0xda8e,0xda8f,
+ 0xda90,0xda91,0xda92,0xda93,0xda94,0xda95,0xda96,0xda97,
+ 0xda98,0xda99,0xda9a,0xda9b,0xda9c,0xda9d,0xda9e,0xda9f,
+ 0xdaa0,0xdaa1,0xdaa2,0xdaa3,0xdaa4,0xdaa5,0xdaa6,0xdaa7,
+ 0xdaa8,0xdaa9,0xdaaa,0xdaab,0xdaac,0xdaad,0xdaae,0xdaaf,
+ 0xdab0,0xdab1,0xdab2,0xdab3,0xdab4,0xdab5,0xdab6,0xdab7,
+ 0xdab8,0xdab9,0xdaba,0xdabb,0xdabc,0xdabd,0xdabe,0xdabf,
+ 0xdac0,0xdac1,0xdac2,0xdac3,0xdac4,0xdac5,0xdac6,0xdac7,
+ 0xdac8,0xdac9,0xdaca,0xdacb,0xdacc,0xdacd,0xdace,0xdacf,
+ 0xdad0,0xdad1,0xdad2,0xdad3,0xdad4,0xdad5,0xdad6,0xdad7,
+ 0xdad8,0xdad9,0xdada,0xdadb,0xdadc,0xdadd,0xdade,0xdadf,
+ 0xdae0,0xdae1,0xdae2,0xdae3,0xdae4,0xdae5,0xdae6,0xdae7,
+ 0xdae8,0xdae9,0xdaea,0xdaeb,0xdaec,0xdaed,0xdaee,0xdaef,
+ 0xdaf0,0xdaf1,0xdaf2,0xdaf3,0xdaf4,0xdaf5,0xdaf6,0xdaf7,
+ 0xdaf8,0xdaf9,0xdafa,0xdafb,0xdafc,0xdafd,0xdafe,0xdaff,
+ 0xdb00,0xdb01,0xdb02,0xdb03,0xdb04,0xdb05,0xdb06,0xdb07,
+ 0xdb08,0xdb09,0xdb0a,0xdb0b,0xdb0c,0xdb0d,0xdb0e,0xdb0f,
+ 0xdb10,0xdb11,0xdb12,0xdb13,0xdb14,0xdb15,0xdb16,0xdb17,
+ 0xdb18,0xdb19,0xdb1a,0xdb1b,0xdb1c,0xdb1d,0xdb1e,0xdb1f,
+ 0xdb20,0xdb21,0xdb22,0xdb23,0xdb24,0xdb25,0xdb26,0xdb27,
+ 0xdb28,0xdb29,0xdb2a,0xdb2b,0xdb2c,0xdb2d,0xdb2e,0xdb2f,
+ 0xdb30,0xdb31,0xdb32,0xdb33,0xdb34,0xdb35,0xdb36,0xdb37,
+ 0xdb38,0xdb39,0xdb3a,0xdb3b,0xdb3c,0xdb3d,0xdb3e,0xdb3f,
+ 0xdb40,0xdb41,0xdb42,0xdb43,0xdb44,0xdb45,0xdb46,0xdb47,
+ 0xdb48,0xdb49,0xdb4a,0xdb4b,0xdb4c,0xdb4d,0xdb4e,0xdb4f,
+ 0xdb50,0xdb51,0xdb52,0xdb53,0xdb54,0xdb55,0xdb56,0xdb57,
+ 0xdb58,0xdb59,0xdb5a,0xdb5b,0xdb5c,0xdb5d,0xdb5e,0xdb5f,
+ 0xdb60,0xdb61,0xdb62,0xdb63,0xdb64,0xdb65,0xdb66,0xdb67,
+ 0xdb68,0xdb69,0xdb6a,0xdb6b,0xdb6c,0xdb6d,0xdb6e,0xdb6f,
+ 0xdb70,0xdb71,0xdb72,0xdb73,0xdb74,0xdb75,0xdb76,0xdb77,
+ 0xdb78,0xdb79,0xdb7a,0xdb7b,0xdb7c,0xdb7d,0xdb7e,0xdb7f,
+ 0xdb80,0xdb81,0xdb82,0xdb83,0xdb84,0xdb85,0xdb86,0xdb87,
+ 0xdb88,0xdb89,0xdb8a,0xdb8b,0xdb8c,0xdb8d,0xdb8e,0xdb8f,
+ 0xdb90,0xdb91,0xdb92,0xdb93,0xdb94,0xdb95,0xdb96,0xdb97,
+ 0xdb98,0xdb99,0xdb9a,0xdb9b,0xdb9c,0xdb9d,0xdb9e,0xdb9f,
+ 0xdba0,0xdba1,0xdba2,0xdba3,0xdba4,0xdba5,0xdba6,0xdba7,
+ 0xdba8,0xdba9,0xdbaa,0xdbab,0xdbac,0xdbad,0xdbae,0xdbaf,
+ 0xdbb0,0xdbb1,0xdbb2,0xdbb3,0xdbb4,0xdbb5,0xdbb6,0xdbb7,
+ 0xdbb8,0xdbb9,0xdbba,0xdbbb,0xdbbc,0xdbbd,0xdbbe,0xdbbf,
+ 0xdbc0,0xdbc1,0xdbc2,0xdbc3,0xdbc4,0xdbc5,0xdbc6,0xdbc7,
+ 0xdbc8,0xdbc9,0xdbca,0xdbcb,0xdbcc,0xdbcd,0xdbce,0xdbcf,
+ 0xdbd0,0xdbd1,0xdbd2,0xdbd3,0xdbd4,0xdbd5,0xdbd6,0xdbd7,
+ 0xdbd8,0xdbd9,0xdbda,0xdbdb,0xdbdc,0xdbdd,0xdbde,0xdbdf,
+ 0xdbe0,0xdbe1,0xdbe2,0xdbe3,0xdbe4,0xdbe5,0xdbe6,0xdbe7,
+ 0xdbe8,0xdbe9,0xdbea,0xdbeb,0xdbec,0xdbed,0xdbee,0xdbef,
+ 0xdbf0,0xdbf1,0xdbf2,0xdbf3,0xdbf4,0xdbf5,0xdbf6,0xdbf7,
+ 0xdbf8,0xdbf9,0xdbfa,0xdbfb,0xdbfc,0xdbfd,0xdbfe,0xdbff,
+ 0xdc00,0xdc01,0xdc02,0xdc03,0xdc04,0xdc05,0xdc06,0xdc07,
+ 0xdc08,0xdc09,0xdc0a,0xdc0b,0xdc0c,0xdc0d,0xdc0e,0xdc0f,
+ 0xdc10,0xdc11,0xdc12,0xdc13,0xdc14,0xdc15,0xdc16,0xdc17,
+ 0xdc18,0xdc19,0xdc1a,0xdc1b,0xdc1c,0xdc1d,0xdc1e,0xdc1f,
+ 0xdc20,0xdc21,0xdc22,0xdc23,0xdc24,0xdc25,0xdc26,0xdc27,
+ 0xdc28,0xdc29,0xdc2a,0xdc2b,0xdc2c,0xdc2d,0xdc2e,0xdc2f,
+ 0xdc30,0xdc31,0xdc32,0xdc33,0xdc34,0xdc35,0xdc36,0xdc37,
+ 0xdc38,0xdc39,0xdc3a,0xdc3b,0xdc3c,0xdc3d,0xdc3e,0xdc3f,
+ 0xdc40,0xdc41,0xdc42,0xdc43,0xdc44,0xdc45,0xdc46,0xdc47,
+ 0xdc48,0xdc49,0xdc4a,0xdc4b,0xdc4c,0xdc4d,0xdc4e,0xdc4f,
+ 0xdc50,0xdc51,0xdc52,0xdc53,0xdc54,0xdc55,0xdc56,0xdc57,
+ 0xdc58,0xdc59,0xdc5a,0xdc5b,0xdc5c,0xdc5d,0xdc5e,0xdc5f,
+ 0xdc60,0xdc61,0xdc62,0xdc63,0xdc64,0xdc65,0xdc66,0xdc67,
+ 0xdc68,0xdc69,0xdc6a,0xdc6b,0xdc6c,0xdc6d,0xdc6e,0xdc6f,
+ 0xdc70,0xdc71,0xdc72,0xdc73,0xdc74,0xdc75,0xdc76,0xdc77,
+ 0xdc78,0xdc79,0xdc7a,0xdc7b,0xdc7c,0xdc7d,0xdc7e,0xdc7f,
+ 0xdc80,0xdc81,0xdc82,0xdc83,0xdc84,0xdc85,0xdc86,0xdc87,
+ 0xdc88,0xdc89,0xdc8a,0xdc8b,0xdc8c,0xdc8d,0xdc8e,0xdc8f,
+ 0xdc90,0xdc91,0xdc92,0xdc93,0xdc94,0xdc95,0xdc96,0xdc97,
+ 0xdc98,0xdc99,0xdc9a,0xdc9b,0xdc9c,0xdc9d,0xdc9e,0xdc9f,
+ 0xdca0,0xdca1,0xdca2,0xdca3,0xdca4,0xdca5,0xdca6,0xdca7,
+ 0xdca8,0xdca9,0xdcaa,0xdcab,0xdcac,0xdcad,0xdcae,0xdcaf,
+ 0xdcb0,0xdcb1,0xdcb2,0xdcb3,0xdcb4,0xdcb5,0xdcb6,0xdcb7,
+ 0xdcb8,0xdcb9,0xdcba,0xdcbb,0xdcbc,0xdcbd,0xdcbe,0xdcbf,
+ 0xdcc0,0xdcc1,0xdcc2,0xdcc3,0xdcc4,0xdcc5,0xdcc6,0xdcc7,
+ 0xdcc8,0xdcc9,0xdcca,0xdccb,0xdccc,0xdccd,0xdcce,0xdccf,
+ 0xdcd0,0xdcd1,0xdcd2,0xdcd3,0xdcd4,0xdcd5,0xdcd6,0xdcd7,
+ 0xdcd8,0xdcd9,0xdcda,0xdcdb,0xdcdc,0xdcdd,0xdcde,0xdcdf,
+ 0xdce0,0xdce1,0xdce2,0xdce3,0xdce4,0xdce5,0xdce6,0xdce7,
+ 0xdce8,0xdce9,0xdcea,0xdceb,0xdcec,0xdced,0xdcee,0xdcef,
+ 0xdcf0,0xdcf1,0xdcf2,0xdcf3,0xdcf4,0xdcf5,0xdcf6,0xdcf7,
+ 0xdcf8,0xdcf9,0xdcfa,0xdcfb,0xdcfc,0xdcfd,0xdcfe,0xdcff,
+ 0xdd00,0xdd01,0xdd02,0xdd03,0xdd04,0xdd05,0xdd06,0xdd07,
+ 0xdd08,0xdd09,0xdd0a,0xdd0b,0xdd0c,0xdd0d,0xdd0e,0xdd0f,
+ 0xdd10,0xdd11,0xdd12,0xdd13,0xdd14,0xdd15,0xdd16,0xdd17,
+ 0xdd18,0xdd19,0xdd1a,0xdd1b,0xdd1c,0xdd1d,0xdd1e,0xdd1f,
+ 0xdd20,0xdd21,0xdd22,0xdd23,0xdd24,0xdd25,0xdd26,0xdd27,
+ 0xdd28,0xdd29,0xdd2a,0xdd2b,0xdd2c,0xdd2d,0xdd2e,0xdd2f,
+ 0xdd30,0xdd31,0xdd32,0xdd33,0xdd34,0xdd35,0xdd36,0xdd37,
+ 0xdd38,0xdd39,0xdd3a,0xdd3b,0xdd3c,0xdd3d,0xdd3e,0xdd3f,
+ 0xdd40,0xdd41,0xdd42,0xdd43,0xdd44,0xdd45,0xdd46,0xdd47,
+ 0xdd48,0xdd49,0xdd4a,0xdd4b,0xdd4c,0xdd4d,0xdd4e,0xdd4f,
+ 0xdd50,0xdd51,0xdd52,0xdd53,0xdd54,0xdd55,0xdd56,0xdd57,
+ 0xdd58,0xdd59,0xdd5a,0xdd5b,0xdd5c,0xdd5d,0xdd5e,0xdd5f,
+ 0xdd60,0xdd61,0xdd62,0xdd63,0xdd64,0xdd65,0xdd66,0xdd67,
+ 0xdd68,0xdd69,0xdd6a,0xdd6b,0xdd6c,0xdd6d,0xdd6e,0xdd6f,
+ 0xdd70,0xdd71,0xdd72,0xdd73,0xdd74,0xdd75,0xdd76,0xdd77,
+ 0xdd78,0xdd79,0xdd7a,0xdd7b,0xdd7c,0xdd7d,0xdd7e,0xdd7f,
+ 0xdd80,0xdd81,0xdd82,0xdd83,0xdd84,0xdd85,0xdd86,0xdd87,
+ 0xdd88,0xdd89,0xdd8a,0xdd8b,0xdd8c,0xdd8d,0xdd8e,0xdd8f,
+ 0xdd90,0xdd91,0xdd92,0xdd93,0xdd94,0xdd95,0xdd96,0xdd97,
+ 0xdd98,0xdd99,0xdd9a,0xdd9b,0xdd9c,0xdd9d,0xdd9e,0xdd9f,
+ 0xdda0,0xdda1,0xdda2,0xdda3,0xdda4,0xdda5,0xdda6,0xdda7,
+ 0xdda8,0xdda9,0xddaa,0xddab,0xddac,0xddad,0xddae,0xddaf,
+ 0xddb0,0xddb1,0xddb2,0xddb3,0xddb4,0xddb5,0xddb6,0xddb7,
+ 0xddb8,0xddb9,0xddba,0xddbb,0xddbc,0xddbd,0xddbe,0xddbf,
+ 0xddc0,0xddc1,0xddc2,0xddc3,0xddc4,0xddc5,0xddc6,0xddc7,
+ 0xddc8,0xddc9,0xddca,0xddcb,0xddcc,0xddcd,0xddce,0xddcf,
+ 0xddd0,0xddd1,0xddd2,0xddd3,0xddd4,0xddd5,0xddd6,0xddd7,
+ 0xddd8,0xddd9,0xddda,0xdddb,0xdddc,0xdddd,0xddde,0xdddf,
+ 0xdde0,0xdde1,0xdde2,0xdde3,0xdde4,0xdde5,0xdde6,0xdde7,
+ 0xdde8,0xdde9,0xddea,0xddeb,0xddec,0xdded,0xddee,0xddef,
+ 0xddf0,0xddf1,0xddf2,0xddf3,0xddf4,0xddf5,0xddf6,0xddf7,
+ 0xddf8,0xddf9,0xddfa,0xddfb,0xddfc,0xddfd,0xddfe,0xddff,
+ 0xde00,0xde01,0xde02,0xde03,0xde04,0xde05,0xde06,0xde07,
+ 0xde08,0xde09,0xde0a,0xde0b,0xde0c,0xde0d,0xde0e,0xde0f,
+ 0xde10,0xde11,0xde12,0xde13,0xde14,0xde15,0xde16,0xde17,
+ 0xde18,0xde19,0xde1a,0xde1b,0xde1c,0xde1d,0xde1e,0xde1f,
+ 0xde20,0xde21,0xde22,0xde23,0xde24,0xde25,0xde26,0xde27,
+ 0xde28,0xde29,0xde2a,0xde2b,0xde2c,0xde2d,0xde2e,0xde2f,
+ 0xde30,0xde31,0xde32,0xde33,0xde34,0xde35,0xde36,0xde37,
+ 0xde38,0xde39,0xde3a,0xde3b,0xde3c,0xde3d,0xde3e,0xde3f,
+ 0xde40,0xde41,0xde42,0xde43,0xde44,0xde45,0xde46,0xde47,
+ 0xde48,0xde49,0xde4a,0xde4b,0xde4c,0xde4d,0xde4e,0xde4f,
+ 0xde50,0xde51,0xde52,0xde53,0xde54,0xde55,0xde56,0xde57,
+ 0xde58,0xde59,0xde5a,0xde5b,0xde5c,0xde5d,0xde5e,0xde5f,
+ 0xde60,0xde61,0xde62,0xde63,0xde64,0xde65,0xde66,0xde67,
+ 0xde68,0xde69,0xde6a,0xde6b,0xde6c,0xde6d,0xde6e,0xde6f,
+ 0xde70,0xde71,0xde72,0xde73,0xde74,0xde75,0xde76,0xde77,
+ 0xde78,0xde79,0xde7a,0xde7b,0xde7c,0xde7d,0xde7e,0xde7f,
+ 0xde80,0xde81,0xde82,0xde83,0xde84,0xde85,0xde86,0xde87,
+ 0xde88,0xde89,0xde8a,0xde8b,0xde8c,0xde8d,0xde8e,0xde8f,
+ 0xde90,0xde91,0xde92,0xde93,0xde94,0xde95,0xde96,0xde97,
+ 0xde98,0xde99,0xde9a,0xde9b,0xde9c,0xde9d,0xde9e,0xde9f,
+ 0xdea0,0xdea1,0xdea2,0xdea3,0xdea4,0xdea5,0xdea6,0xdea7,
+ 0xdea8,0xdea9,0xdeaa,0xdeab,0xdeac,0xdead,0xdeae,0xdeaf,
+ 0xdeb0,0xdeb1,0xdeb2,0xdeb3,0xdeb4,0xdeb5,0xdeb6,0xdeb7,
+ 0xdeb8,0xdeb9,0xdeba,0xdebb,0xdebc,0xdebd,0xdebe,0xdebf,
+ 0xdec0,0xdec1,0xdec2,0xdec3,0xdec4,0xdec5,0xdec6,0xdec7,
+ 0xdec8,0xdec9,0xdeca,0xdecb,0xdecc,0xdecd,0xdece,0xdecf,
+ 0xded0,0xded1,0xded2,0xded3,0xded4,0xded5,0xded6,0xded7,
+ 0xded8,0xded9,0xdeda,0xdedb,0xdedc,0xdedd,0xdede,0xdedf,
+ 0xdee0,0xdee1,0xdee2,0xdee3,0xdee4,0xdee5,0xdee6,0xdee7,
+ 0xdee8,0xdee9,0xdeea,0xdeeb,0xdeec,0xdeed,0xdeee,0xdeef,
+ 0xdef0,0xdef1,0xdef2,0xdef3,0xdef4,0xdef5,0xdef6,0xdef7,
+ 0xdef8,0xdef9,0xdefa,0xdefb,0xdefc,0xdefd,0xdefe,0xdeff,
+ 0xdf00,0xdf01,0xdf02,0xdf03,0xdf04,0xdf05,0xdf06,0xdf07,
+ 0xdf08,0xdf09,0xdf0a,0xdf0b,0xdf0c,0xdf0d,0xdf0e,0xdf0f,
+ 0xdf10,0xdf11,0xdf12,0xdf13,0xdf14,0xdf15,0xdf16,0xdf17,
+ 0xdf18,0xdf19,0xdf1a,0xdf1b,0xdf1c,0xdf1d,0xdf1e,0xdf1f,
+ 0xdf20,0xdf21,0xdf22,0xdf23,0xdf24,0xdf25,0xdf26,0xdf27,
+ 0xdf28,0xdf29,0xdf2a,0xdf2b,0xdf2c,0xdf2d,0xdf2e,0xdf2f,
+ 0xdf30,0xdf31,0xdf32,0xdf33,0xdf34,0xdf35,0xdf36,0xdf37,
+ 0xdf38,0xdf39,0xdf3a,0xdf3b,0xdf3c,0xdf3d,0xdf3e,0xdf3f,
+ 0xdf40,0xdf41,0xdf42,0xdf43,0xdf44,0xdf45,0xdf46,0xdf47,
+ 0xdf48,0xdf49,0xdf4a,0xdf4b,0xdf4c,0xdf4d,0xdf4e,0xdf4f,
+ 0xdf50,0xdf51,0xdf52,0xdf53,0xdf54,0xdf55,0xdf56,0xdf57,
+ 0xdf58,0xdf59,0xdf5a,0xdf5b,0xdf5c,0xdf5d,0xdf5e,0xdf5f,
+ 0xdf60,0xdf61,0xdf62,0xdf63,0xdf64,0xdf65,0xdf66,0xdf67,
+ 0xdf68,0xdf69,0xdf6a,0xdf6b,0xdf6c,0xdf6d,0xdf6e,0xdf6f,
+ 0xdf70,0xdf71,0xdf72,0xdf73,0xdf74,0xdf75,0xdf76,0xdf77,
+ 0xdf78,0xdf79,0xdf7a,0xdf7b,0xdf7c,0xdf7d,0xdf7e,0xdf7f,
+ 0xdf80,0xdf81,0xdf82,0xdf83,0xdf84,0xdf85,0xdf86,0xdf87,
+ 0xdf88,0xdf89,0xdf8a,0xdf8b,0xdf8c,0xdf8d,0xdf8e,0xdf8f,
+ 0xdf90,0xdf91,0xdf92,0xdf93,0xdf94,0xdf95,0xdf96,0xdf97,
+ 0xdf98,0xdf99,0xdf9a,0xdf9b,0xdf9c,0xdf9d,0xdf9e,0xdf9f,
+ 0xdfa0,0xdfa1,0xdfa2,0xdfa3,0xdfa4,0xdfa5,0xdfa6,0xdfa7,
+ 0xdfa8,0xdfa9,0xdfaa,0xdfab,0xdfac,0xdfad,0xdfae,0xdfaf,
+ 0xdfb0,0xdfb1,0xdfb2,0xdfb3,0xdfb4,0xdfb5,0xdfb6,0xdfb7,
+ 0xdfb8,0xdfb9,0xdfba,0xdfbb,0xdfbc,0xdfbd,0xdfbe,0xdfbf,
+ 0xdfc0,0xdfc1,0xdfc2,0xdfc3,0xdfc4,0xdfc5,0xdfc6,0xdfc7,
+ 0xdfc8,0xdfc9,0xdfca,0xdfcb,0xdfcc,0xdfcd,0xdfce,0xdfcf,
+ 0xdfd0,0xdfd1,0xdfd2,0xdfd3,0xdfd4,0xdfd5,0xdfd6,0xdfd7,
+ 0xdfd8,0xdfd9,0xdfda,0xdfdb,0xdfdc,0xdfdd,0xdfde,0xdfdf,
+ 0xdfe0,0xdfe1,0xdfe2,0xdfe3,0xdfe4,0xdfe5,0xdfe6,0xdfe7,
+ 0xdfe8,0xdfe9,0xdfea,0xdfeb,0xdfec,0xdfed,0xdfee,0xdfef,
+ 0xdff0,0xdff1,0xdff2,0xdff3,0xdff4,0xdff5,0xdff6,0xdff7,
+ 0xdff8,0xdff9,0xdffa,0xdffb,0xdffc,0xdffd,0xdffe,0xdfff,
+ 0xe000,0xe001,0xe002,0xe003,0xe004,0xe005,0xe006,0xe007,
+ 0xe008,0xe009,0xe00a,0xe00b,0xe00c,0xe00d,0xe00e,0xe00f,
+ 0xe010,0xe011,0xe012,0xe013,0xe014,0xe015,0xe016,0xe017,
+ 0xe018,0xe019,0xe01a,0xe01b,0xe01c,0xe01d,0xe01e,0xe01f,
+ 0xe020,0xe021,0xe022,0xe023,0xe024,0xe025,0xe026,0xe027,
+ 0xe028,0xe029,0xe02a,0xe02b,0xe02c,0xe02d,0xe02e,0xe02f,
+ 0xe030,0xe031,0xe032,0xe033,0xe034,0xe035,0xe036,0xe037,
+ 0xe038,0xe039,0xe03a,0xe03b,0xe03c,0xe03d,0xe03e,0xe03f,
+ 0xe040,0xe041,0xe042,0xe043,0xe044,0xe045,0xe046,0xe047,
+ 0xe048,0xe049,0xe04a,0xe04b,0xe04c,0xe04d,0xe04e,0xe04f,
+ 0xe050,0xe051,0xe052,0xe053,0xe054,0xe055,0xe056,0xe057,
+ 0xe058,0xe059,0xe05a,0xe05b,0xe05c,0xe05d,0xe05e,0xe05f,
+ 0xe060,0xe061,0xe062,0xe063,0xe064,0xe065,0xe066,0xe067,
+ 0xe068,0xe069,0xe06a,0xe06b,0xe06c,0xe06d,0xe06e,0xe06f,
+ 0xe070,0xe071,0xe072,0xe073,0xe074,0xe075,0xe076,0xe077,
+ 0xe078,0xe079,0xe07a,0xe07b,0xe07c,0xe07d,0xe07e,0xe07f,
+ 0xe080,0xe081,0xe082,0xe083,0xe084,0xe085,0xe086,0xe087,
+ 0xe088,0xe089,0xe08a,0xe08b,0xe08c,0xe08d,0xe08e,0xe08f,
+ 0xe090,0xe091,0xe092,0xe093,0xe094,0xe095,0xe096,0xe097,
+ 0xe098,0xe099,0xe09a,0xe09b,0xe09c,0xe09d,0xe09e,0xe09f,
+ 0xe0a0,0xe0a1,0xe0a2,0xe0a3,0xe0a4,0xe0a5,0xe0a6,0xe0a7,
+ 0xe0a8,0xe0a9,0xe0aa,0xe0ab,0xe0ac,0xe0ad,0xe0ae,0xe0af,
+ 0xe0b0,0xe0b1,0xe0b2,0xe0b3,0xe0b4,0xe0b5,0xe0b6,0xe0b7,
+ 0xe0b8,0xe0b9,0xe0ba,0xe0bb,0xe0bc,0xe0bd,0xe0be,0xe0bf,
+ 0xe0c0,0xe0c1,0xe0c2,0xe0c3,0xe0c4,0xe0c5,0xe0c6,0xe0c7,
+ 0xe0c8,0xe0c9,0xe0ca,0xe0cb,0xe0cc,0xe0cd,0xe0ce,0xe0cf,
+ 0xe0d0,0xe0d1,0xe0d2,0xe0d3,0xe0d4,0xe0d5,0xe0d6,0xe0d7,
+ 0xe0d8,0xe0d9,0xe0da,0xe0db,0xe0dc,0xe0dd,0xe0de,0xe0df,
+ 0xe0e0,0xe0e1,0xe0e2,0xe0e3,0xe0e4,0xe0e5,0xe0e6,0xe0e7,
+ 0xe0e8,0xe0e9,0xe0ea,0xe0eb,0xe0ec,0xe0ed,0xe0ee,0xe0ef,
+ 0xe0f0,0xe0f1,0xe0f2,0xe0f3,0xe0f4,0xe0f5,0xe0f6,0xe0f7,
+ 0xe0f8,0xe0f9,0xe0fa,0xe0fb,0xe0fc,0xe0fd,0xe0fe,0xe0ff,
+ 0xe100,0xe101,0xe102,0xe103,0xe104,0xe105,0xe106,0xe107,
+ 0xe108,0xe109,0xe10a,0xe10b,0xe10c,0xe10d,0xe10e,0xe10f,
+ 0xe110,0xe111,0xe112,0xe113,0xe114,0xe115,0xe116,0xe117,
+ 0xe118,0xe119,0xe11a,0xe11b,0xe11c,0xe11d,0xe11e,0xe11f,
+ 0xe120,0xe121,0xe122,0xe123,0xe124,0xe125,0xe126,0xe127,
+ 0xe128,0xe129,0xe12a,0xe12b,0xe12c,0xe12d,0xe12e,0xe12f,
+ 0xe130,0xe131,0xe132,0xe133,0xe134,0xe135,0xe136,0xe137,
+ 0xe138,0xe139,0xe13a,0xe13b,0xe13c,0xe13d,0xe13e,0xe13f,
+ 0xe140,0xe141,0xe142,0xe143,0xe144,0xe145,0xe146,0xe147,
+ 0xe148,0xe149,0xe14a,0xe14b,0xe14c,0xe14d,0xe14e,0xe14f,
+ 0xe150,0xe151,0xe152,0xe153,0xe154,0xe155,0xe156,0xe157,
+ 0xe158,0xe159,0xe15a,0xe15b,0xe15c,0xe15d,0xe15e,0xe15f,
+ 0xe160,0xe161,0xe162,0xe163,0xe164,0xe165,0xe166,0xe167,
+ 0xe168,0xe169,0xe16a,0xe16b,0xe16c,0xe16d,0xe16e,0xe16f,
+ 0xe170,0xe171,0xe172,0xe173,0xe174,0xe175,0xe176,0xe177,
+ 0xe178,0xe179,0xe17a,0xe17b,0xe17c,0xe17d,0xe17e,0xe17f,
+ 0xe180,0xe181,0xe182,0xe183,0xe184,0xe185,0xe186,0xe187,
+ 0xe188,0xe189,0xe18a,0xe18b,0xe18c,0xe18d,0xe18e,0xe18f,
+ 0xe190,0xe191,0xe192,0xe193,0xe194,0xe195,0xe196,0xe197,
+ 0xe198,0xe199,0xe19a,0xe19b,0xe19c,0xe19d,0xe19e,0xe19f,
+ 0xe1a0,0xe1a1,0xe1a2,0xe1a3,0xe1a4,0xe1a5,0xe1a6,0xe1a7,
+ 0xe1a8,0xe1a9,0xe1aa,0xe1ab,0xe1ac,0xe1ad,0xe1ae,0xe1af,
+ 0xe1b0,0xe1b1,0xe1b2,0xe1b3,0xe1b4,0xe1b5,0xe1b6,0xe1b7,
+ 0xe1b8,0xe1b9,0xe1ba,0xe1bb,0xe1bc,0xe1bd,0xe1be,0xe1bf,
+ 0xe1c0,0xe1c1,0xe1c2,0xe1c3,0xe1c4,0xe1c5,0xe1c6,0xe1c7,
+ 0xe1c8,0xe1c9,0xe1ca,0xe1cb,0xe1cc,0xe1cd,0xe1ce,0xe1cf,
+ 0xe1d0,0xe1d1,0xe1d2,0xe1d3,0xe1d4,0xe1d5,0xe1d6,0xe1d7,
+ 0xe1d8,0xe1d9,0xe1da,0xe1db,0xe1dc,0xe1dd,0xe1de,0xe1df,
+ 0xe1e0,0xe1e1,0xe1e2,0xe1e3,0xe1e4,0xe1e5,0xe1e6,0xe1e7,
+ 0xe1e8,0xe1e9,0xe1ea,0xe1eb,0xe1ec,0xe1ed,0xe1ee,0xe1ef,
+ 0xe1f0,0xe1f1,0xe1f2,0xe1f3,0xe1f4,0xe1f5,0xe1f6,0xe1f7,
+ 0xe1f8,0xe1f9,0xe1fa,0xe1fb,0xe1fc,0xe1fd,0xe1fe,0xe1ff,
+ 0xe200,0xe201,0xe202,0xe203,0xe204,0xe205,0xe206,0xe207,
+ 0xe208,0xe209,0xe20a,0xe20b,0xe20c,0xe20d,0xe20e,0xe20f,
+ 0xe210,0xe211,0xe212,0xe213,0xe214,0xe215,0xe216,0xe217,
+ 0xe218,0xe219,0xe21a,0xe21b,0xe21c,0xe21d,0xe21e,0xe21f,
+ 0xe220,0xe221,0xe222,0xe223,0xe224,0xe225,0xe226,0xe227,
+ 0xe228,0xe229,0xe22a,0xe22b,0xe22c,0xe22d,0xe22e,0xe22f,
+ 0xe230,0xe231,0xe232,0xe233,0xe234,0xe235,0xe236,0xe237,
+ 0xe238,0xe239,0xe23a,0xe23b,0xe23c,0xe23d,0xe23e,0xe23f,
+ 0xe240,0xe241,0xe242,0xe243,0xe244,0xe245,0xe246,0xe247,
+ 0xe248,0xe249,0xe24a,0xe24b,0xe24c,0xe24d,0xe24e,0xe24f,
+ 0xe250,0xe251,0xe252,0xe253,0xe254,0xe255,0xe256,0xe257,
+ 0xe258,0xe259,0xe25a,0xe25b,0xe25c,0xe25d,0xe25e,0xe25f,
+ 0xe260,0xe261,0xe262,0xe263,0xe264,0xe265,0xe266,0xe267,
+ 0xe268,0xe269,0xe26a,0xe26b,0xe26c,0xe26d,0xe26e,0xe26f,
+ 0xe270,0xe271,0xe272,0xe273,0xe274,0xe275,0xe276,0xe277,
+ 0xe278,0xe279,0xe27a,0xe27b,0xe27c,0xe27d,0xe27e,0xe27f,
+ 0xe280,0xe281,0xe282,0xe283,0xe284,0xe285,0xe286,0xe287,
+ 0xe288,0xe289,0xe28a,0xe28b,0xe28c,0xe28d,0xe28e,0xe28f,
+ 0xe290,0xe291,0xe292,0xe293,0xe294,0xe295,0xe296,0xe297,
+ 0xe298,0xe299,0xe29a,0xe29b,0xe29c,0xe29d,0xe29e,0xe29f,
+ 0xe2a0,0xe2a1,0xe2a2,0xe2a3,0xe2a4,0xe2a5,0xe2a6,0xe2a7,
+ 0xe2a8,0xe2a9,0xe2aa,0xe2ab,0xe2ac,0xe2ad,0xe2ae,0xe2af,
+ 0xe2b0,0xe2b1,0xe2b2,0xe2b3,0xe2b4,0xe2b5,0xe2b6,0xe2b7,
+ 0xe2b8,0xe2b9,0xe2ba,0xe2bb,0xe2bc,0xe2bd,0xe2be,0xe2bf,
+ 0xe2c0,0xe2c1,0xe2c2,0xe2c3,0xe2c4,0xe2c5,0xe2c6,0xe2c7,
+ 0xe2c8,0xe2c9,0xe2ca,0xe2cb,0xe2cc,0xe2cd,0xe2ce,0xe2cf,
+ 0xe2d0,0xe2d1,0xe2d2,0xe2d3,0xe2d4,0xe2d5,0xe2d6,0xe2d7,
+ 0xe2d8,0xe2d9,0xe2da,0xe2db,0xe2dc,0xe2dd,0xe2de,0xe2df,
+ 0xe2e0,0xe2e1,0xe2e2,0xe2e3,0xe2e4,0xe2e5,0xe2e6,0xe2e7,
+ 0xe2e8,0xe2e9,0xe2ea,0xe2eb,0xe2ec,0xe2ed,0xe2ee,0xe2ef,
+ 0xe2f0,0xe2f1,0xe2f2,0xe2f3,0xe2f4,0xe2f5,0xe2f6,0xe2f7,
+ 0xe2f8,0xe2f9,0xe2fa,0xe2fb,0xe2fc,0xe2fd,0xe2fe,0xe2ff,
+ 0xe300,0xe301,0xe302,0xe303,0xe304,0xe305,0xe306,0xe307,
+ 0xe308,0xe309,0xe30a,0xe30b,0xe30c,0xe30d,0xe30e,0xe30f,
+ 0xe310,0xe311,0xe312,0xe313,0xe314,0xe315,0xe316,0xe317,
+ 0xe318,0xe319,0xe31a,0xe31b,0xe31c,0xe31d,0xe31e,0xe31f,
+ 0xe320,0xe321,0xe322,0xe323,0xe324,0xe325,0xe326,0xe327,
+ 0xe328,0xe329,0xe32a,0xe32b,0xe32c,0xe32d,0xe32e,0xe32f,
+ 0xe330,0xe331,0xe332,0xe333,0xe334,0xe335,0xe336,0xe337,
+ 0xe338,0xe339,0xe33a,0xe33b,0xe33c,0xe33d,0xe33e,0xe33f,
+ 0xe340,0xe341,0xe342,0xe343,0xe344,0xe345,0xe346,0xe347,
+ 0xe348,0xe349,0xe34a,0xe34b,0xe34c,0xe34d,0xe34e,0xe34f,
+ 0xe350,0xe351,0xe352,0xe353,0xe354,0xe355,0xe356,0xe357,
+ 0xe358,0xe359,0xe35a,0xe35b,0xe35c,0xe35d,0xe35e,0xe35f,
+ 0xe360,0xe361,0xe362,0xe363,0xe364,0xe365,0xe366,0xe367,
+ 0xe368,0xe369,0xe36a,0xe36b,0xe36c,0xe36d,0xe36e,0xe36f,
+ 0xe370,0xe371,0xe372,0xe373,0xe374,0xe375,0xe376,0xe377,
+ 0xe378,0xe379,0xe37a,0xe37b,0xe37c,0xe37d,0xe37e,0xe37f,
+ 0xe380,0xe381,0xe382,0xe383,0xe384,0xe385,0xe386,0xe387,
+ 0xe388,0xe389,0xe38a,0xe38b,0xe38c,0xe38d,0xe38e,0xe38f,
+ 0xe390,0xe391,0xe392,0xe393,0xe394,0xe395,0xe396,0xe397,
+ 0xe398,0xe399,0xe39a,0xe39b,0xe39c,0xe39d,0xe39e,0xe39f,
+ 0xe3a0,0xe3a1,0xe3a2,0xe3a3,0xe3a4,0xe3a5,0xe3a6,0xe3a7,
+ 0xe3a8,0xe3a9,0xe3aa,0xe3ab,0xe3ac,0xe3ad,0xe3ae,0xe3af,
+ 0xe3b0,0xe3b1,0xe3b2,0xe3b3,0xe3b4,0xe3b5,0xe3b6,0xe3b7,
+ 0xe3b8,0xe3b9,0xe3ba,0xe3bb,0xe3bc,0xe3bd,0xe3be,0xe3bf,
+ 0xe3c0,0xe3c1,0xe3c2,0xe3c3,0xe3c4,0xe3c5,0xe3c6,0xe3c7,
+ 0xe3c8,0xe3c9,0xe3ca,0xe3cb,0xe3cc,0xe3cd,0xe3ce,0xe3cf,
+ 0xe3d0,0xe3d1,0xe3d2,0xe3d3,0xe3d4,0xe3d5,0xe3d6,0xe3d7,
+ 0xe3d8,0xe3d9,0xe3da,0xe3db,0xe3dc,0xe3dd,0xe3de,0xe3df,
+ 0xe3e0,0xe3e1,0xe3e2,0xe3e3,0xe3e4,0xe3e5,0xe3e6,0xe3e7,
+ 0xe3e8,0xe3e9,0xe3ea,0xe3eb,0xe3ec,0xe3ed,0xe3ee,0xe3ef,
+ 0xe3f0,0xe3f1,0xe3f2,0xe3f3,0xe3f4,0xe3f5,0xe3f6,0xe3f7,
+ 0xe3f8,0xe3f9,0xe3fa,0xe3fb,0xe3fc,0xe3fd,0xe3fe,0xe3ff,
+ 0xe400,0xe401,0xe402,0xe403,0xe404,0xe405,0xe406,0xe407,
+ 0xe408,0xe409,0xe40a,0xe40b,0xe40c,0xe40d,0xe40e,0xe40f,
+ 0xe410,0xe411,0xe412,0xe413,0xe414,0xe415,0xe416,0xe417,
+ 0xe418,0xe419,0xe41a,0xe41b,0xe41c,0xe41d,0xe41e,0xe41f,
+ 0xe420,0xe421,0xe422,0xe423,0xe424,0xe425,0xe426,0xe427,
+ 0xe428,0xe429,0xe42a,0xe42b,0xe42c,0xe42d,0xe42e,0xe42f,
+ 0xe430,0xe431,0xe432,0xe433,0xe434,0xe435,0xe436,0xe437,
+ 0xe438,0xe439,0xe43a,0xe43b,0xe43c,0xe43d,0xe43e,0xe43f,
+ 0xe440,0xe441,0xe442,0xe443,0xe444,0xe445,0xe446,0xe447,
+ 0xe448,0xe449,0xe44a,0xe44b,0xe44c,0xe44d,0xe44e,0xe44f,
+ 0xe450,0xe451,0xe452,0xe453,0xe454,0xe455,0xe456,0xe457,
+ 0xe458,0xe459,0xe45a,0xe45b,0xe45c,0xe45d,0xe45e,0xe45f,
+ 0xe460,0xe461,0xe462,0xe463,0xe464,0xe465,0xe466,0xe467,
+ 0xe468,0xe469,0xe46a,0xe46b,0xe46c,0xe46d,0xe46e,0xe46f,
+ 0xe470,0xe471,0xe472,0xe473,0xe474,0xe475,0xe476,0xe477,
+ 0xe478,0xe479,0xe47a,0xe47b,0xe47c,0xe47d,0xe47e,0xe47f,
+ 0xe480,0xe481,0xe482,0xe483,0xe484,0xe485,0xe486,0xe487,
+ 0xe488,0xe489,0xe48a,0xe48b,0xe48c,0xe48d,0xe48e,0xe48f,
+ 0xe490,0xe491,0xe492,0xe493,0xe494,0xe495,0xe496,0xe497,
+ 0xe498,0xe499,0xe49a,0xe49b,0xe49c,0xe49d,0xe49e,0xe49f,
+ 0xe4a0,0xe4a1,0xe4a2,0xe4a3,0xe4a4,0xe4a5,0xe4a6,0xe4a7,
+ 0xe4a8,0xe4a9,0xe4aa,0xe4ab,0xe4ac,0xe4ad,0xe4ae,0xe4af,
+ 0xe4b0,0xe4b1,0xe4b2,0xe4b3,0xe4b4,0xe4b5,0xe4b6,0xe4b7,
+ 0xe4b8,0xe4b9,0xe4ba,0xe4bb,0xe4bc,0xe4bd,0xe4be,0xe4bf,
+ 0xe4c0,0xe4c1,0xe4c2,0xe4c3,0xe4c4,0xe4c5,0xe4c6,0xe4c7,
+ 0xe4c8,0xe4c9,0xe4ca,0xe4cb,0xe4cc,0xe4cd,0xe4ce,0xe4cf,
+ 0xe4d0,0xe4d1,0xe4d2,0xe4d3,0xe4d4,0xe4d5,0xe4d6,0xe4d7,
+ 0xe4d8,0xe4d9,0xe4da,0xe4db,0xe4dc,0xe4dd,0xe4de,0xe4df,
+ 0xe4e0,0xe4e1,0xe4e2,0xe4e3,0xe4e4,0xe4e5,0xe4e6,0xe4e7,
+ 0xe4e8,0xe4e9,0xe4ea,0xe4eb,0xe4ec,0xe4ed,0xe4ee,0xe4ef,
+ 0xe4f0,0xe4f1,0xe4f2,0xe4f3,0xe4f4,0xe4f5,0xe4f6,0xe4f7,
+ 0xe4f8,0xe4f9,0xe4fa,0xe4fb,0xe4fc,0xe4fd,0xe4fe,0xe4ff,
+ 0xe500,0xe501,0xe502,0xe503,0xe504,0xe505,0xe506,0xe507,
+ 0xe508,0xe509,0xe50a,0xe50b,0xe50c,0xe50d,0xe50e,0xe50f,
+ 0xe510,0xe511,0xe512,0xe513,0xe514,0xe515,0xe516,0xe517,
+ 0xe518,0xe519,0xe51a,0xe51b,0xe51c,0xe51d,0xe51e,0xe51f,
+ 0xe520,0xe521,0xe522,0xe523,0xe524,0xe525,0xe526,0xe527,
+ 0xe528,0xe529,0xe52a,0xe52b,0xe52c,0xe52d,0xe52e,0xe52f,
+ 0xe530,0xe531,0xe532,0xe533,0xe534,0xe535,0xe536,0xe537,
+ 0xe538,0xe539,0xe53a,0xe53b,0xe53c,0xe53d,0xe53e,0xe53f,
+ 0xe540,0xe541,0xe542,0xe543,0xe544,0xe545,0xe546,0xe547,
+ 0xe548,0xe549,0xe54a,0xe54b,0xe54c,0xe54d,0xe54e,0xe54f,
+ 0xe550,0xe551,0xe552,0xe553,0xe554,0xe555,0xe556,0xe557,
+ 0xe558,0xe559,0xe55a,0xe55b,0xe55c,0xe55d,0xe55e,0xe55f,
+ 0xe560,0xe561,0xe562,0xe563,0xe564,0xe565,0xe566,0xe567,
+ 0xe568,0xe569,0xe56a,0xe56b,0xe56c,0xe56d,0xe56e,0xe56f,
+ 0xe570,0xe571,0xe572,0xe573,0xe574,0xe575,0xe576,0xe577,
+ 0xe578,0xe579,0xe57a,0xe57b,0xe57c,0xe57d,0xe57e,0xe57f,
+ 0xe580,0xe581,0xe582,0xe583,0xe584,0xe585,0xe586,0xe587,
+ 0xe588,0xe589,0xe58a,0xe58b,0xe58c,0xe58d,0xe58e,0xe58f,
+ 0xe590,0xe591,0xe592,0xe593,0xe594,0xe595,0xe596,0xe597,
+ 0xe598,0xe599,0xe59a,0xe59b,0xe59c,0xe59d,0xe59e,0xe59f,
+ 0xe5a0,0xe5a1,0xe5a2,0xe5a3,0xe5a4,0xe5a5,0xe5a6,0xe5a7,
+ 0xe5a8,0xe5a9,0xe5aa,0xe5ab,0xe5ac,0xe5ad,0xe5ae,0xe5af,
+ 0xe5b0,0xe5b1,0xe5b2,0xe5b3,0xe5b4,0xe5b5,0xe5b6,0xe5b7,
+ 0xe5b8,0xe5b9,0xe5ba,0xe5bb,0xe5bc,0xe5bd,0xe5be,0xe5bf,
+ 0xe5c0,0xe5c1,0xe5c2,0xe5c3,0xe5c4,0xe5c5,0xe5c6,0xe5c7,
+ 0xe5c8,0xe5c9,0xe5ca,0xe5cb,0xe5cc,0xe5cd,0xe5ce,0xe5cf,
+ 0xe5d0,0xe5d1,0xe5d2,0xe5d3,0xe5d4,0xe5d5,0xe5d6,0xe5d7,
+ 0xe5d8,0xe5d9,0xe5da,0xe5db,0xe5dc,0xe5dd,0xe5de,0xe5df,
+ 0xe5e0,0xe5e1,0xe5e2,0xe5e3,0xe5e4,0xe5e5,0xe5e6,0xe5e7,
+ 0xe5e8,0xe5e9,0xe5ea,0xe5eb,0xe5ec,0xe5ed,0xe5ee,0xe5ef,
+ 0xe5f0,0xe5f1,0xe5f2,0xe5f3,0xe5f4,0xe5f5,0xe5f6,0xe5f7,
+ 0xe5f8,0xe5f9,0xe5fa,0xe5fb,0xe5fc,0xe5fd,0xe5fe,0xe5ff,
+ 0xe600,0xe601,0xe602,0xe603,0xe604,0xe605,0xe606,0xe607,
+ 0xe608,0xe609,0xe60a,0xe60b,0xe60c,0xe60d,0xe60e,0xe60f,
+ 0xe610,0xe611,0xe612,0xe613,0xe614,0xe615,0xe616,0xe617,
+ 0xe618,0xe619,0xe61a,0xe61b,0xe61c,0xe61d,0xe61e,0xe61f,
+ 0xe620,0xe621,0xe622,0xe623,0xe624,0xe625,0xe626,0xe627,
+ 0xe628,0xe629,0xe62a,0xe62b,0xe62c,0xe62d,0xe62e,0xe62f,
+ 0xe630,0xe631,0xe632,0xe633,0xe634,0xe635,0xe636,0xe637,
+ 0xe638,0xe639,0xe63a,0xe63b,0xe63c,0xe63d,0xe63e,0xe63f,
+ 0xe640,0xe641,0xe642,0xe643,0xe644,0xe645,0xe646,0xe647,
+ 0xe648,0xe649,0xe64a,0xe64b,0xe64c,0xe64d,0xe64e,0xe64f,
+ 0xe650,0xe651,0xe652,0xe653,0xe654,0xe655,0xe656,0xe657,
+ 0xe658,0xe659,0xe65a,0xe65b,0xe65c,0xe65d,0xe65e,0xe65f,
+ 0xe660,0xe661,0xe662,0xe663,0xe664,0xe665,0xe666,0xe667,
+ 0xe668,0xe669,0xe66a,0xe66b,0xe66c,0xe66d,0xe66e,0xe66f,
+ 0xe670,0xe671,0xe672,0xe673,0xe674,0xe675,0xe676,0xe677,
+ 0xe678,0xe679,0xe67a,0xe67b,0xe67c,0xe67d,0xe67e,0xe67f,
+ 0xe680,0xe681,0xe682,0xe683,0xe684,0xe685,0xe686,0xe687,
+ 0xe688,0xe689,0xe68a,0xe68b,0xe68c,0xe68d,0xe68e,0xe68f,
+ 0xe690,0xe691,0xe692,0xe693,0xe694,0xe695,0xe696,0xe697,
+ 0xe698,0xe699,0xe69a,0xe69b,0xe69c,0xe69d,0xe69e,0xe69f,
+ 0xe6a0,0xe6a1,0xe6a2,0xe6a3,0xe6a4,0xe6a5,0xe6a6,0xe6a7,
+ 0xe6a8,0xe6a9,0xe6aa,0xe6ab,0xe6ac,0xe6ad,0xe6ae,0xe6af,
+ 0xe6b0,0xe6b1,0xe6b2,0xe6b3,0xe6b4,0xe6b5,0xe6b6,0xe6b7,
+ 0xe6b8,0xe6b9,0xe6ba,0xe6bb,0xe6bc,0xe6bd,0xe6be,0xe6bf,
+ 0xe6c0,0xe6c1,0xe6c2,0xe6c3,0xe6c4,0xe6c5,0xe6c6,0xe6c7,
+ 0xe6c8,0xe6c9,0xe6ca,0xe6cb,0xe6cc,0xe6cd,0xe6ce,0xe6cf,
+ 0xe6d0,0xe6d1,0xe6d2,0xe6d3,0xe6d4,0xe6d5,0xe6d6,0xe6d7,
+ 0xe6d8,0xe6d9,0xe6da,0xe6db,0xe6dc,0xe6dd,0xe6de,0xe6df,
+ 0xe6e0,0xe6e1,0xe6e2,0xe6e3,0xe6e4,0xe6e5,0xe6e6,0xe6e7,
+ 0xe6e8,0xe6e9,0xe6ea,0xe6eb,0xe6ec,0xe6ed,0xe6ee,0xe6ef,
+ 0xe6f0,0xe6f1,0xe6f2,0xe6f3,0xe6f4,0xe6f5,0xe6f6,0xe6f7,
+ 0xe6f8,0xe6f9,0xe6fa,0xe6fb,0xe6fc,0xe6fd,0xe6fe,0xe6ff,
+ 0xe700,0xe701,0xe702,0xe703,0xe704,0xe705,0xe706,0xe707,
+ 0xe708,0xe709,0xe70a,0xe70b,0xe70c,0xe70d,0xe70e,0xe70f,
+ 0xe710,0xe711,0xe712,0xe713,0xe714,0xe715,0xe716,0xe717,
+ 0xe718,0xe719,0xe71a,0xe71b,0xe71c,0xe71d,0xe71e,0xe71f,
+ 0xe720,0xe721,0xe722,0xe723,0xe724,0xe725,0xe726,0xe727,
+ 0xe728,0xe729,0xe72a,0xe72b,0xe72c,0xe72d,0xe72e,0xe72f,
+ 0xe730,0xe731,0xe732,0xe733,0xe734,0xe735,0xe736,0xe737,
+ 0xe738,0xe739,0xe73a,0xe73b,0xe73c,0xe73d,0xe73e,0xe73f,
+ 0xe740,0xe741,0xe742,0xe743,0xe744,0xe745,0xe746,0xe747,
+ 0xe748,0xe749,0xe74a,0xe74b,0xe74c,0xe74d,0xe74e,0xe74f,
+ 0xe750,0xe751,0xe752,0xe753,0xe754,0xe755,0xe756,0xe757,
+ 0xe758,0xe759,0xe75a,0xe75b,0xe75c,0xe75d,0xe75e,0xe75f,
+ 0xe760,0xe761,0xe762,0xe763,0xe764,0xe765,0xe766,0xe767,
+ 0xe768,0xe769,0xe76a,0xe76b,0xe76c,0xe76d,0xe76e,0xe76f,
+ 0xe770,0xe771,0xe772,0xe773,0xe774,0xe775,0xe776,0xe777,
+ 0xe778,0xe779,0xe77a,0xe77b,0xe77c,0xe77d,0xe77e,0xe77f,
+ 0xe780,0xe781,0xe782,0xe783,0xe784,0xe785,0xe786,0xe787,
+ 0xe788,0xe789,0xe78a,0xe78b,0xe78c,0xe78d,0xe78e,0xe78f,
+ 0xe790,0xe791,0xe792,0xe793,0xe794,0xe795,0xe796,0xe797,
+ 0xe798,0xe799,0xe79a,0xe79b,0xe79c,0xe79d,0xe79e,0xe79f,
+ 0xe7a0,0xe7a1,0xe7a2,0xe7a3,0xe7a4,0xe7a5,0xe7a6,0xe7a7,
+ 0xe7a8,0xe7a9,0xe7aa,0xe7ab,0xe7ac,0xe7ad,0xe7ae,0xe7af,
+ 0xe7b0,0xe7b1,0xe7b2,0xe7b3,0xe7b4,0xe7b5,0xe7b6,0xe7b7,
+ 0xe7b8,0xe7b9,0xe7ba,0xe7bb,0xe7bc,0xe7bd,0xe7be,0xe7bf,
+ 0xe7c0,0xe7c1,0xe7c2,0xe7c3,0xe7c4,0xe7c5,0xe7c6,0xe7c7,
+ 0xe7c8,0xe7c9,0xe7ca,0xe7cb,0xe7cc,0xe7cd,0xe7ce,0xe7cf,
+ 0xe7d0,0xe7d1,0xe7d2,0xe7d3,0xe7d4,0xe7d5,0xe7d6,0xe7d7,
+ 0xe7d8,0xe7d9,0xe7da,0xe7db,0xe7dc,0xe7dd,0xe7de,0xe7df,
+ 0xe7e0,0xe7e1,0xe7e2,0xe7e3,0xe7e4,0xe7e5,0xe7e6,0xe7e7,
+ 0xe7e8,0xe7e9,0xe7ea,0xe7eb,0xe7ec,0xe7ed,0xe7ee,0xe7ef,
+ 0xe7f0,0xe7f1,0xe7f2,0xe7f3,0xe7f4,0xe7f5,0xe7f6,0xe7f7,
+ 0xe7f8,0xe7f9,0xe7fa,0xe7fb,0xe7fc,0xe7fd,0xe7fe,0xe7ff,
+ 0xe800,0xe801,0xe802,0xe803,0xe804,0xe805,0xe806,0xe807,
+ 0xe808,0xe809,0xe80a,0xe80b,0xe80c,0xe80d,0xe80e,0xe80f,
+ 0xe810,0xe811,0xe812,0xe813,0xe814,0xe815,0xe816,0xe817,
+ 0xe818,0xe819,0xe81a,0xe81b,0xe81c,0xe81d,0xe81e,0xe81f,
+ 0xe820,0xe821,0xe822,0xe823,0xe824,0xe825,0xe826,0xe827,
+ 0xe828,0xe829,0xe82a,0xe82b,0xe82c,0xe82d,0xe82e,0xe82f,
+ 0xe830,0xe831,0xe832,0xe833,0xe834,0xe835,0xe836,0xe837,
+ 0xe838,0xe839,0xe83a,0xe83b,0xe83c,0xe83d,0xe83e,0xe83f,
+ 0xe840,0xe841,0xe842,0xe843,0xe844,0xe845,0xe846,0xe847,
+ 0xe848,0xe849,0xe84a,0xe84b,0xe84c,0xe84d,0xe84e,0xe84f,
+ 0xe850,0xe851,0xe852,0xe853,0xe854,0xe855,0xe856,0xe857,
+ 0xe858,0xe859,0xe85a,0xe85b,0xe85c,0xe85d,0xe85e,0xe85f,
+ 0xe860,0xe861,0xe862,0xe863,0xe864,0xe865,0xe866,0xe867,
+ 0xe868,0xe869,0xe86a,0xe86b,0xe86c,0xe86d,0xe86e,0xe86f,
+ 0xe870,0xe871,0xe872,0xe873,0xe874,0xe875,0xe876,0xe877,
+ 0xe878,0xe879,0xe87a,0xe87b,0xe87c,0xe87d,0xe87e,0xe87f,
+ 0xe880,0xe881,0xe882,0xe883,0xe884,0xe885,0xe886,0xe887,
+ 0xe888,0xe889,0xe88a,0xe88b,0xe88c,0xe88d,0xe88e,0xe88f,
+ 0xe890,0xe891,0xe892,0xe893,0xe894,0xe895,0xe896,0xe897,
+ 0xe898,0xe899,0xe89a,0xe89b,0xe89c,0xe89d,0xe89e,0xe89f,
+ 0xe8a0,0xe8a1,0xe8a2,0xe8a3,0xe8a4,0xe8a5,0xe8a6,0xe8a7,
+ 0xe8a8,0xe8a9,0xe8aa,0xe8ab,0xe8ac,0xe8ad,0xe8ae,0xe8af,
+ 0xe8b0,0xe8b1,0xe8b2,0xe8b3,0xe8b4,0xe8b5,0xe8b6,0xe8b7,
+ 0xe8b8,0xe8b9,0xe8ba,0xe8bb,0xe8bc,0xe8bd,0xe8be,0xe8bf,
+ 0xe8c0,0xe8c1,0xe8c2,0xe8c3,0xe8c4,0xe8c5,0xe8c6,0xe8c7,
+ 0xe8c8,0xe8c9,0xe8ca,0xe8cb,0xe8cc,0xe8cd,0xe8ce,0xe8cf,
+ 0xe8d0,0xe8d1,0xe8d2,0xe8d3,0xe8d4,0xe8d5,0xe8d6,0xe8d7,
+ 0xe8d8,0xe8d9,0xe8da,0xe8db,0xe8dc,0xe8dd,0xe8de,0xe8df,
+ 0xe8e0,0xe8e1,0xe8e2,0xe8e3,0xe8e4,0xe8e5,0xe8e6,0xe8e7,
+ 0xe8e8,0xe8e9,0xe8ea,0xe8eb,0xe8ec,0xe8ed,0xe8ee,0xe8ef,
+ 0xe8f0,0xe8f1,0xe8f2,0xe8f3,0xe8f4,0xe8f5,0xe8f6,0xe8f7,
+ 0xe8f8,0xe8f9,0xe8fa,0xe8fb,0xe8fc,0xe8fd,0xe8fe,0xe8ff,
+ 0xe900,0xe901,0xe902,0xe903,0xe904,0xe905,0xe906,0xe907,
+ 0xe908,0xe909,0xe90a,0xe90b,0xe90c,0xe90d,0xe90e,0xe90f,
+ 0xe910,0xe911,0xe912,0xe913,0xe914,0xe915,0xe916,0xe917,
+ 0xe918,0xe919,0xe91a,0xe91b,0xe91c,0xe91d,0xe91e,0xe91f,
+ 0xe920,0xe921,0xe922,0xe923,0xe924,0xe925,0xe926,0xe927,
+ 0xe928,0xe929,0xe92a,0xe92b,0xe92c,0xe92d,0xe92e,0xe92f,
+ 0xe930,0xe931,0xe932,0xe933,0xe934,0xe935,0xe936,0xe937,
+ 0xe938,0xe939,0xe93a,0xe93b,0xe93c,0xe93d,0xe93e,0xe93f,
+ 0xe940,0xe941,0xe942,0xe943,0xe944,0xe945,0xe946,0xe947,
+ 0xe948,0xe949,0xe94a,0xe94b,0xe94c,0xe94d,0xe94e,0xe94f,
+ 0xe950,0xe951,0xe952,0xe953,0xe954,0xe955,0xe956,0xe957,
+ 0xe958,0xe959,0xe95a,0xe95b,0xe95c,0xe95d,0xe95e,0xe95f,
+ 0xe960,0xe961,0xe962,0xe963,0xe964,0xe965,0xe966,0xe967,
+ 0xe968,0xe969,0xe96a,0xe96b,0xe96c,0xe96d,0xe96e,0xe96f,
+ 0xe970,0xe971,0xe972,0xe973,0xe974,0xe975,0xe976,0xe977,
+ 0xe978,0xe979,0xe97a,0xe97b,0xe97c,0xe97d,0xe97e,0xe97f,
+ 0xe980,0xe981,0xe982,0xe983,0xe984,0xe985,0xe986,0xe987,
+ 0xe988,0xe989,0xe98a,0xe98b,0xe98c,0xe98d,0xe98e,0xe98f,
+ 0xe990,0xe991,0xe992,0xe993,0xe994,0xe995,0xe996,0xe997,
+ 0xe998,0xe999,0xe99a,0xe99b,0xe99c,0xe99d,0xe99e,0xe99f,
+ 0xe9a0,0xe9a1,0xe9a2,0xe9a3,0xe9a4,0xe9a5,0xe9a6,0xe9a7,
+ 0xe9a8,0xe9a9,0xe9aa,0xe9ab,0xe9ac,0xe9ad,0xe9ae,0xe9af,
+ 0xe9b0,0xe9b1,0xe9b2,0xe9b3,0xe9b4,0xe9b5,0xe9b6,0xe9b7,
+ 0xe9b8,0xe9b9,0xe9ba,0xe9bb,0xe9bc,0xe9bd,0xe9be,0xe9bf,
+ 0xe9c0,0xe9c1,0xe9c2,0xe9c3,0xe9c4,0xe9c5,0xe9c6,0xe9c7,
+ 0xe9c8,0xe9c9,0xe9ca,0xe9cb,0xe9cc,0xe9cd,0xe9ce,0xe9cf,
+ 0xe9d0,0xe9d1,0xe9d2,0xe9d3,0xe9d4,0xe9d5,0xe9d6,0xe9d7,
+ 0xe9d8,0xe9d9,0xe9da,0xe9db,0xe9dc,0xe9dd,0xe9de,0xe9df,
+ 0xe9e0,0xe9e1,0xe9e2,0xe9e3,0xe9e4,0xe9e5,0xe9e6,0xe9e7,
+ 0xe9e8,0xe9e9,0xe9ea,0xe9eb,0xe9ec,0xe9ed,0xe9ee,0xe9ef,
+ 0xe9f0,0xe9f1,0xe9f2,0xe9f3,0xe9f4,0xe9f5,0xe9f6,0xe9f7,
+ 0xe9f8,0xe9f9,0xe9fa,0xe9fb,0xe9fc,0xe9fd,0xe9fe,0xe9ff,
+ 0xea00,0xea01,0xea02,0xea03,0xea04,0xea05,0xea06,0xea07,
+ 0xea08,0xea09,0xea0a,0xea0b,0xea0c,0xea0d,0xea0e,0xea0f,
+ 0xea10,0xea11,0xea12,0xea13,0xea14,0xea15,0xea16,0xea17,
+ 0xea18,0xea19,0xea1a,0xea1b,0xea1c,0xea1d,0xea1e,0xea1f,
+ 0xea20,0xea21,0xea22,0xea23,0xea24,0xea25,0xea26,0xea27,
+ 0xea28,0xea29,0xea2a,0xea2b,0xea2c,0xea2d,0xea2e,0xea2f,
+ 0xea30,0xea31,0xea32,0xea33,0xea34,0xea35,0xea36,0xea37,
+ 0xea38,0xea39,0xea3a,0xea3b,0xea3c,0xea3d,0xea3e,0xea3f,
+ 0xea40,0xea41,0xea42,0xea43,0xea44,0xea45,0xea46,0xea47,
+ 0xea48,0xea49,0xea4a,0xea4b,0xea4c,0xea4d,0xea4e,0xea4f,
+ 0xea50,0xea51,0xea52,0xea53,0xea54,0xea55,0xea56,0xea57,
+ 0xea58,0xea59,0xea5a,0xea5b,0xea5c,0xea5d,0xea5e,0xea5f,
+ 0xea60,0xea61,0xea62,0xea63,0xea64,0xea65,0xea66,0xea67,
+ 0xea68,0xea69,0xea6a,0xea6b,0xea6c,0xea6d,0xea6e,0xea6f,
+ 0xea70,0xea71,0xea72,0xea73,0xea74,0xea75,0xea76,0xea77,
+ 0xea78,0xea79,0xea7a,0xea7b,0xea7c,0xea7d,0xea7e,0xea7f,
+ 0xea80,0xea81,0xea82,0xea83,0xea84,0xea85,0xea86,0xea87,
+ 0xea88,0xea89,0xea8a,0xea8b,0xea8c,0xea8d,0xea8e,0xea8f,
+ 0xea90,0xea91,0xea92,0xea93,0xea94,0xea95,0xea96,0xea97,
+ 0xea98,0xea99,0xea9a,0xea9b,0xea9c,0xea9d,0xea9e,0xea9f,
+ 0xeaa0,0xeaa1,0xeaa2,0xeaa3,0xeaa4,0xeaa5,0xeaa6,0xeaa7,
+ 0xeaa8,0xeaa9,0xeaaa,0xeaab,0xeaac,0xeaad,0xeaae,0xeaaf,
+ 0xeab0,0xeab1,0xeab2,0xeab3,0xeab4,0xeab5,0xeab6,0xeab7,
+ 0xeab8,0xeab9,0xeaba,0xeabb,0xeabc,0xeabd,0xeabe,0xeabf,
+ 0xeac0,0xeac1,0xeac2,0xeac3,0xeac4,0xeac5,0xeac6,0xeac7,
+ 0xeac8,0xeac9,0xeaca,0xeacb,0xeacc,0xeacd,0xeace,0xeacf,
+ 0xead0,0xead1,0xead2,0xead3,0xead4,0xead5,0xead6,0xead7,
+ 0xead8,0xead9,0xeada,0xeadb,0xeadc,0xeadd,0xeade,0xeadf,
+ 0xeae0,0xeae1,0xeae2,0xeae3,0xeae4,0xeae5,0xeae6,0xeae7,
+ 0xeae8,0xeae9,0xeaea,0xeaeb,0xeaec,0xeaed,0xeaee,0xeaef,
+ 0xeaf0,0xeaf1,0xeaf2,0xeaf3,0xeaf4,0xeaf5,0xeaf6,0xeaf7,
+ 0xeaf8,0xeaf9,0xeafa,0xeafb,0xeafc,0xeafd,0xeafe,0xeaff,
+ 0xeb00,0xeb01,0xeb02,0xeb03,0xeb04,0xeb05,0xeb06,0xeb07,
+ 0xeb08,0xeb09,0xeb0a,0xeb0b,0xeb0c,0xeb0d,0xeb0e,0xeb0f,
+ 0xeb10,0xeb11,0xeb12,0xeb13,0xeb14,0xeb15,0xeb16,0xeb17,
+ 0xeb18,0xeb19,0xeb1a,0xeb1b,0xeb1c,0xeb1d,0xeb1e,0xeb1f,
+ 0xeb20,0xeb21,0xeb22,0xeb23,0xeb24,0xeb25,0xeb26,0xeb27,
+ 0xeb28,0xeb29,0xeb2a,0xeb2b,0xeb2c,0xeb2d,0xeb2e,0xeb2f,
+ 0xeb30,0xeb31,0xeb32,0xeb33,0xeb34,0xeb35,0xeb36,0xeb37,
+ 0xeb38,0xeb39,0xeb3a,0xeb3b,0xeb3c,0xeb3d,0xeb3e,0xeb3f,
+ 0xeb40,0xeb41,0xeb42,0xeb43,0xeb44,0xeb45,0xeb46,0xeb47,
+ 0xeb48,0xeb49,0xeb4a,0xeb4b,0xeb4c,0xeb4d,0xeb4e,0xeb4f,
+ 0xeb50,0xeb51,0xeb52,0xeb53,0xeb54,0xeb55,0xeb56,0xeb57,
+ 0xeb58,0xeb59,0xeb5a,0xeb5b,0xeb5c,0xeb5d,0xeb5e,0xeb5f,
+ 0xeb60,0xeb61,0xeb62,0xeb63,0xeb64,0xeb65,0xeb66,0xeb67,
+ 0xeb68,0xeb69,0xeb6a,0xeb6b,0xeb6c,0xeb6d,0xeb6e,0xeb6f,
+ 0xeb70,0xeb71,0xeb72,0xeb73,0xeb74,0xeb75,0xeb76,0xeb77,
+ 0xeb78,0xeb79,0xeb7a,0xeb7b,0xeb7c,0xeb7d,0xeb7e,0xeb7f,
+ 0xeb80,0xeb81,0xeb82,0xeb83,0xeb84,0xeb85,0xeb86,0xeb87,
+ 0xeb88,0xeb89,0xeb8a,0xeb8b,0xeb8c,0xeb8d,0xeb8e,0xeb8f,
+ 0xeb90,0xeb91,0xeb92,0xeb93,0xeb94,0xeb95,0xeb96,0xeb97,
+ 0xeb98,0xeb99,0xeb9a,0xeb9b,0xeb9c,0xeb9d,0xeb9e,0xeb9f,
+ 0xeba0,0xeba1,0xeba2,0xeba3,0xeba4,0xeba5,0xeba6,0xeba7,
+ 0xeba8,0xeba9,0xebaa,0xebab,0xebac,0xebad,0xebae,0xebaf,
+ 0xebb0,0xebb1,0xebb2,0xebb3,0xebb4,0xebb5,0xebb6,0xebb7,
+ 0xebb8,0xebb9,0xebba,0xebbb,0xebbc,0xebbd,0xebbe,0xebbf,
+ 0xebc0,0xebc1,0xebc2,0xebc3,0xebc4,0xebc5,0xebc6,0xebc7,
+ 0xebc8,0xebc9,0xebca,0xebcb,0xebcc,0xebcd,0xebce,0xebcf,
+ 0xebd0,0xebd1,0xebd2,0xebd3,0xebd4,0xebd5,0xebd6,0xebd7,
+ 0xebd8,0xebd9,0xebda,0xebdb,0xebdc,0xebdd,0xebde,0xebdf,
+ 0xebe0,0xebe1,0xebe2,0xebe3,0xebe4,0xebe5,0xebe6,0xebe7,
+ 0xebe8,0xebe9,0xebea,0xebeb,0xebec,0xebed,0xebee,0xebef,
+ 0xebf0,0xebf1,0xebf2,0xebf3,0xebf4,0xebf5,0xebf6,0xebf7,
+ 0xebf8,0xebf9,0xebfa,0xebfb,0xebfc,0xebfd,0xebfe,0xebff,
+ 0xec00,0xec01,0xec02,0xec03,0xec04,0xec05,0xec06,0xec07,
+ 0xec08,0xec09,0xec0a,0xec0b,0xec0c,0xec0d,0xec0e,0xec0f,
+ 0xec10,0xec11,0xec12,0xec13,0xec14,0xec15,0xec16,0xec17,
+ 0xec18,0xec19,0xec1a,0xec1b,0xec1c,0xec1d,0xec1e,0xec1f,
+ 0xec20,0xec21,0xec22,0xec23,0xec24,0xec25,0xec26,0xec27,
+ 0xec28,0xec29,0xec2a,0xec2b,0xec2c,0xec2d,0xec2e,0xec2f,
+ 0xec30,0xec31,0xec32,0xec33,0xec34,0xec35,0xec36,0xec37,
+ 0xec38,0xec39,0xec3a,0xec3b,0xec3c,0xec3d,0xec3e,0xec3f,
+ 0xec40,0xec41,0xec42,0xec43,0xec44,0xec45,0xec46,0xec47,
+ 0xec48,0xec49,0xec4a,0xec4b,0xec4c,0xec4d,0xec4e,0xec4f,
+ 0xec50,0xec51,0xec52,0xec53,0xec54,0xec55,0xec56,0xec57,
+ 0xec58,0xec59,0xec5a,0xec5b,0xec5c,0xec5d,0xec5e,0xec5f,
+ 0xec60,0xec61,0xec62,0xec63,0xec64,0xec65,0xec66,0xec67,
+ 0xec68,0xec69,0xec6a,0xec6b,0xec6c,0xec6d,0xec6e,0xec6f,
+ 0xec70,0xec71,0xec72,0xec73,0xec74,0xec75,0xec76,0xec77,
+ 0xec78,0xec79,0xec7a,0xec7b,0xec7c,0xec7d,0xec7e,0xec7f,
+ 0xec80,0xec81,0xec82,0xec83,0xec84,0xec85,0xec86,0xec87,
+ 0xec88,0xec89,0xec8a,0xec8b,0xec8c,0xec8d,0xec8e,0xec8f,
+ 0xec90,0xec91,0xec92,0xec93,0xec94,0xec95,0xec96,0xec97,
+ 0xec98,0xec99,0xec9a,0xec9b,0xec9c,0xec9d,0xec9e,0xec9f,
+ 0xeca0,0xeca1,0xeca2,0xeca3,0xeca4,0xeca5,0xeca6,0xeca7,
+ 0xeca8,0xeca9,0xecaa,0xecab,0xecac,0xecad,0xecae,0xecaf,
+ 0xecb0,0xecb1,0xecb2,0xecb3,0xecb4,0xecb5,0xecb6,0xecb7,
+ 0xecb8,0xecb9,0xecba,0xecbb,0xecbc,0xecbd,0xecbe,0xecbf,
+ 0xecc0,0xecc1,0xecc2,0xecc3,0xecc4,0xecc5,0xecc6,0xecc7,
+ 0xecc8,0xecc9,0xecca,0xeccb,0xeccc,0xeccd,0xecce,0xeccf,
+ 0xecd0,0xecd1,0xecd2,0xecd3,0xecd4,0xecd5,0xecd6,0xecd7,
+ 0xecd8,0xecd9,0xecda,0xecdb,0xecdc,0xecdd,0xecde,0xecdf,
+ 0xece0,0xece1,0xece2,0xece3,0xece4,0xece5,0xece6,0xece7,
+ 0xece8,0xece9,0xecea,0xeceb,0xecec,0xeced,0xecee,0xecef,
+ 0xecf0,0xecf1,0xecf2,0xecf3,0xecf4,0xecf5,0xecf6,0xecf7,
+ 0xecf8,0xecf9,0xecfa,0xecfb,0xecfc,0xecfd,0xecfe,0xecff,
+ 0xed00,0xed01,0xed02,0xed03,0xed04,0xed05,0xed06,0xed07,
+ 0xed08,0xed09,0xed0a,0xed0b,0xed0c,0xed0d,0xed0e,0xed0f,
+ 0xed10,0xed11,0xed12,0xed13,0xed14,0xed15,0xed16,0xed17,
+ 0xed18,0xed19,0xed1a,0xed1b,0xed1c,0xed1d,0xed1e,0xed1f,
+ 0xed20,0xed21,0xed22,0xed23,0xed24,0xed25,0xed26,0xed27,
+ 0xed28,0xed29,0xed2a,0xed2b,0xed2c,0xed2d,0xed2e,0xed2f,
+ 0xed30,0xed31,0xed32,0xed33,0xed34,0xed35,0xed36,0xed37,
+ 0xed38,0xed39,0xed3a,0xed3b,0xed3c,0xed3d,0xed3e,0xed3f,
+ 0xed40,0xed41,0xed42,0xed43,0xed44,0xed45,0xed46,0xed47,
+ 0xed48,0xed49,0xed4a,0xed4b,0xed4c,0xed4d,0xed4e,0xed4f,
+ 0xed50,0xed51,0xed52,0xed53,0xed54,0xed55,0xed56,0xed57,
+ 0xed58,0xed59,0xed5a,0xed5b,0xed5c,0xed5d,0xed5e,0xed5f,
+ 0xed60,0xed61,0xed62,0xed63,0xed64,0xed65,0xed66,0xed67,
+ 0xed68,0xed69,0xed6a,0xed6b,0xed6c,0xed6d,0xed6e,0xed6f,
+ 0xed70,0xed71,0xed72,0xed73,0xed74,0xed75,0xed76,0xed77,
+ 0xed78,0xed79,0xed7a,0xed7b,0xed7c,0xed7d,0xed7e,0xed7f,
+ 0xed80,0xed81,0xed82,0xed83,0xed84,0xed85,0xed86,0xed87,
+ 0xed88,0xed89,0xed8a,0xed8b,0xed8c,0xed8d,0xed8e,0xed8f,
+ 0xed90,0xed91,0xed92,0xed93,0xed94,0xed95,0xed96,0xed97,
+ 0xed98,0xed99,0xed9a,0xed9b,0xed9c,0xed9d,0xed9e,0xed9f,
+ 0xeda0,0xeda1,0xeda2,0xeda3,0xeda4,0xeda5,0xeda6,0xeda7,
+ 0xeda8,0xeda9,0xedaa,0xedab,0xedac,0xedad,0xedae,0xedaf,
+ 0xedb0,0xedb1,0xedb2,0xedb3,0xedb4,0xedb5,0xedb6,0xedb7,
+ 0xedb8,0xedb9,0xedba,0xedbb,0xedbc,0xedbd,0xedbe,0xedbf,
+ 0xedc0,0xedc1,0xedc2,0xedc3,0xedc4,0xedc5,0xedc6,0xedc7,
+ 0xedc8,0xedc9,0xedca,0xedcb,0xedcc,0xedcd,0xedce,0xedcf,
+ 0xedd0,0xedd1,0xedd2,0xedd3,0xedd4,0xedd5,0xedd6,0xedd7,
+ 0xedd8,0xedd9,0xedda,0xeddb,0xeddc,0xeddd,0xedde,0xeddf,
+ 0xede0,0xede1,0xede2,0xede3,0xede4,0xede5,0xede6,0xede7,
+ 0xede8,0xede9,0xedea,0xedeb,0xedec,0xeded,0xedee,0xedef,
+ 0xedf0,0xedf1,0xedf2,0xedf3,0xedf4,0xedf5,0xedf6,0xedf7,
+ 0xedf8,0xedf9,0xedfa,0xedfb,0xedfc,0xedfd,0xedfe,0xedff,
+ 0xee00,0xee01,0xee02,0xee03,0xee04,0xee05,0xee06,0xee07,
+ 0xee08,0xee09,0xee0a,0xee0b,0xee0c,0xee0d,0xee0e,0xee0f,
+ 0xee10,0xee11,0xee12,0xee13,0xee14,0xee15,0xee16,0xee17,
+ 0xee18,0xee19,0xee1a,0xee1b,0xee1c,0xee1d,0xee1e,0xee1f,
+ 0xee20,0xee21,0xee22,0xee23,0xee24,0xee25,0xee26,0xee27,
+ 0xee28,0xee29,0xee2a,0xee2b,0xee2c,0xee2d,0xee2e,0xee2f,
+ 0xee30,0xee31,0xee32,0xee33,0xee34,0xee35,0xee36,0xee37,
+ 0xee38,0xee39,0xee3a,0xee3b,0xee3c,0xee3d,0xee3e,0xee3f,
+ 0xee40,0xee41,0xee42,0xee43,0xee44,0xee45,0xee46,0xee47,
+ 0xee48,0xee49,0xee4a,0xee4b,0xee4c,0xee4d,0xee4e,0xee4f,
+ 0xee50,0xee51,0xee52,0xee53,0xee54,0xee55,0xee56,0xee57,
+ 0xee58,0xee59,0xee5a,0xee5b,0xee5c,0xee5d,0xee5e,0xee5f,
+ 0xee60,0xee61,0xee62,0xee63,0xee64,0xee65,0xee66,0xee67,
+ 0xee68,0xee69,0xee6a,0xee6b,0xee6c,0xee6d,0xee6e,0xee6f,
+ 0xee70,0xee71,0xee72,0xee73,0xee74,0xee75,0xee76,0xee77,
+ 0xee78,0xee79,0xee7a,0xee7b,0xee7c,0xee7d,0xee7e,0xee7f,
+ 0xee80,0xee81,0xee82,0xee83,0xee84,0xee85,0xee86,0xee87,
+ 0xee88,0xee89,0xee8a,0xee8b,0xee8c,0xee8d,0xee8e,0xee8f,
+ 0xee90,0xee91,0xee92,0xee93,0xee94,0xee95,0xee96,0xee97,
+ 0xee98,0xee99,0xee9a,0xee9b,0xee9c,0xee9d,0xee9e,0xee9f,
+ 0xeea0,0xeea1,0xeea2,0xeea3,0xeea4,0xeea5,0xeea6,0xeea7,
+ 0xeea8,0xeea9,0xeeaa,0xeeab,0xeeac,0xeead,0xeeae,0xeeaf,
+ 0xeeb0,0xeeb1,0xeeb2,0xeeb3,0xeeb4,0xeeb5,0xeeb6,0xeeb7,
+ 0xeeb8,0xeeb9,0xeeba,0xeebb,0xeebc,0xeebd,0xeebe,0xeebf,
+ 0xeec0,0xeec1,0xeec2,0xeec3,0xeec4,0xeec5,0xeec6,0xeec7,
+ 0xeec8,0xeec9,0xeeca,0xeecb,0xeecc,0xeecd,0xeece,0xeecf,
+ 0xeed0,0xeed1,0xeed2,0xeed3,0xeed4,0xeed5,0xeed6,0xeed7,
+ 0xeed8,0xeed9,0xeeda,0xeedb,0xeedc,0xeedd,0xeede,0xeedf,
+ 0xeee0,0xeee1,0xeee2,0xeee3,0xeee4,0xeee5,0xeee6,0xeee7,
+ 0xeee8,0xeee9,0xeeea,0xeeeb,0xeeec,0xeeed,0xeeee,0xeeef,
+ 0xeef0,0xeef1,0xeef2,0xeef3,0xeef4,0xeef5,0xeef6,0xeef7,
+ 0xeef8,0xeef9,0xeefa,0xeefb,0xeefc,0xeefd,0xeefe,0xeeff,
+ 0xef00,0xef01,0xef02,0xef03,0xef04,0xef05,0xef06,0xef07,
+ 0xef08,0xef09,0xef0a,0xef0b,0xef0c,0xef0d,0xef0e,0xef0f,
+ 0xef10,0xef11,0xef12,0xef13,0xef14,0xef15,0xef16,0xef17,
+ 0xef18,0xef19,0xef1a,0xef1b,0xef1c,0xef1d,0xef1e,0xef1f,
+ 0xef20,0xef21,0xef22,0xef23,0xef24,0xef25,0xef26,0xef27,
+ 0xef28,0xef29,0xef2a,0xef2b,0xef2c,0xef2d,0xef2e,0xef2f,
+ 0xef30,0xef31,0xef32,0xef33,0xef34,0xef35,0xef36,0xef37,
+ 0xef38,0xef39,0xef3a,0xef3b,0xef3c,0xef3d,0xef3e,0xef3f,
+ 0xef40,0xef41,0xef42,0xef43,0xef44,0xef45,0xef46,0xef47,
+ 0xef48,0xef49,0xef4a,0xef4b,0xef4c,0xef4d,0xef4e,0xef4f,
+ 0xef50,0xef51,0xef52,0xef53,0xef54,0xef55,0xef56,0xef57,
+ 0xef58,0xef59,0xef5a,0xef5b,0xef5c,0xef5d,0xef5e,0xef5f,
+ 0xef60,0xef61,0xef62,0xef63,0xef64,0xef65,0xef66,0xef67,
+ 0xef68,0xef69,0xef6a,0xef6b,0xef6c,0xef6d,0xef6e,0xef6f,
+ 0xef70,0xef71,0xef72,0xef73,0xef74,0xef75,0xef76,0xef77,
+ 0xef78,0xef79,0xef7a,0xef7b,0xef7c,0xef7d,0xef7e,0xef7f,
+ 0xef80,0xef81,0xef82,0xef83,0xef84,0xef85,0xef86,0xef87,
+ 0xef88,0xef89,0xef8a,0xef8b,0xef8c,0xef8d,0xef8e,0xef8f,
+ 0xef90,0xef91,0xef92,0xef93,0xef94,0xef95,0xef96,0xef97,
+ 0xef98,0xef99,0xef9a,0xef9b,0xef9c,0xef9d,0xef9e,0xef9f,
+ 0xefa0,0xefa1,0xefa2,0xefa3,0xefa4,0xefa5,0xefa6,0xefa7,
+ 0xefa8,0xefa9,0xefaa,0xefab,0xefac,0xefad,0xefae,0xefaf,
+ 0xefb0,0xefb1,0xefb2,0xefb3,0xefb4,0xefb5,0xefb6,0xefb7,
+ 0xefb8,0xefb9,0xefba,0xefbb,0xefbc,0xefbd,0xefbe,0xefbf,
+ 0xefc0,0xefc1,0xefc2,0xefc3,0xefc4,0xefc5,0xefc6,0xefc7,
+ 0xefc8,0xefc9,0xefca,0xefcb,0xefcc,0xefcd,0xefce,0xefcf,
+ 0xefd0,0xefd1,0xefd2,0xefd3,0xefd4,0xefd5,0xefd6,0xefd7,
+ 0xefd8,0xefd9,0xefda,0xefdb,0xefdc,0xefdd,0xefde,0xefdf,
+ 0xefe0,0xefe1,0xefe2,0xefe3,0xefe4,0xefe5,0xefe6,0xefe7,
+ 0xefe8,0xefe9,0xefea,0xefeb,0xefec,0xefed,0xefee,0xefef,
+ 0xeff0,0xeff1,0xeff2,0xeff3,0xeff4,0xeff5,0xeff6,0xeff7,
+ 0xeff8,0xeff9,0xeffa,0xeffb,0xeffc,0xeffd,0xeffe,0xefff,
+ 0xf000,0xf001,0xf002,0xf003,0xf004,0xf005,0xf006,0xf007,
+ 0xf008,0xf009,0xf00a,0xf00b,0xf00c,0xf00d,0xf00e,0xf00f,
+ 0xf010,0xf011,0xf012,0xf013,0xf014,0xf015,0xf016,0xf017,
+ 0xf018,0xf019,0xf01a,0xf01b,0xf01c,0xf01d,0xf01e,0xf01f,
+ 0xf020,0xf021,0xf022,0xf023,0xf024,0xf025,0xf026,0xf027,
+ 0xf028,0xf029,0xf02a,0xf02b,0xf02c,0xf02d,0xf02e,0xf02f,
+ 0xf030,0xf031,0xf032,0xf033,0xf034,0xf035,0xf036,0xf037,
+ 0xf038,0xf039,0xf03a,0xf03b,0xf03c,0xf03d,0xf03e,0xf03f,
+ 0xf040,0xf041,0xf042,0xf043,0xf044,0xf045,0xf046,0xf047,
+ 0xf048,0xf049,0xf04a,0xf04b,0xf04c,0xf04d,0xf04e,0xf04f,
+ 0xf050,0xf051,0xf052,0xf053,0xf054,0xf055,0xf056,0xf057,
+ 0xf058,0xf059,0xf05a,0xf05b,0xf05c,0xf05d,0xf05e,0xf05f,
+ 0xf060,0xf061,0xf062,0xf063,0xf064,0xf065,0xf066,0xf067,
+ 0xf068,0xf069,0xf06a,0xf06b,0xf06c,0xf06d,0xf06e,0xf06f,
+ 0xf070,0xf071,0xf072,0xf073,0xf074,0xf075,0xf076,0xf077,
+ 0xf078,0xf079,0xf07a,0xf07b,0xf07c,0xf07d,0xf07e,0xf07f,
+ 0xf080,0xf081,0xf082,0xf083,0xf084,0xf085,0xf086,0xf087,
+ 0xf088,0xf089,0xf08a,0xf08b,0xf08c,0xf08d,0xf08e,0xf08f,
+ 0xf090,0xf091,0xf092,0xf093,0xf094,0xf095,0xf096,0xf097,
+ 0xf098,0xf099,0xf09a,0xf09b,0xf09c,0xf09d,0xf09e,0xf09f,
+ 0xf0a0,0xf0a1,0xf0a2,0xf0a3,0xf0a4,0xf0a5,0xf0a6,0xf0a7,
+ 0xf0a8,0xf0a9,0xf0aa,0xf0ab,0xf0ac,0xf0ad,0xf0ae,0xf0af,
+ 0xf0b0,0xf0b1,0xf0b2,0xf0b3,0xf0b4,0xf0b5,0xf0b6,0xf0b7,
+ 0xf0b8,0xf0b9,0xf0ba,0xf0bb,0xf0bc,0xf0bd,0xf0be,0xf0bf,
+ 0xf0c0,0xf0c1,0xf0c2,0xf0c3,0xf0c4,0xf0c5,0xf0c6,0xf0c7,
+ 0xf0c8,0xf0c9,0xf0ca,0xf0cb,0xf0cc,0xf0cd,0xf0ce,0xf0cf,
+ 0xf0d0,0xf0d1,0xf0d2,0xf0d3,0xf0d4,0xf0d5,0xf0d6,0xf0d7,
+ 0xf0d8,0xf0d9,0xf0da,0xf0db,0xf0dc,0xf0dd,0xf0de,0xf0df,
+ 0xf0e0,0xf0e1,0xf0e2,0xf0e3,0xf0e4,0xf0e5,0xf0e6,0xf0e7,
+ 0xf0e8,0xf0e9,0xf0ea,0xf0eb,0xf0ec,0xf0ed,0xf0ee,0xf0ef,
+ 0xf0f0,0xf0f1,0xf0f2,0xf0f3,0xf0f4,0xf0f5,0xf0f6,0xf0f7,
+ 0xf0f8,0xf0f9,0xf0fa,0xf0fb,0xf0fc,0xf0fd,0xf0fe,0xf0ff,
+ 0xf100,0xf101,0xf102,0xf103,0xf104,0xf105,0xf106,0xf107,
+ 0xf108,0xf109,0xf10a,0xf10b,0xf10c,0xf10d,0xf10e,0xf10f,
+ 0xf110,0xf111,0xf112,0xf113,0xf114,0xf115,0xf116,0xf117,
+ 0xf118,0xf119,0xf11a,0xf11b,0xf11c,0xf11d,0xf11e,0xf11f,
+ 0xf120,0xf121,0xf122,0xf123,0xf124,0xf125,0xf126,0xf127,
+ 0xf128,0xf129,0xf12a,0xf12b,0xf12c,0xf12d,0xf12e,0xf12f,
+ 0xf130,0xf131,0xf132,0xf133,0xf134,0xf135,0xf136,0xf137,
+ 0xf138,0xf139,0xf13a,0xf13b,0xf13c,0xf13d,0xf13e,0xf13f,
+ 0xf140,0xf141,0xf142,0xf143,0xf144,0xf145,0xf146,0xf147,
+ 0xf148,0xf149,0xf14a,0xf14b,0xf14c,0xf14d,0xf14e,0xf14f,
+ 0xf150,0xf151,0xf152,0xf153,0xf154,0xf155,0xf156,0xf157,
+ 0xf158,0xf159,0xf15a,0xf15b,0xf15c,0xf15d,0xf15e,0xf15f,
+ 0xf160,0xf161,0xf162,0xf163,0xf164,0xf165,0xf166,0xf167,
+ 0xf168,0xf169,0xf16a,0xf16b,0xf16c,0xf16d,0xf16e,0xf16f,
+ 0xf170,0xf171,0xf172,0xf173,0xf174,0xf175,0xf176,0xf177,
+ 0xf178,0xf179,0xf17a,0xf17b,0xf17c,0xf17d,0xf17e,0xf17f,
+ 0xf180,0xf181,0xf182,0xf183,0xf184,0xf185,0xf186,0xf187,
+ 0xf188,0xf189,0xf18a,0xf18b,0xf18c,0xf18d,0xf18e,0xf18f,
+ 0xf190,0xf191,0xf192,0xf193,0xf194,0xf195,0xf196,0xf197,
+ 0xf198,0xf199,0xf19a,0xf19b,0xf19c,0xf19d,0xf19e,0xf19f,
+ 0xf1a0,0xf1a1,0xf1a2,0xf1a3,0xf1a4,0xf1a5,0xf1a6,0xf1a7,
+ 0xf1a8,0xf1a9,0xf1aa,0xf1ab,0xf1ac,0xf1ad,0xf1ae,0xf1af,
+ 0xf1b0,0xf1b1,0xf1b2,0xf1b3,0xf1b4,0xf1b5,0xf1b6,0xf1b7,
+ 0xf1b8,0xf1b9,0xf1ba,0xf1bb,0xf1bc,0xf1bd,0xf1be,0xf1bf,
+ 0xf1c0,0xf1c1,0xf1c2,0xf1c3,0xf1c4,0xf1c5,0xf1c6,0xf1c7,
+ 0xf1c8,0xf1c9,0xf1ca,0xf1cb,0xf1cc,0xf1cd,0xf1ce,0xf1cf,
+ 0xf1d0,0xf1d1,0xf1d2,0xf1d3,0xf1d4,0xf1d5,0xf1d6,0xf1d7,
+ 0xf1d8,0xf1d9,0xf1da,0xf1db,0xf1dc,0xf1dd,0xf1de,0xf1df,
+ 0xf1e0,0xf1e1,0xf1e2,0xf1e3,0xf1e4,0xf1e5,0xf1e6,0xf1e7,
+ 0xf1e8,0xf1e9,0xf1ea,0xf1eb,0xf1ec,0xf1ed,0xf1ee,0xf1ef,
+ 0xf1f0,0xf1f1,0xf1f2,0xf1f3,0xf1f4,0xf1f5,0xf1f6,0xf1f7,
+ 0xf1f8,0xf1f9,0xf1fa,0xf1fb,0xf1fc,0xf1fd,0xf1fe,0xf1ff,
+ 0xf200,0xf201,0xf202,0xf203,0xf204,0xf205,0xf206,0xf207,
+ 0xf208,0xf209,0xf20a,0xf20b,0xf20c,0xf20d,0xf20e,0xf20f,
+ 0xf210,0xf211,0xf212,0xf213,0xf214,0xf215,0xf216,0xf217,
+ 0xf218,0xf219,0xf21a,0xf21b,0xf21c,0xf21d,0xf21e,0xf21f,
+ 0xf220,0xf221,0xf222,0xf223,0xf224,0xf225,0xf226,0xf227,
+ 0xf228,0xf229,0xf22a,0xf22b,0xf22c,0xf22d,0xf22e,0xf22f,
+ 0xf230,0xf231,0xf232,0xf233,0xf234,0xf235,0xf236,0xf237,
+ 0xf238,0xf239,0xf23a,0xf23b,0xf23c,0xf23d,0xf23e,0xf23f,
+ 0xf240,0xf241,0xf242,0xf243,0xf244,0xf245,0xf246,0xf247,
+ 0xf248,0xf249,0xf24a,0xf24b,0xf24c,0xf24d,0xf24e,0xf24f,
+ 0xf250,0xf251,0xf252,0xf253,0xf254,0xf255,0xf256,0xf257,
+ 0xf258,0xf259,0xf25a,0xf25b,0xf25c,0xf25d,0xf25e,0xf25f,
+ 0xf260,0xf261,0xf262,0xf263,0xf264,0xf265,0xf266,0xf267,
+ 0xf268,0xf269,0xf26a,0xf26b,0xf26c,0xf26d,0xf26e,0xf26f,
+ 0xf270,0xf271,0xf272,0xf273,0xf274,0xf275,0xf276,0xf277,
+ 0xf278,0xf279,0xf27a,0xf27b,0xf27c,0xf27d,0xf27e,0xf27f,
+ 0xf280,0xf281,0xf282,0xf283,0xf284,0xf285,0xf286,0xf287,
+ 0xf288,0xf289,0xf28a,0xf28b,0xf28c,0xf28d,0xf28e,0xf28f,
+ 0xf290,0xf291,0xf292,0xf293,0xf294,0xf295,0xf296,0xf297,
+ 0xf298,0xf299,0xf29a,0xf29b,0xf29c,0xf29d,0xf29e,0xf29f,
+ 0xf2a0,0xf2a1,0xf2a2,0xf2a3,0xf2a4,0xf2a5,0xf2a6,0xf2a7,
+ 0xf2a8,0xf2a9,0xf2aa,0xf2ab,0xf2ac,0xf2ad,0xf2ae,0xf2af,
+ 0xf2b0,0xf2b1,0xf2b2,0xf2b3,0xf2b4,0xf2b5,0xf2b6,0xf2b7,
+ 0xf2b8,0xf2b9,0xf2ba,0xf2bb,0xf2bc,0xf2bd,0xf2be,0xf2bf,
+ 0xf2c0,0xf2c1,0xf2c2,0xf2c3,0xf2c4,0xf2c5,0xf2c6,0xf2c7,
+ 0xf2c8,0xf2c9,0xf2ca,0xf2cb,0xf2cc,0xf2cd,0xf2ce,0xf2cf,
+ 0xf2d0,0xf2d1,0xf2d2,0xf2d3,0xf2d4,0xf2d5,0xf2d6,0xf2d7,
+ 0xf2d8,0xf2d9,0xf2da,0xf2db,0xf2dc,0xf2dd,0xf2de,0xf2df,
+ 0xf2e0,0xf2e1,0xf2e2,0xf2e3,0xf2e4,0xf2e5,0xf2e6,0xf2e7,
+ 0xf2e8,0xf2e9,0xf2ea,0xf2eb,0xf2ec,0xf2ed,0xf2ee,0xf2ef,
+ 0xf2f0,0xf2f1,0xf2f2,0xf2f3,0xf2f4,0xf2f5,0xf2f6,0xf2f7,
+ 0xf2f8,0xf2f9,0xf2fa,0xf2fb,0xf2fc,0xf2fd,0xf2fe,0xf2ff,
+ 0xf300,0xf301,0xf302,0xf303,0xf304,0xf305,0xf306,0xf307,
+ 0xf308,0xf309,0xf30a,0xf30b,0xf30c,0xf30d,0xf30e,0xf30f,
+ 0xf310,0xf311,0xf312,0xf313,0xf314,0xf315,0xf316,0xf317,
+ 0xf318,0xf319,0xf31a,0xf31b,0xf31c,0xf31d,0xf31e,0xf31f,
+ 0xf320,0xf321,0xf322,0xf323,0xf324,0xf325,0xf326,0xf327,
+ 0xf328,0xf329,0xf32a,0xf32b,0xf32c,0xf32d,0xf32e,0xf32f,
+ 0xf330,0xf331,0xf332,0xf333,0xf334,0xf335,0xf336,0xf337,
+ 0xf338,0xf339,0xf33a,0xf33b,0xf33c,0xf33d,0xf33e,0xf33f,
+ 0xf340,0xf341,0xf342,0xf343,0xf344,0xf345,0xf346,0xf347,
+ 0xf348,0xf349,0xf34a,0xf34b,0xf34c,0xf34d,0xf34e,0xf34f,
+ 0xf350,0xf351,0xf352,0xf353,0xf354,0xf355,0xf356,0xf357,
+ 0xf358,0xf359,0xf35a,0xf35b,0xf35c,0xf35d,0xf35e,0xf35f,
+ 0xf360,0xf361,0xf362,0xf363,0xf364,0xf365,0xf366,0xf367,
+ 0xf368,0xf369,0xf36a,0xf36b,0xf36c,0xf36d,0xf36e,0xf36f,
+ 0xf370,0xf371,0xf372,0xf373,0xf374,0xf375,0xf376,0xf377,
+ 0xf378,0xf379,0xf37a,0xf37b,0xf37c,0xf37d,0xf37e,0xf37f,
+ 0xf380,0xf381,0xf382,0xf383,0xf384,0xf385,0xf386,0xf387,
+ 0xf388,0xf389,0xf38a,0xf38b,0xf38c,0xf38d,0xf38e,0xf38f,
+ 0xf390,0xf391,0xf392,0xf393,0xf394,0xf395,0xf396,0xf397,
+ 0xf398,0xf399,0xf39a,0xf39b,0xf39c,0xf39d,0xf39e,0xf39f,
+ 0xf3a0,0xf3a1,0xf3a2,0xf3a3,0xf3a4,0xf3a5,0xf3a6,0xf3a7,
+ 0xf3a8,0xf3a9,0xf3aa,0xf3ab,0xf3ac,0xf3ad,0xf3ae,0xf3af,
+ 0xf3b0,0xf3b1,0xf3b2,0xf3b3,0xf3b4,0xf3b5,0xf3b6,0xf3b7,
+ 0xf3b8,0xf3b9,0xf3ba,0xf3bb,0xf3bc,0xf3bd,0xf3be,0xf3bf,
+ 0xf3c0,0xf3c1,0xf3c2,0xf3c3,0xf3c4,0xf3c5,0xf3c6,0xf3c7,
+ 0xf3c8,0xf3c9,0xf3ca,0xf3cb,0xf3cc,0xf3cd,0xf3ce,0xf3cf,
+ 0xf3d0,0xf3d1,0xf3d2,0xf3d3,0xf3d4,0xf3d5,0xf3d6,0xf3d7,
+ 0xf3d8,0xf3d9,0xf3da,0xf3db,0xf3dc,0xf3dd,0xf3de,0xf3df,
+ 0xf3e0,0xf3e1,0xf3e2,0xf3e3,0xf3e4,0xf3e5,0xf3e6,0xf3e7,
+ 0xf3e8,0xf3e9,0xf3ea,0xf3eb,0xf3ec,0xf3ed,0xf3ee,0xf3ef,
+ 0xf3f0,0xf3f1,0xf3f2,0xf3f3,0xf3f4,0xf3f5,0xf3f6,0xf3f7,
+ 0xf3f8,0xf3f9,0xf3fa,0xf3fb,0xf3fc,0xf3fd,0xf3fe,0xf3ff,
+ 0xf400,0xf401,0xf402,0xf403,0xf404,0xf405,0xf406,0xf407,
+ 0xf408,0xf409,0xf40a,0xf40b,0xf40c,0xf40d,0xf40e,0xf40f,
+ 0xf410,0xf411,0xf412,0xf413,0xf414,0xf415,0xf416,0xf417,
+ 0xf418,0xf419,0xf41a,0xf41b,0xf41c,0xf41d,0xf41e,0xf41f,
+ 0xf420,0xf421,0xf422,0xf423,0xf424,0xf425,0xf426,0xf427,
+ 0xf428,0xf429,0xf42a,0xf42b,0xf42c,0xf42d,0xf42e,0xf42f,
+ 0xf430,0xf431,0xf432,0xf433,0xf434,0xf435,0xf436,0xf437,
+ 0xf438,0xf439,0xf43a,0xf43b,0xf43c,0xf43d,0xf43e,0xf43f,
+ 0xf440,0xf441,0xf442,0xf443,0xf444,0xf445,0xf446,0xf447,
+ 0xf448,0xf449,0xf44a,0xf44b,0xf44c,0xf44d,0xf44e,0xf44f,
+ 0xf450,0xf451,0xf452,0xf453,0xf454,0xf455,0xf456,0xf457,
+ 0xf458,0xf459,0xf45a,0xf45b,0xf45c,0xf45d,0xf45e,0xf45f,
+ 0xf460,0xf461,0xf462,0xf463,0xf464,0xf465,0xf466,0xf467,
+ 0xf468,0xf469,0xf46a,0xf46b,0xf46c,0xf46d,0xf46e,0xf46f,
+ 0xf470,0xf471,0xf472,0xf473,0xf474,0xf475,0xf476,0xf477,
+ 0xf478,0xf479,0xf47a,0xf47b,0xf47c,0xf47d,0xf47e,0xf47f,
+ 0xf480,0xf481,0xf482,0xf483,0xf484,0xf485,0xf486,0xf487,
+ 0xf488,0xf489,0xf48a,0xf48b,0xf48c,0xf48d,0xf48e,0xf48f,
+ 0xf490,0xf491,0xf492,0xf493,0xf494,0xf495,0xf496,0xf497,
+ 0xf498,0xf499,0xf49a,0xf49b,0xf49c,0xf49d,0xf49e,0xf49f,
+ 0xf4a0,0xf4a1,0xf4a2,0xf4a3,0xf4a4,0xf4a5,0xf4a6,0xf4a7,
+ 0xf4a8,0xf4a9,0xf4aa,0xf4ab,0xf4ac,0xf4ad,0xf4ae,0xf4af,
+ 0xf4b0,0xf4b1,0xf4b2,0xf4b3,0xf4b4,0xf4b5,0xf4b6,0xf4b7,
+ 0xf4b8,0xf4b9,0xf4ba,0xf4bb,0xf4bc,0xf4bd,0xf4be,0xf4bf,
+ 0xf4c0,0xf4c1,0xf4c2,0xf4c3,0xf4c4,0xf4c5,0xf4c6,0xf4c7,
+ 0xf4c8,0xf4c9,0xf4ca,0xf4cb,0xf4cc,0xf4cd,0xf4ce,0xf4cf,
+ 0xf4d0,0xf4d1,0xf4d2,0xf4d3,0xf4d4,0xf4d5,0xf4d6,0xf4d7,
+ 0xf4d8,0xf4d9,0xf4da,0xf4db,0xf4dc,0xf4dd,0xf4de,0xf4df,
+ 0xf4e0,0xf4e1,0xf4e2,0xf4e3,0xf4e4,0xf4e5,0xf4e6,0xf4e7,
+ 0xf4e8,0xf4e9,0xf4ea,0xf4eb,0xf4ec,0xf4ed,0xf4ee,0xf4ef,
+ 0xf4f0,0xf4f1,0xf4f2,0xf4f3,0xf4f4,0xf4f5,0xf4f6,0xf4f7,
+ 0xf4f8,0xf4f9,0xf4fa,0xf4fb,0xf4fc,0xf4fd,0xf4fe,0xf4ff,
+ 0xf500,0xf501,0xf502,0xf503,0xf504,0xf505,0xf506,0xf507,
+ 0xf508,0xf509,0xf50a,0xf50b,0xf50c,0xf50d,0xf50e,0xf50f,
+ 0xf510,0xf511,0xf512,0xf513,0xf514,0xf515,0xf516,0xf517,
+ 0xf518,0xf519,0xf51a,0xf51b,0xf51c,0xf51d,0xf51e,0xf51f,
+ 0xf520,0xf521,0xf522,0xf523,0xf524,0xf525,0xf526,0xf527,
+ 0xf528,0xf529,0xf52a,0xf52b,0xf52c,0xf52d,0xf52e,0xf52f,
+ 0xf530,0xf531,0xf532,0xf533,0xf534,0xf535,0xf536,0xf537,
+ 0xf538,0xf539,0xf53a,0xf53b,0xf53c,0xf53d,0xf53e,0xf53f,
+ 0xf540,0xf541,0xf542,0xf543,0xf544,0xf545,0xf546,0xf547,
+ 0xf548,0xf549,0xf54a,0xf54b,0xf54c,0xf54d,0xf54e,0xf54f,
+ 0xf550,0xf551,0xf552,0xf553,0xf554,0xf555,0xf556,0xf557,
+ 0xf558,0xf559,0xf55a,0xf55b,0xf55c,0xf55d,0xf55e,0xf55f,
+ 0xf560,0xf561,0xf562,0xf563,0xf564,0xf565,0xf566,0xf567,
+ 0xf568,0xf569,0xf56a,0xf56b,0xf56c,0xf56d,0xf56e,0xf56f,
+ 0xf570,0xf571,0xf572,0xf573,0xf574,0xf575,0xf576,0xf577,
+ 0xf578,0xf579,0xf57a,0xf57b,0xf57c,0xf57d,0xf57e,0xf57f,
+ 0xf580,0xf581,0xf582,0xf583,0xf584,0xf585,0xf586,0xf587,
+ 0xf588,0xf589,0xf58a,0xf58b,0xf58c,0xf58d,0xf58e,0xf58f,
+ 0xf590,0xf591,0xf592,0xf593,0xf594,0xf595,0xf596,0xf597,
+ 0xf598,0xf599,0xf59a,0xf59b,0xf59c,0xf59d,0xf59e,0xf59f,
+ 0xf5a0,0xf5a1,0xf5a2,0xf5a3,0xf5a4,0xf5a5,0xf5a6,0xf5a7,
+ 0xf5a8,0xf5a9,0xf5aa,0xf5ab,0xf5ac,0xf5ad,0xf5ae,0xf5af,
+ 0xf5b0,0xf5b1,0xf5b2,0xf5b3,0xf5b4,0xf5b5,0xf5b6,0xf5b7,
+ 0xf5b8,0xf5b9,0xf5ba,0xf5bb,0xf5bc,0xf5bd,0xf5be,0xf5bf,
+ 0xf5c0,0xf5c1,0xf5c2,0xf5c3,0xf5c4,0xf5c5,0xf5c6,0xf5c7,
+ 0xf5c8,0xf5c9,0xf5ca,0xf5cb,0xf5cc,0xf5cd,0xf5ce,0xf5cf,
+ 0xf5d0,0xf5d1,0xf5d2,0xf5d3,0xf5d4,0xf5d5,0xf5d6,0xf5d7,
+ 0xf5d8,0xf5d9,0xf5da,0xf5db,0xf5dc,0xf5dd,0xf5de,0xf5df,
+ 0xf5e0,0xf5e1,0xf5e2,0xf5e3,0xf5e4,0xf5e5,0xf5e6,0xf5e7,
+ 0xf5e8,0xf5e9,0xf5ea,0xf5eb,0xf5ec,0xf5ed,0xf5ee,0xf5ef,
+ 0xf5f0,0xf5f1,0xf5f2,0xf5f3,0xf5f4,0xf5f5,0xf5f6,0xf5f7,
+ 0xf5f8,0xf5f9,0xf5fa,0xf5fb,0xf5fc,0xf5fd,0xf5fe,0xf5ff,
+ 0xf600,0xf601,0xf602,0xf603,0xf604,0xf605,0xf606,0xf607,
+ 0xf608,0xf609,0xf60a,0xf60b,0xf60c,0xf60d,0xf60e,0xf60f,
+ 0xf610,0xf611,0xf612,0xf613,0xf614,0xf615,0xf616,0xf617,
+ 0xf618,0xf619,0xf61a,0xf61b,0xf61c,0xf61d,0xf61e,0xf61f,
+ 0xf620,0xf621,0xf622,0xf623,0xf624,0xf625,0xf626,0xf627,
+ 0xf628,0xf629,0xf62a,0xf62b,0xf62c,0xf62d,0xf62e,0xf62f,
+ 0xf630,0xf631,0xf632,0xf633,0xf634,0xf635,0xf636,0xf637,
+ 0xf638,0xf639,0xf63a,0xf63b,0xf63c,0xf63d,0xf63e,0xf63f,
+ 0xf640,0xf641,0xf642,0xf643,0xf644,0xf645,0xf646,0xf647,
+ 0xf648,0xf649,0xf64a,0xf64b,0xf64c,0xf64d,0xf64e,0xf64f,
+ 0xf650,0xf651,0xf652,0xf653,0xf654,0xf655,0xf656,0xf657,
+ 0xf658,0xf659,0xf65a,0xf65b,0xf65c,0xf65d,0xf65e,0xf65f,
+ 0xf660,0xf661,0xf662,0xf663,0xf664,0xf665,0xf666,0xf667,
+ 0xf668,0xf669,0xf66a,0xf66b,0xf66c,0xf66d,0xf66e,0xf66f,
+ 0xf670,0xf671,0xf672,0xf673,0xf674,0xf675,0xf676,0xf677,
+ 0xf678,0xf679,0xf67a,0xf67b,0xf67c,0xf67d,0xf67e,0xf67f,
+ 0xf680,0xf681,0xf682,0xf683,0xf684,0xf685,0xf686,0xf687,
+ 0xf688,0xf689,0xf68a,0xf68b,0xf68c,0xf68d,0xf68e,0xf68f,
+ 0xf690,0xf691,0xf692,0xf693,0xf694,0xf695,0xf696,0xf697,
+ 0xf698,0xf699,0xf69a,0xf69b,0xf69c,0xf69d,0xf69e,0xf69f,
+ 0xf6a0,0xf6a1,0xf6a2,0xf6a3,0xf6a4,0xf6a5,0xf6a6,0xf6a7,
+ 0xf6a8,0xf6a9,0xf6aa,0xf6ab,0xf6ac,0xf6ad,0xf6ae,0xf6af,
+ 0xf6b0,0xf6b1,0xf6b2,0xf6b3,0xf6b4,0xf6b5,0xf6b6,0xf6b7,
+ 0xf6b8,0xf6b9,0xf6ba,0xf6bb,0xf6bc,0xf6bd,0xf6be,0xf6bf,
+ 0xf6c0,0xf6c1,0xf6c2,0xf6c3,0xf6c4,0xf6c5,0xf6c6,0xf6c7,
+ 0xf6c8,0xf6c9,0xf6ca,0xf6cb,0xf6cc,0xf6cd,0xf6ce,0xf6cf,
+ 0xf6d0,0xf6d1,0xf6d2,0xf6d3,0xf6d4,0xf6d5,0xf6d6,0xf6d7,
+ 0xf6d8,0xf6d9,0xf6da,0xf6db,0xf6dc,0xf6dd,0xf6de,0xf6df,
+ 0xf6e0,0xf6e1,0xf6e2,0xf6e3,0xf6e4,0xf6e5,0xf6e6,0xf6e7,
+ 0xf6e8,0xf6e9,0xf6ea,0xf6eb,0xf6ec,0xf6ed,0xf6ee,0xf6ef,
+ 0xf6f0,0xf6f1,0xf6f2,0xf6f3,0xf6f4,0xf6f5,0xf6f6,0xf6f7,
+ 0xf6f8,0xf6f9,0xf6fa,0xf6fb,0xf6fc,0xf6fd,0xf6fe,0xf6ff,
+ 0xf700,0xf701,0xf702,0xf703,0xf704,0xf705,0xf706,0xf707,
+ 0xf708,0xf709,0xf70a,0xf70b,0xf70c,0xf70d,0xf70e,0xf70f,
+ 0xf710,0xf711,0xf712,0xf713,0xf714,0xf715,0xf716,0xf717,
+ 0xf718,0xf719,0xf71a,0xf71b,0xf71c,0xf71d,0xf71e,0xf71f,
+ 0xf720,0xf721,0xf722,0xf723,0xf724,0xf725,0xf726,0xf727,
+ 0xf728,0xf729,0xf72a,0xf72b,0xf72c,0xf72d,0xf72e,0xf72f,
+ 0xf730,0xf731,0xf732,0xf733,0xf734,0xf735,0xf736,0xf737,
+ 0xf738,0xf739,0xf73a,0xf73b,0xf73c,0xf73d,0xf73e,0xf73f,
+ 0xf740,0xf741,0xf742,0xf743,0xf744,0xf745,0xf746,0xf747,
+ 0xf748,0xf749,0xf74a,0xf74b,0xf74c,0xf74d,0xf74e,0xf74f,
+ 0xf750,0xf751,0xf752,0xf753,0xf754,0xf755,0xf756,0xf757,
+ 0xf758,0xf759,0xf75a,0xf75b,0xf75c,0xf75d,0xf75e,0xf75f,
+ 0xf760,0xf761,0xf762,0xf763,0xf764,0xf765,0xf766,0xf767,
+ 0xf768,0xf769,0xf76a,0xf76b,0xf76c,0xf76d,0xf76e,0xf76f,
+ 0xf770,0xf771,0xf772,0xf773,0xf774,0xf775,0xf776,0xf777,
+ 0xf778,0xf779,0xf77a,0xf77b,0xf77c,0xf77d,0xf77e,0xf77f,
+ 0xf780,0xf781,0xf782,0xf783,0xf784,0xf785,0xf786,0xf787,
+ 0xf788,0xf789,0xf78a,0xf78b,0xf78c,0xf78d,0xf78e,0xf78f,
+ 0xf790,0xf791,0xf792,0xf793,0xf794,0xf795,0xf796,0xf797,
+ 0xf798,0xf799,0xf79a,0xf79b,0xf79c,0xf79d,0xf79e,0xf79f,
+ 0xf7a0,0xf7a1,0xf7a2,0xf7a3,0xf7a4,0xf7a5,0xf7a6,0xf7a7,
+ 0xf7a8,0xf7a9,0xf7aa,0xf7ab,0xf7ac,0xf7ad,0xf7ae,0xf7af,
+ 0xf7b0,0xf7b1,0xf7b2,0xf7b3,0xf7b4,0xf7b5,0xf7b6,0xf7b7,
+ 0xf7b8,0xf7b9,0xf7ba,0xf7bb,0xf7bc,0xf7bd,0xf7be,0xf7bf,
+ 0xf7c0,0xf7c1,0xf7c2,0xf7c3,0xf7c4,0xf7c5,0xf7c6,0xf7c7,
+ 0xf7c8,0xf7c9,0xf7ca,0xf7cb,0xf7cc,0xf7cd,0xf7ce,0xf7cf,
+ 0xf7d0,0xf7d1,0xf7d2,0xf7d3,0xf7d4,0xf7d5,0xf7d6,0xf7d7,
+ 0xf7d8,0xf7d9,0xf7da,0xf7db,0xf7dc,0xf7dd,0xf7de,0xf7df,
+ 0xf7e0,0xf7e1,0xf7e2,0xf7e3,0xf7e4,0xf7e5,0xf7e6,0xf7e7,
+ 0xf7e8,0xf7e9,0xf7ea,0xf7eb,0xf7ec,0xf7ed,0xf7ee,0xf7ef,
+ 0xf7f0,0xf7f1,0xf7f2,0xf7f3,0xf7f4,0xf7f5,0xf7f6,0xf7f7,
+ 0xf7f8,0xf7f9,0xf7fa,0xf7fb,0xf7fc,0xf7fd,0xf7fe,0xf7ff,
+ 0xf800,0xf801,0xf802,0xf803,0xf804,0xf805,0xf806,0xf807,
+ 0xf808,0xf809,0xf80a,0xf80b,0xf80c,0xf80d,0xf80e,0xf80f,
+ 0xf810,0xf811,0xf812,0xf813,0xf814,0xf815,0xf816,0xf817,
+ 0xf818,0xf819,0xf81a,0xf81b,0xf81c,0xf81d,0xf81e,0xf81f,
+ 0xf820,0xf821,0xf822,0xf823,0xf824,0xf825,0xf826,0xf827,
+ 0xf828,0xf829,0xf82a,0xf82b,0xf82c,0xf82d,0xf82e,0xf82f,
+ 0xf830,0xf831,0xf832,0xf833,0xf834,0xf835,0xf836,0xf837,
+ 0xf838,0xf839,0xf83a,0xf83b,0xf83c,0xf83d,0xf83e,0xf83f,
+ 0xf840,0xf841,0xf842,0xf843,0xf844,0xf845,0xf846,0xf847,
+ 0xf848,0xf849,0xf84a,0xf84b,0xf84c,0xf84d,0xf84e,0xf84f,
+ 0xf850,0xf851,0xf852,0xf853,0xf854,0xf855,0xf856,0xf857,
+ 0xf858,0xf859,0xf85a,0xf85b,0xf85c,0xf85d,0xf85e,0xf85f,
+ 0xf860,0xf861,0xf862,0xf863,0xf864,0xf865,0xf866,0xf867,
+ 0xf868,0xf869,0xf86a,0xf86b,0xf86c,0xf86d,0xf86e,0xf86f,
+ 0xf870,0xf871,0xf872,0xf873,0xf874,0xf875,0xf876,0xf877,
+ 0xf878,0xf879,0xf87a,0xf87b,0xf87c,0xf87d,0xf87e,0xf87f,
+ 0xf880,0xf881,0xf882,0xf883,0xf884,0xf885,0xf886,0xf887,
+ 0xf888,0xf889,0xf88a,0xf88b,0xf88c,0xf88d,0xf88e,0xf88f,
+ 0xf890,0xf891,0xf892,0xf893,0xf894,0xf895,0xf896,0xf897,
+ 0xf898,0xf899,0xf89a,0xf89b,0xf89c,0xf89d,0xf89e,0xf89f,
+ 0xf8a0,0xf8a1,0xf8a2,0xf8a3,0xf8a4,0xf8a5,0xf8a6,0xf8a7,
+ 0xf8a8,0xf8a9,0xf8aa,0xf8ab,0xf8ac,0xf8ad,0xf8ae,0xf8af,
+ 0xf8b0,0xf8b1,0xf8b2,0xf8b3,0xf8b4,0xf8b5,0xf8b6,0xf8b7,
+ 0xf8b8,0xf8b9,0xf8ba,0xf8bb,0xf8bc,0xf8bd,0xf8be,0xf8bf,
+ 0xf8c0,0xf8c1,0xf8c2,0xf8c3,0xf8c4,0xf8c5,0xf8c6,0xf8c7,
+ 0xf8c8,0xf8c9,0xf8ca,0xf8cb,0xf8cc,0xf8cd,0xf8ce,0xf8cf,
+ 0xf8d0,0xf8d1,0xf8d2,0xf8d3,0xf8d4,0xf8d5,0xf8d6,0xf8d7,
+ 0xf8d8,0xf8d9,0xf8da,0xf8db,0xf8dc,0xf8dd,0xf8de,0xf8df,
+ 0xf8e0,0xf8e1,0xf8e2,0xf8e3,0xf8e4,0xf8e5,0xf8e6,0xf8e7,
+ 0xf8e8,0xf8e9,0xf8ea,0xf8eb,0xf8ec,0xf8ed,0xf8ee,0xf8ef,
+ 0xf8f0,0xf8f1,0xf8f2,0xf8f3,0xf8f4,0xf8f5,0xf8f6,0xf8f7,
+ 0xf8f8,0xf8f9,0xf8fa,0xf8fb,0xf8fc,0xf8fd,0xf8fe,0xf8ff,
+ 0xf900,0xf901,0xf902,0xf903,0xf904,0xf905,0xf906,0xf907,
+ 0xf908,0xf909,0xf90a,0xf90b,0xf90c,0xf90d,0xf90e,0xf90f,
+ 0xf910,0xf911,0xf912,0xf913,0xf914,0xf915,0xf916,0xf917,
+ 0xf918,0xf919,0xf91a,0xf91b,0xf91c,0xf91d,0xf91e,0xf91f,
+ 0xf920,0xf921,0xf922,0xf923,0xf924,0xf925,0xf926,0xf927,
+ 0xf928,0xf929,0xf92a,0xf92b,0xf92c,0xf92d,0xf92e,0xf92f,
+ 0xf930,0xf931,0xf932,0xf933,0xf934,0xf935,0xf936,0xf937,
+ 0xf938,0xf939,0xf93a,0xf93b,0xf93c,0xf93d,0xf93e,0xf93f,
+ 0xf940,0xf941,0xf942,0xf943,0xf944,0xf945,0xf946,0xf947,
+ 0xf948,0xf949,0xf94a,0xf94b,0xf94c,0xf94d,0xf94e,0xf94f,
+ 0xf950,0xf951,0xf952,0xf953,0xf954,0xf955,0xf956,0xf957,
+ 0xf958,0xf959,0xf95a,0xf95b,0xf95c,0xf95d,0xf95e,0xf95f,
+ 0xf960,0xf961,0xf962,0xf963,0xf964,0xf965,0xf966,0xf967,
+ 0xf968,0xf969,0xf96a,0xf96b,0xf96c,0xf96d,0xf96e,0xf96f,
+ 0xf970,0xf971,0xf972,0xf973,0xf974,0xf975,0xf976,0xf977,
+ 0xf978,0xf979,0xf97a,0xf97b,0xf97c,0xf97d,0xf97e,0xf97f,
+ 0xf980,0xf981,0xf982,0xf983,0xf984,0xf985,0xf986,0xf987,
+ 0xf988,0xf989,0xf98a,0xf98b,0xf98c,0xf98d,0xf98e,0xf98f,
+ 0xf990,0xf991,0xf992,0xf993,0xf994,0xf995,0xf996,0xf997,
+ 0xf998,0xf999,0xf99a,0xf99b,0xf99c,0xf99d,0xf99e,0xf99f,
+ 0xf9a0,0xf9a1,0xf9a2,0xf9a3,0xf9a4,0xf9a5,0xf9a6,0xf9a7,
+ 0xf9a8,0xf9a9,0xf9aa,0xf9ab,0xf9ac,0xf9ad,0xf9ae,0xf9af,
+ 0xf9b0,0xf9b1,0xf9b2,0xf9b3,0xf9b4,0xf9b5,0xf9b6,0xf9b7,
+ 0xf9b8,0xf9b9,0xf9ba,0xf9bb,0xf9bc,0xf9bd,0xf9be,0xf9bf,
+ 0xf9c0,0xf9c1,0xf9c2,0xf9c3,0xf9c4,0xf9c5,0xf9c6,0xf9c7,
+ 0xf9c8,0xf9c9,0xf9ca,0xf9cb,0xf9cc,0xf9cd,0xf9ce,0xf9cf,
+ 0xf9d0,0xf9d1,0xf9d2,0xf9d3,0xf9d4,0xf9d5,0xf9d6,0xf9d7,
+ 0xf9d8,0xf9d9,0xf9da,0xf9db,0xf9dc,0xf9dd,0xf9de,0xf9df,
+ 0xf9e0,0xf9e1,0xf9e2,0xf9e3,0xf9e4,0xf9e5,0xf9e6,0xf9e7,
+ 0xf9e8,0xf9e9,0xf9ea,0xf9eb,0xf9ec,0xf9ed,0xf9ee,0xf9ef,
+ 0xf9f0,0xf9f1,0xf9f2,0xf9f3,0xf9f4,0xf9f5,0xf9f6,0xf9f7,
+ 0xf9f8,0xf9f9,0xf9fa,0xf9fb,0xf9fc,0xf9fd,0xf9fe,0xf9ff,
+ 0xfa00,0xfa01,0xfa02,0xfa03,0xfa04,0xfa05,0xfa06,0xfa07,
+ 0xfa08,0xfa09,0xfa0a,0xfa0b,0xfa0c,0xfa0d,0xfa0e,0xfa0f,
+ 0xfa10,0xfa11,0xfa12,0xfa13,0xfa14,0xfa15,0xfa16,0xfa17,
+ 0xfa18,0xfa19,0xfa1a,0xfa1b,0xfa1c,0xfa1d,0xfa1e,0xfa1f,
+ 0xfa20,0xfa21,0xfa22,0xfa23,0xfa24,0xfa25,0xfa26,0xfa27,
+ 0xfa28,0xfa29,0xfa2a,0xfa2b,0xfa2c,0xfa2d,0xfa2e,0xfa2f,
+ 0xfa30,0xfa31,0xfa32,0xfa33,0xfa34,0xfa35,0xfa36,0xfa37,
+ 0xfa38,0xfa39,0xfa3a,0xfa3b,0xfa3c,0xfa3d,0xfa3e,0xfa3f,
+ 0xfa40,0xfa41,0xfa42,0xfa43,0xfa44,0xfa45,0xfa46,0xfa47,
+ 0xfa48,0xfa49,0xfa4a,0xfa4b,0xfa4c,0xfa4d,0xfa4e,0xfa4f,
+ 0xfa50,0xfa51,0xfa52,0xfa53,0xfa54,0xfa55,0xfa56,0xfa57,
+ 0xfa58,0xfa59,0xfa5a,0xfa5b,0xfa5c,0xfa5d,0xfa5e,0xfa5f,
+ 0xfa60,0xfa61,0xfa62,0xfa63,0xfa64,0xfa65,0xfa66,0xfa67,
+ 0xfa68,0xfa69,0xfa6a,0xfa6b,0xfa6c,0xfa6d,0xfa6e,0xfa6f,
+ 0xfa70,0xfa71,0xfa72,0xfa73,0xfa74,0xfa75,0xfa76,0xfa77,
+ 0xfa78,0xfa79,0xfa7a,0xfa7b,0xfa7c,0xfa7d,0xfa7e,0xfa7f,
+ 0xfa80,0xfa81,0xfa82,0xfa83,0xfa84,0xfa85,0xfa86,0xfa87,
+ 0xfa88,0xfa89,0xfa8a,0xfa8b,0xfa8c,0xfa8d,0xfa8e,0xfa8f,
+ 0xfa90,0xfa91,0xfa92,0xfa93,0xfa94,0xfa95,0xfa96,0xfa97,
+ 0xfa98,0xfa99,0xfa9a,0xfa9b,0xfa9c,0xfa9d,0xfa9e,0xfa9f,
+ 0xfaa0,0xfaa1,0xfaa2,0xfaa3,0xfaa4,0xfaa5,0xfaa6,0xfaa7,
+ 0xfaa8,0xfaa9,0xfaaa,0xfaab,0xfaac,0xfaad,0xfaae,0xfaaf,
+ 0xfab0,0xfab1,0xfab2,0xfab3,0xfab4,0xfab5,0xfab6,0xfab7,
+ 0xfab8,0xfab9,0xfaba,0xfabb,0xfabc,0xfabd,0xfabe,0xfabf,
+ 0xfac0,0xfac1,0xfac2,0xfac3,0xfac4,0xfac5,0xfac6,0xfac7,
+ 0xfac8,0xfac9,0xfaca,0xfacb,0xfacc,0xfacd,0xface,0xfacf,
+ 0xfad0,0xfad1,0xfad2,0xfad3,0xfad4,0xfad5,0xfad6,0xfad7,
+ 0xfad8,0xfad9,0xfada,0xfadb,0xfadc,0xfadd,0xfade,0xfadf,
+ 0xfae0,0xfae1,0xfae2,0xfae3,0xfae4,0xfae5,0xfae6,0xfae7,
+ 0xfae8,0xfae9,0xfaea,0xfaeb,0xfaec,0xfaed,0xfaee,0xfaef,
+ 0xfaf0,0xfaf1,0xfaf2,0xfaf3,0xfaf4,0xfaf5,0xfaf6,0xfaf7,
+ 0xfaf8,0xfaf9,0xfafa,0xfafb,0xfafc,0xfafd,0xfafe,0xfaff,
+ 0xfb00,0xfb01,0xfb02,0xfb03,0xfb04,0xfb05,0xfb06,0xfb07,
+ 0xfb08,0xfb09,0xfb0a,0xfb0b,0xfb0c,0xfb0d,0xfb0e,0xfb0f,
+ 0xfb10,0xfb11,0xfb12,0xfb13,0xfb14,0xfb15,0xfb16,0xfb17,
+ 0xfb18,0xfb19,0xfb1a,0xfb1b,0xfb1c,0xfb1d,0xfb1e,0xfb1f,
+ 0xfb20,0xfb21,0xfb22,0xfb23,0xfb24,0xfb25,0xfb26,0xfb27,
+ 0xfb28,0xfb29,0xfb2a,0xfb2b,0xfb2c,0xfb2d,0xfb2e,0xfb2f,
+ 0xfb30,0xfb31,0xfb32,0xfb33,0xfb34,0xfb35,0xfb36,0xfb37,
+ 0xfb38,0xfb39,0xfb3a,0xfb3b,0xfb3c,0xfb3d,0xfb3e,0xfb3f,
+ 0xfb40,0xfb41,0xfb42,0xfb43,0xfb44,0xfb45,0xfb46,0xfb47,
+ 0xfb48,0xfb49,0xfb4a,0xfb4b,0xfb4c,0xfb4d,0xfb4e,0xfb4f,
+ 0xfb50,0xfb51,0xfb52,0xfb53,0xfb54,0xfb55,0xfb56,0xfb57,
+ 0xfb58,0xfb59,0xfb5a,0xfb5b,0xfb5c,0xfb5d,0xfb5e,0xfb5f,
+ 0xfb60,0xfb61,0xfb62,0xfb63,0xfb64,0xfb65,0xfb66,0xfb67,
+ 0xfb68,0xfb69,0xfb6a,0xfb6b,0xfb6c,0xfb6d,0xfb6e,0xfb6f,
+ 0xfb70,0xfb71,0xfb72,0xfb73,0xfb74,0xfb75,0xfb76,0xfb77,
+ 0xfb78,0xfb79,0xfb7a,0xfb7b,0xfb7c,0xfb7d,0xfb7e,0xfb7f,
+ 0xfb80,0xfb81,0xfb82,0xfb83,0xfb84,0xfb85,0xfb86,0xfb87,
+ 0xfb88,0xfb89,0xfb8a,0xfb8b,0xfb8c,0xfb8d,0xfb8e,0xfb8f,
+ 0xfb90,0xfb91,0xfb92,0xfb93,0xfb94,0xfb95,0xfb96,0xfb97,
+ 0xfb98,0xfb99,0xfb9a,0xfb9b,0xfb9c,0xfb9d,0xfb9e,0xfb9f,
+ 0xfba0,0xfba1,0xfba2,0xfba3,0xfba4,0xfba5,0xfba6,0xfba7,
+ 0xfba8,0xfba9,0xfbaa,0xfbab,0xfbac,0xfbad,0xfbae,0xfbaf,
+ 0xfbb0,0xfbb1,0xfbb2,0xfbb3,0xfbb4,0xfbb5,0xfbb6,0xfbb7,
+ 0xfbb8,0xfbb9,0xfbba,0xfbbb,0xfbbc,0xfbbd,0xfbbe,0xfbbf,
+ 0xfbc0,0xfbc1,0xfbc2,0xfbc3,0xfbc4,0xfbc5,0xfbc6,0xfbc7,
+ 0xfbc8,0xfbc9,0xfbca,0xfbcb,0xfbcc,0xfbcd,0xfbce,0xfbcf,
+ 0xfbd0,0xfbd1,0xfbd2,0xfbd3,0xfbd4,0xfbd5,0xfbd6,0xfbd7,
+ 0xfbd8,0xfbd9,0xfbda,0xfbdb,0xfbdc,0xfbdd,0xfbde,0xfbdf,
+ 0xfbe0,0xfbe1,0xfbe2,0xfbe3,0xfbe4,0xfbe5,0xfbe6,0xfbe7,
+ 0xfbe8,0xfbe9,0xfbea,0xfbeb,0xfbec,0xfbed,0xfbee,0xfbef,
+ 0xfbf0,0xfbf1,0xfbf2,0xfbf3,0xfbf4,0xfbf5,0xfbf6,0xfbf7,
+ 0xfbf8,0xfbf9,0xfbfa,0xfbfb,0xfbfc,0xfbfd,0xfbfe,0xfbff,
+ 0xfc00,0xfc01,0xfc02,0xfc03,0xfc04,0xfc05,0xfc06,0xfc07,
+ 0xfc08,0xfc09,0xfc0a,0xfc0b,0xfc0c,0xfc0d,0xfc0e,0xfc0f,
+ 0xfc10,0xfc11,0xfc12,0xfc13,0xfc14,0xfc15,0xfc16,0xfc17,
+ 0xfc18,0xfc19,0xfc1a,0xfc1b,0xfc1c,0xfc1d,0xfc1e,0xfc1f,
+ 0xfc20,0xfc21,0xfc22,0xfc23,0xfc24,0xfc25,0xfc26,0xfc27,
+ 0xfc28,0xfc29,0xfc2a,0xfc2b,0xfc2c,0xfc2d,0xfc2e,0xfc2f,
+ 0xfc30,0xfc31,0xfc32,0xfc33,0xfc34,0xfc35,0xfc36,0xfc37,
+ 0xfc38,0xfc39,0xfc3a,0xfc3b,0xfc3c,0xfc3d,0xfc3e,0xfc3f,
+ 0xfc40,0xfc41,0xfc42,0xfc43,0xfc44,0xfc45,0xfc46,0xfc47,
+ 0xfc48,0xfc49,0xfc4a,0xfc4b,0xfc4c,0xfc4d,0xfc4e,0xfc4f,
+ 0xfc50,0xfc51,0xfc52,0xfc53,0xfc54,0xfc55,0xfc56,0xfc57,
+ 0xfc58,0xfc59,0xfc5a,0xfc5b,0xfc5c,0xfc5d,0xfc5e,0xfc5f,
+ 0xfc60,0xfc61,0xfc62,0xfc63,0xfc64,0xfc65,0xfc66,0xfc67,
+ 0xfc68,0xfc69,0xfc6a,0xfc6b,0xfc6c,0xfc6d,0xfc6e,0xfc6f,
+ 0xfc70,0xfc71,0xfc72,0xfc73,0xfc74,0xfc75,0xfc76,0xfc77,
+ 0xfc78,0xfc79,0xfc7a,0xfc7b,0xfc7c,0xfc7d,0xfc7e,0xfc7f,
+ 0xfc80,0xfc81,0xfc82,0xfc83,0xfc84,0xfc85,0xfc86,0xfc87,
+ 0xfc88,0xfc89,0xfc8a,0xfc8b,0xfc8c,0xfc8d,0xfc8e,0xfc8f,
+ 0xfc90,0xfc91,0xfc92,0xfc93,0xfc94,0xfc95,0xfc96,0xfc97,
+ 0xfc98,0xfc99,0xfc9a,0xfc9b,0xfc9c,0xfc9d,0xfc9e,0xfc9f,
+ 0xfca0,0xfca1,0xfca2,0xfca3,0xfca4,0xfca5,0xfca6,0xfca7,
+ 0xfca8,0xfca9,0xfcaa,0xfcab,0xfcac,0xfcad,0xfcae,0xfcaf,
+ 0xfcb0,0xfcb1,0xfcb2,0xfcb3,0xfcb4,0xfcb5,0xfcb6,0xfcb7,
+ 0xfcb8,0xfcb9,0xfcba,0xfcbb,0xfcbc,0xfcbd,0xfcbe,0xfcbf,
+ 0xfcc0,0xfcc1,0xfcc2,0xfcc3,0xfcc4,0xfcc5,0xfcc6,0xfcc7,
+ 0xfcc8,0xfcc9,0xfcca,0xfccb,0xfccc,0xfccd,0xfcce,0xfccf,
+ 0xfcd0,0xfcd1,0xfcd2,0xfcd3,0xfcd4,0xfcd5,0xfcd6,0xfcd7,
+ 0xfcd8,0xfcd9,0xfcda,0xfcdb,0xfcdc,0xfcdd,0xfcde,0xfcdf,
+ 0xfce0,0xfce1,0xfce2,0xfce3,0xfce4,0xfce5,0xfce6,0xfce7,
+ 0xfce8,0xfce9,0xfcea,0xfceb,0xfcec,0xfced,0xfcee,0xfcef,
+ 0xfcf0,0xfcf1,0xfcf2,0xfcf3,0xfcf4,0xfcf5,0xfcf6,0xfcf7,
+ 0xfcf8,0xfcf9,0xfcfa,0xfcfb,0xfcfc,0xfcfd,0xfcfe,0xfcff,
+ 0xfd00,0xfd01,0xfd02,0xfd03,0xfd04,0xfd05,0xfd06,0xfd07,
+ 0xfd08,0xfd09,0xfd0a,0xfd0b,0xfd0c,0xfd0d,0xfd0e,0xfd0f,
+ 0xfd10,0xfd11,0xfd12,0xfd13,0xfd14,0xfd15,0xfd16,0xfd17,
+ 0xfd18,0xfd19,0xfd1a,0xfd1b,0xfd1c,0xfd1d,0xfd1e,0xfd1f,
+ 0xfd20,0xfd21,0xfd22,0xfd23,0xfd24,0xfd25,0xfd26,0xfd27,
+ 0xfd28,0xfd29,0xfd2a,0xfd2b,0xfd2c,0xfd2d,0xfd2e,0xfd2f,
+ 0xfd30,0xfd31,0xfd32,0xfd33,0xfd34,0xfd35,0xfd36,0xfd37,
+ 0xfd38,0xfd39,0xfd3a,0xfd3b,0xfd3c,0xfd3d,0xfd3e,0xfd3f,
+ 0xfd40,0xfd41,0xfd42,0xfd43,0xfd44,0xfd45,0xfd46,0xfd47,
+ 0xfd48,0xfd49,0xfd4a,0xfd4b,0xfd4c,0xfd4d,0xfd4e,0xfd4f,
+ 0xfd50,0xfd51,0xfd52,0xfd53,0xfd54,0xfd55,0xfd56,0xfd57,
+ 0xfd58,0xfd59,0xfd5a,0xfd5b,0xfd5c,0xfd5d,0xfd5e,0xfd5f,
+ 0xfd60,0xfd61,0xfd62,0xfd63,0xfd64,0xfd65,0xfd66,0xfd67,
+ 0xfd68,0xfd69,0xfd6a,0xfd6b,0xfd6c,0xfd6d,0xfd6e,0xfd6f,
+ 0xfd70,0xfd71,0xfd72,0xfd73,0xfd74,0xfd75,0xfd76,0xfd77,
+ 0xfd78,0xfd79,0xfd7a,0xfd7b,0xfd7c,0xfd7d,0xfd7e,0xfd7f,
+ 0xfd80,0xfd81,0xfd82,0xfd83,0xfd84,0xfd85,0xfd86,0xfd87,
+ 0xfd88,0xfd89,0xfd8a,0xfd8b,0xfd8c,0xfd8d,0xfd8e,0xfd8f,
+ 0xfd90,0xfd91,0xfd92,0xfd93,0xfd94,0xfd95,0xfd96,0xfd97,
+ 0xfd98,0xfd99,0xfd9a,0xfd9b,0xfd9c,0xfd9d,0xfd9e,0xfd9f,
+ 0xfda0,0xfda1,0xfda2,0xfda3,0xfda4,0xfda5,0xfda6,0xfda7,
+ 0xfda8,0xfda9,0xfdaa,0xfdab,0xfdac,0xfdad,0xfdae,0xfdaf,
+ 0xfdb0,0xfdb1,0xfdb2,0xfdb3,0xfdb4,0xfdb5,0xfdb6,0xfdb7,
+ 0xfdb8,0xfdb9,0xfdba,0xfdbb,0xfdbc,0xfdbd,0xfdbe,0xfdbf,
+ 0xfdc0,0xfdc1,0xfdc2,0xfdc3,0xfdc4,0xfdc5,0xfdc6,0xfdc7,
+ 0xfdc8,0xfdc9,0xfdca,0xfdcb,0xfdcc,0xfdcd,0xfdce,0xfdcf,
+ 0xfdd0,0xfdd1,0xfdd2,0xfdd3,0xfdd4,0xfdd5,0xfdd6,0xfdd7,
+ 0xfdd8,0xfdd9,0xfdda,0xfddb,0xfddc,0xfddd,0xfdde,0xfddf,
+ 0xfde0,0xfde1,0xfde2,0xfde3,0xfde4,0xfde5,0xfde6,0xfde7,
+ 0xfde8,0xfde9,0xfdea,0xfdeb,0xfdec,0xfded,0xfdee,0xfdef,
+ 0xfdf0,0xfdf1,0xfdf2,0xfdf3,0xfdf4,0xfdf5,0xfdf6,0xfdf7,
+ 0xfdf8,0xfdf9,0xfdfa,0xfdfb,0xfdfc,0xfdfd,0xfdfe,0xfdff,
+ 0xfe00,0xfe01,0xfe02,0xfe03,0xfe04,0xfe05,0xfe06,0xfe07,
+ 0xfe08,0xfe09,0xfe0a,0xfe0b,0xfe0c,0xfe0d,0xfe0e,0xfe0f,
+ 0xfe10,0xfe11,0xfe12,0xfe13,0xfe14,0xfe15,0xfe16,0xfe17,
+ 0xfe18,0xfe19,0xfe1a,0xfe1b,0xfe1c,0xfe1d,0xfe1e,0xfe1f,
+ 0xfe20,0xfe21,0xfe22,0xfe23,0xfe24,0xfe25,0xfe26,0xfe27,
+ 0xfe28,0xfe29,0xfe2a,0xfe2b,0xfe2c,0xfe2d,0xfe2e,0xfe2f,
+ 0xfe30,0xfe31,0xfe32,0xfe33,0xfe34,0xfe35,0xfe36,0xfe37,
+ 0xfe38,0xfe39,0xfe3a,0xfe3b,0xfe3c,0xfe3d,0xfe3e,0xfe3f,
+ 0xfe40,0xfe41,0xfe42,0xfe43,0xfe44,0xfe45,0xfe46,0xfe47,
+ 0xfe48,0xfe49,0xfe4a,0xfe4b,0xfe4c,0xfe4d,0xfe4e,0xfe4f,
+ 0xfe50,0xfe51,0xfe52,0xfe53,0xfe54,0xfe55,0xfe56,0xfe57,
+ 0xfe58,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e,0xfe5f,
+ 0xfe60,0xfe61,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0xfe67,
+ 0xfe68,0xfe69,0xfe6a,0xfe6b,0xfe6c,0xfe6d,0xfe6e,0xfe6f,
+ 0xfe70,0xfe71,0xfe72,0xfe73,0xfe74,0xfe75,0xfe76,0xfe77,
+ 0xfe78,0xfe79,0xfe7a,0xfe7b,0xfe7c,0xfe7d,0xfe7e,0xfe7f,
+ 0xfe80,0xfe81,0xfe82,0xfe83,0xfe84,0xfe85,0xfe86,0xfe87,
+ 0xfe88,0xfe89,0xfe8a,0xfe8b,0xfe8c,0xfe8d,0xfe8e,0xfe8f,
+ 0xfe90,0xfe91,0xfe92,0xfe93,0xfe94,0xfe95,0xfe96,0xfe97,
+ 0xfe98,0xfe99,0xfe9a,0xfe9b,0xfe9c,0xfe9d,0xfe9e,0xfe9f,
+ 0xfea0,0xfea1,0xfea2,0xfea3,0xfea4,0xfea5,0xfea6,0xfea7,
+ 0xfea8,0xfea9,0xfeaa,0xfeab,0xfeac,0xfead,0xfeae,0xfeaf,
+ 0xfeb0,0xfeb1,0xfeb2,0xfeb3,0xfeb4,0xfeb5,0xfeb6,0xfeb7,
+ 0xfeb8,0xfeb9,0xfeba,0xfebb,0xfebc,0xfebd,0xfebe,0xfebf,
+ 0xfec0,0xfec1,0xfec2,0xfec3,0xfec4,0xfec5,0xfec6,0xfec7,
+ 0xfec8,0xfec9,0xfeca,0xfecb,0xfecc,0xfecd,0xfece,0xfecf,
+ 0xfed0,0xfed1,0xfed2,0xfed3,0xfed4,0xfed5,0xfed6,0xfed7,
+ 0xfed8,0xfed9,0xfeda,0xfedb,0xfedc,0xfedd,0xfede,0xfedf,
+ 0xfee0,0xfee1,0xfee2,0xfee3,0xfee4,0xfee5,0xfee6,0xfee7,
+ 0xfee8,0xfee9,0xfeea,0xfeeb,0xfeec,0xfeed,0xfeee,0xfeef,
+ 0xfef0,0xfef1,0xfef2,0xfef3,0xfef4,0xfef5,0xfef6,0xfef7,
+ 0xfef8,0xfef9,0xfefa,0xfefb,0xfefc,0xfefd,0xfefe,0xfeff,
+ 0xff00,0xff01,0xff02,0xff03,0xff04,0xff05,0xff06,0xff07,
+ 0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,
+ 0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,
+ 0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,
+ 0xff20,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,
+ 0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,
+ 0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,
+ 0xff58,0xff59,0xff5a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f,
+ 0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,
+ 0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,
+ 0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,
+ 0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xff5e,0xff5f,
+ 0xff60,0xff61,0xff62,0xff63,0xff64,0xff65,0xff66,0xff67,
+ 0xff68,0xff69,0xff6a,0xff6b,0xff6c,0xff6d,0xff6e,0xff6f,
+ 0xff70,0xff71,0xff72,0xff73,0xff74,0xff75,0xff76,0xff77,
+ 0xff78,0xff79,0xff7a,0xff7b,0xff7c,0xff7d,0xff7e,0xff7f,
+ 0xff80,0xff81,0xff82,0xff83,0xff84,0xff85,0xff86,0xff87,
+ 0xff88,0xff89,0xff8a,0xff8b,0xff8c,0xff8d,0xff8e,0xff8f,
+ 0xff90,0xff91,0xff92,0xff93,0xff94,0xff95,0xff96,0xff97,
+ 0xff98,0xff99,0xff9a,0xff9b,0xff9c,0xff9d,0xff9e,0xff9f,
+ 0xffa0,0xffa1,0xffa2,0xffa3,0xffa4,0xffa5,0xffa6,0xffa7,
+ 0xffa8,0xffa9,0xffaa,0xffab,0xffac,0xffad,0xffae,0xffaf,
+ 0xffb0,0xffb1,0xffb2,0xffb3,0xffb4,0xffb5,0xffb6,0xffb7,
+ 0xffb8,0xffb9,0xffba,0xffbb,0xffbc,0xffbd,0xffbe,0xffbf,
+ 0xffc0,0xffc1,0xffc2,0xffc3,0xffc4,0xffc5,0xffc6,0xffc7,
+ 0xffc8,0xffc9,0xffca,0xffcb,0xffcc,0xffcd,0xffce,0xffcf,
+ 0xffd0,0xffd1,0xffd2,0xffd3,0xffd4,0xffd5,0xffd6,0xffd7,
+ 0xffd8,0xffd9,0xffda,0xffdb,0xffdc,0xffdd,0xffde,0xffdf,
+ 0xffe0,0xffe1,0xffe2,0xffe3,0xffe4,0xffe5,0xffe6,0xffe7,
+ 0xffe8,0xffe9,0xffea,0xffeb,0xffec,0xffed,0xffee,0xffef,
+ 0xfff0,0xfff1,0xfff2,0xfff3,0xfff4,0xfff5,0xfff6,0xfff7,
+ 0xfff8,0xfff9,0xfffa,0xfffb,0xfffc,0xfffd,0xfffe,0xffff
+};
+
+static const uint16_t upcase_table[] = {
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+ 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
+ 0x0060,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005a,0x007b,0x007c,0x007d,0x007e,0x007f,
+ 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+ 0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+ 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+ 0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+ 0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+ 0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+ 0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+ 0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+ 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+ 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+ 0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
+ 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
+ 0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+ 0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+ 0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00f7,
+ 0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x0178,
+ 0x0100,0x0100,0x0102,0x0102,0x0104,0x0104,0x0106,0x0106,
+ 0x0108,0x0108,0x010a,0x010a,0x010c,0x010c,0x010e,0x010e,
+ 0x0110,0x0110,0x0112,0x0112,0x0114,0x0114,0x0116,0x0116,
+ 0x0118,0x0118,0x011a,0x011a,0x011c,0x011c,0x011e,0x011e,
+ 0x0120,0x0120,0x0122,0x0122,0x0124,0x0124,0x0126,0x0126,
+ 0x0128,0x0128,0x012a,0x012a,0x012c,0x012c,0x012e,0x012e,
+ 0x0130,0x0131,0x0132,0x0132,0x0134,0x0134,0x0136,0x0136,
+ 0x0138,0x0139,0x0139,0x013b,0x013b,0x013d,0x013d,0x013f,
+ 0x013f,0x0141,0x0141,0x0143,0x0143,0x0145,0x0145,0x0147,
+ 0x0147,0x0149,0x014a,0x014a,0x014c,0x014c,0x014e,0x014e,
+ 0x0150,0x0150,0x0152,0x0152,0x0154,0x0154,0x0156,0x0156,
+ 0x0158,0x0158,0x015a,0x015a,0x015c,0x015c,0x015e,0x015e,
+ 0x0160,0x0160,0x0162,0x0162,0x0164,0x0164,0x0166,0x0166,
+ 0x0168,0x0168,0x016a,0x016a,0x016c,0x016c,0x016e,0x016e,
+ 0x0170,0x0170,0x0172,0x0172,0x0174,0x0174,0x0176,0x0176,
+ 0x0178,0x0179,0x0179,0x017b,0x017b,0x017d,0x017d,0x017f,
+ 0x0180,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,
+ 0x0187,0x0189,0x018a,0x018b,0x018b,0x018d,0x018e,0x018f,
+ 0x0190,0x0191,0x0191,0x0193,0x0194,0x0195,0x0196,0x0197,
+ 0x0198,0x0198,0x019a,0x019b,0x019c,0x019d,0x019e,0x019f,
+ 0x01a0,0x01a0,0x01a2,0x01a2,0x01a4,0x01a4,0x01a6,0x01a7,
+ 0x01a7,0x01a9,0x01aa,0x01ab,0x01ac,0x01ac,0x01ae,0x01af,
+ 0x01af,0x01b1,0x01b2,0x01b3,0x01b3,0x01b5,0x01b5,0x01b7,
+ 0x01b8,0x01b8,0x01ba,0x01bb,0x01bc,0x01bc,0x01be,0x01bf,
+ 0x01c0,0x01c1,0x01c2,0x01c3,0x01c4,0x01c5,0x01c4,0x01c7,
+ 0x01c8,0x01c7,0x01ca,0x01cb,0x01ca,0x01cd,0x01cd,0x01cf,
+ 0x01cf,0x01d1,0x01d1,0x01d3,0x01d3,0x01d5,0x01d5,0x01d7,
+ 0x01d7,0x01d9,0x01d9,0x01db,0x01db,0x018e,0x01de,0x01de,
+ 0x01e0,0x01e0,0x01e2,0x01e2,0x01e4,0x01e4,0x01e6,0x01e6,
+ 0x01e8,0x01e8,0x01ea,0x01ea,0x01ec,0x01ec,0x01ee,0x01ee,
+ 0x01f0,0x01f1,0x01f2,0x01f1,0x01f4,0x01f4,0x01f6,0x01f7,
+ 0x01f8,0x01f9,0x01fa,0x01fa,0x01fc,0x01fc,0x01fe,0x01fe,
+ 0x0200,0x0200,0x0202,0x0202,0x0204,0x0204,0x0206,0x0206,
+ 0x0208,0x0208,0x020a,0x020a,0x020c,0x020c,0x020e,0x020e,
+ 0x0210,0x0210,0x0212,0x0212,0x0214,0x0214,0x0216,0x0216,
+ 0x0218,0x0219,0x021a,0x021b,0x021c,0x021d,0x021e,0x021f,
+ 0x0220,0x0221,0x0222,0x0223,0x0224,0x0225,0x0226,0x0227,
+ 0x0228,0x0229,0x022a,0x022b,0x022c,0x022d,0x022e,0x022f,
+ 0x0230,0x0231,0x0232,0x0233,0x0234,0x0235,0x0236,0x0237,
+ 0x0238,0x0239,0x023a,0x023b,0x023c,0x023d,0x023e,0x023f,
+ 0x0240,0x0241,0x0242,0x0243,0x0244,0x0245,0x0246,0x0247,
+ 0x0248,0x0249,0x024a,0x024b,0x024c,0x024d,0x024e,0x024f,
+ 0x0250,0x0251,0x0252,0x0181,0x0186,0x0255,0x0189,0x018a,
+ 0x0258,0x018f,0x025a,0x0190,0x025c,0x025d,0x025e,0x025f,
+ 0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,
+ 0x0197,0x0196,0x026a,0x026b,0x026c,0x026d,0x026e,0x019c,
+ 0x0270,0x0271,0x019d,0x0273,0x0274,0x019f,0x0276,0x0277,
+ 0x0278,0x0279,0x027a,0x027b,0x027c,0x027d,0x027e,0x027f,
+ 0x0280,0x0281,0x0282,0x01a9,0x0284,0x0285,0x0286,0x0287,
+ 0x01ae,0x0289,0x01b1,0x01b2,0x028c,0x028d,0x028e,0x028f,
+ 0x0290,0x0291,0x01b7,0x0293,0x0294,0x0295,0x0296,0x0297,
+ 0x0298,0x0299,0x029a,0x029b,0x029c,0x029d,0x029e,0x029f,
+ 0x02a0,0x02a1,0x02a2,0x02a3,0x02a4,0x02a5,0x02a6,0x02a7,
+ 0x02a8,0x02a9,0x02aa,0x02ab,0x02ac,0x02ad,0x02ae,0x02af,
+ 0x02b0,0x02b1,0x02b2,0x02b3,0x02b4,0x02b5,0x02b6,0x02b7,
+ 0x02b8,0x02b9,0x02ba,0x02bb,0x02bc,0x02bd,0x02be,0x02bf,
+ 0x02c0,0x02c1,0x02c2,0x02c3,0x02c4,0x02c5,0x02c6,0x02c7,
+ 0x02c8,0x02c9,0x02ca,0x02cb,0x02cc,0x02cd,0x02ce,0x02cf,
+ 0x02d0,0x02d1,0x02d2,0x02d3,0x02d4,0x02d5,0x02d6,0x02d7,
+ 0x02d8,0x02d9,0x02da,0x02db,0x02dc,0x02dd,0x02de,0x02df,
+ 0x02e0,0x02e1,0x02e2,0x02e3,0x02e4,0x02e5,0x02e6,0x02e7,
+ 0x02e8,0x02e9,0x02ea,0x02eb,0x02ec,0x02ed,0x02ee,0x02ef,
+ 0x02f0,0x02f1,0x02f2,0x02f3,0x02f4,0x02f5,0x02f6,0x02f7,
+ 0x02f8,0x02f9,0x02fa,0x02fb,0x02fc,0x02fd,0x02fe,0x02ff,
+ 0x0300,0x0301,0x0302,0x0303,0x0304,0x0305,0x0306,0x0307,
+ 0x0308,0x0309,0x030a,0x030b,0x030c,0x030d,0x030e,0x030f,
+ 0x0310,0x0311,0x0312,0x0313,0x0314,0x0315,0x0316,0x0317,
+ 0x0318,0x0319,0x031a,0x031b,0x031c,0x031d,0x031e,0x031f,
+ 0x0320,0x0321,0x0322,0x0323,0x0324,0x0325,0x0326,0x0327,
+ 0x0328,0x0329,0x032a,0x032b,0x032c,0x032d,0x032e,0x032f,
+ 0x0330,0x0331,0x0332,0x0333,0x0334,0x0335,0x0336,0x0337,
+ 0x0338,0x0339,0x033a,0x033b,0x033c,0x033d,0x033e,0x033f,
+ 0x0340,0x0341,0x0342,0x0343,0x0344,0x0345,0x0346,0x0347,
+ 0x0348,0x0349,0x034a,0x034b,0x034c,0x034d,0x034e,0x034f,
+ 0x0350,0x0351,0x0352,0x0353,0x0354,0x0355,0x0356,0x0357,
+ 0x0358,0x0359,0x035a,0x035b,0x035c,0x035d,0x035e,0x035f,
+ 0x0360,0x0361,0x0362,0x0363,0x0364,0x0365,0x0366,0x0367,
+ 0x0368,0x0369,0x036a,0x036b,0x036c,0x036d,0x036e,0x036f,
+ 0x0370,0x0371,0x0372,0x0373,0x0374,0x0375,0x0376,0x0377,
+ 0x0378,0x0379,0x037a,0x037b,0x037c,0x037d,0x037e,0x037f,
+ 0x0380,0x0381,0x0382,0x0383,0x0384,0x0385,0x0386,0x0387,
+ 0x0388,0x0389,0x038a,0x038b,0x038c,0x038d,0x038e,0x038f,
+ 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
+ 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
+ 0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
+ 0x03a8,0x03a9,0x03aa,0x03ab,0x0386,0x0388,0x0389,0x038a,
+ 0x03b0,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
+ 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
+ 0x03a0,0x03a1,0x03a3,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
+ 0x03a8,0x03a9,0x03aa,0x03ab,0x038c,0x038e,0x038f,0x03cf,
+ 0x03d0,0x03d1,0x03d2,0x03d3,0x03d4,0x03d5,0x03d6,0x03d7,
+ 0x03d8,0x03d9,0x03da,0x03db,0x03dc,0x03dd,0x03de,0x03df,
+ 0x03e0,0x03e1,0x03e2,0x03e2,0x03e4,0x03e4,0x03e6,0x03e6,
+ 0x03e8,0x03e8,0x03ea,0x03ea,0x03ec,0x03ec,0x03ee,0x03ee,
+ 0x03f0,0x03f1,0x03f2,0x03f3,0x03f4,0x03f5,0x03f6,0x03f7,
+ 0x03f8,0x03f9,0x03fa,0x03fb,0x03fc,0x03fd,0x03fe,0x03ff,
+ 0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
+ 0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,0x040e,0x040f,
+ 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
+ 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
+ 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
+ 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+ 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
+ 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
+ 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
+ 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+ 0x0450,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
+ 0x0408,0x0409,0x040a,0x040b,0x040c,0x045d,0x040e,0x040f,
+ 0x0460,0x0460,0x0462,0x0462,0x0464,0x0464,0x0466,0x0466,
+ 0x0468,0x0468,0x046a,0x046a,0x046c,0x046c,0x046e,0x046e,
+ 0x0470,0x0470,0x0472,0x0472,0x0474,0x0474,0x0476,0x0476,
+ 0x0478,0x0478,0x047a,0x047a,0x047c,0x047c,0x047e,0x047e,
+ 0x0480,0x0480,0x0482,0x0483,0x0484,0x0485,0x0486,0x0487,
+ 0x0488,0x0489,0x048a,0x048b,0x048c,0x048d,0x048e,0x048f,
+ 0x0490,0x0490,0x0492,0x0492,0x0494,0x0494,0x0496,0x0496,
+ 0x0498,0x0498,0x049a,0x049a,0x049c,0x049c,0x049e,0x049e,
+ 0x04a0,0x04a0,0x04a2,0x04a2,0x04a4,0x04a4,0x04a6,0x04a6,
+ 0x04a8,0x04a8,0x04aa,0x04aa,0x04ac,0x04ac,0x04ae,0x04ae,
+ 0x04b0,0x04b0,0x04b2,0x04b2,0x04b4,0x04b4,0x04b6,0x04b6,
+ 0x04b8,0x04b8,0x04ba,0x04ba,0x04bc,0x04bc,0x04be,0x04be,
+ 0x04c0,0x04c1,0x04c1,0x04c3,0x04c3,0x04c5,0x04c6,0x04c7,
+ 0x04c7,0x04c9,0x04ca,0x04cb,0x04cb,0x04cd,0x04ce,0x04cf,
+ 0x04d0,0x04d0,0x04d2,0x04d2,0x04d4,0x04d4,0x04d6,0x04d6,
+ 0x04d8,0x04d8,0x04da,0x04da,0x04dc,0x04dc,0x04de,0x04de,
+ 0x04e0,0x04e0,0x04e2,0x04e2,0x04e4,0x04e4,0x04e6,0x04e6,
+ 0x04e8,0x04e8,0x04ea,0x04ea,0x04ec,0x04ed,0x04ee,0x04ee,
+ 0x04f0,0x04f0,0x04f2,0x04f2,0x04f4,0x04f4,0x04f6,0x04f7,
+ 0x04f8,0x04f8,0x04fa,0x04fb,0x04fc,0x04fd,0x04fe,0x04ff,
+ 0x0500,0x0501,0x0502,0x0503,0x0504,0x0505,0x0506,0x0507,
+ 0x0508,0x0509,0x050a,0x050b,0x050c,0x050d,0x050e,0x050f,
+ 0x0510,0x0511,0x0512,0x0513,0x0514,0x0515,0x0516,0x0517,
+ 0x0518,0x0519,0x051a,0x051b,0x051c,0x051d,0x051e,0x051f,
+ 0x0520,0x0521,0x0522,0x0523,0x0524,0x0525,0x0526,0x0527,
+ 0x0528,0x0529,0x052a,0x052b,0x052c,0x052d,0x052e,0x052f,
+ 0x0530,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537,
+ 0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f,
+ 0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547,
+ 0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f,
+ 0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0557,
+ 0x0558,0x0559,0x055a,0x055b,0x055c,0x055d,0x055e,0x055f,
+ 0x0560,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537,
+ 0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f,
+ 0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547,
+ 0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f,
+ 0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0587,
+ 0x0588,0x0589,0x058a,0x058b,0x058c,0x058d,0x058e,0x058f,
+ 0x0590,0x0591,0x0592,0x0593,0x0594,0x0595,0x0596,0x0597,
+ 0x0598,0x0599,0x059a,0x059b,0x059c,0x059d,0x059e,0x059f,
+ 0x05a0,0x05a1,0x05a2,0x05a3,0x05a4,0x05a5,0x05a6,0x05a7,
+ 0x05a8,0x05a9,0x05aa,0x05ab,0x05ac,0x05ad,0x05ae,0x05af,
+ 0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,
+ 0x05b8,0x05b9,0x05ba,0x05bb,0x05bc,0x05bd,0x05be,0x05bf,
+ 0x05c0,0x05c1,0x05c2,0x05c3,0x05c4,0x05c5,0x05c6,0x05c7,
+ 0x05c8,0x05c9,0x05ca,0x05cb,0x05cc,0x05cd,0x05ce,0x05cf,
+ 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
+ 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
+ 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
+ 0x05e8,0x05e9,0x05ea,0x05eb,0x05ec,0x05ed,0x05ee,0x05ef,
+ 0x05f0,0x05f1,0x05f2,0x05f3,0x05f4,0x05f5,0x05f6,0x05f7,
+ 0x05f8,0x05f9,0x05fa,0x05fb,0x05fc,0x05fd,0x05fe,0x05ff,
+ 0x0600,0x0601,0x0602,0x0603,0x0604,0x0605,0x0606,0x0607,
+ 0x0608,0x0609,0x060a,0x060b,0x060c,0x060d,0x060e,0x060f,
+ 0x0610,0x0611,0x0612,0x0613,0x0614,0x0615,0x0616,0x0617,
+ 0x0618,0x0619,0x061a,0x061b,0x061c,0x061d,0x061e,0x061f,
+ 0x0620,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
+ 0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
+ 0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637,
+ 0x0638,0x0639,0x063a,0x063b,0x063c,0x063d,0x063e,0x063f,
+ 0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647,
+ 0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f,
+ 0x0650,0x0651,0x0652,0x0653,0x0654,0x0655,0x0656,0x0657,
+ 0x0658,0x0659,0x065a,0x065b,0x065c,0x065d,0x065e,0x065f,
+ 0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,
+ 0x0668,0x0669,0x066a,0x066b,0x066c,0x066d,0x066e,0x066f,
+ 0x0670,0x0671,0x0672,0x0673,0x0674,0x0675,0x0676,0x0677,
+ 0x0678,0x0679,0x067a,0x067b,0x067c,0x067d,0x067e,0x067f,
+ 0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0686,0x0687,
+ 0x0688,0x0689,0x068a,0x068b,0x068c,0x068d,0x068e,0x068f,
+ 0x0690,0x0691,0x0692,0x0693,0x0694,0x0695,0x0696,0x0697,
+ 0x0698,0x0699,0x069a,0x069b,0x069c,0x069d,0x069e,0x069f,
+ 0x06a0,0x06a1,0x06a2,0x06a3,0x06a4,0x06a5,0x06a6,0x06a7,
+ 0x06a8,0x06a9,0x06aa,0x06ab,0x06ac,0x06ad,0x06ae,0x06af,
+ 0x06b0,0x06b1,0x06b2,0x06b3,0x06b4,0x06b5,0x06b6,0x06b7,
+ 0x06b8,0x06b9,0x06ba,0x06bb,0x06bc,0x06bd,0x06be,0x06bf,
+ 0x06c0,0x06c1,0x06c2,0x06c3,0x06c4,0x06c5,0x06c6,0x06c7,
+ 0x06c8,0x06c9,0x06ca,0x06cb,0x06cc,0x06cd,0x06ce,0x06cf,
+ 0x06d0,0x06d1,0x06d2,0x06d3,0x06d4,0x06d5,0x06d6,0x06d7,
+ 0x06d8,0x06d9,0x06da,0x06db,0x06dc,0x06dd,0x06de,0x06df,
+ 0x06e0,0x06e1,0x06e2,0x06e3,0x06e4,0x06e5,0x06e6,0x06e7,
+ 0x06e8,0x06e9,0x06ea,0x06eb,0x06ec,0x06ed,0x06ee,0x06ef,
+ 0x06f0,0x06f1,0x06f2,0x06f3,0x06f4,0x06f5,0x06f6,0x06f7,
+ 0x06f8,0x06f9,0x06fa,0x06fb,0x06fc,0x06fd,0x06fe,0x06ff,
+ 0x0700,0x0701,0x0702,0x0703,0x0704,0x0705,0x0706,0x0707,
+ 0x0708,0x0709,0x070a,0x070b,0x070c,0x070d,0x070e,0x070f,
+ 0x0710,0x0711,0x0712,0x0713,0x0714,0x0715,0x0716,0x0717,
+ 0x0718,0x0719,0x071a,0x071b,0x071c,0x071d,0x071e,0x071f,
+ 0x0720,0x0721,0x0722,0x0723,0x0724,0x0725,0x0726,0x0727,
+ 0x0728,0x0729,0x072a,0x072b,0x072c,0x072d,0x072e,0x072f,
+ 0x0730,0x0731,0x0732,0x0733,0x0734,0x0735,0x0736,0x0737,
+ 0x0738,0x0739,0x073a,0x073b,0x073c,0x073d,0x073e,0x073f,
+ 0x0740,0x0741,0x0742,0x0743,0x0744,0x0745,0x0746,0x0747,
+ 0x0748,0x0749,0x074a,0x074b,0x074c,0x074d,0x074e,0x074f,
+ 0x0750,0x0751,0x0752,0x0753,0x0754,0x0755,0x0756,0x0757,
+ 0x0758,0x0759,0x075a,0x075b,0x075c,0x075d,0x075e,0x075f,
+ 0x0760,0x0761,0x0762,0x0763,0x0764,0x0765,0x0766,0x0767,
+ 0x0768,0x0769,0x076a,0x076b,0x076c,0x076d,0x076e,0x076f,
+ 0x0770,0x0771,0x0772,0x0773,0x0774,0x0775,0x0776,0x0777,
+ 0x0778,0x0779,0x077a,0x077b,0x077c,0x077d,0x077e,0x077f,
+ 0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0786,0x0787,
+ 0x0788,0x0789,0x078a,0x078b,0x078c,0x078d,0x078e,0x078f,
+ 0x0790,0x0791,0x0792,0x0793,0x0794,0x0795,0x0796,0x0797,
+ 0x0798,0x0799,0x079a,0x079b,0x079c,0x079d,0x079e,0x079f,
+ 0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a6,0x07a7,
+ 0x07a8,0x07a9,0x07aa,0x07ab,0x07ac,0x07ad,0x07ae,0x07af,
+ 0x07b0,0x07b1,0x07b2,0x07b3,0x07b4,0x07b5,0x07b6,0x07b7,
+ 0x07b8,0x07b9,0x07ba,0x07bb,0x07bc,0x07bd,0x07be,0x07bf,
+ 0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7,
+ 0x07c8,0x07c9,0x07ca,0x07cb,0x07cc,0x07cd,0x07ce,0x07cf,
+ 0x07d0,0x07d1,0x07d2,0x07d3,0x07d4,0x07d5,0x07d6,0x07d7,
+ 0x07d8,0x07d9,0x07da,0x07db,0x07dc,0x07dd,0x07de,0x07df,
+ 0x07e0,0x07e1,0x07e2,0x07e3,0x07e4,0x07e5,0x07e6,0x07e7,
+ 0x07e8,0x07e9,0x07ea,0x07eb,0x07ec,0x07ed,0x07ee,0x07ef,
+ 0x07f0,0x07f1,0x07f2,0x07f3,0x07f4,0x07f5,0x07f6,0x07f7,
+ 0x07f8,0x07f9,0x07fa,0x07fb,0x07fc,0x07fd,0x07fe,0x07ff,
+ 0x0800,0x0801,0x0802,0x0803,0x0804,0x0805,0x0806,0x0807,
+ 0x0808,0x0809,0x080a,0x080b,0x080c,0x080d,0x080e,0x080f,
+ 0x0810,0x0811,0x0812,0x0813,0x0814,0x0815,0x0816,0x0817,
+ 0x0818,0x0819,0x081a,0x081b,0x081c,0x081d,0x081e,0x081f,
+ 0x0820,0x0821,0x0822,0x0823,0x0824,0x0825,0x0826,0x0827,
+ 0x0828,0x0829,0x082a,0x082b,0x082c,0x082d,0x082e,0x082f,
+ 0x0830,0x0831,0x0832,0x0833,0x0834,0x0835,0x0836,0x0837,
+ 0x0838,0x0839,0x083a,0x083b,0x083c,0x083d,0x083e,0x083f,
+ 0x0840,0x0841,0x0842,0x0843,0x0844,0x0845,0x0846,0x0847,
+ 0x0848,0x0849,0x084a,0x084b,0x084c,0x084d,0x084e,0x084f,
+ 0x0850,0x0851,0x0852,0x0853,0x0854,0x0855,0x0856,0x0857,
+ 0x0858,0x0859,0x085a,0x085b,0x085c,0x085d,0x085e,0x085f,
+ 0x0860,0x0861,0x0862,0x0863,0x0864,0x0865,0x0866,0x0867,
+ 0x0868,0x0869,0x086a,0x086b,0x086c,0x086d,0x086e,0x086f,
+ 0x0870,0x0871,0x0872,0x0873,0x0874,0x0875,0x0876,0x0877,
+ 0x0878,0x0879,0x087a,0x087b,0x087c,0x087d,0x087e,0x087f,
+ 0x0880,0x0881,0x0882,0x0883,0x0884,0x0885,0x0886,0x0887,
+ 0x0888,0x0889,0x088a,0x088b,0x088c,0x088d,0x088e,0x088f,
+ 0x0890,0x0891,0x0892,0x0893,0x0894,0x0895,0x0896,0x0897,
+ 0x0898,0x0899,0x089a,0x089b,0x089c,0x089d,0x089e,0x089f,
+ 0x08a0,0x08a1,0x08a2,0x08a3,0x08a4,0x08a5,0x08a6,0x08a7,
+ 0x08a8,0x08a9,0x08aa,0x08ab,0x08ac,0x08ad,0x08ae,0x08af,
+ 0x08b0,0x08b1,0x08b2,0x08b3,0x08b4,0x08b5,0x08b6,0x08b7,
+ 0x08b8,0x08b9,0x08ba,0x08bb,0x08bc,0x08bd,0x08be,0x08bf,
+ 0x08c0,0x08c1,0x08c2,0x08c3,0x08c4,0x08c5,0x08c6,0x08c7,
+ 0x08c8,0x08c9,0x08ca,0x08cb,0x08cc,0x08cd,0x08ce,0x08cf,
+ 0x08d0,0x08d1,0x08d2,0x08d3,0x08d4,0x08d5,0x08d6,0x08d7,
+ 0x08d8,0x08d9,0x08da,0x08db,0x08dc,0x08dd,0x08de,0x08df,
+ 0x08e0,0x08e1,0x08e2,0x08e3,0x08e4,0x08e5,0x08e6,0x08e7,
+ 0x08e8,0x08e9,0x08ea,0x08eb,0x08ec,0x08ed,0x08ee,0x08ef,
+ 0x08f0,0x08f1,0x08f2,0x08f3,0x08f4,0x08f5,0x08f6,0x08f7,
+ 0x08f8,0x08f9,0x08fa,0x08fb,0x08fc,0x08fd,0x08fe,0x08ff,
+ 0x0900,0x0901,0x0902,0x0903,0x0904,0x0905,0x0906,0x0907,
+ 0x0908,0x0909,0x090a,0x090b,0x090c,0x090d,0x090e,0x090f,
+ 0x0910,0x0911,0x0912,0x0913,0x0914,0x0915,0x0916,0x0917,
+ 0x0918,0x0919,0x091a,0x091b,0x091c,0x091d,0x091e,0x091f,
+ 0x0920,0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927,
+ 0x0928,0x0929,0x092a,0x092b,0x092c,0x092d,0x092e,0x092f,
+ 0x0930,0x0931,0x0932,0x0933,0x0934,0x0935,0x0936,0x0937,
+ 0x0938,0x0939,0x093a,0x093b,0x093c,0x093d,0x093e,0x093f,
+ 0x0940,0x0941,0x0942,0x0943,0x0944,0x0945,0x0946,0x0947,
+ 0x0948,0x0949,0x094a,0x094b,0x094c,0x094d,0x094e,0x094f,
+ 0x0950,0x0951,0x0952,0x0953,0x0954,0x0955,0x0956,0x0957,
+ 0x0958,0x0959,0x095a,0x095b,0x095c,0x095d,0x095e,0x095f,
+ 0x0960,0x0961,0x0962,0x0963,0x0964,0x0965,0x0966,0x0967,
+ 0x0968,0x0969,0x096a,0x096b,0x096c,0x096d,0x096e,0x096f,
+ 0x0970,0x0971,0x0972,0x0973,0x0974,0x0975,0x0976,0x0977,
+ 0x0978,0x0979,0x097a,0x097b,0x097c,0x097d,0x097e,0x097f,
+ 0x0980,0x0981,0x0982,0x0983,0x0984,0x0985,0x0986,0x0987,
+ 0x0988,0x0989,0x098a,0x098b,0x098c,0x098d,0x098e,0x098f,
+ 0x0990,0x0991,0x0992,0x0993,0x0994,0x0995,0x0996,0x0997,
+ 0x0998,0x0999,0x099a,0x099b,0x099c,0x099d,0x099e,0x099f,
+ 0x09a0,0x09a1,0x09a2,0x09a3,0x09a4,0x09a5,0x09a6,0x09a7,
+ 0x09a8,0x09a9,0x09aa,0x09ab,0x09ac,0x09ad,0x09ae,0x09af,
+ 0x09b0,0x09b1,0x09b2,0x09b3,0x09b4,0x09b5,0x09b6,0x09b7,
+ 0x09b8,0x09b9,0x09ba,0x09bb,0x09bc,0x09bd,0x09be,0x09bf,
+ 0x09c0,0x09c1,0x09c2,0x09c3,0x09c4,0x09c5,0x09c6,0x09c7,
+ 0x09c8,0x09c9,0x09ca,0x09cb,0x09cc,0x09cd,0x09ce,0x09cf,
+ 0x09d0,0x09d1,0x09d2,0x09d3,0x09d4,0x09d5,0x09d6,0x09d7,
+ 0x09d8,0x09d9,0x09da,0x09db,0x09dc,0x09dd,0x09de,0x09df,
+ 0x09e0,0x09e1,0x09e2,0x09e3,0x09e4,0x09e5,0x09e6,0x09e7,
+ 0x09e8,0x09e9,0x09ea,0x09eb,0x09ec,0x09ed,0x09ee,0x09ef,
+ 0x09f0,0x09f1,0x09f2,0x09f3,0x09f4,0x09f5,0x09f6,0x09f7,
+ 0x09f8,0x09f9,0x09fa,0x09fb,0x09fc,0x09fd,0x09fe,0x09ff,
+ 0x0a00,0x0a01,0x0a02,0x0a03,0x0a04,0x0a05,0x0a06,0x0a07,
+ 0x0a08,0x0a09,0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f,
+ 0x0a10,0x0a11,0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17,
+ 0x0a18,0x0a19,0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f,
+ 0x0a20,0x0a21,0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27,
+ 0x0a28,0x0a29,0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f,
+ 0x0a30,0x0a31,0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37,
+ 0x0a38,0x0a39,0x0a3a,0x0a3b,0x0a3c,0x0a3d,0x0a3e,0x0a3f,
+ 0x0a40,0x0a41,0x0a42,0x0a43,0x0a44,0x0a45,0x0a46,0x0a47,
+ 0x0a48,0x0a49,0x0a4a,0x0a4b,0x0a4c,0x0a4d,0x0a4e,0x0a4f,
+ 0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55,0x0a56,0x0a57,
+ 0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d,0x0a5e,0x0a5f,
+ 0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65,0x0a66,0x0a67,
+ 0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d,0x0a6e,0x0a6f,
+ 0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75,0x0a76,0x0a77,
+ 0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d,0x0a7e,0x0a7f,
+ 0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85,0x0a86,0x0a87,
+ 0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d,0x0a8e,0x0a8f,
+ 0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95,0x0a96,0x0a97,
+ 0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d,0x0a9e,0x0a9f,
+ 0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5,0x0aa6,0x0aa7,
+ 0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad,0x0aae,0x0aaf,
+ 0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5,0x0ab6,0x0ab7,
+ 0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd,0x0abe,0x0abf,
+ 0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5,0x0ac6,0x0ac7,
+ 0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd,0x0ace,0x0acf,
+ 0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5,0x0ad6,0x0ad7,
+ 0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add,0x0ade,0x0adf,
+ 0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5,0x0ae6,0x0ae7,
+ 0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed,0x0aee,0x0aef,
+ 0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5,0x0af6,0x0af7,
+ 0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd,0x0afe,0x0aff,
+ 0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05,0x0b06,0x0b07,
+ 0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d,0x0b0e,0x0b0f,
+ 0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15,0x0b16,0x0b17,
+ 0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d,0x0b1e,0x0b1f,
+ 0x0b20,0x0b21,0x0b22,0x0b23,0x0b24,0x0b25,0x0b26,0x0b27,
+ 0x0b28,0x0b29,0x0b2a,0x0b2b,0x0b2c,0x0b2d,0x0b2e,0x0b2f,
+ 0x0b30,0x0b31,0x0b32,0x0b33,0x0b34,0x0b35,0x0b36,0x0b37,
+ 0x0b38,0x0b39,0x0b3a,0x0b3b,0x0b3c,0x0b3d,0x0b3e,0x0b3f,
+ 0x0b40,0x0b41,0x0b42,0x0b43,0x0b44,0x0b45,0x0b46,0x0b47,
+ 0x0b48,0x0b49,0x0b4a,0x0b4b,0x0b4c,0x0b4d,0x0b4e,0x0b4f,
+ 0x0b50,0x0b51,0x0b52,0x0b53,0x0b54,0x0b55,0x0b56,0x0b57,
+ 0x0b58,0x0b59,0x0b5a,0x0b5b,0x0b5c,0x0b5d,0x0b5e,0x0b5f,
+ 0x0b60,0x0b61,0x0b62,0x0b63,0x0b64,0x0b65,0x0b66,0x0b67,
+ 0x0b68,0x0b69,0x0b6a,0x0b6b,0x0b6c,0x0b6d,0x0b6e,0x0b6f,
+ 0x0b70,0x0b71,0x0b72,0x0b73,0x0b74,0x0b75,0x0b76,0x0b77,
+ 0x0b78,0x0b79,0x0b7a,0x0b7b,0x0b7c,0x0b7d,0x0b7e,0x0b7f,
+ 0x0b80,0x0b81,0x0b82,0x0b83,0x0b84,0x0b85,0x0b86,0x0b87,
+ 0x0b88,0x0b89,0x0b8a,0x0b8b,0x0b8c,0x0b8d,0x0b8e,0x0b8f,
+ 0x0b90,0x0b91,0x0b92,0x0b93,0x0b94,0x0b95,0x0b96,0x0b97,
+ 0x0b98,0x0b99,0x0b9a,0x0b9b,0x0b9c,0x0b9d,0x0b9e,0x0b9f,
+ 0x0ba0,0x0ba1,0x0ba2,0x0ba3,0x0ba4,0x0ba5,0x0ba6,0x0ba7,
+ 0x0ba8,0x0ba9,0x0baa,0x0bab,0x0bac,0x0bad,0x0bae,0x0baf,
+ 0x0bb0,0x0bb1,0x0bb2,0x0bb3,0x0bb4,0x0bb5,0x0bb6,0x0bb7,
+ 0x0bb8,0x0bb9,0x0bba,0x0bbb,0x0bbc,0x0bbd,0x0bbe,0x0bbf,
+ 0x0bc0,0x0bc1,0x0bc2,0x0bc3,0x0bc4,0x0bc5,0x0bc6,0x0bc7,
+ 0x0bc8,0x0bc9,0x0bca,0x0bcb,0x0bcc,0x0bcd,0x0bce,0x0bcf,
+ 0x0bd0,0x0bd1,0x0bd2,0x0bd3,0x0bd4,0x0bd5,0x0bd6,0x0bd7,
+ 0x0bd8,0x0bd9,0x0bda,0x0bdb,0x0bdc,0x0bdd,0x0bde,0x0bdf,
+ 0x0be0,0x0be1,0x0be2,0x0be3,0x0be4,0x0be5,0x0be6,0x0be7,
+ 0x0be8,0x0be9,0x0bea,0x0beb,0x0bec,0x0bed,0x0bee,0x0bef,
+ 0x0bf0,0x0bf1,0x0bf2,0x0bf3,0x0bf4,0x0bf5,0x0bf6,0x0bf7,
+ 0x0bf8,0x0bf9,0x0bfa,0x0bfb,0x0bfc,0x0bfd,0x0bfe,0x0bff,
+ 0x0c00,0x0c01,0x0c02,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07,
+ 0x0c08,0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f,
+ 0x0c10,0x0c11,0x0c12,0x0c13,0x0c14,0x0c15,0x0c16,0x0c17,
+ 0x0c18,0x0c19,0x0c1a,0x0c1b,0x0c1c,0x0c1d,0x0c1e,0x0c1f,
+ 0x0c20,0x0c21,0x0c22,0x0c23,0x0c24,0x0c25,0x0c26,0x0c27,
+ 0x0c28,0x0c29,0x0c2a,0x0c2b,0x0c2c,0x0c2d,0x0c2e,0x0c2f,
+ 0x0c30,0x0c31,0x0c32,0x0c33,0x0c34,0x0c35,0x0c36,0x0c37,
+ 0x0c38,0x0c39,0x0c3a,0x0c3b,0x0c3c,0x0c3d,0x0c3e,0x0c3f,
+ 0x0c40,0x0c41,0x0c42,0x0c43,0x0c44,0x0c45,0x0c46,0x0c47,
+ 0x0c48,0x0c49,0x0c4a,0x0c4b,0x0c4c,0x0c4d,0x0c4e,0x0c4f,
+ 0x0c50,0x0c51,0x0c52,0x0c53,0x0c54,0x0c55,0x0c56,0x0c57,
+ 0x0c58,0x0c59,0x0c5a,0x0c5b,0x0c5c,0x0c5d,0x0c5e,0x0c5f,
+ 0x0c60,0x0c61,0x0c62,0x0c63,0x0c64,0x0c65,0x0c66,0x0c67,
+ 0x0c68,0x0c69,0x0c6a,0x0c6b,0x0c6c,0x0c6d,0x0c6e,0x0c6f,
+ 0x0c70,0x0c71,0x0c72,0x0c73,0x0c74,0x0c75,0x0c76,0x0c77,
+ 0x0c78,0x0c79,0x0c7a,0x0c7b,0x0c7c,0x0c7d,0x0c7e,0x0c7f,
+ 0x0c80,0x0c81,0x0c82,0x0c83,0x0c84,0x0c85,0x0c86,0x0c87,
+ 0x0c88,0x0c89,0x0c8a,0x0c8b,0x0c8c,0x0c8d,0x0c8e,0x0c8f,
+ 0x0c90,0x0c91,0x0c92,0x0c93,0x0c94,0x0c95,0x0c96,0x0c97,
+ 0x0c98,0x0c99,0x0c9a,0x0c9b,0x0c9c,0x0c9d,0x0c9e,0x0c9f,
+ 0x0ca0,0x0ca1,0x0ca2,0x0ca3,0x0ca4,0x0ca5,0x0ca6,0x0ca7,
+ 0x0ca8,0x0ca9,0x0caa,0x0cab,0x0cac,0x0cad,0x0cae,0x0caf,
+ 0x0cb0,0x0cb1,0x0cb2,0x0cb3,0x0cb4,0x0cb5,0x0cb6,0x0cb7,
+ 0x0cb8,0x0cb9,0x0cba,0x0cbb,0x0cbc,0x0cbd,0x0cbe,0x0cbf,
+ 0x0cc0,0x0cc1,0x0cc2,0x0cc3,0x0cc4,0x0cc5,0x0cc6,0x0cc7,
+ 0x0cc8,0x0cc9,0x0cca,0x0ccb,0x0ccc,0x0ccd,0x0cce,0x0ccf,
+ 0x0cd0,0x0cd1,0x0cd2,0x0cd3,0x0cd4,0x0cd5,0x0cd6,0x0cd7,
+ 0x0cd8,0x0cd9,0x0cda,0x0cdb,0x0cdc,0x0cdd,0x0cde,0x0cdf,
+ 0x0ce0,0x0ce1,0x0ce2,0x0ce3,0x0ce4,0x0ce5,0x0ce6,0x0ce7,
+ 0x0ce8,0x0ce9,0x0cea,0x0ceb,0x0cec,0x0ced,0x0cee,0x0cef,
+ 0x0cf0,0x0cf1,0x0cf2,0x0cf3,0x0cf4,0x0cf5,0x0cf6,0x0cf7,
+ 0x0cf8,0x0cf9,0x0cfa,0x0cfb,0x0cfc,0x0cfd,0x0cfe,0x0cff,
+ 0x0d00,0x0d01,0x0d02,0x0d03,0x0d04,0x0d05,0x0d06,0x0d07,
+ 0x0d08,0x0d09,0x0d0a,0x0d0b,0x0d0c,0x0d0d,0x0d0e,0x0d0f,
+ 0x0d10,0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17,
+ 0x0d18,0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x0d1f,
+ 0x0d20,0x0d21,0x0d22,0x0d23,0x0d24,0x0d25,0x0d26,0x0d27,
+ 0x0d28,0x0d29,0x0d2a,0x0d2b,0x0d2c,0x0d2d,0x0d2e,0x0d2f,
+ 0x0d30,0x0d31,0x0d32,0x0d33,0x0d34,0x0d35,0x0d36,0x0d37,
+ 0x0d38,0x0d39,0x0d3a,0x0d3b,0x0d3c,0x0d3d,0x0d3e,0x0d3f,
+ 0x0d40,0x0d41,0x0d42,0x0d43,0x0d44,0x0d45,0x0d46,0x0d47,
+ 0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d,0x0d4e,0x0d4f,
+ 0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55,0x0d56,0x0d57,
+ 0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d,0x0d5e,0x0d5f,
+ 0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65,0x0d66,0x0d67,
+ 0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d,0x0d6e,0x0d6f,
+ 0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75,0x0d76,0x0d77,
+ 0x0d78,0x0d79,0x0d7a,0x0d7b,0x0d7c,0x0d7d,0x0d7e,0x0d7f,
+ 0x0d80,0x0d81,0x0d82,0x0d83,0x0d84,0x0d85,0x0d86,0x0d87,
+ 0x0d88,0x0d89,0x0d8a,0x0d8b,0x0d8c,0x0d8d,0x0d8e,0x0d8f,
+ 0x0d90,0x0d91,0x0d92,0x0d93,0x0d94,0x0d95,0x0d96,0x0d97,
+ 0x0d98,0x0d99,0x0d9a,0x0d9b,0x0d9c,0x0d9d,0x0d9e,0x0d9f,
+ 0x0da0,0x0da1,0x0da2,0x0da3,0x0da4,0x0da5,0x0da6,0x0da7,
+ 0x0da8,0x0da9,0x0daa,0x0dab,0x0dac,0x0dad,0x0dae,0x0daf,
+ 0x0db0,0x0db1,0x0db2,0x0db3,0x0db4,0x0db5,0x0db6,0x0db7,
+ 0x0db8,0x0db9,0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf,
+ 0x0dc0,0x0dc1,0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7,
+ 0x0dc8,0x0dc9,0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf,
+ 0x0dd0,0x0dd1,0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7,
+ 0x0dd8,0x0dd9,0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf,
+ 0x0de0,0x0de1,0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7,
+ 0x0de8,0x0de9,0x0dea,0x0deb,0x0dec,0x0ded,0x0dee,0x0def,
+ 0x0df0,0x0df1,0x0df2,0x0df3,0x0df4,0x0df5,0x0df6,0x0df7,
+ 0x0df8,0x0df9,0x0dfa,0x0dfb,0x0dfc,0x0dfd,0x0dfe,0x0dff,
+ 0x0e00,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
+ 0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
+ 0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
+ 0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
+ 0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
+ 0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
+ 0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
+ 0x0e38,0x0e39,0x0e3a,0x0e3b,0x0e3c,0x0e3d,0x0e3e,0x0e3f,
+ 0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
+ 0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
+ 0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
+ 0x0e58,0x0e59,0x0e5a,0x0e5b,0x0e5c,0x0e5d,0x0e5e,0x0e5f,
+ 0x0e60,0x0e61,0x0e62,0x0e63,0x0e64,0x0e65,0x0e66,0x0e67,
+ 0x0e68,0x0e69,0x0e6a,0x0e6b,0x0e6c,0x0e6d,0x0e6e,0x0e6f,
+ 0x0e70,0x0e71,0x0e72,0x0e73,0x0e74,0x0e75,0x0e76,0x0e77,
+ 0x0e78,0x0e79,0x0e7a,0x0e7b,0x0e7c,0x0e7d,0x0e7e,0x0e7f,
+ 0x0e80,0x0e81,0x0e82,0x0e83,0x0e84,0x0e85,0x0e86,0x0e87,
+ 0x0e88,0x0e89,0x0e8a,0x0e8b,0x0e8c,0x0e8d,0x0e8e,0x0e8f,
+ 0x0e90,0x0e91,0x0e92,0x0e93,0x0e94,0x0e95,0x0e96,0x0e97,
+ 0x0e98,0x0e99,0x0e9a,0x0e9b,0x0e9c,0x0e9d,0x0e9e,0x0e9f,
+ 0x0ea0,0x0ea1,0x0ea2,0x0ea3,0x0ea4,0x0ea5,0x0ea6,0x0ea7,
+ 0x0ea8,0x0ea9,0x0eaa,0x0eab,0x0eac,0x0ead,0x0eae,0x0eaf,
+ 0x0eb0,0x0eb1,0x0eb2,0x0eb3,0x0eb4,0x0eb5,0x0eb6,0x0eb7,
+ 0x0eb8,0x0eb9,0x0eba,0x0ebb,0x0ebc,0x0ebd,0x0ebe,0x0ebf,
+ 0x0ec0,0x0ec1,0x0ec2,0x0ec3,0x0ec4,0x0ec5,0x0ec6,0x0ec7,
+ 0x0ec8,0x0ec9,0x0eca,0x0ecb,0x0ecc,0x0ecd,0x0ece,0x0ecf,
+ 0x0ed0,0x0ed1,0x0ed2,0x0ed3,0x0ed4,0x0ed5,0x0ed6,0x0ed7,
+ 0x0ed8,0x0ed9,0x0eda,0x0edb,0x0edc,0x0edd,0x0ede,0x0edf,
+ 0x0ee0,0x0ee1,0x0ee2,0x0ee3,0x0ee4,0x0ee5,0x0ee6,0x0ee7,
+ 0x0ee8,0x0ee9,0x0eea,0x0eeb,0x0eec,0x0eed,0x0eee,0x0eef,
+ 0x0ef0,0x0ef1,0x0ef2,0x0ef3,0x0ef4,0x0ef5,0x0ef6,0x0ef7,
+ 0x0ef8,0x0ef9,0x0efa,0x0efb,0x0efc,0x0efd,0x0efe,0x0eff,
+ 0x0f00,0x0f01,0x0f02,0x0f03,0x0f04,0x0f05,0x0f06,0x0f07,
+ 0x0f08,0x0f09,0x0f0a,0x0f0b,0x0f0c,0x0f0d,0x0f0e,0x0f0f,
+ 0x0f10,0x0f11,0x0f12,0x0f13,0x0f14,0x0f15,0x0f16,0x0f17,
+ 0x0f18,0x0f19,0x0f1a,0x0f1b,0x0f1c,0x0f1d,0x0f1e,0x0f1f,
+ 0x0f20,0x0f21,0x0f22,0x0f23,0x0f24,0x0f25,0x0f26,0x0f27,
+ 0x0f28,0x0f29,0x0f2a,0x0f2b,0x0f2c,0x0f2d,0x0f2e,0x0f2f,
+ 0x0f30,0x0f31,0x0f32,0x0f33,0x0f34,0x0f35,0x0f36,0x0f37,
+ 0x0f38,0x0f39,0x0f3a,0x0f3b,0x0f3c,0x0f3d,0x0f3e,0x0f3f,
+ 0x0f40,0x0f41,0x0f42,0x0f43,0x0f44,0x0f45,0x0f46,0x0f47,
+ 0x0f48,0x0f49,0x0f4a,0x0f4b,0x0f4c,0x0f4d,0x0f4e,0x0f4f,
+ 0x0f50,0x0f51,0x0f52,0x0f53,0x0f54,0x0f55,0x0f56,0x0f57,
+ 0x0f58,0x0f59,0x0f5a,0x0f5b,0x0f5c,0x0f5d,0x0f5e,0x0f5f,
+ 0x0f60,0x0f61,0x0f62,0x0f63,0x0f64,0x0f65,0x0f66,0x0f67,
+ 0x0f68,0x0f69,0x0f6a,0x0f6b,0x0f6c,0x0f6d,0x0f6e,0x0f6f,
+ 0x0f70,0x0f71,0x0f72,0x0f73,0x0f74,0x0f75,0x0f76,0x0f77,
+ 0x0f78,0x0f79,0x0f7a,0x0f7b,0x0f7c,0x0f7d,0x0f7e,0x0f7f,
+ 0x0f80,0x0f81,0x0f82,0x0f83,0x0f84,0x0f85,0x0f86,0x0f87,
+ 0x0f88,0x0f89,0x0f8a,0x0f8b,0x0f8c,0x0f8d,0x0f8e,0x0f8f,
+ 0x0f90,0x0f91,0x0f92,0x0f93,0x0f94,0x0f95,0x0f96,0x0f97,
+ 0x0f98,0x0f99,0x0f9a,0x0f9b,0x0f9c,0x0f9d,0x0f9e,0x0f9f,
+ 0x0fa0,0x0fa1,0x0fa2,0x0fa3,0x0fa4,0x0fa5,0x0fa6,0x0fa7,
+ 0x0fa8,0x0fa9,0x0faa,0x0fab,0x0fac,0x0fad,0x0fae,0x0faf,
+ 0x0fb0,0x0fb1,0x0fb2,0x0fb3,0x0fb4,0x0fb5,0x0fb6,0x0fb7,
+ 0x0fb8,0x0fb9,0x0fba,0x0fbb,0x0fbc,0x0fbd,0x0fbe,0x0fbf,
+ 0x0fc0,0x0fc1,0x0fc2,0x0fc3,0x0fc4,0x0fc5,0x0fc6,0x0fc7,
+ 0x0fc8,0x0fc9,0x0fca,0x0fcb,0x0fcc,0x0fcd,0x0fce,0x0fcf,
+ 0x0fd0,0x0fd1,0x0fd2,0x0fd3,0x0fd4,0x0fd5,0x0fd6,0x0fd7,
+ 0x0fd8,0x0fd9,0x0fda,0x0fdb,0x0fdc,0x0fdd,0x0fde,0x0fdf,
+ 0x0fe0,0x0fe1,0x0fe2,0x0fe3,0x0fe4,0x0fe5,0x0fe6,0x0fe7,
+ 0x0fe8,0x0fe9,0x0fea,0x0feb,0x0fec,0x0fed,0x0fee,0x0fef,
+ 0x0ff0,0x0ff1,0x0ff2,0x0ff3,0x0ff4,0x0ff5,0x0ff6,0x0ff7,
+ 0x0ff8,0x0ff9,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff,
+ 0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007,
+ 0x1008,0x1009,0x100a,0x100b,0x100c,0x100d,0x100e,0x100f,
+ 0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017,
+ 0x1018,0x1019,0x101a,0x101b,0x101c,0x101d,0x101e,0x101f,
+ 0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027,
+ 0x1028,0x1029,0x102a,0x102b,0x102c,0x102d,0x102e,0x102f,
+ 0x1030,0x1031,0x1032,0x1033,0x1034,0x1035,0x1036,0x1037,
+ 0x1038,0x1039,0x103a,0x103b,0x103c,0x103d,0x103e,0x103f,
+ 0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047,
+ 0x1048,0x1049,0x104a,0x104b,0x104c,0x104d,0x104e,0x104f,
+ 0x1050,0x1051,0x1052,0x1053,0x1054,0x1055,0x1056,0x1057,
+ 0x1058,0x1059,0x105a,0x105b,0x105c,0x105d,0x105e,0x105f,
+ 0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
+ 0x1068,0x1069,0x106a,0x106b,0x106c,0x106d,0x106e,0x106f,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x1078,0x1079,0x107a,0x107b,0x107c,0x107d,0x107e,0x107f,
+ 0x1080,0x1081,0x1082,0x1083,0x1084,0x1085,0x1086,0x1087,
+ 0x1088,0x1089,0x108a,0x108b,0x108c,0x108d,0x108e,0x108f,
+ 0x1090,0x1091,0x1092,0x1093,0x1094,0x1095,0x1096,0x1097,
+ 0x1098,0x1099,0x109a,0x109b,0x109c,0x109d,0x109e,0x109f,
+ 0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7,
+ 0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af,
+ 0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7,
+ 0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf,
+ 0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5,0x10c6,0x10c7,
+ 0x10c8,0x10c9,0x10ca,0x10cb,0x10cc,0x10cd,0x10ce,0x10cf,
+ 0x10d0,0x10d1,0x10d2,0x10d3,0x10d4,0x10d5,0x10d6,0x10d7,
+ 0x10d8,0x10d9,0x10da,0x10db,0x10dc,0x10dd,0x10de,0x10df,
+ 0x10e0,0x10e1,0x10e2,0x10e3,0x10e4,0x10e5,0x10e6,0x10e7,
+ 0x10e8,0x10e9,0x10ea,0x10eb,0x10ec,0x10ed,0x10ee,0x10ef,
+ 0x10f0,0x10f1,0x10f2,0x10f3,0x10f4,0x10f5,0x10f6,0x10f7,
+ 0x10f8,0x10f9,0x10fa,0x10fb,0x10fc,0x10fd,0x10fe,0x10ff,
+ 0x1100,0x1101,0x1102,0x1103,0x1104,0x1105,0x1106,0x1107,
+ 0x1108,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f,
+ 0x1110,0x1111,0x1112,0x1113,0x1114,0x1115,0x1116,0x1117,
+ 0x1118,0x1119,0x111a,0x111b,0x111c,0x111d,0x111e,0x111f,
+ 0x1120,0x1121,0x1122,0x1123,0x1124,0x1125,0x1126,0x1127,
+ 0x1128,0x1129,0x112a,0x112b,0x112c,0x112d,0x112e,0x112f,
+ 0x1130,0x1131,0x1132,0x1133,0x1134,0x1135,0x1136,0x1137,
+ 0x1138,0x1139,0x113a,0x113b,0x113c,0x113d,0x113e,0x113f,
+ 0x1140,0x1141,0x1142,0x1143,0x1144,0x1145,0x1146,0x1147,
+ 0x1148,0x1149,0x114a,0x114b,0x114c,0x114d,0x114e,0x114f,
+ 0x1150,0x1151,0x1152,0x1153,0x1154,0x1155,0x1156,0x1157,
+ 0x1158,0x1159,0x115a,0x115b,0x115c,0x115d,0x115e,0x115f,
+ 0x1160,0x1161,0x1162,0x1163,0x1164,0x1165,0x1166,0x1167,
+ 0x1168,0x1169,0x116a,0x116b,0x116c,0x116d,0x116e,0x116f,
+ 0x1170,0x1171,0x1172,0x1173,0x1174,0x1175,0x1176,0x1177,
+ 0x1178,0x1179,0x117a,0x117b,0x117c,0x117d,0x117e,0x117f,
+ 0x1180,0x1181,0x1182,0x1183,0x1184,0x1185,0x1186,0x1187,
+ 0x1188,0x1189,0x118a,0x118b,0x118c,0x118d,0x118e,0x118f,
+ 0x1190,0x1191,0x1192,0x1193,0x1194,0x1195,0x1196,0x1197,
+ 0x1198,0x1199,0x119a,0x119b,0x119c,0x119d,0x119e,0x119f,
+ 0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a7,
+ 0x11a8,0x11a9,0x11aa,0x11ab,0x11ac,0x11ad,0x11ae,0x11af,
+ 0x11b0,0x11b1,0x11b2,0x11b3,0x11b4,0x11b5,0x11b6,0x11b7,
+ 0x11b8,0x11b9,0x11ba,0x11bb,0x11bc,0x11bd,0x11be,0x11bf,
+ 0x11c0,0x11c1,0x11c2,0x11c3,0x11c4,0x11c5,0x11c6,0x11c7,
+ 0x11c8,0x11c9,0x11ca,0x11cb,0x11cc,0x11cd,0x11ce,0x11cf,
+ 0x11d0,0x11d1,0x11d2,0x11d3,0x11d4,0x11d5,0x11d6,0x11d7,
+ 0x11d8,0x11d9,0x11da,0x11db,0x11dc,0x11dd,0x11de,0x11df,
+ 0x11e0,0x11e1,0x11e2,0x11e3,0x11e4,0x11e5,0x11e6,0x11e7,
+ 0x11e8,0x11e9,0x11ea,0x11eb,0x11ec,0x11ed,0x11ee,0x11ef,
+ 0x11f0,0x11f1,0x11f2,0x11f3,0x11f4,0x11f5,0x11f6,0x11f7,
+ 0x11f8,0x11f9,0x11fa,0x11fb,0x11fc,0x11fd,0x11fe,0x11ff,
+ 0x1200,0x1201,0x1202,0x1203,0x1204,0x1205,0x1206,0x1207,
+ 0x1208,0x1209,0x120a,0x120b,0x120c,0x120d,0x120e,0x120f,
+ 0x1210,0x1211,0x1212,0x1213,0x1214,0x1215,0x1216,0x1217,
+ 0x1218,0x1219,0x121a,0x121b,0x121c,0x121d,0x121e,0x121f,
+ 0x1220,0x1221,0x1222,0x1223,0x1224,0x1225,0x1226,0x1227,
+ 0x1228,0x1229,0x122a,0x122b,0x122c,0x122d,0x122e,0x122f,
+ 0x1230,0x1231,0x1232,0x1233,0x1234,0x1235,0x1236,0x1237,
+ 0x1238,0x1239,0x123a,0x123b,0x123c,0x123d,0x123e,0x123f,
+ 0x1240,0x1241,0x1242,0x1243,0x1244,0x1245,0x1246,0x1247,
+ 0x1248,0x1249,0x124a,0x124b,0x124c,0x124d,0x124e,0x124f,
+ 0x1250,0x1251,0x1252,0x1253,0x1254,0x1255,0x1256,0x1257,
+ 0x1258,0x1259,0x125a,0x125b,0x125c,0x125d,0x125e,0x125f,
+ 0x1260,0x1261,0x1262,0x1263,0x1264,0x1265,0x1266,0x1267,
+ 0x1268,0x1269,0x126a,0x126b,0x126c,0x126d,0x126e,0x126f,
+ 0x1270,0x1271,0x1272,0x1273,0x1274,0x1275,0x1276,0x1277,
+ 0x1278,0x1279,0x127a,0x127b,0x127c,0x127d,0x127e,0x127f,
+ 0x1280,0x1281,0x1282,0x1283,0x1284,0x1285,0x1286,0x1287,
+ 0x1288,0x1289,0x128a,0x128b,0x128c,0x128d,0x128e,0x128f,
+ 0x1290,0x1291,0x1292,0x1293,0x1294,0x1295,0x1296,0x1297,
+ 0x1298,0x1299,0x129a,0x129b,0x129c,0x129d,0x129e,0x129f,
+ 0x12a0,0x12a1,0x12a2,0x12a3,0x12a4,0x12a5,0x12a6,0x12a7,
+ 0x12a8,0x12a9,0x12aa,0x12ab,0x12ac,0x12ad,0x12ae,0x12af,
+ 0x12b0,0x12b1,0x12b2,0x12b3,0x12b4,0x12b5,0x12b6,0x12b7,
+ 0x12b8,0x12b9,0x12ba,0x12bb,0x12bc,0x12bd,0x12be,0x12bf,
+ 0x12c0,0x12c1,0x12c2,0x12c3,0x12c4,0x12c5,0x12c6,0x12c7,
+ 0x12c8,0x12c9,0x12ca,0x12cb,0x12cc,0x12cd,0x12ce,0x12cf,
+ 0x12d0,0x12d1,0x12d2,0x12d3,0x12d4,0x12d5,0x12d6,0x12d7,
+ 0x12d8,0x12d9,0x12da,0x12db,0x12dc,0x12dd,0x12de,0x12df,
+ 0x12e0,0x12e1,0x12e2,0x12e3,0x12e4,0x12e5,0x12e6,0x12e7,
+ 0x12e8,0x12e9,0x12ea,0x12eb,0x12ec,0x12ed,0x12ee,0x12ef,
+ 0x12f0,0x12f1,0x12f2,0x12f3,0x12f4,0x12f5,0x12f6,0x12f7,
+ 0x12f8,0x12f9,0x12fa,0x12fb,0x12fc,0x12fd,0x12fe,0x12ff,
+ 0x1300,0x1301,0x1302,0x1303,0x1304,0x1305,0x1306,0x1307,
+ 0x1308,0x1309,0x130a,0x130b,0x130c,0x130d,0x130e,0x130f,
+ 0x1310,0x1311,0x1312,0x1313,0x1314,0x1315,0x1316,0x1317,
+ 0x1318,0x1319,0x131a,0x131b,0x131c,0x131d,0x131e,0x131f,
+ 0x1320,0x1321,0x1322,0x1323,0x1324,0x1325,0x1326,0x1327,
+ 0x1328,0x1329,0x132a,0x132b,0x132c,0x132d,0x132e,0x132f,
+ 0x1330,0x1331,0x1332,0x1333,0x1334,0x1335,0x1336,0x1337,
+ 0x1338,0x1339,0x133a,0x133b,0x133c,0x133d,0x133e,0x133f,
+ 0x1340,0x1341,0x1342,0x1343,0x1344,0x1345,0x1346,0x1347,
+ 0x1348,0x1349,0x134a,0x134b,0x134c,0x134d,0x134e,0x134f,
+ 0x1350,0x1351,0x1352,0x1353,0x1354,0x1355,0x1356,0x1357,
+ 0x1358,0x1359,0x135a,0x135b,0x135c,0x135d,0x135e,0x135f,
+ 0x1360,0x1361,0x1362,0x1363,0x1364,0x1365,0x1366,0x1367,
+ 0x1368,0x1369,0x136a,0x136b,0x136c,0x136d,0x136e,0x136f,
+ 0x1370,0x1371,0x1372,0x1373,0x1374,0x1375,0x1376,0x1377,
+ 0x1378,0x1379,0x137a,0x137b,0x137c,0x137d,0x137e,0x137f,
+ 0x1380,0x1381,0x1382,0x1383,0x1384,0x1385,0x1386,0x1387,
+ 0x1388,0x1389,0x138a,0x138b,0x138c,0x138d,0x138e,0x138f,
+ 0x1390,0x1391,0x1392,0x1393,0x1394,0x1395,0x1396,0x1397,
+ 0x1398,0x1399,0x139a,0x139b,0x139c,0x139d,0x139e,0x139f,
+ 0x13a0,0x13a1,0x13a2,0x13a3,0x13a4,0x13a5,0x13a6,0x13a7,
+ 0x13a8,0x13a9,0x13aa,0x13ab,0x13ac,0x13ad,0x13ae,0x13af,
+ 0x13b0,0x13b1,0x13b2,0x13b3,0x13b4,0x13b5,0x13b6,0x13b7,
+ 0x13b8,0x13b9,0x13ba,0x13bb,0x13bc,0x13bd,0x13be,0x13bf,
+ 0x13c0,0x13c1,0x13c2,0x13c3,0x13c4,0x13c5,0x13c6,0x13c7,
+ 0x13c8,0x13c9,0x13ca,0x13cb,0x13cc,0x13cd,0x13ce,0x13cf,
+ 0x13d0,0x13d1,0x13d2,0x13d3,0x13d4,0x13d5,0x13d6,0x13d7,
+ 0x13d8,0x13d9,0x13da,0x13db,0x13dc,0x13dd,0x13de,0x13df,
+ 0x13e0,0x13e1,0x13e2,0x13e3,0x13e4,0x13e5,0x13e6,0x13e7,
+ 0x13e8,0x13e9,0x13ea,0x13eb,0x13ec,0x13ed,0x13ee,0x13ef,
+ 0x13f0,0x13f1,0x13f2,0x13f3,0x13f4,0x13f5,0x13f6,0x13f7,
+ 0x13f8,0x13f9,0x13fa,0x13fb,0x13fc,0x13fd,0x13fe,0x13ff,
+ 0x1400,0x1401,0x1402,0x1403,0x1404,0x1405,0x1406,0x1407,
+ 0x1408,0x1409,0x140a,0x140b,0x140c,0x140d,0x140e,0x140f,
+ 0x1410,0x1411,0x1412,0x1413,0x1414,0x1415,0x1416,0x1417,
+ 0x1418,0x1419,0x141a,0x141b,0x141c,0x141d,0x141e,0x141f,
+ 0x1420,0x1421,0x1422,0x1423,0x1424,0x1425,0x1426,0x1427,
+ 0x1428,0x1429,0x142a,0x142b,0x142c,0x142d,0x142e,0x142f,
+ 0x1430,0x1431,0x1432,0x1433,0x1434,0x1435,0x1436,0x1437,
+ 0x1438,0x1439,0x143a,0x143b,0x143c,0x143d,0x143e,0x143f,
+ 0x1440,0x1441,0x1442,0x1443,0x1444,0x1445,0x1446,0x1447,
+ 0x1448,0x1449,0x144a,0x144b,0x144c,0x144d,0x144e,0x144f,
+ 0x1450,0x1451,0x1452,0x1453,0x1454,0x1455,0x1456,0x1457,
+ 0x1458,0x1459,0x145a,0x145b,0x145c,0x145d,0x145e,0x145f,
+ 0x1460,0x1461,0x1462,0x1463,0x1464,0x1465,0x1466,0x1467,
+ 0x1468,0x1469,0x146a,0x146b,0x146c,0x146d,0x146e,0x146f,
+ 0x1470,0x1471,0x1472,0x1473,0x1474,0x1475,0x1476,0x1477,
+ 0x1478,0x1479,0x147a,0x147b,0x147c,0x147d,0x147e,0x147f,
+ 0x1480,0x1481,0x1482,0x1483,0x1484,0x1485,0x1486,0x1487,
+ 0x1488,0x1489,0x148a,0x148b,0x148c,0x148d,0x148e,0x148f,
+ 0x1490,0x1491,0x1492,0x1493,0x1494,0x1495,0x1496,0x1497,
+ 0x1498,0x1499,0x149a,0x149b,0x149c,0x149d,0x149e,0x149f,
+ 0x14a0,0x14a1,0x14a2,0x14a3,0x14a4,0x14a5,0x14a6,0x14a7,
+ 0x14a8,0x14a9,0x14aa,0x14ab,0x14ac,0x14ad,0x14ae,0x14af,
+ 0x14b0,0x14b1,0x14b2,0x14b3,0x14b4,0x14b5,0x14b6,0x14b7,
+ 0x14b8,0x14b9,0x14ba,0x14bb,0x14bc,0x14bd,0x14be,0x14bf,
+ 0x14c0,0x14c1,0x14c2,0x14c3,0x14c4,0x14c5,0x14c6,0x14c7,
+ 0x14c8,0x14c9,0x14ca,0x14cb,0x14cc,0x14cd,0x14ce,0x14cf,
+ 0x14d0,0x14d1,0x14d2,0x14d3,0x14d4,0x14d5,0x14d6,0x14d7,
+ 0x14d8,0x14d9,0x14da,0x14db,0x14dc,0x14dd,0x14de,0x14df,
+ 0x14e0,0x14e1,0x14e2,0x14e3,0x14e4,0x14e5,0x14e6,0x14e7,
+ 0x14e8,0x14e9,0x14ea,0x14eb,0x14ec,0x14ed,0x14ee,0x14ef,
+ 0x14f0,0x14f1,0x14f2,0x14f3,0x14f4,0x14f5,0x14f6,0x14f7,
+ 0x14f8,0x14f9,0x14fa,0x14fb,0x14fc,0x14fd,0x14fe,0x14ff,
+ 0x1500,0x1501,0x1502,0x1503,0x1504,0x1505,0x1506,0x1507,
+ 0x1508,0x1509,0x150a,0x150b,0x150c,0x150d,0x150e,0x150f,
+ 0x1510,0x1511,0x1512,0x1513,0x1514,0x1515,0x1516,0x1517,
+ 0x1518,0x1519,0x151a,0x151b,0x151c,0x151d,0x151e,0x151f,
+ 0x1520,0x1521,0x1522,0x1523,0x1524,0x1525,0x1526,0x1527,
+ 0x1528,0x1529,0x152a,0x152b,0x152c,0x152d,0x152e,0x152f,
+ 0x1530,0x1531,0x1532,0x1533,0x1534,0x1535,0x1536,0x1537,
+ 0x1538,0x1539,0x153a,0x153b,0x153c,0x153d,0x153e,0x153f,
+ 0x1540,0x1541,0x1542,0x1543,0x1544,0x1545,0x1546,0x1547,
+ 0x1548,0x1549,0x154a,0x154b,0x154c,0x154d,0x154e,0x154f,
+ 0x1550,0x1551,0x1552,0x1553,0x1554,0x1555,0x1556,0x1557,
+ 0x1558,0x1559,0x155a,0x155b,0x155c,0x155d,0x155e,0x155f,
+ 0x1560,0x1561,0x1562,0x1563,0x1564,0x1565,0x1566,0x1567,
+ 0x1568,0x1569,0x156a,0x156b,0x156c,0x156d,0x156e,0x156f,
+ 0x1570,0x1571,0x1572,0x1573,0x1574,0x1575,0x1576,0x1577,
+ 0x1578,0x1579,0x157a,0x157b,0x157c,0x157d,0x157e,0x157f,
+ 0x1580,0x1581,0x1582,0x1583,0x1584,0x1585,0x1586,0x1587,
+ 0x1588,0x1589,0x158a,0x158b,0x158c,0x158d,0x158e,0x158f,
+ 0x1590,0x1591,0x1592,0x1593,0x1594,0x1595,0x1596,0x1597,
+ 0x1598,0x1599,0x159a,0x159b,0x159c,0x159d,0x159e,0x159f,
+ 0x15a0,0x15a1,0x15a2,0x15a3,0x15a4,0x15a5,0x15a6,0x15a7,
+ 0x15a8,0x15a9,0x15aa,0x15ab,0x15ac,0x15ad,0x15ae,0x15af,
+ 0x15b0,0x15b1,0x15b2,0x15b3,0x15b4,0x15b5,0x15b6,0x15b7,
+ 0x15b8,0x15b9,0x15ba,0x15bb,0x15bc,0x15bd,0x15be,0x15bf,
+ 0x15c0,0x15c1,0x15c2,0x15c3,0x15c4,0x15c5,0x15c6,0x15c7,
+ 0x15c8,0x15c9,0x15ca,0x15cb,0x15cc,0x15cd,0x15ce,0x15cf,
+ 0x15d0,0x15d1,0x15d2,0x15d3,0x15d4,0x15d5,0x15d6,0x15d7,
+ 0x15d8,0x15d9,0x15da,0x15db,0x15dc,0x15dd,0x15de,0x15df,
+ 0x15e0,0x15e1,0x15e2,0x15e3,0x15e4,0x15e5,0x15e6,0x15e7,
+ 0x15e8,0x15e9,0x15ea,0x15eb,0x15ec,0x15ed,0x15ee,0x15ef,
+ 0x15f0,0x15f1,0x15f2,0x15f3,0x15f4,0x15f5,0x15f6,0x15f7,
+ 0x15f8,0x15f9,0x15fa,0x15fb,0x15fc,0x15fd,0x15fe,0x15ff,
+ 0x1600,0x1601,0x1602,0x1603,0x1604,0x1605,0x1606,0x1607,
+ 0x1608,0x1609,0x160a,0x160b,0x160c,0x160d,0x160e,0x160f,
+ 0x1610,0x1611,0x1612,0x1613,0x1614,0x1615,0x1616,0x1617,
+ 0x1618,0x1619,0x161a,0x161b,0x161c,0x161d,0x161e,0x161f,
+ 0x1620,0x1621,0x1622,0x1623,0x1624,0x1625,0x1626,0x1627,
+ 0x1628,0x1629,0x162a,0x162b,0x162c,0x162d,0x162e,0x162f,
+ 0x1630,0x1631,0x1632,0x1633,0x1634,0x1635,0x1636,0x1637,
+ 0x1638,0x1639,0x163a,0x163b,0x163c,0x163d,0x163e,0x163f,
+ 0x1640,0x1641,0x1642,0x1643,0x1644,0x1645,0x1646,0x1647,
+ 0x1648,0x1649,0x164a,0x164b,0x164c,0x164d,0x164e,0x164f,
+ 0x1650,0x1651,0x1652,0x1653,0x1654,0x1655,0x1656,0x1657,
+ 0x1658,0x1659,0x165a,0x165b,0x165c,0x165d,0x165e,0x165f,
+ 0x1660,0x1661,0x1662,0x1663,0x1664,0x1665,0x1666,0x1667,
+ 0x1668,0x1669,0x166a,0x166b,0x166c,0x166d,0x166e,0x166f,
+ 0x1670,0x1671,0x1672,0x1673,0x1674,0x1675,0x1676,0x1677,
+ 0x1678,0x1679,0x167a,0x167b,0x167c,0x167d,0x167e,0x167f,
+ 0x1680,0x1681,0x1682,0x1683,0x1684,0x1685,0x1686,0x1687,
+ 0x1688,0x1689,0x168a,0x168b,0x168c,0x168d,0x168e,0x168f,
+ 0x1690,0x1691,0x1692,0x1693,0x1694,0x1695,0x1696,0x1697,
+ 0x1698,0x1699,0x169a,0x169b,0x169c,0x169d,0x169e,0x169f,
+ 0x16a0,0x16a1,0x16a2,0x16a3,0x16a4,0x16a5,0x16a6,0x16a7,
+ 0x16a8,0x16a9,0x16aa,0x16ab,0x16ac,0x16ad,0x16ae,0x16af,
+ 0x16b0,0x16b1,0x16b2,0x16b3,0x16b4,0x16b5,0x16b6,0x16b7,
+ 0x16b8,0x16b9,0x16ba,0x16bb,0x16bc,0x16bd,0x16be,0x16bf,
+ 0x16c0,0x16c1,0x16c2,0x16c3,0x16c4,0x16c5,0x16c6,0x16c7,
+ 0x16c8,0x16c9,0x16ca,0x16cb,0x16cc,0x16cd,0x16ce,0x16cf,
+ 0x16d0,0x16d1,0x16d2,0x16d3,0x16d4,0x16d5,0x16d6,0x16d7,
+ 0x16d8,0x16d9,0x16da,0x16db,0x16dc,0x16dd,0x16de,0x16df,
+ 0x16e0,0x16e1,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,
+ 0x16e8,0x16e9,0x16ea,0x16eb,0x16ec,0x16ed,0x16ee,0x16ef,
+ 0x16f0,0x16f1,0x16f2,0x16f3,0x16f4,0x16f5,0x16f6,0x16f7,
+ 0x16f8,0x16f9,0x16fa,0x16fb,0x16fc,0x16fd,0x16fe,0x16ff,
+ 0x1700,0x1701,0x1702,0x1703,0x1704,0x1705,0x1706,0x1707,
+ 0x1708,0x1709,0x170a,0x170b,0x170c,0x170d,0x170e,0x170f,
+ 0x1710,0x1711,0x1712,0x1713,0x1714,0x1715,0x1716,0x1717,
+ 0x1718,0x1719,0x171a,0x171b,0x171c,0x171d,0x171e,0x171f,
+ 0x1720,0x1721,0x1722,0x1723,0x1724,0x1725,0x1726,0x1727,
+ 0x1728,0x1729,0x172a,0x172b,0x172c,0x172d,0x172e,0x172f,
+ 0x1730,0x1731,0x1732,0x1733,0x1734,0x1735,0x1736,0x1737,
+ 0x1738,0x1739,0x173a,0x173b,0x173c,0x173d,0x173e,0x173f,
+ 0x1740,0x1741,0x1742,0x1743,0x1744,0x1745,0x1746,0x1747,
+ 0x1748,0x1749,0x174a,0x174b,0x174c,0x174d,0x174e,0x174f,
+ 0x1750,0x1751,0x1752,0x1753,0x1754,0x1755,0x1756,0x1757,
+ 0x1758,0x1759,0x175a,0x175b,0x175c,0x175d,0x175e,0x175f,
+ 0x1760,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,
+ 0x1768,0x1769,0x176a,0x176b,0x176c,0x176d,0x176e,0x176f,
+ 0x1770,0x1771,0x1772,0x1773,0x1774,0x1775,0x1776,0x1777,
+ 0x1778,0x1779,0x177a,0x177b,0x177c,0x177d,0x177e,0x177f,
+ 0x1780,0x1781,0x1782,0x1783,0x1784,0x1785,0x1786,0x1787,
+ 0x1788,0x1789,0x178a,0x178b,0x178c,0x178d,0x178e,0x178f,
+ 0x1790,0x1791,0x1792,0x1793,0x1794,0x1795,0x1796,0x1797,
+ 0x1798,0x1799,0x179a,0x179b,0x179c,0x179d,0x179e,0x179f,
+ 0x17a0,0x17a1,0x17a2,0x17a3,0x17a4,0x17a5,0x17a6,0x17a7,
+ 0x17a8,0x17a9,0x17aa,0x17ab,0x17ac,0x17ad,0x17ae,0x17af,
+ 0x17b0,0x17b1,0x17b2,0x17b3,0x17b4,0x17b5,0x17b6,0x17b7,
+ 0x17b8,0x17b9,0x17ba,0x17bb,0x17bc,0x17bd,0x17be,0x17bf,
+ 0x17c0,0x17c1,0x17c2,0x17c3,0x17c4,0x17c5,0x17c6,0x17c7,
+ 0x17c8,0x17c9,0x17ca,0x17cb,0x17cc,0x17cd,0x17ce,0x17cf,
+ 0x17d0,0x17d1,0x17d2,0x17d3,0x17d4,0x17d5,0x17d6,0x17d7,
+ 0x17d8,0x17d9,0x17da,0x17db,0x17dc,0x17dd,0x17de,0x17df,
+ 0x17e0,0x17e1,0x17e2,0x17e3,0x17e4,0x17e5,0x17e6,0x17e7,
+ 0x17e8,0x17e9,0x17ea,0x17eb,0x17ec,0x17ed,0x17ee,0x17ef,
+ 0x17f0,0x17f1,0x17f2,0x17f3,0x17f4,0x17f5,0x17f6,0x17f7,
+ 0x17f8,0x17f9,0x17fa,0x17fb,0x17fc,0x17fd,0x17fe,0x17ff,
+ 0x1800,0x1801,0x1802,0x1803,0x1804,0x1805,0x1806,0x1807,
+ 0x1808,0x1809,0x180a,0x180b,0x180c,0x180d,0x180e,0x180f,
+ 0x1810,0x1811,0x1812,0x1813,0x1814,0x1815,0x1816,0x1817,
+ 0x1818,0x1819,0x181a,0x181b,0x181c,0x181d,0x181e,0x181f,
+ 0x1820,0x1821,0x1822,0x1823,0x1824,0x1825,0x1826,0x1827,
+ 0x1828,0x1829,0x182a,0x182b,0x182c,0x182d,0x182e,0x182f,
+ 0x1830,0x1831,0x1832,0x1833,0x1834,0x1835,0x1836,0x1837,
+ 0x1838,0x1839,0x183a,0x183b,0x183c,0x183d,0x183e,0x183f,
+ 0x1840,0x1841,0x1842,0x1843,0x1844,0x1845,0x1846,0x1847,
+ 0x1848,0x1849,0x184a,0x184b,0x184c,0x184d,0x184e,0x184f,
+ 0x1850,0x1851,0x1852,0x1853,0x1854,0x1855,0x1856,0x1857,
+ 0x1858,0x1859,0x185a,0x185b,0x185c,0x185d,0x185e,0x185f,
+ 0x1860,0x1861,0x1862,0x1863,0x1864,0x1865,0x1866,0x1867,
+ 0x1868,0x1869,0x186a,0x186b,0x186c,0x186d,0x186e,0x186f,
+ 0x1870,0x1871,0x1872,0x1873,0x1874,0x1875,0x1876,0x1877,
+ 0x1878,0x1879,0x187a,0x187b,0x187c,0x187d,0x187e,0x187f,
+ 0x1880,0x1881,0x1882,0x1883,0x1884,0x1885,0x1886,0x1887,
+ 0x1888,0x1889,0x188a,0x188b,0x188c,0x188d,0x188e,0x188f,
+ 0x1890,0x1891,0x1892,0x1893,0x1894,0x1895,0x1896,0x1897,
+ 0x1898,0x1899,0x189a,0x189b,0x189c,0x189d,0x189e,0x189f,
+ 0x18a0,0x18a1,0x18a2,0x18a3,0x18a4,0x18a5,0x18a6,0x18a7,
+ 0x18a8,0x18a9,0x18aa,0x18ab,0x18ac,0x18ad,0x18ae,0x18af,
+ 0x18b0,0x18b1,0x18b2,0x18b3,0x18b4,0x18b5,0x18b6,0x18b7,
+ 0x18b8,0x18b9,0x18ba,0x18bb,0x18bc,0x18bd,0x18be,0x18bf,
+ 0x18c0,0x18c1,0x18c2,0x18c3,0x18c4,0x18c5,0x18c6,0x18c7,
+ 0x18c8,0x18c9,0x18ca,0x18cb,0x18cc,0x18cd,0x18ce,0x18cf,
+ 0x18d0,0x18d1,0x18d2,0x18d3,0x18d4,0x18d5,0x18d6,0x18d7,
+ 0x18d8,0x18d9,0x18da,0x18db,0x18dc,0x18dd,0x18de,0x18df,
+ 0x18e0,0x18e1,0x18e2,0x18e3,0x18e4,0x18e5,0x18e6,0x18e7,
+ 0x18e8,0x18e9,0x18ea,0x18eb,0x18ec,0x18ed,0x18ee,0x18ef,
+ 0x18f0,0x18f1,0x18f2,0x18f3,0x18f4,0x18f5,0x18f6,0x18f7,
+ 0x18f8,0x18f9,0x18fa,0x18fb,0x18fc,0x18fd,0x18fe,0x18ff,
+ 0x1900,0x1901,0x1902,0x1903,0x1904,0x1905,0x1906,0x1907,
+ 0x1908,0x1909,0x190a,0x190b,0x190c,0x190d,0x190e,0x190f,
+ 0x1910,0x1911,0x1912,0x1913,0x1914,0x1915,0x1916,0x1917,
+ 0x1918,0x1919,0x191a,0x191b,0x191c,0x191d,0x191e,0x191f,
+ 0x1920,0x1921,0x1922,0x1923,0x1924,0x1925,0x1926,0x1927,
+ 0x1928,0x1929,0x192a,0x192b,0x192c,0x192d,0x192e,0x192f,
+ 0x1930,0x1931,0x1932,0x1933,0x1934,0x1935,0x1936,0x1937,
+ 0x1938,0x1939,0x193a,0x193b,0x193c,0x193d,0x193e,0x193f,
+ 0x1940,0x1941,0x1942,0x1943,0x1944,0x1945,0x1946,0x1947,
+ 0x1948,0x1949,0x194a,0x194b,0x194c,0x194d,0x194e,0x194f,
+ 0x1950,0x1951,0x1952,0x1953,0x1954,0x1955,0x1956,0x1957,
+ 0x1958,0x1959,0x195a,0x195b,0x195c,0x195d,0x195e,0x195f,
+ 0x1960,0x1961,0x1962,0x1963,0x1964,0x1965,0x1966,0x1967,
+ 0x1968,0x1969,0x196a,0x196b,0x196c,0x196d,0x196e,0x196f,
+ 0x1970,0x1971,0x1972,0x1973,0x1974,0x1975,0x1976,0x1977,
+ 0x1978,0x1979,0x197a,0x197b,0x197c,0x197d,0x197e,0x197f,
+ 0x1980,0x1981,0x1982,0x1983,0x1984,0x1985,0x1986,0x1987,
+ 0x1988,0x1989,0x198a,0x198b,0x198c,0x198d,0x198e,0x198f,
+ 0x1990,0x1991,0x1992,0x1993,0x1994,0x1995,0x1996,0x1997,
+ 0x1998,0x1999,0x199a,0x199b,0x199c,0x199d,0x199e,0x199f,
+ 0x19a0,0x19a1,0x19a2,0x19a3,0x19a4,0x19a5,0x19a6,0x19a7,
+ 0x19a8,0x19a9,0x19aa,0x19ab,0x19ac,0x19ad,0x19ae,0x19af,
+ 0x19b0,0x19b1,0x19b2,0x19b3,0x19b4,0x19b5,0x19b6,0x19b7,
+ 0x19b8,0x19b9,0x19ba,0x19bb,0x19bc,0x19bd,0x19be,0x19bf,
+ 0x19c0,0x19c1,0x19c2,0x19c3,0x19c4,0x19c5,0x19c6,0x19c7,
+ 0x19c8,0x19c9,0x19ca,0x19cb,0x19cc,0x19cd,0x19ce,0x19cf,
+ 0x19d0,0x19d1,0x19d2,0x19d3,0x19d4,0x19d5,0x19d6,0x19d7,
+ 0x19d8,0x19d9,0x19da,0x19db,0x19dc,0x19dd,0x19de,0x19df,
+ 0x19e0,0x19e1,0x19e2,0x19e3,0x19e4,0x19e5,0x19e6,0x19e7,
+ 0x19e8,0x19e9,0x19ea,0x19eb,0x19ec,0x19ed,0x19ee,0x19ef,
+ 0x19f0,0x19f1,0x19f2,0x19f3,0x19f4,0x19f5,0x19f6,0x19f7,
+ 0x19f8,0x19f9,0x19fa,0x19fb,0x19fc,0x19fd,0x19fe,0x19ff,
+ 0x1a00,0x1a01,0x1a02,0x1a03,0x1a04,0x1a05,0x1a06,0x1a07,
+ 0x1a08,0x1a09,0x1a0a,0x1a0b,0x1a0c,0x1a0d,0x1a0e,0x1a0f,
+ 0x1a10,0x1a11,0x1a12,0x1a13,0x1a14,0x1a15,0x1a16,0x1a17,
+ 0x1a18,0x1a19,0x1a1a,0x1a1b,0x1a1c,0x1a1d,0x1a1e,0x1a1f,
+ 0x1a20,0x1a21,0x1a22,0x1a23,0x1a24,0x1a25,0x1a26,0x1a27,
+ 0x1a28,0x1a29,0x1a2a,0x1a2b,0x1a2c,0x1a2d,0x1a2e,0x1a2f,
+ 0x1a30,0x1a31,0x1a32,0x1a33,0x1a34,0x1a35,0x1a36,0x1a37,
+ 0x1a38,0x1a39,0x1a3a,0x1a3b,0x1a3c,0x1a3d,0x1a3e,0x1a3f,
+ 0x1a40,0x1a41,0x1a42,0x1a43,0x1a44,0x1a45,0x1a46,0x1a47,
+ 0x1a48,0x1a49,0x1a4a,0x1a4b,0x1a4c,0x1a4d,0x1a4e,0x1a4f,
+ 0x1a50,0x1a51,0x1a52,0x1a53,0x1a54,0x1a55,0x1a56,0x1a57,
+ 0x1a58,0x1a59,0x1a5a,0x1a5b,0x1a5c,0x1a5d,0x1a5e,0x1a5f,
+ 0x1a60,0x1a61,0x1a62,0x1a63,0x1a64,0x1a65,0x1a66,0x1a67,
+ 0x1a68,0x1a69,0x1a6a,0x1a6b,0x1a6c,0x1a6d,0x1a6e,0x1a6f,
+ 0x1a70,0x1a71,0x1a72,0x1a73,0x1a74,0x1a75,0x1a76,0x1a77,
+ 0x1a78,0x1a79,0x1a7a,0x1a7b,0x1a7c,0x1a7d,0x1a7e,0x1a7f,
+ 0x1a80,0x1a81,0x1a82,0x1a83,0x1a84,0x1a85,0x1a86,0x1a87,
+ 0x1a88,0x1a89,0x1a8a,0x1a8b,0x1a8c,0x1a8d,0x1a8e,0x1a8f,
+ 0x1a90,0x1a91,0x1a92,0x1a93,0x1a94,0x1a95,0x1a96,0x1a97,
+ 0x1a98,0x1a99,0x1a9a,0x1a9b,0x1a9c,0x1a9d,0x1a9e,0x1a9f,
+ 0x1aa0,0x1aa1,0x1aa2,0x1aa3,0x1aa4,0x1aa5,0x1aa6,0x1aa7,
+ 0x1aa8,0x1aa9,0x1aaa,0x1aab,0x1aac,0x1aad,0x1aae,0x1aaf,
+ 0x1ab0,0x1ab1,0x1ab2,0x1ab3,0x1ab4,0x1ab5,0x1ab6,0x1ab7,
+ 0x1ab8,0x1ab9,0x1aba,0x1abb,0x1abc,0x1abd,0x1abe,0x1abf,
+ 0x1ac0,0x1ac1,0x1ac2,0x1ac3,0x1ac4,0x1ac5,0x1ac6,0x1ac7,
+ 0x1ac8,0x1ac9,0x1aca,0x1acb,0x1acc,0x1acd,0x1ace,0x1acf,
+ 0x1ad0,0x1ad1,0x1ad2,0x1ad3,0x1ad4,0x1ad5,0x1ad6,0x1ad7,
+ 0x1ad8,0x1ad9,0x1ada,0x1adb,0x1adc,0x1add,0x1ade,0x1adf,
+ 0x1ae0,0x1ae1,0x1ae2,0x1ae3,0x1ae4,0x1ae5,0x1ae6,0x1ae7,
+ 0x1ae8,0x1ae9,0x1aea,0x1aeb,0x1aec,0x1aed,0x1aee,0x1aef,
+ 0x1af0,0x1af1,0x1af2,0x1af3,0x1af4,0x1af5,0x1af6,0x1af7,
+ 0x1af8,0x1af9,0x1afa,0x1afb,0x1afc,0x1afd,0x1afe,0x1aff,
+ 0x1b00,0x1b01,0x1b02,0x1b03,0x1b04,0x1b05,0x1b06,0x1b07,
+ 0x1b08,0x1b09,0x1b0a,0x1b0b,0x1b0c,0x1b0d,0x1b0e,0x1b0f,
+ 0x1b10,0x1b11,0x1b12,0x1b13,0x1b14,0x1b15,0x1b16,0x1b17,
+ 0x1b18,0x1b19,0x1b1a,0x1b1b,0x1b1c,0x1b1d,0x1b1e,0x1b1f,
+ 0x1b20,0x1b21,0x1b22,0x1b23,0x1b24,0x1b25,0x1b26,0x1b27,
+ 0x1b28,0x1b29,0x1b2a,0x1b2b,0x1b2c,0x1b2d,0x1b2e,0x1b2f,
+ 0x1b30,0x1b31,0x1b32,0x1b33,0x1b34,0x1b35,0x1b36,0x1b37,
+ 0x1b38,0x1b39,0x1b3a,0x1b3b,0x1b3c,0x1b3d,0x1b3e,0x1b3f,
+ 0x1b40,0x1b41,0x1b42,0x1b43,0x1b44,0x1b45,0x1b46,0x1b47,
+ 0x1b48,0x1b49,0x1b4a,0x1b4b,0x1b4c,0x1b4d,0x1b4e,0x1b4f,
+ 0x1b50,0x1b51,0x1b52,0x1b53,0x1b54,0x1b55,0x1b56,0x1b57,
+ 0x1b58,0x1b59,0x1b5a,0x1b5b,0x1b5c,0x1b5d,0x1b5e,0x1b5f,
+ 0x1b60,0x1b61,0x1b62,0x1b63,0x1b64,0x1b65,0x1b66,0x1b67,
+ 0x1b68,0x1b69,0x1b6a,0x1b6b,0x1b6c,0x1b6d,0x1b6e,0x1b6f,
+ 0x1b70,0x1b71,0x1b72,0x1b73,0x1b74,0x1b75,0x1b76,0x1b77,
+ 0x1b78,0x1b79,0x1b7a,0x1b7b,0x1b7c,0x1b7d,0x1b7e,0x1b7f,
+ 0x1b80,0x1b81,0x1b82,0x1b83,0x1b84,0x1b85,0x1b86,0x1b87,
+ 0x1b88,0x1b89,0x1b8a,0x1b8b,0x1b8c,0x1b8d,0x1b8e,0x1b8f,
+ 0x1b90,0x1b91,0x1b92,0x1b93,0x1b94,0x1b95,0x1b96,0x1b97,
+ 0x1b98,0x1b99,0x1b9a,0x1b9b,0x1b9c,0x1b9d,0x1b9e,0x1b9f,
+ 0x1ba0,0x1ba1,0x1ba2,0x1ba3,0x1ba4,0x1ba5,0x1ba6,0x1ba7,
+ 0x1ba8,0x1ba9,0x1baa,0x1bab,0x1bac,0x1bad,0x1bae,0x1baf,
+ 0x1bb0,0x1bb1,0x1bb2,0x1bb3,0x1bb4,0x1bb5,0x1bb6,0x1bb7,
+ 0x1bb8,0x1bb9,0x1bba,0x1bbb,0x1bbc,0x1bbd,0x1bbe,0x1bbf,
+ 0x1bc0,0x1bc1,0x1bc2,0x1bc3,0x1bc4,0x1bc5,0x1bc6,0x1bc7,
+ 0x1bc8,0x1bc9,0x1bca,0x1bcb,0x1bcc,0x1bcd,0x1bce,0x1bcf,
+ 0x1bd0,0x1bd1,0x1bd2,0x1bd3,0x1bd4,0x1bd5,0x1bd6,0x1bd7,
+ 0x1bd8,0x1bd9,0x1bda,0x1bdb,0x1bdc,0x1bdd,0x1bde,0x1bdf,
+ 0x1be0,0x1be1,0x1be2,0x1be3,0x1be4,0x1be5,0x1be6,0x1be7,
+ 0x1be8,0x1be9,0x1bea,0x1beb,0x1bec,0x1bed,0x1bee,0x1bef,
+ 0x1bf0,0x1bf1,0x1bf2,0x1bf3,0x1bf4,0x1bf5,0x1bf6,0x1bf7,
+ 0x1bf8,0x1bf9,0x1bfa,0x1bfb,0x1bfc,0x1bfd,0x1bfe,0x1bff,
+ 0x1c00,0x1c01,0x1c02,0x1c03,0x1c04,0x1c05,0x1c06,0x1c07,
+ 0x1c08,0x1c09,0x1c0a,0x1c0b,0x1c0c,0x1c0d,0x1c0e,0x1c0f,
+ 0x1c10,0x1c11,0x1c12,0x1c13,0x1c14,0x1c15,0x1c16,0x1c17,
+ 0x1c18,0x1c19,0x1c1a,0x1c1b,0x1c1c,0x1c1d,0x1c1e,0x1c1f,
+ 0x1c20,0x1c21,0x1c22,0x1c23,0x1c24,0x1c25,0x1c26,0x1c27,
+ 0x1c28,0x1c29,0x1c2a,0x1c2b,0x1c2c,0x1c2d,0x1c2e,0x1c2f,
+ 0x1c30,0x1c31,0x1c32,0x1c33,0x1c34,0x1c35,0x1c36,0x1c37,
+ 0x1c38,0x1c39,0x1c3a,0x1c3b,0x1c3c,0x1c3d,0x1c3e,0x1c3f,
+ 0x1c40,0x1c41,0x1c42,0x1c43,0x1c44,0x1c45,0x1c46,0x1c47,
+ 0x1c48,0x1c49,0x1c4a,0x1c4b,0x1c4c,0x1c4d,0x1c4e,0x1c4f,
+ 0x1c50,0x1c51,0x1c52,0x1c53,0x1c54,0x1c55,0x1c56,0x1c57,
+ 0x1c58,0x1c59,0x1c5a,0x1c5b,0x1c5c,0x1c5d,0x1c5e,0x1c5f,
+ 0x1c60,0x1c61,0x1c62,0x1c63,0x1c64,0x1c65,0x1c66,0x1c67,
+ 0x1c68,0x1c69,0x1c6a,0x1c6b,0x1c6c,0x1c6d,0x1c6e,0x1c6f,
+ 0x1c70,0x1c71,0x1c72,0x1c73,0x1c74,0x1c75,0x1c76,0x1c77,
+ 0x1c78,0x1c79,0x1c7a,0x1c7b,0x1c7c,0x1c7d,0x1c7e,0x1c7f,
+ 0x1c80,0x1c81,0x1c82,0x1c83,0x1c84,0x1c85,0x1c86,0x1c87,
+ 0x1c88,0x1c89,0x1c8a,0x1c8b,0x1c8c,0x1c8d,0x1c8e,0x1c8f,
+ 0x1c90,0x1c91,0x1c92,0x1c93,0x1c94,0x1c95,0x1c96,0x1c97,
+ 0x1c98,0x1c99,0x1c9a,0x1c9b,0x1c9c,0x1c9d,0x1c9e,0x1c9f,
+ 0x1ca0,0x1ca1,0x1ca2,0x1ca3,0x1ca4,0x1ca5,0x1ca6,0x1ca7,
+ 0x1ca8,0x1ca9,0x1caa,0x1cab,0x1cac,0x1cad,0x1cae,0x1caf,
+ 0x1cb0,0x1cb1,0x1cb2,0x1cb3,0x1cb4,0x1cb5,0x1cb6,0x1cb7,
+ 0x1cb8,0x1cb9,0x1cba,0x1cbb,0x1cbc,0x1cbd,0x1cbe,0x1cbf,
+ 0x1cc0,0x1cc1,0x1cc2,0x1cc3,0x1cc4,0x1cc5,0x1cc6,0x1cc7,
+ 0x1cc8,0x1cc9,0x1cca,0x1ccb,0x1ccc,0x1ccd,0x1cce,0x1ccf,
+ 0x1cd0,0x1cd1,0x1cd2,0x1cd3,0x1cd4,0x1cd5,0x1cd6,0x1cd7,
+ 0x1cd8,0x1cd9,0x1cda,0x1cdb,0x1cdc,0x1cdd,0x1cde,0x1cdf,
+ 0x1ce0,0x1ce1,0x1ce2,0x1ce3,0x1ce4,0x1ce5,0x1ce6,0x1ce7,
+ 0x1ce8,0x1ce9,0x1cea,0x1ceb,0x1cec,0x1ced,0x1cee,0x1cef,
+ 0x1cf0,0x1cf1,0x1cf2,0x1cf3,0x1cf4,0x1cf5,0x1cf6,0x1cf7,
+ 0x1cf8,0x1cf9,0x1cfa,0x1cfb,0x1cfc,0x1cfd,0x1cfe,0x1cff,
+ 0x1d00,0x1d01,0x1d02,0x1d03,0x1d04,0x1d05,0x1d06,0x1d07,
+ 0x1d08,0x1d09,0x1d0a,0x1d0b,0x1d0c,0x1d0d,0x1d0e,0x1d0f,
+ 0x1d10,0x1d11,0x1d12,0x1d13,0x1d14,0x1d15,0x1d16,0x1d17,
+ 0x1d18,0x1d19,0x1d1a,0x1d1b,0x1d1c,0x1d1d,0x1d1e,0x1d1f,
+ 0x1d20,0x1d21,0x1d22,0x1d23,0x1d24,0x1d25,0x1d26,0x1d27,
+ 0x1d28,0x1d29,0x1d2a,0x1d2b,0x1d2c,0x1d2d,0x1d2e,0x1d2f,
+ 0x1d30,0x1d31,0x1d32,0x1d33,0x1d34,0x1d35,0x1d36,0x1d37,
+ 0x1d38,0x1d39,0x1d3a,0x1d3b,0x1d3c,0x1d3d,0x1d3e,0x1d3f,
+ 0x1d40,0x1d41,0x1d42,0x1d43,0x1d44,0x1d45,0x1d46,0x1d47,
+ 0x1d48,0x1d49,0x1d4a,0x1d4b,0x1d4c,0x1d4d,0x1d4e,0x1d4f,
+ 0x1d50,0x1d51,0x1d52,0x1d53,0x1d54,0x1d55,0x1d56,0x1d57,
+ 0x1d58,0x1d59,0x1d5a,0x1d5b,0x1d5c,0x1d5d,0x1d5e,0x1d5f,
+ 0x1d60,0x1d61,0x1d62,0x1d63,0x1d64,0x1d65,0x1d66,0x1d67,
+ 0x1d68,0x1d69,0x1d6a,0x1d6b,0x1d6c,0x1d6d,0x1d6e,0x1d6f,
+ 0x1d70,0x1d71,0x1d72,0x1d73,0x1d74,0x1d75,0x1d76,0x1d77,
+ 0x1d78,0x1d79,0x1d7a,0x1d7b,0x1d7c,0x1d7d,0x1d7e,0x1d7f,
+ 0x1d80,0x1d81,0x1d82,0x1d83,0x1d84,0x1d85,0x1d86,0x1d87,
+ 0x1d88,0x1d89,0x1d8a,0x1d8b,0x1d8c,0x1d8d,0x1d8e,0x1d8f,
+ 0x1d90,0x1d91,0x1d92,0x1d93,0x1d94,0x1d95,0x1d96,0x1d97,
+ 0x1d98,0x1d99,0x1d9a,0x1d9b,0x1d9c,0x1d9d,0x1d9e,0x1d9f,
+ 0x1da0,0x1da1,0x1da2,0x1da3,0x1da4,0x1da5,0x1da6,0x1da7,
+ 0x1da8,0x1da9,0x1daa,0x1dab,0x1dac,0x1dad,0x1dae,0x1daf,
+ 0x1db0,0x1db1,0x1db2,0x1db3,0x1db4,0x1db5,0x1db6,0x1db7,
+ 0x1db8,0x1db9,0x1dba,0x1dbb,0x1dbc,0x1dbd,0x1dbe,0x1dbf,
+ 0x1dc0,0x1dc1,0x1dc2,0x1dc3,0x1dc4,0x1dc5,0x1dc6,0x1dc7,
+ 0x1dc8,0x1dc9,0x1dca,0x1dcb,0x1dcc,0x1dcd,0x1dce,0x1dcf,
+ 0x1dd0,0x1dd1,0x1dd2,0x1dd3,0x1dd4,0x1dd5,0x1dd6,0x1dd7,
+ 0x1dd8,0x1dd9,0x1dda,0x1ddb,0x1ddc,0x1ddd,0x1dde,0x1ddf,
+ 0x1de0,0x1de1,0x1de2,0x1de3,0x1de4,0x1de5,0x1de6,0x1de7,
+ 0x1de8,0x1de9,0x1dea,0x1deb,0x1dec,0x1ded,0x1dee,0x1def,
+ 0x1df0,0x1df1,0x1df2,0x1df3,0x1df4,0x1df5,0x1df6,0x1df7,
+ 0x1df8,0x1df9,0x1dfa,0x1dfb,0x1dfc,0x1dfd,0x1dfe,0x1dff,
+ 0x1e00,0x1e00,0x1e02,0x1e02,0x1e04,0x1e04,0x1e06,0x1e06,
+ 0x1e08,0x1e08,0x1e0a,0x1e0a,0x1e0c,0x1e0c,0x1e0e,0x1e0e,
+ 0x1e10,0x1e10,0x1e12,0x1e12,0x1e14,0x1e14,0x1e16,0x1e16,
+ 0x1e18,0x1e18,0x1e1a,0x1e1a,0x1e1c,0x1e1c,0x1e1e,0x1e1e,
+ 0x1e20,0x1e20,0x1e22,0x1e22,0x1e24,0x1e24,0x1e26,0x1e26,
+ 0x1e28,0x1e28,0x1e2a,0x1e2a,0x1e2c,0x1e2c,0x1e2e,0x1e2e,
+ 0x1e30,0x1e30,0x1e32,0x1e32,0x1e34,0x1e34,0x1e36,0x1e36,
+ 0x1e38,0x1e38,0x1e3a,0x1e3a,0x1e3c,0x1e3c,0x1e3e,0x1e3e,
+ 0x1e40,0x1e40,0x1e42,0x1e42,0x1e44,0x1e44,0x1e46,0x1e46,
+ 0x1e48,0x1e48,0x1e4a,0x1e4a,0x1e4c,0x1e4c,0x1e4e,0x1e4e,
+ 0x1e50,0x1e50,0x1e52,0x1e52,0x1e54,0x1e54,0x1e56,0x1e56,
+ 0x1e58,0x1e58,0x1e5a,0x1e5a,0x1e5c,0x1e5c,0x1e5e,0x1e5e,
+ 0x1e60,0x1e60,0x1e62,0x1e62,0x1e64,0x1e64,0x1e66,0x1e66,
+ 0x1e68,0x1e68,0x1e6a,0x1e6a,0x1e6c,0x1e6c,0x1e6e,0x1e6e,
+ 0x1e70,0x1e70,0x1e72,0x1e72,0x1e74,0x1e74,0x1e76,0x1e76,
+ 0x1e78,0x1e78,0x1e7a,0x1e7a,0x1e7c,0x1e7c,0x1e7e,0x1e7e,
+ 0x1e80,0x1e80,0x1e82,0x1e82,0x1e84,0x1e84,0x1e86,0x1e86,
+ 0x1e88,0x1e88,0x1e8a,0x1e8a,0x1e8c,0x1e8c,0x1e8e,0x1e8e,
+ 0x1e90,0x1e90,0x1e92,0x1e92,0x1e94,0x1e94,0x1e96,0x1e97,
+ 0x1e98,0x1e99,0x1e9a,0x1e9b,0x1e9c,0x1e9d,0x1e9e,0x1e9f,
+ 0x1ea0,0x1ea0,0x1ea2,0x1ea2,0x1ea4,0x1ea4,0x1ea6,0x1ea6,
+ 0x1ea8,0x1ea8,0x1eaa,0x1eaa,0x1eac,0x1eac,0x1eae,0x1eae,
+ 0x1eb0,0x1eb0,0x1eb2,0x1eb2,0x1eb4,0x1eb4,0x1eb6,0x1eb6,
+ 0x1eb8,0x1eb8,0x1eba,0x1eba,0x1ebc,0x1ebc,0x1ebe,0x1ebe,
+ 0x1ec0,0x1ec0,0x1ec2,0x1ec2,0x1ec4,0x1ec4,0x1ec6,0x1ec6,
+ 0x1ec8,0x1ec8,0x1eca,0x1eca,0x1ecc,0x1ecc,0x1ece,0x1ece,
+ 0x1ed0,0x1ed0,0x1ed2,0x1ed2,0x1ed4,0x1ed4,0x1ed6,0x1ed6,
+ 0x1ed8,0x1ed8,0x1eda,0x1eda,0x1edc,0x1edc,0x1ede,0x1ede,
+ 0x1ee0,0x1ee0,0x1ee2,0x1ee2,0x1ee4,0x1ee4,0x1ee6,0x1ee6,
+ 0x1ee8,0x1ee8,0x1eea,0x1eea,0x1eec,0x1eec,0x1eee,0x1eee,
+ 0x1ef0,0x1ef0,0x1ef2,0x1ef2,0x1ef4,0x1ef4,0x1ef6,0x1ef6,
+ 0x1ef8,0x1ef8,0x1efa,0x1efb,0x1efc,0x1efd,0x1efe,0x1eff,
+ 0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f,
+ 0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f,
+ 0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f16,0x1f17,
+ 0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f1e,0x1f1f,
+ 0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f,
+ 0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f,
+ 0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f,
+ 0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f,
+ 0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f46,0x1f47,
+ 0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f4e,0x1f4f,
+ 0x1f50,0x1f59,0x1f52,0x1f5b,0x1f54,0x1f5d,0x1f56,0x1f5f,
+ 0x1f58,0x1f59,0x1f5a,0x1f5b,0x1f5c,0x1f5d,0x1f5e,0x1f5f,
+ 0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f,
+ 0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f,
+ 0x1fba,0x1fbb,0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fda,0x1fdb,
+ 0x1ff8,0x1ff9,0x1fea,0x1feb,0x1ffa,0x1ffb,0x1f7e,0x1f7f,
+ 0x1f80,0x1f81,0x1f82,0x1f83,0x1f84,0x1f85,0x1f86,0x1f87,
+ 0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f,
+ 0x1f90,0x1f91,0x1f92,0x1f93,0x1f94,0x1f95,0x1f96,0x1f97,
+ 0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f,
+ 0x1fa0,0x1fa1,0x1fa2,0x1fa3,0x1fa4,0x1fa5,0x1fa6,0x1fa7,
+ 0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf,
+ 0x1fb8,0x1fb9,0x1fb2,0x1fb3,0x1fb4,0x1fb5,0x1fb6,0x1fb7,
+ 0x1fb8,0x1fb9,0x1fba,0x1fbb,0x1fbc,0x1fbd,0x1fbe,0x1fbf,
+ 0x1fc0,0x1fc1,0x1fc2,0x1fc3,0x1fc4,0x1fc5,0x1fc6,0x1fc7,
+ 0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fcc,0x1fcd,0x1fce,0x1fcf,
+ 0x1fd8,0x1fd9,0x1fd2,0x1fd3,0x1fd4,0x1fd5,0x1fd6,0x1fd7,
+ 0x1fd8,0x1fd9,0x1fda,0x1fdb,0x1fdc,0x1fdd,0x1fde,0x1fdf,
+ 0x1fe8,0x1fe9,0x1fe2,0x1fe3,0x1fe4,0x1fec,0x1fe6,0x1fe7,
+ 0x1fe8,0x1fe9,0x1fea,0x1feb,0x1fec,0x1fed,0x1fee,0x1fef,
+ 0x1ff0,0x1ff1,0x1ff2,0x1ff3,0x1ff4,0x1ff5,0x1ff6,0x1ff7,
+ 0x1ff8,0x1ff9,0x1ffa,0x1ffb,0x1ffc,0x1ffd,0x1ffe,0x1fff,
+ 0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,
+ 0x2008,0x2009,0x200a,0x200b,0x200c,0x200d,0x200e,0x200f,
+ 0x2010,0x2011,0x2012,0x2013,0x2014,0x2015,0x2016,0x2017,
+ 0x2018,0x2019,0x201a,0x201b,0x201c,0x201d,0x201e,0x201f,
+ 0x2020,0x2021,0x2022,0x2023,0x2024,0x2025,0x2026,0x2027,
+ 0x2028,0x2029,0x202a,0x202b,0x202c,0x202d,0x202e,0x202f,
+ 0x2030,0x2031,0x2032,0x2033,0x2034,0x2035,0x2036,0x2037,
+ 0x2038,0x2039,0x203a,0x203b,0x203c,0x203d,0x203e,0x203f,
+ 0x2040,0x2041,0x2042,0x2043,0x2044,0x2045,0x2046,0x2047,
+ 0x2048,0x2049,0x204a,0x204b,0x204c,0x204d,0x204e,0x204f,
+ 0x2050,0x2051,0x2052,0x2053,0x2054,0x2055,0x2056,0x2057,
+ 0x2058,0x2059,0x205a,0x205b,0x205c,0x205d,0x205e,0x205f,
+ 0x2060,0x2061,0x2062,0x2063,0x2064,0x2065,0x2066,0x2067,
+ 0x2068,0x2069,0x206a,0x206b,0x206c,0x206d,0x206e,0x206f,
+ 0x2070,0x2071,0x2072,0x2073,0x2074,0x2075,0x2076,0x2077,
+ 0x2078,0x2079,0x207a,0x207b,0x207c,0x207d,0x207e,0x207f,
+ 0x2080,0x2081,0x2082,0x2083,0x2084,0x2085,0x2086,0x2087,
+ 0x2088,0x2089,0x208a,0x208b,0x208c,0x208d,0x208e,0x208f,
+ 0x2090,0x2091,0x2092,0x2093,0x2094,0x2095,0x2096,0x2097,
+ 0x2098,0x2099,0x209a,0x209b,0x209c,0x209d,0x209e,0x209f,
+ 0x20a0,0x20a1,0x20a2,0x20a3,0x20a4,0x20a5,0x20a6,0x20a7,
+ 0x20a8,0x20a9,0x20aa,0x20ab,0x20ac,0x20ad,0x20ae,0x20af,
+ 0x20b0,0x20b1,0x20b2,0x20b3,0x20b4,0x20b5,0x20b6,0x20b7,
+ 0x20b8,0x20b9,0x20ba,0x20bb,0x20bc,0x20bd,0x20be,0x20bf,
+ 0x20c0,0x20c1,0x20c2,0x20c3,0x20c4,0x20c5,0x20c6,0x20c7,
+ 0x20c8,0x20c9,0x20ca,0x20cb,0x20cc,0x20cd,0x20ce,0x20cf,
+ 0x20d0,0x20d1,0x20d2,0x20d3,0x20d4,0x20d5,0x20d6,0x20d7,
+ 0x20d8,0x20d9,0x20da,0x20db,0x20dc,0x20dd,0x20de,0x20df,
+ 0x20e0,0x20e1,0x20e2,0x20e3,0x20e4,0x20e5,0x20e6,0x20e7,
+ 0x20e8,0x20e9,0x20ea,0x20eb,0x20ec,0x20ed,0x20ee,0x20ef,
+ 0x20f0,0x20f1,0x20f2,0x20f3,0x20f4,0x20f5,0x20f6,0x20f7,
+ 0x20f8,0x20f9,0x20fa,0x20fb,0x20fc,0x20fd,0x20fe,0x20ff,
+ 0x2100,0x2101,0x2102,0x2103,0x2104,0x2105,0x2106,0x2107,
+ 0x2108,0x2109,0x210a,0x210b,0x210c,0x210d,0x210e,0x210f,
+ 0x2110,0x2111,0x2112,0x2113,0x2114,0x2115,0x2116,0x2117,
+ 0x2118,0x2119,0x211a,0x211b,0x211c,0x211d,0x211e,0x211f,
+ 0x2120,0x2121,0x2122,0x2123,0x2124,0x2125,0x2126,0x2127,
+ 0x2128,0x2129,0x212a,0x212b,0x212c,0x212d,0x212e,0x212f,
+ 0x2130,0x2131,0x2132,0x2133,0x2134,0x2135,0x2136,0x2137,
+ 0x2138,0x2139,0x213a,0x213b,0x213c,0x213d,0x213e,0x213f,
+ 0x2140,0x2141,0x2142,0x2143,0x2144,0x2145,0x2146,0x2147,
+ 0x2148,0x2149,0x214a,0x214b,0x214c,0x214d,0x214e,0x214f,
+ 0x2150,0x2151,0x2152,0x2153,0x2154,0x2155,0x2156,0x2157,
+ 0x2158,0x2159,0x215a,0x215b,0x215c,0x215d,0x215e,0x215f,
+ 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,
+ 0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f,
+ 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,
+ 0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f,
+ 0x2180,0x2181,0x2182,0x2183,0x2184,0x2185,0x2186,0x2187,
+ 0x2188,0x2189,0x218a,0x218b,0x218c,0x218d,0x218e,0x218f,
+ 0x2190,0x2191,0x2192,0x2193,0x2194,0x2195,0x2196,0x2197,
+ 0x2198,0x2199,0x219a,0x219b,0x219c,0x219d,0x219e,0x219f,
+ 0x21a0,0x21a1,0x21a2,0x21a3,0x21a4,0x21a5,0x21a6,0x21a7,
+ 0x21a8,0x21a9,0x21aa,0x21ab,0x21ac,0x21ad,0x21ae,0x21af,
+ 0x21b0,0x21b1,0x21b2,0x21b3,0x21b4,0x21b5,0x21b6,0x21b7,
+ 0x21b8,0x21b9,0x21ba,0x21bb,0x21bc,0x21bd,0x21be,0x21bf,
+ 0x21c0,0x21c1,0x21c2,0x21c3,0x21c4,0x21c5,0x21c6,0x21c7,
+ 0x21c8,0x21c9,0x21ca,0x21cb,0x21cc,0x21cd,0x21ce,0x21cf,
+ 0x21d0,0x21d1,0x21d2,0x21d3,0x21d4,0x21d5,0x21d6,0x21d7,
+ 0x21d8,0x21d9,0x21da,0x21db,0x21dc,0x21dd,0x21de,0x21df,
+ 0x21e0,0x21e1,0x21e2,0x21e3,0x21e4,0x21e5,0x21e6,0x21e7,
+ 0x21e8,0x21e9,0x21ea,0x21eb,0x21ec,0x21ed,0x21ee,0x21ef,
+ 0x21f0,0x21f1,0x21f2,0x21f3,0x21f4,0x21f5,0x21f6,0x21f7,
+ 0x21f8,0x21f9,0x21fa,0x21fb,0x21fc,0x21fd,0x21fe,0x21ff,
+ 0x2200,0x2201,0x2202,0x2203,0x2204,0x2205,0x2206,0x2207,
+ 0x2208,0x2209,0x220a,0x220b,0x220c,0x220d,0x220e,0x220f,
+ 0x2210,0x2211,0x2212,0x2213,0x2214,0x2215,0x2216,0x2217,
+ 0x2218,0x2219,0x221a,0x221b,0x221c,0x221d,0x221e,0x221f,
+ 0x2220,0x2221,0x2222,0x2223,0x2224,0x2225,0x2226,0x2227,
+ 0x2228,0x2229,0x222a,0x222b,0x222c,0x222d,0x222e,0x222f,
+ 0x2230,0x2231,0x2232,0x2233,0x2234,0x2235,0x2236,0x2237,
+ 0x2238,0x2239,0x223a,0x223b,0x223c,0x223d,0x223e,0x223f,
+ 0x2240,0x2241,0x2242,0x2243,0x2244,0x2245,0x2246,0x2247,
+ 0x2248,0x2249,0x224a,0x224b,0x224c,0x224d,0x224e,0x224f,
+ 0x2250,0x2251,0x2252,0x2253,0x2254,0x2255,0x2256,0x2257,
+ 0x2258,0x2259,0x225a,0x225b,0x225c,0x225d,0x225e,0x225f,
+ 0x2260,0x2261,0x2262,0x2263,0x2264,0x2265,0x2266,0x2267,
+ 0x2268,0x2269,0x226a,0x226b,0x226c,0x226d,0x226e,0x226f,
+ 0x2270,0x2271,0x2272,0x2273,0x2274,0x2275,0x2276,0x2277,
+ 0x2278,0x2279,0x227a,0x227b,0x227c,0x227d,0x227e,0x227f,
+ 0x2280,0x2281,0x2282,0x2283,0x2284,0x2285,0x2286,0x2287,
+ 0x2288,0x2289,0x228a,0x228b,0x228c,0x228d,0x228e,0x228f,
+ 0x2290,0x2291,0x2292,0x2293,0x2294,0x2295,0x2296,0x2297,
+ 0x2298,0x2299,0x229a,0x229b,0x229c,0x229d,0x229e,0x229f,
+ 0x22a0,0x22a1,0x22a2,0x22a3,0x22a4,0x22a5,0x22a6,0x22a7,
+ 0x22a8,0x22a9,0x22aa,0x22ab,0x22ac,0x22ad,0x22ae,0x22af,
+ 0x22b0,0x22b1,0x22b2,0x22b3,0x22b4,0x22b5,0x22b6,0x22b7,
+ 0x22b8,0x22b9,0x22ba,0x22bb,0x22bc,0x22bd,0x22be,0x22bf,
+ 0x22c0,0x22c1,0x22c2,0x22c3,0x22c4,0x22c5,0x22c6,0x22c7,
+ 0x22c8,0x22c9,0x22ca,0x22cb,0x22cc,0x22cd,0x22ce,0x22cf,
+ 0x22d0,0x22d1,0x22d2,0x22d3,0x22d4,0x22d5,0x22d6,0x22d7,
+ 0x22d8,0x22d9,0x22da,0x22db,0x22dc,0x22dd,0x22de,0x22df,
+ 0x22e0,0x22e1,0x22e2,0x22e3,0x22e4,0x22e5,0x22e6,0x22e7,
+ 0x22e8,0x22e9,0x22ea,0x22eb,0x22ec,0x22ed,0x22ee,0x22ef,
+ 0x22f0,0x22f1,0x22f2,0x22f3,0x22f4,0x22f5,0x22f6,0x22f7,
+ 0x22f8,0x22f9,0x22fa,0x22fb,0x22fc,0x22fd,0x22fe,0x22ff,
+ 0x2300,0x2301,0x2302,0x2303,0x2304,0x2305,0x2306,0x2307,
+ 0x2308,0x2309,0x230a,0x230b,0x230c,0x230d,0x230e,0x230f,
+ 0x2310,0x2311,0x2312,0x2313,0x2314,0x2315,0x2316,0x2317,
+ 0x2318,0x2319,0x231a,0x231b,0x231c,0x231d,0x231e,0x231f,
+ 0x2320,0x2321,0x2322,0x2323,0x2324,0x2325,0x2326,0x2327,
+ 0x2328,0x2329,0x232a,0x232b,0x232c,0x232d,0x232e,0x232f,
+ 0x2330,0x2331,0x2332,0x2333,0x2334,0x2335,0x2336,0x2337,
+ 0x2338,0x2339,0x233a,0x233b,0x233c,0x233d,0x233e,0x233f,
+ 0x2340,0x2341,0x2342,0x2343,0x2344,0x2345,0x2346,0x2347,
+ 0x2348,0x2349,0x234a,0x234b,0x234c,0x234d,0x234e,0x234f,
+ 0x2350,0x2351,0x2352,0x2353,0x2354,0x2355,0x2356,0x2357,
+ 0x2358,0x2359,0x235a,0x235b,0x235c,0x235d,0x235e,0x235f,
+ 0x2360,0x2361,0x2362,0x2363,0x2364,0x2365,0x2366,0x2367,
+ 0x2368,0x2369,0x236a,0x236b,0x236c,0x236d,0x236e,0x236f,
+ 0x2370,0x2371,0x2372,0x2373,0x2374,0x2375,0x2376,0x2377,
+ 0x2378,0x2379,0x237a,0x237b,0x237c,0x237d,0x237e,0x237f,
+ 0x2380,0x2381,0x2382,0x2383,0x2384,0x2385,0x2386,0x2387,
+ 0x2388,0x2389,0x238a,0x238b,0x238c,0x238d,0x238e,0x238f,
+ 0x2390,0x2391,0x2392,0x2393,0x2394,0x2395,0x2396,0x2397,
+ 0x2398,0x2399,0x239a,0x239b,0x239c,0x239d,0x239e,0x239f,
+ 0x23a0,0x23a1,0x23a2,0x23a3,0x23a4,0x23a5,0x23a6,0x23a7,
+ 0x23a8,0x23a9,0x23aa,0x23ab,0x23ac,0x23ad,0x23ae,0x23af,
+ 0x23b0,0x23b1,0x23b2,0x23b3,0x23b4,0x23b5,0x23b6,0x23b7,
+ 0x23b8,0x23b9,0x23ba,0x23bb,0x23bc,0x23bd,0x23be,0x23bf,
+ 0x23c0,0x23c1,0x23c2,0x23c3,0x23c4,0x23c5,0x23c6,0x23c7,
+ 0x23c8,0x23c9,0x23ca,0x23cb,0x23cc,0x23cd,0x23ce,0x23cf,
+ 0x23d0,0x23d1,0x23d2,0x23d3,0x23d4,0x23d5,0x23d6,0x23d7,
+ 0x23d8,0x23d9,0x23da,0x23db,0x23dc,0x23dd,0x23de,0x23df,
+ 0x23e0,0x23e1,0x23e2,0x23e3,0x23e4,0x23e5,0x23e6,0x23e7,
+ 0x23e8,0x23e9,0x23ea,0x23eb,0x23ec,0x23ed,0x23ee,0x23ef,
+ 0x23f0,0x23f1,0x23f2,0x23f3,0x23f4,0x23f5,0x23f6,0x23f7,
+ 0x23f8,0x23f9,0x23fa,0x23fb,0x23fc,0x23fd,0x23fe,0x23ff,
+ 0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407,
+ 0x2408,0x2409,0x240a,0x240b,0x240c,0x240d,0x240e,0x240f,
+ 0x2410,0x2411,0x2412,0x2413,0x2414,0x2415,0x2416,0x2417,
+ 0x2418,0x2419,0x241a,0x241b,0x241c,0x241d,0x241e,0x241f,
+ 0x2420,0x2421,0x2422,0x2423,0x2424,0x2425,0x2426,0x2427,
+ 0x2428,0x2429,0x242a,0x242b,0x242c,0x242d,0x242e,0x242f,
+ 0x2430,0x2431,0x2432,0x2433,0x2434,0x2435,0x2436,0x2437,
+ 0x2438,0x2439,0x243a,0x243b,0x243c,0x243d,0x243e,0x243f,
+ 0x2440,0x2441,0x2442,0x2443,0x2444,0x2445,0x2446,0x2447,
+ 0x2448,0x2449,0x244a,0x244b,0x244c,0x244d,0x244e,0x244f,
+ 0x2450,0x2451,0x2452,0x2453,0x2454,0x2455,0x2456,0x2457,
+ 0x2458,0x2459,0x245a,0x245b,0x245c,0x245d,0x245e,0x245f,
+ 0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
+ 0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,
+ 0x2470,0x2471,0x2472,0x2473,0x2474,0x2475,0x2476,0x2477,
+ 0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,
+ 0x2480,0x2481,0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,
+ 0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e,0x248f,
+ 0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497,
+ 0x2498,0x2499,0x249a,0x249b,0x249c,0x249d,0x249e,0x249f,
+ 0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5,0x24a6,0x24a7,
+ 0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af,
+ 0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x24b6,0x24b7,
+ 0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd,0x24be,0x24bf,
+ 0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5,0x24c6,0x24c7,
+ 0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd,0x24ce,0x24cf,
+ 0x24b6,0x24b7,0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd,
+ 0x24be,0x24bf,0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5,
+ 0x24c6,0x24c7,0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd,
+ 0x24ce,0x24cf,0x24ea,0x24eb,0x24ec,0x24ed,0x24ee,0x24ef,
+ 0x24f0,0x24f1,0x24f2,0x24f3,0x24f4,0x24f5,0x24f6,0x24f7,
+ 0x24f8,0x24f9,0x24fa,0x24fb,0x24fc,0x24fd,0x24fe,0x24ff,
+ 0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507,
+ 0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,
+ 0x2510,0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517,
+ 0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,0x251e,0x251f,
+ 0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,
+ 0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,
+ 0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,
+ 0x2538,0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,
+ 0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547,
+ 0x2548,0x2549,0x254a,0x254b,0x254c,0x254d,0x254e,0x254f,
+ 0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,
+ 0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,
+ 0x2560,0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567,
+ 0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,0x256e,0x256f,
+ 0x2570,0x2571,0x2572,0x2573,0x2574,0x2575,0x2576,0x2577,
+ 0x2578,0x2579,0x257a,0x257b,0x257c,0x257d,0x257e,0x257f,
+ 0x2580,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,
+ 0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,0x258e,0x258f,
+ 0x2590,0x2591,0x2592,0x2593,0x2594,0x2595,0x2596,0x2597,
+ 0x2598,0x2599,0x259a,0x259b,0x259c,0x259d,0x259e,0x259f,
+ 0x25a0,0x25a1,0x25a2,0x25a3,0x25a4,0x25a5,0x25a6,0x25a7,
+ 0x25a8,0x25a9,0x25aa,0x25ab,0x25ac,0x25ad,0x25ae,0x25af,
+ 0x25b0,0x25b1,0x25b2,0x25b3,0x25b4,0x25b5,0x25b6,0x25b7,
+ 0x25b8,0x25b9,0x25ba,0x25bb,0x25bc,0x25bd,0x25be,0x25bf,
+ 0x25c0,0x25c1,0x25c2,0x25c3,0x25c4,0x25c5,0x25c6,0x25c7,
+ 0x25c8,0x25c9,0x25ca,0x25cb,0x25cc,0x25cd,0x25ce,0x25cf,
+ 0x25d0,0x25d1,0x25d2,0x25d3,0x25d4,0x25d5,0x25d6,0x25d7,
+ 0x25d8,0x25d9,0x25da,0x25db,0x25dc,0x25dd,0x25de,0x25df,
+ 0x25e0,0x25e1,0x25e2,0x25e3,0x25e4,0x25e5,0x25e6,0x25e7,
+ 0x25e8,0x25e9,0x25ea,0x25eb,0x25ec,0x25ed,0x25ee,0x25ef,
+ 0x25f0,0x25f1,0x25f2,0x25f3,0x25f4,0x25f5,0x25f6,0x25f7,
+ 0x25f8,0x25f9,0x25fa,0x25fb,0x25fc,0x25fd,0x25fe,0x25ff,
+ 0x2600,0x2601,0x2602,0x2603,0x2604,0x2605,0x2606,0x2607,
+ 0x2608,0x2609,0x260a,0x260b,0x260c,0x260d,0x260e,0x260f,
+ 0x2610,0x2611,0x2612,0x2613,0x2614,0x2615,0x2616,0x2617,
+ 0x2618,0x2619,0x261a,0x261b,0x261c,0x261d,0x261e,0x261f,
+ 0x2620,0x2621,0x2622,0x2623,0x2624,0x2625,0x2626,0x2627,
+ 0x2628,0x2629,0x262a,0x262b,0x262c,0x262d,0x262e,0x262f,
+ 0x2630,0x2631,0x2632,0x2633,0x2634,0x2635,0x2636,0x2637,
+ 0x2638,0x2639,0x263a,0x263b,0x263c,0x263d,0x263e,0x263f,
+ 0x2640,0x2641,0x2642,0x2643,0x2644,0x2645,0x2646,0x2647,
+ 0x2648,0x2649,0x264a,0x264b,0x264c,0x264d,0x264e,0x264f,
+ 0x2650,0x2651,0x2652,0x2653,0x2654,0x2655,0x2656,0x2657,
+ 0x2658,0x2659,0x265a,0x265b,0x265c,0x265d,0x265e,0x265f,
+ 0x2660,0x2661,0x2662,0x2663,0x2664,0x2665,0x2666,0x2667,
+ 0x2668,0x2669,0x266a,0x266b,0x266c,0x266d,0x266e,0x266f,
+ 0x2670,0x2671,0x2672,0x2673,0x2674,0x2675,0x2676,0x2677,
+ 0x2678,0x2679,0x267a,0x267b,0x267c,0x267d,0x267e,0x267f,
+ 0x2680,0x2681,0x2682,0x2683,0x2684,0x2685,0x2686,0x2687,
+ 0x2688,0x2689,0x268a,0x268b,0x268c,0x268d,0x268e,0x268f,
+ 0x2690,0x2691,0x2692,0x2693,0x2694,0x2695,0x2696,0x2697,
+ 0x2698,0x2699,0x269a,0x269b,0x269c,0x269d,0x269e,0x269f,
+ 0x26a0,0x26a1,0x26a2,0x26a3,0x26a4,0x26a5,0x26a6,0x26a7,
+ 0x26a8,0x26a9,0x26aa,0x26ab,0x26ac,0x26ad,0x26ae,0x26af,
+ 0x26b0,0x26b1,0x26b2,0x26b3,0x26b4,0x26b5,0x26b6,0x26b7,
+ 0x26b8,0x26b9,0x26ba,0x26bb,0x26bc,0x26bd,0x26be,0x26bf,
+ 0x26c0,0x26c1,0x26c2,0x26c3,0x26c4,0x26c5,0x26c6,0x26c7,
+ 0x26c8,0x26c9,0x26ca,0x26cb,0x26cc,0x26cd,0x26ce,0x26cf,
+ 0x26d0,0x26d1,0x26d2,0x26d3,0x26d4,0x26d5,0x26d6,0x26d7,
+ 0x26d8,0x26d9,0x26da,0x26db,0x26dc,0x26dd,0x26de,0x26df,
+ 0x26e0,0x26e1,0x26e2,0x26e3,0x26e4,0x26e5,0x26e6,0x26e7,
+ 0x26e8,0x26e9,0x26ea,0x26eb,0x26ec,0x26ed,0x26ee,0x26ef,
+ 0x26f0,0x26f1,0x26f2,0x26f3,0x26f4,0x26f5,0x26f6,0x26f7,
+ 0x26f8,0x26f9,0x26fa,0x26fb,0x26fc,0x26fd,0x26fe,0x26ff,
+ 0x2700,0x2701,0x2702,0x2703,0x2704,0x2705,0x2706,0x2707,
+ 0x2708,0x2709,0x270a,0x270b,0x270c,0x270d,0x270e,0x270f,
+ 0x2710,0x2711,0x2712,0x2713,0x2714,0x2715,0x2716,0x2717,
+ 0x2718,0x2719,0x271a,0x271b,0x271c,0x271d,0x271e,0x271f,
+ 0x2720,0x2721,0x2722,0x2723,0x2724,0x2725,0x2726,0x2727,
+ 0x2728,0x2729,0x272a,0x272b,0x272c,0x272d,0x272e,0x272f,
+ 0x2730,0x2731,0x2732,0x2733,0x2734,0x2735,0x2736,0x2737,
+ 0x2738,0x2739,0x273a,0x273b,0x273c,0x273d,0x273e,0x273f,
+ 0x2740,0x2741,0x2742,0x2743,0x2744,0x2745,0x2746,0x2747,
+ 0x2748,0x2749,0x274a,0x274b,0x274c,0x274d,0x274e,0x274f,
+ 0x2750,0x2751,0x2752,0x2753,0x2754,0x2755,0x2756,0x2757,
+ 0x2758,0x2759,0x275a,0x275b,0x275c,0x275d,0x275e,0x275f,
+ 0x2760,0x2761,0x2762,0x2763,0x2764,0x2765,0x2766,0x2767,
+ 0x2768,0x2769,0x276a,0x276b,0x276c,0x276d,0x276e,0x276f,
+ 0x2770,0x2771,0x2772,0x2773,0x2774,0x2775,0x2776,0x2777,
+ 0x2778,0x2779,0x277a,0x277b,0x277c,0x277d,0x277e,0x277f,
+ 0x2780,0x2781,0x2782,0x2783,0x2784,0x2785,0x2786,0x2787,
+ 0x2788,0x2789,0x278a,0x278b,0x278c,0x278d,0x278e,0x278f,
+ 0x2790,0x2791,0x2792,0x2793,0x2794,0x2795,0x2796,0x2797,
+ 0x2798,0x2799,0x279a,0x279b,0x279c,0x279d,0x279e,0x279f,
+ 0x27a0,0x27a1,0x27a2,0x27a3,0x27a4,0x27a5,0x27a6,0x27a7,
+ 0x27a8,0x27a9,0x27aa,0x27ab,0x27ac,0x27ad,0x27ae,0x27af,
+ 0x27b0,0x27b1,0x27b2,0x27b3,0x27b4,0x27b5,0x27b6,0x27b7,
+ 0x27b8,0x27b9,0x27ba,0x27bb,0x27bc,0x27bd,0x27be,0x27bf,
+ 0x27c0,0x27c1,0x27c2,0x27c3,0x27c4,0x27c5,0x27c6,0x27c7,
+ 0x27c8,0x27c9,0x27ca,0x27cb,0x27cc,0x27cd,0x27ce,0x27cf,
+ 0x27d0,0x27d1,0x27d2,0x27d3,0x27d4,0x27d5,0x27d6,0x27d7,
+ 0x27d8,0x27d9,0x27da,0x27db,0x27dc,0x27dd,0x27de,0x27df,
+ 0x27e0,0x27e1,0x27e2,0x27e3,0x27e4,0x27e5,0x27e6,0x27e7,
+ 0x27e8,0x27e9,0x27ea,0x27eb,0x27ec,0x27ed,0x27ee,0x27ef,
+ 0x27f0,0x27f1,0x27f2,0x27f3,0x27f4,0x27f5,0x27f6,0x27f7,
+ 0x27f8,0x27f9,0x27fa,0x27fb,0x27fc,0x27fd,0x27fe,0x27ff,
+ 0x2800,0x2801,0x2802,0x2803,0x2804,0x2805,0x2806,0x2807,
+ 0x2808,0x2809,0x280a,0x280b,0x280c,0x280d,0x280e,0x280f,
+ 0x2810,0x2811,0x2812,0x2813,0x2814,0x2815,0x2816,0x2817,
+ 0x2818,0x2819,0x281a,0x281b,0x281c,0x281d,0x281e,0x281f,
+ 0x2820,0x2821,0x2822,0x2823,0x2824,0x2825,0x2826,0x2827,
+ 0x2828,0x2829,0x282a,0x282b,0x282c,0x282d,0x282e,0x282f,
+ 0x2830,0x2831,0x2832,0x2833,0x2834,0x2835,0x2836,0x2837,
+ 0x2838,0x2839,0x283a,0x283b,0x283c,0x283d,0x283e,0x283f,
+ 0x2840,0x2841,0x2842,0x2843,0x2844,0x2845,0x2846,0x2847,
+ 0x2848,0x2849,0x284a,0x284b,0x284c,0x284d,0x284e,0x284f,
+ 0x2850,0x2851,0x2852,0x2853,0x2854,0x2855,0x2856,0x2857,
+ 0x2858,0x2859,0x285a,0x285b,0x285c,0x285d,0x285e,0x285f,
+ 0x2860,0x2861,0x2862,0x2863,0x2864,0x2865,0x2866,0x2867,
+ 0x2868,0x2869,0x286a,0x286b,0x286c,0x286d,0x286e,0x286f,
+ 0x2870,0x2871,0x2872,0x2873,0x2874,0x2875,0x2876,0x2877,
+ 0x2878,0x2879,0x287a,0x287b,0x287c,0x287d,0x287e,0x287f,
+ 0x2880,0x2881,0x2882,0x2883,0x2884,0x2885,0x2886,0x2887,
+ 0x2888,0x2889,0x288a,0x288b,0x288c,0x288d,0x288e,0x288f,
+ 0x2890,0x2891,0x2892,0x2893,0x2894,0x2895,0x2896,0x2897,
+ 0x2898,0x2899,0x289a,0x289b,0x289c,0x289d,0x289e,0x289f,
+ 0x28a0,0x28a1,0x28a2,0x28a3,0x28a4,0x28a5,0x28a6,0x28a7,
+ 0x28a8,0x28a9,0x28aa,0x28ab,0x28ac,0x28ad,0x28ae,0x28af,
+ 0x28b0,0x28b1,0x28b2,0x28b3,0x28b4,0x28b5,0x28b6,0x28b7,
+ 0x28b8,0x28b9,0x28ba,0x28bb,0x28bc,0x28bd,0x28be,0x28bf,
+ 0x28c0,0x28c1,0x28c2,0x28c3,0x28c4,0x28c5,0x28c6,0x28c7,
+ 0x28c8,0x28c9,0x28ca,0x28cb,0x28cc,0x28cd,0x28ce,0x28cf,
+ 0x28d0,0x28d1,0x28d2,0x28d3,0x28d4,0x28d5,0x28d6,0x28d7,
+ 0x28d8,0x28d9,0x28da,0x28db,0x28dc,0x28dd,0x28de,0x28df,
+ 0x28e0,0x28e1,0x28e2,0x28e3,0x28e4,0x28e5,0x28e6,0x28e7,
+ 0x28e8,0x28e9,0x28ea,0x28eb,0x28ec,0x28ed,0x28ee,0x28ef,
+ 0x28f0,0x28f1,0x28f2,0x28f3,0x28f4,0x28f5,0x28f6,0x28f7,
+ 0x28f8,0x28f9,0x28fa,0x28fb,0x28fc,0x28fd,0x28fe,0x28ff,
+ 0x2900,0x2901,0x2902,0x2903,0x2904,0x2905,0x2906,0x2907,
+ 0x2908,0x2909,0x290a,0x290b,0x290c,0x290d,0x290e,0x290f,
+ 0x2910,0x2911,0x2912,0x2913,0x2914,0x2915,0x2916,0x2917,
+ 0x2918,0x2919,0x291a,0x291b,0x291c,0x291d,0x291e,0x291f,
+ 0x2920,0x2921,0x2922,0x2923,0x2924,0x2925,0x2926,0x2927,
+ 0x2928,0x2929,0x292a,0x292b,0x292c,0x292d,0x292e,0x292f,
+ 0x2930,0x2931,0x2932,0x2933,0x2934,0x2935,0x2936,0x2937,
+ 0x2938,0x2939,0x293a,0x293b,0x293c,0x293d,0x293e,0x293f,
+ 0x2940,0x2941,0x2942,0x2943,0x2944,0x2945,0x2946,0x2947,
+ 0x2948,0x2949,0x294a,0x294b,0x294c,0x294d,0x294e,0x294f,
+ 0x2950,0x2951,0x2952,0x2953,0x2954,0x2955,0x2956,0x2957,
+ 0x2958,0x2959,0x295a,0x295b,0x295c,0x295d,0x295e,0x295f,
+ 0x2960,0x2961,0x2962,0x2963,0x2964,0x2965,0x2966,0x2967,
+ 0x2968,0x2969,0x296a,0x296b,0x296c,0x296d,0x296e,0x296f,
+ 0x2970,0x2971,0x2972,0x2973,0x2974,0x2975,0x2976,0x2977,
+ 0x2978,0x2979,0x297a,0x297b,0x297c,0x297d,0x297e,0x297f,
+ 0x2980,0x2981,0x2982,0x2983,0x2984,0x2985,0x2986,0x2987,
+ 0x2988,0x2989,0x298a,0x298b,0x298c,0x298d,0x298e,0x298f,
+ 0x2990,0x2991,0x2992,0x2993,0x2994,0x2995,0x2996,0x2997,
+ 0x2998,0x2999,0x299a,0x299b,0x299c,0x299d,0x299e,0x299f,
+ 0x29a0,0x29a1,0x29a2,0x29a3,0x29a4,0x29a5,0x29a6,0x29a7,
+ 0x29a8,0x29a9,0x29aa,0x29ab,0x29ac,0x29ad,0x29ae,0x29af,
+ 0x29b0,0x29b1,0x29b2,0x29b3,0x29b4,0x29b5,0x29b6,0x29b7,
+ 0x29b8,0x29b9,0x29ba,0x29bb,0x29bc,0x29bd,0x29be,0x29bf,
+ 0x29c0,0x29c1,0x29c2,0x29c3,0x29c4,0x29c5,0x29c6,0x29c7,
+ 0x29c8,0x29c9,0x29ca,0x29cb,0x29cc,0x29cd,0x29ce,0x29cf,
+ 0x29d0,0x29d1,0x29d2,0x29d3,0x29d4,0x29d5,0x29d6,0x29d7,
+ 0x29d8,0x29d9,0x29da,0x29db,0x29dc,0x29dd,0x29de,0x29df,
+ 0x29e0,0x29e1,0x29e2,0x29e3,0x29e4,0x29e5,0x29e6,0x29e7,
+ 0x29e8,0x29e9,0x29ea,0x29eb,0x29ec,0x29ed,0x29ee,0x29ef,
+ 0x29f0,0x29f1,0x29f2,0x29f3,0x29f4,0x29f5,0x29f6,0x29f7,
+ 0x29f8,0x29f9,0x29fa,0x29fb,0x29fc,0x29fd,0x29fe,0x29ff,
+ 0x2a00,0x2a01,0x2a02,0x2a03,0x2a04,0x2a05,0x2a06,0x2a07,
+ 0x2a08,0x2a09,0x2a0a,0x2a0b,0x2a0c,0x2a0d,0x2a0e,0x2a0f,
+ 0x2a10,0x2a11,0x2a12,0x2a13,0x2a14,0x2a15,0x2a16,0x2a17,
+ 0x2a18,0x2a19,0x2a1a,0x2a1b,0x2a1c,0x2a1d,0x2a1e,0x2a1f,
+ 0x2a20,0x2a21,0x2a22,0x2a23,0x2a24,0x2a25,0x2a26,0x2a27,
+ 0x2a28,0x2a29,0x2a2a,0x2a2b,0x2a2c,0x2a2d,0x2a2e,0x2a2f,
+ 0x2a30,0x2a31,0x2a32,0x2a33,0x2a34,0x2a35,0x2a36,0x2a37,
+ 0x2a38,0x2a39,0x2a3a,0x2a3b,0x2a3c,0x2a3d,0x2a3e,0x2a3f,
+ 0x2a40,0x2a41,0x2a42,0x2a43,0x2a44,0x2a45,0x2a46,0x2a47,
+ 0x2a48,0x2a49,0x2a4a,0x2a4b,0x2a4c,0x2a4d,0x2a4e,0x2a4f,
+ 0x2a50,0x2a51,0x2a52,0x2a53,0x2a54,0x2a55,0x2a56,0x2a57,
+ 0x2a58,0x2a59,0x2a5a,0x2a5b,0x2a5c,0x2a5d,0x2a5e,0x2a5f,
+ 0x2a60,0x2a61,0x2a62,0x2a63,0x2a64,0x2a65,0x2a66,0x2a67,
+ 0x2a68,0x2a69,0x2a6a,0x2a6b,0x2a6c,0x2a6d,0x2a6e,0x2a6f,
+ 0x2a70,0x2a71,0x2a72,0x2a73,0x2a74,0x2a75,0x2a76,0x2a77,
+ 0x2a78,0x2a79,0x2a7a,0x2a7b,0x2a7c,0x2a7d,0x2a7e,0x2a7f,
+ 0x2a80,0x2a81,0x2a82,0x2a83,0x2a84,0x2a85,0x2a86,0x2a87,
+ 0x2a88,0x2a89,0x2a8a,0x2a8b,0x2a8c,0x2a8d,0x2a8e,0x2a8f,
+ 0x2a90,0x2a91,0x2a92,0x2a93,0x2a94,0x2a95,0x2a96,0x2a97,
+ 0x2a98,0x2a99,0x2a9a,0x2a9b,0x2a9c,0x2a9d,0x2a9e,0x2a9f,
+ 0x2aa0,0x2aa1,0x2aa2,0x2aa3,0x2aa4,0x2aa5,0x2aa6,0x2aa7,
+ 0x2aa8,0x2aa9,0x2aaa,0x2aab,0x2aac,0x2aad,0x2aae,0x2aaf,
+ 0x2ab0,0x2ab1,0x2ab2,0x2ab3,0x2ab4,0x2ab5,0x2ab6,0x2ab7,
+ 0x2ab8,0x2ab9,0x2aba,0x2abb,0x2abc,0x2abd,0x2abe,0x2abf,
+ 0x2ac0,0x2ac1,0x2ac2,0x2ac3,0x2ac4,0x2ac5,0x2ac6,0x2ac7,
+ 0x2ac8,0x2ac9,0x2aca,0x2acb,0x2acc,0x2acd,0x2ace,0x2acf,
+ 0x2ad0,0x2ad1,0x2ad2,0x2ad3,0x2ad4,0x2ad5,0x2ad6,0x2ad7,
+ 0x2ad8,0x2ad9,0x2ada,0x2adb,0x2adc,0x2add,0x2ade,0x2adf,
+ 0x2ae0,0x2ae1,0x2ae2,0x2ae3,0x2ae4,0x2ae5,0x2ae6,0x2ae7,
+ 0x2ae8,0x2ae9,0x2aea,0x2aeb,0x2aec,0x2aed,0x2aee,0x2aef,
+ 0x2af0,0x2af1,0x2af2,0x2af3,0x2af4,0x2af5,0x2af6,0x2af7,
+ 0x2af8,0x2af9,0x2afa,0x2afb,0x2afc,0x2afd,0x2afe,0x2aff,
+ 0x2b00,0x2b01,0x2b02,0x2b03,0x2b04,0x2b05,0x2b06,0x2b07,
+ 0x2b08,0x2b09,0x2b0a,0x2b0b,0x2b0c,0x2b0d,0x2b0e,0x2b0f,
+ 0x2b10,0x2b11,0x2b12,0x2b13,0x2b14,0x2b15,0x2b16,0x2b17,
+ 0x2b18,0x2b19,0x2b1a,0x2b1b,0x2b1c,0x2b1d,0x2b1e,0x2b1f,
+ 0x2b20,0x2b21,0x2b22,0x2b23,0x2b24,0x2b25,0x2b26,0x2b27,
+ 0x2b28,0x2b29,0x2b2a,0x2b2b,0x2b2c,0x2b2d,0x2b2e,0x2b2f,
+ 0x2b30,0x2b31,0x2b32,0x2b33,0x2b34,0x2b35,0x2b36,0x2b37,
+ 0x2b38,0x2b39,0x2b3a,0x2b3b,0x2b3c,0x2b3d,0x2b3e,0x2b3f,
+ 0x2b40,0x2b41,0x2b42,0x2b43,0x2b44,0x2b45,0x2b46,0x2b47,
+ 0x2b48,0x2b49,0x2b4a,0x2b4b,0x2b4c,0x2b4d,0x2b4e,0x2b4f,
+ 0x2b50,0x2b51,0x2b52,0x2b53,0x2b54,0x2b55,0x2b56,0x2b57,
+ 0x2b58,0x2b59,0x2b5a,0x2b5b,0x2b5c,0x2b5d,0x2b5e,0x2b5f,
+ 0x2b60,0x2b61,0x2b62,0x2b63,0x2b64,0x2b65,0x2b66,0x2b67,
+ 0x2b68,0x2b69,0x2b6a,0x2b6b,0x2b6c,0x2b6d,0x2b6e,0x2b6f,
+ 0x2b70,0x2b71,0x2b72,0x2b73,0x2b74,0x2b75,0x2b76,0x2b77,
+ 0x2b78,0x2b79,0x2b7a,0x2b7b,0x2b7c,0x2b7d,0x2b7e,0x2b7f,
+ 0x2b80,0x2b81,0x2b82,0x2b83,0x2b84,0x2b85,0x2b86,0x2b87,
+ 0x2b88,0x2b89,0x2b8a,0x2b8b,0x2b8c,0x2b8d,0x2b8e,0x2b8f,
+ 0x2b90,0x2b91,0x2b92,0x2b93,0x2b94,0x2b95,0x2b96,0x2b97,
+ 0x2b98,0x2b99,0x2b9a,0x2b9b,0x2b9c,0x2b9d,0x2b9e,0x2b9f,
+ 0x2ba0,0x2ba1,0x2ba2,0x2ba3,0x2ba4,0x2ba5,0x2ba6,0x2ba7,
+ 0x2ba8,0x2ba9,0x2baa,0x2bab,0x2bac,0x2bad,0x2bae,0x2baf,
+ 0x2bb0,0x2bb1,0x2bb2,0x2bb3,0x2bb4,0x2bb5,0x2bb6,0x2bb7,
+ 0x2bb8,0x2bb9,0x2bba,0x2bbb,0x2bbc,0x2bbd,0x2bbe,0x2bbf,
+ 0x2bc0,0x2bc1,0x2bc2,0x2bc3,0x2bc4,0x2bc5,0x2bc6,0x2bc7,
+ 0x2bc8,0x2bc9,0x2bca,0x2bcb,0x2bcc,0x2bcd,0x2bce,0x2bcf,
+ 0x2bd0,0x2bd1,0x2bd2,0x2bd3,0x2bd4,0x2bd5,0x2bd6,0x2bd7,
+ 0x2bd8,0x2bd9,0x2bda,0x2bdb,0x2bdc,0x2bdd,0x2bde,0x2bdf,
+ 0x2be0,0x2be1,0x2be2,0x2be3,0x2be4,0x2be5,0x2be6,0x2be7,
+ 0x2be8,0x2be9,0x2bea,0x2beb,0x2bec,0x2bed,0x2bee,0x2bef,
+ 0x2bf0,0x2bf1,0x2bf2,0x2bf3,0x2bf4,0x2bf5,0x2bf6,0x2bf7,
+ 0x2bf8,0x2bf9,0x2bfa,0x2bfb,0x2bfc,0x2bfd,0x2bfe,0x2bff,
+ 0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07,
+ 0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f,
+ 0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17,
+ 0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f,
+ 0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27,
+ 0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c2f,
+ 0x2c30,0x2c31,0x2c32,0x2c33,0x2c34,0x2c35,0x2c36,0x2c37,
+ 0x2c38,0x2c39,0x2c3a,0x2c3b,0x2c3c,0x2c3d,0x2c3e,0x2c3f,
+ 0x2c40,0x2c41,0x2c42,0x2c43,0x2c44,0x2c45,0x2c46,0x2c47,
+ 0x2c48,0x2c49,0x2c4a,0x2c4b,0x2c4c,0x2c4d,0x2c4e,0x2c4f,
+ 0x2c50,0x2c51,0x2c52,0x2c53,0x2c54,0x2c55,0x2c56,0x2c57,
+ 0x2c58,0x2c59,0x2c5a,0x2c5b,0x2c5c,0x2c5d,0x2c5e,0x2c5f,
+ 0x2c60,0x2c61,0x2c62,0x2c63,0x2c64,0x2c65,0x2c66,0x2c67,
+ 0x2c68,0x2c69,0x2c6a,0x2c6b,0x2c6c,0x2c6d,0x2c6e,0x2c6f,
+ 0x2c70,0x2c71,0x2c72,0x2c73,0x2c74,0x2c75,0x2c76,0x2c77,
+ 0x2c78,0x2c79,0x2c7a,0x2c7b,0x2c7c,0x2c7d,0x2c7e,0x2c7f,
+ 0x2c80,0x2c81,0x2c82,0x2c83,0x2c84,0x2c85,0x2c86,0x2c87,
+ 0x2c88,0x2c89,0x2c8a,0x2c8b,0x2c8c,0x2c8d,0x2c8e,0x2c8f,
+ 0x2c90,0x2c91,0x2c92,0x2c93,0x2c94,0x2c95,0x2c96,0x2c97,
+ 0x2c98,0x2c99,0x2c9a,0x2c9b,0x2c9c,0x2c9d,0x2c9e,0x2c9f,
+ 0x2ca0,0x2ca1,0x2ca2,0x2ca3,0x2ca4,0x2ca5,0x2ca6,0x2ca7,
+ 0x2ca8,0x2ca9,0x2caa,0x2cab,0x2cac,0x2cad,0x2cae,0x2caf,
+ 0x2cb0,0x2cb1,0x2cb2,0x2cb3,0x2cb4,0x2cb5,0x2cb6,0x2cb7,
+ 0x2cb8,0x2cb9,0x2cba,0x2cbb,0x2cbc,0x2cbd,0x2cbe,0x2cbf,
+ 0x2cc0,0x2cc1,0x2cc2,0x2cc3,0x2cc4,0x2cc5,0x2cc6,0x2cc7,
+ 0x2cc8,0x2cc9,0x2cca,0x2ccb,0x2ccc,0x2ccd,0x2cce,0x2ccf,
+ 0x2cd0,0x2cd1,0x2cd2,0x2cd3,0x2cd4,0x2cd5,0x2cd6,0x2cd7,
+ 0x2cd8,0x2cd9,0x2cda,0x2cdb,0x2cdc,0x2cdd,0x2cde,0x2cdf,
+ 0x2ce0,0x2ce1,0x2ce2,0x2ce3,0x2ce4,0x2ce5,0x2ce6,0x2ce7,
+ 0x2ce8,0x2ce9,0x2cea,0x2ceb,0x2cec,0x2ced,0x2cee,0x2cef,
+ 0x2cf0,0x2cf1,0x2cf2,0x2cf3,0x2cf4,0x2cf5,0x2cf6,0x2cf7,
+ 0x2cf8,0x2cf9,0x2cfa,0x2cfb,0x2cfc,0x2cfd,0x2cfe,0x2cff,
+ 0x2d00,0x2d01,0x2d02,0x2d03,0x2d04,0x2d05,0x2d06,0x2d07,
+ 0x2d08,0x2d09,0x2d0a,0x2d0b,0x2d0c,0x2d0d,0x2d0e,0x2d0f,
+ 0x2d10,0x2d11,0x2d12,0x2d13,0x2d14,0x2d15,0x2d16,0x2d17,
+ 0x2d18,0x2d19,0x2d1a,0x2d1b,0x2d1c,0x2d1d,0x2d1e,0x2d1f,
+ 0x2d20,0x2d21,0x2d22,0x2d23,0x2d24,0x2d25,0x2d26,0x2d27,
+ 0x2d28,0x2d29,0x2d2a,0x2d2b,0x2d2c,0x2d2d,0x2d2e,0x2d2f,
+ 0x2d30,0x2d31,0x2d32,0x2d33,0x2d34,0x2d35,0x2d36,0x2d37,
+ 0x2d38,0x2d39,0x2d3a,0x2d3b,0x2d3c,0x2d3d,0x2d3e,0x2d3f,
+ 0x2d40,0x2d41,0x2d42,0x2d43,0x2d44,0x2d45,0x2d46,0x2d47,
+ 0x2d48,0x2d49,0x2d4a,0x2d4b,0x2d4c,0x2d4d,0x2d4e,0x2d4f,
+ 0x2d50,0x2d51,0x2d52,0x2d53,0x2d54,0x2d55,0x2d56,0x2d57,
+ 0x2d58,0x2d59,0x2d5a,0x2d5b,0x2d5c,0x2d5d,0x2d5e,0x2d5f,
+ 0x2d60,0x2d61,0x2d62,0x2d63,0x2d64,0x2d65,0x2d66,0x2d67,
+ 0x2d68,0x2d69,0x2d6a,0x2d6b,0x2d6c,0x2d6d,0x2d6e,0x2d6f,
+ 0x2d70,0x2d71,0x2d72,0x2d73,0x2d74,0x2d75,0x2d76,0x2d77,
+ 0x2d78,0x2d79,0x2d7a,0x2d7b,0x2d7c,0x2d7d,0x2d7e,0x2d7f,
+ 0x2d80,0x2d81,0x2d82,0x2d83,0x2d84,0x2d85,0x2d86,0x2d87,
+ 0x2d88,0x2d89,0x2d8a,0x2d8b,0x2d8c,0x2d8d,0x2d8e,0x2d8f,
+ 0x2d90,0x2d91,0x2d92,0x2d93,0x2d94,0x2d95,0x2d96,0x2d97,
+ 0x2d98,0x2d99,0x2d9a,0x2d9b,0x2d9c,0x2d9d,0x2d9e,0x2d9f,
+ 0x2da0,0x2da1,0x2da2,0x2da3,0x2da4,0x2da5,0x2da6,0x2da7,
+ 0x2da8,0x2da9,0x2daa,0x2dab,0x2dac,0x2dad,0x2dae,0x2daf,
+ 0x2db0,0x2db1,0x2db2,0x2db3,0x2db4,0x2db5,0x2db6,0x2db7,
+ 0x2db8,0x2db9,0x2dba,0x2dbb,0x2dbc,0x2dbd,0x2dbe,0x2dbf,
+ 0x2dc0,0x2dc1,0x2dc2,0x2dc3,0x2dc4,0x2dc5,0x2dc6,0x2dc7,
+ 0x2dc8,0x2dc9,0x2dca,0x2dcb,0x2dcc,0x2dcd,0x2dce,0x2dcf,
+ 0x2dd0,0x2dd1,0x2dd2,0x2dd3,0x2dd4,0x2dd5,0x2dd6,0x2dd7,
+ 0x2dd8,0x2dd9,0x2dda,0x2ddb,0x2ddc,0x2ddd,0x2dde,0x2ddf,
+ 0x2de0,0x2de1,0x2de2,0x2de3,0x2de4,0x2de5,0x2de6,0x2de7,
+ 0x2de8,0x2de9,0x2dea,0x2deb,0x2dec,0x2ded,0x2dee,0x2def,
+ 0x2df0,0x2df1,0x2df2,0x2df3,0x2df4,0x2df5,0x2df6,0x2df7,
+ 0x2df8,0x2df9,0x2dfa,0x2dfb,0x2dfc,0x2dfd,0x2dfe,0x2dff,
+ 0x2e00,0x2e01,0x2e02,0x2e03,0x2e04,0x2e05,0x2e06,0x2e07,
+ 0x2e08,0x2e09,0x2e0a,0x2e0b,0x2e0c,0x2e0d,0x2e0e,0x2e0f,
+ 0x2e10,0x2e11,0x2e12,0x2e13,0x2e14,0x2e15,0x2e16,0x2e17,
+ 0x2e18,0x2e19,0x2e1a,0x2e1b,0x2e1c,0x2e1d,0x2e1e,0x2e1f,
+ 0x2e20,0x2e21,0x2e22,0x2e23,0x2e24,0x2e25,0x2e26,0x2e27,
+ 0x2e28,0x2e29,0x2e2a,0x2e2b,0x2e2c,0x2e2d,0x2e2e,0x2e2f,
+ 0x2e30,0x2e31,0x2e32,0x2e33,0x2e34,0x2e35,0x2e36,0x2e37,
+ 0x2e38,0x2e39,0x2e3a,0x2e3b,0x2e3c,0x2e3d,0x2e3e,0x2e3f,
+ 0x2e40,0x2e41,0x2e42,0x2e43,0x2e44,0x2e45,0x2e46,0x2e47,
+ 0x2e48,0x2e49,0x2e4a,0x2e4b,0x2e4c,0x2e4d,0x2e4e,0x2e4f,
+ 0x2e50,0x2e51,0x2e52,0x2e53,0x2e54,0x2e55,0x2e56,0x2e57,
+ 0x2e58,0x2e59,0x2e5a,0x2e5b,0x2e5c,0x2e5d,0x2e5e,0x2e5f,
+ 0x2e60,0x2e61,0x2e62,0x2e63,0x2e64,0x2e65,0x2e66,0x2e67,
+ 0x2e68,0x2e69,0x2e6a,0x2e6b,0x2e6c,0x2e6d,0x2e6e,0x2e6f,
+ 0x2e70,0x2e71,0x2e72,0x2e73,0x2e74,0x2e75,0x2e76,0x2e77,
+ 0x2e78,0x2e79,0x2e7a,0x2e7b,0x2e7c,0x2e7d,0x2e7e,0x2e7f,
+ 0x2e80,0x2e81,0x2e82,0x2e83,0x2e84,0x2e85,0x2e86,0x2e87,
+ 0x2e88,0x2e89,0x2e8a,0x2e8b,0x2e8c,0x2e8d,0x2e8e,0x2e8f,
+ 0x2e90,0x2e91,0x2e92,0x2e93,0x2e94,0x2e95,0x2e96,0x2e97,
+ 0x2e98,0x2e99,0x2e9a,0x2e9b,0x2e9c,0x2e9d,0x2e9e,0x2e9f,
+ 0x2ea0,0x2ea1,0x2ea2,0x2ea3,0x2ea4,0x2ea5,0x2ea6,0x2ea7,
+ 0x2ea8,0x2ea9,0x2eaa,0x2eab,0x2eac,0x2ead,0x2eae,0x2eaf,
+ 0x2eb0,0x2eb1,0x2eb2,0x2eb3,0x2eb4,0x2eb5,0x2eb6,0x2eb7,
+ 0x2eb8,0x2eb9,0x2eba,0x2ebb,0x2ebc,0x2ebd,0x2ebe,0x2ebf,
+ 0x2ec0,0x2ec1,0x2ec2,0x2ec3,0x2ec4,0x2ec5,0x2ec6,0x2ec7,
+ 0x2ec8,0x2ec9,0x2eca,0x2ecb,0x2ecc,0x2ecd,0x2ece,0x2ecf,
+ 0x2ed0,0x2ed1,0x2ed2,0x2ed3,0x2ed4,0x2ed5,0x2ed6,0x2ed7,
+ 0x2ed8,0x2ed9,0x2eda,0x2edb,0x2edc,0x2edd,0x2ede,0x2edf,
+ 0x2ee0,0x2ee1,0x2ee2,0x2ee3,0x2ee4,0x2ee5,0x2ee6,0x2ee7,
+ 0x2ee8,0x2ee9,0x2eea,0x2eeb,0x2eec,0x2eed,0x2eee,0x2eef,
+ 0x2ef0,0x2ef1,0x2ef2,0x2ef3,0x2ef4,0x2ef5,0x2ef6,0x2ef7,
+ 0x2ef8,0x2ef9,0x2efa,0x2efb,0x2efc,0x2efd,0x2efe,0x2eff,
+ 0x2f00,0x2f01,0x2f02,0x2f03,0x2f04,0x2f05,0x2f06,0x2f07,
+ 0x2f08,0x2f09,0x2f0a,0x2f0b,0x2f0c,0x2f0d,0x2f0e,0x2f0f,
+ 0x2f10,0x2f11,0x2f12,0x2f13,0x2f14,0x2f15,0x2f16,0x2f17,
+ 0x2f18,0x2f19,0x2f1a,0x2f1b,0x2f1c,0x2f1d,0x2f1e,0x2f1f,
+ 0x2f20,0x2f21,0x2f22,0x2f23,0x2f24,0x2f25,0x2f26,0x2f27,
+ 0x2f28,0x2f29,0x2f2a,0x2f2b,0x2f2c,0x2f2d,0x2f2e,0x2f2f,
+ 0x2f30,0x2f31,0x2f32,0x2f33,0x2f34,0x2f35,0x2f36,0x2f37,
+ 0x2f38,0x2f39,0x2f3a,0x2f3b,0x2f3c,0x2f3d,0x2f3e,0x2f3f,
+ 0x2f40,0x2f41,0x2f42,0x2f43,0x2f44,0x2f45,0x2f46,0x2f47,
+ 0x2f48,0x2f49,0x2f4a,0x2f4b,0x2f4c,0x2f4d,0x2f4e,0x2f4f,
+ 0x2f50,0x2f51,0x2f52,0x2f53,0x2f54,0x2f55,0x2f56,0x2f57,
+ 0x2f58,0x2f59,0x2f5a,0x2f5b,0x2f5c,0x2f5d,0x2f5e,0x2f5f,
+ 0x2f60,0x2f61,0x2f62,0x2f63,0x2f64,0x2f65,0x2f66,0x2f67,
+ 0x2f68,0x2f69,0x2f6a,0x2f6b,0x2f6c,0x2f6d,0x2f6e,0x2f6f,
+ 0x2f70,0x2f71,0x2f72,0x2f73,0x2f74,0x2f75,0x2f76,0x2f77,
+ 0x2f78,0x2f79,0x2f7a,0x2f7b,0x2f7c,0x2f7d,0x2f7e,0x2f7f,
+ 0x2f80,0x2f81,0x2f82,0x2f83,0x2f84,0x2f85,0x2f86,0x2f87,
+ 0x2f88,0x2f89,0x2f8a,0x2f8b,0x2f8c,0x2f8d,0x2f8e,0x2f8f,
+ 0x2f90,0x2f91,0x2f92,0x2f93,0x2f94,0x2f95,0x2f96,0x2f97,
+ 0x2f98,0x2f99,0x2f9a,0x2f9b,0x2f9c,0x2f9d,0x2f9e,0x2f9f,
+ 0x2fa0,0x2fa1,0x2fa2,0x2fa3,0x2fa4,0x2fa5,0x2fa6,0x2fa7,
+ 0x2fa8,0x2fa9,0x2faa,0x2fab,0x2fac,0x2fad,0x2fae,0x2faf,
+ 0x2fb0,0x2fb1,0x2fb2,0x2fb3,0x2fb4,0x2fb5,0x2fb6,0x2fb7,
+ 0x2fb8,0x2fb9,0x2fba,0x2fbb,0x2fbc,0x2fbd,0x2fbe,0x2fbf,
+ 0x2fc0,0x2fc1,0x2fc2,0x2fc3,0x2fc4,0x2fc5,0x2fc6,0x2fc7,
+ 0x2fc8,0x2fc9,0x2fca,0x2fcb,0x2fcc,0x2fcd,0x2fce,0x2fcf,
+ 0x2fd0,0x2fd1,0x2fd2,0x2fd3,0x2fd4,0x2fd5,0x2fd6,0x2fd7,
+ 0x2fd8,0x2fd9,0x2fda,0x2fdb,0x2fdc,0x2fdd,0x2fde,0x2fdf,
+ 0x2fe0,0x2fe1,0x2fe2,0x2fe3,0x2fe4,0x2fe5,0x2fe6,0x2fe7,
+ 0x2fe8,0x2fe9,0x2fea,0x2feb,0x2fec,0x2fed,0x2fee,0x2fef,
+ 0x2ff0,0x2ff1,0x2ff2,0x2ff3,0x2ff4,0x2ff5,0x2ff6,0x2ff7,
+ 0x2ff8,0x2ff9,0x2ffa,0x2ffb,0x2ffc,0x2ffd,0x2ffe,0x2fff,
+ 0x3000,0x3001,0x3002,0x3003,0x3004,0x3005,0x3006,0x3007,
+ 0x3008,0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,
+ 0x3010,0x3011,0x3012,0x3013,0x3014,0x3015,0x3016,0x3017,
+ 0x3018,0x3019,0x301a,0x301b,0x301c,0x301d,0x301e,0x301f,
+ 0x3020,0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,
+ 0x3028,0x3029,0x302a,0x302b,0x302c,0x302d,0x302e,0x302f,
+ 0x3030,0x3031,0x3032,0x3033,0x3034,0x3035,0x3036,0x3037,
+ 0x3038,0x3039,0x303a,0x303b,0x303c,0x303d,0x303e,0x303f,
+ 0x3040,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,
+ 0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,0x304f,
+ 0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,
+ 0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,
+ 0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,
+ 0x3068,0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,
+ 0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,
+ 0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,
+ 0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,
+ 0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,
+ 0x3090,0x3091,0x3092,0x3093,0x3094,0x3095,0x3096,0x3097,
+ 0x3098,0x3099,0x309a,0x309b,0x309c,0x309d,0x309e,0x309f,
+ 0x30a0,0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,
+ 0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,0x30af,
+ 0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,
+ 0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,
+ 0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,
+ 0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,
+ 0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,
+ 0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,
+ 0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,
+ 0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,
+ 0x30f0,0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,0x30f7,
+ 0x30f8,0x30f9,0x30fa,0x30fb,0x30fc,0x30fd,0x30fe,0x30ff,
+ 0x3100,0x3101,0x3102,0x3103,0x3104,0x3105,0x3106,0x3107,
+ 0x3108,0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,
+ 0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,
+ 0x3118,0x3119,0x311a,0x311b,0x311c,0x311d,0x311e,0x311f,
+ 0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127,
+ 0x3128,0x3129,0x312a,0x312b,0x312c,0x312d,0x312e,0x312f,
+ 0x3130,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137,
+ 0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,0x313f,
+ 0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,
+ 0x3148,0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x314f,
+ 0x3150,0x3151,0x3152,0x3153,0x3154,0x3155,0x3156,0x3157,
+ 0x3158,0x3159,0x315a,0x315b,0x315c,0x315d,0x315e,0x315f,
+ 0x3160,0x3161,0x3162,0x3163,0x3164,0x3165,0x3166,0x3167,
+ 0x3168,0x3169,0x316a,0x316b,0x316c,0x316d,0x316e,0x316f,
+ 0x3170,0x3171,0x3172,0x3173,0x3174,0x3175,0x3176,0x3177,
+ 0x3178,0x3179,0x317a,0x317b,0x317c,0x317d,0x317e,0x317f,
+ 0x3180,0x3181,0x3182,0x3183,0x3184,0x3185,0x3186,0x3187,
+ 0x3188,0x3189,0x318a,0x318b,0x318c,0x318d,0x318e,0x318f,
+ 0x3190,0x3191,0x3192,0x3193,0x3194,0x3195,0x3196,0x3197,
+ 0x3198,0x3199,0x319a,0x319b,0x319c,0x319d,0x319e,0x319f,
+ 0x31a0,0x31a1,0x31a2,0x31a3,0x31a4,0x31a5,0x31a6,0x31a7,
+ 0x31a8,0x31a9,0x31aa,0x31ab,0x31ac,0x31ad,0x31ae,0x31af,
+ 0x31b0,0x31b1,0x31b2,0x31b3,0x31b4,0x31b5,0x31b6,0x31b7,
+ 0x31b8,0x31b9,0x31ba,0x31bb,0x31bc,0x31bd,0x31be,0x31bf,
+ 0x31c0,0x31c1,0x31c2,0x31c3,0x31c4,0x31c5,0x31c6,0x31c7,
+ 0x31c8,0x31c9,0x31ca,0x31cb,0x31cc,0x31cd,0x31ce,0x31cf,
+ 0x31d0,0x31d1,0x31d2,0x31d3,0x31d4,0x31d5,0x31d6,0x31d7,
+ 0x31d8,0x31d9,0x31da,0x31db,0x31dc,0x31dd,0x31de,0x31df,
+ 0x31e0,0x31e1,0x31e2,0x31e3,0x31e4,0x31e5,0x31e6,0x31e7,
+ 0x31e8,0x31e9,0x31ea,0x31eb,0x31ec,0x31ed,0x31ee,0x31ef,
+ 0x31f0,0x31f1,0x31f2,0x31f3,0x31f4,0x31f5,0x31f6,0x31f7,
+ 0x31f8,0x31f9,0x31fa,0x31fb,0x31fc,0x31fd,0x31fe,0x31ff,
+ 0x3200,0x3201,0x3202,0x3203,0x3204,0x3205,0x3206,0x3207,
+ 0x3208,0x3209,0x320a,0x320b,0x320c,0x320d,0x320e,0x320f,
+ 0x3210,0x3211,0x3212,0x3213,0x3214,0x3215,0x3216,0x3217,
+ 0x3218,0x3219,0x321a,0x321b,0x321c,0x321d,0x321e,0x321f,
+ 0x3220,0x3221,0x3222,0x3223,0x3224,0x3225,0x3226,0x3227,
+ 0x3228,0x3229,0x322a,0x322b,0x322c,0x322d,0x322e,0x322f,
+ 0x3230,0x3231,0x3232,0x3233,0x3234,0x3235,0x3236,0x3237,
+ 0x3238,0x3239,0x323a,0x323b,0x323c,0x323d,0x323e,0x323f,
+ 0x3240,0x3241,0x3242,0x3243,0x3244,0x3245,0x3246,0x3247,
+ 0x3248,0x3249,0x324a,0x324b,0x324c,0x324d,0x324e,0x324f,
+ 0x3250,0x3251,0x3252,0x3253,0x3254,0x3255,0x3256,0x3257,
+ 0x3258,0x3259,0x325a,0x325b,0x325c,0x325d,0x325e,0x325f,
+ 0x3260,0x3261,0x3262,0x3263,0x3264,0x3265,0x3266,0x3267,
+ 0x3268,0x3269,0x326a,0x326b,0x326c,0x326d,0x326e,0x326f,
+ 0x3270,0x3271,0x3272,0x3273,0x3274,0x3275,0x3276,0x3277,
+ 0x3278,0x3279,0x327a,0x327b,0x327c,0x327d,0x327e,0x327f,
+ 0x3280,0x3281,0x3282,0x3283,0x3284,0x3285,0x3286,0x3287,
+ 0x3288,0x3289,0x328a,0x328b,0x328c,0x328d,0x328e,0x328f,
+ 0x3290,0x3291,0x3292,0x3293,0x3294,0x3295,0x3296,0x3297,
+ 0x3298,0x3299,0x329a,0x329b,0x329c,0x329d,0x329e,0x329f,
+ 0x32a0,0x32a1,0x32a2,0x32a3,0x32a4,0x32a5,0x32a6,0x32a7,
+ 0x32a8,0x32a9,0x32aa,0x32ab,0x32ac,0x32ad,0x32ae,0x32af,
+ 0x32b0,0x32b1,0x32b2,0x32b3,0x32b4,0x32b5,0x32b6,0x32b7,
+ 0x32b8,0x32b9,0x32ba,0x32bb,0x32bc,0x32bd,0x32be,0x32bf,
+ 0x32c0,0x32c1,0x32c2,0x32c3,0x32c4,0x32c5,0x32c6,0x32c7,
+ 0x32c8,0x32c9,0x32ca,0x32cb,0x32cc,0x32cd,0x32ce,0x32cf,
+ 0x32d0,0x32d1,0x32d2,0x32d3,0x32d4,0x32d5,0x32d6,0x32d7,
+ 0x32d8,0x32d9,0x32da,0x32db,0x32dc,0x32dd,0x32de,0x32df,
+ 0x32e0,0x32e1,0x32e2,0x32e3,0x32e4,0x32e5,0x32e6,0x32e7,
+ 0x32e8,0x32e9,0x32ea,0x32eb,0x32ec,0x32ed,0x32ee,0x32ef,
+ 0x32f0,0x32f1,0x32f2,0x32f3,0x32f4,0x32f5,0x32f6,0x32f7,
+ 0x32f8,0x32f9,0x32fa,0x32fb,0x32fc,0x32fd,0x32fe,0x32ff,
+ 0x3300,0x3301,0x3302,0x3303,0x3304,0x3305,0x3306,0x3307,
+ 0x3308,0x3309,0x330a,0x330b,0x330c,0x330d,0x330e,0x330f,
+ 0x3310,0x3311,0x3312,0x3313,0x3314,0x3315,0x3316,0x3317,
+ 0x3318,0x3319,0x331a,0x331b,0x331c,0x331d,0x331e,0x331f,
+ 0x3320,0x3321,0x3322,0x3323,0x3324,0x3325,0x3326,0x3327,
+ 0x3328,0x3329,0x332a,0x332b,0x332c,0x332d,0x332e,0x332f,
+ 0x3330,0x3331,0x3332,0x3333,0x3334,0x3335,0x3336,0x3337,
+ 0x3338,0x3339,0x333a,0x333b,0x333c,0x333d,0x333e,0x333f,
+ 0x3340,0x3341,0x3342,0x3343,0x3344,0x3345,0x3346,0x3347,
+ 0x3348,0x3349,0x334a,0x334b,0x334c,0x334d,0x334e,0x334f,
+ 0x3350,0x3351,0x3352,0x3353,0x3354,0x3355,0x3356,0x3357,
+ 0x3358,0x3359,0x335a,0x335b,0x335c,0x335d,0x335e,0x335f,
+ 0x3360,0x3361,0x3362,0x3363,0x3364,0x3365,0x3366,0x3367,
+ 0x3368,0x3369,0x336a,0x336b,0x336c,0x336d,0x336e,0x336f,
+ 0x3370,0x3371,0x3372,0x3373,0x3374,0x3375,0x3376,0x3377,
+ 0x3378,0x3379,0x337a,0x337b,0x337c,0x337d,0x337e,0x337f,
+ 0x3380,0x3381,0x3382,0x3383,0x3384,0x3385,0x3386,0x3387,
+ 0x3388,0x3389,0x338a,0x338b,0x338c,0x338d,0x338e,0x338f,
+ 0x3390,0x3391,0x3392,0x3393,0x3394,0x3395,0x3396,0x3397,
+ 0x3398,0x3399,0x339a,0x339b,0x339c,0x339d,0x339e,0x339f,
+ 0x33a0,0x33a1,0x33a2,0x33a3,0x33a4,0x33a5,0x33a6,0x33a7,
+ 0x33a8,0x33a9,0x33aa,0x33ab,0x33ac,0x33ad,0x33ae,0x33af,
+ 0x33b0,0x33b1,0x33b2,0x33b3,0x33b4,0x33b5,0x33b6,0x33b7,
+ 0x33b8,0x33b9,0x33ba,0x33bb,0x33bc,0x33bd,0x33be,0x33bf,
+ 0x33c0,0x33c1,0x33c2,0x33c3,0x33c4,0x33c5,0x33c6,0x33c7,
+ 0x33c8,0x33c9,0x33ca,0x33cb,0x33cc,0x33cd,0x33ce,0x33cf,
+ 0x33d0,0x33d1,0x33d2,0x33d3,0x33d4,0x33d5,0x33d6,0x33d7,
+ 0x33d8,0x33d9,0x33da,0x33db,0x33dc,0x33dd,0x33de,0x33df,
+ 0x33e0,0x33e1,0x33e2,0x33e3,0x33e4,0x33e5,0x33e6,0x33e7,
+ 0x33e8,0x33e9,0x33ea,0x33eb,0x33ec,0x33ed,0x33ee,0x33ef,
+ 0x33f0,0x33f1,0x33f2,0x33f3,0x33f4,0x33f5,0x33f6,0x33f7,
+ 0x33f8,0x33f9,0x33fa,0x33fb,0x33fc,0x33fd,0x33fe,0x33ff,
+ 0x3400,0x3401,0x3402,0x3403,0x3404,0x3405,0x3406,0x3407,
+ 0x3408,0x3409,0x340a,0x340b,0x340c,0x340d,0x340e,0x340f,
+ 0x3410,0x3411,0x3412,0x3413,0x3414,0x3415,0x3416,0x3417,
+ 0x3418,0x3419,0x341a,0x341b,0x341c,0x341d,0x341e,0x341f,
+ 0x3420,0x3421,0x3422,0x3423,0x3424,0x3425,0x3426,0x3427,
+ 0x3428,0x3429,0x342a,0x342b,0x342c,0x342d,0x342e,0x342f,
+ 0x3430,0x3431,0x3432,0x3433,0x3434,0x3435,0x3436,0x3437,
+ 0x3438,0x3439,0x343a,0x343b,0x343c,0x343d,0x343e,0x343f,
+ 0x3440,0x3441,0x3442,0x3443,0x3444,0x3445,0x3446,0x3447,
+ 0x3448,0x3449,0x344a,0x344b,0x344c,0x344d,0x344e,0x344f,
+ 0x3450,0x3451,0x3452,0x3453,0x3454,0x3455,0x3456,0x3457,
+ 0x3458,0x3459,0x345a,0x345b,0x345c,0x345d,0x345e,0x345f,
+ 0x3460,0x3461,0x3462,0x3463,0x3464,0x3465,0x3466,0x3467,
+ 0x3468,0x3469,0x346a,0x346b,0x346c,0x346d,0x346e,0x346f,
+ 0x3470,0x3471,0x3472,0x3473,0x3474,0x3475,0x3476,0x3477,
+ 0x3478,0x3479,0x347a,0x347b,0x347c,0x347d,0x347e,0x347f,
+ 0x3480,0x3481,0x3482,0x3483,0x3484,0x3485,0x3486,0x3487,
+ 0x3488,0x3489,0x348a,0x348b,0x348c,0x348d,0x348e,0x348f,
+ 0x3490,0x3491,0x3492,0x3493,0x3494,0x3495,0x3496,0x3497,
+ 0x3498,0x3499,0x349a,0x349b,0x349c,0x349d,0x349e,0x349f,
+ 0x34a0,0x34a1,0x34a2,0x34a3,0x34a4,0x34a5,0x34a6,0x34a7,
+ 0x34a8,0x34a9,0x34aa,0x34ab,0x34ac,0x34ad,0x34ae,0x34af,
+ 0x34b0,0x34b1,0x34b2,0x34b3,0x34b4,0x34b5,0x34b6,0x34b7,
+ 0x34b8,0x34b9,0x34ba,0x34bb,0x34bc,0x34bd,0x34be,0x34bf,
+ 0x34c0,0x34c1,0x34c2,0x34c3,0x34c4,0x34c5,0x34c6,0x34c7,
+ 0x34c8,0x34c9,0x34ca,0x34cb,0x34cc,0x34cd,0x34ce,0x34cf,
+ 0x34d0,0x34d1,0x34d2,0x34d3,0x34d4,0x34d5,0x34d6,0x34d7,
+ 0x34d8,0x34d9,0x34da,0x34db,0x34dc,0x34dd,0x34de,0x34df,
+ 0x34e0,0x34e1,0x34e2,0x34e3,0x34e4,0x34e5,0x34e6,0x34e7,
+ 0x34e8,0x34e9,0x34ea,0x34eb,0x34ec,0x34ed,0x34ee,0x34ef,
+ 0x34f0,0x34f1,0x34f2,0x34f3,0x34f4,0x34f5,0x34f6,0x34f7,
+ 0x34f8,0x34f9,0x34fa,0x34fb,0x34fc,0x34fd,0x34fe,0x34ff,
+ 0x3500,0x3501,0x3502,0x3503,0x3504,0x3505,0x3506,0x3507,
+ 0x3508,0x3509,0x350a,0x350b,0x350c,0x350d,0x350e,0x350f,
+ 0x3510,0x3511,0x3512,0x3513,0x3514,0x3515,0x3516,0x3517,
+ 0x3518,0x3519,0x351a,0x351b,0x351c,0x351d,0x351e,0x351f,
+ 0x3520,0x3521,0x3522,0x3523,0x3524,0x3525,0x3526,0x3527,
+ 0x3528,0x3529,0x352a,0x352b,0x352c,0x352d,0x352e,0x352f,
+ 0x3530,0x3531,0x3532,0x3533,0x3534,0x3535,0x3536,0x3537,
+ 0x3538,0x3539,0x353a,0x353b,0x353c,0x353d,0x353e,0x353f,
+ 0x3540,0x3541,0x3542,0x3543,0x3544,0x3545,0x3546,0x3547,
+ 0x3548,0x3549,0x354a,0x354b,0x354c,0x354d,0x354e,0x354f,
+ 0x3550,0x3551,0x3552,0x3553,0x3554,0x3555,0x3556,0x3557,
+ 0x3558,0x3559,0x355a,0x355b,0x355c,0x355d,0x355e,0x355f,
+ 0x3560,0x3561,0x3562,0x3563,0x3564,0x3565,0x3566,0x3567,
+ 0x3568,0x3569,0x356a,0x356b,0x356c,0x356d,0x356e,0x356f,
+ 0x3570,0x3571,0x3572,0x3573,0x3574,0x3575,0x3576,0x3577,
+ 0x3578,0x3579,0x357a,0x357b,0x357c,0x357d,0x357e,0x357f,
+ 0x3580,0x3581,0x3582,0x3583,0x3584,0x3585,0x3586,0x3587,
+ 0x3588,0x3589,0x358a,0x358b,0x358c,0x358d,0x358e,0x358f,
+ 0x3590,0x3591,0x3592,0x3593,0x3594,0x3595,0x3596,0x3597,
+ 0x3598,0x3599,0x359a,0x359b,0x359c,0x359d,0x359e,0x359f,
+ 0x35a0,0x35a1,0x35a2,0x35a3,0x35a4,0x35a5,0x35a6,0x35a7,
+ 0x35a8,0x35a9,0x35aa,0x35ab,0x35ac,0x35ad,0x35ae,0x35af,
+ 0x35b0,0x35b1,0x35b2,0x35b3,0x35b4,0x35b5,0x35b6,0x35b7,
+ 0x35b8,0x35b9,0x35ba,0x35bb,0x35bc,0x35bd,0x35be,0x35bf,
+ 0x35c0,0x35c1,0x35c2,0x35c3,0x35c4,0x35c5,0x35c6,0x35c7,
+ 0x35c8,0x35c9,0x35ca,0x35cb,0x35cc,0x35cd,0x35ce,0x35cf,
+ 0x35d0,0x35d1,0x35d2,0x35d3,0x35d4,0x35d5,0x35d6,0x35d7,
+ 0x35d8,0x35d9,0x35da,0x35db,0x35dc,0x35dd,0x35de,0x35df,
+ 0x35e0,0x35e1,0x35e2,0x35e3,0x35e4,0x35e5,0x35e6,0x35e7,
+ 0x35e8,0x35e9,0x35ea,0x35eb,0x35ec,0x35ed,0x35ee,0x35ef,
+ 0x35f0,0x35f1,0x35f2,0x35f3,0x35f4,0x35f5,0x35f6,0x35f7,
+ 0x35f8,0x35f9,0x35fa,0x35fb,0x35fc,0x35fd,0x35fe,0x35ff,
+ 0x3600,0x3601,0x3602,0x3603,0x3604,0x3605,0x3606,0x3607,
+ 0x3608,0x3609,0x360a,0x360b,0x360c,0x360d,0x360e,0x360f,
+ 0x3610,0x3611,0x3612,0x3613,0x3614,0x3615,0x3616,0x3617,
+ 0x3618,0x3619,0x361a,0x361b,0x361c,0x361d,0x361e,0x361f,
+ 0x3620,0x3621,0x3622,0x3623,0x3624,0x3625,0x3626,0x3627,
+ 0x3628,0x3629,0x362a,0x362b,0x362c,0x362d,0x362e,0x362f,
+ 0x3630,0x3631,0x3632,0x3633,0x3634,0x3635,0x3636,0x3637,
+ 0x3638,0x3639,0x363a,0x363b,0x363c,0x363d,0x363e,0x363f,
+ 0x3640,0x3641,0x3642,0x3643,0x3644,0x3645,0x3646,0x3647,
+ 0x3648,0x3649,0x364a,0x364b,0x364c,0x364d,0x364e,0x364f,
+ 0x3650,0x3651,0x3652,0x3653,0x3654,0x3655,0x3656,0x3657,
+ 0x3658,0x3659,0x365a,0x365b,0x365c,0x365d,0x365e,0x365f,
+ 0x3660,0x3661,0x3662,0x3663,0x3664,0x3665,0x3666,0x3667,
+ 0x3668,0x3669,0x366a,0x366b,0x366c,0x366d,0x366e,0x366f,
+ 0x3670,0x3671,0x3672,0x3673,0x3674,0x3675,0x3676,0x3677,
+ 0x3678,0x3679,0x367a,0x367b,0x367c,0x367d,0x367e,0x367f,
+ 0x3680,0x3681,0x3682,0x3683,0x3684,0x3685,0x3686,0x3687,
+ 0x3688,0x3689,0x368a,0x368b,0x368c,0x368d,0x368e,0x368f,
+ 0x3690,0x3691,0x3692,0x3693,0x3694,0x3695,0x3696,0x3697,
+ 0x3698,0x3699,0x369a,0x369b,0x369c,0x369d,0x369e,0x369f,
+ 0x36a0,0x36a1,0x36a2,0x36a3,0x36a4,0x36a5,0x36a6,0x36a7,
+ 0x36a8,0x36a9,0x36aa,0x36ab,0x36ac,0x36ad,0x36ae,0x36af,
+ 0x36b0,0x36b1,0x36b2,0x36b3,0x36b4,0x36b5,0x36b6,0x36b7,
+ 0x36b8,0x36b9,0x36ba,0x36bb,0x36bc,0x36bd,0x36be,0x36bf,
+ 0x36c0,0x36c1,0x36c2,0x36c3,0x36c4,0x36c5,0x36c6,0x36c7,
+ 0x36c8,0x36c9,0x36ca,0x36cb,0x36cc,0x36cd,0x36ce,0x36cf,
+ 0x36d0,0x36d1,0x36d2,0x36d3,0x36d4,0x36d5,0x36d6,0x36d7,
+ 0x36d8,0x36d9,0x36da,0x36db,0x36dc,0x36dd,0x36de,0x36df,
+ 0x36e0,0x36e1,0x36e2,0x36e3,0x36e4,0x36e5,0x36e6,0x36e7,
+ 0x36e8,0x36e9,0x36ea,0x36eb,0x36ec,0x36ed,0x36ee,0x36ef,
+ 0x36f0,0x36f1,0x36f2,0x36f3,0x36f4,0x36f5,0x36f6,0x36f7,
+ 0x36f8,0x36f9,0x36fa,0x36fb,0x36fc,0x36fd,0x36fe,0x36ff,
+ 0x3700,0x3701,0x3702,0x3703,0x3704,0x3705,0x3706,0x3707,
+ 0x3708,0x3709,0x370a,0x370b,0x370c,0x370d,0x370e,0x370f,
+ 0x3710,0x3711,0x3712,0x3713,0x3714,0x3715,0x3716,0x3717,
+ 0x3718,0x3719,0x371a,0x371b,0x371c,0x371d,0x371e,0x371f,
+ 0x3720,0x3721,0x3722,0x3723,0x3724,0x3725,0x3726,0x3727,
+ 0x3728,0x3729,0x372a,0x372b,0x372c,0x372d,0x372e,0x372f,
+ 0x3730,0x3731,0x3732,0x3733,0x3734,0x3735,0x3736,0x3737,
+ 0x3738,0x3739,0x373a,0x373b,0x373c,0x373d,0x373e,0x373f,
+ 0x3740,0x3741,0x3742,0x3743,0x3744,0x3745,0x3746,0x3747,
+ 0x3748,0x3749,0x374a,0x374b,0x374c,0x374d,0x374e,0x374f,
+ 0x3750,0x3751,0x3752,0x3753,0x3754,0x3755,0x3756,0x3757,
+ 0x3758,0x3759,0x375a,0x375b,0x375c,0x375d,0x375e,0x375f,
+ 0x3760,0x3761,0x3762,0x3763,0x3764,0x3765,0x3766,0x3767,
+ 0x3768,0x3769,0x376a,0x376b,0x376c,0x376d,0x376e,0x376f,
+ 0x3770,0x3771,0x3772,0x3773,0x3774,0x3775,0x3776,0x3777,
+ 0x3778,0x3779,0x377a,0x377b,0x377c,0x377d,0x377e,0x377f,
+ 0x3780,0x3781,0x3782,0x3783,0x3784,0x3785,0x3786,0x3787,
+ 0x3788,0x3789,0x378a,0x378b,0x378c,0x378d,0x378e,0x378f,
+ 0x3790,0x3791,0x3792,0x3793,0x3794,0x3795,0x3796,0x3797,
+ 0x3798,0x3799,0x379a,0x379b,0x379c,0x379d,0x379e,0x379f,
+ 0x37a0,0x37a1,0x37a2,0x37a3,0x37a4,0x37a5,0x37a6,0x37a7,
+ 0x37a8,0x37a9,0x37aa,0x37ab,0x37ac,0x37ad,0x37ae,0x37af,
+ 0x37b0,0x37b1,0x37b2,0x37b3,0x37b4,0x37b5,0x37b6,0x37b7,
+ 0x37b8,0x37b9,0x37ba,0x37bb,0x37bc,0x37bd,0x37be,0x37bf,
+ 0x37c0,0x37c1,0x37c2,0x37c3,0x37c4,0x37c5,0x37c6,0x37c7,
+ 0x37c8,0x37c9,0x37ca,0x37cb,0x37cc,0x37cd,0x37ce,0x37cf,
+ 0x37d0,0x37d1,0x37d2,0x37d3,0x37d4,0x37d5,0x37d6,0x37d7,
+ 0x37d8,0x37d9,0x37da,0x37db,0x37dc,0x37dd,0x37de,0x37df,
+ 0x37e0,0x37e1,0x37e2,0x37e3,0x37e4,0x37e5,0x37e6,0x37e7,
+ 0x37e8,0x37e9,0x37ea,0x37eb,0x37ec,0x37ed,0x37ee,0x37ef,
+ 0x37f0,0x37f1,0x37f2,0x37f3,0x37f4,0x37f5,0x37f6,0x37f7,
+ 0x37f8,0x37f9,0x37fa,0x37fb,0x37fc,0x37fd,0x37fe,0x37ff,
+ 0x3800,0x3801,0x3802,0x3803,0x3804,0x3805,0x3806,0x3807,
+ 0x3808,0x3809,0x380a,0x380b,0x380c,0x380d,0x380e,0x380f,
+ 0x3810,0x3811,0x3812,0x3813,0x3814,0x3815,0x3816,0x3817,
+ 0x3818,0x3819,0x381a,0x381b,0x381c,0x381d,0x381e,0x381f,
+ 0x3820,0x3821,0x3822,0x3823,0x3824,0x3825,0x3826,0x3827,
+ 0x3828,0x3829,0x382a,0x382b,0x382c,0x382d,0x382e,0x382f,
+ 0x3830,0x3831,0x3832,0x3833,0x3834,0x3835,0x3836,0x3837,
+ 0x3838,0x3839,0x383a,0x383b,0x383c,0x383d,0x383e,0x383f,
+ 0x3840,0x3841,0x3842,0x3843,0x3844,0x3845,0x3846,0x3847,
+ 0x3848,0x3849,0x384a,0x384b,0x384c,0x384d,0x384e,0x384f,
+ 0x3850,0x3851,0x3852,0x3853,0x3854,0x3855,0x3856,0x3857,
+ 0x3858,0x3859,0x385a,0x385b,0x385c,0x385d,0x385e,0x385f,
+ 0x3860,0x3861,0x3862,0x3863,0x3864,0x3865,0x3866,0x3867,
+ 0x3868,0x3869,0x386a,0x386b,0x386c,0x386d,0x386e,0x386f,
+ 0x3870,0x3871,0x3872,0x3873,0x3874,0x3875,0x3876,0x3877,
+ 0x3878,0x3879,0x387a,0x387b,0x387c,0x387d,0x387e,0x387f,
+ 0x3880,0x3881,0x3882,0x3883,0x3884,0x3885,0x3886,0x3887,
+ 0x3888,0x3889,0x388a,0x388b,0x388c,0x388d,0x388e,0x388f,
+ 0x3890,0x3891,0x3892,0x3893,0x3894,0x3895,0x3896,0x3897,
+ 0x3898,0x3899,0x389a,0x389b,0x389c,0x389d,0x389e,0x389f,
+ 0x38a0,0x38a1,0x38a2,0x38a3,0x38a4,0x38a5,0x38a6,0x38a7,
+ 0x38a8,0x38a9,0x38aa,0x38ab,0x38ac,0x38ad,0x38ae,0x38af,
+ 0x38b0,0x38b1,0x38b2,0x38b3,0x38b4,0x38b5,0x38b6,0x38b7,
+ 0x38b8,0x38b9,0x38ba,0x38bb,0x38bc,0x38bd,0x38be,0x38bf,
+ 0x38c0,0x38c1,0x38c2,0x38c3,0x38c4,0x38c5,0x38c6,0x38c7,
+ 0x38c8,0x38c9,0x38ca,0x38cb,0x38cc,0x38cd,0x38ce,0x38cf,
+ 0x38d0,0x38d1,0x38d2,0x38d3,0x38d4,0x38d5,0x38d6,0x38d7,
+ 0x38d8,0x38d9,0x38da,0x38db,0x38dc,0x38dd,0x38de,0x38df,
+ 0x38e0,0x38e1,0x38e2,0x38e3,0x38e4,0x38e5,0x38e6,0x38e7,
+ 0x38e8,0x38e9,0x38ea,0x38eb,0x38ec,0x38ed,0x38ee,0x38ef,
+ 0x38f0,0x38f1,0x38f2,0x38f3,0x38f4,0x38f5,0x38f6,0x38f7,
+ 0x38f8,0x38f9,0x38fa,0x38fb,0x38fc,0x38fd,0x38fe,0x38ff,
+ 0x3900,0x3901,0x3902,0x3903,0x3904,0x3905,0x3906,0x3907,
+ 0x3908,0x3909,0x390a,0x390b,0x390c,0x390d,0x390e,0x390f,
+ 0x3910,0x3911,0x3912,0x3913,0x3914,0x3915,0x3916,0x3917,
+ 0x3918,0x3919,0x391a,0x391b,0x391c,0x391d,0x391e,0x391f,
+ 0x3920,0x3921,0x3922,0x3923,0x3924,0x3925,0x3926,0x3927,
+ 0x3928,0x3929,0x392a,0x392b,0x392c,0x392d,0x392e,0x392f,
+ 0x3930,0x3931,0x3932,0x3933,0x3934,0x3935,0x3936,0x3937,
+ 0x3938,0x3939,0x393a,0x393b,0x393c,0x393d,0x393e,0x393f,
+ 0x3940,0x3941,0x3942,0x3943,0x3944,0x3945,0x3946,0x3947,
+ 0x3948,0x3949,0x394a,0x394b,0x394c,0x394d,0x394e,0x394f,
+ 0x3950,0x3951,0x3952,0x3953,0x3954,0x3955,0x3956,0x3957,
+ 0x3958,0x3959,0x395a,0x395b,0x395c,0x395d,0x395e,0x395f,
+ 0x3960,0x3961,0x3962,0x3963,0x3964,0x3965,0x3966,0x3967,
+ 0x3968,0x3969,0x396a,0x396b,0x396c,0x396d,0x396e,0x396f,
+ 0x3970,0x3971,0x3972,0x3973,0x3974,0x3975,0x3976,0x3977,
+ 0x3978,0x3979,0x397a,0x397b,0x397c,0x397d,0x397e,0x397f,
+ 0x3980,0x3981,0x3982,0x3983,0x3984,0x3985,0x3986,0x3987,
+ 0x3988,0x3989,0x398a,0x398b,0x398c,0x398d,0x398e,0x398f,
+ 0x3990,0x3991,0x3992,0x3993,0x3994,0x3995,0x3996,0x3997,
+ 0x3998,0x3999,0x399a,0x399b,0x399c,0x399d,0x399e,0x399f,
+ 0x39a0,0x39a1,0x39a2,0x39a3,0x39a4,0x39a5,0x39a6,0x39a7,
+ 0x39a8,0x39a9,0x39aa,0x39ab,0x39ac,0x39ad,0x39ae,0x39af,
+ 0x39b0,0x39b1,0x39b2,0x39b3,0x39b4,0x39b5,0x39b6,0x39b7,
+ 0x39b8,0x39b9,0x39ba,0x39bb,0x39bc,0x39bd,0x39be,0x39bf,
+ 0x39c0,0x39c1,0x39c2,0x39c3,0x39c4,0x39c5,0x39c6,0x39c7,
+ 0x39c8,0x39c9,0x39ca,0x39cb,0x39cc,0x39cd,0x39ce,0x39cf,
+ 0x39d0,0x39d1,0x39d2,0x39d3,0x39d4,0x39d5,0x39d6,0x39d7,
+ 0x39d8,0x39d9,0x39da,0x39db,0x39dc,0x39dd,0x39de,0x39df,
+ 0x39e0,0x39e1,0x39e2,0x39e3,0x39e4,0x39e5,0x39e6,0x39e7,
+ 0x39e8,0x39e9,0x39ea,0x39eb,0x39ec,0x39ed,0x39ee,0x39ef,
+ 0x39f0,0x39f1,0x39f2,0x39f3,0x39f4,0x39f5,0x39f6,0x39f7,
+ 0x39f8,0x39f9,0x39fa,0x39fb,0x39fc,0x39fd,0x39fe,0x39ff,
+ 0x3a00,0x3a01,0x3a02,0x3a03,0x3a04,0x3a05,0x3a06,0x3a07,
+ 0x3a08,0x3a09,0x3a0a,0x3a0b,0x3a0c,0x3a0d,0x3a0e,0x3a0f,
+ 0x3a10,0x3a11,0x3a12,0x3a13,0x3a14,0x3a15,0x3a16,0x3a17,
+ 0x3a18,0x3a19,0x3a1a,0x3a1b,0x3a1c,0x3a1d,0x3a1e,0x3a1f,
+ 0x3a20,0x3a21,0x3a22,0x3a23,0x3a24,0x3a25,0x3a26,0x3a27,
+ 0x3a28,0x3a29,0x3a2a,0x3a2b,0x3a2c,0x3a2d,0x3a2e,0x3a2f,
+ 0x3a30,0x3a31,0x3a32,0x3a33,0x3a34,0x3a35,0x3a36,0x3a37,
+ 0x3a38,0x3a39,0x3a3a,0x3a3b,0x3a3c,0x3a3d,0x3a3e,0x3a3f,
+ 0x3a40,0x3a41,0x3a42,0x3a43,0x3a44,0x3a45,0x3a46,0x3a47,
+ 0x3a48,0x3a49,0x3a4a,0x3a4b,0x3a4c,0x3a4d,0x3a4e,0x3a4f,
+ 0x3a50,0x3a51,0x3a52,0x3a53,0x3a54,0x3a55,0x3a56,0x3a57,
+ 0x3a58,0x3a59,0x3a5a,0x3a5b,0x3a5c,0x3a5d,0x3a5e,0x3a5f,
+ 0x3a60,0x3a61,0x3a62,0x3a63,0x3a64,0x3a65,0x3a66,0x3a67,
+ 0x3a68,0x3a69,0x3a6a,0x3a6b,0x3a6c,0x3a6d,0x3a6e,0x3a6f,
+ 0x3a70,0x3a71,0x3a72,0x3a73,0x3a74,0x3a75,0x3a76,0x3a77,
+ 0x3a78,0x3a79,0x3a7a,0x3a7b,0x3a7c,0x3a7d,0x3a7e,0x3a7f,
+ 0x3a80,0x3a81,0x3a82,0x3a83,0x3a84,0x3a85,0x3a86,0x3a87,
+ 0x3a88,0x3a89,0x3a8a,0x3a8b,0x3a8c,0x3a8d,0x3a8e,0x3a8f,
+ 0x3a90,0x3a91,0x3a92,0x3a93,0x3a94,0x3a95,0x3a96,0x3a97,
+ 0x3a98,0x3a99,0x3a9a,0x3a9b,0x3a9c,0x3a9d,0x3a9e,0x3a9f,
+ 0x3aa0,0x3aa1,0x3aa2,0x3aa3,0x3aa4,0x3aa5,0x3aa6,0x3aa7,
+ 0x3aa8,0x3aa9,0x3aaa,0x3aab,0x3aac,0x3aad,0x3aae,0x3aaf,
+ 0x3ab0,0x3ab1,0x3ab2,0x3ab3,0x3ab4,0x3ab5,0x3ab6,0x3ab7,
+ 0x3ab8,0x3ab9,0x3aba,0x3abb,0x3abc,0x3abd,0x3abe,0x3abf,
+ 0x3ac0,0x3ac1,0x3ac2,0x3ac3,0x3ac4,0x3ac5,0x3ac6,0x3ac7,
+ 0x3ac8,0x3ac9,0x3aca,0x3acb,0x3acc,0x3acd,0x3ace,0x3acf,
+ 0x3ad0,0x3ad1,0x3ad2,0x3ad3,0x3ad4,0x3ad5,0x3ad6,0x3ad7,
+ 0x3ad8,0x3ad9,0x3ada,0x3adb,0x3adc,0x3add,0x3ade,0x3adf,
+ 0x3ae0,0x3ae1,0x3ae2,0x3ae3,0x3ae4,0x3ae5,0x3ae6,0x3ae7,
+ 0x3ae8,0x3ae9,0x3aea,0x3aeb,0x3aec,0x3aed,0x3aee,0x3aef,
+ 0x3af0,0x3af1,0x3af2,0x3af3,0x3af4,0x3af5,0x3af6,0x3af7,
+ 0x3af8,0x3af9,0x3afa,0x3afb,0x3afc,0x3afd,0x3afe,0x3aff,
+ 0x3b00,0x3b01,0x3b02,0x3b03,0x3b04,0x3b05,0x3b06,0x3b07,
+ 0x3b08,0x3b09,0x3b0a,0x3b0b,0x3b0c,0x3b0d,0x3b0e,0x3b0f,
+ 0x3b10,0x3b11,0x3b12,0x3b13,0x3b14,0x3b15,0x3b16,0x3b17,
+ 0x3b18,0x3b19,0x3b1a,0x3b1b,0x3b1c,0x3b1d,0x3b1e,0x3b1f,
+ 0x3b20,0x3b21,0x3b22,0x3b23,0x3b24,0x3b25,0x3b26,0x3b27,
+ 0x3b28,0x3b29,0x3b2a,0x3b2b,0x3b2c,0x3b2d,0x3b2e,0x3b2f,
+ 0x3b30,0x3b31,0x3b32,0x3b33,0x3b34,0x3b35,0x3b36,0x3b37,
+ 0x3b38,0x3b39,0x3b3a,0x3b3b,0x3b3c,0x3b3d,0x3b3e,0x3b3f,
+ 0x3b40,0x3b41,0x3b42,0x3b43,0x3b44,0x3b45,0x3b46,0x3b47,
+ 0x3b48,0x3b49,0x3b4a,0x3b4b,0x3b4c,0x3b4d,0x3b4e,0x3b4f,
+ 0x3b50,0x3b51,0x3b52,0x3b53,0x3b54,0x3b55,0x3b56,0x3b57,
+ 0x3b58,0x3b59,0x3b5a,0x3b5b,0x3b5c,0x3b5d,0x3b5e,0x3b5f,
+ 0x3b60,0x3b61,0x3b62,0x3b63,0x3b64,0x3b65,0x3b66,0x3b67,
+ 0x3b68,0x3b69,0x3b6a,0x3b6b,0x3b6c,0x3b6d,0x3b6e,0x3b6f,
+ 0x3b70,0x3b71,0x3b72,0x3b73,0x3b74,0x3b75,0x3b76,0x3b77,
+ 0x3b78,0x3b79,0x3b7a,0x3b7b,0x3b7c,0x3b7d,0x3b7e,0x3b7f,
+ 0x3b80,0x3b81,0x3b82,0x3b83,0x3b84,0x3b85,0x3b86,0x3b87,
+ 0x3b88,0x3b89,0x3b8a,0x3b8b,0x3b8c,0x3b8d,0x3b8e,0x3b8f,
+ 0x3b90,0x3b91,0x3b92,0x3b93,0x3b94,0x3b95,0x3b96,0x3b97,
+ 0x3b98,0x3b99,0x3b9a,0x3b9b,0x3b9c,0x3b9d,0x3b9e,0x3b9f,
+ 0x3ba0,0x3ba1,0x3ba2,0x3ba3,0x3ba4,0x3ba5,0x3ba6,0x3ba7,
+ 0x3ba8,0x3ba9,0x3baa,0x3bab,0x3bac,0x3bad,0x3bae,0x3baf,
+ 0x3bb0,0x3bb1,0x3bb2,0x3bb3,0x3bb4,0x3bb5,0x3bb6,0x3bb7,
+ 0x3bb8,0x3bb9,0x3bba,0x3bbb,0x3bbc,0x3bbd,0x3bbe,0x3bbf,
+ 0x3bc0,0x3bc1,0x3bc2,0x3bc3,0x3bc4,0x3bc5,0x3bc6,0x3bc7,
+ 0x3bc8,0x3bc9,0x3bca,0x3bcb,0x3bcc,0x3bcd,0x3bce,0x3bcf,
+ 0x3bd0,0x3bd1,0x3bd2,0x3bd3,0x3bd4,0x3bd5,0x3bd6,0x3bd7,
+ 0x3bd8,0x3bd9,0x3bda,0x3bdb,0x3bdc,0x3bdd,0x3bde,0x3bdf,
+ 0x3be0,0x3be1,0x3be2,0x3be3,0x3be4,0x3be5,0x3be6,0x3be7,
+ 0x3be8,0x3be9,0x3bea,0x3beb,0x3bec,0x3bed,0x3bee,0x3bef,
+ 0x3bf0,0x3bf1,0x3bf2,0x3bf3,0x3bf4,0x3bf5,0x3bf6,0x3bf7,
+ 0x3bf8,0x3bf9,0x3bfa,0x3bfb,0x3bfc,0x3bfd,0x3bfe,0x3bff,
+ 0x3c00,0x3c01,0x3c02,0x3c03,0x3c04,0x3c05,0x3c06,0x3c07,
+ 0x3c08,0x3c09,0x3c0a,0x3c0b,0x3c0c,0x3c0d,0x3c0e,0x3c0f,
+ 0x3c10,0x3c11,0x3c12,0x3c13,0x3c14,0x3c15,0x3c16,0x3c17,
+ 0x3c18,0x3c19,0x3c1a,0x3c1b,0x3c1c,0x3c1d,0x3c1e,0x3c1f,
+ 0x3c20,0x3c21,0x3c22,0x3c23,0x3c24,0x3c25,0x3c26,0x3c27,
+ 0x3c28,0x3c29,0x3c2a,0x3c2b,0x3c2c,0x3c2d,0x3c2e,0x3c2f,
+ 0x3c30,0x3c31,0x3c32,0x3c33,0x3c34,0x3c35,0x3c36,0x3c37,
+ 0x3c38,0x3c39,0x3c3a,0x3c3b,0x3c3c,0x3c3d,0x3c3e,0x3c3f,
+ 0x3c40,0x3c41,0x3c42,0x3c43,0x3c44,0x3c45,0x3c46,0x3c47,
+ 0x3c48,0x3c49,0x3c4a,0x3c4b,0x3c4c,0x3c4d,0x3c4e,0x3c4f,
+ 0x3c50,0x3c51,0x3c52,0x3c53,0x3c54,0x3c55,0x3c56,0x3c57,
+ 0x3c58,0x3c59,0x3c5a,0x3c5b,0x3c5c,0x3c5d,0x3c5e,0x3c5f,
+ 0x3c60,0x3c61,0x3c62,0x3c63,0x3c64,0x3c65,0x3c66,0x3c67,
+ 0x3c68,0x3c69,0x3c6a,0x3c6b,0x3c6c,0x3c6d,0x3c6e,0x3c6f,
+ 0x3c70,0x3c71,0x3c72,0x3c73,0x3c74,0x3c75,0x3c76,0x3c77,
+ 0x3c78,0x3c79,0x3c7a,0x3c7b,0x3c7c,0x3c7d,0x3c7e,0x3c7f,
+ 0x3c80,0x3c81,0x3c82,0x3c83,0x3c84,0x3c85,0x3c86,0x3c87,
+ 0x3c88,0x3c89,0x3c8a,0x3c8b,0x3c8c,0x3c8d,0x3c8e,0x3c8f,
+ 0x3c90,0x3c91,0x3c92,0x3c93,0x3c94,0x3c95,0x3c96,0x3c97,
+ 0x3c98,0x3c99,0x3c9a,0x3c9b,0x3c9c,0x3c9d,0x3c9e,0x3c9f,
+ 0x3ca0,0x3ca1,0x3ca2,0x3ca3,0x3ca4,0x3ca5,0x3ca6,0x3ca7,
+ 0x3ca8,0x3ca9,0x3caa,0x3cab,0x3cac,0x3cad,0x3cae,0x3caf,
+ 0x3cb0,0x3cb1,0x3cb2,0x3cb3,0x3cb4,0x3cb5,0x3cb6,0x3cb7,
+ 0x3cb8,0x3cb9,0x3cba,0x3cbb,0x3cbc,0x3cbd,0x3cbe,0x3cbf,
+ 0x3cc0,0x3cc1,0x3cc2,0x3cc3,0x3cc4,0x3cc5,0x3cc6,0x3cc7,
+ 0x3cc8,0x3cc9,0x3cca,0x3ccb,0x3ccc,0x3ccd,0x3cce,0x3ccf,
+ 0x3cd0,0x3cd1,0x3cd2,0x3cd3,0x3cd4,0x3cd5,0x3cd6,0x3cd7,
+ 0x3cd8,0x3cd9,0x3cda,0x3cdb,0x3cdc,0x3cdd,0x3cde,0x3cdf,
+ 0x3ce0,0x3ce1,0x3ce2,0x3ce3,0x3ce4,0x3ce5,0x3ce6,0x3ce7,
+ 0x3ce8,0x3ce9,0x3cea,0x3ceb,0x3cec,0x3ced,0x3cee,0x3cef,
+ 0x3cf0,0x3cf1,0x3cf2,0x3cf3,0x3cf4,0x3cf5,0x3cf6,0x3cf7,
+ 0x3cf8,0x3cf9,0x3cfa,0x3cfb,0x3cfc,0x3cfd,0x3cfe,0x3cff,
+ 0x3d00,0x3d01,0x3d02,0x3d03,0x3d04,0x3d05,0x3d06,0x3d07,
+ 0x3d08,0x3d09,0x3d0a,0x3d0b,0x3d0c,0x3d0d,0x3d0e,0x3d0f,
+ 0x3d10,0x3d11,0x3d12,0x3d13,0x3d14,0x3d15,0x3d16,0x3d17,
+ 0x3d18,0x3d19,0x3d1a,0x3d1b,0x3d1c,0x3d1d,0x3d1e,0x3d1f,
+ 0x3d20,0x3d21,0x3d22,0x3d23,0x3d24,0x3d25,0x3d26,0x3d27,
+ 0x3d28,0x3d29,0x3d2a,0x3d2b,0x3d2c,0x3d2d,0x3d2e,0x3d2f,
+ 0x3d30,0x3d31,0x3d32,0x3d33,0x3d34,0x3d35,0x3d36,0x3d37,
+ 0x3d38,0x3d39,0x3d3a,0x3d3b,0x3d3c,0x3d3d,0x3d3e,0x3d3f,
+ 0x3d40,0x3d41,0x3d42,0x3d43,0x3d44,0x3d45,0x3d46,0x3d47,
+ 0x3d48,0x3d49,0x3d4a,0x3d4b,0x3d4c,0x3d4d,0x3d4e,0x3d4f,
+ 0x3d50,0x3d51,0x3d52,0x3d53,0x3d54,0x3d55,0x3d56,0x3d57,
+ 0x3d58,0x3d59,0x3d5a,0x3d5b,0x3d5c,0x3d5d,0x3d5e,0x3d5f,
+ 0x3d60,0x3d61,0x3d62,0x3d63,0x3d64,0x3d65,0x3d66,0x3d67,
+ 0x3d68,0x3d69,0x3d6a,0x3d6b,0x3d6c,0x3d6d,0x3d6e,0x3d6f,
+ 0x3d70,0x3d71,0x3d72,0x3d73,0x3d74,0x3d75,0x3d76,0x3d77,
+ 0x3d78,0x3d79,0x3d7a,0x3d7b,0x3d7c,0x3d7d,0x3d7e,0x3d7f,
+ 0x3d80,0x3d81,0x3d82,0x3d83,0x3d84,0x3d85,0x3d86,0x3d87,
+ 0x3d88,0x3d89,0x3d8a,0x3d8b,0x3d8c,0x3d8d,0x3d8e,0x3d8f,
+ 0x3d90,0x3d91,0x3d92,0x3d93,0x3d94,0x3d95,0x3d96,0x3d97,
+ 0x3d98,0x3d99,0x3d9a,0x3d9b,0x3d9c,0x3d9d,0x3d9e,0x3d9f,
+ 0x3da0,0x3da1,0x3da2,0x3da3,0x3da4,0x3da5,0x3da6,0x3da7,
+ 0x3da8,0x3da9,0x3daa,0x3dab,0x3dac,0x3dad,0x3dae,0x3daf,
+ 0x3db0,0x3db1,0x3db2,0x3db3,0x3db4,0x3db5,0x3db6,0x3db7,
+ 0x3db8,0x3db9,0x3dba,0x3dbb,0x3dbc,0x3dbd,0x3dbe,0x3dbf,
+ 0x3dc0,0x3dc1,0x3dc2,0x3dc3,0x3dc4,0x3dc5,0x3dc6,0x3dc7,
+ 0x3dc8,0x3dc9,0x3dca,0x3dcb,0x3dcc,0x3dcd,0x3dce,0x3dcf,
+ 0x3dd0,0x3dd1,0x3dd2,0x3dd3,0x3dd4,0x3dd5,0x3dd6,0x3dd7,
+ 0x3dd8,0x3dd9,0x3dda,0x3ddb,0x3ddc,0x3ddd,0x3dde,0x3ddf,
+ 0x3de0,0x3de1,0x3de2,0x3de3,0x3de4,0x3de5,0x3de6,0x3de7,
+ 0x3de8,0x3de9,0x3dea,0x3deb,0x3dec,0x3ded,0x3dee,0x3def,
+ 0x3df0,0x3df1,0x3df2,0x3df3,0x3df4,0x3df5,0x3df6,0x3df7,
+ 0x3df8,0x3df9,0x3dfa,0x3dfb,0x3dfc,0x3dfd,0x3dfe,0x3dff,
+ 0x3e00,0x3e01,0x3e02,0x3e03,0x3e04,0x3e05,0x3e06,0x3e07,
+ 0x3e08,0x3e09,0x3e0a,0x3e0b,0x3e0c,0x3e0d,0x3e0e,0x3e0f,
+ 0x3e10,0x3e11,0x3e12,0x3e13,0x3e14,0x3e15,0x3e16,0x3e17,
+ 0x3e18,0x3e19,0x3e1a,0x3e1b,0x3e1c,0x3e1d,0x3e1e,0x3e1f,
+ 0x3e20,0x3e21,0x3e22,0x3e23,0x3e24,0x3e25,0x3e26,0x3e27,
+ 0x3e28,0x3e29,0x3e2a,0x3e2b,0x3e2c,0x3e2d,0x3e2e,0x3e2f,
+ 0x3e30,0x3e31,0x3e32,0x3e33,0x3e34,0x3e35,0x3e36,0x3e37,
+ 0x3e38,0x3e39,0x3e3a,0x3e3b,0x3e3c,0x3e3d,0x3e3e,0x3e3f,
+ 0x3e40,0x3e41,0x3e42,0x3e43,0x3e44,0x3e45,0x3e46,0x3e47,
+ 0x3e48,0x3e49,0x3e4a,0x3e4b,0x3e4c,0x3e4d,0x3e4e,0x3e4f,
+ 0x3e50,0x3e51,0x3e52,0x3e53,0x3e54,0x3e55,0x3e56,0x3e57,
+ 0x3e58,0x3e59,0x3e5a,0x3e5b,0x3e5c,0x3e5d,0x3e5e,0x3e5f,
+ 0x3e60,0x3e61,0x3e62,0x3e63,0x3e64,0x3e65,0x3e66,0x3e67,
+ 0x3e68,0x3e69,0x3e6a,0x3e6b,0x3e6c,0x3e6d,0x3e6e,0x3e6f,
+ 0x3e70,0x3e71,0x3e72,0x3e73,0x3e74,0x3e75,0x3e76,0x3e77,
+ 0x3e78,0x3e79,0x3e7a,0x3e7b,0x3e7c,0x3e7d,0x3e7e,0x3e7f,
+ 0x3e80,0x3e81,0x3e82,0x3e83,0x3e84,0x3e85,0x3e86,0x3e87,
+ 0x3e88,0x3e89,0x3e8a,0x3e8b,0x3e8c,0x3e8d,0x3e8e,0x3e8f,
+ 0x3e90,0x3e91,0x3e92,0x3e93,0x3e94,0x3e95,0x3e96,0x3e97,
+ 0x3e98,0x3e99,0x3e9a,0x3e9b,0x3e9c,0x3e9d,0x3e9e,0x3e9f,
+ 0x3ea0,0x3ea1,0x3ea2,0x3ea3,0x3ea4,0x3ea5,0x3ea6,0x3ea7,
+ 0x3ea8,0x3ea9,0x3eaa,0x3eab,0x3eac,0x3ead,0x3eae,0x3eaf,
+ 0x3eb0,0x3eb1,0x3eb2,0x3eb3,0x3eb4,0x3eb5,0x3eb6,0x3eb7,
+ 0x3eb8,0x3eb9,0x3eba,0x3ebb,0x3ebc,0x3ebd,0x3ebe,0x3ebf,
+ 0x3ec0,0x3ec1,0x3ec2,0x3ec3,0x3ec4,0x3ec5,0x3ec6,0x3ec7,
+ 0x3ec8,0x3ec9,0x3eca,0x3ecb,0x3ecc,0x3ecd,0x3ece,0x3ecf,
+ 0x3ed0,0x3ed1,0x3ed2,0x3ed3,0x3ed4,0x3ed5,0x3ed6,0x3ed7,
+ 0x3ed8,0x3ed9,0x3eda,0x3edb,0x3edc,0x3edd,0x3ede,0x3edf,
+ 0x3ee0,0x3ee1,0x3ee2,0x3ee3,0x3ee4,0x3ee5,0x3ee6,0x3ee7,
+ 0x3ee8,0x3ee9,0x3eea,0x3eeb,0x3eec,0x3eed,0x3eee,0x3eef,
+ 0x3ef0,0x3ef1,0x3ef2,0x3ef3,0x3ef4,0x3ef5,0x3ef6,0x3ef7,
+ 0x3ef8,0x3ef9,0x3efa,0x3efb,0x3efc,0x3efd,0x3efe,0x3eff,
+ 0x3f00,0x3f01,0x3f02,0x3f03,0x3f04,0x3f05,0x3f06,0x3f07,
+ 0x3f08,0x3f09,0x3f0a,0x3f0b,0x3f0c,0x3f0d,0x3f0e,0x3f0f,
+ 0x3f10,0x3f11,0x3f12,0x3f13,0x3f14,0x3f15,0x3f16,0x3f17,
+ 0x3f18,0x3f19,0x3f1a,0x3f1b,0x3f1c,0x3f1d,0x3f1e,0x3f1f,
+ 0x3f20,0x3f21,0x3f22,0x3f23,0x3f24,0x3f25,0x3f26,0x3f27,
+ 0x3f28,0x3f29,0x3f2a,0x3f2b,0x3f2c,0x3f2d,0x3f2e,0x3f2f,
+ 0x3f30,0x3f31,0x3f32,0x3f33,0x3f34,0x3f35,0x3f36,0x3f37,
+ 0x3f38,0x3f39,0x3f3a,0x3f3b,0x3f3c,0x3f3d,0x3f3e,0x3f3f,
+ 0x3f40,0x3f41,0x3f42,0x3f43,0x3f44,0x3f45,0x3f46,0x3f47,
+ 0x3f48,0x3f49,0x3f4a,0x3f4b,0x3f4c,0x3f4d,0x3f4e,0x3f4f,
+ 0x3f50,0x3f51,0x3f52,0x3f53,0x3f54,0x3f55,0x3f56,0x3f57,
+ 0x3f58,0x3f59,0x3f5a,0x3f5b,0x3f5c,0x3f5d,0x3f5e,0x3f5f,
+ 0x3f60,0x3f61,0x3f62,0x3f63,0x3f64,0x3f65,0x3f66,0x3f67,
+ 0x3f68,0x3f69,0x3f6a,0x3f6b,0x3f6c,0x3f6d,0x3f6e,0x3f6f,
+ 0x3f70,0x3f71,0x3f72,0x3f73,0x3f74,0x3f75,0x3f76,0x3f77,
+ 0x3f78,0x3f79,0x3f7a,0x3f7b,0x3f7c,0x3f7d,0x3f7e,0x3f7f,
+ 0x3f80,0x3f81,0x3f82,0x3f83,0x3f84,0x3f85,0x3f86,0x3f87,
+ 0x3f88,0x3f89,0x3f8a,0x3f8b,0x3f8c,0x3f8d,0x3f8e,0x3f8f,
+ 0x3f90,0x3f91,0x3f92,0x3f93,0x3f94,0x3f95,0x3f96,0x3f97,
+ 0x3f98,0x3f99,0x3f9a,0x3f9b,0x3f9c,0x3f9d,0x3f9e,0x3f9f,
+ 0x3fa0,0x3fa1,0x3fa2,0x3fa3,0x3fa4,0x3fa5,0x3fa6,0x3fa7,
+ 0x3fa8,0x3fa9,0x3faa,0x3fab,0x3fac,0x3fad,0x3fae,0x3faf,
+ 0x3fb0,0x3fb1,0x3fb2,0x3fb3,0x3fb4,0x3fb5,0x3fb6,0x3fb7,
+ 0x3fb8,0x3fb9,0x3fba,0x3fbb,0x3fbc,0x3fbd,0x3fbe,0x3fbf,
+ 0x3fc0,0x3fc1,0x3fc2,0x3fc3,0x3fc4,0x3fc5,0x3fc6,0x3fc7,
+ 0x3fc8,0x3fc9,0x3fca,0x3fcb,0x3fcc,0x3fcd,0x3fce,0x3fcf,
+ 0x3fd0,0x3fd1,0x3fd2,0x3fd3,0x3fd4,0x3fd5,0x3fd6,0x3fd7,
+ 0x3fd8,0x3fd9,0x3fda,0x3fdb,0x3fdc,0x3fdd,0x3fde,0x3fdf,
+ 0x3fe0,0x3fe1,0x3fe2,0x3fe3,0x3fe4,0x3fe5,0x3fe6,0x3fe7,
+ 0x3fe8,0x3fe9,0x3fea,0x3feb,0x3fec,0x3fed,0x3fee,0x3fef,
+ 0x3ff0,0x3ff1,0x3ff2,0x3ff3,0x3ff4,0x3ff5,0x3ff6,0x3ff7,
+ 0x3ff8,0x3ff9,0x3ffa,0x3ffb,0x3ffc,0x3ffd,0x3ffe,0x3fff,
+ 0x4000,0x4001,0x4002,0x4003,0x4004,0x4005,0x4006,0x4007,
+ 0x4008,0x4009,0x400a,0x400b,0x400c,0x400d,0x400e,0x400f,
+ 0x4010,0x4011,0x4012,0x4013,0x4014,0x4015,0x4016,0x4017,
+ 0x4018,0x4019,0x401a,0x401b,0x401c,0x401d,0x401e,0x401f,
+ 0x4020,0x4021,0x4022,0x4023,0x4024,0x4025,0x4026,0x4027,
+ 0x4028,0x4029,0x402a,0x402b,0x402c,0x402d,0x402e,0x402f,
+ 0x4030,0x4031,0x4032,0x4033,0x4034,0x4035,0x4036,0x4037,
+ 0x4038,0x4039,0x403a,0x403b,0x403c,0x403d,0x403e,0x403f,
+ 0x4040,0x4041,0x4042,0x4043,0x4044,0x4045,0x4046,0x4047,
+ 0x4048,0x4049,0x404a,0x404b,0x404c,0x404d,0x404e,0x404f,
+ 0x4050,0x4051,0x4052,0x4053,0x4054,0x4055,0x4056,0x4057,
+ 0x4058,0x4059,0x405a,0x405b,0x405c,0x405d,0x405e,0x405f,
+ 0x4060,0x4061,0x4062,0x4063,0x4064,0x4065,0x4066,0x4067,
+ 0x4068,0x4069,0x406a,0x406b,0x406c,0x406d,0x406e,0x406f,
+ 0x4070,0x4071,0x4072,0x4073,0x4074,0x4075,0x4076,0x4077,
+ 0x4078,0x4079,0x407a,0x407b,0x407c,0x407d,0x407e,0x407f,
+ 0x4080,0x4081,0x4082,0x4083,0x4084,0x4085,0x4086,0x4087,
+ 0x4088,0x4089,0x408a,0x408b,0x408c,0x408d,0x408e,0x408f,
+ 0x4090,0x4091,0x4092,0x4093,0x4094,0x4095,0x4096,0x4097,
+ 0x4098,0x4099,0x409a,0x409b,0x409c,0x409d,0x409e,0x409f,
+ 0x40a0,0x40a1,0x40a2,0x40a3,0x40a4,0x40a5,0x40a6,0x40a7,
+ 0x40a8,0x40a9,0x40aa,0x40ab,0x40ac,0x40ad,0x40ae,0x40af,
+ 0x40b0,0x40b1,0x40b2,0x40b3,0x40b4,0x40b5,0x40b6,0x40b7,
+ 0x40b8,0x40b9,0x40ba,0x40bb,0x40bc,0x40bd,0x40be,0x40bf,
+ 0x40c0,0x40c1,0x40c2,0x40c3,0x40c4,0x40c5,0x40c6,0x40c7,
+ 0x40c8,0x40c9,0x40ca,0x40cb,0x40cc,0x40cd,0x40ce,0x40cf,
+ 0x40d0,0x40d1,0x40d2,0x40d3,0x40d4,0x40d5,0x40d6,0x40d7,
+ 0x40d8,0x40d9,0x40da,0x40db,0x40dc,0x40dd,0x40de,0x40df,
+ 0x40e0,0x40e1,0x40e2,0x40e3,0x40e4,0x40e5,0x40e6,0x40e7,
+ 0x40e8,0x40e9,0x40ea,0x40eb,0x40ec,0x40ed,0x40ee,0x40ef,
+ 0x40f0,0x40f1,0x40f2,0x40f3,0x40f4,0x40f5,0x40f6,0x40f7,
+ 0x40f8,0x40f9,0x40fa,0x40fb,0x40fc,0x40fd,0x40fe,0x40ff,
+ 0x4100,0x4101,0x4102,0x4103,0x4104,0x4105,0x4106,0x4107,
+ 0x4108,0x4109,0x410a,0x410b,0x410c,0x410d,0x410e,0x410f,
+ 0x4110,0x4111,0x4112,0x4113,0x4114,0x4115,0x4116,0x4117,
+ 0x4118,0x4119,0x411a,0x411b,0x411c,0x411d,0x411e,0x411f,
+ 0x4120,0x4121,0x4122,0x4123,0x4124,0x4125,0x4126,0x4127,
+ 0x4128,0x4129,0x412a,0x412b,0x412c,0x412d,0x412e,0x412f,
+ 0x4130,0x4131,0x4132,0x4133,0x4134,0x4135,0x4136,0x4137,
+ 0x4138,0x4139,0x413a,0x413b,0x413c,0x413d,0x413e,0x413f,
+ 0x4140,0x4141,0x4142,0x4143,0x4144,0x4145,0x4146,0x4147,
+ 0x4148,0x4149,0x414a,0x414b,0x414c,0x414d,0x414e,0x414f,
+ 0x4150,0x4151,0x4152,0x4153,0x4154,0x4155,0x4156,0x4157,
+ 0x4158,0x4159,0x415a,0x415b,0x415c,0x415d,0x415e,0x415f,
+ 0x4160,0x4161,0x4162,0x4163,0x4164,0x4165,0x4166,0x4167,
+ 0x4168,0x4169,0x416a,0x416b,0x416c,0x416d,0x416e,0x416f,
+ 0x4170,0x4171,0x4172,0x4173,0x4174,0x4175,0x4176,0x4177,
+ 0x4178,0x4179,0x417a,0x417b,0x417c,0x417d,0x417e,0x417f,
+ 0x4180,0x4181,0x4182,0x4183,0x4184,0x4185,0x4186,0x4187,
+ 0x4188,0x4189,0x418a,0x418b,0x418c,0x418d,0x418e,0x418f,
+ 0x4190,0x4191,0x4192,0x4193,0x4194,0x4195,0x4196,0x4197,
+ 0x4198,0x4199,0x419a,0x419b,0x419c,0x419d,0x419e,0x419f,
+ 0x41a0,0x41a1,0x41a2,0x41a3,0x41a4,0x41a5,0x41a6,0x41a7,
+ 0x41a8,0x41a9,0x41aa,0x41ab,0x41ac,0x41ad,0x41ae,0x41af,
+ 0x41b0,0x41b1,0x41b2,0x41b3,0x41b4,0x41b5,0x41b6,0x41b7,
+ 0x41b8,0x41b9,0x41ba,0x41bb,0x41bc,0x41bd,0x41be,0x41bf,
+ 0x41c0,0x41c1,0x41c2,0x41c3,0x41c4,0x41c5,0x41c6,0x41c7,
+ 0x41c8,0x41c9,0x41ca,0x41cb,0x41cc,0x41cd,0x41ce,0x41cf,
+ 0x41d0,0x41d1,0x41d2,0x41d3,0x41d4,0x41d5,0x41d6,0x41d7,
+ 0x41d8,0x41d9,0x41da,0x41db,0x41dc,0x41dd,0x41de,0x41df,
+ 0x41e0,0x41e1,0x41e2,0x41e3,0x41e4,0x41e5,0x41e6,0x41e7,
+ 0x41e8,0x41e9,0x41ea,0x41eb,0x41ec,0x41ed,0x41ee,0x41ef,
+ 0x41f0,0x41f1,0x41f2,0x41f3,0x41f4,0x41f5,0x41f6,0x41f7,
+ 0x41f8,0x41f9,0x41fa,0x41fb,0x41fc,0x41fd,0x41fe,0x41ff,
+ 0x4200,0x4201,0x4202,0x4203,0x4204,0x4205,0x4206,0x4207,
+ 0x4208,0x4209,0x420a,0x420b,0x420c,0x420d,0x420e,0x420f,
+ 0x4210,0x4211,0x4212,0x4213,0x4214,0x4215,0x4216,0x4217,
+ 0x4218,0x4219,0x421a,0x421b,0x421c,0x421d,0x421e,0x421f,
+ 0x4220,0x4221,0x4222,0x4223,0x4224,0x4225,0x4226,0x4227,
+ 0x4228,0x4229,0x422a,0x422b,0x422c,0x422d,0x422e,0x422f,
+ 0x4230,0x4231,0x4232,0x4233,0x4234,0x4235,0x4236,0x4237,
+ 0x4238,0x4239,0x423a,0x423b,0x423c,0x423d,0x423e,0x423f,
+ 0x4240,0x4241,0x4242,0x4243,0x4244,0x4245,0x4246,0x4247,
+ 0x4248,0x4249,0x424a,0x424b,0x424c,0x424d,0x424e,0x424f,
+ 0x4250,0x4251,0x4252,0x4253,0x4254,0x4255,0x4256,0x4257,
+ 0x4258,0x4259,0x425a,0x425b,0x425c,0x425d,0x425e,0x425f,
+ 0x4260,0x4261,0x4262,0x4263,0x4264,0x4265,0x4266,0x4267,
+ 0x4268,0x4269,0x426a,0x426b,0x426c,0x426d,0x426e,0x426f,
+ 0x4270,0x4271,0x4272,0x4273,0x4274,0x4275,0x4276,0x4277,
+ 0x4278,0x4279,0x427a,0x427b,0x427c,0x427d,0x427e,0x427f,
+ 0x4280,0x4281,0x4282,0x4283,0x4284,0x4285,0x4286,0x4287,
+ 0x4288,0x4289,0x428a,0x428b,0x428c,0x428d,0x428e,0x428f,
+ 0x4290,0x4291,0x4292,0x4293,0x4294,0x4295,0x4296,0x4297,
+ 0x4298,0x4299,0x429a,0x429b,0x429c,0x429d,0x429e,0x429f,
+ 0x42a0,0x42a1,0x42a2,0x42a3,0x42a4,0x42a5,0x42a6,0x42a7,
+ 0x42a8,0x42a9,0x42aa,0x42ab,0x42ac,0x42ad,0x42ae,0x42af,
+ 0x42b0,0x42b1,0x42b2,0x42b3,0x42b4,0x42b5,0x42b6,0x42b7,
+ 0x42b8,0x42b9,0x42ba,0x42bb,0x42bc,0x42bd,0x42be,0x42bf,
+ 0x42c0,0x42c1,0x42c2,0x42c3,0x42c4,0x42c5,0x42c6,0x42c7,
+ 0x42c8,0x42c9,0x42ca,0x42cb,0x42cc,0x42cd,0x42ce,0x42cf,
+ 0x42d0,0x42d1,0x42d2,0x42d3,0x42d4,0x42d5,0x42d6,0x42d7,
+ 0x42d8,0x42d9,0x42da,0x42db,0x42dc,0x42dd,0x42de,0x42df,
+ 0x42e0,0x42e1,0x42e2,0x42e3,0x42e4,0x42e5,0x42e6,0x42e7,
+ 0x42e8,0x42e9,0x42ea,0x42eb,0x42ec,0x42ed,0x42ee,0x42ef,
+ 0x42f0,0x42f1,0x42f2,0x42f3,0x42f4,0x42f5,0x42f6,0x42f7,
+ 0x42f8,0x42f9,0x42fa,0x42fb,0x42fc,0x42fd,0x42fe,0x42ff,
+ 0x4300,0x4301,0x4302,0x4303,0x4304,0x4305,0x4306,0x4307,
+ 0x4308,0x4309,0x430a,0x430b,0x430c,0x430d,0x430e,0x430f,
+ 0x4310,0x4311,0x4312,0x4313,0x4314,0x4315,0x4316,0x4317,
+ 0x4318,0x4319,0x431a,0x431b,0x431c,0x431d,0x431e,0x431f,
+ 0x4320,0x4321,0x4322,0x4323,0x4324,0x4325,0x4326,0x4327,
+ 0x4328,0x4329,0x432a,0x432b,0x432c,0x432d,0x432e,0x432f,
+ 0x4330,0x4331,0x4332,0x4333,0x4334,0x4335,0x4336,0x4337,
+ 0x4338,0x4339,0x433a,0x433b,0x433c,0x433d,0x433e,0x433f,
+ 0x4340,0x4341,0x4342,0x4343,0x4344,0x4345,0x4346,0x4347,
+ 0x4348,0x4349,0x434a,0x434b,0x434c,0x434d,0x434e,0x434f,
+ 0x4350,0x4351,0x4352,0x4353,0x4354,0x4355,0x4356,0x4357,
+ 0x4358,0x4359,0x435a,0x435b,0x435c,0x435d,0x435e,0x435f,
+ 0x4360,0x4361,0x4362,0x4363,0x4364,0x4365,0x4366,0x4367,
+ 0x4368,0x4369,0x436a,0x436b,0x436c,0x436d,0x436e,0x436f,
+ 0x4370,0x4371,0x4372,0x4373,0x4374,0x4375,0x4376,0x4377,
+ 0x4378,0x4379,0x437a,0x437b,0x437c,0x437d,0x437e,0x437f,
+ 0x4380,0x4381,0x4382,0x4383,0x4384,0x4385,0x4386,0x4387,
+ 0x4388,0x4389,0x438a,0x438b,0x438c,0x438d,0x438e,0x438f,
+ 0x4390,0x4391,0x4392,0x4393,0x4394,0x4395,0x4396,0x4397,
+ 0x4398,0x4399,0x439a,0x439b,0x439c,0x439d,0x439e,0x439f,
+ 0x43a0,0x43a1,0x43a2,0x43a3,0x43a4,0x43a5,0x43a6,0x43a7,
+ 0x43a8,0x43a9,0x43aa,0x43ab,0x43ac,0x43ad,0x43ae,0x43af,
+ 0x43b0,0x43b1,0x43b2,0x43b3,0x43b4,0x43b5,0x43b6,0x43b7,
+ 0x43b8,0x43b9,0x43ba,0x43bb,0x43bc,0x43bd,0x43be,0x43bf,
+ 0x43c0,0x43c1,0x43c2,0x43c3,0x43c4,0x43c5,0x43c6,0x43c7,
+ 0x43c8,0x43c9,0x43ca,0x43cb,0x43cc,0x43cd,0x43ce,0x43cf,
+ 0x43d0,0x43d1,0x43d2,0x43d3,0x43d4,0x43d5,0x43d6,0x43d7,
+ 0x43d8,0x43d9,0x43da,0x43db,0x43dc,0x43dd,0x43de,0x43df,
+ 0x43e0,0x43e1,0x43e2,0x43e3,0x43e4,0x43e5,0x43e6,0x43e7,
+ 0x43e8,0x43e9,0x43ea,0x43eb,0x43ec,0x43ed,0x43ee,0x43ef,
+ 0x43f0,0x43f1,0x43f2,0x43f3,0x43f4,0x43f5,0x43f6,0x43f7,
+ 0x43f8,0x43f9,0x43fa,0x43fb,0x43fc,0x43fd,0x43fe,0x43ff,
+ 0x4400,0x4401,0x4402,0x4403,0x4404,0x4405,0x4406,0x4407,
+ 0x4408,0x4409,0x440a,0x440b,0x440c,0x440d,0x440e,0x440f,
+ 0x4410,0x4411,0x4412,0x4413,0x4414,0x4415,0x4416,0x4417,
+ 0x4418,0x4419,0x441a,0x441b,0x441c,0x441d,0x441e,0x441f,
+ 0x4420,0x4421,0x4422,0x4423,0x4424,0x4425,0x4426,0x4427,
+ 0x4428,0x4429,0x442a,0x442b,0x442c,0x442d,0x442e,0x442f,
+ 0x4430,0x4431,0x4432,0x4433,0x4434,0x4435,0x4436,0x4437,
+ 0x4438,0x4439,0x443a,0x443b,0x443c,0x443d,0x443e,0x443f,
+ 0x4440,0x4441,0x4442,0x4443,0x4444,0x4445,0x4446,0x4447,
+ 0x4448,0x4449,0x444a,0x444b,0x444c,0x444d,0x444e,0x444f,
+ 0x4450,0x4451,0x4452,0x4453,0x4454,0x4455,0x4456,0x4457,
+ 0x4458,0x4459,0x445a,0x445b,0x445c,0x445d,0x445e,0x445f,
+ 0x4460,0x4461,0x4462,0x4463,0x4464,0x4465,0x4466,0x4467,
+ 0x4468,0x4469,0x446a,0x446b,0x446c,0x446d,0x446e,0x446f,
+ 0x4470,0x4471,0x4472,0x4473,0x4474,0x4475,0x4476,0x4477,
+ 0x4478,0x4479,0x447a,0x447b,0x447c,0x447d,0x447e,0x447f,
+ 0x4480,0x4481,0x4482,0x4483,0x4484,0x4485,0x4486,0x4487,
+ 0x4488,0x4489,0x448a,0x448b,0x448c,0x448d,0x448e,0x448f,
+ 0x4490,0x4491,0x4492,0x4493,0x4494,0x4495,0x4496,0x4497,
+ 0x4498,0x4499,0x449a,0x449b,0x449c,0x449d,0x449e,0x449f,
+ 0x44a0,0x44a1,0x44a2,0x44a3,0x44a4,0x44a5,0x44a6,0x44a7,
+ 0x44a8,0x44a9,0x44aa,0x44ab,0x44ac,0x44ad,0x44ae,0x44af,
+ 0x44b0,0x44b1,0x44b2,0x44b3,0x44b4,0x44b5,0x44b6,0x44b7,
+ 0x44b8,0x44b9,0x44ba,0x44bb,0x44bc,0x44bd,0x44be,0x44bf,
+ 0x44c0,0x44c1,0x44c2,0x44c3,0x44c4,0x44c5,0x44c6,0x44c7,
+ 0x44c8,0x44c9,0x44ca,0x44cb,0x44cc,0x44cd,0x44ce,0x44cf,
+ 0x44d0,0x44d1,0x44d2,0x44d3,0x44d4,0x44d5,0x44d6,0x44d7,
+ 0x44d8,0x44d9,0x44da,0x44db,0x44dc,0x44dd,0x44de,0x44df,
+ 0x44e0,0x44e1,0x44e2,0x44e3,0x44e4,0x44e5,0x44e6,0x44e7,
+ 0x44e8,0x44e9,0x44ea,0x44eb,0x44ec,0x44ed,0x44ee,0x44ef,
+ 0x44f0,0x44f1,0x44f2,0x44f3,0x44f4,0x44f5,0x44f6,0x44f7,
+ 0x44f8,0x44f9,0x44fa,0x44fb,0x44fc,0x44fd,0x44fe,0x44ff,
+ 0x4500,0x4501,0x4502,0x4503,0x4504,0x4505,0x4506,0x4507,
+ 0x4508,0x4509,0x450a,0x450b,0x450c,0x450d,0x450e,0x450f,
+ 0x4510,0x4511,0x4512,0x4513,0x4514,0x4515,0x4516,0x4517,
+ 0x4518,0x4519,0x451a,0x451b,0x451c,0x451d,0x451e,0x451f,
+ 0x4520,0x4521,0x4522,0x4523,0x4524,0x4525,0x4526,0x4527,
+ 0x4528,0x4529,0x452a,0x452b,0x452c,0x452d,0x452e,0x452f,
+ 0x4530,0x4531,0x4532,0x4533,0x4534,0x4535,0x4536,0x4537,
+ 0x4538,0x4539,0x453a,0x453b,0x453c,0x453d,0x453e,0x453f,
+ 0x4540,0x4541,0x4542,0x4543,0x4544,0x4545,0x4546,0x4547,
+ 0x4548,0x4549,0x454a,0x454b,0x454c,0x454d,0x454e,0x454f,
+ 0x4550,0x4551,0x4552,0x4553,0x4554,0x4555,0x4556,0x4557,
+ 0x4558,0x4559,0x455a,0x455b,0x455c,0x455d,0x455e,0x455f,
+ 0x4560,0x4561,0x4562,0x4563,0x4564,0x4565,0x4566,0x4567,
+ 0x4568,0x4569,0x456a,0x456b,0x456c,0x456d,0x456e,0x456f,
+ 0x4570,0x4571,0x4572,0x4573,0x4574,0x4575,0x4576,0x4577,
+ 0x4578,0x4579,0x457a,0x457b,0x457c,0x457d,0x457e,0x457f,
+ 0x4580,0x4581,0x4582,0x4583,0x4584,0x4585,0x4586,0x4587,
+ 0x4588,0x4589,0x458a,0x458b,0x458c,0x458d,0x458e,0x458f,
+ 0x4590,0x4591,0x4592,0x4593,0x4594,0x4595,0x4596,0x4597,
+ 0x4598,0x4599,0x459a,0x459b,0x459c,0x459d,0x459e,0x459f,
+ 0x45a0,0x45a1,0x45a2,0x45a3,0x45a4,0x45a5,0x45a6,0x45a7,
+ 0x45a8,0x45a9,0x45aa,0x45ab,0x45ac,0x45ad,0x45ae,0x45af,
+ 0x45b0,0x45b1,0x45b2,0x45b3,0x45b4,0x45b5,0x45b6,0x45b7,
+ 0x45b8,0x45b9,0x45ba,0x45bb,0x45bc,0x45bd,0x45be,0x45bf,
+ 0x45c0,0x45c1,0x45c2,0x45c3,0x45c4,0x45c5,0x45c6,0x45c7,
+ 0x45c8,0x45c9,0x45ca,0x45cb,0x45cc,0x45cd,0x45ce,0x45cf,
+ 0x45d0,0x45d1,0x45d2,0x45d3,0x45d4,0x45d5,0x45d6,0x45d7,
+ 0x45d8,0x45d9,0x45da,0x45db,0x45dc,0x45dd,0x45de,0x45df,
+ 0x45e0,0x45e1,0x45e2,0x45e3,0x45e4,0x45e5,0x45e6,0x45e7,
+ 0x45e8,0x45e9,0x45ea,0x45eb,0x45ec,0x45ed,0x45ee,0x45ef,
+ 0x45f0,0x45f1,0x45f2,0x45f3,0x45f4,0x45f5,0x45f6,0x45f7,
+ 0x45f8,0x45f9,0x45fa,0x45fb,0x45fc,0x45fd,0x45fe,0x45ff,
+ 0x4600,0x4601,0x4602,0x4603,0x4604,0x4605,0x4606,0x4607,
+ 0x4608,0x4609,0x460a,0x460b,0x460c,0x460d,0x460e,0x460f,
+ 0x4610,0x4611,0x4612,0x4613,0x4614,0x4615,0x4616,0x4617,
+ 0x4618,0x4619,0x461a,0x461b,0x461c,0x461d,0x461e,0x461f,
+ 0x4620,0x4621,0x4622,0x4623,0x4624,0x4625,0x4626,0x4627,
+ 0x4628,0x4629,0x462a,0x462b,0x462c,0x462d,0x462e,0x462f,
+ 0x4630,0x4631,0x4632,0x4633,0x4634,0x4635,0x4636,0x4637,
+ 0x4638,0x4639,0x463a,0x463b,0x463c,0x463d,0x463e,0x463f,
+ 0x4640,0x4641,0x4642,0x4643,0x4644,0x4645,0x4646,0x4647,
+ 0x4648,0x4649,0x464a,0x464b,0x464c,0x464d,0x464e,0x464f,
+ 0x4650,0x4651,0x4652,0x4653,0x4654,0x4655,0x4656,0x4657,
+ 0x4658,0x4659,0x465a,0x465b,0x465c,0x465d,0x465e,0x465f,
+ 0x4660,0x4661,0x4662,0x4663,0x4664,0x4665,0x4666,0x4667,
+ 0x4668,0x4669,0x466a,0x466b,0x466c,0x466d,0x466e,0x466f,
+ 0x4670,0x4671,0x4672,0x4673,0x4674,0x4675,0x4676,0x4677,
+ 0x4678,0x4679,0x467a,0x467b,0x467c,0x467d,0x467e,0x467f,
+ 0x4680,0x4681,0x4682,0x4683,0x4684,0x4685,0x4686,0x4687,
+ 0x4688,0x4689,0x468a,0x468b,0x468c,0x468d,0x468e,0x468f,
+ 0x4690,0x4691,0x4692,0x4693,0x4694,0x4695,0x4696,0x4697,
+ 0x4698,0x4699,0x469a,0x469b,0x469c,0x469d,0x469e,0x469f,
+ 0x46a0,0x46a1,0x46a2,0x46a3,0x46a4,0x46a5,0x46a6,0x46a7,
+ 0x46a8,0x46a9,0x46aa,0x46ab,0x46ac,0x46ad,0x46ae,0x46af,
+ 0x46b0,0x46b1,0x46b2,0x46b3,0x46b4,0x46b5,0x46b6,0x46b7,
+ 0x46b8,0x46b9,0x46ba,0x46bb,0x46bc,0x46bd,0x46be,0x46bf,
+ 0x46c0,0x46c1,0x46c2,0x46c3,0x46c4,0x46c5,0x46c6,0x46c7,
+ 0x46c8,0x46c9,0x46ca,0x46cb,0x46cc,0x46cd,0x46ce,0x46cf,
+ 0x46d0,0x46d1,0x46d2,0x46d3,0x46d4,0x46d5,0x46d6,0x46d7,
+ 0x46d8,0x46d9,0x46da,0x46db,0x46dc,0x46dd,0x46de,0x46df,
+ 0x46e0,0x46e1,0x46e2,0x46e3,0x46e4,0x46e5,0x46e6,0x46e7,
+ 0x46e8,0x46e9,0x46ea,0x46eb,0x46ec,0x46ed,0x46ee,0x46ef,
+ 0x46f0,0x46f1,0x46f2,0x46f3,0x46f4,0x46f5,0x46f6,0x46f7,
+ 0x46f8,0x46f9,0x46fa,0x46fb,0x46fc,0x46fd,0x46fe,0x46ff,
+ 0x4700,0x4701,0x4702,0x4703,0x4704,0x4705,0x4706,0x4707,
+ 0x4708,0x4709,0x470a,0x470b,0x470c,0x470d,0x470e,0x470f,
+ 0x4710,0x4711,0x4712,0x4713,0x4714,0x4715,0x4716,0x4717,
+ 0x4718,0x4719,0x471a,0x471b,0x471c,0x471d,0x471e,0x471f,
+ 0x4720,0x4721,0x4722,0x4723,0x4724,0x4725,0x4726,0x4727,
+ 0x4728,0x4729,0x472a,0x472b,0x472c,0x472d,0x472e,0x472f,
+ 0x4730,0x4731,0x4732,0x4733,0x4734,0x4735,0x4736,0x4737,
+ 0x4738,0x4739,0x473a,0x473b,0x473c,0x473d,0x473e,0x473f,
+ 0x4740,0x4741,0x4742,0x4743,0x4744,0x4745,0x4746,0x4747,
+ 0x4748,0x4749,0x474a,0x474b,0x474c,0x474d,0x474e,0x474f,
+ 0x4750,0x4751,0x4752,0x4753,0x4754,0x4755,0x4756,0x4757,
+ 0x4758,0x4759,0x475a,0x475b,0x475c,0x475d,0x475e,0x475f,
+ 0x4760,0x4761,0x4762,0x4763,0x4764,0x4765,0x4766,0x4767,
+ 0x4768,0x4769,0x476a,0x476b,0x476c,0x476d,0x476e,0x476f,
+ 0x4770,0x4771,0x4772,0x4773,0x4774,0x4775,0x4776,0x4777,
+ 0x4778,0x4779,0x477a,0x477b,0x477c,0x477d,0x477e,0x477f,
+ 0x4780,0x4781,0x4782,0x4783,0x4784,0x4785,0x4786,0x4787,
+ 0x4788,0x4789,0x478a,0x478b,0x478c,0x478d,0x478e,0x478f,
+ 0x4790,0x4791,0x4792,0x4793,0x4794,0x4795,0x4796,0x4797,
+ 0x4798,0x4799,0x479a,0x479b,0x479c,0x479d,0x479e,0x479f,
+ 0x47a0,0x47a1,0x47a2,0x47a3,0x47a4,0x47a5,0x47a6,0x47a7,
+ 0x47a8,0x47a9,0x47aa,0x47ab,0x47ac,0x47ad,0x47ae,0x47af,
+ 0x47b0,0x47b1,0x47b2,0x47b3,0x47b4,0x47b5,0x47b6,0x47b7,
+ 0x47b8,0x47b9,0x47ba,0x47bb,0x47bc,0x47bd,0x47be,0x47bf,
+ 0x47c0,0x47c1,0x47c2,0x47c3,0x47c4,0x47c5,0x47c6,0x47c7,
+ 0x47c8,0x47c9,0x47ca,0x47cb,0x47cc,0x47cd,0x47ce,0x47cf,
+ 0x47d0,0x47d1,0x47d2,0x47d3,0x47d4,0x47d5,0x47d6,0x47d7,
+ 0x47d8,0x47d9,0x47da,0x47db,0x47dc,0x47dd,0x47de,0x47df,
+ 0x47e0,0x47e1,0x47e2,0x47e3,0x47e4,0x47e5,0x47e6,0x47e7,
+ 0x47e8,0x47e9,0x47ea,0x47eb,0x47ec,0x47ed,0x47ee,0x47ef,
+ 0x47f0,0x47f1,0x47f2,0x47f3,0x47f4,0x47f5,0x47f6,0x47f7,
+ 0x47f8,0x47f9,0x47fa,0x47fb,0x47fc,0x47fd,0x47fe,0x47ff,
+ 0x4800,0x4801,0x4802,0x4803,0x4804,0x4805,0x4806,0x4807,
+ 0x4808,0x4809,0x480a,0x480b,0x480c,0x480d,0x480e,0x480f,
+ 0x4810,0x4811,0x4812,0x4813,0x4814,0x4815,0x4816,0x4817,
+ 0x4818,0x4819,0x481a,0x481b,0x481c,0x481d,0x481e,0x481f,
+ 0x4820,0x4821,0x4822,0x4823,0x4824,0x4825,0x4826,0x4827,
+ 0x4828,0x4829,0x482a,0x482b,0x482c,0x482d,0x482e,0x482f,
+ 0x4830,0x4831,0x4832,0x4833,0x4834,0x4835,0x4836,0x4837,
+ 0x4838,0x4839,0x483a,0x483b,0x483c,0x483d,0x483e,0x483f,
+ 0x4840,0x4841,0x4842,0x4843,0x4844,0x4845,0x4846,0x4847,
+ 0x4848,0x4849,0x484a,0x484b,0x484c,0x484d,0x484e,0x484f,
+ 0x4850,0x4851,0x4852,0x4853,0x4854,0x4855,0x4856,0x4857,
+ 0x4858,0x4859,0x485a,0x485b,0x485c,0x485d,0x485e,0x485f,
+ 0x4860,0x4861,0x4862,0x4863,0x4864,0x4865,0x4866,0x4867,
+ 0x4868,0x4869,0x486a,0x486b,0x486c,0x486d,0x486e,0x486f,
+ 0x4870,0x4871,0x4872,0x4873,0x4874,0x4875,0x4876,0x4877,
+ 0x4878,0x4879,0x487a,0x487b,0x487c,0x487d,0x487e,0x487f,
+ 0x4880,0x4881,0x4882,0x4883,0x4884,0x4885,0x4886,0x4887,
+ 0x4888,0x4889,0x488a,0x488b,0x488c,0x488d,0x488e,0x488f,
+ 0x4890,0x4891,0x4892,0x4893,0x4894,0x4895,0x4896,0x4897,
+ 0x4898,0x4899,0x489a,0x489b,0x489c,0x489d,0x489e,0x489f,
+ 0x48a0,0x48a1,0x48a2,0x48a3,0x48a4,0x48a5,0x48a6,0x48a7,
+ 0x48a8,0x48a9,0x48aa,0x48ab,0x48ac,0x48ad,0x48ae,0x48af,
+ 0x48b0,0x48b1,0x48b2,0x48b3,0x48b4,0x48b5,0x48b6,0x48b7,
+ 0x48b8,0x48b9,0x48ba,0x48bb,0x48bc,0x48bd,0x48be,0x48bf,
+ 0x48c0,0x48c1,0x48c2,0x48c3,0x48c4,0x48c5,0x48c6,0x48c7,
+ 0x48c8,0x48c9,0x48ca,0x48cb,0x48cc,0x48cd,0x48ce,0x48cf,
+ 0x48d0,0x48d1,0x48d2,0x48d3,0x48d4,0x48d5,0x48d6,0x48d7,
+ 0x48d8,0x48d9,0x48da,0x48db,0x48dc,0x48dd,0x48de,0x48df,
+ 0x48e0,0x48e1,0x48e2,0x48e3,0x48e4,0x48e5,0x48e6,0x48e7,
+ 0x48e8,0x48e9,0x48ea,0x48eb,0x48ec,0x48ed,0x48ee,0x48ef,
+ 0x48f0,0x48f1,0x48f2,0x48f3,0x48f4,0x48f5,0x48f6,0x48f7,
+ 0x48f8,0x48f9,0x48fa,0x48fb,0x48fc,0x48fd,0x48fe,0x48ff,
+ 0x4900,0x4901,0x4902,0x4903,0x4904,0x4905,0x4906,0x4907,
+ 0x4908,0x4909,0x490a,0x490b,0x490c,0x490d,0x490e,0x490f,
+ 0x4910,0x4911,0x4912,0x4913,0x4914,0x4915,0x4916,0x4917,
+ 0x4918,0x4919,0x491a,0x491b,0x491c,0x491d,0x491e,0x491f,
+ 0x4920,0x4921,0x4922,0x4923,0x4924,0x4925,0x4926,0x4927,
+ 0x4928,0x4929,0x492a,0x492b,0x492c,0x492d,0x492e,0x492f,
+ 0x4930,0x4931,0x4932,0x4933,0x4934,0x4935,0x4936,0x4937,
+ 0x4938,0x4939,0x493a,0x493b,0x493c,0x493d,0x493e,0x493f,
+ 0x4940,0x4941,0x4942,0x4943,0x4944,0x4945,0x4946,0x4947,
+ 0x4948,0x4949,0x494a,0x494b,0x494c,0x494d,0x494e,0x494f,
+ 0x4950,0x4951,0x4952,0x4953,0x4954,0x4955,0x4956,0x4957,
+ 0x4958,0x4959,0x495a,0x495b,0x495c,0x495d,0x495e,0x495f,
+ 0x4960,0x4961,0x4962,0x4963,0x4964,0x4965,0x4966,0x4967,
+ 0x4968,0x4969,0x496a,0x496b,0x496c,0x496d,0x496e,0x496f,
+ 0x4970,0x4971,0x4972,0x4973,0x4974,0x4975,0x4976,0x4977,
+ 0x4978,0x4979,0x497a,0x497b,0x497c,0x497d,0x497e,0x497f,
+ 0x4980,0x4981,0x4982,0x4983,0x4984,0x4985,0x4986,0x4987,
+ 0x4988,0x4989,0x498a,0x498b,0x498c,0x498d,0x498e,0x498f,
+ 0x4990,0x4991,0x4992,0x4993,0x4994,0x4995,0x4996,0x4997,
+ 0x4998,0x4999,0x499a,0x499b,0x499c,0x499d,0x499e,0x499f,
+ 0x49a0,0x49a1,0x49a2,0x49a3,0x49a4,0x49a5,0x49a6,0x49a7,
+ 0x49a8,0x49a9,0x49aa,0x49ab,0x49ac,0x49ad,0x49ae,0x49af,
+ 0x49b0,0x49b1,0x49b2,0x49b3,0x49b4,0x49b5,0x49b6,0x49b7,
+ 0x49b8,0x49b9,0x49ba,0x49bb,0x49bc,0x49bd,0x49be,0x49bf,
+ 0x49c0,0x49c1,0x49c2,0x49c3,0x49c4,0x49c5,0x49c6,0x49c7,
+ 0x49c8,0x49c9,0x49ca,0x49cb,0x49cc,0x49cd,0x49ce,0x49cf,
+ 0x49d0,0x49d1,0x49d2,0x49d3,0x49d4,0x49d5,0x49d6,0x49d7,
+ 0x49d8,0x49d9,0x49da,0x49db,0x49dc,0x49dd,0x49de,0x49df,
+ 0x49e0,0x49e1,0x49e2,0x49e3,0x49e4,0x49e5,0x49e6,0x49e7,
+ 0x49e8,0x49e9,0x49ea,0x49eb,0x49ec,0x49ed,0x49ee,0x49ef,
+ 0x49f0,0x49f1,0x49f2,0x49f3,0x49f4,0x49f5,0x49f6,0x49f7,
+ 0x49f8,0x49f9,0x49fa,0x49fb,0x49fc,0x49fd,0x49fe,0x49ff,
+ 0x4a00,0x4a01,0x4a02,0x4a03,0x4a04,0x4a05,0x4a06,0x4a07,
+ 0x4a08,0x4a09,0x4a0a,0x4a0b,0x4a0c,0x4a0d,0x4a0e,0x4a0f,
+ 0x4a10,0x4a11,0x4a12,0x4a13,0x4a14,0x4a15,0x4a16,0x4a17,
+ 0x4a18,0x4a19,0x4a1a,0x4a1b,0x4a1c,0x4a1d,0x4a1e,0x4a1f,
+ 0x4a20,0x4a21,0x4a22,0x4a23,0x4a24,0x4a25,0x4a26,0x4a27,
+ 0x4a28,0x4a29,0x4a2a,0x4a2b,0x4a2c,0x4a2d,0x4a2e,0x4a2f,
+ 0x4a30,0x4a31,0x4a32,0x4a33,0x4a34,0x4a35,0x4a36,0x4a37,
+ 0x4a38,0x4a39,0x4a3a,0x4a3b,0x4a3c,0x4a3d,0x4a3e,0x4a3f,
+ 0x4a40,0x4a41,0x4a42,0x4a43,0x4a44,0x4a45,0x4a46,0x4a47,
+ 0x4a48,0x4a49,0x4a4a,0x4a4b,0x4a4c,0x4a4d,0x4a4e,0x4a4f,
+ 0x4a50,0x4a51,0x4a52,0x4a53,0x4a54,0x4a55,0x4a56,0x4a57,
+ 0x4a58,0x4a59,0x4a5a,0x4a5b,0x4a5c,0x4a5d,0x4a5e,0x4a5f,
+ 0x4a60,0x4a61,0x4a62,0x4a63,0x4a64,0x4a65,0x4a66,0x4a67,
+ 0x4a68,0x4a69,0x4a6a,0x4a6b,0x4a6c,0x4a6d,0x4a6e,0x4a6f,
+ 0x4a70,0x4a71,0x4a72,0x4a73,0x4a74,0x4a75,0x4a76,0x4a77,
+ 0x4a78,0x4a79,0x4a7a,0x4a7b,0x4a7c,0x4a7d,0x4a7e,0x4a7f,
+ 0x4a80,0x4a81,0x4a82,0x4a83,0x4a84,0x4a85,0x4a86,0x4a87,
+ 0x4a88,0x4a89,0x4a8a,0x4a8b,0x4a8c,0x4a8d,0x4a8e,0x4a8f,
+ 0x4a90,0x4a91,0x4a92,0x4a93,0x4a94,0x4a95,0x4a96,0x4a97,
+ 0x4a98,0x4a99,0x4a9a,0x4a9b,0x4a9c,0x4a9d,0x4a9e,0x4a9f,
+ 0x4aa0,0x4aa1,0x4aa2,0x4aa3,0x4aa4,0x4aa5,0x4aa6,0x4aa7,
+ 0x4aa8,0x4aa9,0x4aaa,0x4aab,0x4aac,0x4aad,0x4aae,0x4aaf,
+ 0x4ab0,0x4ab1,0x4ab2,0x4ab3,0x4ab4,0x4ab5,0x4ab6,0x4ab7,
+ 0x4ab8,0x4ab9,0x4aba,0x4abb,0x4abc,0x4abd,0x4abe,0x4abf,
+ 0x4ac0,0x4ac1,0x4ac2,0x4ac3,0x4ac4,0x4ac5,0x4ac6,0x4ac7,
+ 0x4ac8,0x4ac9,0x4aca,0x4acb,0x4acc,0x4acd,0x4ace,0x4acf,
+ 0x4ad0,0x4ad1,0x4ad2,0x4ad3,0x4ad4,0x4ad5,0x4ad6,0x4ad7,
+ 0x4ad8,0x4ad9,0x4ada,0x4adb,0x4adc,0x4add,0x4ade,0x4adf,
+ 0x4ae0,0x4ae1,0x4ae2,0x4ae3,0x4ae4,0x4ae5,0x4ae6,0x4ae7,
+ 0x4ae8,0x4ae9,0x4aea,0x4aeb,0x4aec,0x4aed,0x4aee,0x4aef,
+ 0x4af0,0x4af1,0x4af2,0x4af3,0x4af4,0x4af5,0x4af6,0x4af7,
+ 0x4af8,0x4af9,0x4afa,0x4afb,0x4afc,0x4afd,0x4afe,0x4aff,
+ 0x4b00,0x4b01,0x4b02,0x4b03,0x4b04,0x4b05,0x4b06,0x4b07,
+ 0x4b08,0x4b09,0x4b0a,0x4b0b,0x4b0c,0x4b0d,0x4b0e,0x4b0f,
+ 0x4b10,0x4b11,0x4b12,0x4b13,0x4b14,0x4b15,0x4b16,0x4b17,
+ 0x4b18,0x4b19,0x4b1a,0x4b1b,0x4b1c,0x4b1d,0x4b1e,0x4b1f,
+ 0x4b20,0x4b21,0x4b22,0x4b23,0x4b24,0x4b25,0x4b26,0x4b27,
+ 0x4b28,0x4b29,0x4b2a,0x4b2b,0x4b2c,0x4b2d,0x4b2e,0x4b2f,
+ 0x4b30,0x4b31,0x4b32,0x4b33,0x4b34,0x4b35,0x4b36,0x4b37,
+ 0x4b38,0x4b39,0x4b3a,0x4b3b,0x4b3c,0x4b3d,0x4b3e,0x4b3f,
+ 0x4b40,0x4b41,0x4b42,0x4b43,0x4b44,0x4b45,0x4b46,0x4b47,
+ 0x4b48,0x4b49,0x4b4a,0x4b4b,0x4b4c,0x4b4d,0x4b4e,0x4b4f,
+ 0x4b50,0x4b51,0x4b52,0x4b53,0x4b54,0x4b55,0x4b56,0x4b57,
+ 0x4b58,0x4b59,0x4b5a,0x4b5b,0x4b5c,0x4b5d,0x4b5e,0x4b5f,
+ 0x4b60,0x4b61,0x4b62,0x4b63,0x4b64,0x4b65,0x4b66,0x4b67,
+ 0x4b68,0x4b69,0x4b6a,0x4b6b,0x4b6c,0x4b6d,0x4b6e,0x4b6f,
+ 0x4b70,0x4b71,0x4b72,0x4b73,0x4b74,0x4b75,0x4b76,0x4b77,
+ 0x4b78,0x4b79,0x4b7a,0x4b7b,0x4b7c,0x4b7d,0x4b7e,0x4b7f,
+ 0x4b80,0x4b81,0x4b82,0x4b83,0x4b84,0x4b85,0x4b86,0x4b87,
+ 0x4b88,0x4b89,0x4b8a,0x4b8b,0x4b8c,0x4b8d,0x4b8e,0x4b8f,
+ 0x4b90,0x4b91,0x4b92,0x4b93,0x4b94,0x4b95,0x4b96,0x4b97,
+ 0x4b98,0x4b99,0x4b9a,0x4b9b,0x4b9c,0x4b9d,0x4b9e,0x4b9f,
+ 0x4ba0,0x4ba1,0x4ba2,0x4ba3,0x4ba4,0x4ba5,0x4ba6,0x4ba7,
+ 0x4ba8,0x4ba9,0x4baa,0x4bab,0x4bac,0x4bad,0x4bae,0x4baf,
+ 0x4bb0,0x4bb1,0x4bb2,0x4bb3,0x4bb4,0x4bb5,0x4bb6,0x4bb7,
+ 0x4bb8,0x4bb9,0x4bba,0x4bbb,0x4bbc,0x4bbd,0x4bbe,0x4bbf,
+ 0x4bc0,0x4bc1,0x4bc2,0x4bc3,0x4bc4,0x4bc5,0x4bc6,0x4bc7,
+ 0x4bc8,0x4bc9,0x4bca,0x4bcb,0x4bcc,0x4bcd,0x4bce,0x4bcf,
+ 0x4bd0,0x4bd1,0x4bd2,0x4bd3,0x4bd4,0x4bd5,0x4bd6,0x4bd7,
+ 0x4bd8,0x4bd9,0x4bda,0x4bdb,0x4bdc,0x4bdd,0x4bde,0x4bdf,
+ 0x4be0,0x4be1,0x4be2,0x4be3,0x4be4,0x4be5,0x4be6,0x4be7,
+ 0x4be8,0x4be9,0x4bea,0x4beb,0x4bec,0x4bed,0x4bee,0x4bef,
+ 0x4bf0,0x4bf1,0x4bf2,0x4bf3,0x4bf4,0x4bf5,0x4bf6,0x4bf7,
+ 0x4bf8,0x4bf9,0x4bfa,0x4bfb,0x4bfc,0x4bfd,0x4bfe,0x4bff,
+ 0x4c00,0x4c01,0x4c02,0x4c03,0x4c04,0x4c05,0x4c06,0x4c07,
+ 0x4c08,0x4c09,0x4c0a,0x4c0b,0x4c0c,0x4c0d,0x4c0e,0x4c0f,
+ 0x4c10,0x4c11,0x4c12,0x4c13,0x4c14,0x4c15,0x4c16,0x4c17,
+ 0x4c18,0x4c19,0x4c1a,0x4c1b,0x4c1c,0x4c1d,0x4c1e,0x4c1f,
+ 0x4c20,0x4c21,0x4c22,0x4c23,0x4c24,0x4c25,0x4c26,0x4c27,
+ 0x4c28,0x4c29,0x4c2a,0x4c2b,0x4c2c,0x4c2d,0x4c2e,0x4c2f,
+ 0x4c30,0x4c31,0x4c32,0x4c33,0x4c34,0x4c35,0x4c36,0x4c37,
+ 0x4c38,0x4c39,0x4c3a,0x4c3b,0x4c3c,0x4c3d,0x4c3e,0x4c3f,
+ 0x4c40,0x4c41,0x4c42,0x4c43,0x4c44,0x4c45,0x4c46,0x4c47,
+ 0x4c48,0x4c49,0x4c4a,0x4c4b,0x4c4c,0x4c4d,0x4c4e,0x4c4f,
+ 0x4c50,0x4c51,0x4c52,0x4c53,0x4c54,0x4c55,0x4c56,0x4c57,
+ 0x4c58,0x4c59,0x4c5a,0x4c5b,0x4c5c,0x4c5d,0x4c5e,0x4c5f,
+ 0x4c60,0x4c61,0x4c62,0x4c63,0x4c64,0x4c65,0x4c66,0x4c67,
+ 0x4c68,0x4c69,0x4c6a,0x4c6b,0x4c6c,0x4c6d,0x4c6e,0x4c6f,
+ 0x4c70,0x4c71,0x4c72,0x4c73,0x4c74,0x4c75,0x4c76,0x4c77,
+ 0x4c78,0x4c79,0x4c7a,0x4c7b,0x4c7c,0x4c7d,0x4c7e,0x4c7f,
+ 0x4c80,0x4c81,0x4c82,0x4c83,0x4c84,0x4c85,0x4c86,0x4c87,
+ 0x4c88,0x4c89,0x4c8a,0x4c8b,0x4c8c,0x4c8d,0x4c8e,0x4c8f,
+ 0x4c90,0x4c91,0x4c92,0x4c93,0x4c94,0x4c95,0x4c96,0x4c97,
+ 0x4c98,0x4c99,0x4c9a,0x4c9b,0x4c9c,0x4c9d,0x4c9e,0x4c9f,
+ 0x4ca0,0x4ca1,0x4ca2,0x4ca3,0x4ca4,0x4ca5,0x4ca6,0x4ca7,
+ 0x4ca8,0x4ca9,0x4caa,0x4cab,0x4cac,0x4cad,0x4cae,0x4caf,
+ 0x4cb0,0x4cb1,0x4cb2,0x4cb3,0x4cb4,0x4cb5,0x4cb6,0x4cb7,
+ 0x4cb8,0x4cb9,0x4cba,0x4cbb,0x4cbc,0x4cbd,0x4cbe,0x4cbf,
+ 0x4cc0,0x4cc1,0x4cc2,0x4cc3,0x4cc4,0x4cc5,0x4cc6,0x4cc7,
+ 0x4cc8,0x4cc9,0x4cca,0x4ccb,0x4ccc,0x4ccd,0x4cce,0x4ccf,
+ 0x4cd0,0x4cd1,0x4cd2,0x4cd3,0x4cd4,0x4cd5,0x4cd6,0x4cd7,
+ 0x4cd8,0x4cd9,0x4cda,0x4cdb,0x4cdc,0x4cdd,0x4cde,0x4cdf,
+ 0x4ce0,0x4ce1,0x4ce2,0x4ce3,0x4ce4,0x4ce5,0x4ce6,0x4ce7,
+ 0x4ce8,0x4ce9,0x4cea,0x4ceb,0x4cec,0x4ced,0x4cee,0x4cef,
+ 0x4cf0,0x4cf1,0x4cf2,0x4cf3,0x4cf4,0x4cf5,0x4cf6,0x4cf7,
+ 0x4cf8,0x4cf9,0x4cfa,0x4cfb,0x4cfc,0x4cfd,0x4cfe,0x4cff,
+ 0x4d00,0x4d01,0x4d02,0x4d03,0x4d04,0x4d05,0x4d06,0x4d07,
+ 0x4d08,0x4d09,0x4d0a,0x4d0b,0x4d0c,0x4d0d,0x4d0e,0x4d0f,
+ 0x4d10,0x4d11,0x4d12,0x4d13,0x4d14,0x4d15,0x4d16,0x4d17,
+ 0x4d18,0x4d19,0x4d1a,0x4d1b,0x4d1c,0x4d1d,0x4d1e,0x4d1f,
+ 0x4d20,0x4d21,0x4d22,0x4d23,0x4d24,0x4d25,0x4d26,0x4d27,
+ 0x4d28,0x4d29,0x4d2a,0x4d2b,0x4d2c,0x4d2d,0x4d2e,0x4d2f,
+ 0x4d30,0x4d31,0x4d32,0x4d33,0x4d34,0x4d35,0x4d36,0x4d37,
+ 0x4d38,0x4d39,0x4d3a,0x4d3b,0x4d3c,0x4d3d,0x4d3e,0x4d3f,
+ 0x4d40,0x4d41,0x4d42,0x4d43,0x4d44,0x4d45,0x4d46,0x4d47,
+ 0x4d48,0x4d49,0x4d4a,0x4d4b,0x4d4c,0x4d4d,0x4d4e,0x4d4f,
+ 0x4d50,0x4d51,0x4d52,0x4d53,0x4d54,0x4d55,0x4d56,0x4d57,
+ 0x4d58,0x4d59,0x4d5a,0x4d5b,0x4d5c,0x4d5d,0x4d5e,0x4d5f,
+ 0x4d60,0x4d61,0x4d62,0x4d63,0x4d64,0x4d65,0x4d66,0x4d67,
+ 0x4d68,0x4d69,0x4d6a,0x4d6b,0x4d6c,0x4d6d,0x4d6e,0x4d6f,
+ 0x4d70,0x4d71,0x4d72,0x4d73,0x4d74,0x4d75,0x4d76,0x4d77,
+ 0x4d78,0x4d79,0x4d7a,0x4d7b,0x4d7c,0x4d7d,0x4d7e,0x4d7f,
+ 0x4d80,0x4d81,0x4d82,0x4d83,0x4d84,0x4d85,0x4d86,0x4d87,
+ 0x4d88,0x4d89,0x4d8a,0x4d8b,0x4d8c,0x4d8d,0x4d8e,0x4d8f,
+ 0x4d90,0x4d91,0x4d92,0x4d93,0x4d94,0x4d95,0x4d96,0x4d97,
+ 0x4d98,0x4d99,0x4d9a,0x4d9b,0x4d9c,0x4d9d,0x4d9e,0x4d9f,
+ 0x4da0,0x4da1,0x4da2,0x4da3,0x4da4,0x4da5,0x4da6,0x4da7,
+ 0x4da8,0x4da9,0x4daa,0x4dab,0x4dac,0x4dad,0x4dae,0x4daf,
+ 0x4db0,0x4db1,0x4db2,0x4db3,0x4db4,0x4db5,0x4db6,0x4db7,
+ 0x4db8,0x4db9,0x4dba,0x4dbb,0x4dbc,0x4dbd,0x4dbe,0x4dbf,
+ 0x4dc0,0x4dc1,0x4dc2,0x4dc3,0x4dc4,0x4dc5,0x4dc6,0x4dc7,
+ 0x4dc8,0x4dc9,0x4dca,0x4dcb,0x4dcc,0x4dcd,0x4dce,0x4dcf,
+ 0x4dd0,0x4dd1,0x4dd2,0x4dd3,0x4dd4,0x4dd5,0x4dd6,0x4dd7,
+ 0x4dd8,0x4dd9,0x4dda,0x4ddb,0x4ddc,0x4ddd,0x4dde,0x4ddf,
+ 0x4de0,0x4de1,0x4de2,0x4de3,0x4de4,0x4de5,0x4de6,0x4de7,
+ 0x4de8,0x4de9,0x4dea,0x4deb,0x4dec,0x4ded,0x4dee,0x4def,
+ 0x4df0,0x4df1,0x4df2,0x4df3,0x4df4,0x4df5,0x4df6,0x4df7,
+ 0x4df8,0x4df9,0x4dfa,0x4dfb,0x4dfc,0x4dfd,0x4dfe,0x4dff,
+ 0x4e00,0x4e01,0x4e02,0x4e03,0x4e04,0x4e05,0x4e06,0x4e07,
+ 0x4e08,0x4e09,0x4e0a,0x4e0b,0x4e0c,0x4e0d,0x4e0e,0x4e0f,
+ 0x4e10,0x4e11,0x4e12,0x4e13,0x4e14,0x4e15,0x4e16,0x4e17,
+ 0x4e18,0x4e19,0x4e1a,0x4e1b,0x4e1c,0x4e1d,0x4e1e,0x4e1f,
+ 0x4e20,0x4e21,0x4e22,0x4e23,0x4e24,0x4e25,0x4e26,0x4e27,
+ 0x4e28,0x4e29,0x4e2a,0x4e2b,0x4e2c,0x4e2d,0x4e2e,0x4e2f,
+ 0x4e30,0x4e31,0x4e32,0x4e33,0x4e34,0x4e35,0x4e36,0x4e37,
+ 0x4e38,0x4e39,0x4e3a,0x4e3b,0x4e3c,0x4e3d,0x4e3e,0x4e3f,
+ 0x4e40,0x4e41,0x4e42,0x4e43,0x4e44,0x4e45,0x4e46,0x4e47,
+ 0x4e48,0x4e49,0x4e4a,0x4e4b,0x4e4c,0x4e4d,0x4e4e,0x4e4f,
+ 0x4e50,0x4e51,0x4e52,0x4e53,0x4e54,0x4e55,0x4e56,0x4e57,
+ 0x4e58,0x4e59,0x4e5a,0x4e5b,0x4e5c,0x4e5d,0x4e5e,0x4e5f,
+ 0x4e60,0x4e61,0x4e62,0x4e63,0x4e64,0x4e65,0x4e66,0x4e67,
+ 0x4e68,0x4e69,0x4e6a,0x4e6b,0x4e6c,0x4e6d,0x4e6e,0x4e6f,
+ 0x4e70,0x4e71,0x4e72,0x4e73,0x4e74,0x4e75,0x4e76,0x4e77,
+ 0x4e78,0x4e79,0x4e7a,0x4e7b,0x4e7c,0x4e7d,0x4e7e,0x4e7f,
+ 0x4e80,0x4e81,0x4e82,0x4e83,0x4e84,0x4e85,0x4e86,0x4e87,
+ 0x4e88,0x4e89,0x4e8a,0x4e8b,0x4e8c,0x4e8d,0x4e8e,0x4e8f,
+ 0x4e90,0x4e91,0x4e92,0x4e93,0x4e94,0x4e95,0x4e96,0x4e97,
+ 0x4e98,0x4e99,0x4e9a,0x4e9b,0x4e9c,0x4e9d,0x4e9e,0x4e9f,
+ 0x4ea0,0x4ea1,0x4ea2,0x4ea3,0x4ea4,0x4ea5,0x4ea6,0x4ea7,
+ 0x4ea8,0x4ea9,0x4eaa,0x4eab,0x4eac,0x4ead,0x4eae,0x4eaf,
+ 0x4eb0,0x4eb1,0x4eb2,0x4eb3,0x4eb4,0x4eb5,0x4eb6,0x4eb7,
+ 0x4eb8,0x4eb9,0x4eba,0x4ebb,0x4ebc,0x4ebd,0x4ebe,0x4ebf,
+ 0x4ec0,0x4ec1,0x4ec2,0x4ec3,0x4ec4,0x4ec5,0x4ec6,0x4ec7,
+ 0x4ec8,0x4ec9,0x4eca,0x4ecb,0x4ecc,0x4ecd,0x4ece,0x4ecf,
+ 0x4ed0,0x4ed1,0x4ed2,0x4ed3,0x4ed4,0x4ed5,0x4ed6,0x4ed7,
+ 0x4ed8,0x4ed9,0x4eda,0x4edb,0x4edc,0x4edd,0x4ede,0x4edf,
+ 0x4ee0,0x4ee1,0x4ee2,0x4ee3,0x4ee4,0x4ee5,0x4ee6,0x4ee7,
+ 0x4ee8,0x4ee9,0x4eea,0x4eeb,0x4eec,0x4eed,0x4eee,0x4eef,
+ 0x4ef0,0x4ef1,0x4ef2,0x4ef3,0x4ef4,0x4ef5,0x4ef6,0x4ef7,
+ 0x4ef8,0x4ef9,0x4efa,0x4efb,0x4efc,0x4efd,0x4efe,0x4eff,
+ 0x4f00,0x4f01,0x4f02,0x4f03,0x4f04,0x4f05,0x4f06,0x4f07,
+ 0x4f08,0x4f09,0x4f0a,0x4f0b,0x4f0c,0x4f0d,0x4f0e,0x4f0f,
+ 0x4f10,0x4f11,0x4f12,0x4f13,0x4f14,0x4f15,0x4f16,0x4f17,
+ 0x4f18,0x4f19,0x4f1a,0x4f1b,0x4f1c,0x4f1d,0x4f1e,0x4f1f,
+ 0x4f20,0x4f21,0x4f22,0x4f23,0x4f24,0x4f25,0x4f26,0x4f27,
+ 0x4f28,0x4f29,0x4f2a,0x4f2b,0x4f2c,0x4f2d,0x4f2e,0x4f2f,
+ 0x4f30,0x4f31,0x4f32,0x4f33,0x4f34,0x4f35,0x4f36,0x4f37,
+ 0x4f38,0x4f39,0x4f3a,0x4f3b,0x4f3c,0x4f3d,0x4f3e,0x4f3f,
+ 0x4f40,0x4f41,0x4f42,0x4f43,0x4f44,0x4f45,0x4f46,0x4f47,
+ 0x4f48,0x4f49,0x4f4a,0x4f4b,0x4f4c,0x4f4d,0x4f4e,0x4f4f,
+ 0x4f50,0x4f51,0x4f52,0x4f53,0x4f54,0x4f55,0x4f56,0x4f57,
+ 0x4f58,0x4f59,0x4f5a,0x4f5b,0x4f5c,0x4f5d,0x4f5e,0x4f5f,
+ 0x4f60,0x4f61,0x4f62,0x4f63,0x4f64,0x4f65,0x4f66,0x4f67,
+ 0x4f68,0x4f69,0x4f6a,0x4f6b,0x4f6c,0x4f6d,0x4f6e,0x4f6f,
+ 0x4f70,0x4f71,0x4f72,0x4f73,0x4f74,0x4f75,0x4f76,0x4f77,
+ 0x4f78,0x4f79,0x4f7a,0x4f7b,0x4f7c,0x4f7d,0x4f7e,0x4f7f,
+ 0x4f80,0x4f81,0x4f82,0x4f83,0x4f84,0x4f85,0x4f86,0x4f87,
+ 0x4f88,0x4f89,0x4f8a,0x4f8b,0x4f8c,0x4f8d,0x4f8e,0x4f8f,
+ 0x4f90,0x4f91,0x4f92,0x4f93,0x4f94,0x4f95,0x4f96,0x4f97,
+ 0x4f98,0x4f99,0x4f9a,0x4f9b,0x4f9c,0x4f9d,0x4f9e,0x4f9f,
+ 0x4fa0,0x4fa1,0x4fa2,0x4fa3,0x4fa4,0x4fa5,0x4fa6,0x4fa7,
+ 0x4fa8,0x4fa9,0x4faa,0x4fab,0x4fac,0x4fad,0x4fae,0x4faf,
+ 0x4fb0,0x4fb1,0x4fb2,0x4fb3,0x4fb4,0x4fb5,0x4fb6,0x4fb7,
+ 0x4fb8,0x4fb9,0x4fba,0x4fbb,0x4fbc,0x4fbd,0x4fbe,0x4fbf,
+ 0x4fc0,0x4fc1,0x4fc2,0x4fc3,0x4fc4,0x4fc5,0x4fc6,0x4fc7,
+ 0x4fc8,0x4fc9,0x4fca,0x4fcb,0x4fcc,0x4fcd,0x4fce,0x4fcf,
+ 0x4fd0,0x4fd1,0x4fd2,0x4fd3,0x4fd4,0x4fd5,0x4fd6,0x4fd7,
+ 0x4fd8,0x4fd9,0x4fda,0x4fdb,0x4fdc,0x4fdd,0x4fde,0x4fdf,
+ 0x4fe0,0x4fe1,0x4fe2,0x4fe3,0x4fe4,0x4fe5,0x4fe6,0x4fe7,
+ 0x4fe8,0x4fe9,0x4fea,0x4feb,0x4fec,0x4fed,0x4fee,0x4fef,
+ 0x4ff0,0x4ff1,0x4ff2,0x4ff3,0x4ff4,0x4ff5,0x4ff6,0x4ff7,
+ 0x4ff8,0x4ff9,0x4ffa,0x4ffb,0x4ffc,0x4ffd,0x4ffe,0x4fff,
+ 0x5000,0x5001,0x5002,0x5003,0x5004,0x5005,0x5006,0x5007,
+ 0x5008,0x5009,0x500a,0x500b,0x500c,0x500d,0x500e,0x500f,
+ 0x5010,0x5011,0x5012,0x5013,0x5014,0x5015,0x5016,0x5017,
+ 0x5018,0x5019,0x501a,0x501b,0x501c,0x501d,0x501e,0x501f,
+ 0x5020,0x5021,0x5022,0x5023,0x5024,0x5025,0x5026,0x5027,
+ 0x5028,0x5029,0x502a,0x502b,0x502c,0x502d,0x502e,0x502f,
+ 0x5030,0x5031,0x5032,0x5033,0x5034,0x5035,0x5036,0x5037,
+ 0x5038,0x5039,0x503a,0x503b,0x503c,0x503d,0x503e,0x503f,
+ 0x5040,0x5041,0x5042,0x5043,0x5044,0x5045,0x5046,0x5047,
+ 0x5048,0x5049,0x504a,0x504b,0x504c,0x504d,0x504e,0x504f,
+ 0x5050,0x5051,0x5052,0x5053,0x5054,0x5055,0x5056,0x5057,
+ 0x5058,0x5059,0x505a,0x505b,0x505c,0x505d,0x505e,0x505f,
+ 0x5060,0x5061,0x5062,0x5063,0x5064,0x5065,0x5066,0x5067,
+ 0x5068,0x5069,0x506a,0x506b,0x506c,0x506d,0x506e,0x506f,
+ 0x5070,0x5071,0x5072,0x5073,0x5074,0x5075,0x5076,0x5077,
+ 0x5078,0x5079,0x507a,0x507b,0x507c,0x507d,0x507e,0x507f,
+ 0x5080,0x5081,0x5082,0x5083,0x5084,0x5085,0x5086,0x5087,
+ 0x5088,0x5089,0x508a,0x508b,0x508c,0x508d,0x508e,0x508f,
+ 0x5090,0x5091,0x5092,0x5093,0x5094,0x5095,0x5096,0x5097,
+ 0x5098,0x5099,0x509a,0x509b,0x509c,0x509d,0x509e,0x509f,
+ 0x50a0,0x50a1,0x50a2,0x50a3,0x50a4,0x50a5,0x50a6,0x50a7,
+ 0x50a8,0x50a9,0x50aa,0x50ab,0x50ac,0x50ad,0x50ae,0x50af,
+ 0x50b0,0x50b1,0x50b2,0x50b3,0x50b4,0x50b5,0x50b6,0x50b7,
+ 0x50b8,0x50b9,0x50ba,0x50bb,0x50bc,0x50bd,0x50be,0x50bf,
+ 0x50c0,0x50c1,0x50c2,0x50c3,0x50c4,0x50c5,0x50c6,0x50c7,
+ 0x50c8,0x50c9,0x50ca,0x50cb,0x50cc,0x50cd,0x50ce,0x50cf,
+ 0x50d0,0x50d1,0x50d2,0x50d3,0x50d4,0x50d5,0x50d6,0x50d7,
+ 0x50d8,0x50d9,0x50da,0x50db,0x50dc,0x50dd,0x50de,0x50df,
+ 0x50e0,0x50e1,0x50e2,0x50e3,0x50e4,0x50e5,0x50e6,0x50e7,
+ 0x50e8,0x50e9,0x50ea,0x50eb,0x50ec,0x50ed,0x50ee,0x50ef,
+ 0x50f0,0x50f1,0x50f2,0x50f3,0x50f4,0x50f5,0x50f6,0x50f7,
+ 0x50f8,0x50f9,0x50fa,0x50fb,0x50fc,0x50fd,0x50fe,0x50ff,
+ 0x5100,0x5101,0x5102,0x5103,0x5104,0x5105,0x5106,0x5107,
+ 0x5108,0x5109,0x510a,0x510b,0x510c,0x510d,0x510e,0x510f,
+ 0x5110,0x5111,0x5112,0x5113,0x5114,0x5115,0x5116,0x5117,
+ 0x5118,0x5119,0x511a,0x511b,0x511c,0x511d,0x511e,0x511f,
+ 0x5120,0x5121,0x5122,0x5123,0x5124,0x5125,0x5126,0x5127,
+ 0x5128,0x5129,0x512a,0x512b,0x512c,0x512d,0x512e,0x512f,
+ 0x5130,0x5131,0x5132,0x5133,0x5134,0x5135,0x5136,0x5137,
+ 0x5138,0x5139,0x513a,0x513b,0x513c,0x513d,0x513e,0x513f,
+ 0x5140,0x5141,0x5142,0x5143,0x5144,0x5145,0x5146,0x5147,
+ 0x5148,0x5149,0x514a,0x514b,0x514c,0x514d,0x514e,0x514f,
+ 0x5150,0x5151,0x5152,0x5153,0x5154,0x5155,0x5156,0x5157,
+ 0x5158,0x5159,0x515a,0x515b,0x515c,0x515d,0x515e,0x515f,
+ 0x5160,0x5161,0x5162,0x5163,0x5164,0x5165,0x5166,0x5167,
+ 0x5168,0x5169,0x516a,0x516b,0x516c,0x516d,0x516e,0x516f,
+ 0x5170,0x5171,0x5172,0x5173,0x5174,0x5175,0x5176,0x5177,
+ 0x5178,0x5179,0x517a,0x517b,0x517c,0x517d,0x517e,0x517f,
+ 0x5180,0x5181,0x5182,0x5183,0x5184,0x5185,0x5186,0x5187,
+ 0x5188,0x5189,0x518a,0x518b,0x518c,0x518d,0x518e,0x518f,
+ 0x5190,0x5191,0x5192,0x5193,0x5194,0x5195,0x5196,0x5197,
+ 0x5198,0x5199,0x519a,0x519b,0x519c,0x519d,0x519e,0x519f,
+ 0x51a0,0x51a1,0x51a2,0x51a3,0x51a4,0x51a5,0x51a6,0x51a7,
+ 0x51a8,0x51a9,0x51aa,0x51ab,0x51ac,0x51ad,0x51ae,0x51af,
+ 0x51b0,0x51b1,0x51b2,0x51b3,0x51b4,0x51b5,0x51b6,0x51b7,
+ 0x51b8,0x51b9,0x51ba,0x51bb,0x51bc,0x51bd,0x51be,0x51bf,
+ 0x51c0,0x51c1,0x51c2,0x51c3,0x51c4,0x51c5,0x51c6,0x51c7,
+ 0x51c8,0x51c9,0x51ca,0x51cb,0x51cc,0x51cd,0x51ce,0x51cf,
+ 0x51d0,0x51d1,0x51d2,0x51d3,0x51d4,0x51d5,0x51d6,0x51d7,
+ 0x51d8,0x51d9,0x51da,0x51db,0x51dc,0x51dd,0x51de,0x51df,
+ 0x51e0,0x51e1,0x51e2,0x51e3,0x51e4,0x51e5,0x51e6,0x51e7,
+ 0x51e8,0x51e9,0x51ea,0x51eb,0x51ec,0x51ed,0x51ee,0x51ef,
+ 0x51f0,0x51f1,0x51f2,0x51f3,0x51f4,0x51f5,0x51f6,0x51f7,
+ 0x51f8,0x51f9,0x51fa,0x51fb,0x51fc,0x51fd,0x51fe,0x51ff,
+ 0x5200,0x5201,0x5202,0x5203,0x5204,0x5205,0x5206,0x5207,
+ 0x5208,0x5209,0x520a,0x520b,0x520c,0x520d,0x520e,0x520f,
+ 0x5210,0x5211,0x5212,0x5213,0x5214,0x5215,0x5216,0x5217,
+ 0x5218,0x5219,0x521a,0x521b,0x521c,0x521d,0x521e,0x521f,
+ 0x5220,0x5221,0x5222,0x5223,0x5224,0x5225,0x5226,0x5227,
+ 0x5228,0x5229,0x522a,0x522b,0x522c,0x522d,0x522e,0x522f,
+ 0x5230,0x5231,0x5232,0x5233,0x5234,0x5235,0x5236,0x5237,
+ 0x5238,0x5239,0x523a,0x523b,0x523c,0x523d,0x523e,0x523f,
+ 0x5240,0x5241,0x5242,0x5243,0x5244,0x5245,0x5246,0x5247,
+ 0x5248,0x5249,0x524a,0x524b,0x524c,0x524d,0x524e,0x524f,
+ 0x5250,0x5251,0x5252,0x5253,0x5254,0x5255,0x5256,0x5257,
+ 0x5258,0x5259,0x525a,0x525b,0x525c,0x525d,0x525e,0x525f,
+ 0x5260,0x5261,0x5262,0x5263,0x5264,0x5265,0x5266,0x5267,
+ 0x5268,0x5269,0x526a,0x526b,0x526c,0x526d,0x526e,0x526f,
+ 0x5270,0x5271,0x5272,0x5273,0x5274,0x5275,0x5276,0x5277,
+ 0x5278,0x5279,0x527a,0x527b,0x527c,0x527d,0x527e,0x527f,
+ 0x5280,0x5281,0x5282,0x5283,0x5284,0x5285,0x5286,0x5287,
+ 0x5288,0x5289,0x528a,0x528b,0x528c,0x528d,0x528e,0x528f,
+ 0x5290,0x5291,0x5292,0x5293,0x5294,0x5295,0x5296,0x5297,
+ 0x5298,0x5299,0x529a,0x529b,0x529c,0x529d,0x529e,0x529f,
+ 0x52a0,0x52a1,0x52a2,0x52a3,0x52a4,0x52a5,0x52a6,0x52a7,
+ 0x52a8,0x52a9,0x52aa,0x52ab,0x52ac,0x52ad,0x52ae,0x52af,
+ 0x52b0,0x52b1,0x52b2,0x52b3,0x52b4,0x52b5,0x52b6,0x52b7,
+ 0x52b8,0x52b9,0x52ba,0x52bb,0x52bc,0x52bd,0x52be,0x52bf,
+ 0x52c0,0x52c1,0x52c2,0x52c3,0x52c4,0x52c5,0x52c6,0x52c7,
+ 0x52c8,0x52c9,0x52ca,0x52cb,0x52cc,0x52cd,0x52ce,0x52cf,
+ 0x52d0,0x52d1,0x52d2,0x52d3,0x52d4,0x52d5,0x52d6,0x52d7,
+ 0x52d8,0x52d9,0x52da,0x52db,0x52dc,0x52dd,0x52de,0x52df,
+ 0x52e0,0x52e1,0x52e2,0x52e3,0x52e4,0x52e5,0x52e6,0x52e7,
+ 0x52e8,0x52e9,0x52ea,0x52eb,0x52ec,0x52ed,0x52ee,0x52ef,
+ 0x52f0,0x52f1,0x52f2,0x52f3,0x52f4,0x52f5,0x52f6,0x52f7,
+ 0x52f8,0x52f9,0x52fa,0x52fb,0x52fc,0x52fd,0x52fe,0x52ff,
+ 0x5300,0x5301,0x5302,0x5303,0x5304,0x5305,0x5306,0x5307,
+ 0x5308,0x5309,0x530a,0x530b,0x530c,0x530d,0x530e,0x530f,
+ 0x5310,0x5311,0x5312,0x5313,0x5314,0x5315,0x5316,0x5317,
+ 0x5318,0x5319,0x531a,0x531b,0x531c,0x531d,0x531e,0x531f,
+ 0x5320,0x5321,0x5322,0x5323,0x5324,0x5325,0x5326,0x5327,
+ 0x5328,0x5329,0x532a,0x532b,0x532c,0x532d,0x532e,0x532f,
+ 0x5330,0x5331,0x5332,0x5333,0x5334,0x5335,0x5336,0x5337,
+ 0x5338,0x5339,0x533a,0x533b,0x533c,0x533d,0x533e,0x533f,
+ 0x5340,0x5341,0x5342,0x5343,0x5344,0x5345,0x5346,0x5347,
+ 0x5348,0x5349,0x534a,0x534b,0x534c,0x534d,0x534e,0x534f,
+ 0x5350,0x5351,0x5352,0x5353,0x5354,0x5355,0x5356,0x5357,
+ 0x5358,0x5359,0x535a,0x535b,0x535c,0x535d,0x535e,0x535f,
+ 0x5360,0x5361,0x5362,0x5363,0x5364,0x5365,0x5366,0x5367,
+ 0x5368,0x5369,0x536a,0x536b,0x536c,0x536d,0x536e,0x536f,
+ 0x5370,0x5371,0x5372,0x5373,0x5374,0x5375,0x5376,0x5377,
+ 0x5378,0x5379,0x537a,0x537b,0x537c,0x537d,0x537e,0x537f,
+ 0x5380,0x5381,0x5382,0x5383,0x5384,0x5385,0x5386,0x5387,
+ 0x5388,0x5389,0x538a,0x538b,0x538c,0x538d,0x538e,0x538f,
+ 0x5390,0x5391,0x5392,0x5393,0x5394,0x5395,0x5396,0x5397,
+ 0x5398,0x5399,0x539a,0x539b,0x539c,0x539d,0x539e,0x539f,
+ 0x53a0,0x53a1,0x53a2,0x53a3,0x53a4,0x53a5,0x53a6,0x53a7,
+ 0x53a8,0x53a9,0x53aa,0x53ab,0x53ac,0x53ad,0x53ae,0x53af,
+ 0x53b0,0x53b1,0x53b2,0x53b3,0x53b4,0x53b5,0x53b6,0x53b7,
+ 0x53b8,0x53b9,0x53ba,0x53bb,0x53bc,0x53bd,0x53be,0x53bf,
+ 0x53c0,0x53c1,0x53c2,0x53c3,0x53c4,0x53c5,0x53c6,0x53c7,
+ 0x53c8,0x53c9,0x53ca,0x53cb,0x53cc,0x53cd,0x53ce,0x53cf,
+ 0x53d0,0x53d1,0x53d2,0x53d3,0x53d4,0x53d5,0x53d6,0x53d7,
+ 0x53d8,0x53d9,0x53da,0x53db,0x53dc,0x53dd,0x53de,0x53df,
+ 0x53e0,0x53e1,0x53e2,0x53e3,0x53e4,0x53e5,0x53e6,0x53e7,
+ 0x53e8,0x53e9,0x53ea,0x53eb,0x53ec,0x53ed,0x53ee,0x53ef,
+ 0x53f0,0x53f1,0x53f2,0x53f3,0x53f4,0x53f5,0x53f6,0x53f7,
+ 0x53f8,0x53f9,0x53fa,0x53fb,0x53fc,0x53fd,0x53fe,0x53ff,
+ 0x5400,0x5401,0x5402,0x5403,0x5404,0x5405,0x5406,0x5407,
+ 0x5408,0x5409,0x540a,0x540b,0x540c,0x540d,0x540e,0x540f,
+ 0x5410,0x5411,0x5412,0x5413,0x5414,0x5415,0x5416,0x5417,
+ 0x5418,0x5419,0x541a,0x541b,0x541c,0x541d,0x541e,0x541f,
+ 0x5420,0x5421,0x5422,0x5423,0x5424,0x5425,0x5426,0x5427,
+ 0x5428,0x5429,0x542a,0x542b,0x542c,0x542d,0x542e,0x542f,
+ 0x5430,0x5431,0x5432,0x5433,0x5434,0x5435,0x5436,0x5437,
+ 0x5438,0x5439,0x543a,0x543b,0x543c,0x543d,0x543e,0x543f,
+ 0x5440,0x5441,0x5442,0x5443,0x5444,0x5445,0x5446,0x5447,
+ 0x5448,0x5449,0x544a,0x544b,0x544c,0x544d,0x544e,0x544f,
+ 0x5450,0x5451,0x5452,0x5453,0x5454,0x5455,0x5456,0x5457,
+ 0x5458,0x5459,0x545a,0x545b,0x545c,0x545d,0x545e,0x545f,
+ 0x5460,0x5461,0x5462,0x5463,0x5464,0x5465,0x5466,0x5467,
+ 0x5468,0x5469,0x546a,0x546b,0x546c,0x546d,0x546e,0x546f,
+ 0x5470,0x5471,0x5472,0x5473,0x5474,0x5475,0x5476,0x5477,
+ 0x5478,0x5479,0x547a,0x547b,0x547c,0x547d,0x547e,0x547f,
+ 0x5480,0x5481,0x5482,0x5483,0x5484,0x5485,0x5486,0x5487,
+ 0x5488,0x5489,0x548a,0x548b,0x548c,0x548d,0x548e,0x548f,
+ 0x5490,0x5491,0x5492,0x5493,0x5494,0x5495,0x5496,0x5497,
+ 0x5498,0x5499,0x549a,0x549b,0x549c,0x549d,0x549e,0x549f,
+ 0x54a0,0x54a1,0x54a2,0x54a3,0x54a4,0x54a5,0x54a6,0x54a7,
+ 0x54a8,0x54a9,0x54aa,0x54ab,0x54ac,0x54ad,0x54ae,0x54af,
+ 0x54b0,0x54b1,0x54b2,0x54b3,0x54b4,0x54b5,0x54b6,0x54b7,
+ 0x54b8,0x54b9,0x54ba,0x54bb,0x54bc,0x54bd,0x54be,0x54bf,
+ 0x54c0,0x54c1,0x54c2,0x54c3,0x54c4,0x54c5,0x54c6,0x54c7,
+ 0x54c8,0x54c9,0x54ca,0x54cb,0x54cc,0x54cd,0x54ce,0x54cf,
+ 0x54d0,0x54d1,0x54d2,0x54d3,0x54d4,0x54d5,0x54d6,0x54d7,
+ 0x54d8,0x54d9,0x54da,0x54db,0x54dc,0x54dd,0x54de,0x54df,
+ 0x54e0,0x54e1,0x54e2,0x54e3,0x54e4,0x54e5,0x54e6,0x54e7,
+ 0x54e8,0x54e9,0x54ea,0x54eb,0x54ec,0x54ed,0x54ee,0x54ef,
+ 0x54f0,0x54f1,0x54f2,0x54f3,0x54f4,0x54f5,0x54f6,0x54f7,
+ 0x54f8,0x54f9,0x54fa,0x54fb,0x54fc,0x54fd,0x54fe,0x54ff,
+ 0x5500,0x5501,0x5502,0x5503,0x5504,0x5505,0x5506,0x5507,
+ 0x5508,0x5509,0x550a,0x550b,0x550c,0x550d,0x550e,0x550f,
+ 0x5510,0x5511,0x5512,0x5513,0x5514,0x5515,0x5516,0x5517,
+ 0x5518,0x5519,0x551a,0x551b,0x551c,0x551d,0x551e,0x551f,
+ 0x5520,0x5521,0x5522,0x5523,0x5524,0x5525,0x5526,0x5527,
+ 0x5528,0x5529,0x552a,0x552b,0x552c,0x552d,0x552e,0x552f,
+ 0x5530,0x5531,0x5532,0x5533,0x5534,0x5535,0x5536,0x5537,
+ 0x5538,0x5539,0x553a,0x553b,0x553c,0x553d,0x553e,0x553f,
+ 0x5540,0x5541,0x5542,0x5543,0x5544,0x5545,0x5546,0x5547,
+ 0x5548,0x5549,0x554a,0x554b,0x554c,0x554d,0x554e,0x554f,
+ 0x5550,0x5551,0x5552,0x5553,0x5554,0x5555,0x5556,0x5557,
+ 0x5558,0x5559,0x555a,0x555b,0x555c,0x555d,0x555e,0x555f,
+ 0x5560,0x5561,0x5562,0x5563,0x5564,0x5565,0x5566,0x5567,
+ 0x5568,0x5569,0x556a,0x556b,0x556c,0x556d,0x556e,0x556f,
+ 0x5570,0x5571,0x5572,0x5573,0x5574,0x5575,0x5576,0x5577,
+ 0x5578,0x5579,0x557a,0x557b,0x557c,0x557d,0x557e,0x557f,
+ 0x5580,0x5581,0x5582,0x5583,0x5584,0x5585,0x5586,0x5587,
+ 0x5588,0x5589,0x558a,0x558b,0x558c,0x558d,0x558e,0x558f,
+ 0x5590,0x5591,0x5592,0x5593,0x5594,0x5595,0x5596,0x5597,
+ 0x5598,0x5599,0x559a,0x559b,0x559c,0x559d,0x559e,0x559f,
+ 0x55a0,0x55a1,0x55a2,0x55a3,0x55a4,0x55a5,0x55a6,0x55a7,
+ 0x55a8,0x55a9,0x55aa,0x55ab,0x55ac,0x55ad,0x55ae,0x55af,
+ 0x55b0,0x55b1,0x55b2,0x55b3,0x55b4,0x55b5,0x55b6,0x55b7,
+ 0x55b8,0x55b9,0x55ba,0x55bb,0x55bc,0x55bd,0x55be,0x55bf,
+ 0x55c0,0x55c1,0x55c2,0x55c3,0x55c4,0x55c5,0x55c6,0x55c7,
+ 0x55c8,0x55c9,0x55ca,0x55cb,0x55cc,0x55cd,0x55ce,0x55cf,
+ 0x55d0,0x55d1,0x55d2,0x55d3,0x55d4,0x55d5,0x55d6,0x55d7,
+ 0x55d8,0x55d9,0x55da,0x55db,0x55dc,0x55dd,0x55de,0x55df,
+ 0x55e0,0x55e1,0x55e2,0x55e3,0x55e4,0x55e5,0x55e6,0x55e7,
+ 0x55e8,0x55e9,0x55ea,0x55eb,0x55ec,0x55ed,0x55ee,0x55ef,
+ 0x55f0,0x55f1,0x55f2,0x55f3,0x55f4,0x55f5,0x55f6,0x55f7,
+ 0x55f8,0x55f9,0x55fa,0x55fb,0x55fc,0x55fd,0x55fe,0x55ff,
+ 0x5600,0x5601,0x5602,0x5603,0x5604,0x5605,0x5606,0x5607,
+ 0x5608,0x5609,0x560a,0x560b,0x560c,0x560d,0x560e,0x560f,
+ 0x5610,0x5611,0x5612,0x5613,0x5614,0x5615,0x5616,0x5617,
+ 0x5618,0x5619,0x561a,0x561b,0x561c,0x561d,0x561e,0x561f,
+ 0x5620,0x5621,0x5622,0x5623,0x5624,0x5625,0x5626,0x5627,
+ 0x5628,0x5629,0x562a,0x562b,0x562c,0x562d,0x562e,0x562f,
+ 0x5630,0x5631,0x5632,0x5633,0x5634,0x5635,0x5636,0x5637,
+ 0x5638,0x5639,0x563a,0x563b,0x563c,0x563d,0x563e,0x563f,
+ 0x5640,0x5641,0x5642,0x5643,0x5644,0x5645,0x5646,0x5647,
+ 0x5648,0x5649,0x564a,0x564b,0x564c,0x564d,0x564e,0x564f,
+ 0x5650,0x5651,0x5652,0x5653,0x5654,0x5655,0x5656,0x5657,
+ 0x5658,0x5659,0x565a,0x565b,0x565c,0x565d,0x565e,0x565f,
+ 0x5660,0x5661,0x5662,0x5663,0x5664,0x5665,0x5666,0x5667,
+ 0x5668,0x5669,0x566a,0x566b,0x566c,0x566d,0x566e,0x566f,
+ 0x5670,0x5671,0x5672,0x5673,0x5674,0x5675,0x5676,0x5677,
+ 0x5678,0x5679,0x567a,0x567b,0x567c,0x567d,0x567e,0x567f,
+ 0x5680,0x5681,0x5682,0x5683,0x5684,0x5685,0x5686,0x5687,
+ 0x5688,0x5689,0x568a,0x568b,0x568c,0x568d,0x568e,0x568f,
+ 0x5690,0x5691,0x5692,0x5693,0x5694,0x5695,0x5696,0x5697,
+ 0x5698,0x5699,0x569a,0x569b,0x569c,0x569d,0x569e,0x569f,
+ 0x56a0,0x56a1,0x56a2,0x56a3,0x56a4,0x56a5,0x56a6,0x56a7,
+ 0x56a8,0x56a9,0x56aa,0x56ab,0x56ac,0x56ad,0x56ae,0x56af,
+ 0x56b0,0x56b1,0x56b2,0x56b3,0x56b4,0x56b5,0x56b6,0x56b7,
+ 0x56b8,0x56b9,0x56ba,0x56bb,0x56bc,0x56bd,0x56be,0x56bf,
+ 0x56c0,0x56c1,0x56c2,0x56c3,0x56c4,0x56c5,0x56c6,0x56c7,
+ 0x56c8,0x56c9,0x56ca,0x56cb,0x56cc,0x56cd,0x56ce,0x56cf,
+ 0x56d0,0x56d1,0x56d2,0x56d3,0x56d4,0x56d5,0x56d6,0x56d7,
+ 0x56d8,0x56d9,0x56da,0x56db,0x56dc,0x56dd,0x56de,0x56df,
+ 0x56e0,0x56e1,0x56e2,0x56e3,0x56e4,0x56e5,0x56e6,0x56e7,
+ 0x56e8,0x56e9,0x56ea,0x56eb,0x56ec,0x56ed,0x56ee,0x56ef,
+ 0x56f0,0x56f1,0x56f2,0x56f3,0x56f4,0x56f5,0x56f6,0x56f7,
+ 0x56f8,0x56f9,0x56fa,0x56fb,0x56fc,0x56fd,0x56fe,0x56ff,
+ 0x5700,0x5701,0x5702,0x5703,0x5704,0x5705,0x5706,0x5707,
+ 0x5708,0x5709,0x570a,0x570b,0x570c,0x570d,0x570e,0x570f,
+ 0x5710,0x5711,0x5712,0x5713,0x5714,0x5715,0x5716,0x5717,
+ 0x5718,0x5719,0x571a,0x571b,0x571c,0x571d,0x571e,0x571f,
+ 0x5720,0x5721,0x5722,0x5723,0x5724,0x5725,0x5726,0x5727,
+ 0x5728,0x5729,0x572a,0x572b,0x572c,0x572d,0x572e,0x572f,
+ 0x5730,0x5731,0x5732,0x5733,0x5734,0x5735,0x5736,0x5737,
+ 0x5738,0x5739,0x573a,0x573b,0x573c,0x573d,0x573e,0x573f,
+ 0x5740,0x5741,0x5742,0x5743,0x5744,0x5745,0x5746,0x5747,
+ 0x5748,0x5749,0x574a,0x574b,0x574c,0x574d,0x574e,0x574f,
+ 0x5750,0x5751,0x5752,0x5753,0x5754,0x5755,0x5756,0x5757,
+ 0x5758,0x5759,0x575a,0x575b,0x575c,0x575d,0x575e,0x575f,
+ 0x5760,0x5761,0x5762,0x5763,0x5764,0x5765,0x5766,0x5767,
+ 0x5768,0x5769,0x576a,0x576b,0x576c,0x576d,0x576e,0x576f,
+ 0x5770,0x5771,0x5772,0x5773,0x5774,0x5775,0x5776,0x5777,
+ 0x5778,0x5779,0x577a,0x577b,0x577c,0x577d,0x577e,0x577f,
+ 0x5780,0x5781,0x5782,0x5783,0x5784,0x5785,0x5786,0x5787,
+ 0x5788,0x5789,0x578a,0x578b,0x578c,0x578d,0x578e,0x578f,
+ 0x5790,0x5791,0x5792,0x5793,0x5794,0x5795,0x5796,0x5797,
+ 0x5798,0x5799,0x579a,0x579b,0x579c,0x579d,0x579e,0x579f,
+ 0x57a0,0x57a1,0x57a2,0x57a3,0x57a4,0x57a5,0x57a6,0x57a7,
+ 0x57a8,0x57a9,0x57aa,0x57ab,0x57ac,0x57ad,0x57ae,0x57af,
+ 0x57b0,0x57b1,0x57b2,0x57b3,0x57b4,0x57b5,0x57b6,0x57b7,
+ 0x57b8,0x57b9,0x57ba,0x57bb,0x57bc,0x57bd,0x57be,0x57bf,
+ 0x57c0,0x57c1,0x57c2,0x57c3,0x57c4,0x57c5,0x57c6,0x57c7,
+ 0x57c8,0x57c9,0x57ca,0x57cb,0x57cc,0x57cd,0x57ce,0x57cf,
+ 0x57d0,0x57d1,0x57d2,0x57d3,0x57d4,0x57d5,0x57d6,0x57d7,
+ 0x57d8,0x57d9,0x57da,0x57db,0x57dc,0x57dd,0x57de,0x57df,
+ 0x57e0,0x57e1,0x57e2,0x57e3,0x57e4,0x57e5,0x57e6,0x57e7,
+ 0x57e8,0x57e9,0x57ea,0x57eb,0x57ec,0x57ed,0x57ee,0x57ef,
+ 0x57f0,0x57f1,0x57f2,0x57f3,0x57f4,0x57f5,0x57f6,0x57f7,
+ 0x57f8,0x57f9,0x57fa,0x57fb,0x57fc,0x57fd,0x57fe,0x57ff,
+ 0x5800,0x5801,0x5802,0x5803,0x5804,0x5805,0x5806,0x5807,
+ 0x5808,0x5809,0x580a,0x580b,0x580c,0x580d,0x580e,0x580f,
+ 0x5810,0x5811,0x5812,0x5813,0x5814,0x5815,0x5816,0x5817,
+ 0x5818,0x5819,0x581a,0x581b,0x581c,0x581d,0x581e,0x581f,
+ 0x5820,0x5821,0x5822,0x5823,0x5824,0x5825,0x5826,0x5827,
+ 0x5828,0x5829,0x582a,0x582b,0x582c,0x582d,0x582e,0x582f,
+ 0x5830,0x5831,0x5832,0x5833,0x5834,0x5835,0x5836,0x5837,
+ 0x5838,0x5839,0x583a,0x583b,0x583c,0x583d,0x583e,0x583f,
+ 0x5840,0x5841,0x5842,0x5843,0x5844,0x5845,0x5846,0x5847,
+ 0x5848,0x5849,0x584a,0x584b,0x584c,0x584d,0x584e,0x584f,
+ 0x5850,0x5851,0x5852,0x5853,0x5854,0x5855,0x5856,0x5857,
+ 0x5858,0x5859,0x585a,0x585b,0x585c,0x585d,0x585e,0x585f,
+ 0x5860,0x5861,0x5862,0x5863,0x5864,0x5865,0x5866,0x5867,
+ 0x5868,0x5869,0x586a,0x586b,0x586c,0x586d,0x586e,0x586f,
+ 0x5870,0x5871,0x5872,0x5873,0x5874,0x5875,0x5876,0x5877,
+ 0x5878,0x5879,0x587a,0x587b,0x587c,0x587d,0x587e,0x587f,
+ 0x5880,0x5881,0x5882,0x5883,0x5884,0x5885,0x5886,0x5887,
+ 0x5888,0x5889,0x588a,0x588b,0x588c,0x588d,0x588e,0x588f,
+ 0x5890,0x5891,0x5892,0x5893,0x5894,0x5895,0x5896,0x5897,
+ 0x5898,0x5899,0x589a,0x589b,0x589c,0x589d,0x589e,0x589f,
+ 0x58a0,0x58a1,0x58a2,0x58a3,0x58a4,0x58a5,0x58a6,0x58a7,
+ 0x58a8,0x58a9,0x58aa,0x58ab,0x58ac,0x58ad,0x58ae,0x58af,
+ 0x58b0,0x58b1,0x58b2,0x58b3,0x58b4,0x58b5,0x58b6,0x58b7,
+ 0x58b8,0x58b9,0x58ba,0x58bb,0x58bc,0x58bd,0x58be,0x58bf,
+ 0x58c0,0x58c1,0x58c2,0x58c3,0x58c4,0x58c5,0x58c6,0x58c7,
+ 0x58c8,0x58c9,0x58ca,0x58cb,0x58cc,0x58cd,0x58ce,0x58cf,
+ 0x58d0,0x58d1,0x58d2,0x58d3,0x58d4,0x58d5,0x58d6,0x58d7,
+ 0x58d8,0x58d9,0x58da,0x58db,0x58dc,0x58dd,0x58de,0x58df,
+ 0x58e0,0x58e1,0x58e2,0x58e3,0x58e4,0x58e5,0x58e6,0x58e7,
+ 0x58e8,0x58e9,0x58ea,0x58eb,0x58ec,0x58ed,0x58ee,0x58ef,
+ 0x58f0,0x58f1,0x58f2,0x58f3,0x58f4,0x58f5,0x58f6,0x58f7,
+ 0x58f8,0x58f9,0x58fa,0x58fb,0x58fc,0x58fd,0x58fe,0x58ff,
+ 0x5900,0x5901,0x5902,0x5903,0x5904,0x5905,0x5906,0x5907,
+ 0x5908,0x5909,0x590a,0x590b,0x590c,0x590d,0x590e,0x590f,
+ 0x5910,0x5911,0x5912,0x5913,0x5914,0x5915,0x5916,0x5917,
+ 0x5918,0x5919,0x591a,0x591b,0x591c,0x591d,0x591e,0x591f,
+ 0x5920,0x5921,0x5922,0x5923,0x5924,0x5925,0x5926,0x5927,
+ 0x5928,0x5929,0x592a,0x592b,0x592c,0x592d,0x592e,0x592f,
+ 0x5930,0x5931,0x5932,0x5933,0x5934,0x5935,0x5936,0x5937,
+ 0x5938,0x5939,0x593a,0x593b,0x593c,0x593d,0x593e,0x593f,
+ 0x5940,0x5941,0x5942,0x5943,0x5944,0x5945,0x5946,0x5947,
+ 0x5948,0x5949,0x594a,0x594b,0x594c,0x594d,0x594e,0x594f,
+ 0x5950,0x5951,0x5952,0x5953,0x5954,0x5955,0x5956,0x5957,
+ 0x5958,0x5959,0x595a,0x595b,0x595c,0x595d,0x595e,0x595f,
+ 0x5960,0x5961,0x5962,0x5963,0x5964,0x5965,0x5966,0x5967,
+ 0x5968,0x5969,0x596a,0x596b,0x596c,0x596d,0x596e,0x596f,
+ 0x5970,0x5971,0x5972,0x5973,0x5974,0x5975,0x5976,0x5977,
+ 0x5978,0x5979,0x597a,0x597b,0x597c,0x597d,0x597e,0x597f,
+ 0x5980,0x5981,0x5982,0x5983,0x5984,0x5985,0x5986,0x5987,
+ 0x5988,0x5989,0x598a,0x598b,0x598c,0x598d,0x598e,0x598f,
+ 0x5990,0x5991,0x5992,0x5993,0x5994,0x5995,0x5996,0x5997,
+ 0x5998,0x5999,0x599a,0x599b,0x599c,0x599d,0x599e,0x599f,
+ 0x59a0,0x59a1,0x59a2,0x59a3,0x59a4,0x59a5,0x59a6,0x59a7,
+ 0x59a8,0x59a9,0x59aa,0x59ab,0x59ac,0x59ad,0x59ae,0x59af,
+ 0x59b0,0x59b1,0x59b2,0x59b3,0x59b4,0x59b5,0x59b6,0x59b7,
+ 0x59b8,0x59b9,0x59ba,0x59bb,0x59bc,0x59bd,0x59be,0x59bf,
+ 0x59c0,0x59c1,0x59c2,0x59c3,0x59c4,0x59c5,0x59c6,0x59c7,
+ 0x59c8,0x59c9,0x59ca,0x59cb,0x59cc,0x59cd,0x59ce,0x59cf,
+ 0x59d0,0x59d1,0x59d2,0x59d3,0x59d4,0x59d5,0x59d6,0x59d7,
+ 0x59d8,0x59d9,0x59da,0x59db,0x59dc,0x59dd,0x59de,0x59df,
+ 0x59e0,0x59e1,0x59e2,0x59e3,0x59e4,0x59e5,0x59e6,0x59e7,
+ 0x59e8,0x59e9,0x59ea,0x59eb,0x59ec,0x59ed,0x59ee,0x59ef,
+ 0x59f0,0x59f1,0x59f2,0x59f3,0x59f4,0x59f5,0x59f6,0x59f7,
+ 0x59f8,0x59f9,0x59fa,0x59fb,0x59fc,0x59fd,0x59fe,0x59ff,
+ 0x5a00,0x5a01,0x5a02,0x5a03,0x5a04,0x5a05,0x5a06,0x5a07,
+ 0x5a08,0x5a09,0x5a0a,0x5a0b,0x5a0c,0x5a0d,0x5a0e,0x5a0f,
+ 0x5a10,0x5a11,0x5a12,0x5a13,0x5a14,0x5a15,0x5a16,0x5a17,
+ 0x5a18,0x5a19,0x5a1a,0x5a1b,0x5a1c,0x5a1d,0x5a1e,0x5a1f,
+ 0x5a20,0x5a21,0x5a22,0x5a23,0x5a24,0x5a25,0x5a26,0x5a27,
+ 0x5a28,0x5a29,0x5a2a,0x5a2b,0x5a2c,0x5a2d,0x5a2e,0x5a2f,
+ 0x5a30,0x5a31,0x5a32,0x5a33,0x5a34,0x5a35,0x5a36,0x5a37,
+ 0x5a38,0x5a39,0x5a3a,0x5a3b,0x5a3c,0x5a3d,0x5a3e,0x5a3f,
+ 0x5a40,0x5a41,0x5a42,0x5a43,0x5a44,0x5a45,0x5a46,0x5a47,
+ 0x5a48,0x5a49,0x5a4a,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f,
+ 0x5a50,0x5a51,0x5a52,0x5a53,0x5a54,0x5a55,0x5a56,0x5a57,
+ 0x5a58,0x5a59,0x5a5a,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5a5f,
+ 0x5a60,0x5a61,0x5a62,0x5a63,0x5a64,0x5a65,0x5a66,0x5a67,
+ 0x5a68,0x5a69,0x5a6a,0x5a6b,0x5a6c,0x5a6d,0x5a6e,0x5a6f,
+ 0x5a70,0x5a71,0x5a72,0x5a73,0x5a74,0x5a75,0x5a76,0x5a77,
+ 0x5a78,0x5a79,0x5a7a,0x5a7b,0x5a7c,0x5a7d,0x5a7e,0x5a7f,
+ 0x5a80,0x5a81,0x5a82,0x5a83,0x5a84,0x5a85,0x5a86,0x5a87,
+ 0x5a88,0x5a89,0x5a8a,0x5a8b,0x5a8c,0x5a8d,0x5a8e,0x5a8f,
+ 0x5a90,0x5a91,0x5a92,0x5a93,0x5a94,0x5a95,0x5a96,0x5a97,
+ 0x5a98,0x5a99,0x5a9a,0x5a9b,0x5a9c,0x5a9d,0x5a9e,0x5a9f,
+ 0x5aa0,0x5aa1,0x5aa2,0x5aa3,0x5aa4,0x5aa5,0x5aa6,0x5aa7,
+ 0x5aa8,0x5aa9,0x5aaa,0x5aab,0x5aac,0x5aad,0x5aae,0x5aaf,
+ 0x5ab0,0x5ab1,0x5ab2,0x5ab3,0x5ab4,0x5ab5,0x5ab6,0x5ab7,
+ 0x5ab8,0x5ab9,0x5aba,0x5abb,0x5abc,0x5abd,0x5abe,0x5abf,
+ 0x5ac0,0x5ac1,0x5ac2,0x5ac3,0x5ac4,0x5ac5,0x5ac6,0x5ac7,
+ 0x5ac8,0x5ac9,0x5aca,0x5acb,0x5acc,0x5acd,0x5ace,0x5acf,
+ 0x5ad0,0x5ad1,0x5ad2,0x5ad3,0x5ad4,0x5ad5,0x5ad6,0x5ad7,
+ 0x5ad8,0x5ad9,0x5ada,0x5adb,0x5adc,0x5add,0x5ade,0x5adf,
+ 0x5ae0,0x5ae1,0x5ae2,0x5ae3,0x5ae4,0x5ae5,0x5ae6,0x5ae7,
+ 0x5ae8,0x5ae9,0x5aea,0x5aeb,0x5aec,0x5aed,0x5aee,0x5aef,
+ 0x5af0,0x5af1,0x5af2,0x5af3,0x5af4,0x5af5,0x5af6,0x5af7,
+ 0x5af8,0x5af9,0x5afa,0x5afb,0x5afc,0x5afd,0x5afe,0x5aff,
+ 0x5b00,0x5b01,0x5b02,0x5b03,0x5b04,0x5b05,0x5b06,0x5b07,
+ 0x5b08,0x5b09,0x5b0a,0x5b0b,0x5b0c,0x5b0d,0x5b0e,0x5b0f,
+ 0x5b10,0x5b11,0x5b12,0x5b13,0x5b14,0x5b15,0x5b16,0x5b17,
+ 0x5b18,0x5b19,0x5b1a,0x5b1b,0x5b1c,0x5b1d,0x5b1e,0x5b1f,
+ 0x5b20,0x5b21,0x5b22,0x5b23,0x5b24,0x5b25,0x5b26,0x5b27,
+ 0x5b28,0x5b29,0x5b2a,0x5b2b,0x5b2c,0x5b2d,0x5b2e,0x5b2f,
+ 0x5b30,0x5b31,0x5b32,0x5b33,0x5b34,0x5b35,0x5b36,0x5b37,
+ 0x5b38,0x5b39,0x5b3a,0x5b3b,0x5b3c,0x5b3d,0x5b3e,0x5b3f,
+ 0x5b40,0x5b41,0x5b42,0x5b43,0x5b44,0x5b45,0x5b46,0x5b47,
+ 0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f,
+ 0x5b50,0x5b51,0x5b52,0x5b53,0x5b54,0x5b55,0x5b56,0x5b57,
+ 0x5b58,0x5b59,0x5b5a,0x5b5b,0x5b5c,0x5b5d,0x5b5e,0x5b5f,
+ 0x5b60,0x5b61,0x5b62,0x5b63,0x5b64,0x5b65,0x5b66,0x5b67,
+ 0x5b68,0x5b69,0x5b6a,0x5b6b,0x5b6c,0x5b6d,0x5b6e,0x5b6f,
+ 0x5b70,0x5b71,0x5b72,0x5b73,0x5b74,0x5b75,0x5b76,0x5b77,
+ 0x5b78,0x5b79,0x5b7a,0x5b7b,0x5b7c,0x5b7d,0x5b7e,0x5b7f,
+ 0x5b80,0x5b81,0x5b82,0x5b83,0x5b84,0x5b85,0x5b86,0x5b87,
+ 0x5b88,0x5b89,0x5b8a,0x5b8b,0x5b8c,0x5b8d,0x5b8e,0x5b8f,
+ 0x5b90,0x5b91,0x5b92,0x5b93,0x5b94,0x5b95,0x5b96,0x5b97,
+ 0x5b98,0x5b99,0x5b9a,0x5b9b,0x5b9c,0x5b9d,0x5b9e,0x5b9f,
+ 0x5ba0,0x5ba1,0x5ba2,0x5ba3,0x5ba4,0x5ba5,0x5ba6,0x5ba7,
+ 0x5ba8,0x5ba9,0x5baa,0x5bab,0x5bac,0x5bad,0x5bae,0x5baf,
+ 0x5bb0,0x5bb1,0x5bb2,0x5bb3,0x5bb4,0x5bb5,0x5bb6,0x5bb7,
+ 0x5bb8,0x5bb9,0x5bba,0x5bbb,0x5bbc,0x5bbd,0x5bbe,0x5bbf,
+ 0x5bc0,0x5bc1,0x5bc2,0x5bc3,0x5bc4,0x5bc5,0x5bc6,0x5bc7,
+ 0x5bc8,0x5bc9,0x5bca,0x5bcb,0x5bcc,0x5bcd,0x5bce,0x5bcf,
+ 0x5bd0,0x5bd1,0x5bd2,0x5bd3,0x5bd4,0x5bd5,0x5bd6,0x5bd7,
+ 0x5bd8,0x5bd9,0x5bda,0x5bdb,0x5bdc,0x5bdd,0x5bde,0x5bdf,
+ 0x5be0,0x5be1,0x5be2,0x5be3,0x5be4,0x5be5,0x5be6,0x5be7,
+ 0x5be8,0x5be9,0x5bea,0x5beb,0x5bec,0x5bed,0x5bee,0x5bef,
+ 0x5bf0,0x5bf1,0x5bf2,0x5bf3,0x5bf4,0x5bf5,0x5bf6,0x5bf7,
+ 0x5bf8,0x5bf9,0x5bfa,0x5bfb,0x5bfc,0x5bfd,0x5bfe,0x5bff,
+ 0x5c00,0x5c01,0x5c02,0x5c03,0x5c04,0x5c05,0x5c06,0x5c07,
+ 0x5c08,0x5c09,0x5c0a,0x5c0b,0x5c0c,0x5c0d,0x5c0e,0x5c0f,
+ 0x5c10,0x5c11,0x5c12,0x5c13,0x5c14,0x5c15,0x5c16,0x5c17,
+ 0x5c18,0x5c19,0x5c1a,0x5c1b,0x5c1c,0x5c1d,0x5c1e,0x5c1f,
+ 0x5c20,0x5c21,0x5c22,0x5c23,0x5c24,0x5c25,0x5c26,0x5c27,
+ 0x5c28,0x5c29,0x5c2a,0x5c2b,0x5c2c,0x5c2d,0x5c2e,0x5c2f,
+ 0x5c30,0x5c31,0x5c32,0x5c33,0x5c34,0x5c35,0x5c36,0x5c37,
+ 0x5c38,0x5c39,0x5c3a,0x5c3b,0x5c3c,0x5c3d,0x5c3e,0x5c3f,
+ 0x5c40,0x5c41,0x5c42,0x5c43,0x5c44,0x5c45,0x5c46,0x5c47,
+ 0x5c48,0x5c49,0x5c4a,0x5c4b,0x5c4c,0x5c4d,0x5c4e,0x5c4f,
+ 0x5c50,0x5c51,0x5c52,0x5c53,0x5c54,0x5c55,0x5c56,0x5c57,
+ 0x5c58,0x5c59,0x5c5a,0x5c5b,0x5c5c,0x5c5d,0x5c5e,0x5c5f,
+ 0x5c60,0x5c61,0x5c62,0x5c63,0x5c64,0x5c65,0x5c66,0x5c67,
+ 0x5c68,0x5c69,0x5c6a,0x5c6b,0x5c6c,0x5c6d,0x5c6e,0x5c6f,
+ 0x5c70,0x5c71,0x5c72,0x5c73,0x5c74,0x5c75,0x5c76,0x5c77,
+ 0x5c78,0x5c79,0x5c7a,0x5c7b,0x5c7c,0x5c7d,0x5c7e,0x5c7f,
+ 0x5c80,0x5c81,0x5c82,0x5c83,0x5c84,0x5c85,0x5c86,0x5c87,
+ 0x5c88,0x5c89,0x5c8a,0x5c8b,0x5c8c,0x5c8d,0x5c8e,0x5c8f,
+ 0x5c90,0x5c91,0x5c92,0x5c93,0x5c94,0x5c95,0x5c96,0x5c97,
+ 0x5c98,0x5c99,0x5c9a,0x5c9b,0x5c9c,0x5c9d,0x5c9e,0x5c9f,
+ 0x5ca0,0x5ca1,0x5ca2,0x5ca3,0x5ca4,0x5ca5,0x5ca6,0x5ca7,
+ 0x5ca8,0x5ca9,0x5caa,0x5cab,0x5cac,0x5cad,0x5cae,0x5caf,
+ 0x5cb0,0x5cb1,0x5cb2,0x5cb3,0x5cb4,0x5cb5,0x5cb6,0x5cb7,
+ 0x5cb8,0x5cb9,0x5cba,0x5cbb,0x5cbc,0x5cbd,0x5cbe,0x5cbf,
+ 0x5cc0,0x5cc1,0x5cc2,0x5cc3,0x5cc4,0x5cc5,0x5cc6,0x5cc7,
+ 0x5cc8,0x5cc9,0x5cca,0x5ccb,0x5ccc,0x5ccd,0x5cce,0x5ccf,
+ 0x5cd0,0x5cd1,0x5cd2,0x5cd3,0x5cd4,0x5cd5,0x5cd6,0x5cd7,
+ 0x5cd8,0x5cd9,0x5cda,0x5cdb,0x5cdc,0x5cdd,0x5cde,0x5cdf,
+ 0x5ce0,0x5ce1,0x5ce2,0x5ce3,0x5ce4,0x5ce5,0x5ce6,0x5ce7,
+ 0x5ce8,0x5ce9,0x5cea,0x5ceb,0x5cec,0x5ced,0x5cee,0x5cef,
+ 0x5cf0,0x5cf1,0x5cf2,0x5cf3,0x5cf4,0x5cf5,0x5cf6,0x5cf7,
+ 0x5cf8,0x5cf9,0x5cfa,0x5cfb,0x5cfc,0x5cfd,0x5cfe,0x5cff,
+ 0x5d00,0x5d01,0x5d02,0x5d03,0x5d04,0x5d05,0x5d06,0x5d07,
+ 0x5d08,0x5d09,0x5d0a,0x5d0b,0x5d0c,0x5d0d,0x5d0e,0x5d0f,
+ 0x5d10,0x5d11,0x5d12,0x5d13,0x5d14,0x5d15,0x5d16,0x5d17,
+ 0x5d18,0x5d19,0x5d1a,0x5d1b,0x5d1c,0x5d1d,0x5d1e,0x5d1f,
+ 0x5d20,0x5d21,0x5d22,0x5d23,0x5d24,0x5d25,0x5d26,0x5d27,
+ 0x5d28,0x5d29,0x5d2a,0x5d2b,0x5d2c,0x5d2d,0x5d2e,0x5d2f,
+ 0x5d30,0x5d31,0x5d32,0x5d33,0x5d34,0x5d35,0x5d36,0x5d37,
+ 0x5d38,0x5d39,0x5d3a,0x5d3b,0x5d3c,0x5d3d,0x5d3e,0x5d3f,
+ 0x5d40,0x5d41,0x5d42,0x5d43,0x5d44,0x5d45,0x5d46,0x5d47,
+ 0x5d48,0x5d49,0x5d4a,0x5d4b,0x5d4c,0x5d4d,0x5d4e,0x5d4f,
+ 0x5d50,0x5d51,0x5d52,0x5d53,0x5d54,0x5d55,0x5d56,0x5d57,
+ 0x5d58,0x5d59,0x5d5a,0x5d5b,0x5d5c,0x5d5d,0x5d5e,0x5d5f,
+ 0x5d60,0x5d61,0x5d62,0x5d63,0x5d64,0x5d65,0x5d66,0x5d67,
+ 0x5d68,0x5d69,0x5d6a,0x5d6b,0x5d6c,0x5d6d,0x5d6e,0x5d6f,
+ 0x5d70,0x5d71,0x5d72,0x5d73,0x5d74,0x5d75,0x5d76,0x5d77,
+ 0x5d78,0x5d79,0x5d7a,0x5d7b,0x5d7c,0x5d7d,0x5d7e,0x5d7f,
+ 0x5d80,0x5d81,0x5d82,0x5d83,0x5d84,0x5d85,0x5d86,0x5d87,
+ 0x5d88,0x5d89,0x5d8a,0x5d8b,0x5d8c,0x5d8d,0x5d8e,0x5d8f,
+ 0x5d90,0x5d91,0x5d92,0x5d93,0x5d94,0x5d95,0x5d96,0x5d97,
+ 0x5d98,0x5d99,0x5d9a,0x5d9b,0x5d9c,0x5d9d,0x5d9e,0x5d9f,
+ 0x5da0,0x5da1,0x5da2,0x5da3,0x5da4,0x5da5,0x5da6,0x5da7,
+ 0x5da8,0x5da9,0x5daa,0x5dab,0x5dac,0x5dad,0x5dae,0x5daf,
+ 0x5db0,0x5db1,0x5db2,0x5db3,0x5db4,0x5db5,0x5db6,0x5db7,
+ 0x5db8,0x5db9,0x5dba,0x5dbb,0x5dbc,0x5dbd,0x5dbe,0x5dbf,
+ 0x5dc0,0x5dc1,0x5dc2,0x5dc3,0x5dc4,0x5dc5,0x5dc6,0x5dc7,
+ 0x5dc8,0x5dc9,0x5dca,0x5dcb,0x5dcc,0x5dcd,0x5dce,0x5dcf,
+ 0x5dd0,0x5dd1,0x5dd2,0x5dd3,0x5dd4,0x5dd5,0x5dd6,0x5dd7,
+ 0x5dd8,0x5dd9,0x5dda,0x5ddb,0x5ddc,0x5ddd,0x5dde,0x5ddf,
+ 0x5de0,0x5de1,0x5de2,0x5de3,0x5de4,0x5de5,0x5de6,0x5de7,
+ 0x5de8,0x5de9,0x5dea,0x5deb,0x5dec,0x5ded,0x5dee,0x5def,
+ 0x5df0,0x5df1,0x5df2,0x5df3,0x5df4,0x5df5,0x5df6,0x5df7,
+ 0x5df8,0x5df9,0x5dfa,0x5dfb,0x5dfc,0x5dfd,0x5dfe,0x5dff,
+ 0x5e00,0x5e01,0x5e02,0x5e03,0x5e04,0x5e05,0x5e06,0x5e07,
+ 0x5e08,0x5e09,0x5e0a,0x5e0b,0x5e0c,0x5e0d,0x5e0e,0x5e0f,
+ 0x5e10,0x5e11,0x5e12,0x5e13,0x5e14,0x5e15,0x5e16,0x5e17,
+ 0x5e18,0x5e19,0x5e1a,0x5e1b,0x5e1c,0x5e1d,0x5e1e,0x5e1f,
+ 0x5e20,0x5e21,0x5e22,0x5e23,0x5e24,0x5e25,0x5e26,0x5e27,
+ 0x5e28,0x5e29,0x5e2a,0x5e2b,0x5e2c,0x5e2d,0x5e2e,0x5e2f,
+ 0x5e30,0x5e31,0x5e32,0x5e33,0x5e34,0x5e35,0x5e36,0x5e37,
+ 0x5e38,0x5e39,0x5e3a,0x5e3b,0x5e3c,0x5e3d,0x5e3e,0x5e3f,
+ 0x5e40,0x5e41,0x5e42,0x5e43,0x5e44,0x5e45,0x5e46,0x5e47,
+ 0x5e48,0x5e49,0x5e4a,0x5e4b,0x5e4c,0x5e4d,0x5e4e,0x5e4f,
+ 0x5e50,0x5e51,0x5e52,0x5e53,0x5e54,0x5e55,0x5e56,0x5e57,
+ 0x5e58,0x5e59,0x5e5a,0x5e5b,0x5e5c,0x5e5d,0x5e5e,0x5e5f,
+ 0x5e60,0x5e61,0x5e62,0x5e63,0x5e64,0x5e65,0x5e66,0x5e67,
+ 0x5e68,0x5e69,0x5e6a,0x5e6b,0x5e6c,0x5e6d,0x5e6e,0x5e6f,
+ 0x5e70,0x5e71,0x5e72,0x5e73,0x5e74,0x5e75,0x5e76,0x5e77,
+ 0x5e78,0x5e79,0x5e7a,0x5e7b,0x5e7c,0x5e7d,0x5e7e,0x5e7f,
+ 0x5e80,0x5e81,0x5e82,0x5e83,0x5e84,0x5e85,0x5e86,0x5e87,
+ 0x5e88,0x5e89,0x5e8a,0x5e8b,0x5e8c,0x5e8d,0x5e8e,0x5e8f,
+ 0x5e90,0x5e91,0x5e92,0x5e93,0x5e94,0x5e95,0x5e96,0x5e97,
+ 0x5e98,0x5e99,0x5e9a,0x5e9b,0x5e9c,0x5e9d,0x5e9e,0x5e9f,
+ 0x5ea0,0x5ea1,0x5ea2,0x5ea3,0x5ea4,0x5ea5,0x5ea6,0x5ea7,
+ 0x5ea8,0x5ea9,0x5eaa,0x5eab,0x5eac,0x5ead,0x5eae,0x5eaf,
+ 0x5eb0,0x5eb1,0x5eb2,0x5eb3,0x5eb4,0x5eb5,0x5eb6,0x5eb7,
+ 0x5eb8,0x5eb9,0x5eba,0x5ebb,0x5ebc,0x5ebd,0x5ebe,0x5ebf,
+ 0x5ec0,0x5ec1,0x5ec2,0x5ec3,0x5ec4,0x5ec5,0x5ec6,0x5ec7,
+ 0x5ec8,0x5ec9,0x5eca,0x5ecb,0x5ecc,0x5ecd,0x5ece,0x5ecf,
+ 0x5ed0,0x5ed1,0x5ed2,0x5ed3,0x5ed4,0x5ed5,0x5ed6,0x5ed7,
+ 0x5ed8,0x5ed9,0x5eda,0x5edb,0x5edc,0x5edd,0x5ede,0x5edf,
+ 0x5ee0,0x5ee1,0x5ee2,0x5ee3,0x5ee4,0x5ee5,0x5ee6,0x5ee7,
+ 0x5ee8,0x5ee9,0x5eea,0x5eeb,0x5eec,0x5eed,0x5eee,0x5eef,
+ 0x5ef0,0x5ef1,0x5ef2,0x5ef3,0x5ef4,0x5ef5,0x5ef6,0x5ef7,
+ 0x5ef8,0x5ef9,0x5efa,0x5efb,0x5efc,0x5efd,0x5efe,0x5eff,
+ 0x5f00,0x5f01,0x5f02,0x5f03,0x5f04,0x5f05,0x5f06,0x5f07,
+ 0x5f08,0x5f09,0x5f0a,0x5f0b,0x5f0c,0x5f0d,0x5f0e,0x5f0f,
+ 0x5f10,0x5f11,0x5f12,0x5f13,0x5f14,0x5f15,0x5f16,0x5f17,
+ 0x5f18,0x5f19,0x5f1a,0x5f1b,0x5f1c,0x5f1d,0x5f1e,0x5f1f,
+ 0x5f20,0x5f21,0x5f22,0x5f23,0x5f24,0x5f25,0x5f26,0x5f27,
+ 0x5f28,0x5f29,0x5f2a,0x5f2b,0x5f2c,0x5f2d,0x5f2e,0x5f2f,
+ 0x5f30,0x5f31,0x5f32,0x5f33,0x5f34,0x5f35,0x5f36,0x5f37,
+ 0x5f38,0x5f39,0x5f3a,0x5f3b,0x5f3c,0x5f3d,0x5f3e,0x5f3f,
+ 0x5f40,0x5f41,0x5f42,0x5f43,0x5f44,0x5f45,0x5f46,0x5f47,
+ 0x5f48,0x5f49,0x5f4a,0x5f4b,0x5f4c,0x5f4d,0x5f4e,0x5f4f,
+ 0x5f50,0x5f51,0x5f52,0x5f53,0x5f54,0x5f55,0x5f56,0x5f57,
+ 0x5f58,0x5f59,0x5f5a,0x5f5b,0x5f5c,0x5f5d,0x5f5e,0x5f5f,
+ 0x5f60,0x5f61,0x5f62,0x5f63,0x5f64,0x5f65,0x5f66,0x5f67,
+ 0x5f68,0x5f69,0x5f6a,0x5f6b,0x5f6c,0x5f6d,0x5f6e,0x5f6f,
+ 0x5f70,0x5f71,0x5f72,0x5f73,0x5f74,0x5f75,0x5f76,0x5f77,
+ 0x5f78,0x5f79,0x5f7a,0x5f7b,0x5f7c,0x5f7d,0x5f7e,0x5f7f,
+ 0x5f80,0x5f81,0x5f82,0x5f83,0x5f84,0x5f85,0x5f86,0x5f87,
+ 0x5f88,0x5f89,0x5f8a,0x5f8b,0x5f8c,0x5f8d,0x5f8e,0x5f8f,
+ 0x5f90,0x5f91,0x5f92,0x5f93,0x5f94,0x5f95,0x5f96,0x5f97,
+ 0x5f98,0x5f99,0x5f9a,0x5f9b,0x5f9c,0x5f9d,0x5f9e,0x5f9f,
+ 0x5fa0,0x5fa1,0x5fa2,0x5fa3,0x5fa4,0x5fa5,0x5fa6,0x5fa7,
+ 0x5fa8,0x5fa9,0x5faa,0x5fab,0x5fac,0x5fad,0x5fae,0x5faf,
+ 0x5fb0,0x5fb1,0x5fb2,0x5fb3,0x5fb4,0x5fb5,0x5fb6,0x5fb7,
+ 0x5fb8,0x5fb9,0x5fba,0x5fbb,0x5fbc,0x5fbd,0x5fbe,0x5fbf,
+ 0x5fc0,0x5fc1,0x5fc2,0x5fc3,0x5fc4,0x5fc5,0x5fc6,0x5fc7,
+ 0x5fc8,0x5fc9,0x5fca,0x5fcb,0x5fcc,0x5fcd,0x5fce,0x5fcf,
+ 0x5fd0,0x5fd1,0x5fd2,0x5fd3,0x5fd4,0x5fd5,0x5fd6,0x5fd7,
+ 0x5fd8,0x5fd9,0x5fda,0x5fdb,0x5fdc,0x5fdd,0x5fde,0x5fdf,
+ 0x5fe0,0x5fe1,0x5fe2,0x5fe3,0x5fe4,0x5fe5,0x5fe6,0x5fe7,
+ 0x5fe8,0x5fe9,0x5fea,0x5feb,0x5fec,0x5fed,0x5fee,0x5fef,
+ 0x5ff0,0x5ff1,0x5ff2,0x5ff3,0x5ff4,0x5ff5,0x5ff6,0x5ff7,
+ 0x5ff8,0x5ff9,0x5ffa,0x5ffb,0x5ffc,0x5ffd,0x5ffe,0x5fff,
+ 0x6000,0x6001,0x6002,0x6003,0x6004,0x6005,0x6006,0x6007,
+ 0x6008,0x6009,0x600a,0x600b,0x600c,0x600d,0x600e,0x600f,
+ 0x6010,0x6011,0x6012,0x6013,0x6014,0x6015,0x6016,0x6017,
+ 0x6018,0x6019,0x601a,0x601b,0x601c,0x601d,0x601e,0x601f,
+ 0x6020,0x6021,0x6022,0x6023,0x6024,0x6025,0x6026,0x6027,
+ 0x6028,0x6029,0x602a,0x602b,0x602c,0x602d,0x602e,0x602f,
+ 0x6030,0x6031,0x6032,0x6033,0x6034,0x6035,0x6036,0x6037,
+ 0x6038,0x6039,0x603a,0x603b,0x603c,0x603d,0x603e,0x603f,
+ 0x6040,0x6041,0x6042,0x6043,0x6044,0x6045,0x6046,0x6047,
+ 0x6048,0x6049,0x604a,0x604b,0x604c,0x604d,0x604e,0x604f,
+ 0x6050,0x6051,0x6052,0x6053,0x6054,0x6055,0x6056,0x6057,
+ 0x6058,0x6059,0x605a,0x605b,0x605c,0x605d,0x605e,0x605f,
+ 0x6060,0x6061,0x6062,0x6063,0x6064,0x6065,0x6066,0x6067,
+ 0x6068,0x6069,0x606a,0x606b,0x606c,0x606d,0x606e,0x606f,
+ 0x6070,0x6071,0x6072,0x6073,0x6074,0x6075,0x6076,0x6077,
+ 0x6078,0x6079,0x607a,0x607b,0x607c,0x607d,0x607e,0x607f,
+ 0x6080,0x6081,0x6082,0x6083,0x6084,0x6085,0x6086,0x6087,
+ 0x6088,0x6089,0x608a,0x608b,0x608c,0x608d,0x608e,0x608f,
+ 0x6090,0x6091,0x6092,0x6093,0x6094,0x6095,0x6096,0x6097,
+ 0x6098,0x6099,0x609a,0x609b,0x609c,0x609d,0x609e,0x609f,
+ 0x60a0,0x60a1,0x60a2,0x60a3,0x60a4,0x60a5,0x60a6,0x60a7,
+ 0x60a8,0x60a9,0x60aa,0x60ab,0x60ac,0x60ad,0x60ae,0x60af,
+ 0x60b0,0x60b1,0x60b2,0x60b3,0x60b4,0x60b5,0x60b6,0x60b7,
+ 0x60b8,0x60b9,0x60ba,0x60bb,0x60bc,0x60bd,0x60be,0x60bf,
+ 0x60c0,0x60c1,0x60c2,0x60c3,0x60c4,0x60c5,0x60c6,0x60c7,
+ 0x60c8,0x60c9,0x60ca,0x60cb,0x60cc,0x60cd,0x60ce,0x60cf,
+ 0x60d0,0x60d1,0x60d2,0x60d3,0x60d4,0x60d5,0x60d6,0x60d7,
+ 0x60d8,0x60d9,0x60da,0x60db,0x60dc,0x60dd,0x60de,0x60df,
+ 0x60e0,0x60e1,0x60e2,0x60e3,0x60e4,0x60e5,0x60e6,0x60e7,
+ 0x60e8,0x60e9,0x60ea,0x60eb,0x60ec,0x60ed,0x60ee,0x60ef,
+ 0x60f0,0x60f1,0x60f2,0x60f3,0x60f4,0x60f5,0x60f6,0x60f7,
+ 0x60f8,0x60f9,0x60fa,0x60fb,0x60fc,0x60fd,0x60fe,0x60ff,
+ 0x6100,0x6101,0x6102,0x6103,0x6104,0x6105,0x6106,0x6107,
+ 0x6108,0x6109,0x610a,0x610b,0x610c,0x610d,0x610e,0x610f,
+ 0x6110,0x6111,0x6112,0x6113,0x6114,0x6115,0x6116,0x6117,
+ 0x6118,0x6119,0x611a,0x611b,0x611c,0x611d,0x611e,0x611f,
+ 0x6120,0x6121,0x6122,0x6123,0x6124,0x6125,0x6126,0x6127,
+ 0x6128,0x6129,0x612a,0x612b,0x612c,0x612d,0x612e,0x612f,
+ 0x6130,0x6131,0x6132,0x6133,0x6134,0x6135,0x6136,0x6137,
+ 0x6138,0x6139,0x613a,0x613b,0x613c,0x613d,0x613e,0x613f,
+ 0x6140,0x6141,0x6142,0x6143,0x6144,0x6145,0x6146,0x6147,
+ 0x6148,0x6149,0x614a,0x614b,0x614c,0x614d,0x614e,0x614f,
+ 0x6150,0x6151,0x6152,0x6153,0x6154,0x6155,0x6156,0x6157,
+ 0x6158,0x6159,0x615a,0x615b,0x615c,0x615d,0x615e,0x615f,
+ 0x6160,0x6161,0x6162,0x6163,0x6164,0x6165,0x6166,0x6167,
+ 0x6168,0x6169,0x616a,0x616b,0x616c,0x616d,0x616e,0x616f,
+ 0x6170,0x6171,0x6172,0x6173,0x6174,0x6175,0x6176,0x6177,
+ 0x6178,0x6179,0x617a,0x617b,0x617c,0x617d,0x617e,0x617f,
+ 0x6180,0x6181,0x6182,0x6183,0x6184,0x6185,0x6186,0x6187,
+ 0x6188,0x6189,0x618a,0x618b,0x618c,0x618d,0x618e,0x618f,
+ 0x6190,0x6191,0x6192,0x6193,0x6194,0x6195,0x6196,0x6197,
+ 0x6198,0x6199,0x619a,0x619b,0x619c,0x619d,0x619e,0x619f,
+ 0x61a0,0x61a1,0x61a2,0x61a3,0x61a4,0x61a5,0x61a6,0x61a7,
+ 0x61a8,0x61a9,0x61aa,0x61ab,0x61ac,0x61ad,0x61ae,0x61af,
+ 0x61b0,0x61b1,0x61b2,0x61b3,0x61b4,0x61b5,0x61b6,0x61b7,
+ 0x61b8,0x61b9,0x61ba,0x61bb,0x61bc,0x61bd,0x61be,0x61bf,
+ 0x61c0,0x61c1,0x61c2,0x61c3,0x61c4,0x61c5,0x61c6,0x61c7,
+ 0x61c8,0x61c9,0x61ca,0x61cb,0x61cc,0x61cd,0x61ce,0x61cf,
+ 0x61d0,0x61d1,0x61d2,0x61d3,0x61d4,0x61d5,0x61d6,0x61d7,
+ 0x61d8,0x61d9,0x61da,0x61db,0x61dc,0x61dd,0x61de,0x61df,
+ 0x61e0,0x61e1,0x61e2,0x61e3,0x61e4,0x61e5,0x61e6,0x61e7,
+ 0x61e8,0x61e9,0x61ea,0x61eb,0x61ec,0x61ed,0x61ee,0x61ef,
+ 0x61f0,0x61f1,0x61f2,0x61f3,0x61f4,0x61f5,0x61f6,0x61f7,
+ 0x61f8,0x61f9,0x61fa,0x61fb,0x61fc,0x61fd,0x61fe,0x61ff,
+ 0x6200,0x6201,0x6202,0x6203,0x6204,0x6205,0x6206,0x6207,
+ 0x6208,0x6209,0x620a,0x620b,0x620c,0x620d,0x620e,0x620f,
+ 0x6210,0x6211,0x6212,0x6213,0x6214,0x6215,0x6216,0x6217,
+ 0x6218,0x6219,0x621a,0x621b,0x621c,0x621d,0x621e,0x621f,
+ 0x6220,0x6221,0x6222,0x6223,0x6224,0x6225,0x6226,0x6227,
+ 0x6228,0x6229,0x622a,0x622b,0x622c,0x622d,0x622e,0x622f,
+ 0x6230,0x6231,0x6232,0x6233,0x6234,0x6235,0x6236,0x6237,
+ 0x6238,0x6239,0x623a,0x623b,0x623c,0x623d,0x623e,0x623f,
+ 0x6240,0x6241,0x6242,0x6243,0x6244,0x6245,0x6246,0x6247,
+ 0x6248,0x6249,0x624a,0x624b,0x624c,0x624d,0x624e,0x624f,
+ 0x6250,0x6251,0x6252,0x6253,0x6254,0x6255,0x6256,0x6257,
+ 0x6258,0x6259,0x625a,0x625b,0x625c,0x625d,0x625e,0x625f,
+ 0x6260,0x6261,0x6262,0x6263,0x6264,0x6265,0x6266,0x6267,
+ 0x6268,0x6269,0x626a,0x626b,0x626c,0x626d,0x626e,0x626f,
+ 0x6270,0x6271,0x6272,0x6273,0x6274,0x6275,0x6276,0x6277,
+ 0x6278,0x6279,0x627a,0x627b,0x627c,0x627d,0x627e,0x627f,
+ 0x6280,0x6281,0x6282,0x6283,0x6284,0x6285,0x6286,0x6287,
+ 0x6288,0x6289,0x628a,0x628b,0x628c,0x628d,0x628e,0x628f,
+ 0x6290,0x6291,0x6292,0x6293,0x6294,0x6295,0x6296,0x6297,
+ 0x6298,0x6299,0x629a,0x629b,0x629c,0x629d,0x629e,0x629f,
+ 0x62a0,0x62a1,0x62a2,0x62a3,0x62a4,0x62a5,0x62a6,0x62a7,
+ 0x62a8,0x62a9,0x62aa,0x62ab,0x62ac,0x62ad,0x62ae,0x62af,
+ 0x62b0,0x62b1,0x62b2,0x62b3,0x62b4,0x62b5,0x62b6,0x62b7,
+ 0x62b8,0x62b9,0x62ba,0x62bb,0x62bc,0x62bd,0x62be,0x62bf,
+ 0x62c0,0x62c1,0x62c2,0x62c3,0x62c4,0x62c5,0x62c6,0x62c7,
+ 0x62c8,0x62c9,0x62ca,0x62cb,0x62cc,0x62cd,0x62ce,0x62cf,
+ 0x62d0,0x62d1,0x62d2,0x62d3,0x62d4,0x62d5,0x62d6,0x62d7,
+ 0x62d8,0x62d9,0x62da,0x62db,0x62dc,0x62dd,0x62de,0x62df,
+ 0x62e0,0x62e1,0x62e2,0x62e3,0x62e4,0x62e5,0x62e6,0x62e7,
+ 0x62e8,0x62e9,0x62ea,0x62eb,0x62ec,0x62ed,0x62ee,0x62ef,
+ 0x62f0,0x62f1,0x62f2,0x62f3,0x62f4,0x62f5,0x62f6,0x62f7,
+ 0x62f8,0x62f9,0x62fa,0x62fb,0x62fc,0x62fd,0x62fe,0x62ff,
+ 0x6300,0x6301,0x6302,0x6303,0x6304,0x6305,0x6306,0x6307,
+ 0x6308,0x6309,0x630a,0x630b,0x630c,0x630d,0x630e,0x630f,
+ 0x6310,0x6311,0x6312,0x6313,0x6314,0x6315,0x6316,0x6317,
+ 0x6318,0x6319,0x631a,0x631b,0x631c,0x631d,0x631e,0x631f,
+ 0x6320,0x6321,0x6322,0x6323,0x6324,0x6325,0x6326,0x6327,
+ 0x6328,0x6329,0x632a,0x632b,0x632c,0x632d,0x632e,0x632f,
+ 0x6330,0x6331,0x6332,0x6333,0x6334,0x6335,0x6336,0x6337,
+ 0x6338,0x6339,0x633a,0x633b,0x633c,0x633d,0x633e,0x633f,
+ 0x6340,0x6341,0x6342,0x6343,0x6344,0x6345,0x6346,0x6347,
+ 0x6348,0x6349,0x634a,0x634b,0x634c,0x634d,0x634e,0x634f,
+ 0x6350,0x6351,0x6352,0x6353,0x6354,0x6355,0x6356,0x6357,
+ 0x6358,0x6359,0x635a,0x635b,0x635c,0x635d,0x635e,0x635f,
+ 0x6360,0x6361,0x6362,0x6363,0x6364,0x6365,0x6366,0x6367,
+ 0x6368,0x6369,0x636a,0x636b,0x636c,0x636d,0x636e,0x636f,
+ 0x6370,0x6371,0x6372,0x6373,0x6374,0x6375,0x6376,0x6377,
+ 0x6378,0x6379,0x637a,0x637b,0x637c,0x637d,0x637e,0x637f,
+ 0x6380,0x6381,0x6382,0x6383,0x6384,0x6385,0x6386,0x6387,
+ 0x6388,0x6389,0x638a,0x638b,0x638c,0x638d,0x638e,0x638f,
+ 0x6390,0x6391,0x6392,0x6393,0x6394,0x6395,0x6396,0x6397,
+ 0x6398,0x6399,0x639a,0x639b,0x639c,0x639d,0x639e,0x639f,
+ 0x63a0,0x63a1,0x63a2,0x63a3,0x63a4,0x63a5,0x63a6,0x63a7,
+ 0x63a8,0x63a9,0x63aa,0x63ab,0x63ac,0x63ad,0x63ae,0x63af,
+ 0x63b0,0x63b1,0x63b2,0x63b3,0x63b4,0x63b5,0x63b6,0x63b7,
+ 0x63b8,0x63b9,0x63ba,0x63bb,0x63bc,0x63bd,0x63be,0x63bf,
+ 0x63c0,0x63c1,0x63c2,0x63c3,0x63c4,0x63c5,0x63c6,0x63c7,
+ 0x63c8,0x63c9,0x63ca,0x63cb,0x63cc,0x63cd,0x63ce,0x63cf,
+ 0x63d0,0x63d1,0x63d2,0x63d3,0x63d4,0x63d5,0x63d6,0x63d7,
+ 0x63d8,0x63d9,0x63da,0x63db,0x63dc,0x63dd,0x63de,0x63df,
+ 0x63e0,0x63e1,0x63e2,0x63e3,0x63e4,0x63e5,0x63e6,0x63e7,
+ 0x63e8,0x63e9,0x63ea,0x63eb,0x63ec,0x63ed,0x63ee,0x63ef,
+ 0x63f0,0x63f1,0x63f2,0x63f3,0x63f4,0x63f5,0x63f6,0x63f7,
+ 0x63f8,0x63f9,0x63fa,0x63fb,0x63fc,0x63fd,0x63fe,0x63ff,
+ 0x6400,0x6401,0x6402,0x6403,0x6404,0x6405,0x6406,0x6407,
+ 0x6408,0x6409,0x640a,0x640b,0x640c,0x640d,0x640e,0x640f,
+ 0x6410,0x6411,0x6412,0x6413,0x6414,0x6415,0x6416,0x6417,
+ 0x6418,0x6419,0x641a,0x641b,0x641c,0x641d,0x641e,0x641f,
+ 0x6420,0x6421,0x6422,0x6423,0x6424,0x6425,0x6426,0x6427,
+ 0x6428,0x6429,0x642a,0x642b,0x642c,0x642d,0x642e,0x642f,
+ 0x6430,0x6431,0x6432,0x6433,0x6434,0x6435,0x6436,0x6437,
+ 0x6438,0x6439,0x643a,0x643b,0x643c,0x643d,0x643e,0x643f,
+ 0x6440,0x6441,0x6442,0x6443,0x6444,0x6445,0x6446,0x6447,
+ 0x6448,0x6449,0x644a,0x644b,0x644c,0x644d,0x644e,0x644f,
+ 0x6450,0x6451,0x6452,0x6453,0x6454,0x6455,0x6456,0x6457,
+ 0x6458,0x6459,0x645a,0x645b,0x645c,0x645d,0x645e,0x645f,
+ 0x6460,0x6461,0x6462,0x6463,0x6464,0x6465,0x6466,0x6467,
+ 0x6468,0x6469,0x646a,0x646b,0x646c,0x646d,0x646e,0x646f,
+ 0x6470,0x6471,0x6472,0x6473,0x6474,0x6475,0x6476,0x6477,
+ 0x6478,0x6479,0x647a,0x647b,0x647c,0x647d,0x647e,0x647f,
+ 0x6480,0x6481,0x6482,0x6483,0x6484,0x6485,0x6486,0x6487,
+ 0x6488,0x6489,0x648a,0x648b,0x648c,0x648d,0x648e,0x648f,
+ 0x6490,0x6491,0x6492,0x6493,0x6494,0x6495,0x6496,0x6497,
+ 0x6498,0x6499,0x649a,0x649b,0x649c,0x649d,0x649e,0x649f,
+ 0x64a0,0x64a1,0x64a2,0x64a3,0x64a4,0x64a5,0x64a6,0x64a7,
+ 0x64a8,0x64a9,0x64aa,0x64ab,0x64ac,0x64ad,0x64ae,0x64af,
+ 0x64b0,0x64b1,0x64b2,0x64b3,0x64b4,0x64b5,0x64b6,0x64b7,
+ 0x64b8,0x64b9,0x64ba,0x64bb,0x64bc,0x64bd,0x64be,0x64bf,
+ 0x64c0,0x64c1,0x64c2,0x64c3,0x64c4,0x64c5,0x64c6,0x64c7,
+ 0x64c8,0x64c9,0x64ca,0x64cb,0x64cc,0x64cd,0x64ce,0x64cf,
+ 0x64d0,0x64d1,0x64d2,0x64d3,0x64d4,0x64d5,0x64d6,0x64d7,
+ 0x64d8,0x64d9,0x64da,0x64db,0x64dc,0x64dd,0x64de,0x64df,
+ 0x64e0,0x64e1,0x64e2,0x64e3,0x64e4,0x64e5,0x64e6,0x64e7,
+ 0x64e8,0x64e9,0x64ea,0x64eb,0x64ec,0x64ed,0x64ee,0x64ef,
+ 0x64f0,0x64f1,0x64f2,0x64f3,0x64f4,0x64f5,0x64f6,0x64f7,
+ 0x64f8,0x64f9,0x64fa,0x64fb,0x64fc,0x64fd,0x64fe,0x64ff,
+ 0x6500,0x6501,0x6502,0x6503,0x6504,0x6505,0x6506,0x6507,
+ 0x6508,0x6509,0x650a,0x650b,0x650c,0x650d,0x650e,0x650f,
+ 0x6510,0x6511,0x6512,0x6513,0x6514,0x6515,0x6516,0x6517,
+ 0x6518,0x6519,0x651a,0x651b,0x651c,0x651d,0x651e,0x651f,
+ 0x6520,0x6521,0x6522,0x6523,0x6524,0x6525,0x6526,0x6527,
+ 0x6528,0x6529,0x652a,0x652b,0x652c,0x652d,0x652e,0x652f,
+ 0x6530,0x6531,0x6532,0x6533,0x6534,0x6535,0x6536,0x6537,
+ 0x6538,0x6539,0x653a,0x653b,0x653c,0x653d,0x653e,0x653f,
+ 0x6540,0x6541,0x6542,0x6543,0x6544,0x6545,0x6546,0x6547,
+ 0x6548,0x6549,0x654a,0x654b,0x654c,0x654d,0x654e,0x654f,
+ 0x6550,0x6551,0x6552,0x6553,0x6554,0x6555,0x6556,0x6557,
+ 0x6558,0x6559,0x655a,0x655b,0x655c,0x655d,0x655e,0x655f,
+ 0x6560,0x6561,0x6562,0x6563,0x6564,0x6565,0x6566,0x6567,
+ 0x6568,0x6569,0x656a,0x656b,0x656c,0x656d,0x656e,0x656f,
+ 0x6570,0x6571,0x6572,0x6573,0x6574,0x6575,0x6576,0x6577,
+ 0x6578,0x6579,0x657a,0x657b,0x657c,0x657d,0x657e,0x657f,
+ 0x6580,0x6581,0x6582,0x6583,0x6584,0x6585,0x6586,0x6587,
+ 0x6588,0x6589,0x658a,0x658b,0x658c,0x658d,0x658e,0x658f,
+ 0x6590,0x6591,0x6592,0x6593,0x6594,0x6595,0x6596,0x6597,
+ 0x6598,0x6599,0x659a,0x659b,0x659c,0x659d,0x659e,0x659f,
+ 0x65a0,0x65a1,0x65a2,0x65a3,0x65a4,0x65a5,0x65a6,0x65a7,
+ 0x65a8,0x65a9,0x65aa,0x65ab,0x65ac,0x65ad,0x65ae,0x65af,
+ 0x65b0,0x65b1,0x65b2,0x65b3,0x65b4,0x65b5,0x65b6,0x65b7,
+ 0x65b8,0x65b9,0x65ba,0x65bb,0x65bc,0x65bd,0x65be,0x65bf,
+ 0x65c0,0x65c1,0x65c2,0x65c3,0x65c4,0x65c5,0x65c6,0x65c7,
+ 0x65c8,0x65c9,0x65ca,0x65cb,0x65cc,0x65cd,0x65ce,0x65cf,
+ 0x65d0,0x65d1,0x65d2,0x65d3,0x65d4,0x65d5,0x65d6,0x65d7,
+ 0x65d8,0x65d9,0x65da,0x65db,0x65dc,0x65dd,0x65de,0x65df,
+ 0x65e0,0x65e1,0x65e2,0x65e3,0x65e4,0x65e5,0x65e6,0x65e7,
+ 0x65e8,0x65e9,0x65ea,0x65eb,0x65ec,0x65ed,0x65ee,0x65ef,
+ 0x65f0,0x65f1,0x65f2,0x65f3,0x65f4,0x65f5,0x65f6,0x65f7,
+ 0x65f8,0x65f9,0x65fa,0x65fb,0x65fc,0x65fd,0x65fe,0x65ff,
+ 0x6600,0x6601,0x6602,0x6603,0x6604,0x6605,0x6606,0x6607,
+ 0x6608,0x6609,0x660a,0x660b,0x660c,0x660d,0x660e,0x660f,
+ 0x6610,0x6611,0x6612,0x6613,0x6614,0x6615,0x6616,0x6617,
+ 0x6618,0x6619,0x661a,0x661b,0x661c,0x661d,0x661e,0x661f,
+ 0x6620,0x6621,0x6622,0x6623,0x6624,0x6625,0x6626,0x6627,
+ 0x6628,0x6629,0x662a,0x662b,0x662c,0x662d,0x662e,0x662f,
+ 0x6630,0x6631,0x6632,0x6633,0x6634,0x6635,0x6636,0x6637,
+ 0x6638,0x6639,0x663a,0x663b,0x663c,0x663d,0x663e,0x663f,
+ 0x6640,0x6641,0x6642,0x6643,0x6644,0x6645,0x6646,0x6647,
+ 0x6648,0x6649,0x664a,0x664b,0x664c,0x664d,0x664e,0x664f,
+ 0x6650,0x6651,0x6652,0x6653,0x6654,0x6655,0x6656,0x6657,
+ 0x6658,0x6659,0x665a,0x665b,0x665c,0x665d,0x665e,0x665f,
+ 0x6660,0x6661,0x6662,0x6663,0x6664,0x6665,0x6666,0x6667,
+ 0x6668,0x6669,0x666a,0x666b,0x666c,0x666d,0x666e,0x666f,
+ 0x6670,0x6671,0x6672,0x6673,0x6674,0x6675,0x6676,0x6677,
+ 0x6678,0x6679,0x667a,0x667b,0x667c,0x667d,0x667e,0x667f,
+ 0x6680,0x6681,0x6682,0x6683,0x6684,0x6685,0x6686,0x6687,
+ 0x6688,0x6689,0x668a,0x668b,0x668c,0x668d,0x668e,0x668f,
+ 0x6690,0x6691,0x6692,0x6693,0x6694,0x6695,0x6696,0x6697,
+ 0x6698,0x6699,0x669a,0x669b,0x669c,0x669d,0x669e,0x669f,
+ 0x66a0,0x66a1,0x66a2,0x66a3,0x66a4,0x66a5,0x66a6,0x66a7,
+ 0x66a8,0x66a9,0x66aa,0x66ab,0x66ac,0x66ad,0x66ae,0x66af,
+ 0x66b0,0x66b1,0x66b2,0x66b3,0x66b4,0x66b5,0x66b6,0x66b7,
+ 0x66b8,0x66b9,0x66ba,0x66bb,0x66bc,0x66bd,0x66be,0x66bf,
+ 0x66c0,0x66c1,0x66c2,0x66c3,0x66c4,0x66c5,0x66c6,0x66c7,
+ 0x66c8,0x66c9,0x66ca,0x66cb,0x66cc,0x66cd,0x66ce,0x66cf,
+ 0x66d0,0x66d1,0x66d2,0x66d3,0x66d4,0x66d5,0x66d6,0x66d7,
+ 0x66d8,0x66d9,0x66da,0x66db,0x66dc,0x66dd,0x66de,0x66df,
+ 0x66e0,0x66e1,0x66e2,0x66e3,0x66e4,0x66e5,0x66e6,0x66e7,
+ 0x66e8,0x66e9,0x66ea,0x66eb,0x66ec,0x66ed,0x66ee,0x66ef,
+ 0x66f0,0x66f1,0x66f2,0x66f3,0x66f4,0x66f5,0x66f6,0x66f7,
+ 0x66f8,0x66f9,0x66fa,0x66fb,0x66fc,0x66fd,0x66fe,0x66ff,
+ 0x6700,0x6701,0x6702,0x6703,0x6704,0x6705,0x6706,0x6707,
+ 0x6708,0x6709,0x670a,0x670b,0x670c,0x670d,0x670e,0x670f,
+ 0x6710,0x6711,0x6712,0x6713,0x6714,0x6715,0x6716,0x6717,
+ 0x6718,0x6719,0x671a,0x671b,0x671c,0x671d,0x671e,0x671f,
+ 0x6720,0x6721,0x6722,0x6723,0x6724,0x6725,0x6726,0x6727,
+ 0x6728,0x6729,0x672a,0x672b,0x672c,0x672d,0x672e,0x672f,
+ 0x6730,0x6731,0x6732,0x6733,0x6734,0x6735,0x6736,0x6737,
+ 0x6738,0x6739,0x673a,0x673b,0x673c,0x673d,0x673e,0x673f,
+ 0x6740,0x6741,0x6742,0x6743,0x6744,0x6745,0x6746,0x6747,
+ 0x6748,0x6749,0x674a,0x674b,0x674c,0x674d,0x674e,0x674f,
+ 0x6750,0x6751,0x6752,0x6753,0x6754,0x6755,0x6756,0x6757,
+ 0x6758,0x6759,0x675a,0x675b,0x675c,0x675d,0x675e,0x675f,
+ 0x6760,0x6761,0x6762,0x6763,0x6764,0x6765,0x6766,0x6767,
+ 0x6768,0x6769,0x676a,0x676b,0x676c,0x676d,0x676e,0x676f,
+ 0x6770,0x6771,0x6772,0x6773,0x6774,0x6775,0x6776,0x6777,
+ 0x6778,0x6779,0x677a,0x677b,0x677c,0x677d,0x677e,0x677f,
+ 0x6780,0x6781,0x6782,0x6783,0x6784,0x6785,0x6786,0x6787,
+ 0x6788,0x6789,0x678a,0x678b,0x678c,0x678d,0x678e,0x678f,
+ 0x6790,0x6791,0x6792,0x6793,0x6794,0x6795,0x6796,0x6797,
+ 0x6798,0x6799,0x679a,0x679b,0x679c,0x679d,0x679e,0x679f,
+ 0x67a0,0x67a1,0x67a2,0x67a3,0x67a4,0x67a5,0x67a6,0x67a7,
+ 0x67a8,0x67a9,0x67aa,0x67ab,0x67ac,0x67ad,0x67ae,0x67af,
+ 0x67b0,0x67b1,0x67b2,0x67b3,0x67b4,0x67b5,0x67b6,0x67b7,
+ 0x67b8,0x67b9,0x67ba,0x67bb,0x67bc,0x67bd,0x67be,0x67bf,
+ 0x67c0,0x67c1,0x67c2,0x67c3,0x67c4,0x67c5,0x67c6,0x67c7,
+ 0x67c8,0x67c9,0x67ca,0x67cb,0x67cc,0x67cd,0x67ce,0x67cf,
+ 0x67d0,0x67d1,0x67d2,0x67d3,0x67d4,0x67d5,0x67d6,0x67d7,
+ 0x67d8,0x67d9,0x67da,0x67db,0x67dc,0x67dd,0x67de,0x67df,
+ 0x67e0,0x67e1,0x67e2,0x67e3,0x67e4,0x67e5,0x67e6,0x67e7,
+ 0x67e8,0x67e9,0x67ea,0x67eb,0x67ec,0x67ed,0x67ee,0x67ef,
+ 0x67f0,0x67f1,0x67f2,0x67f3,0x67f4,0x67f5,0x67f6,0x67f7,
+ 0x67f8,0x67f9,0x67fa,0x67fb,0x67fc,0x67fd,0x67fe,0x67ff,
+ 0x6800,0x6801,0x6802,0x6803,0x6804,0x6805,0x6806,0x6807,
+ 0x6808,0x6809,0x680a,0x680b,0x680c,0x680d,0x680e,0x680f,
+ 0x6810,0x6811,0x6812,0x6813,0x6814,0x6815,0x6816,0x6817,
+ 0x6818,0x6819,0x681a,0x681b,0x681c,0x681d,0x681e,0x681f,
+ 0x6820,0x6821,0x6822,0x6823,0x6824,0x6825,0x6826,0x6827,
+ 0x6828,0x6829,0x682a,0x682b,0x682c,0x682d,0x682e,0x682f,
+ 0x6830,0x6831,0x6832,0x6833,0x6834,0x6835,0x6836,0x6837,
+ 0x6838,0x6839,0x683a,0x683b,0x683c,0x683d,0x683e,0x683f,
+ 0x6840,0x6841,0x6842,0x6843,0x6844,0x6845,0x6846,0x6847,
+ 0x6848,0x6849,0x684a,0x684b,0x684c,0x684d,0x684e,0x684f,
+ 0x6850,0x6851,0x6852,0x6853,0x6854,0x6855,0x6856,0x6857,
+ 0x6858,0x6859,0x685a,0x685b,0x685c,0x685d,0x685e,0x685f,
+ 0x6860,0x6861,0x6862,0x6863,0x6864,0x6865,0x6866,0x6867,
+ 0x6868,0x6869,0x686a,0x686b,0x686c,0x686d,0x686e,0x686f,
+ 0x6870,0x6871,0x6872,0x6873,0x6874,0x6875,0x6876,0x6877,
+ 0x6878,0x6879,0x687a,0x687b,0x687c,0x687d,0x687e,0x687f,
+ 0x6880,0x6881,0x6882,0x6883,0x6884,0x6885,0x6886,0x6887,
+ 0x6888,0x6889,0x688a,0x688b,0x688c,0x688d,0x688e,0x688f,
+ 0x6890,0x6891,0x6892,0x6893,0x6894,0x6895,0x6896,0x6897,
+ 0x6898,0x6899,0x689a,0x689b,0x689c,0x689d,0x689e,0x689f,
+ 0x68a0,0x68a1,0x68a2,0x68a3,0x68a4,0x68a5,0x68a6,0x68a7,
+ 0x68a8,0x68a9,0x68aa,0x68ab,0x68ac,0x68ad,0x68ae,0x68af,
+ 0x68b0,0x68b1,0x68b2,0x68b3,0x68b4,0x68b5,0x68b6,0x68b7,
+ 0x68b8,0x68b9,0x68ba,0x68bb,0x68bc,0x68bd,0x68be,0x68bf,
+ 0x68c0,0x68c1,0x68c2,0x68c3,0x68c4,0x68c5,0x68c6,0x68c7,
+ 0x68c8,0x68c9,0x68ca,0x68cb,0x68cc,0x68cd,0x68ce,0x68cf,
+ 0x68d0,0x68d1,0x68d2,0x68d3,0x68d4,0x68d5,0x68d6,0x68d7,
+ 0x68d8,0x68d9,0x68da,0x68db,0x68dc,0x68dd,0x68de,0x68df,
+ 0x68e0,0x68e1,0x68e2,0x68e3,0x68e4,0x68e5,0x68e6,0x68e7,
+ 0x68e8,0x68e9,0x68ea,0x68eb,0x68ec,0x68ed,0x68ee,0x68ef,
+ 0x68f0,0x68f1,0x68f2,0x68f3,0x68f4,0x68f5,0x68f6,0x68f7,
+ 0x68f8,0x68f9,0x68fa,0x68fb,0x68fc,0x68fd,0x68fe,0x68ff,
+ 0x6900,0x6901,0x6902,0x6903,0x6904,0x6905,0x6906,0x6907,
+ 0x6908,0x6909,0x690a,0x690b,0x690c,0x690d,0x690e,0x690f,
+ 0x6910,0x6911,0x6912,0x6913,0x6914,0x6915,0x6916,0x6917,
+ 0x6918,0x6919,0x691a,0x691b,0x691c,0x691d,0x691e,0x691f,
+ 0x6920,0x6921,0x6922,0x6923,0x6924,0x6925,0x6926,0x6927,
+ 0x6928,0x6929,0x692a,0x692b,0x692c,0x692d,0x692e,0x692f,
+ 0x6930,0x6931,0x6932,0x6933,0x6934,0x6935,0x6936,0x6937,
+ 0x6938,0x6939,0x693a,0x693b,0x693c,0x693d,0x693e,0x693f,
+ 0x6940,0x6941,0x6942,0x6943,0x6944,0x6945,0x6946,0x6947,
+ 0x6948,0x6949,0x694a,0x694b,0x694c,0x694d,0x694e,0x694f,
+ 0x6950,0x6951,0x6952,0x6953,0x6954,0x6955,0x6956,0x6957,
+ 0x6958,0x6959,0x695a,0x695b,0x695c,0x695d,0x695e,0x695f,
+ 0x6960,0x6961,0x6962,0x6963,0x6964,0x6965,0x6966,0x6967,
+ 0x6968,0x6969,0x696a,0x696b,0x696c,0x696d,0x696e,0x696f,
+ 0x6970,0x6971,0x6972,0x6973,0x6974,0x6975,0x6976,0x6977,
+ 0x6978,0x6979,0x697a,0x697b,0x697c,0x697d,0x697e,0x697f,
+ 0x6980,0x6981,0x6982,0x6983,0x6984,0x6985,0x6986,0x6987,
+ 0x6988,0x6989,0x698a,0x698b,0x698c,0x698d,0x698e,0x698f,
+ 0x6990,0x6991,0x6992,0x6993,0x6994,0x6995,0x6996,0x6997,
+ 0x6998,0x6999,0x699a,0x699b,0x699c,0x699d,0x699e,0x699f,
+ 0x69a0,0x69a1,0x69a2,0x69a3,0x69a4,0x69a5,0x69a6,0x69a7,
+ 0x69a8,0x69a9,0x69aa,0x69ab,0x69ac,0x69ad,0x69ae,0x69af,
+ 0x69b0,0x69b1,0x69b2,0x69b3,0x69b4,0x69b5,0x69b6,0x69b7,
+ 0x69b8,0x69b9,0x69ba,0x69bb,0x69bc,0x69bd,0x69be,0x69bf,
+ 0x69c0,0x69c1,0x69c2,0x69c3,0x69c4,0x69c5,0x69c6,0x69c7,
+ 0x69c8,0x69c9,0x69ca,0x69cb,0x69cc,0x69cd,0x69ce,0x69cf,
+ 0x69d0,0x69d1,0x69d2,0x69d3,0x69d4,0x69d5,0x69d6,0x69d7,
+ 0x69d8,0x69d9,0x69da,0x69db,0x69dc,0x69dd,0x69de,0x69df,
+ 0x69e0,0x69e1,0x69e2,0x69e3,0x69e4,0x69e5,0x69e6,0x69e7,
+ 0x69e8,0x69e9,0x69ea,0x69eb,0x69ec,0x69ed,0x69ee,0x69ef,
+ 0x69f0,0x69f1,0x69f2,0x69f3,0x69f4,0x69f5,0x69f6,0x69f7,
+ 0x69f8,0x69f9,0x69fa,0x69fb,0x69fc,0x69fd,0x69fe,0x69ff,
+ 0x6a00,0x6a01,0x6a02,0x6a03,0x6a04,0x6a05,0x6a06,0x6a07,
+ 0x6a08,0x6a09,0x6a0a,0x6a0b,0x6a0c,0x6a0d,0x6a0e,0x6a0f,
+ 0x6a10,0x6a11,0x6a12,0x6a13,0x6a14,0x6a15,0x6a16,0x6a17,
+ 0x6a18,0x6a19,0x6a1a,0x6a1b,0x6a1c,0x6a1d,0x6a1e,0x6a1f,
+ 0x6a20,0x6a21,0x6a22,0x6a23,0x6a24,0x6a25,0x6a26,0x6a27,
+ 0x6a28,0x6a29,0x6a2a,0x6a2b,0x6a2c,0x6a2d,0x6a2e,0x6a2f,
+ 0x6a30,0x6a31,0x6a32,0x6a33,0x6a34,0x6a35,0x6a36,0x6a37,
+ 0x6a38,0x6a39,0x6a3a,0x6a3b,0x6a3c,0x6a3d,0x6a3e,0x6a3f,
+ 0x6a40,0x6a41,0x6a42,0x6a43,0x6a44,0x6a45,0x6a46,0x6a47,
+ 0x6a48,0x6a49,0x6a4a,0x6a4b,0x6a4c,0x6a4d,0x6a4e,0x6a4f,
+ 0x6a50,0x6a51,0x6a52,0x6a53,0x6a54,0x6a55,0x6a56,0x6a57,
+ 0x6a58,0x6a59,0x6a5a,0x6a5b,0x6a5c,0x6a5d,0x6a5e,0x6a5f,
+ 0x6a60,0x6a61,0x6a62,0x6a63,0x6a64,0x6a65,0x6a66,0x6a67,
+ 0x6a68,0x6a69,0x6a6a,0x6a6b,0x6a6c,0x6a6d,0x6a6e,0x6a6f,
+ 0x6a70,0x6a71,0x6a72,0x6a73,0x6a74,0x6a75,0x6a76,0x6a77,
+ 0x6a78,0x6a79,0x6a7a,0x6a7b,0x6a7c,0x6a7d,0x6a7e,0x6a7f,
+ 0x6a80,0x6a81,0x6a82,0x6a83,0x6a84,0x6a85,0x6a86,0x6a87,
+ 0x6a88,0x6a89,0x6a8a,0x6a8b,0x6a8c,0x6a8d,0x6a8e,0x6a8f,
+ 0x6a90,0x6a91,0x6a92,0x6a93,0x6a94,0x6a95,0x6a96,0x6a97,
+ 0x6a98,0x6a99,0x6a9a,0x6a9b,0x6a9c,0x6a9d,0x6a9e,0x6a9f,
+ 0x6aa0,0x6aa1,0x6aa2,0x6aa3,0x6aa4,0x6aa5,0x6aa6,0x6aa7,
+ 0x6aa8,0x6aa9,0x6aaa,0x6aab,0x6aac,0x6aad,0x6aae,0x6aaf,
+ 0x6ab0,0x6ab1,0x6ab2,0x6ab3,0x6ab4,0x6ab5,0x6ab6,0x6ab7,
+ 0x6ab8,0x6ab9,0x6aba,0x6abb,0x6abc,0x6abd,0x6abe,0x6abf,
+ 0x6ac0,0x6ac1,0x6ac2,0x6ac3,0x6ac4,0x6ac5,0x6ac6,0x6ac7,
+ 0x6ac8,0x6ac9,0x6aca,0x6acb,0x6acc,0x6acd,0x6ace,0x6acf,
+ 0x6ad0,0x6ad1,0x6ad2,0x6ad3,0x6ad4,0x6ad5,0x6ad6,0x6ad7,
+ 0x6ad8,0x6ad9,0x6ada,0x6adb,0x6adc,0x6add,0x6ade,0x6adf,
+ 0x6ae0,0x6ae1,0x6ae2,0x6ae3,0x6ae4,0x6ae5,0x6ae6,0x6ae7,
+ 0x6ae8,0x6ae9,0x6aea,0x6aeb,0x6aec,0x6aed,0x6aee,0x6aef,
+ 0x6af0,0x6af1,0x6af2,0x6af3,0x6af4,0x6af5,0x6af6,0x6af7,
+ 0x6af8,0x6af9,0x6afa,0x6afb,0x6afc,0x6afd,0x6afe,0x6aff,
+ 0x6b00,0x6b01,0x6b02,0x6b03,0x6b04,0x6b05,0x6b06,0x6b07,
+ 0x6b08,0x6b09,0x6b0a,0x6b0b,0x6b0c,0x6b0d,0x6b0e,0x6b0f,
+ 0x6b10,0x6b11,0x6b12,0x6b13,0x6b14,0x6b15,0x6b16,0x6b17,
+ 0x6b18,0x6b19,0x6b1a,0x6b1b,0x6b1c,0x6b1d,0x6b1e,0x6b1f,
+ 0x6b20,0x6b21,0x6b22,0x6b23,0x6b24,0x6b25,0x6b26,0x6b27,
+ 0x6b28,0x6b29,0x6b2a,0x6b2b,0x6b2c,0x6b2d,0x6b2e,0x6b2f,
+ 0x6b30,0x6b31,0x6b32,0x6b33,0x6b34,0x6b35,0x6b36,0x6b37,
+ 0x6b38,0x6b39,0x6b3a,0x6b3b,0x6b3c,0x6b3d,0x6b3e,0x6b3f,
+ 0x6b40,0x6b41,0x6b42,0x6b43,0x6b44,0x6b45,0x6b46,0x6b47,
+ 0x6b48,0x6b49,0x6b4a,0x6b4b,0x6b4c,0x6b4d,0x6b4e,0x6b4f,
+ 0x6b50,0x6b51,0x6b52,0x6b53,0x6b54,0x6b55,0x6b56,0x6b57,
+ 0x6b58,0x6b59,0x6b5a,0x6b5b,0x6b5c,0x6b5d,0x6b5e,0x6b5f,
+ 0x6b60,0x6b61,0x6b62,0x6b63,0x6b64,0x6b65,0x6b66,0x6b67,
+ 0x6b68,0x6b69,0x6b6a,0x6b6b,0x6b6c,0x6b6d,0x6b6e,0x6b6f,
+ 0x6b70,0x6b71,0x6b72,0x6b73,0x6b74,0x6b75,0x6b76,0x6b77,
+ 0x6b78,0x6b79,0x6b7a,0x6b7b,0x6b7c,0x6b7d,0x6b7e,0x6b7f,
+ 0x6b80,0x6b81,0x6b82,0x6b83,0x6b84,0x6b85,0x6b86,0x6b87,
+ 0x6b88,0x6b89,0x6b8a,0x6b8b,0x6b8c,0x6b8d,0x6b8e,0x6b8f,
+ 0x6b90,0x6b91,0x6b92,0x6b93,0x6b94,0x6b95,0x6b96,0x6b97,
+ 0x6b98,0x6b99,0x6b9a,0x6b9b,0x6b9c,0x6b9d,0x6b9e,0x6b9f,
+ 0x6ba0,0x6ba1,0x6ba2,0x6ba3,0x6ba4,0x6ba5,0x6ba6,0x6ba7,
+ 0x6ba8,0x6ba9,0x6baa,0x6bab,0x6bac,0x6bad,0x6bae,0x6baf,
+ 0x6bb0,0x6bb1,0x6bb2,0x6bb3,0x6bb4,0x6bb5,0x6bb6,0x6bb7,
+ 0x6bb8,0x6bb9,0x6bba,0x6bbb,0x6bbc,0x6bbd,0x6bbe,0x6bbf,
+ 0x6bc0,0x6bc1,0x6bc2,0x6bc3,0x6bc4,0x6bc5,0x6bc6,0x6bc7,
+ 0x6bc8,0x6bc9,0x6bca,0x6bcb,0x6bcc,0x6bcd,0x6bce,0x6bcf,
+ 0x6bd0,0x6bd1,0x6bd2,0x6bd3,0x6bd4,0x6bd5,0x6bd6,0x6bd7,
+ 0x6bd8,0x6bd9,0x6bda,0x6bdb,0x6bdc,0x6bdd,0x6bde,0x6bdf,
+ 0x6be0,0x6be1,0x6be2,0x6be3,0x6be4,0x6be5,0x6be6,0x6be7,
+ 0x6be8,0x6be9,0x6bea,0x6beb,0x6bec,0x6bed,0x6bee,0x6bef,
+ 0x6bf0,0x6bf1,0x6bf2,0x6bf3,0x6bf4,0x6bf5,0x6bf6,0x6bf7,
+ 0x6bf8,0x6bf9,0x6bfa,0x6bfb,0x6bfc,0x6bfd,0x6bfe,0x6bff,
+ 0x6c00,0x6c01,0x6c02,0x6c03,0x6c04,0x6c05,0x6c06,0x6c07,
+ 0x6c08,0x6c09,0x6c0a,0x6c0b,0x6c0c,0x6c0d,0x6c0e,0x6c0f,
+ 0x6c10,0x6c11,0x6c12,0x6c13,0x6c14,0x6c15,0x6c16,0x6c17,
+ 0x6c18,0x6c19,0x6c1a,0x6c1b,0x6c1c,0x6c1d,0x6c1e,0x6c1f,
+ 0x6c20,0x6c21,0x6c22,0x6c23,0x6c24,0x6c25,0x6c26,0x6c27,
+ 0x6c28,0x6c29,0x6c2a,0x6c2b,0x6c2c,0x6c2d,0x6c2e,0x6c2f,
+ 0x6c30,0x6c31,0x6c32,0x6c33,0x6c34,0x6c35,0x6c36,0x6c37,
+ 0x6c38,0x6c39,0x6c3a,0x6c3b,0x6c3c,0x6c3d,0x6c3e,0x6c3f,
+ 0x6c40,0x6c41,0x6c42,0x6c43,0x6c44,0x6c45,0x6c46,0x6c47,
+ 0x6c48,0x6c49,0x6c4a,0x6c4b,0x6c4c,0x6c4d,0x6c4e,0x6c4f,
+ 0x6c50,0x6c51,0x6c52,0x6c53,0x6c54,0x6c55,0x6c56,0x6c57,
+ 0x6c58,0x6c59,0x6c5a,0x6c5b,0x6c5c,0x6c5d,0x6c5e,0x6c5f,
+ 0x6c60,0x6c61,0x6c62,0x6c63,0x6c64,0x6c65,0x6c66,0x6c67,
+ 0x6c68,0x6c69,0x6c6a,0x6c6b,0x6c6c,0x6c6d,0x6c6e,0x6c6f,
+ 0x6c70,0x6c71,0x6c72,0x6c73,0x6c74,0x6c75,0x6c76,0x6c77,
+ 0x6c78,0x6c79,0x6c7a,0x6c7b,0x6c7c,0x6c7d,0x6c7e,0x6c7f,
+ 0x6c80,0x6c81,0x6c82,0x6c83,0x6c84,0x6c85,0x6c86,0x6c87,
+ 0x6c88,0x6c89,0x6c8a,0x6c8b,0x6c8c,0x6c8d,0x6c8e,0x6c8f,
+ 0x6c90,0x6c91,0x6c92,0x6c93,0x6c94,0x6c95,0x6c96,0x6c97,
+ 0x6c98,0x6c99,0x6c9a,0x6c9b,0x6c9c,0x6c9d,0x6c9e,0x6c9f,
+ 0x6ca0,0x6ca1,0x6ca2,0x6ca3,0x6ca4,0x6ca5,0x6ca6,0x6ca7,
+ 0x6ca8,0x6ca9,0x6caa,0x6cab,0x6cac,0x6cad,0x6cae,0x6caf,
+ 0x6cb0,0x6cb1,0x6cb2,0x6cb3,0x6cb4,0x6cb5,0x6cb6,0x6cb7,
+ 0x6cb8,0x6cb9,0x6cba,0x6cbb,0x6cbc,0x6cbd,0x6cbe,0x6cbf,
+ 0x6cc0,0x6cc1,0x6cc2,0x6cc3,0x6cc4,0x6cc5,0x6cc6,0x6cc7,
+ 0x6cc8,0x6cc9,0x6cca,0x6ccb,0x6ccc,0x6ccd,0x6cce,0x6ccf,
+ 0x6cd0,0x6cd1,0x6cd2,0x6cd3,0x6cd4,0x6cd5,0x6cd6,0x6cd7,
+ 0x6cd8,0x6cd9,0x6cda,0x6cdb,0x6cdc,0x6cdd,0x6cde,0x6cdf,
+ 0x6ce0,0x6ce1,0x6ce2,0x6ce3,0x6ce4,0x6ce5,0x6ce6,0x6ce7,
+ 0x6ce8,0x6ce9,0x6cea,0x6ceb,0x6cec,0x6ced,0x6cee,0x6cef,
+ 0x6cf0,0x6cf1,0x6cf2,0x6cf3,0x6cf4,0x6cf5,0x6cf6,0x6cf7,
+ 0x6cf8,0x6cf9,0x6cfa,0x6cfb,0x6cfc,0x6cfd,0x6cfe,0x6cff,
+ 0x6d00,0x6d01,0x6d02,0x6d03,0x6d04,0x6d05,0x6d06,0x6d07,
+ 0x6d08,0x6d09,0x6d0a,0x6d0b,0x6d0c,0x6d0d,0x6d0e,0x6d0f,
+ 0x6d10,0x6d11,0x6d12,0x6d13,0x6d14,0x6d15,0x6d16,0x6d17,
+ 0x6d18,0x6d19,0x6d1a,0x6d1b,0x6d1c,0x6d1d,0x6d1e,0x6d1f,
+ 0x6d20,0x6d21,0x6d22,0x6d23,0x6d24,0x6d25,0x6d26,0x6d27,
+ 0x6d28,0x6d29,0x6d2a,0x6d2b,0x6d2c,0x6d2d,0x6d2e,0x6d2f,
+ 0x6d30,0x6d31,0x6d32,0x6d33,0x6d34,0x6d35,0x6d36,0x6d37,
+ 0x6d38,0x6d39,0x6d3a,0x6d3b,0x6d3c,0x6d3d,0x6d3e,0x6d3f,
+ 0x6d40,0x6d41,0x6d42,0x6d43,0x6d44,0x6d45,0x6d46,0x6d47,
+ 0x6d48,0x6d49,0x6d4a,0x6d4b,0x6d4c,0x6d4d,0x6d4e,0x6d4f,
+ 0x6d50,0x6d51,0x6d52,0x6d53,0x6d54,0x6d55,0x6d56,0x6d57,
+ 0x6d58,0x6d59,0x6d5a,0x6d5b,0x6d5c,0x6d5d,0x6d5e,0x6d5f,
+ 0x6d60,0x6d61,0x6d62,0x6d63,0x6d64,0x6d65,0x6d66,0x6d67,
+ 0x6d68,0x6d69,0x6d6a,0x6d6b,0x6d6c,0x6d6d,0x6d6e,0x6d6f,
+ 0x6d70,0x6d71,0x6d72,0x6d73,0x6d74,0x6d75,0x6d76,0x6d77,
+ 0x6d78,0x6d79,0x6d7a,0x6d7b,0x6d7c,0x6d7d,0x6d7e,0x6d7f,
+ 0x6d80,0x6d81,0x6d82,0x6d83,0x6d84,0x6d85,0x6d86,0x6d87,
+ 0x6d88,0x6d89,0x6d8a,0x6d8b,0x6d8c,0x6d8d,0x6d8e,0x6d8f,
+ 0x6d90,0x6d91,0x6d92,0x6d93,0x6d94,0x6d95,0x6d96,0x6d97,
+ 0x6d98,0x6d99,0x6d9a,0x6d9b,0x6d9c,0x6d9d,0x6d9e,0x6d9f,
+ 0x6da0,0x6da1,0x6da2,0x6da3,0x6da4,0x6da5,0x6da6,0x6da7,
+ 0x6da8,0x6da9,0x6daa,0x6dab,0x6dac,0x6dad,0x6dae,0x6daf,
+ 0x6db0,0x6db1,0x6db2,0x6db3,0x6db4,0x6db5,0x6db6,0x6db7,
+ 0x6db8,0x6db9,0x6dba,0x6dbb,0x6dbc,0x6dbd,0x6dbe,0x6dbf,
+ 0x6dc0,0x6dc1,0x6dc2,0x6dc3,0x6dc4,0x6dc5,0x6dc6,0x6dc7,
+ 0x6dc8,0x6dc9,0x6dca,0x6dcb,0x6dcc,0x6dcd,0x6dce,0x6dcf,
+ 0x6dd0,0x6dd1,0x6dd2,0x6dd3,0x6dd4,0x6dd5,0x6dd6,0x6dd7,
+ 0x6dd8,0x6dd9,0x6dda,0x6ddb,0x6ddc,0x6ddd,0x6dde,0x6ddf,
+ 0x6de0,0x6de1,0x6de2,0x6de3,0x6de4,0x6de5,0x6de6,0x6de7,
+ 0x6de8,0x6de9,0x6dea,0x6deb,0x6dec,0x6ded,0x6dee,0x6def,
+ 0x6df0,0x6df1,0x6df2,0x6df3,0x6df4,0x6df5,0x6df6,0x6df7,
+ 0x6df8,0x6df9,0x6dfa,0x6dfb,0x6dfc,0x6dfd,0x6dfe,0x6dff,
+ 0x6e00,0x6e01,0x6e02,0x6e03,0x6e04,0x6e05,0x6e06,0x6e07,
+ 0x6e08,0x6e09,0x6e0a,0x6e0b,0x6e0c,0x6e0d,0x6e0e,0x6e0f,
+ 0x6e10,0x6e11,0x6e12,0x6e13,0x6e14,0x6e15,0x6e16,0x6e17,
+ 0x6e18,0x6e19,0x6e1a,0x6e1b,0x6e1c,0x6e1d,0x6e1e,0x6e1f,
+ 0x6e20,0x6e21,0x6e22,0x6e23,0x6e24,0x6e25,0x6e26,0x6e27,
+ 0x6e28,0x6e29,0x6e2a,0x6e2b,0x6e2c,0x6e2d,0x6e2e,0x6e2f,
+ 0x6e30,0x6e31,0x6e32,0x6e33,0x6e34,0x6e35,0x6e36,0x6e37,
+ 0x6e38,0x6e39,0x6e3a,0x6e3b,0x6e3c,0x6e3d,0x6e3e,0x6e3f,
+ 0x6e40,0x6e41,0x6e42,0x6e43,0x6e44,0x6e45,0x6e46,0x6e47,
+ 0x6e48,0x6e49,0x6e4a,0x6e4b,0x6e4c,0x6e4d,0x6e4e,0x6e4f,
+ 0x6e50,0x6e51,0x6e52,0x6e53,0x6e54,0x6e55,0x6e56,0x6e57,
+ 0x6e58,0x6e59,0x6e5a,0x6e5b,0x6e5c,0x6e5d,0x6e5e,0x6e5f,
+ 0x6e60,0x6e61,0x6e62,0x6e63,0x6e64,0x6e65,0x6e66,0x6e67,
+ 0x6e68,0x6e69,0x6e6a,0x6e6b,0x6e6c,0x6e6d,0x6e6e,0x6e6f,
+ 0x6e70,0x6e71,0x6e72,0x6e73,0x6e74,0x6e75,0x6e76,0x6e77,
+ 0x6e78,0x6e79,0x6e7a,0x6e7b,0x6e7c,0x6e7d,0x6e7e,0x6e7f,
+ 0x6e80,0x6e81,0x6e82,0x6e83,0x6e84,0x6e85,0x6e86,0x6e87,
+ 0x6e88,0x6e89,0x6e8a,0x6e8b,0x6e8c,0x6e8d,0x6e8e,0x6e8f,
+ 0x6e90,0x6e91,0x6e92,0x6e93,0x6e94,0x6e95,0x6e96,0x6e97,
+ 0x6e98,0x6e99,0x6e9a,0x6e9b,0x6e9c,0x6e9d,0x6e9e,0x6e9f,
+ 0x6ea0,0x6ea1,0x6ea2,0x6ea3,0x6ea4,0x6ea5,0x6ea6,0x6ea7,
+ 0x6ea8,0x6ea9,0x6eaa,0x6eab,0x6eac,0x6ead,0x6eae,0x6eaf,
+ 0x6eb0,0x6eb1,0x6eb2,0x6eb3,0x6eb4,0x6eb5,0x6eb6,0x6eb7,
+ 0x6eb8,0x6eb9,0x6eba,0x6ebb,0x6ebc,0x6ebd,0x6ebe,0x6ebf,
+ 0x6ec0,0x6ec1,0x6ec2,0x6ec3,0x6ec4,0x6ec5,0x6ec6,0x6ec7,
+ 0x6ec8,0x6ec9,0x6eca,0x6ecb,0x6ecc,0x6ecd,0x6ece,0x6ecf,
+ 0x6ed0,0x6ed1,0x6ed2,0x6ed3,0x6ed4,0x6ed5,0x6ed6,0x6ed7,
+ 0x6ed8,0x6ed9,0x6eda,0x6edb,0x6edc,0x6edd,0x6ede,0x6edf,
+ 0x6ee0,0x6ee1,0x6ee2,0x6ee3,0x6ee4,0x6ee5,0x6ee6,0x6ee7,
+ 0x6ee8,0x6ee9,0x6eea,0x6eeb,0x6eec,0x6eed,0x6eee,0x6eef,
+ 0x6ef0,0x6ef1,0x6ef2,0x6ef3,0x6ef4,0x6ef5,0x6ef6,0x6ef7,
+ 0x6ef8,0x6ef9,0x6efa,0x6efb,0x6efc,0x6efd,0x6efe,0x6eff,
+ 0x6f00,0x6f01,0x6f02,0x6f03,0x6f04,0x6f05,0x6f06,0x6f07,
+ 0x6f08,0x6f09,0x6f0a,0x6f0b,0x6f0c,0x6f0d,0x6f0e,0x6f0f,
+ 0x6f10,0x6f11,0x6f12,0x6f13,0x6f14,0x6f15,0x6f16,0x6f17,
+ 0x6f18,0x6f19,0x6f1a,0x6f1b,0x6f1c,0x6f1d,0x6f1e,0x6f1f,
+ 0x6f20,0x6f21,0x6f22,0x6f23,0x6f24,0x6f25,0x6f26,0x6f27,
+ 0x6f28,0x6f29,0x6f2a,0x6f2b,0x6f2c,0x6f2d,0x6f2e,0x6f2f,
+ 0x6f30,0x6f31,0x6f32,0x6f33,0x6f34,0x6f35,0x6f36,0x6f37,
+ 0x6f38,0x6f39,0x6f3a,0x6f3b,0x6f3c,0x6f3d,0x6f3e,0x6f3f,
+ 0x6f40,0x6f41,0x6f42,0x6f43,0x6f44,0x6f45,0x6f46,0x6f47,
+ 0x6f48,0x6f49,0x6f4a,0x6f4b,0x6f4c,0x6f4d,0x6f4e,0x6f4f,
+ 0x6f50,0x6f51,0x6f52,0x6f53,0x6f54,0x6f55,0x6f56,0x6f57,
+ 0x6f58,0x6f59,0x6f5a,0x6f5b,0x6f5c,0x6f5d,0x6f5e,0x6f5f,
+ 0x6f60,0x6f61,0x6f62,0x6f63,0x6f64,0x6f65,0x6f66,0x6f67,
+ 0x6f68,0x6f69,0x6f6a,0x6f6b,0x6f6c,0x6f6d,0x6f6e,0x6f6f,
+ 0x6f70,0x6f71,0x6f72,0x6f73,0x6f74,0x6f75,0x6f76,0x6f77,
+ 0x6f78,0x6f79,0x6f7a,0x6f7b,0x6f7c,0x6f7d,0x6f7e,0x6f7f,
+ 0x6f80,0x6f81,0x6f82,0x6f83,0x6f84,0x6f85,0x6f86,0x6f87,
+ 0x6f88,0x6f89,0x6f8a,0x6f8b,0x6f8c,0x6f8d,0x6f8e,0x6f8f,
+ 0x6f90,0x6f91,0x6f92,0x6f93,0x6f94,0x6f95,0x6f96,0x6f97,
+ 0x6f98,0x6f99,0x6f9a,0x6f9b,0x6f9c,0x6f9d,0x6f9e,0x6f9f,
+ 0x6fa0,0x6fa1,0x6fa2,0x6fa3,0x6fa4,0x6fa5,0x6fa6,0x6fa7,
+ 0x6fa8,0x6fa9,0x6faa,0x6fab,0x6fac,0x6fad,0x6fae,0x6faf,
+ 0x6fb0,0x6fb1,0x6fb2,0x6fb3,0x6fb4,0x6fb5,0x6fb6,0x6fb7,
+ 0x6fb8,0x6fb9,0x6fba,0x6fbb,0x6fbc,0x6fbd,0x6fbe,0x6fbf,
+ 0x6fc0,0x6fc1,0x6fc2,0x6fc3,0x6fc4,0x6fc5,0x6fc6,0x6fc7,
+ 0x6fc8,0x6fc9,0x6fca,0x6fcb,0x6fcc,0x6fcd,0x6fce,0x6fcf,
+ 0x6fd0,0x6fd1,0x6fd2,0x6fd3,0x6fd4,0x6fd5,0x6fd6,0x6fd7,
+ 0x6fd8,0x6fd9,0x6fda,0x6fdb,0x6fdc,0x6fdd,0x6fde,0x6fdf,
+ 0x6fe0,0x6fe1,0x6fe2,0x6fe3,0x6fe4,0x6fe5,0x6fe6,0x6fe7,
+ 0x6fe8,0x6fe9,0x6fea,0x6feb,0x6fec,0x6fed,0x6fee,0x6fef,
+ 0x6ff0,0x6ff1,0x6ff2,0x6ff3,0x6ff4,0x6ff5,0x6ff6,0x6ff7,
+ 0x6ff8,0x6ff9,0x6ffa,0x6ffb,0x6ffc,0x6ffd,0x6ffe,0x6fff,
+ 0x7000,0x7001,0x7002,0x7003,0x7004,0x7005,0x7006,0x7007,
+ 0x7008,0x7009,0x700a,0x700b,0x700c,0x700d,0x700e,0x700f,
+ 0x7010,0x7011,0x7012,0x7013,0x7014,0x7015,0x7016,0x7017,
+ 0x7018,0x7019,0x701a,0x701b,0x701c,0x701d,0x701e,0x701f,
+ 0x7020,0x7021,0x7022,0x7023,0x7024,0x7025,0x7026,0x7027,
+ 0x7028,0x7029,0x702a,0x702b,0x702c,0x702d,0x702e,0x702f,
+ 0x7030,0x7031,0x7032,0x7033,0x7034,0x7035,0x7036,0x7037,
+ 0x7038,0x7039,0x703a,0x703b,0x703c,0x703d,0x703e,0x703f,
+ 0x7040,0x7041,0x7042,0x7043,0x7044,0x7045,0x7046,0x7047,
+ 0x7048,0x7049,0x704a,0x704b,0x704c,0x704d,0x704e,0x704f,
+ 0x7050,0x7051,0x7052,0x7053,0x7054,0x7055,0x7056,0x7057,
+ 0x7058,0x7059,0x705a,0x705b,0x705c,0x705d,0x705e,0x705f,
+ 0x7060,0x7061,0x7062,0x7063,0x7064,0x7065,0x7066,0x7067,
+ 0x7068,0x7069,0x706a,0x706b,0x706c,0x706d,0x706e,0x706f,
+ 0x7070,0x7071,0x7072,0x7073,0x7074,0x7075,0x7076,0x7077,
+ 0x7078,0x7079,0x707a,0x707b,0x707c,0x707d,0x707e,0x707f,
+ 0x7080,0x7081,0x7082,0x7083,0x7084,0x7085,0x7086,0x7087,
+ 0x7088,0x7089,0x708a,0x708b,0x708c,0x708d,0x708e,0x708f,
+ 0x7090,0x7091,0x7092,0x7093,0x7094,0x7095,0x7096,0x7097,
+ 0x7098,0x7099,0x709a,0x709b,0x709c,0x709d,0x709e,0x709f,
+ 0x70a0,0x70a1,0x70a2,0x70a3,0x70a4,0x70a5,0x70a6,0x70a7,
+ 0x70a8,0x70a9,0x70aa,0x70ab,0x70ac,0x70ad,0x70ae,0x70af,
+ 0x70b0,0x70b1,0x70b2,0x70b3,0x70b4,0x70b5,0x70b6,0x70b7,
+ 0x70b8,0x70b9,0x70ba,0x70bb,0x70bc,0x70bd,0x70be,0x70bf,
+ 0x70c0,0x70c1,0x70c2,0x70c3,0x70c4,0x70c5,0x70c6,0x70c7,
+ 0x70c8,0x70c9,0x70ca,0x70cb,0x70cc,0x70cd,0x70ce,0x70cf,
+ 0x70d0,0x70d1,0x70d2,0x70d3,0x70d4,0x70d5,0x70d6,0x70d7,
+ 0x70d8,0x70d9,0x70da,0x70db,0x70dc,0x70dd,0x70de,0x70df,
+ 0x70e0,0x70e1,0x70e2,0x70e3,0x70e4,0x70e5,0x70e6,0x70e7,
+ 0x70e8,0x70e9,0x70ea,0x70eb,0x70ec,0x70ed,0x70ee,0x70ef,
+ 0x70f0,0x70f1,0x70f2,0x70f3,0x70f4,0x70f5,0x70f6,0x70f7,
+ 0x70f8,0x70f9,0x70fa,0x70fb,0x70fc,0x70fd,0x70fe,0x70ff,
+ 0x7100,0x7101,0x7102,0x7103,0x7104,0x7105,0x7106,0x7107,
+ 0x7108,0x7109,0x710a,0x710b,0x710c,0x710d,0x710e,0x710f,
+ 0x7110,0x7111,0x7112,0x7113,0x7114,0x7115,0x7116,0x7117,
+ 0x7118,0x7119,0x711a,0x711b,0x711c,0x711d,0x711e,0x711f,
+ 0x7120,0x7121,0x7122,0x7123,0x7124,0x7125,0x7126,0x7127,
+ 0x7128,0x7129,0x712a,0x712b,0x712c,0x712d,0x712e,0x712f,
+ 0x7130,0x7131,0x7132,0x7133,0x7134,0x7135,0x7136,0x7137,
+ 0x7138,0x7139,0x713a,0x713b,0x713c,0x713d,0x713e,0x713f,
+ 0x7140,0x7141,0x7142,0x7143,0x7144,0x7145,0x7146,0x7147,
+ 0x7148,0x7149,0x714a,0x714b,0x714c,0x714d,0x714e,0x714f,
+ 0x7150,0x7151,0x7152,0x7153,0x7154,0x7155,0x7156,0x7157,
+ 0x7158,0x7159,0x715a,0x715b,0x715c,0x715d,0x715e,0x715f,
+ 0x7160,0x7161,0x7162,0x7163,0x7164,0x7165,0x7166,0x7167,
+ 0x7168,0x7169,0x716a,0x716b,0x716c,0x716d,0x716e,0x716f,
+ 0x7170,0x7171,0x7172,0x7173,0x7174,0x7175,0x7176,0x7177,
+ 0x7178,0x7179,0x717a,0x717b,0x717c,0x717d,0x717e,0x717f,
+ 0x7180,0x7181,0x7182,0x7183,0x7184,0x7185,0x7186,0x7187,
+ 0x7188,0x7189,0x718a,0x718b,0x718c,0x718d,0x718e,0x718f,
+ 0x7190,0x7191,0x7192,0x7193,0x7194,0x7195,0x7196,0x7197,
+ 0x7198,0x7199,0x719a,0x719b,0x719c,0x719d,0x719e,0x719f,
+ 0x71a0,0x71a1,0x71a2,0x71a3,0x71a4,0x71a5,0x71a6,0x71a7,
+ 0x71a8,0x71a9,0x71aa,0x71ab,0x71ac,0x71ad,0x71ae,0x71af,
+ 0x71b0,0x71b1,0x71b2,0x71b3,0x71b4,0x71b5,0x71b6,0x71b7,
+ 0x71b8,0x71b9,0x71ba,0x71bb,0x71bc,0x71bd,0x71be,0x71bf,
+ 0x71c0,0x71c1,0x71c2,0x71c3,0x71c4,0x71c5,0x71c6,0x71c7,
+ 0x71c8,0x71c9,0x71ca,0x71cb,0x71cc,0x71cd,0x71ce,0x71cf,
+ 0x71d0,0x71d1,0x71d2,0x71d3,0x71d4,0x71d5,0x71d6,0x71d7,
+ 0x71d8,0x71d9,0x71da,0x71db,0x71dc,0x71dd,0x71de,0x71df,
+ 0x71e0,0x71e1,0x71e2,0x71e3,0x71e4,0x71e5,0x71e6,0x71e7,
+ 0x71e8,0x71e9,0x71ea,0x71eb,0x71ec,0x71ed,0x71ee,0x71ef,
+ 0x71f0,0x71f1,0x71f2,0x71f3,0x71f4,0x71f5,0x71f6,0x71f7,
+ 0x71f8,0x71f9,0x71fa,0x71fb,0x71fc,0x71fd,0x71fe,0x71ff,
+ 0x7200,0x7201,0x7202,0x7203,0x7204,0x7205,0x7206,0x7207,
+ 0x7208,0x7209,0x720a,0x720b,0x720c,0x720d,0x720e,0x720f,
+ 0x7210,0x7211,0x7212,0x7213,0x7214,0x7215,0x7216,0x7217,
+ 0x7218,0x7219,0x721a,0x721b,0x721c,0x721d,0x721e,0x721f,
+ 0x7220,0x7221,0x7222,0x7223,0x7224,0x7225,0x7226,0x7227,
+ 0x7228,0x7229,0x722a,0x722b,0x722c,0x722d,0x722e,0x722f,
+ 0x7230,0x7231,0x7232,0x7233,0x7234,0x7235,0x7236,0x7237,
+ 0x7238,0x7239,0x723a,0x723b,0x723c,0x723d,0x723e,0x723f,
+ 0x7240,0x7241,0x7242,0x7243,0x7244,0x7245,0x7246,0x7247,
+ 0x7248,0x7249,0x724a,0x724b,0x724c,0x724d,0x724e,0x724f,
+ 0x7250,0x7251,0x7252,0x7253,0x7254,0x7255,0x7256,0x7257,
+ 0x7258,0x7259,0x725a,0x725b,0x725c,0x725d,0x725e,0x725f,
+ 0x7260,0x7261,0x7262,0x7263,0x7264,0x7265,0x7266,0x7267,
+ 0x7268,0x7269,0x726a,0x726b,0x726c,0x726d,0x726e,0x726f,
+ 0x7270,0x7271,0x7272,0x7273,0x7274,0x7275,0x7276,0x7277,
+ 0x7278,0x7279,0x727a,0x727b,0x727c,0x727d,0x727e,0x727f,
+ 0x7280,0x7281,0x7282,0x7283,0x7284,0x7285,0x7286,0x7287,
+ 0x7288,0x7289,0x728a,0x728b,0x728c,0x728d,0x728e,0x728f,
+ 0x7290,0x7291,0x7292,0x7293,0x7294,0x7295,0x7296,0x7297,
+ 0x7298,0x7299,0x729a,0x729b,0x729c,0x729d,0x729e,0x729f,
+ 0x72a0,0x72a1,0x72a2,0x72a3,0x72a4,0x72a5,0x72a6,0x72a7,
+ 0x72a8,0x72a9,0x72aa,0x72ab,0x72ac,0x72ad,0x72ae,0x72af,
+ 0x72b0,0x72b1,0x72b2,0x72b3,0x72b4,0x72b5,0x72b6,0x72b7,
+ 0x72b8,0x72b9,0x72ba,0x72bb,0x72bc,0x72bd,0x72be,0x72bf,
+ 0x72c0,0x72c1,0x72c2,0x72c3,0x72c4,0x72c5,0x72c6,0x72c7,
+ 0x72c8,0x72c9,0x72ca,0x72cb,0x72cc,0x72cd,0x72ce,0x72cf,
+ 0x72d0,0x72d1,0x72d2,0x72d3,0x72d4,0x72d5,0x72d6,0x72d7,
+ 0x72d8,0x72d9,0x72da,0x72db,0x72dc,0x72dd,0x72de,0x72df,
+ 0x72e0,0x72e1,0x72e2,0x72e3,0x72e4,0x72e5,0x72e6,0x72e7,
+ 0x72e8,0x72e9,0x72ea,0x72eb,0x72ec,0x72ed,0x72ee,0x72ef,
+ 0x72f0,0x72f1,0x72f2,0x72f3,0x72f4,0x72f5,0x72f6,0x72f7,
+ 0x72f8,0x72f9,0x72fa,0x72fb,0x72fc,0x72fd,0x72fe,0x72ff,
+ 0x7300,0x7301,0x7302,0x7303,0x7304,0x7305,0x7306,0x7307,
+ 0x7308,0x7309,0x730a,0x730b,0x730c,0x730d,0x730e,0x730f,
+ 0x7310,0x7311,0x7312,0x7313,0x7314,0x7315,0x7316,0x7317,
+ 0x7318,0x7319,0x731a,0x731b,0x731c,0x731d,0x731e,0x731f,
+ 0x7320,0x7321,0x7322,0x7323,0x7324,0x7325,0x7326,0x7327,
+ 0x7328,0x7329,0x732a,0x732b,0x732c,0x732d,0x732e,0x732f,
+ 0x7330,0x7331,0x7332,0x7333,0x7334,0x7335,0x7336,0x7337,
+ 0x7338,0x7339,0x733a,0x733b,0x733c,0x733d,0x733e,0x733f,
+ 0x7340,0x7341,0x7342,0x7343,0x7344,0x7345,0x7346,0x7347,
+ 0x7348,0x7349,0x734a,0x734b,0x734c,0x734d,0x734e,0x734f,
+ 0x7350,0x7351,0x7352,0x7353,0x7354,0x7355,0x7356,0x7357,
+ 0x7358,0x7359,0x735a,0x735b,0x735c,0x735d,0x735e,0x735f,
+ 0x7360,0x7361,0x7362,0x7363,0x7364,0x7365,0x7366,0x7367,
+ 0x7368,0x7369,0x736a,0x736b,0x736c,0x736d,0x736e,0x736f,
+ 0x7370,0x7371,0x7372,0x7373,0x7374,0x7375,0x7376,0x7377,
+ 0x7378,0x7379,0x737a,0x737b,0x737c,0x737d,0x737e,0x737f,
+ 0x7380,0x7381,0x7382,0x7383,0x7384,0x7385,0x7386,0x7387,
+ 0x7388,0x7389,0x738a,0x738b,0x738c,0x738d,0x738e,0x738f,
+ 0x7390,0x7391,0x7392,0x7393,0x7394,0x7395,0x7396,0x7397,
+ 0x7398,0x7399,0x739a,0x739b,0x739c,0x739d,0x739e,0x739f,
+ 0x73a0,0x73a1,0x73a2,0x73a3,0x73a4,0x73a5,0x73a6,0x73a7,
+ 0x73a8,0x73a9,0x73aa,0x73ab,0x73ac,0x73ad,0x73ae,0x73af,
+ 0x73b0,0x73b1,0x73b2,0x73b3,0x73b4,0x73b5,0x73b6,0x73b7,
+ 0x73b8,0x73b9,0x73ba,0x73bb,0x73bc,0x73bd,0x73be,0x73bf,
+ 0x73c0,0x73c1,0x73c2,0x73c3,0x73c4,0x73c5,0x73c6,0x73c7,
+ 0x73c8,0x73c9,0x73ca,0x73cb,0x73cc,0x73cd,0x73ce,0x73cf,
+ 0x73d0,0x73d1,0x73d2,0x73d3,0x73d4,0x73d5,0x73d6,0x73d7,
+ 0x73d8,0x73d9,0x73da,0x73db,0x73dc,0x73dd,0x73de,0x73df,
+ 0x73e0,0x73e1,0x73e2,0x73e3,0x73e4,0x73e5,0x73e6,0x73e7,
+ 0x73e8,0x73e9,0x73ea,0x73eb,0x73ec,0x73ed,0x73ee,0x73ef,
+ 0x73f0,0x73f1,0x73f2,0x73f3,0x73f4,0x73f5,0x73f6,0x73f7,
+ 0x73f8,0x73f9,0x73fa,0x73fb,0x73fc,0x73fd,0x73fe,0x73ff,
+ 0x7400,0x7401,0x7402,0x7403,0x7404,0x7405,0x7406,0x7407,
+ 0x7408,0x7409,0x740a,0x740b,0x740c,0x740d,0x740e,0x740f,
+ 0x7410,0x7411,0x7412,0x7413,0x7414,0x7415,0x7416,0x7417,
+ 0x7418,0x7419,0x741a,0x741b,0x741c,0x741d,0x741e,0x741f,
+ 0x7420,0x7421,0x7422,0x7423,0x7424,0x7425,0x7426,0x7427,
+ 0x7428,0x7429,0x742a,0x742b,0x742c,0x742d,0x742e,0x742f,
+ 0x7430,0x7431,0x7432,0x7433,0x7434,0x7435,0x7436,0x7437,
+ 0x7438,0x7439,0x743a,0x743b,0x743c,0x743d,0x743e,0x743f,
+ 0x7440,0x7441,0x7442,0x7443,0x7444,0x7445,0x7446,0x7447,
+ 0x7448,0x7449,0x744a,0x744b,0x744c,0x744d,0x744e,0x744f,
+ 0x7450,0x7451,0x7452,0x7453,0x7454,0x7455,0x7456,0x7457,
+ 0x7458,0x7459,0x745a,0x745b,0x745c,0x745d,0x745e,0x745f,
+ 0x7460,0x7461,0x7462,0x7463,0x7464,0x7465,0x7466,0x7467,
+ 0x7468,0x7469,0x746a,0x746b,0x746c,0x746d,0x746e,0x746f,
+ 0x7470,0x7471,0x7472,0x7473,0x7474,0x7475,0x7476,0x7477,
+ 0x7478,0x7479,0x747a,0x747b,0x747c,0x747d,0x747e,0x747f,
+ 0x7480,0x7481,0x7482,0x7483,0x7484,0x7485,0x7486,0x7487,
+ 0x7488,0x7489,0x748a,0x748b,0x748c,0x748d,0x748e,0x748f,
+ 0x7490,0x7491,0x7492,0x7493,0x7494,0x7495,0x7496,0x7497,
+ 0x7498,0x7499,0x749a,0x749b,0x749c,0x749d,0x749e,0x749f,
+ 0x74a0,0x74a1,0x74a2,0x74a3,0x74a4,0x74a5,0x74a6,0x74a7,
+ 0x74a8,0x74a9,0x74aa,0x74ab,0x74ac,0x74ad,0x74ae,0x74af,
+ 0x74b0,0x74b1,0x74b2,0x74b3,0x74b4,0x74b5,0x74b6,0x74b7,
+ 0x74b8,0x74b9,0x74ba,0x74bb,0x74bc,0x74bd,0x74be,0x74bf,
+ 0x74c0,0x74c1,0x74c2,0x74c3,0x74c4,0x74c5,0x74c6,0x74c7,
+ 0x74c8,0x74c9,0x74ca,0x74cb,0x74cc,0x74cd,0x74ce,0x74cf,
+ 0x74d0,0x74d1,0x74d2,0x74d3,0x74d4,0x74d5,0x74d6,0x74d7,
+ 0x74d8,0x74d9,0x74da,0x74db,0x74dc,0x74dd,0x74de,0x74df,
+ 0x74e0,0x74e1,0x74e2,0x74e3,0x74e4,0x74e5,0x74e6,0x74e7,
+ 0x74e8,0x74e9,0x74ea,0x74eb,0x74ec,0x74ed,0x74ee,0x74ef,
+ 0x74f0,0x74f1,0x74f2,0x74f3,0x74f4,0x74f5,0x74f6,0x74f7,
+ 0x74f8,0x74f9,0x74fa,0x74fb,0x74fc,0x74fd,0x74fe,0x74ff,
+ 0x7500,0x7501,0x7502,0x7503,0x7504,0x7505,0x7506,0x7507,
+ 0x7508,0x7509,0x750a,0x750b,0x750c,0x750d,0x750e,0x750f,
+ 0x7510,0x7511,0x7512,0x7513,0x7514,0x7515,0x7516,0x7517,
+ 0x7518,0x7519,0x751a,0x751b,0x751c,0x751d,0x751e,0x751f,
+ 0x7520,0x7521,0x7522,0x7523,0x7524,0x7525,0x7526,0x7527,
+ 0x7528,0x7529,0x752a,0x752b,0x752c,0x752d,0x752e,0x752f,
+ 0x7530,0x7531,0x7532,0x7533,0x7534,0x7535,0x7536,0x7537,
+ 0x7538,0x7539,0x753a,0x753b,0x753c,0x753d,0x753e,0x753f,
+ 0x7540,0x7541,0x7542,0x7543,0x7544,0x7545,0x7546,0x7547,
+ 0x7548,0x7549,0x754a,0x754b,0x754c,0x754d,0x754e,0x754f,
+ 0x7550,0x7551,0x7552,0x7553,0x7554,0x7555,0x7556,0x7557,
+ 0x7558,0x7559,0x755a,0x755b,0x755c,0x755d,0x755e,0x755f,
+ 0x7560,0x7561,0x7562,0x7563,0x7564,0x7565,0x7566,0x7567,
+ 0x7568,0x7569,0x756a,0x756b,0x756c,0x756d,0x756e,0x756f,
+ 0x7570,0x7571,0x7572,0x7573,0x7574,0x7575,0x7576,0x7577,
+ 0x7578,0x7579,0x757a,0x757b,0x757c,0x757d,0x757e,0x757f,
+ 0x7580,0x7581,0x7582,0x7583,0x7584,0x7585,0x7586,0x7587,
+ 0x7588,0x7589,0x758a,0x758b,0x758c,0x758d,0x758e,0x758f,
+ 0x7590,0x7591,0x7592,0x7593,0x7594,0x7595,0x7596,0x7597,
+ 0x7598,0x7599,0x759a,0x759b,0x759c,0x759d,0x759e,0x759f,
+ 0x75a0,0x75a1,0x75a2,0x75a3,0x75a4,0x75a5,0x75a6,0x75a7,
+ 0x75a8,0x75a9,0x75aa,0x75ab,0x75ac,0x75ad,0x75ae,0x75af,
+ 0x75b0,0x75b1,0x75b2,0x75b3,0x75b4,0x75b5,0x75b6,0x75b7,
+ 0x75b8,0x75b9,0x75ba,0x75bb,0x75bc,0x75bd,0x75be,0x75bf,
+ 0x75c0,0x75c1,0x75c2,0x75c3,0x75c4,0x75c5,0x75c6,0x75c7,
+ 0x75c8,0x75c9,0x75ca,0x75cb,0x75cc,0x75cd,0x75ce,0x75cf,
+ 0x75d0,0x75d1,0x75d2,0x75d3,0x75d4,0x75d5,0x75d6,0x75d7,
+ 0x75d8,0x75d9,0x75da,0x75db,0x75dc,0x75dd,0x75de,0x75df,
+ 0x75e0,0x75e1,0x75e2,0x75e3,0x75e4,0x75e5,0x75e6,0x75e7,
+ 0x75e8,0x75e9,0x75ea,0x75eb,0x75ec,0x75ed,0x75ee,0x75ef,
+ 0x75f0,0x75f1,0x75f2,0x75f3,0x75f4,0x75f5,0x75f6,0x75f7,
+ 0x75f8,0x75f9,0x75fa,0x75fb,0x75fc,0x75fd,0x75fe,0x75ff,
+ 0x7600,0x7601,0x7602,0x7603,0x7604,0x7605,0x7606,0x7607,
+ 0x7608,0x7609,0x760a,0x760b,0x760c,0x760d,0x760e,0x760f,
+ 0x7610,0x7611,0x7612,0x7613,0x7614,0x7615,0x7616,0x7617,
+ 0x7618,0x7619,0x761a,0x761b,0x761c,0x761d,0x761e,0x761f,
+ 0x7620,0x7621,0x7622,0x7623,0x7624,0x7625,0x7626,0x7627,
+ 0x7628,0x7629,0x762a,0x762b,0x762c,0x762d,0x762e,0x762f,
+ 0x7630,0x7631,0x7632,0x7633,0x7634,0x7635,0x7636,0x7637,
+ 0x7638,0x7639,0x763a,0x763b,0x763c,0x763d,0x763e,0x763f,
+ 0x7640,0x7641,0x7642,0x7643,0x7644,0x7645,0x7646,0x7647,
+ 0x7648,0x7649,0x764a,0x764b,0x764c,0x764d,0x764e,0x764f,
+ 0x7650,0x7651,0x7652,0x7653,0x7654,0x7655,0x7656,0x7657,
+ 0x7658,0x7659,0x765a,0x765b,0x765c,0x765d,0x765e,0x765f,
+ 0x7660,0x7661,0x7662,0x7663,0x7664,0x7665,0x7666,0x7667,
+ 0x7668,0x7669,0x766a,0x766b,0x766c,0x766d,0x766e,0x766f,
+ 0x7670,0x7671,0x7672,0x7673,0x7674,0x7675,0x7676,0x7677,
+ 0x7678,0x7679,0x767a,0x767b,0x767c,0x767d,0x767e,0x767f,
+ 0x7680,0x7681,0x7682,0x7683,0x7684,0x7685,0x7686,0x7687,
+ 0x7688,0x7689,0x768a,0x768b,0x768c,0x768d,0x768e,0x768f,
+ 0x7690,0x7691,0x7692,0x7693,0x7694,0x7695,0x7696,0x7697,
+ 0x7698,0x7699,0x769a,0x769b,0x769c,0x769d,0x769e,0x769f,
+ 0x76a0,0x76a1,0x76a2,0x76a3,0x76a4,0x76a5,0x76a6,0x76a7,
+ 0x76a8,0x76a9,0x76aa,0x76ab,0x76ac,0x76ad,0x76ae,0x76af,
+ 0x76b0,0x76b1,0x76b2,0x76b3,0x76b4,0x76b5,0x76b6,0x76b7,
+ 0x76b8,0x76b9,0x76ba,0x76bb,0x76bc,0x76bd,0x76be,0x76bf,
+ 0x76c0,0x76c1,0x76c2,0x76c3,0x76c4,0x76c5,0x76c6,0x76c7,
+ 0x76c8,0x76c9,0x76ca,0x76cb,0x76cc,0x76cd,0x76ce,0x76cf,
+ 0x76d0,0x76d1,0x76d2,0x76d3,0x76d4,0x76d5,0x76d6,0x76d7,
+ 0x76d8,0x76d9,0x76da,0x76db,0x76dc,0x76dd,0x76de,0x76df,
+ 0x76e0,0x76e1,0x76e2,0x76e3,0x76e4,0x76e5,0x76e6,0x76e7,
+ 0x76e8,0x76e9,0x76ea,0x76eb,0x76ec,0x76ed,0x76ee,0x76ef,
+ 0x76f0,0x76f1,0x76f2,0x76f3,0x76f4,0x76f5,0x76f6,0x76f7,
+ 0x76f8,0x76f9,0x76fa,0x76fb,0x76fc,0x76fd,0x76fe,0x76ff,
+ 0x7700,0x7701,0x7702,0x7703,0x7704,0x7705,0x7706,0x7707,
+ 0x7708,0x7709,0x770a,0x770b,0x770c,0x770d,0x770e,0x770f,
+ 0x7710,0x7711,0x7712,0x7713,0x7714,0x7715,0x7716,0x7717,
+ 0x7718,0x7719,0x771a,0x771b,0x771c,0x771d,0x771e,0x771f,
+ 0x7720,0x7721,0x7722,0x7723,0x7724,0x7725,0x7726,0x7727,
+ 0x7728,0x7729,0x772a,0x772b,0x772c,0x772d,0x772e,0x772f,
+ 0x7730,0x7731,0x7732,0x7733,0x7734,0x7735,0x7736,0x7737,
+ 0x7738,0x7739,0x773a,0x773b,0x773c,0x773d,0x773e,0x773f,
+ 0x7740,0x7741,0x7742,0x7743,0x7744,0x7745,0x7746,0x7747,
+ 0x7748,0x7749,0x774a,0x774b,0x774c,0x774d,0x774e,0x774f,
+ 0x7750,0x7751,0x7752,0x7753,0x7754,0x7755,0x7756,0x7757,
+ 0x7758,0x7759,0x775a,0x775b,0x775c,0x775d,0x775e,0x775f,
+ 0x7760,0x7761,0x7762,0x7763,0x7764,0x7765,0x7766,0x7767,
+ 0x7768,0x7769,0x776a,0x776b,0x776c,0x776d,0x776e,0x776f,
+ 0x7770,0x7771,0x7772,0x7773,0x7774,0x7775,0x7776,0x7777,
+ 0x7778,0x7779,0x777a,0x777b,0x777c,0x777d,0x777e,0x777f,
+ 0x7780,0x7781,0x7782,0x7783,0x7784,0x7785,0x7786,0x7787,
+ 0x7788,0x7789,0x778a,0x778b,0x778c,0x778d,0x778e,0x778f,
+ 0x7790,0x7791,0x7792,0x7793,0x7794,0x7795,0x7796,0x7797,
+ 0x7798,0x7799,0x779a,0x779b,0x779c,0x779d,0x779e,0x779f,
+ 0x77a0,0x77a1,0x77a2,0x77a3,0x77a4,0x77a5,0x77a6,0x77a7,
+ 0x77a8,0x77a9,0x77aa,0x77ab,0x77ac,0x77ad,0x77ae,0x77af,
+ 0x77b0,0x77b1,0x77b2,0x77b3,0x77b4,0x77b5,0x77b6,0x77b7,
+ 0x77b8,0x77b9,0x77ba,0x77bb,0x77bc,0x77bd,0x77be,0x77bf,
+ 0x77c0,0x77c1,0x77c2,0x77c3,0x77c4,0x77c5,0x77c6,0x77c7,
+ 0x77c8,0x77c9,0x77ca,0x77cb,0x77cc,0x77cd,0x77ce,0x77cf,
+ 0x77d0,0x77d1,0x77d2,0x77d3,0x77d4,0x77d5,0x77d6,0x77d7,
+ 0x77d8,0x77d9,0x77da,0x77db,0x77dc,0x77dd,0x77de,0x77df,
+ 0x77e0,0x77e1,0x77e2,0x77e3,0x77e4,0x77e5,0x77e6,0x77e7,
+ 0x77e8,0x77e9,0x77ea,0x77eb,0x77ec,0x77ed,0x77ee,0x77ef,
+ 0x77f0,0x77f1,0x77f2,0x77f3,0x77f4,0x77f5,0x77f6,0x77f7,
+ 0x77f8,0x77f9,0x77fa,0x77fb,0x77fc,0x77fd,0x77fe,0x77ff,
+ 0x7800,0x7801,0x7802,0x7803,0x7804,0x7805,0x7806,0x7807,
+ 0x7808,0x7809,0x780a,0x780b,0x780c,0x780d,0x780e,0x780f,
+ 0x7810,0x7811,0x7812,0x7813,0x7814,0x7815,0x7816,0x7817,
+ 0x7818,0x7819,0x781a,0x781b,0x781c,0x781d,0x781e,0x781f,
+ 0x7820,0x7821,0x7822,0x7823,0x7824,0x7825,0x7826,0x7827,
+ 0x7828,0x7829,0x782a,0x782b,0x782c,0x782d,0x782e,0x782f,
+ 0x7830,0x7831,0x7832,0x7833,0x7834,0x7835,0x7836,0x7837,
+ 0x7838,0x7839,0x783a,0x783b,0x783c,0x783d,0x783e,0x783f,
+ 0x7840,0x7841,0x7842,0x7843,0x7844,0x7845,0x7846,0x7847,
+ 0x7848,0x7849,0x784a,0x784b,0x784c,0x784d,0x784e,0x784f,
+ 0x7850,0x7851,0x7852,0x7853,0x7854,0x7855,0x7856,0x7857,
+ 0x7858,0x7859,0x785a,0x785b,0x785c,0x785d,0x785e,0x785f,
+ 0x7860,0x7861,0x7862,0x7863,0x7864,0x7865,0x7866,0x7867,
+ 0x7868,0x7869,0x786a,0x786b,0x786c,0x786d,0x786e,0x786f,
+ 0x7870,0x7871,0x7872,0x7873,0x7874,0x7875,0x7876,0x7877,
+ 0x7878,0x7879,0x787a,0x787b,0x787c,0x787d,0x787e,0x787f,
+ 0x7880,0x7881,0x7882,0x7883,0x7884,0x7885,0x7886,0x7887,
+ 0x7888,0x7889,0x788a,0x788b,0x788c,0x788d,0x788e,0x788f,
+ 0x7890,0x7891,0x7892,0x7893,0x7894,0x7895,0x7896,0x7897,
+ 0x7898,0x7899,0x789a,0x789b,0x789c,0x789d,0x789e,0x789f,
+ 0x78a0,0x78a1,0x78a2,0x78a3,0x78a4,0x78a5,0x78a6,0x78a7,
+ 0x78a8,0x78a9,0x78aa,0x78ab,0x78ac,0x78ad,0x78ae,0x78af,
+ 0x78b0,0x78b1,0x78b2,0x78b3,0x78b4,0x78b5,0x78b6,0x78b7,
+ 0x78b8,0x78b9,0x78ba,0x78bb,0x78bc,0x78bd,0x78be,0x78bf,
+ 0x78c0,0x78c1,0x78c2,0x78c3,0x78c4,0x78c5,0x78c6,0x78c7,
+ 0x78c8,0x78c9,0x78ca,0x78cb,0x78cc,0x78cd,0x78ce,0x78cf,
+ 0x78d0,0x78d1,0x78d2,0x78d3,0x78d4,0x78d5,0x78d6,0x78d7,
+ 0x78d8,0x78d9,0x78da,0x78db,0x78dc,0x78dd,0x78de,0x78df,
+ 0x78e0,0x78e1,0x78e2,0x78e3,0x78e4,0x78e5,0x78e6,0x78e7,
+ 0x78e8,0x78e9,0x78ea,0x78eb,0x78ec,0x78ed,0x78ee,0x78ef,
+ 0x78f0,0x78f1,0x78f2,0x78f3,0x78f4,0x78f5,0x78f6,0x78f7,
+ 0x78f8,0x78f9,0x78fa,0x78fb,0x78fc,0x78fd,0x78fe,0x78ff,
+ 0x7900,0x7901,0x7902,0x7903,0x7904,0x7905,0x7906,0x7907,
+ 0x7908,0x7909,0x790a,0x790b,0x790c,0x790d,0x790e,0x790f,
+ 0x7910,0x7911,0x7912,0x7913,0x7914,0x7915,0x7916,0x7917,
+ 0x7918,0x7919,0x791a,0x791b,0x791c,0x791d,0x791e,0x791f,
+ 0x7920,0x7921,0x7922,0x7923,0x7924,0x7925,0x7926,0x7927,
+ 0x7928,0x7929,0x792a,0x792b,0x792c,0x792d,0x792e,0x792f,
+ 0x7930,0x7931,0x7932,0x7933,0x7934,0x7935,0x7936,0x7937,
+ 0x7938,0x7939,0x793a,0x793b,0x793c,0x793d,0x793e,0x793f,
+ 0x7940,0x7941,0x7942,0x7943,0x7944,0x7945,0x7946,0x7947,
+ 0x7948,0x7949,0x794a,0x794b,0x794c,0x794d,0x794e,0x794f,
+ 0x7950,0x7951,0x7952,0x7953,0x7954,0x7955,0x7956,0x7957,
+ 0x7958,0x7959,0x795a,0x795b,0x795c,0x795d,0x795e,0x795f,
+ 0x7960,0x7961,0x7962,0x7963,0x7964,0x7965,0x7966,0x7967,
+ 0x7968,0x7969,0x796a,0x796b,0x796c,0x796d,0x796e,0x796f,
+ 0x7970,0x7971,0x7972,0x7973,0x7974,0x7975,0x7976,0x7977,
+ 0x7978,0x7979,0x797a,0x797b,0x797c,0x797d,0x797e,0x797f,
+ 0x7980,0x7981,0x7982,0x7983,0x7984,0x7985,0x7986,0x7987,
+ 0x7988,0x7989,0x798a,0x798b,0x798c,0x798d,0x798e,0x798f,
+ 0x7990,0x7991,0x7992,0x7993,0x7994,0x7995,0x7996,0x7997,
+ 0x7998,0x7999,0x799a,0x799b,0x799c,0x799d,0x799e,0x799f,
+ 0x79a0,0x79a1,0x79a2,0x79a3,0x79a4,0x79a5,0x79a6,0x79a7,
+ 0x79a8,0x79a9,0x79aa,0x79ab,0x79ac,0x79ad,0x79ae,0x79af,
+ 0x79b0,0x79b1,0x79b2,0x79b3,0x79b4,0x79b5,0x79b6,0x79b7,
+ 0x79b8,0x79b9,0x79ba,0x79bb,0x79bc,0x79bd,0x79be,0x79bf,
+ 0x79c0,0x79c1,0x79c2,0x79c3,0x79c4,0x79c5,0x79c6,0x79c7,
+ 0x79c8,0x79c9,0x79ca,0x79cb,0x79cc,0x79cd,0x79ce,0x79cf,
+ 0x79d0,0x79d1,0x79d2,0x79d3,0x79d4,0x79d5,0x79d6,0x79d7,
+ 0x79d8,0x79d9,0x79da,0x79db,0x79dc,0x79dd,0x79de,0x79df,
+ 0x79e0,0x79e1,0x79e2,0x79e3,0x79e4,0x79e5,0x79e6,0x79e7,
+ 0x79e8,0x79e9,0x79ea,0x79eb,0x79ec,0x79ed,0x79ee,0x79ef,
+ 0x79f0,0x79f1,0x79f2,0x79f3,0x79f4,0x79f5,0x79f6,0x79f7,
+ 0x79f8,0x79f9,0x79fa,0x79fb,0x79fc,0x79fd,0x79fe,0x79ff,
+ 0x7a00,0x7a01,0x7a02,0x7a03,0x7a04,0x7a05,0x7a06,0x7a07,
+ 0x7a08,0x7a09,0x7a0a,0x7a0b,0x7a0c,0x7a0d,0x7a0e,0x7a0f,
+ 0x7a10,0x7a11,0x7a12,0x7a13,0x7a14,0x7a15,0x7a16,0x7a17,
+ 0x7a18,0x7a19,0x7a1a,0x7a1b,0x7a1c,0x7a1d,0x7a1e,0x7a1f,
+ 0x7a20,0x7a21,0x7a22,0x7a23,0x7a24,0x7a25,0x7a26,0x7a27,
+ 0x7a28,0x7a29,0x7a2a,0x7a2b,0x7a2c,0x7a2d,0x7a2e,0x7a2f,
+ 0x7a30,0x7a31,0x7a32,0x7a33,0x7a34,0x7a35,0x7a36,0x7a37,
+ 0x7a38,0x7a39,0x7a3a,0x7a3b,0x7a3c,0x7a3d,0x7a3e,0x7a3f,
+ 0x7a40,0x7a41,0x7a42,0x7a43,0x7a44,0x7a45,0x7a46,0x7a47,
+ 0x7a48,0x7a49,0x7a4a,0x7a4b,0x7a4c,0x7a4d,0x7a4e,0x7a4f,
+ 0x7a50,0x7a51,0x7a52,0x7a53,0x7a54,0x7a55,0x7a56,0x7a57,
+ 0x7a58,0x7a59,0x7a5a,0x7a5b,0x7a5c,0x7a5d,0x7a5e,0x7a5f,
+ 0x7a60,0x7a61,0x7a62,0x7a63,0x7a64,0x7a65,0x7a66,0x7a67,
+ 0x7a68,0x7a69,0x7a6a,0x7a6b,0x7a6c,0x7a6d,0x7a6e,0x7a6f,
+ 0x7a70,0x7a71,0x7a72,0x7a73,0x7a74,0x7a75,0x7a76,0x7a77,
+ 0x7a78,0x7a79,0x7a7a,0x7a7b,0x7a7c,0x7a7d,0x7a7e,0x7a7f,
+ 0x7a80,0x7a81,0x7a82,0x7a83,0x7a84,0x7a85,0x7a86,0x7a87,
+ 0x7a88,0x7a89,0x7a8a,0x7a8b,0x7a8c,0x7a8d,0x7a8e,0x7a8f,
+ 0x7a90,0x7a91,0x7a92,0x7a93,0x7a94,0x7a95,0x7a96,0x7a97,
+ 0x7a98,0x7a99,0x7a9a,0x7a9b,0x7a9c,0x7a9d,0x7a9e,0x7a9f,
+ 0x7aa0,0x7aa1,0x7aa2,0x7aa3,0x7aa4,0x7aa5,0x7aa6,0x7aa7,
+ 0x7aa8,0x7aa9,0x7aaa,0x7aab,0x7aac,0x7aad,0x7aae,0x7aaf,
+ 0x7ab0,0x7ab1,0x7ab2,0x7ab3,0x7ab4,0x7ab5,0x7ab6,0x7ab7,
+ 0x7ab8,0x7ab9,0x7aba,0x7abb,0x7abc,0x7abd,0x7abe,0x7abf,
+ 0x7ac0,0x7ac1,0x7ac2,0x7ac3,0x7ac4,0x7ac5,0x7ac6,0x7ac7,
+ 0x7ac8,0x7ac9,0x7aca,0x7acb,0x7acc,0x7acd,0x7ace,0x7acf,
+ 0x7ad0,0x7ad1,0x7ad2,0x7ad3,0x7ad4,0x7ad5,0x7ad6,0x7ad7,
+ 0x7ad8,0x7ad9,0x7ada,0x7adb,0x7adc,0x7add,0x7ade,0x7adf,
+ 0x7ae0,0x7ae1,0x7ae2,0x7ae3,0x7ae4,0x7ae5,0x7ae6,0x7ae7,
+ 0x7ae8,0x7ae9,0x7aea,0x7aeb,0x7aec,0x7aed,0x7aee,0x7aef,
+ 0x7af0,0x7af1,0x7af2,0x7af3,0x7af4,0x7af5,0x7af6,0x7af7,
+ 0x7af8,0x7af9,0x7afa,0x7afb,0x7afc,0x7afd,0x7afe,0x7aff,
+ 0x7b00,0x7b01,0x7b02,0x7b03,0x7b04,0x7b05,0x7b06,0x7b07,
+ 0x7b08,0x7b09,0x7b0a,0x7b0b,0x7b0c,0x7b0d,0x7b0e,0x7b0f,
+ 0x7b10,0x7b11,0x7b12,0x7b13,0x7b14,0x7b15,0x7b16,0x7b17,
+ 0x7b18,0x7b19,0x7b1a,0x7b1b,0x7b1c,0x7b1d,0x7b1e,0x7b1f,
+ 0x7b20,0x7b21,0x7b22,0x7b23,0x7b24,0x7b25,0x7b26,0x7b27,
+ 0x7b28,0x7b29,0x7b2a,0x7b2b,0x7b2c,0x7b2d,0x7b2e,0x7b2f,
+ 0x7b30,0x7b31,0x7b32,0x7b33,0x7b34,0x7b35,0x7b36,0x7b37,
+ 0x7b38,0x7b39,0x7b3a,0x7b3b,0x7b3c,0x7b3d,0x7b3e,0x7b3f,
+ 0x7b40,0x7b41,0x7b42,0x7b43,0x7b44,0x7b45,0x7b46,0x7b47,
+ 0x7b48,0x7b49,0x7b4a,0x7b4b,0x7b4c,0x7b4d,0x7b4e,0x7b4f,
+ 0x7b50,0x7b51,0x7b52,0x7b53,0x7b54,0x7b55,0x7b56,0x7b57,
+ 0x7b58,0x7b59,0x7b5a,0x7b5b,0x7b5c,0x7b5d,0x7b5e,0x7b5f,
+ 0x7b60,0x7b61,0x7b62,0x7b63,0x7b64,0x7b65,0x7b66,0x7b67,
+ 0x7b68,0x7b69,0x7b6a,0x7b6b,0x7b6c,0x7b6d,0x7b6e,0x7b6f,
+ 0x7b70,0x7b71,0x7b72,0x7b73,0x7b74,0x7b75,0x7b76,0x7b77,
+ 0x7b78,0x7b79,0x7b7a,0x7b7b,0x7b7c,0x7b7d,0x7b7e,0x7b7f,
+ 0x7b80,0x7b81,0x7b82,0x7b83,0x7b84,0x7b85,0x7b86,0x7b87,
+ 0x7b88,0x7b89,0x7b8a,0x7b8b,0x7b8c,0x7b8d,0x7b8e,0x7b8f,
+ 0x7b90,0x7b91,0x7b92,0x7b93,0x7b94,0x7b95,0x7b96,0x7b97,
+ 0x7b98,0x7b99,0x7b9a,0x7b9b,0x7b9c,0x7b9d,0x7b9e,0x7b9f,
+ 0x7ba0,0x7ba1,0x7ba2,0x7ba3,0x7ba4,0x7ba5,0x7ba6,0x7ba7,
+ 0x7ba8,0x7ba9,0x7baa,0x7bab,0x7bac,0x7bad,0x7bae,0x7baf,
+ 0x7bb0,0x7bb1,0x7bb2,0x7bb3,0x7bb4,0x7bb5,0x7bb6,0x7bb7,
+ 0x7bb8,0x7bb9,0x7bba,0x7bbb,0x7bbc,0x7bbd,0x7bbe,0x7bbf,
+ 0x7bc0,0x7bc1,0x7bc2,0x7bc3,0x7bc4,0x7bc5,0x7bc6,0x7bc7,
+ 0x7bc8,0x7bc9,0x7bca,0x7bcb,0x7bcc,0x7bcd,0x7bce,0x7bcf,
+ 0x7bd0,0x7bd1,0x7bd2,0x7bd3,0x7bd4,0x7bd5,0x7bd6,0x7bd7,
+ 0x7bd8,0x7bd9,0x7bda,0x7bdb,0x7bdc,0x7bdd,0x7bde,0x7bdf,
+ 0x7be0,0x7be1,0x7be2,0x7be3,0x7be4,0x7be5,0x7be6,0x7be7,
+ 0x7be8,0x7be9,0x7bea,0x7beb,0x7bec,0x7bed,0x7bee,0x7bef,
+ 0x7bf0,0x7bf1,0x7bf2,0x7bf3,0x7bf4,0x7bf5,0x7bf6,0x7bf7,
+ 0x7bf8,0x7bf9,0x7bfa,0x7bfb,0x7bfc,0x7bfd,0x7bfe,0x7bff,
+ 0x7c00,0x7c01,0x7c02,0x7c03,0x7c04,0x7c05,0x7c06,0x7c07,
+ 0x7c08,0x7c09,0x7c0a,0x7c0b,0x7c0c,0x7c0d,0x7c0e,0x7c0f,
+ 0x7c10,0x7c11,0x7c12,0x7c13,0x7c14,0x7c15,0x7c16,0x7c17,
+ 0x7c18,0x7c19,0x7c1a,0x7c1b,0x7c1c,0x7c1d,0x7c1e,0x7c1f,
+ 0x7c20,0x7c21,0x7c22,0x7c23,0x7c24,0x7c25,0x7c26,0x7c27,
+ 0x7c28,0x7c29,0x7c2a,0x7c2b,0x7c2c,0x7c2d,0x7c2e,0x7c2f,
+ 0x7c30,0x7c31,0x7c32,0x7c33,0x7c34,0x7c35,0x7c36,0x7c37,
+ 0x7c38,0x7c39,0x7c3a,0x7c3b,0x7c3c,0x7c3d,0x7c3e,0x7c3f,
+ 0x7c40,0x7c41,0x7c42,0x7c43,0x7c44,0x7c45,0x7c46,0x7c47,
+ 0x7c48,0x7c49,0x7c4a,0x7c4b,0x7c4c,0x7c4d,0x7c4e,0x7c4f,
+ 0x7c50,0x7c51,0x7c52,0x7c53,0x7c54,0x7c55,0x7c56,0x7c57,
+ 0x7c58,0x7c59,0x7c5a,0x7c5b,0x7c5c,0x7c5d,0x7c5e,0x7c5f,
+ 0x7c60,0x7c61,0x7c62,0x7c63,0x7c64,0x7c65,0x7c66,0x7c67,
+ 0x7c68,0x7c69,0x7c6a,0x7c6b,0x7c6c,0x7c6d,0x7c6e,0x7c6f,
+ 0x7c70,0x7c71,0x7c72,0x7c73,0x7c74,0x7c75,0x7c76,0x7c77,
+ 0x7c78,0x7c79,0x7c7a,0x7c7b,0x7c7c,0x7c7d,0x7c7e,0x7c7f,
+ 0x7c80,0x7c81,0x7c82,0x7c83,0x7c84,0x7c85,0x7c86,0x7c87,
+ 0x7c88,0x7c89,0x7c8a,0x7c8b,0x7c8c,0x7c8d,0x7c8e,0x7c8f,
+ 0x7c90,0x7c91,0x7c92,0x7c93,0x7c94,0x7c95,0x7c96,0x7c97,
+ 0x7c98,0x7c99,0x7c9a,0x7c9b,0x7c9c,0x7c9d,0x7c9e,0x7c9f,
+ 0x7ca0,0x7ca1,0x7ca2,0x7ca3,0x7ca4,0x7ca5,0x7ca6,0x7ca7,
+ 0x7ca8,0x7ca9,0x7caa,0x7cab,0x7cac,0x7cad,0x7cae,0x7caf,
+ 0x7cb0,0x7cb1,0x7cb2,0x7cb3,0x7cb4,0x7cb5,0x7cb6,0x7cb7,
+ 0x7cb8,0x7cb9,0x7cba,0x7cbb,0x7cbc,0x7cbd,0x7cbe,0x7cbf,
+ 0x7cc0,0x7cc1,0x7cc2,0x7cc3,0x7cc4,0x7cc5,0x7cc6,0x7cc7,
+ 0x7cc8,0x7cc9,0x7cca,0x7ccb,0x7ccc,0x7ccd,0x7cce,0x7ccf,
+ 0x7cd0,0x7cd1,0x7cd2,0x7cd3,0x7cd4,0x7cd5,0x7cd6,0x7cd7,
+ 0x7cd8,0x7cd9,0x7cda,0x7cdb,0x7cdc,0x7cdd,0x7cde,0x7cdf,
+ 0x7ce0,0x7ce1,0x7ce2,0x7ce3,0x7ce4,0x7ce5,0x7ce6,0x7ce7,
+ 0x7ce8,0x7ce9,0x7cea,0x7ceb,0x7cec,0x7ced,0x7cee,0x7cef,
+ 0x7cf0,0x7cf1,0x7cf2,0x7cf3,0x7cf4,0x7cf5,0x7cf6,0x7cf7,
+ 0x7cf8,0x7cf9,0x7cfa,0x7cfb,0x7cfc,0x7cfd,0x7cfe,0x7cff,
+ 0x7d00,0x7d01,0x7d02,0x7d03,0x7d04,0x7d05,0x7d06,0x7d07,
+ 0x7d08,0x7d09,0x7d0a,0x7d0b,0x7d0c,0x7d0d,0x7d0e,0x7d0f,
+ 0x7d10,0x7d11,0x7d12,0x7d13,0x7d14,0x7d15,0x7d16,0x7d17,
+ 0x7d18,0x7d19,0x7d1a,0x7d1b,0x7d1c,0x7d1d,0x7d1e,0x7d1f,
+ 0x7d20,0x7d21,0x7d22,0x7d23,0x7d24,0x7d25,0x7d26,0x7d27,
+ 0x7d28,0x7d29,0x7d2a,0x7d2b,0x7d2c,0x7d2d,0x7d2e,0x7d2f,
+ 0x7d30,0x7d31,0x7d32,0x7d33,0x7d34,0x7d35,0x7d36,0x7d37,
+ 0x7d38,0x7d39,0x7d3a,0x7d3b,0x7d3c,0x7d3d,0x7d3e,0x7d3f,
+ 0x7d40,0x7d41,0x7d42,0x7d43,0x7d44,0x7d45,0x7d46,0x7d47,
+ 0x7d48,0x7d49,0x7d4a,0x7d4b,0x7d4c,0x7d4d,0x7d4e,0x7d4f,
+ 0x7d50,0x7d51,0x7d52,0x7d53,0x7d54,0x7d55,0x7d56,0x7d57,
+ 0x7d58,0x7d59,0x7d5a,0x7d5b,0x7d5c,0x7d5d,0x7d5e,0x7d5f,
+ 0x7d60,0x7d61,0x7d62,0x7d63,0x7d64,0x7d65,0x7d66,0x7d67,
+ 0x7d68,0x7d69,0x7d6a,0x7d6b,0x7d6c,0x7d6d,0x7d6e,0x7d6f,
+ 0x7d70,0x7d71,0x7d72,0x7d73,0x7d74,0x7d75,0x7d76,0x7d77,
+ 0x7d78,0x7d79,0x7d7a,0x7d7b,0x7d7c,0x7d7d,0x7d7e,0x7d7f,
+ 0x7d80,0x7d81,0x7d82,0x7d83,0x7d84,0x7d85,0x7d86,0x7d87,
+ 0x7d88,0x7d89,0x7d8a,0x7d8b,0x7d8c,0x7d8d,0x7d8e,0x7d8f,
+ 0x7d90,0x7d91,0x7d92,0x7d93,0x7d94,0x7d95,0x7d96,0x7d97,
+ 0x7d98,0x7d99,0x7d9a,0x7d9b,0x7d9c,0x7d9d,0x7d9e,0x7d9f,
+ 0x7da0,0x7da1,0x7da2,0x7da3,0x7da4,0x7da5,0x7da6,0x7da7,
+ 0x7da8,0x7da9,0x7daa,0x7dab,0x7dac,0x7dad,0x7dae,0x7daf,
+ 0x7db0,0x7db1,0x7db2,0x7db3,0x7db4,0x7db5,0x7db6,0x7db7,
+ 0x7db8,0x7db9,0x7dba,0x7dbb,0x7dbc,0x7dbd,0x7dbe,0x7dbf,
+ 0x7dc0,0x7dc1,0x7dc2,0x7dc3,0x7dc4,0x7dc5,0x7dc6,0x7dc7,
+ 0x7dc8,0x7dc9,0x7dca,0x7dcb,0x7dcc,0x7dcd,0x7dce,0x7dcf,
+ 0x7dd0,0x7dd1,0x7dd2,0x7dd3,0x7dd4,0x7dd5,0x7dd6,0x7dd7,
+ 0x7dd8,0x7dd9,0x7dda,0x7ddb,0x7ddc,0x7ddd,0x7dde,0x7ddf,
+ 0x7de0,0x7de1,0x7de2,0x7de3,0x7de4,0x7de5,0x7de6,0x7de7,
+ 0x7de8,0x7de9,0x7dea,0x7deb,0x7dec,0x7ded,0x7dee,0x7def,
+ 0x7df0,0x7df1,0x7df2,0x7df3,0x7df4,0x7df5,0x7df6,0x7df7,
+ 0x7df8,0x7df9,0x7dfa,0x7dfb,0x7dfc,0x7dfd,0x7dfe,0x7dff,
+ 0x7e00,0x7e01,0x7e02,0x7e03,0x7e04,0x7e05,0x7e06,0x7e07,
+ 0x7e08,0x7e09,0x7e0a,0x7e0b,0x7e0c,0x7e0d,0x7e0e,0x7e0f,
+ 0x7e10,0x7e11,0x7e12,0x7e13,0x7e14,0x7e15,0x7e16,0x7e17,
+ 0x7e18,0x7e19,0x7e1a,0x7e1b,0x7e1c,0x7e1d,0x7e1e,0x7e1f,
+ 0x7e20,0x7e21,0x7e22,0x7e23,0x7e24,0x7e25,0x7e26,0x7e27,
+ 0x7e28,0x7e29,0x7e2a,0x7e2b,0x7e2c,0x7e2d,0x7e2e,0x7e2f,
+ 0x7e30,0x7e31,0x7e32,0x7e33,0x7e34,0x7e35,0x7e36,0x7e37,
+ 0x7e38,0x7e39,0x7e3a,0x7e3b,0x7e3c,0x7e3d,0x7e3e,0x7e3f,
+ 0x7e40,0x7e41,0x7e42,0x7e43,0x7e44,0x7e45,0x7e46,0x7e47,
+ 0x7e48,0x7e49,0x7e4a,0x7e4b,0x7e4c,0x7e4d,0x7e4e,0x7e4f,
+ 0x7e50,0x7e51,0x7e52,0x7e53,0x7e54,0x7e55,0x7e56,0x7e57,
+ 0x7e58,0x7e59,0x7e5a,0x7e5b,0x7e5c,0x7e5d,0x7e5e,0x7e5f,
+ 0x7e60,0x7e61,0x7e62,0x7e63,0x7e64,0x7e65,0x7e66,0x7e67,
+ 0x7e68,0x7e69,0x7e6a,0x7e6b,0x7e6c,0x7e6d,0x7e6e,0x7e6f,
+ 0x7e70,0x7e71,0x7e72,0x7e73,0x7e74,0x7e75,0x7e76,0x7e77,
+ 0x7e78,0x7e79,0x7e7a,0x7e7b,0x7e7c,0x7e7d,0x7e7e,0x7e7f,
+ 0x7e80,0x7e81,0x7e82,0x7e83,0x7e84,0x7e85,0x7e86,0x7e87,
+ 0x7e88,0x7e89,0x7e8a,0x7e8b,0x7e8c,0x7e8d,0x7e8e,0x7e8f,
+ 0x7e90,0x7e91,0x7e92,0x7e93,0x7e94,0x7e95,0x7e96,0x7e97,
+ 0x7e98,0x7e99,0x7e9a,0x7e9b,0x7e9c,0x7e9d,0x7e9e,0x7e9f,
+ 0x7ea0,0x7ea1,0x7ea2,0x7ea3,0x7ea4,0x7ea5,0x7ea6,0x7ea7,
+ 0x7ea8,0x7ea9,0x7eaa,0x7eab,0x7eac,0x7ead,0x7eae,0x7eaf,
+ 0x7eb0,0x7eb1,0x7eb2,0x7eb3,0x7eb4,0x7eb5,0x7eb6,0x7eb7,
+ 0x7eb8,0x7eb9,0x7eba,0x7ebb,0x7ebc,0x7ebd,0x7ebe,0x7ebf,
+ 0x7ec0,0x7ec1,0x7ec2,0x7ec3,0x7ec4,0x7ec5,0x7ec6,0x7ec7,
+ 0x7ec8,0x7ec9,0x7eca,0x7ecb,0x7ecc,0x7ecd,0x7ece,0x7ecf,
+ 0x7ed0,0x7ed1,0x7ed2,0x7ed3,0x7ed4,0x7ed5,0x7ed6,0x7ed7,
+ 0x7ed8,0x7ed9,0x7eda,0x7edb,0x7edc,0x7edd,0x7ede,0x7edf,
+ 0x7ee0,0x7ee1,0x7ee2,0x7ee3,0x7ee4,0x7ee5,0x7ee6,0x7ee7,
+ 0x7ee8,0x7ee9,0x7eea,0x7eeb,0x7eec,0x7eed,0x7eee,0x7eef,
+ 0x7ef0,0x7ef1,0x7ef2,0x7ef3,0x7ef4,0x7ef5,0x7ef6,0x7ef7,
+ 0x7ef8,0x7ef9,0x7efa,0x7efb,0x7efc,0x7efd,0x7efe,0x7eff,
+ 0x7f00,0x7f01,0x7f02,0x7f03,0x7f04,0x7f05,0x7f06,0x7f07,
+ 0x7f08,0x7f09,0x7f0a,0x7f0b,0x7f0c,0x7f0d,0x7f0e,0x7f0f,
+ 0x7f10,0x7f11,0x7f12,0x7f13,0x7f14,0x7f15,0x7f16,0x7f17,
+ 0x7f18,0x7f19,0x7f1a,0x7f1b,0x7f1c,0x7f1d,0x7f1e,0x7f1f,
+ 0x7f20,0x7f21,0x7f22,0x7f23,0x7f24,0x7f25,0x7f26,0x7f27,
+ 0x7f28,0x7f29,0x7f2a,0x7f2b,0x7f2c,0x7f2d,0x7f2e,0x7f2f,
+ 0x7f30,0x7f31,0x7f32,0x7f33,0x7f34,0x7f35,0x7f36,0x7f37,
+ 0x7f38,0x7f39,0x7f3a,0x7f3b,0x7f3c,0x7f3d,0x7f3e,0x7f3f,
+ 0x7f40,0x7f41,0x7f42,0x7f43,0x7f44,0x7f45,0x7f46,0x7f47,
+ 0x7f48,0x7f49,0x7f4a,0x7f4b,0x7f4c,0x7f4d,0x7f4e,0x7f4f,
+ 0x7f50,0x7f51,0x7f52,0x7f53,0x7f54,0x7f55,0x7f56,0x7f57,
+ 0x7f58,0x7f59,0x7f5a,0x7f5b,0x7f5c,0x7f5d,0x7f5e,0x7f5f,
+ 0x7f60,0x7f61,0x7f62,0x7f63,0x7f64,0x7f65,0x7f66,0x7f67,
+ 0x7f68,0x7f69,0x7f6a,0x7f6b,0x7f6c,0x7f6d,0x7f6e,0x7f6f,
+ 0x7f70,0x7f71,0x7f72,0x7f73,0x7f74,0x7f75,0x7f76,0x7f77,
+ 0x7f78,0x7f79,0x7f7a,0x7f7b,0x7f7c,0x7f7d,0x7f7e,0x7f7f,
+ 0x7f80,0x7f81,0x7f82,0x7f83,0x7f84,0x7f85,0x7f86,0x7f87,
+ 0x7f88,0x7f89,0x7f8a,0x7f8b,0x7f8c,0x7f8d,0x7f8e,0x7f8f,
+ 0x7f90,0x7f91,0x7f92,0x7f93,0x7f94,0x7f95,0x7f96,0x7f97,
+ 0x7f98,0x7f99,0x7f9a,0x7f9b,0x7f9c,0x7f9d,0x7f9e,0x7f9f,
+ 0x7fa0,0x7fa1,0x7fa2,0x7fa3,0x7fa4,0x7fa5,0x7fa6,0x7fa7,
+ 0x7fa8,0x7fa9,0x7faa,0x7fab,0x7fac,0x7fad,0x7fae,0x7faf,
+ 0x7fb0,0x7fb1,0x7fb2,0x7fb3,0x7fb4,0x7fb5,0x7fb6,0x7fb7,
+ 0x7fb8,0x7fb9,0x7fba,0x7fbb,0x7fbc,0x7fbd,0x7fbe,0x7fbf,
+ 0x7fc0,0x7fc1,0x7fc2,0x7fc3,0x7fc4,0x7fc5,0x7fc6,0x7fc7,
+ 0x7fc8,0x7fc9,0x7fca,0x7fcb,0x7fcc,0x7fcd,0x7fce,0x7fcf,
+ 0x7fd0,0x7fd1,0x7fd2,0x7fd3,0x7fd4,0x7fd5,0x7fd6,0x7fd7,
+ 0x7fd8,0x7fd9,0x7fda,0x7fdb,0x7fdc,0x7fdd,0x7fde,0x7fdf,
+ 0x7fe0,0x7fe1,0x7fe2,0x7fe3,0x7fe4,0x7fe5,0x7fe6,0x7fe7,
+ 0x7fe8,0x7fe9,0x7fea,0x7feb,0x7fec,0x7fed,0x7fee,0x7fef,
+ 0x7ff0,0x7ff1,0x7ff2,0x7ff3,0x7ff4,0x7ff5,0x7ff6,0x7ff7,
+ 0x7ff8,0x7ff9,0x7ffa,0x7ffb,0x7ffc,0x7ffd,0x7ffe,0x7fff,
+ 0x8000,0x8001,0x8002,0x8003,0x8004,0x8005,0x8006,0x8007,
+ 0x8008,0x8009,0x800a,0x800b,0x800c,0x800d,0x800e,0x800f,
+ 0x8010,0x8011,0x8012,0x8013,0x8014,0x8015,0x8016,0x8017,
+ 0x8018,0x8019,0x801a,0x801b,0x801c,0x801d,0x801e,0x801f,
+ 0x8020,0x8021,0x8022,0x8023,0x8024,0x8025,0x8026,0x8027,
+ 0x8028,0x8029,0x802a,0x802b,0x802c,0x802d,0x802e,0x802f,
+ 0x8030,0x8031,0x8032,0x8033,0x8034,0x8035,0x8036,0x8037,
+ 0x8038,0x8039,0x803a,0x803b,0x803c,0x803d,0x803e,0x803f,
+ 0x8040,0x8041,0x8042,0x8043,0x8044,0x8045,0x8046,0x8047,
+ 0x8048,0x8049,0x804a,0x804b,0x804c,0x804d,0x804e,0x804f,
+ 0x8050,0x8051,0x8052,0x8053,0x8054,0x8055,0x8056,0x8057,
+ 0x8058,0x8059,0x805a,0x805b,0x805c,0x805d,0x805e,0x805f,
+ 0x8060,0x8061,0x8062,0x8063,0x8064,0x8065,0x8066,0x8067,
+ 0x8068,0x8069,0x806a,0x806b,0x806c,0x806d,0x806e,0x806f,
+ 0x8070,0x8071,0x8072,0x8073,0x8074,0x8075,0x8076,0x8077,
+ 0x8078,0x8079,0x807a,0x807b,0x807c,0x807d,0x807e,0x807f,
+ 0x8080,0x8081,0x8082,0x8083,0x8084,0x8085,0x8086,0x8087,
+ 0x8088,0x8089,0x808a,0x808b,0x808c,0x808d,0x808e,0x808f,
+ 0x8090,0x8091,0x8092,0x8093,0x8094,0x8095,0x8096,0x8097,
+ 0x8098,0x8099,0x809a,0x809b,0x809c,0x809d,0x809e,0x809f,
+ 0x80a0,0x80a1,0x80a2,0x80a3,0x80a4,0x80a5,0x80a6,0x80a7,
+ 0x80a8,0x80a9,0x80aa,0x80ab,0x80ac,0x80ad,0x80ae,0x80af,
+ 0x80b0,0x80b1,0x80b2,0x80b3,0x80b4,0x80b5,0x80b6,0x80b7,
+ 0x80b8,0x80b9,0x80ba,0x80bb,0x80bc,0x80bd,0x80be,0x80bf,
+ 0x80c0,0x80c1,0x80c2,0x80c3,0x80c4,0x80c5,0x80c6,0x80c7,
+ 0x80c8,0x80c9,0x80ca,0x80cb,0x80cc,0x80cd,0x80ce,0x80cf,
+ 0x80d0,0x80d1,0x80d2,0x80d3,0x80d4,0x80d5,0x80d6,0x80d7,
+ 0x80d8,0x80d9,0x80da,0x80db,0x80dc,0x80dd,0x80de,0x80df,
+ 0x80e0,0x80e1,0x80e2,0x80e3,0x80e4,0x80e5,0x80e6,0x80e7,
+ 0x80e8,0x80e9,0x80ea,0x80eb,0x80ec,0x80ed,0x80ee,0x80ef,
+ 0x80f0,0x80f1,0x80f2,0x80f3,0x80f4,0x80f5,0x80f6,0x80f7,
+ 0x80f8,0x80f9,0x80fa,0x80fb,0x80fc,0x80fd,0x80fe,0x80ff,
+ 0x8100,0x8101,0x8102,0x8103,0x8104,0x8105,0x8106,0x8107,
+ 0x8108,0x8109,0x810a,0x810b,0x810c,0x810d,0x810e,0x810f,
+ 0x8110,0x8111,0x8112,0x8113,0x8114,0x8115,0x8116,0x8117,
+ 0x8118,0x8119,0x811a,0x811b,0x811c,0x811d,0x811e,0x811f,
+ 0x8120,0x8121,0x8122,0x8123,0x8124,0x8125,0x8126,0x8127,
+ 0x8128,0x8129,0x812a,0x812b,0x812c,0x812d,0x812e,0x812f,
+ 0x8130,0x8131,0x8132,0x8133,0x8134,0x8135,0x8136,0x8137,
+ 0x8138,0x8139,0x813a,0x813b,0x813c,0x813d,0x813e,0x813f,
+ 0x8140,0x8141,0x8142,0x8143,0x8144,0x8145,0x8146,0x8147,
+ 0x8148,0x8149,0x814a,0x814b,0x814c,0x814d,0x814e,0x814f,
+ 0x8150,0x8151,0x8152,0x8153,0x8154,0x8155,0x8156,0x8157,
+ 0x8158,0x8159,0x815a,0x815b,0x815c,0x815d,0x815e,0x815f,
+ 0x8160,0x8161,0x8162,0x8163,0x8164,0x8165,0x8166,0x8167,
+ 0x8168,0x8169,0x816a,0x816b,0x816c,0x816d,0x816e,0x816f,
+ 0x8170,0x8171,0x8172,0x8173,0x8174,0x8175,0x8176,0x8177,
+ 0x8178,0x8179,0x817a,0x817b,0x817c,0x817d,0x817e,0x817f,
+ 0x8180,0x8181,0x8182,0x8183,0x8184,0x8185,0x8186,0x8187,
+ 0x8188,0x8189,0x818a,0x818b,0x818c,0x818d,0x818e,0x818f,
+ 0x8190,0x8191,0x8192,0x8193,0x8194,0x8195,0x8196,0x8197,
+ 0x8198,0x8199,0x819a,0x819b,0x819c,0x819d,0x819e,0x819f,
+ 0x81a0,0x81a1,0x81a2,0x81a3,0x81a4,0x81a5,0x81a6,0x81a7,
+ 0x81a8,0x81a9,0x81aa,0x81ab,0x81ac,0x81ad,0x81ae,0x81af,
+ 0x81b0,0x81b1,0x81b2,0x81b3,0x81b4,0x81b5,0x81b6,0x81b7,
+ 0x81b8,0x81b9,0x81ba,0x81bb,0x81bc,0x81bd,0x81be,0x81bf,
+ 0x81c0,0x81c1,0x81c2,0x81c3,0x81c4,0x81c5,0x81c6,0x81c7,
+ 0x81c8,0x81c9,0x81ca,0x81cb,0x81cc,0x81cd,0x81ce,0x81cf,
+ 0x81d0,0x81d1,0x81d2,0x81d3,0x81d4,0x81d5,0x81d6,0x81d7,
+ 0x81d8,0x81d9,0x81da,0x81db,0x81dc,0x81dd,0x81de,0x81df,
+ 0x81e0,0x81e1,0x81e2,0x81e3,0x81e4,0x81e5,0x81e6,0x81e7,
+ 0x81e8,0x81e9,0x81ea,0x81eb,0x81ec,0x81ed,0x81ee,0x81ef,
+ 0x81f0,0x81f1,0x81f2,0x81f3,0x81f4,0x81f5,0x81f6,0x81f7,
+ 0x81f8,0x81f9,0x81fa,0x81fb,0x81fc,0x81fd,0x81fe,0x81ff,
+ 0x8200,0x8201,0x8202,0x8203,0x8204,0x8205,0x8206,0x8207,
+ 0x8208,0x8209,0x820a,0x820b,0x820c,0x820d,0x820e,0x820f,
+ 0x8210,0x8211,0x8212,0x8213,0x8214,0x8215,0x8216,0x8217,
+ 0x8218,0x8219,0x821a,0x821b,0x821c,0x821d,0x821e,0x821f,
+ 0x8220,0x8221,0x8222,0x8223,0x8224,0x8225,0x8226,0x8227,
+ 0x8228,0x8229,0x822a,0x822b,0x822c,0x822d,0x822e,0x822f,
+ 0x8230,0x8231,0x8232,0x8233,0x8234,0x8235,0x8236,0x8237,
+ 0x8238,0x8239,0x823a,0x823b,0x823c,0x823d,0x823e,0x823f,
+ 0x8240,0x8241,0x8242,0x8243,0x8244,0x8245,0x8246,0x8247,
+ 0x8248,0x8249,0x824a,0x824b,0x824c,0x824d,0x824e,0x824f,
+ 0x8250,0x8251,0x8252,0x8253,0x8254,0x8255,0x8256,0x8257,
+ 0x8258,0x8259,0x825a,0x825b,0x825c,0x825d,0x825e,0x825f,
+ 0x8260,0x8261,0x8262,0x8263,0x8264,0x8265,0x8266,0x8267,
+ 0x8268,0x8269,0x826a,0x826b,0x826c,0x826d,0x826e,0x826f,
+ 0x8270,0x8271,0x8272,0x8273,0x8274,0x8275,0x8276,0x8277,
+ 0x8278,0x8279,0x827a,0x827b,0x827c,0x827d,0x827e,0x827f,
+ 0x8280,0x8281,0x8282,0x8283,0x8284,0x8285,0x8286,0x8287,
+ 0x8288,0x8289,0x828a,0x828b,0x828c,0x828d,0x828e,0x828f,
+ 0x8290,0x8291,0x8292,0x8293,0x8294,0x8295,0x8296,0x8297,
+ 0x8298,0x8299,0x829a,0x829b,0x829c,0x829d,0x829e,0x829f,
+ 0x82a0,0x82a1,0x82a2,0x82a3,0x82a4,0x82a5,0x82a6,0x82a7,
+ 0x82a8,0x82a9,0x82aa,0x82ab,0x82ac,0x82ad,0x82ae,0x82af,
+ 0x82b0,0x82b1,0x82b2,0x82b3,0x82b4,0x82b5,0x82b6,0x82b7,
+ 0x82b8,0x82b9,0x82ba,0x82bb,0x82bc,0x82bd,0x82be,0x82bf,
+ 0x82c0,0x82c1,0x82c2,0x82c3,0x82c4,0x82c5,0x82c6,0x82c7,
+ 0x82c8,0x82c9,0x82ca,0x82cb,0x82cc,0x82cd,0x82ce,0x82cf,
+ 0x82d0,0x82d1,0x82d2,0x82d3,0x82d4,0x82d5,0x82d6,0x82d7,
+ 0x82d8,0x82d9,0x82da,0x82db,0x82dc,0x82dd,0x82de,0x82df,
+ 0x82e0,0x82e1,0x82e2,0x82e3,0x82e4,0x82e5,0x82e6,0x82e7,
+ 0x82e8,0x82e9,0x82ea,0x82eb,0x82ec,0x82ed,0x82ee,0x82ef,
+ 0x82f0,0x82f1,0x82f2,0x82f3,0x82f4,0x82f5,0x82f6,0x82f7,
+ 0x82f8,0x82f9,0x82fa,0x82fb,0x82fc,0x82fd,0x82fe,0x82ff,
+ 0x8300,0x8301,0x8302,0x8303,0x8304,0x8305,0x8306,0x8307,
+ 0x8308,0x8309,0x830a,0x830b,0x830c,0x830d,0x830e,0x830f,
+ 0x8310,0x8311,0x8312,0x8313,0x8314,0x8315,0x8316,0x8317,
+ 0x8318,0x8319,0x831a,0x831b,0x831c,0x831d,0x831e,0x831f,
+ 0x8320,0x8321,0x8322,0x8323,0x8324,0x8325,0x8326,0x8327,
+ 0x8328,0x8329,0x832a,0x832b,0x832c,0x832d,0x832e,0x832f,
+ 0x8330,0x8331,0x8332,0x8333,0x8334,0x8335,0x8336,0x8337,
+ 0x8338,0x8339,0x833a,0x833b,0x833c,0x833d,0x833e,0x833f,
+ 0x8340,0x8341,0x8342,0x8343,0x8344,0x8345,0x8346,0x8347,
+ 0x8348,0x8349,0x834a,0x834b,0x834c,0x834d,0x834e,0x834f,
+ 0x8350,0x8351,0x8352,0x8353,0x8354,0x8355,0x8356,0x8357,
+ 0x8358,0x8359,0x835a,0x835b,0x835c,0x835d,0x835e,0x835f,
+ 0x8360,0x8361,0x8362,0x8363,0x8364,0x8365,0x8366,0x8367,
+ 0x8368,0x8369,0x836a,0x836b,0x836c,0x836d,0x836e,0x836f,
+ 0x8370,0x8371,0x8372,0x8373,0x8374,0x8375,0x8376,0x8377,
+ 0x8378,0x8379,0x837a,0x837b,0x837c,0x837d,0x837e,0x837f,
+ 0x8380,0x8381,0x8382,0x8383,0x8384,0x8385,0x8386,0x8387,
+ 0x8388,0x8389,0x838a,0x838b,0x838c,0x838d,0x838e,0x838f,
+ 0x8390,0x8391,0x8392,0x8393,0x8394,0x8395,0x8396,0x8397,
+ 0x8398,0x8399,0x839a,0x839b,0x839c,0x839d,0x839e,0x839f,
+ 0x83a0,0x83a1,0x83a2,0x83a3,0x83a4,0x83a5,0x83a6,0x83a7,
+ 0x83a8,0x83a9,0x83aa,0x83ab,0x83ac,0x83ad,0x83ae,0x83af,
+ 0x83b0,0x83b1,0x83b2,0x83b3,0x83b4,0x83b5,0x83b6,0x83b7,
+ 0x83b8,0x83b9,0x83ba,0x83bb,0x83bc,0x83bd,0x83be,0x83bf,
+ 0x83c0,0x83c1,0x83c2,0x83c3,0x83c4,0x83c5,0x83c6,0x83c7,
+ 0x83c8,0x83c9,0x83ca,0x83cb,0x83cc,0x83cd,0x83ce,0x83cf,
+ 0x83d0,0x83d1,0x83d2,0x83d3,0x83d4,0x83d5,0x83d6,0x83d7,
+ 0x83d8,0x83d9,0x83da,0x83db,0x83dc,0x83dd,0x83de,0x83df,
+ 0x83e0,0x83e1,0x83e2,0x83e3,0x83e4,0x83e5,0x83e6,0x83e7,
+ 0x83e8,0x83e9,0x83ea,0x83eb,0x83ec,0x83ed,0x83ee,0x83ef,
+ 0x83f0,0x83f1,0x83f2,0x83f3,0x83f4,0x83f5,0x83f6,0x83f7,
+ 0x83f8,0x83f9,0x83fa,0x83fb,0x83fc,0x83fd,0x83fe,0x83ff,
+ 0x8400,0x8401,0x8402,0x8403,0x8404,0x8405,0x8406,0x8407,
+ 0x8408,0x8409,0x840a,0x840b,0x840c,0x840d,0x840e,0x840f,
+ 0x8410,0x8411,0x8412,0x8413,0x8414,0x8415,0x8416,0x8417,
+ 0x8418,0x8419,0x841a,0x841b,0x841c,0x841d,0x841e,0x841f,
+ 0x8420,0x8421,0x8422,0x8423,0x8424,0x8425,0x8426,0x8427,
+ 0x8428,0x8429,0x842a,0x842b,0x842c,0x842d,0x842e,0x842f,
+ 0x8430,0x8431,0x8432,0x8433,0x8434,0x8435,0x8436,0x8437,
+ 0x8438,0x8439,0x843a,0x843b,0x843c,0x843d,0x843e,0x843f,
+ 0x8440,0x8441,0x8442,0x8443,0x8444,0x8445,0x8446,0x8447,
+ 0x8448,0x8449,0x844a,0x844b,0x844c,0x844d,0x844e,0x844f,
+ 0x8450,0x8451,0x8452,0x8453,0x8454,0x8455,0x8456,0x8457,
+ 0x8458,0x8459,0x845a,0x845b,0x845c,0x845d,0x845e,0x845f,
+ 0x8460,0x8461,0x8462,0x8463,0x8464,0x8465,0x8466,0x8467,
+ 0x8468,0x8469,0x846a,0x846b,0x846c,0x846d,0x846e,0x846f,
+ 0x8470,0x8471,0x8472,0x8473,0x8474,0x8475,0x8476,0x8477,
+ 0x8478,0x8479,0x847a,0x847b,0x847c,0x847d,0x847e,0x847f,
+ 0x8480,0x8481,0x8482,0x8483,0x8484,0x8485,0x8486,0x8487,
+ 0x8488,0x8489,0x848a,0x848b,0x848c,0x848d,0x848e,0x848f,
+ 0x8490,0x8491,0x8492,0x8493,0x8494,0x8495,0x8496,0x8497,
+ 0x8498,0x8499,0x849a,0x849b,0x849c,0x849d,0x849e,0x849f,
+ 0x84a0,0x84a1,0x84a2,0x84a3,0x84a4,0x84a5,0x84a6,0x84a7,
+ 0x84a8,0x84a9,0x84aa,0x84ab,0x84ac,0x84ad,0x84ae,0x84af,
+ 0x84b0,0x84b1,0x84b2,0x84b3,0x84b4,0x84b5,0x84b6,0x84b7,
+ 0x84b8,0x84b9,0x84ba,0x84bb,0x84bc,0x84bd,0x84be,0x84bf,
+ 0x84c0,0x84c1,0x84c2,0x84c3,0x84c4,0x84c5,0x84c6,0x84c7,
+ 0x84c8,0x84c9,0x84ca,0x84cb,0x84cc,0x84cd,0x84ce,0x84cf,
+ 0x84d0,0x84d1,0x84d2,0x84d3,0x84d4,0x84d5,0x84d6,0x84d7,
+ 0x84d8,0x84d9,0x84da,0x84db,0x84dc,0x84dd,0x84de,0x84df,
+ 0x84e0,0x84e1,0x84e2,0x84e3,0x84e4,0x84e5,0x84e6,0x84e7,
+ 0x84e8,0x84e9,0x84ea,0x84eb,0x84ec,0x84ed,0x84ee,0x84ef,
+ 0x84f0,0x84f1,0x84f2,0x84f3,0x84f4,0x84f5,0x84f6,0x84f7,
+ 0x84f8,0x84f9,0x84fa,0x84fb,0x84fc,0x84fd,0x84fe,0x84ff,
+ 0x8500,0x8501,0x8502,0x8503,0x8504,0x8505,0x8506,0x8507,
+ 0x8508,0x8509,0x850a,0x850b,0x850c,0x850d,0x850e,0x850f,
+ 0x8510,0x8511,0x8512,0x8513,0x8514,0x8515,0x8516,0x8517,
+ 0x8518,0x8519,0x851a,0x851b,0x851c,0x851d,0x851e,0x851f,
+ 0x8520,0x8521,0x8522,0x8523,0x8524,0x8525,0x8526,0x8527,
+ 0x8528,0x8529,0x852a,0x852b,0x852c,0x852d,0x852e,0x852f,
+ 0x8530,0x8531,0x8532,0x8533,0x8534,0x8535,0x8536,0x8537,
+ 0x8538,0x8539,0x853a,0x853b,0x853c,0x853d,0x853e,0x853f,
+ 0x8540,0x8541,0x8542,0x8543,0x8544,0x8545,0x8546,0x8547,
+ 0x8548,0x8549,0x854a,0x854b,0x854c,0x854d,0x854e,0x854f,
+ 0x8550,0x8551,0x8552,0x8553,0x8554,0x8555,0x8556,0x8557,
+ 0x8558,0x8559,0x855a,0x855b,0x855c,0x855d,0x855e,0x855f,
+ 0x8560,0x8561,0x8562,0x8563,0x8564,0x8565,0x8566,0x8567,
+ 0x8568,0x8569,0x856a,0x856b,0x856c,0x856d,0x856e,0x856f,
+ 0x8570,0x8571,0x8572,0x8573,0x8574,0x8575,0x8576,0x8577,
+ 0x8578,0x8579,0x857a,0x857b,0x857c,0x857d,0x857e,0x857f,
+ 0x8580,0x8581,0x8582,0x8583,0x8584,0x8585,0x8586,0x8587,
+ 0x8588,0x8589,0x858a,0x858b,0x858c,0x858d,0x858e,0x858f,
+ 0x8590,0x8591,0x8592,0x8593,0x8594,0x8595,0x8596,0x8597,
+ 0x8598,0x8599,0x859a,0x859b,0x859c,0x859d,0x859e,0x859f,
+ 0x85a0,0x85a1,0x85a2,0x85a3,0x85a4,0x85a5,0x85a6,0x85a7,
+ 0x85a8,0x85a9,0x85aa,0x85ab,0x85ac,0x85ad,0x85ae,0x85af,
+ 0x85b0,0x85b1,0x85b2,0x85b3,0x85b4,0x85b5,0x85b6,0x85b7,
+ 0x85b8,0x85b9,0x85ba,0x85bb,0x85bc,0x85bd,0x85be,0x85bf,
+ 0x85c0,0x85c1,0x85c2,0x85c3,0x85c4,0x85c5,0x85c6,0x85c7,
+ 0x85c8,0x85c9,0x85ca,0x85cb,0x85cc,0x85cd,0x85ce,0x85cf,
+ 0x85d0,0x85d1,0x85d2,0x85d3,0x85d4,0x85d5,0x85d6,0x85d7,
+ 0x85d8,0x85d9,0x85da,0x85db,0x85dc,0x85dd,0x85de,0x85df,
+ 0x85e0,0x85e1,0x85e2,0x85e3,0x85e4,0x85e5,0x85e6,0x85e7,
+ 0x85e8,0x85e9,0x85ea,0x85eb,0x85ec,0x85ed,0x85ee,0x85ef,
+ 0x85f0,0x85f1,0x85f2,0x85f3,0x85f4,0x85f5,0x85f6,0x85f7,
+ 0x85f8,0x85f9,0x85fa,0x85fb,0x85fc,0x85fd,0x85fe,0x85ff,
+ 0x8600,0x8601,0x8602,0x8603,0x8604,0x8605,0x8606,0x8607,
+ 0x8608,0x8609,0x860a,0x860b,0x860c,0x860d,0x860e,0x860f,
+ 0x8610,0x8611,0x8612,0x8613,0x8614,0x8615,0x8616,0x8617,
+ 0x8618,0x8619,0x861a,0x861b,0x861c,0x861d,0x861e,0x861f,
+ 0x8620,0x8621,0x8622,0x8623,0x8624,0x8625,0x8626,0x8627,
+ 0x8628,0x8629,0x862a,0x862b,0x862c,0x862d,0x862e,0x862f,
+ 0x8630,0x8631,0x8632,0x8633,0x8634,0x8635,0x8636,0x8637,
+ 0x8638,0x8639,0x863a,0x863b,0x863c,0x863d,0x863e,0x863f,
+ 0x8640,0x8641,0x8642,0x8643,0x8644,0x8645,0x8646,0x8647,
+ 0x8648,0x8649,0x864a,0x864b,0x864c,0x864d,0x864e,0x864f,
+ 0x8650,0x8651,0x8652,0x8653,0x8654,0x8655,0x8656,0x8657,
+ 0x8658,0x8659,0x865a,0x865b,0x865c,0x865d,0x865e,0x865f,
+ 0x8660,0x8661,0x8662,0x8663,0x8664,0x8665,0x8666,0x8667,
+ 0x8668,0x8669,0x866a,0x866b,0x866c,0x866d,0x866e,0x866f,
+ 0x8670,0x8671,0x8672,0x8673,0x8674,0x8675,0x8676,0x8677,
+ 0x8678,0x8679,0x867a,0x867b,0x867c,0x867d,0x867e,0x867f,
+ 0x8680,0x8681,0x8682,0x8683,0x8684,0x8685,0x8686,0x8687,
+ 0x8688,0x8689,0x868a,0x868b,0x868c,0x868d,0x868e,0x868f,
+ 0x8690,0x8691,0x8692,0x8693,0x8694,0x8695,0x8696,0x8697,
+ 0x8698,0x8699,0x869a,0x869b,0x869c,0x869d,0x869e,0x869f,
+ 0x86a0,0x86a1,0x86a2,0x86a3,0x86a4,0x86a5,0x86a6,0x86a7,
+ 0x86a8,0x86a9,0x86aa,0x86ab,0x86ac,0x86ad,0x86ae,0x86af,
+ 0x86b0,0x86b1,0x86b2,0x86b3,0x86b4,0x86b5,0x86b6,0x86b7,
+ 0x86b8,0x86b9,0x86ba,0x86bb,0x86bc,0x86bd,0x86be,0x86bf,
+ 0x86c0,0x86c1,0x86c2,0x86c3,0x86c4,0x86c5,0x86c6,0x86c7,
+ 0x86c8,0x86c9,0x86ca,0x86cb,0x86cc,0x86cd,0x86ce,0x86cf,
+ 0x86d0,0x86d1,0x86d2,0x86d3,0x86d4,0x86d5,0x86d6,0x86d7,
+ 0x86d8,0x86d9,0x86da,0x86db,0x86dc,0x86dd,0x86de,0x86df,
+ 0x86e0,0x86e1,0x86e2,0x86e3,0x86e4,0x86e5,0x86e6,0x86e7,
+ 0x86e8,0x86e9,0x86ea,0x86eb,0x86ec,0x86ed,0x86ee,0x86ef,
+ 0x86f0,0x86f1,0x86f2,0x86f3,0x86f4,0x86f5,0x86f6,0x86f7,
+ 0x86f8,0x86f9,0x86fa,0x86fb,0x86fc,0x86fd,0x86fe,0x86ff,
+ 0x8700,0x8701,0x8702,0x8703,0x8704,0x8705,0x8706,0x8707,
+ 0x8708,0x8709,0x870a,0x870b,0x870c,0x870d,0x870e,0x870f,
+ 0x8710,0x8711,0x8712,0x8713,0x8714,0x8715,0x8716,0x8717,
+ 0x8718,0x8719,0x871a,0x871b,0x871c,0x871d,0x871e,0x871f,
+ 0x8720,0x8721,0x8722,0x8723,0x8724,0x8725,0x8726,0x8727,
+ 0x8728,0x8729,0x872a,0x872b,0x872c,0x872d,0x872e,0x872f,
+ 0x8730,0x8731,0x8732,0x8733,0x8734,0x8735,0x8736,0x8737,
+ 0x8738,0x8739,0x873a,0x873b,0x873c,0x873d,0x873e,0x873f,
+ 0x8740,0x8741,0x8742,0x8743,0x8744,0x8745,0x8746,0x8747,
+ 0x8748,0x8749,0x874a,0x874b,0x874c,0x874d,0x874e,0x874f,
+ 0x8750,0x8751,0x8752,0x8753,0x8754,0x8755,0x8756,0x8757,
+ 0x8758,0x8759,0x875a,0x875b,0x875c,0x875d,0x875e,0x875f,
+ 0x8760,0x8761,0x8762,0x8763,0x8764,0x8765,0x8766,0x8767,
+ 0x8768,0x8769,0x876a,0x876b,0x876c,0x876d,0x876e,0x876f,
+ 0x8770,0x8771,0x8772,0x8773,0x8774,0x8775,0x8776,0x8777,
+ 0x8778,0x8779,0x877a,0x877b,0x877c,0x877d,0x877e,0x877f,
+ 0x8780,0x8781,0x8782,0x8783,0x8784,0x8785,0x8786,0x8787,
+ 0x8788,0x8789,0x878a,0x878b,0x878c,0x878d,0x878e,0x878f,
+ 0x8790,0x8791,0x8792,0x8793,0x8794,0x8795,0x8796,0x8797,
+ 0x8798,0x8799,0x879a,0x879b,0x879c,0x879d,0x879e,0x879f,
+ 0x87a0,0x87a1,0x87a2,0x87a3,0x87a4,0x87a5,0x87a6,0x87a7,
+ 0x87a8,0x87a9,0x87aa,0x87ab,0x87ac,0x87ad,0x87ae,0x87af,
+ 0x87b0,0x87b1,0x87b2,0x87b3,0x87b4,0x87b5,0x87b6,0x87b7,
+ 0x87b8,0x87b9,0x87ba,0x87bb,0x87bc,0x87bd,0x87be,0x87bf,
+ 0x87c0,0x87c1,0x87c2,0x87c3,0x87c4,0x87c5,0x87c6,0x87c7,
+ 0x87c8,0x87c9,0x87ca,0x87cb,0x87cc,0x87cd,0x87ce,0x87cf,
+ 0x87d0,0x87d1,0x87d2,0x87d3,0x87d4,0x87d5,0x87d6,0x87d7,
+ 0x87d8,0x87d9,0x87da,0x87db,0x87dc,0x87dd,0x87de,0x87df,
+ 0x87e0,0x87e1,0x87e2,0x87e3,0x87e4,0x87e5,0x87e6,0x87e7,
+ 0x87e8,0x87e9,0x87ea,0x87eb,0x87ec,0x87ed,0x87ee,0x87ef,
+ 0x87f0,0x87f1,0x87f2,0x87f3,0x87f4,0x87f5,0x87f6,0x87f7,
+ 0x87f8,0x87f9,0x87fa,0x87fb,0x87fc,0x87fd,0x87fe,0x87ff,
+ 0x8800,0x8801,0x8802,0x8803,0x8804,0x8805,0x8806,0x8807,
+ 0x8808,0x8809,0x880a,0x880b,0x880c,0x880d,0x880e,0x880f,
+ 0x8810,0x8811,0x8812,0x8813,0x8814,0x8815,0x8816,0x8817,
+ 0x8818,0x8819,0x881a,0x881b,0x881c,0x881d,0x881e,0x881f,
+ 0x8820,0x8821,0x8822,0x8823,0x8824,0x8825,0x8826,0x8827,
+ 0x8828,0x8829,0x882a,0x882b,0x882c,0x882d,0x882e,0x882f,
+ 0x8830,0x8831,0x8832,0x8833,0x8834,0x8835,0x8836,0x8837,
+ 0x8838,0x8839,0x883a,0x883b,0x883c,0x883d,0x883e,0x883f,
+ 0x8840,0x8841,0x8842,0x8843,0x8844,0x8845,0x8846,0x8847,
+ 0x8848,0x8849,0x884a,0x884b,0x884c,0x884d,0x884e,0x884f,
+ 0x8850,0x8851,0x8852,0x8853,0x8854,0x8855,0x8856,0x8857,
+ 0x8858,0x8859,0x885a,0x885b,0x885c,0x885d,0x885e,0x885f,
+ 0x8860,0x8861,0x8862,0x8863,0x8864,0x8865,0x8866,0x8867,
+ 0x8868,0x8869,0x886a,0x886b,0x886c,0x886d,0x886e,0x886f,
+ 0x8870,0x8871,0x8872,0x8873,0x8874,0x8875,0x8876,0x8877,
+ 0x8878,0x8879,0x887a,0x887b,0x887c,0x887d,0x887e,0x887f,
+ 0x8880,0x8881,0x8882,0x8883,0x8884,0x8885,0x8886,0x8887,
+ 0x8888,0x8889,0x888a,0x888b,0x888c,0x888d,0x888e,0x888f,
+ 0x8890,0x8891,0x8892,0x8893,0x8894,0x8895,0x8896,0x8897,
+ 0x8898,0x8899,0x889a,0x889b,0x889c,0x889d,0x889e,0x889f,
+ 0x88a0,0x88a1,0x88a2,0x88a3,0x88a4,0x88a5,0x88a6,0x88a7,
+ 0x88a8,0x88a9,0x88aa,0x88ab,0x88ac,0x88ad,0x88ae,0x88af,
+ 0x88b0,0x88b1,0x88b2,0x88b3,0x88b4,0x88b5,0x88b6,0x88b7,
+ 0x88b8,0x88b9,0x88ba,0x88bb,0x88bc,0x88bd,0x88be,0x88bf,
+ 0x88c0,0x88c1,0x88c2,0x88c3,0x88c4,0x88c5,0x88c6,0x88c7,
+ 0x88c8,0x88c9,0x88ca,0x88cb,0x88cc,0x88cd,0x88ce,0x88cf,
+ 0x88d0,0x88d1,0x88d2,0x88d3,0x88d4,0x88d5,0x88d6,0x88d7,
+ 0x88d8,0x88d9,0x88da,0x88db,0x88dc,0x88dd,0x88de,0x88df,
+ 0x88e0,0x88e1,0x88e2,0x88e3,0x88e4,0x88e5,0x88e6,0x88e7,
+ 0x88e8,0x88e9,0x88ea,0x88eb,0x88ec,0x88ed,0x88ee,0x88ef,
+ 0x88f0,0x88f1,0x88f2,0x88f3,0x88f4,0x88f5,0x88f6,0x88f7,
+ 0x88f8,0x88f9,0x88fa,0x88fb,0x88fc,0x88fd,0x88fe,0x88ff,
+ 0x8900,0x8901,0x8902,0x8903,0x8904,0x8905,0x8906,0x8907,
+ 0x8908,0x8909,0x890a,0x890b,0x890c,0x890d,0x890e,0x890f,
+ 0x8910,0x8911,0x8912,0x8913,0x8914,0x8915,0x8916,0x8917,
+ 0x8918,0x8919,0x891a,0x891b,0x891c,0x891d,0x891e,0x891f,
+ 0x8920,0x8921,0x8922,0x8923,0x8924,0x8925,0x8926,0x8927,
+ 0x8928,0x8929,0x892a,0x892b,0x892c,0x892d,0x892e,0x892f,
+ 0x8930,0x8931,0x8932,0x8933,0x8934,0x8935,0x8936,0x8937,
+ 0x8938,0x8939,0x893a,0x893b,0x893c,0x893d,0x893e,0x893f,
+ 0x8940,0x8941,0x8942,0x8943,0x8944,0x8945,0x8946,0x8947,
+ 0x8948,0x8949,0x894a,0x894b,0x894c,0x894d,0x894e,0x894f,
+ 0x8950,0x8951,0x8952,0x8953,0x8954,0x8955,0x8956,0x8957,
+ 0x8958,0x8959,0x895a,0x895b,0x895c,0x895d,0x895e,0x895f,
+ 0x8960,0x8961,0x8962,0x8963,0x8964,0x8965,0x8966,0x8967,
+ 0x8968,0x8969,0x896a,0x896b,0x896c,0x896d,0x896e,0x896f,
+ 0x8970,0x8971,0x8972,0x8973,0x8974,0x8975,0x8976,0x8977,
+ 0x8978,0x8979,0x897a,0x897b,0x897c,0x897d,0x897e,0x897f,
+ 0x8980,0x8981,0x8982,0x8983,0x8984,0x8985,0x8986,0x8987,
+ 0x8988,0x8989,0x898a,0x898b,0x898c,0x898d,0x898e,0x898f,
+ 0x8990,0x8991,0x8992,0x8993,0x8994,0x8995,0x8996,0x8997,
+ 0x8998,0x8999,0x899a,0x899b,0x899c,0x899d,0x899e,0x899f,
+ 0x89a0,0x89a1,0x89a2,0x89a3,0x89a4,0x89a5,0x89a6,0x89a7,
+ 0x89a8,0x89a9,0x89aa,0x89ab,0x89ac,0x89ad,0x89ae,0x89af,
+ 0x89b0,0x89b1,0x89b2,0x89b3,0x89b4,0x89b5,0x89b6,0x89b7,
+ 0x89b8,0x89b9,0x89ba,0x89bb,0x89bc,0x89bd,0x89be,0x89bf,
+ 0x89c0,0x89c1,0x89c2,0x89c3,0x89c4,0x89c5,0x89c6,0x89c7,
+ 0x89c8,0x89c9,0x89ca,0x89cb,0x89cc,0x89cd,0x89ce,0x89cf,
+ 0x89d0,0x89d1,0x89d2,0x89d3,0x89d4,0x89d5,0x89d6,0x89d7,
+ 0x89d8,0x89d9,0x89da,0x89db,0x89dc,0x89dd,0x89de,0x89df,
+ 0x89e0,0x89e1,0x89e2,0x89e3,0x89e4,0x89e5,0x89e6,0x89e7,
+ 0x89e8,0x89e9,0x89ea,0x89eb,0x89ec,0x89ed,0x89ee,0x89ef,
+ 0x89f0,0x89f1,0x89f2,0x89f3,0x89f4,0x89f5,0x89f6,0x89f7,
+ 0x89f8,0x89f9,0x89fa,0x89fb,0x89fc,0x89fd,0x89fe,0x89ff,
+ 0x8a00,0x8a01,0x8a02,0x8a03,0x8a04,0x8a05,0x8a06,0x8a07,
+ 0x8a08,0x8a09,0x8a0a,0x8a0b,0x8a0c,0x8a0d,0x8a0e,0x8a0f,
+ 0x8a10,0x8a11,0x8a12,0x8a13,0x8a14,0x8a15,0x8a16,0x8a17,
+ 0x8a18,0x8a19,0x8a1a,0x8a1b,0x8a1c,0x8a1d,0x8a1e,0x8a1f,
+ 0x8a20,0x8a21,0x8a22,0x8a23,0x8a24,0x8a25,0x8a26,0x8a27,
+ 0x8a28,0x8a29,0x8a2a,0x8a2b,0x8a2c,0x8a2d,0x8a2e,0x8a2f,
+ 0x8a30,0x8a31,0x8a32,0x8a33,0x8a34,0x8a35,0x8a36,0x8a37,
+ 0x8a38,0x8a39,0x8a3a,0x8a3b,0x8a3c,0x8a3d,0x8a3e,0x8a3f,
+ 0x8a40,0x8a41,0x8a42,0x8a43,0x8a44,0x8a45,0x8a46,0x8a47,
+ 0x8a48,0x8a49,0x8a4a,0x8a4b,0x8a4c,0x8a4d,0x8a4e,0x8a4f,
+ 0x8a50,0x8a51,0x8a52,0x8a53,0x8a54,0x8a55,0x8a56,0x8a57,
+ 0x8a58,0x8a59,0x8a5a,0x8a5b,0x8a5c,0x8a5d,0x8a5e,0x8a5f,
+ 0x8a60,0x8a61,0x8a62,0x8a63,0x8a64,0x8a65,0x8a66,0x8a67,
+ 0x8a68,0x8a69,0x8a6a,0x8a6b,0x8a6c,0x8a6d,0x8a6e,0x8a6f,
+ 0x8a70,0x8a71,0x8a72,0x8a73,0x8a74,0x8a75,0x8a76,0x8a77,
+ 0x8a78,0x8a79,0x8a7a,0x8a7b,0x8a7c,0x8a7d,0x8a7e,0x8a7f,
+ 0x8a80,0x8a81,0x8a82,0x8a83,0x8a84,0x8a85,0x8a86,0x8a87,
+ 0x8a88,0x8a89,0x8a8a,0x8a8b,0x8a8c,0x8a8d,0x8a8e,0x8a8f,
+ 0x8a90,0x8a91,0x8a92,0x8a93,0x8a94,0x8a95,0x8a96,0x8a97,
+ 0x8a98,0x8a99,0x8a9a,0x8a9b,0x8a9c,0x8a9d,0x8a9e,0x8a9f,
+ 0x8aa0,0x8aa1,0x8aa2,0x8aa3,0x8aa4,0x8aa5,0x8aa6,0x8aa7,
+ 0x8aa8,0x8aa9,0x8aaa,0x8aab,0x8aac,0x8aad,0x8aae,0x8aaf,
+ 0x8ab0,0x8ab1,0x8ab2,0x8ab3,0x8ab4,0x8ab5,0x8ab6,0x8ab7,
+ 0x8ab8,0x8ab9,0x8aba,0x8abb,0x8abc,0x8abd,0x8abe,0x8abf,
+ 0x8ac0,0x8ac1,0x8ac2,0x8ac3,0x8ac4,0x8ac5,0x8ac6,0x8ac7,
+ 0x8ac8,0x8ac9,0x8aca,0x8acb,0x8acc,0x8acd,0x8ace,0x8acf,
+ 0x8ad0,0x8ad1,0x8ad2,0x8ad3,0x8ad4,0x8ad5,0x8ad6,0x8ad7,
+ 0x8ad8,0x8ad9,0x8ada,0x8adb,0x8adc,0x8add,0x8ade,0x8adf,
+ 0x8ae0,0x8ae1,0x8ae2,0x8ae3,0x8ae4,0x8ae5,0x8ae6,0x8ae7,
+ 0x8ae8,0x8ae9,0x8aea,0x8aeb,0x8aec,0x8aed,0x8aee,0x8aef,
+ 0x8af0,0x8af1,0x8af2,0x8af3,0x8af4,0x8af5,0x8af6,0x8af7,
+ 0x8af8,0x8af9,0x8afa,0x8afb,0x8afc,0x8afd,0x8afe,0x8aff,
+ 0x8b00,0x8b01,0x8b02,0x8b03,0x8b04,0x8b05,0x8b06,0x8b07,
+ 0x8b08,0x8b09,0x8b0a,0x8b0b,0x8b0c,0x8b0d,0x8b0e,0x8b0f,
+ 0x8b10,0x8b11,0x8b12,0x8b13,0x8b14,0x8b15,0x8b16,0x8b17,
+ 0x8b18,0x8b19,0x8b1a,0x8b1b,0x8b1c,0x8b1d,0x8b1e,0x8b1f,
+ 0x8b20,0x8b21,0x8b22,0x8b23,0x8b24,0x8b25,0x8b26,0x8b27,
+ 0x8b28,0x8b29,0x8b2a,0x8b2b,0x8b2c,0x8b2d,0x8b2e,0x8b2f,
+ 0x8b30,0x8b31,0x8b32,0x8b33,0x8b34,0x8b35,0x8b36,0x8b37,
+ 0x8b38,0x8b39,0x8b3a,0x8b3b,0x8b3c,0x8b3d,0x8b3e,0x8b3f,
+ 0x8b40,0x8b41,0x8b42,0x8b43,0x8b44,0x8b45,0x8b46,0x8b47,
+ 0x8b48,0x8b49,0x8b4a,0x8b4b,0x8b4c,0x8b4d,0x8b4e,0x8b4f,
+ 0x8b50,0x8b51,0x8b52,0x8b53,0x8b54,0x8b55,0x8b56,0x8b57,
+ 0x8b58,0x8b59,0x8b5a,0x8b5b,0x8b5c,0x8b5d,0x8b5e,0x8b5f,
+ 0x8b60,0x8b61,0x8b62,0x8b63,0x8b64,0x8b65,0x8b66,0x8b67,
+ 0x8b68,0x8b69,0x8b6a,0x8b6b,0x8b6c,0x8b6d,0x8b6e,0x8b6f,
+ 0x8b70,0x8b71,0x8b72,0x8b73,0x8b74,0x8b75,0x8b76,0x8b77,
+ 0x8b78,0x8b79,0x8b7a,0x8b7b,0x8b7c,0x8b7d,0x8b7e,0x8b7f,
+ 0x8b80,0x8b81,0x8b82,0x8b83,0x8b84,0x8b85,0x8b86,0x8b87,
+ 0x8b88,0x8b89,0x8b8a,0x8b8b,0x8b8c,0x8b8d,0x8b8e,0x8b8f,
+ 0x8b90,0x8b91,0x8b92,0x8b93,0x8b94,0x8b95,0x8b96,0x8b97,
+ 0x8b98,0x8b99,0x8b9a,0x8b9b,0x8b9c,0x8b9d,0x8b9e,0x8b9f,
+ 0x8ba0,0x8ba1,0x8ba2,0x8ba3,0x8ba4,0x8ba5,0x8ba6,0x8ba7,
+ 0x8ba8,0x8ba9,0x8baa,0x8bab,0x8bac,0x8bad,0x8bae,0x8baf,
+ 0x8bb0,0x8bb1,0x8bb2,0x8bb3,0x8bb4,0x8bb5,0x8bb6,0x8bb7,
+ 0x8bb8,0x8bb9,0x8bba,0x8bbb,0x8bbc,0x8bbd,0x8bbe,0x8bbf,
+ 0x8bc0,0x8bc1,0x8bc2,0x8bc3,0x8bc4,0x8bc5,0x8bc6,0x8bc7,
+ 0x8bc8,0x8bc9,0x8bca,0x8bcb,0x8bcc,0x8bcd,0x8bce,0x8bcf,
+ 0x8bd0,0x8bd1,0x8bd2,0x8bd3,0x8bd4,0x8bd5,0x8bd6,0x8bd7,
+ 0x8bd8,0x8bd9,0x8bda,0x8bdb,0x8bdc,0x8bdd,0x8bde,0x8bdf,
+ 0x8be0,0x8be1,0x8be2,0x8be3,0x8be4,0x8be5,0x8be6,0x8be7,
+ 0x8be8,0x8be9,0x8bea,0x8beb,0x8bec,0x8bed,0x8bee,0x8bef,
+ 0x8bf0,0x8bf1,0x8bf2,0x8bf3,0x8bf4,0x8bf5,0x8bf6,0x8bf7,
+ 0x8bf8,0x8bf9,0x8bfa,0x8bfb,0x8bfc,0x8bfd,0x8bfe,0x8bff,
+ 0x8c00,0x8c01,0x8c02,0x8c03,0x8c04,0x8c05,0x8c06,0x8c07,
+ 0x8c08,0x8c09,0x8c0a,0x8c0b,0x8c0c,0x8c0d,0x8c0e,0x8c0f,
+ 0x8c10,0x8c11,0x8c12,0x8c13,0x8c14,0x8c15,0x8c16,0x8c17,
+ 0x8c18,0x8c19,0x8c1a,0x8c1b,0x8c1c,0x8c1d,0x8c1e,0x8c1f,
+ 0x8c20,0x8c21,0x8c22,0x8c23,0x8c24,0x8c25,0x8c26,0x8c27,
+ 0x8c28,0x8c29,0x8c2a,0x8c2b,0x8c2c,0x8c2d,0x8c2e,0x8c2f,
+ 0x8c30,0x8c31,0x8c32,0x8c33,0x8c34,0x8c35,0x8c36,0x8c37,
+ 0x8c38,0x8c39,0x8c3a,0x8c3b,0x8c3c,0x8c3d,0x8c3e,0x8c3f,
+ 0x8c40,0x8c41,0x8c42,0x8c43,0x8c44,0x8c45,0x8c46,0x8c47,
+ 0x8c48,0x8c49,0x8c4a,0x8c4b,0x8c4c,0x8c4d,0x8c4e,0x8c4f,
+ 0x8c50,0x8c51,0x8c52,0x8c53,0x8c54,0x8c55,0x8c56,0x8c57,
+ 0x8c58,0x8c59,0x8c5a,0x8c5b,0x8c5c,0x8c5d,0x8c5e,0x8c5f,
+ 0x8c60,0x8c61,0x8c62,0x8c63,0x8c64,0x8c65,0x8c66,0x8c67,
+ 0x8c68,0x8c69,0x8c6a,0x8c6b,0x8c6c,0x8c6d,0x8c6e,0x8c6f,
+ 0x8c70,0x8c71,0x8c72,0x8c73,0x8c74,0x8c75,0x8c76,0x8c77,
+ 0x8c78,0x8c79,0x8c7a,0x8c7b,0x8c7c,0x8c7d,0x8c7e,0x8c7f,
+ 0x8c80,0x8c81,0x8c82,0x8c83,0x8c84,0x8c85,0x8c86,0x8c87,
+ 0x8c88,0x8c89,0x8c8a,0x8c8b,0x8c8c,0x8c8d,0x8c8e,0x8c8f,
+ 0x8c90,0x8c91,0x8c92,0x8c93,0x8c94,0x8c95,0x8c96,0x8c97,
+ 0x8c98,0x8c99,0x8c9a,0x8c9b,0x8c9c,0x8c9d,0x8c9e,0x8c9f,
+ 0x8ca0,0x8ca1,0x8ca2,0x8ca3,0x8ca4,0x8ca5,0x8ca6,0x8ca7,
+ 0x8ca8,0x8ca9,0x8caa,0x8cab,0x8cac,0x8cad,0x8cae,0x8caf,
+ 0x8cb0,0x8cb1,0x8cb2,0x8cb3,0x8cb4,0x8cb5,0x8cb6,0x8cb7,
+ 0x8cb8,0x8cb9,0x8cba,0x8cbb,0x8cbc,0x8cbd,0x8cbe,0x8cbf,
+ 0x8cc0,0x8cc1,0x8cc2,0x8cc3,0x8cc4,0x8cc5,0x8cc6,0x8cc7,
+ 0x8cc8,0x8cc9,0x8cca,0x8ccb,0x8ccc,0x8ccd,0x8cce,0x8ccf,
+ 0x8cd0,0x8cd1,0x8cd2,0x8cd3,0x8cd4,0x8cd5,0x8cd6,0x8cd7,
+ 0x8cd8,0x8cd9,0x8cda,0x8cdb,0x8cdc,0x8cdd,0x8cde,0x8cdf,
+ 0x8ce0,0x8ce1,0x8ce2,0x8ce3,0x8ce4,0x8ce5,0x8ce6,0x8ce7,
+ 0x8ce8,0x8ce9,0x8cea,0x8ceb,0x8cec,0x8ced,0x8cee,0x8cef,
+ 0x8cf0,0x8cf1,0x8cf2,0x8cf3,0x8cf4,0x8cf5,0x8cf6,0x8cf7,
+ 0x8cf8,0x8cf9,0x8cfa,0x8cfb,0x8cfc,0x8cfd,0x8cfe,0x8cff,
+ 0x8d00,0x8d01,0x8d02,0x8d03,0x8d04,0x8d05,0x8d06,0x8d07,
+ 0x8d08,0x8d09,0x8d0a,0x8d0b,0x8d0c,0x8d0d,0x8d0e,0x8d0f,
+ 0x8d10,0x8d11,0x8d12,0x8d13,0x8d14,0x8d15,0x8d16,0x8d17,
+ 0x8d18,0x8d19,0x8d1a,0x8d1b,0x8d1c,0x8d1d,0x8d1e,0x8d1f,
+ 0x8d20,0x8d21,0x8d22,0x8d23,0x8d24,0x8d25,0x8d26,0x8d27,
+ 0x8d28,0x8d29,0x8d2a,0x8d2b,0x8d2c,0x8d2d,0x8d2e,0x8d2f,
+ 0x8d30,0x8d31,0x8d32,0x8d33,0x8d34,0x8d35,0x8d36,0x8d37,
+ 0x8d38,0x8d39,0x8d3a,0x8d3b,0x8d3c,0x8d3d,0x8d3e,0x8d3f,
+ 0x8d40,0x8d41,0x8d42,0x8d43,0x8d44,0x8d45,0x8d46,0x8d47,
+ 0x8d48,0x8d49,0x8d4a,0x8d4b,0x8d4c,0x8d4d,0x8d4e,0x8d4f,
+ 0x8d50,0x8d51,0x8d52,0x8d53,0x8d54,0x8d55,0x8d56,0x8d57,
+ 0x8d58,0x8d59,0x8d5a,0x8d5b,0x8d5c,0x8d5d,0x8d5e,0x8d5f,
+ 0x8d60,0x8d61,0x8d62,0x8d63,0x8d64,0x8d65,0x8d66,0x8d67,
+ 0x8d68,0x8d69,0x8d6a,0x8d6b,0x8d6c,0x8d6d,0x8d6e,0x8d6f,
+ 0x8d70,0x8d71,0x8d72,0x8d73,0x8d74,0x8d75,0x8d76,0x8d77,
+ 0x8d78,0x8d79,0x8d7a,0x8d7b,0x8d7c,0x8d7d,0x8d7e,0x8d7f,
+ 0x8d80,0x8d81,0x8d82,0x8d83,0x8d84,0x8d85,0x8d86,0x8d87,
+ 0x8d88,0x8d89,0x8d8a,0x8d8b,0x8d8c,0x8d8d,0x8d8e,0x8d8f,
+ 0x8d90,0x8d91,0x8d92,0x8d93,0x8d94,0x8d95,0x8d96,0x8d97,
+ 0x8d98,0x8d99,0x8d9a,0x8d9b,0x8d9c,0x8d9d,0x8d9e,0x8d9f,
+ 0x8da0,0x8da1,0x8da2,0x8da3,0x8da4,0x8da5,0x8da6,0x8da7,
+ 0x8da8,0x8da9,0x8daa,0x8dab,0x8dac,0x8dad,0x8dae,0x8daf,
+ 0x8db0,0x8db1,0x8db2,0x8db3,0x8db4,0x8db5,0x8db6,0x8db7,
+ 0x8db8,0x8db9,0x8dba,0x8dbb,0x8dbc,0x8dbd,0x8dbe,0x8dbf,
+ 0x8dc0,0x8dc1,0x8dc2,0x8dc3,0x8dc4,0x8dc5,0x8dc6,0x8dc7,
+ 0x8dc8,0x8dc9,0x8dca,0x8dcb,0x8dcc,0x8dcd,0x8dce,0x8dcf,
+ 0x8dd0,0x8dd1,0x8dd2,0x8dd3,0x8dd4,0x8dd5,0x8dd6,0x8dd7,
+ 0x8dd8,0x8dd9,0x8dda,0x8ddb,0x8ddc,0x8ddd,0x8dde,0x8ddf,
+ 0x8de0,0x8de1,0x8de2,0x8de3,0x8de4,0x8de5,0x8de6,0x8de7,
+ 0x8de8,0x8de9,0x8dea,0x8deb,0x8dec,0x8ded,0x8dee,0x8def,
+ 0x8df0,0x8df1,0x8df2,0x8df3,0x8df4,0x8df5,0x8df6,0x8df7,
+ 0x8df8,0x8df9,0x8dfa,0x8dfb,0x8dfc,0x8dfd,0x8dfe,0x8dff,
+ 0x8e00,0x8e01,0x8e02,0x8e03,0x8e04,0x8e05,0x8e06,0x8e07,
+ 0x8e08,0x8e09,0x8e0a,0x8e0b,0x8e0c,0x8e0d,0x8e0e,0x8e0f,
+ 0x8e10,0x8e11,0x8e12,0x8e13,0x8e14,0x8e15,0x8e16,0x8e17,
+ 0x8e18,0x8e19,0x8e1a,0x8e1b,0x8e1c,0x8e1d,0x8e1e,0x8e1f,
+ 0x8e20,0x8e21,0x8e22,0x8e23,0x8e24,0x8e25,0x8e26,0x8e27,
+ 0x8e28,0x8e29,0x8e2a,0x8e2b,0x8e2c,0x8e2d,0x8e2e,0x8e2f,
+ 0x8e30,0x8e31,0x8e32,0x8e33,0x8e34,0x8e35,0x8e36,0x8e37,
+ 0x8e38,0x8e39,0x8e3a,0x8e3b,0x8e3c,0x8e3d,0x8e3e,0x8e3f,
+ 0x8e40,0x8e41,0x8e42,0x8e43,0x8e44,0x8e45,0x8e46,0x8e47,
+ 0x8e48,0x8e49,0x8e4a,0x8e4b,0x8e4c,0x8e4d,0x8e4e,0x8e4f,
+ 0x8e50,0x8e51,0x8e52,0x8e53,0x8e54,0x8e55,0x8e56,0x8e57,
+ 0x8e58,0x8e59,0x8e5a,0x8e5b,0x8e5c,0x8e5d,0x8e5e,0x8e5f,
+ 0x8e60,0x8e61,0x8e62,0x8e63,0x8e64,0x8e65,0x8e66,0x8e67,
+ 0x8e68,0x8e69,0x8e6a,0x8e6b,0x8e6c,0x8e6d,0x8e6e,0x8e6f,
+ 0x8e70,0x8e71,0x8e72,0x8e73,0x8e74,0x8e75,0x8e76,0x8e77,
+ 0x8e78,0x8e79,0x8e7a,0x8e7b,0x8e7c,0x8e7d,0x8e7e,0x8e7f,
+ 0x8e80,0x8e81,0x8e82,0x8e83,0x8e84,0x8e85,0x8e86,0x8e87,
+ 0x8e88,0x8e89,0x8e8a,0x8e8b,0x8e8c,0x8e8d,0x8e8e,0x8e8f,
+ 0x8e90,0x8e91,0x8e92,0x8e93,0x8e94,0x8e95,0x8e96,0x8e97,
+ 0x8e98,0x8e99,0x8e9a,0x8e9b,0x8e9c,0x8e9d,0x8e9e,0x8e9f,
+ 0x8ea0,0x8ea1,0x8ea2,0x8ea3,0x8ea4,0x8ea5,0x8ea6,0x8ea7,
+ 0x8ea8,0x8ea9,0x8eaa,0x8eab,0x8eac,0x8ead,0x8eae,0x8eaf,
+ 0x8eb0,0x8eb1,0x8eb2,0x8eb3,0x8eb4,0x8eb5,0x8eb6,0x8eb7,
+ 0x8eb8,0x8eb9,0x8eba,0x8ebb,0x8ebc,0x8ebd,0x8ebe,0x8ebf,
+ 0x8ec0,0x8ec1,0x8ec2,0x8ec3,0x8ec4,0x8ec5,0x8ec6,0x8ec7,
+ 0x8ec8,0x8ec9,0x8eca,0x8ecb,0x8ecc,0x8ecd,0x8ece,0x8ecf,
+ 0x8ed0,0x8ed1,0x8ed2,0x8ed3,0x8ed4,0x8ed5,0x8ed6,0x8ed7,
+ 0x8ed8,0x8ed9,0x8eda,0x8edb,0x8edc,0x8edd,0x8ede,0x8edf,
+ 0x8ee0,0x8ee1,0x8ee2,0x8ee3,0x8ee4,0x8ee5,0x8ee6,0x8ee7,
+ 0x8ee8,0x8ee9,0x8eea,0x8eeb,0x8eec,0x8eed,0x8eee,0x8eef,
+ 0x8ef0,0x8ef1,0x8ef2,0x8ef3,0x8ef4,0x8ef5,0x8ef6,0x8ef7,
+ 0x8ef8,0x8ef9,0x8efa,0x8efb,0x8efc,0x8efd,0x8efe,0x8eff,
+ 0x8f00,0x8f01,0x8f02,0x8f03,0x8f04,0x8f05,0x8f06,0x8f07,
+ 0x8f08,0x8f09,0x8f0a,0x8f0b,0x8f0c,0x8f0d,0x8f0e,0x8f0f,
+ 0x8f10,0x8f11,0x8f12,0x8f13,0x8f14,0x8f15,0x8f16,0x8f17,
+ 0x8f18,0x8f19,0x8f1a,0x8f1b,0x8f1c,0x8f1d,0x8f1e,0x8f1f,
+ 0x8f20,0x8f21,0x8f22,0x8f23,0x8f24,0x8f25,0x8f26,0x8f27,
+ 0x8f28,0x8f29,0x8f2a,0x8f2b,0x8f2c,0x8f2d,0x8f2e,0x8f2f,
+ 0x8f30,0x8f31,0x8f32,0x8f33,0x8f34,0x8f35,0x8f36,0x8f37,
+ 0x8f38,0x8f39,0x8f3a,0x8f3b,0x8f3c,0x8f3d,0x8f3e,0x8f3f,
+ 0x8f40,0x8f41,0x8f42,0x8f43,0x8f44,0x8f45,0x8f46,0x8f47,
+ 0x8f48,0x8f49,0x8f4a,0x8f4b,0x8f4c,0x8f4d,0x8f4e,0x8f4f,
+ 0x8f50,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f56,0x8f57,
+ 0x8f58,0x8f59,0x8f5a,0x8f5b,0x8f5c,0x8f5d,0x8f5e,0x8f5f,
+ 0x8f60,0x8f61,0x8f62,0x8f63,0x8f64,0x8f65,0x8f66,0x8f67,
+ 0x8f68,0x8f69,0x8f6a,0x8f6b,0x8f6c,0x8f6d,0x8f6e,0x8f6f,
+ 0x8f70,0x8f71,0x8f72,0x8f73,0x8f74,0x8f75,0x8f76,0x8f77,
+ 0x8f78,0x8f79,0x8f7a,0x8f7b,0x8f7c,0x8f7d,0x8f7e,0x8f7f,
+ 0x8f80,0x8f81,0x8f82,0x8f83,0x8f84,0x8f85,0x8f86,0x8f87,
+ 0x8f88,0x8f89,0x8f8a,0x8f8b,0x8f8c,0x8f8d,0x8f8e,0x8f8f,
+ 0x8f90,0x8f91,0x8f92,0x8f93,0x8f94,0x8f95,0x8f96,0x8f97,
+ 0x8f98,0x8f99,0x8f9a,0x8f9b,0x8f9c,0x8f9d,0x8f9e,0x8f9f,
+ 0x8fa0,0x8fa1,0x8fa2,0x8fa3,0x8fa4,0x8fa5,0x8fa6,0x8fa7,
+ 0x8fa8,0x8fa9,0x8faa,0x8fab,0x8fac,0x8fad,0x8fae,0x8faf,
+ 0x8fb0,0x8fb1,0x8fb2,0x8fb3,0x8fb4,0x8fb5,0x8fb6,0x8fb7,
+ 0x8fb8,0x8fb9,0x8fba,0x8fbb,0x8fbc,0x8fbd,0x8fbe,0x8fbf,
+ 0x8fc0,0x8fc1,0x8fc2,0x8fc3,0x8fc4,0x8fc5,0x8fc6,0x8fc7,
+ 0x8fc8,0x8fc9,0x8fca,0x8fcb,0x8fcc,0x8fcd,0x8fce,0x8fcf,
+ 0x8fd0,0x8fd1,0x8fd2,0x8fd3,0x8fd4,0x8fd5,0x8fd6,0x8fd7,
+ 0x8fd8,0x8fd9,0x8fda,0x8fdb,0x8fdc,0x8fdd,0x8fde,0x8fdf,
+ 0x8fe0,0x8fe1,0x8fe2,0x8fe3,0x8fe4,0x8fe5,0x8fe6,0x8fe7,
+ 0x8fe8,0x8fe9,0x8fea,0x8feb,0x8fec,0x8fed,0x8fee,0x8fef,
+ 0x8ff0,0x8ff1,0x8ff2,0x8ff3,0x8ff4,0x8ff5,0x8ff6,0x8ff7,
+ 0x8ff8,0x8ff9,0x8ffa,0x8ffb,0x8ffc,0x8ffd,0x8ffe,0x8fff,
+ 0x9000,0x9001,0x9002,0x9003,0x9004,0x9005,0x9006,0x9007,
+ 0x9008,0x9009,0x900a,0x900b,0x900c,0x900d,0x900e,0x900f,
+ 0x9010,0x9011,0x9012,0x9013,0x9014,0x9015,0x9016,0x9017,
+ 0x9018,0x9019,0x901a,0x901b,0x901c,0x901d,0x901e,0x901f,
+ 0x9020,0x9021,0x9022,0x9023,0x9024,0x9025,0x9026,0x9027,
+ 0x9028,0x9029,0x902a,0x902b,0x902c,0x902d,0x902e,0x902f,
+ 0x9030,0x9031,0x9032,0x9033,0x9034,0x9035,0x9036,0x9037,
+ 0x9038,0x9039,0x903a,0x903b,0x903c,0x903d,0x903e,0x903f,
+ 0x9040,0x9041,0x9042,0x9043,0x9044,0x9045,0x9046,0x9047,
+ 0x9048,0x9049,0x904a,0x904b,0x904c,0x904d,0x904e,0x904f,
+ 0x9050,0x9051,0x9052,0x9053,0x9054,0x9055,0x9056,0x9057,
+ 0x9058,0x9059,0x905a,0x905b,0x905c,0x905d,0x905e,0x905f,
+ 0x9060,0x9061,0x9062,0x9063,0x9064,0x9065,0x9066,0x9067,
+ 0x9068,0x9069,0x906a,0x906b,0x906c,0x906d,0x906e,0x906f,
+ 0x9070,0x9071,0x9072,0x9073,0x9074,0x9075,0x9076,0x9077,
+ 0x9078,0x9079,0x907a,0x907b,0x907c,0x907d,0x907e,0x907f,
+ 0x9080,0x9081,0x9082,0x9083,0x9084,0x9085,0x9086,0x9087,
+ 0x9088,0x9089,0x908a,0x908b,0x908c,0x908d,0x908e,0x908f,
+ 0x9090,0x9091,0x9092,0x9093,0x9094,0x9095,0x9096,0x9097,
+ 0x9098,0x9099,0x909a,0x909b,0x909c,0x909d,0x909e,0x909f,
+ 0x90a0,0x90a1,0x90a2,0x90a3,0x90a4,0x90a5,0x90a6,0x90a7,
+ 0x90a8,0x90a9,0x90aa,0x90ab,0x90ac,0x90ad,0x90ae,0x90af,
+ 0x90b0,0x90b1,0x90b2,0x90b3,0x90b4,0x90b5,0x90b6,0x90b7,
+ 0x90b8,0x90b9,0x90ba,0x90bb,0x90bc,0x90bd,0x90be,0x90bf,
+ 0x90c0,0x90c1,0x90c2,0x90c3,0x90c4,0x90c5,0x90c6,0x90c7,
+ 0x90c8,0x90c9,0x90ca,0x90cb,0x90cc,0x90cd,0x90ce,0x90cf,
+ 0x90d0,0x90d1,0x90d2,0x90d3,0x90d4,0x90d5,0x90d6,0x90d7,
+ 0x90d8,0x90d9,0x90da,0x90db,0x90dc,0x90dd,0x90de,0x90df,
+ 0x90e0,0x90e1,0x90e2,0x90e3,0x90e4,0x90e5,0x90e6,0x90e7,
+ 0x90e8,0x90e9,0x90ea,0x90eb,0x90ec,0x90ed,0x90ee,0x90ef,
+ 0x90f0,0x90f1,0x90f2,0x90f3,0x90f4,0x90f5,0x90f6,0x90f7,
+ 0x90f8,0x90f9,0x90fa,0x90fb,0x90fc,0x90fd,0x90fe,0x90ff,
+ 0x9100,0x9101,0x9102,0x9103,0x9104,0x9105,0x9106,0x9107,
+ 0x9108,0x9109,0x910a,0x910b,0x910c,0x910d,0x910e,0x910f,
+ 0x9110,0x9111,0x9112,0x9113,0x9114,0x9115,0x9116,0x9117,
+ 0x9118,0x9119,0x911a,0x911b,0x911c,0x911d,0x911e,0x911f,
+ 0x9120,0x9121,0x9122,0x9123,0x9124,0x9125,0x9126,0x9127,
+ 0x9128,0x9129,0x912a,0x912b,0x912c,0x912d,0x912e,0x912f,
+ 0x9130,0x9131,0x9132,0x9133,0x9134,0x9135,0x9136,0x9137,
+ 0x9138,0x9139,0x913a,0x913b,0x913c,0x913d,0x913e,0x913f,
+ 0x9140,0x9141,0x9142,0x9143,0x9144,0x9145,0x9146,0x9147,
+ 0x9148,0x9149,0x914a,0x914b,0x914c,0x914d,0x914e,0x914f,
+ 0x9150,0x9151,0x9152,0x9153,0x9154,0x9155,0x9156,0x9157,
+ 0x9158,0x9159,0x915a,0x915b,0x915c,0x915d,0x915e,0x915f,
+ 0x9160,0x9161,0x9162,0x9163,0x9164,0x9165,0x9166,0x9167,
+ 0x9168,0x9169,0x916a,0x916b,0x916c,0x916d,0x916e,0x916f,
+ 0x9170,0x9171,0x9172,0x9173,0x9174,0x9175,0x9176,0x9177,
+ 0x9178,0x9179,0x917a,0x917b,0x917c,0x917d,0x917e,0x917f,
+ 0x9180,0x9181,0x9182,0x9183,0x9184,0x9185,0x9186,0x9187,
+ 0x9188,0x9189,0x918a,0x918b,0x918c,0x918d,0x918e,0x918f,
+ 0x9190,0x9191,0x9192,0x9193,0x9194,0x9195,0x9196,0x9197,
+ 0x9198,0x9199,0x919a,0x919b,0x919c,0x919d,0x919e,0x919f,
+ 0x91a0,0x91a1,0x91a2,0x91a3,0x91a4,0x91a5,0x91a6,0x91a7,
+ 0x91a8,0x91a9,0x91aa,0x91ab,0x91ac,0x91ad,0x91ae,0x91af,
+ 0x91b0,0x91b1,0x91b2,0x91b3,0x91b4,0x91b5,0x91b6,0x91b7,
+ 0x91b8,0x91b9,0x91ba,0x91bb,0x91bc,0x91bd,0x91be,0x91bf,
+ 0x91c0,0x91c1,0x91c2,0x91c3,0x91c4,0x91c5,0x91c6,0x91c7,
+ 0x91c8,0x91c9,0x91ca,0x91cb,0x91cc,0x91cd,0x91ce,0x91cf,
+ 0x91d0,0x91d1,0x91d2,0x91d3,0x91d4,0x91d5,0x91d6,0x91d7,
+ 0x91d8,0x91d9,0x91da,0x91db,0x91dc,0x91dd,0x91de,0x91df,
+ 0x91e0,0x91e1,0x91e2,0x91e3,0x91e4,0x91e5,0x91e6,0x91e7,
+ 0x91e8,0x91e9,0x91ea,0x91eb,0x91ec,0x91ed,0x91ee,0x91ef,
+ 0x91f0,0x91f1,0x91f2,0x91f3,0x91f4,0x91f5,0x91f6,0x91f7,
+ 0x91f8,0x91f9,0x91fa,0x91fb,0x91fc,0x91fd,0x91fe,0x91ff,
+ 0x9200,0x9201,0x9202,0x9203,0x9204,0x9205,0x9206,0x9207,
+ 0x9208,0x9209,0x920a,0x920b,0x920c,0x920d,0x920e,0x920f,
+ 0x9210,0x9211,0x9212,0x9213,0x9214,0x9215,0x9216,0x9217,
+ 0x9218,0x9219,0x921a,0x921b,0x921c,0x921d,0x921e,0x921f,
+ 0x9220,0x9221,0x9222,0x9223,0x9224,0x9225,0x9226,0x9227,
+ 0x9228,0x9229,0x922a,0x922b,0x922c,0x922d,0x922e,0x922f,
+ 0x9230,0x9231,0x9232,0x9233,0x9234,0x9235,0x9236,0x9237,
+ 0x9238,0x9239,0x923a,0x923b,0x923c,0x923d,0x923e,0x923f,
+ 0x9240,0x9241,0x9242,0x9243,0x9244,0x9245,0x9246,0x9247,
+ 0x9248,0x9249,0x924a,0x924b,0x924c,0x924d,0x924e,0x924f,
+ 0x9250,0x9251,0x9252,0x9253,0x9254,0x9255,0x9256,0x9257,
+ 0x9258,0x9259,0x925a,0x925b,0x925c,0x925d,0x925e,0x925f,
+ 0x9260,0x9261,0x9262,0x9263,0x9264,0x9265,0x9266,0x9267,
+ 0x9268,0x9269,0x926a,0x926b,0x926c,0x926d,0x926e,0x926f,
+ 0x9270,0x9271,0x9272,0x9273,0x9274,0x9275,0x9276,0x9277,
+ 0x9278,0x9279,0x927a,0x927b,0x927c,0x927d,0x927e,0x927f,
+ 0x9280,0x9281,0x9282,0x9283,0x9284,0x9285,0x9286,0x9287,
+ 0x9288,0x9289,0x928a,0x928b,0x928c,0x928d,0x928e,0x928f,
+ 0x9290,0x9291,0x9292,0x9293,0x9294,0x9295,0x9296,0x9297,
+ 0x9298,0x9299,0x929a,0x929b,0x929c,0x929d,0x929e,0x929f,
+ 0x92a0,0x92a1,0x92a2,0x92a3,0x92a4,0x92a5,0x92a6,0x92a7,
+ 0x92a8,0x92a9,0x92aa,0x92ab,0x92ac,0x92ad,0x92ae,0x92af,
+ 0x92b0,0x92b1,0x92b2,0x92b3,0x92b4,0x92b5,0x92b6,0x92b7,
+ 0x92b8,0x92b9,0x92ba,0x92bb,0x92bc,0x92bd,0x92be,0x92bf,
+ 0x92c0,0x92c1,0x92c2,0x92c3,0x92c4,0x92c5,0x92c6,0x92c7,
+ 0x92c8,0x92c9,0x92ca,0x92cb,0x92cc,0x92cd,0x92ce,0x92cf,
+ 0x92d0,0x92d1,0x92d2,0x92d3,0x92d4,0x92d5,0x92d6,0x92d7,
+ 0x92d8,0x92d9,0x92da,0x92db,0x92dc,0x92dd,0x92de,0x92df,
+ 0x92e0,0x92e1,0x92e2,0x92e3,0x92e4,0x92e5,0x92e6,0x92e7,
+ 0x92e8,0x92e9,0x92ea,0x92eb,0x92ec,0x92ed,0x92ee,0x92ef,
+ 0x92f0,0x92f1,0x92f2,0x92f3,0x92f4,0x92f5,0x92f6,0x92f7,
+ 0x92f8,0x92f9,0x92fa,0x92fb,0x92fc,0x92fd,0x92fe,0x92ff,
+ 0x9300,0x9301,0x9302,0x9303,0x9304,0x9305,0x9306,0x9307,
+ 0x9308,0x9309,0x930a,0x930b,0x930c,0x930d,0x930e,0x930f,
+ 0x9310,0x9311,0x9312,0x9313,0x9314,0x9315,0x9316,0x9317,
+ 0x9318,0x9319,0x931a,0x931b,0x931c,0x931d,0x931e,0x931f,
+ 0x9320,0x9321,0x9322,0x9323,0x9324,0x9325,0x9326,0x9327,
+ 0x9328,0x9329,0x932a,0x932b,0x932c,0x932d,0x932e,0x932f,
+ 0x9330,0x9331,0x9332,0x9333,0x9334,0x9335,0x9336,0x9337,
+ 0x9338,0x9339,0x933a,0x933b,0x933c,0x933d,0x933e,0x933f,
+ 0x9340,0x9341,0x9342,0x9343,0x9344,0x9345,0x9346,0x9347,
+ 0x9348,0x9349,0x934a,0x934b,0x934c,0x934d,0x934e,0x934f,
+ 0x9350,0x9351,0x9352,0x9353,0x9354,0x9355,0x9356,0x9357,
+ 0x9358,0x9359,0x935a,0x935b,0x935c,0x935d,0x935e,0x935f,
+ 0x9360,0x9361,0x9362,0x9363,0x9364,0x9365,0x9366,0x9367,
+ 0x9368,0x9369,0x936a,0x936b,0x936c,0x936d,0x936e,0x936f,
+ 0x9370,0x9371,0x9372,0x9373,0x9374,0x9375,0x9376,0x9377,
+ 0x9378,0x9379,0x937a,0x937b,0x937c,0x937d,0x937e,0x937f,
+ 0x9380,0x9381,0x9382,0x9383,0x9384,0x9385,0x9386,0x9387,
+ 0x9388,0x9389,0x938a,0x938b,0x938c,0x938d,0x938e,0x938f,
+ 0x9390,0x9391,0x9392,0x9393,0x9394,0x9395,0x9396,0x9397,
+ 0x9398,0x9399,0x939a,0x939b,0x939c,0x939d,0x939e,0x939f,
+ 0x93a0,0x93a1,0x93a2,0x93a3,0x93a4,0x93a5,0x93a6,0x93a7,
+ 0x93a8,0x93a9,0x93aa,0x93ab,0x93ac,0x93ad,0x93ae,0x93af,
+ 0x93b0,0x93b1,0x93b2,0x93b3,0x93b4,0x93b5,0x93b6,0x93b7,
+ 0x93b8,0x93b9,0x93ba,0x93bb,0x93bc,0x93bd,0x93be,0x93bf,
+ 0x93c0,0x93c1,0x93c2,0x93c3,0x93c4,0x93c5,0x93c6,0x93c7,
+ 0x93c8,0x93c9,0x93ca,0x93cb,0x93cc,0x93cd,0x93ce,0x93cf,
+ 0x93d0,0x93d1,0x93d2,0x93d3,0x93d4,0x93d5,0x93d6,0x93d7,
+ 0x93d8,0x93d9,0x93da,0x93db,0x93dc,0x93dd,0x93de,0x93df,
+ 0x93e0,0x93e1,0x93e2,0x93e3,0x93e4,0x93e5,0x93e6,0x93e7,
+ 0x93e8,0x93e9,0x93ea,0x93eb,0x93ec,0x93ed,0x93ee,0x93ef,
+ 0x93f0,0x93f1,0x93f2,0x93f3,0x93f4,0x93f5,0x93f6,0x93f7,
+ 0x93f8,0x93f9,0x93fa,0x93fb,0x93fc,0x93fd,0x93fe,0x93ff,
+ 0x9400,0x9401,0x9402,0x9403,0x9404,0x9405,0x9406,0x9407,
+ 0x9408,0x9409,0x940a,0x940b,0x940c,0x940d,0x940e,0x940f,
+ 0x9410,0x9411,0x9412,0x9413,0x9414,0x9415,0x9416,0x9417,
+ 0x9418,0x9419,0x941a,0x941b,0x941c,0x941d,0x941e,0x941f,
+ 0x9420,0x9421,0x9422,0x9423,0x9424,0x9425,0x9426,0x9427,
+ 0x9428,0x9429,0x942a,0x942b,0x942c,0x942d,0x942e,0x942f,
+ 0x9430,0x9431,0x9432,0x9433,0x9434,0x9435,0x9436,0x9437,
+ 0x9438,0x9439,0x943a,0x943b,0x943c,0x943d,0x943e,0x943f,
+ 0x9440,0x9441,0x9442,0x9443,0x9444,0x9445,0x9446,0x9447,
+ 0x9448,0x9449,0x944a,0x944b,0x944c,0x944d,0x944e,0x944f,
+ 0x9450,0x9451,0x9452,0x9453,0x9454,0x9455,0x9456,0x9457,
+ 0x9458,0x9459,0x945a,0x945b,0x945c,0x945d,0x945e,0x945f,
+ 0x9460,0x9461,0x9462,0x9463,0x9464,0x9465,0x9466,0x9467,
+ 0x9468,0x9469,0x946a,0x946b,0x946c,0x946d,0x946e,0x946f,
+ 0x9470,0x9471,0x9472,0x9473,0x9474,0x9475,0x9476,0x9477,
+ 0x9478,0x9479,0x947a,0x947b,0x947c,0x947d,0x947e,0x947f,
+ 0x9480,0x9481,0x9482,0x9483,0x9484,0x9485,0x9486,0x9487,
+ 0x9488,0x9489,0x948a,0x948b,0x948c,0x948d,0x948e,0x948f,
+ 0x9490,0x9491,0x9492,0x9493,0x9494,0x9495,0x9496,0x9497,
+ 0x9498,0x9499,0x949a,0x949b,0x949c,0x949d,0x949e,0x949f,
+ 0x94a0,0x94a1,0x94a2,0x94a3,0x94a4,0x94a5,0x94a6,0x94a7,
+ 0x94a8,0x94a9,0x94aa,0x94ab,0x94ac,0x94ad,0x94ae,0x94af,
+ 0x94b0,0x94b1,0x94b2,0x94b3,0x94b4,0x94b5,0x94b6,0x94b7,
+ 0x94b8,0x94b9,0x94ba,0x94bb,0x94bc,0x94bd,0x94be,0x94bf,
+ 0x94c0,0x94c1,0x94c2,0x94c3,0x94c4,0x94c5,0x94c6,0x94c7,
+ 0x94c8,0x94c9,0x94ca,0x94cb,0x94cc,0x94cd,0x94ce,0x94cf,
+ 0x94d0,0x94d1,0x94d2,0x94d3,0x94d4,0x94d5,0x94d6,0x94d7,
+ 0x94d8,0x94d9,0x94da,0x94db,0x94dc,0x94dd,0x94de,0x94df,
+ 0x94e0,0x94e1,0x94e2,0x94e3,0x94e4,0x94e5,0x94e6,0x94e7,
+ 0x94e8,0x94e9,0x94ea,0x94eb,0x94ec,0x94ed,0x94ee,0x94ef,
+ 0x94f0,0x94f1,0x94f2,0x94f3,0x94f4,0x94f5,0x94f6,0x94f7,
+ 0x94f8,0x94f9,0x94fa,0x94fb,0x94fc,0x94fd,0x94fe,0x94ff,
+ 0x9500,0x9501,0x9502,0x9503,0x9504,0x9505,0x9506,0x9507,
+ 0x9508,0x9509,0x950a,0x950b,0x950c,0x950d,0x950e,0x950f,
+ 0x9510,0x9511,0x9512,0x9513,0x9514,0x9515,0x9516,0x9517,
+ 0x9518,0x9519,0x951a,0x951b,0x951c,0x951d,0x951e,0x951f,
+ 0x9520,0x9521,0x9522,0x9523,0x9524,0x9525,0x9526,0x9527,
+ 0x9528,0x9529,0x952a,0x952b,0x952c,0x952d,0x952e,0x952f,
+ 0x9530,0x9531,0x9532,0x9533,0x9534,0x9535,0x9536,0x9537,
+ 0x9538,0x9539,0x953a,0x953b,0x953c,0x953d,0x953e,0x953f,
+ 0x9540,0x9541,0x9542,0x9543,0x9544,0x9545,0x9546,0x9547,
+ 0x9548,0x9549,0x954a,0x954b,0x954c,0x954d,0x954e,0x954f,
+ 0x9550,0x9551,0x9552,0x9553,0x9554,0x9555,0x9556,0x9557,
+ 0x9558,0x9559,0x955a,0x955b,0x955c,0x955d,0x955e,0x955f,
+ 0x9560,0x9561,0x9562,0x9563,0x9564,0x9565,0x9566,0x9567,
+ 0x9568,0x9569,0x956a,0x956b,0x956c,0x956d,0x956e,0x956f,
+ 0x9570,0x9571,0x9572,0x9573,0x9574,0x9575,0x9576,0x9577,
+ 0x9578,0x9579,0x957a,0x957b,0x957c,0x957d,0x957e,0x957f,
+ 0x9580,0x9581,0x9582,0x9583,0x9584,0x9585,0x9586,0x9587,
+ 0x9588,0x9589,0x958a,0x958b,0x958c,0x958d,0x958e,0x958f,
+ 0x9590,0x9591,0x9592,0x9593,0x9594,0x9595,0x9596,0x9597,
+ 0x9598,0x9599,0x959a,0x959b,0x959c,0x959d,0x959e,0x959f,
+ 0x95a0,0x95a1,0x95a2,0x95a3,0x95a4,0x95a5,0x95a6,0x95a7,
+ 0x95a8,0x95a9,0x95aa,0x95ab,0x95ac,0x95ad,0x95ae,0x95af,
+ 0x95b0,0x95b1,0x95b2,0x95b3,0x95b4,0x95b5,0x95b6,0x95b7,
+ 0x95b8,0x95b9,0x95ba,0x95bb,0x95bc,0x95bd,0x95be,0x95bf,
+ 0x95c0,0x95c1,0x95c2,0x95c3,0x95c4,0x95c5,0x95c6,0x95c7,
+ 0x95c8,0x95c9,0x95ca,0x95cb,0x95cc,0x95cd,0x95ce,0x95cf,
+ 0x95d0,0x95d1,0x95d2,0x95d3,0x95d4,0x95d5,0x95d6,0x95d7,
+ 0x95d8,0x95d9,0x95da,0x95db,0x95dc,0x95dd,0x95de,0x95df,
+ 0x95e0,0x95e1,0x95e2,0x95e3,0x95e4,0x95e5,0x95e6,0x95e7,
+ 0x95e8,0x95e9,0x95ea,0x95eb,0x95ec,0x95ed,0x95ee,0x95ef,
+ 0x95f0,0x95f1,0x95f2,0x95f3,0x95f4,0x95f5,0x95f6,0x95f7,
+ 0x95f8,0x95f9,0x95fa,0x95fb,0x95fc,0x95fd,0x95fe,0x95ff,
+ 0x9600,0x9601,0x9602,0x9603,0x9604,0x9605,0x9606,0x9607,
+ 0x9608,0x9609,0x960a,0x960b,0x960c,0x960d,0x960e,0x960f,
+ 0x9610,0x9611,0x9612,0x9613,0x9614,0x9615,0x9616,0x9617,
+ 0x9618,0x9619,0x961a,0x961b,0x961c,0x961d,0x961e,0x961f,
+ 0x9620,0x9621,0x9622,0x9623,0x9624,0x9625,0x9626,0x9627,
+ 0x9628,0x9629,0x962a,0x962b,0x962c,0x962d,0x962e,0x962f,
+ 0x9630,0x9631,0x9632,0x9633,0x9634,0x9635,0x9636,0x9637,
+ 0x9638,0x9639,0x963a,0x963b,0x963c,0x963d,0x963e,0x963f,
+ 0x9640,0x9641,0x9642,0x9643,0x9644,0x9645,0x9646,0x9647,
+ 0x9648,0x9649,0x964a,0x964b,0x964c,0x964d,0x964e,0x964f,
+ 0x9650,0x9651,0x9652,0x9653,0x9654,0x9655,0x9656,0x9657,
+ 0x9658,0x9659,0x965a,0x965b,0x965c,0x965d,0x965e,0x965f,
+ 0x9660,0x9661,0x9662,0x9663,0x9664,0x9665,0x9666,0x9667,
+ 0x9668,0x9669,0x966a,0x966b,0x966c,0x966d,0x966e,0x966f,
+ 0x9670,0x9671,0x9672,0x9673,0x9674,0x9675,0x9676,0x9677,
+ 0x9678,0x9679,0x967a,0x967b,0x967c,0x967d,0x967e,0x967f,
+ 0x9680,0x9681,0x9682,0x9683,0x9684,0x9685,0x9686,0x9687,
+ 0x9688,0x9689,0x968a,0x968b,0x968c,0x968d,0x968e,0x968f,
+ 0x9690,0x9691,0x9692,0x9693,0x9694,0x9695,0x9696,0x9697,
+ 0x9698,0x9699,0x969a,0x969b,0x969c,0x969d,0x969e,0x969f,
+ 0x96a0,0x96a1,0x96a2,0x96a3,0x96a4,0x96a5,0x96a6,0x96a7,
+ 0x96a8,0x96a9,0x96aa,0x96ab,0x96ac,0x96ad,0x96ae,0x96af,
+ 0x96b0,0x96b1,0x96b2,0x96b3,0x96b4,0x96b5,0x96b6,0x96b7,
+ 0x96b8,0x96b9,0x96ba,0x96bb,0x96bc,0x96bd,0x96be,0x96bf,
+ 0x96c0,0x96c1,0x96c2,0x96c3,0x96c4,0x96c5,0x96c6,0x96c7,
+ 0x96c8,0x96c9,0x96ca,0x96cb,0x96cc,0x96cd,0x96ce,0x96cf,
+ 0x96d0,0x96d1,0x96d2,0x96d3,0x96d4,0x96d5,0x96d6,0x96d7,
+ 0x96d8,0x96d9,0x96da,0x96db,0x96dc,0x96dd,0x96de,0x96df,
+ 0x96e0,0x96e1,0x96e2,0x96e3,0x96e4,0x96e5,0x96e6,0x96e7,
+ 0x96e8,0x96e9,0x96ea,0x96eb,0x96ec,0x96ed,0x96ee,0x96ef,
+ 0x96f0,0x96f1,0x96f2,0x96f3,0x96f4,0x96f5,0x96f6,0x96f7,
+ 0x96f8,0x96f9,0x96fa,0x96fb,0x96fc,0x96fd,0x96fe,0x96ff,
+ 0x9700,0x9701,0x9702,0x9703,0x9704,0x9705,0x9706,0x9707,
+ 0x9708,0x9709,0x970a,0x970b,0x970c,0x970d,0x970e,0x970f,
+ 0x9710,0x9711,0x9712,0x9713,0x9714,0x9715,0x9716,0x9717,
+ 0x9718,0x9719,0x971a,0x971b,0x971c,0x971d,0x971e,0x971f,
+ 0x9720,0x9721,0x9722,0x9723,0x9724,0x9725,0x9726,0x9727,
+ 0x9728,0x9729,0x972a,0x972b,0x972c,0x972d,0x972e,0x972f,
+ 0x9730,0x9731,0x9732,0x9733,0x9734,0x9735,0x9736,0x9737,
+ 0x9738,0x9739,0x973a,0x973b,0x973c,0x973d,0x973e,0x973f,
+ 0x9740,0x9741,0x9742,0x9743,0x9744,0x9745,0x9746,0x9747,
+ 0x9748,0x9749,0x974a,0x974b,0x974c,0x974d,0x974e,0x974f,
+ 0x9750,0x9751,0x9752,0x9753,0x9754,0x9755,0x9756,0x9757,
+ 0x9758,0x9759,0x975a,0x975b,0x975c,0x975d,0x975e,0x975f,
+ 0x9760,0x9761,0x9762,0x9763,0x9764,0x9765,0x9766,0x9767,
+ 0x9768,0x9769,0x976a,0x976b,0x976c,0x976d,0x976e,0x976f,
+ 0x9770,0x9771,0x9772,0x9773,0x9774,0x9775,0x9776,0x9777,
+ 0x9778,0x9779,0x977a,0x977b,0x977c,0x977d,0x977e,0x977f,
+ 0x9780,0x9781,0x9782,0x9783,0x9784,0x9785,0x9786,0x9787,
+ 0x9788,0x9789,0x978a,0x978b,0x978c,0x978d,0x978e,0x978f,
+ 0x9790,0x9791,0x9792,0x9793,0x9794,0x9795,0x9796,0x9797,
+ 0x9798,0x9799,0x979a,0x979b,0x979c,0x979d,0x979e,0x979f,
+ 0x97a0,0x97a1,0x97a2,0x97a3,0x97a4,0x97a5,0x97a6,0x97a7,
+ 0x97a8,0x97a9,0x97aa,0x97ab,0x97ac,0x97ad,0x97ae,0x97af,
+ 0x97b0,0x97b1,0x97b2,0x97b3,0x97b4,0x97b5,0x97b6,0x97b7,
+ 0x97b8,0x97b9,0x97ba,0x97bb,0x97bc,0x97bd,0x97be,0x97bf,
+ 0x97c0,0x97c1,0x97c2,0x97c3,0x97c4,0x97c5,0x97c6,0x97c7,
+ 0x97c8,0x97c9,0x97ca,0x97cb,0x97cc,0x97cd,0x97ce,0x97cf,
+ 0x97d0,0x97d1,0x97d2,0x97d3,0x97d4,0x97d5,0x97d6,0x97d7,
+ 0x97d8,0x97d9,0x97da,0x97db,0x97dc,0x97dd,0x97de,0x97df,
+ 0x97e0,0x97e1,0x97e2,0x97e3,0x97e4,0x97e5,0x97e6,0x97e7,
+ 0x97e8,0x97e9,0x97ea,0x97eb,0x97ec,0x97ed,0x97ee,0x97ef,
+ 0x97f0,0x97f1,0x97f2,0x97f3,0x97f4,0x97f5,0x97f6,0x97f7,
+ 0x97f8,0x97f9,0x97fa,0x97fb,0x97fc,0x97fd,0x97fe,0x97ff,
+ 0x9800,0x9801,0x9802,0x9803,0x9804,0x9805,0x9806,0x9807,
+ 0x9808,0x9809,0x980a,0x980b,0x980c,0x980d,0x980e,0x980f,
+ 0x9810,0x9811,0x9812,0x9813,0x9814,0x9815,0x9816,0x9817,
+ 0x9818,0x9819,0x981a,0x981b,0x981c,0x981d,0x981e,0x981f,
+ 0x9820,0x9821,0x9822,0x9823,0x9824,0x9825,0x9826,0x9827,
+ 0x9828,0x9829,0x982a,0x982b,0x982c,0x982d,0x982e,0x982f,
+ 0x9830,0x9831,0x9832,0x9833,0x9834,0x9835,0x9836,0x9837,
+ 0x9838,0x9839,0x983a,0x983b,0x983c,0x983d,0x983e,0x983f,
+ 0x9840,0x9841,0x9842,0x9843,0x9844,0x9845,0x9846,0x9847,
+ 0x9848,0x9849,0x984a,0x984b,0x984c,0x984d,0x984e,0x984f,
+ 0x9850,0x9851,0x9852,0x9853,0x9854,0x9855,0x9856,0x9857,
+ 0x9858,0x9859,0x985a,0x985b,0x985c,0x985d,0x985e,0x985f,
+ 0x9860,0x9861,0x9862,0x9863,0x9864,0x9865,0x9866,0x9867,
+ 0x9868,0x9869,0x986a,0x986b,0x986c,0x986d,0x986e,0x986f,
+ 0x9870,0x9871,0x9872,0x9873,0x9874,0x9875,0x9876,0x9877,
+ 0x9878,0x9879,0x987a,0x987b,0x987c,0x987d,0x987e,0x987f,
+ 0x9880,0x9881,0x9882,0x9883,0x9884,0x9885,0x9886,0x9887,
+ 0x9888,0x9889,0x988a,0x988b,0x988c,0x988d,0x988e,0x988f,
+ 0x9890,0x9891,0x9892,0x9893,0x9894,0x9895,0x9896,0x9897,
+ 0x9898,0x9899,0x989a,0x989b,0x989c,0x989d,0x989e,0x989f,
+ 0x98a0,0x98a1,0x98a2,0x98a3,0x98a4,0x98a5,0x98a6,0x98a7,
+ 0x98a8,0x98a9,0x98aa,0x98ab,0x98ac,0x98ad,0x98ae,0x98af,
+ 0x98b0,0x98b1,0x98b2,0x98b3,0x98b4,0x98b5,0x98b6,0x98b7,
+ 0x98b8,0x98b9,0x98ba,0x98bb,0x98bc,0x98bd,0x98be,0x98bf,
+ 0x98c0,0x98c1,0x98c2,0x98c3,0x98c4,0x98c5,0x98c6,0x98c7,
+ 0x98c8,0x98c9,0x98ca,0x98cb,0x98cc,0x98cd,0x98ce,0x98cf,
+ 0x98d0,0x98d1,0x98d2,0x98d3,0x98d4,0x98d5,0x98d6,0x98d7,
+ 0x98d8,0x98d9,0x98da,0x98db,0x98dc,0x98dd,0x98de,0x98df,
+ 0x98e0,0x98e1,0x98e2,0x98e3,0x98e4,0x98e5,0x98e6,0x98e7,
+ 0x98e8,0x98e9,0x98ea,0x98eb,0x98ec,0x98ed,0x98ee,0x98ef,
+ 0x98f0,0x98f1,0x98f2,0x98f3,0x98f4,0x98f5,0x98f6,0x98f7,
+ 0x98f8,0x98f9,0x98fa,0x98fb,0x98fc,0x98fd,0x98fe,0x98ff,
+ 0x9900,0x9901,0x9902,0x9903,0x9904,0x9905,0x9906,0x9907,
+ 0x9908,0x9909,0x990a,0x990b,0x990c,0x990d,0x990e,0x990f,
+ 0x9910,0x9911,0x9912,0x9913,0x9914,0x9915,0x9916,0x9917,
+ 0x9918,0x9919,0x991a,0x991b,0x991c,0x991d,0x991e,0x991f,
+ 0x9920,0x9921,0x9922,0x9923,0x9924,0x9925,0x9926,0x9927,
+ 0x9928,0x9929,0x992a,0x992b,0x992c,0x992d,0x992e,0x992f,
+ 0x9930,0x9931,0x9932,0x9933,0x9934,0x9935,0x9936,0x9937,
+ 0x9938,0x9939,0x993a,0x993b,0x993c,0x993d,0x993e,0x993f,
+ 0x9940,0x9941,0x9942,0x9943,0x9944,0x9945,0x9946,0x9947,
+ 0x9948,0x9949,0x994a,0x994b,0x994c,0x994d,0x994e,0x994f,
+ 0x9950,0x9951,0x9952,0x9953,0x9954,0x9955,0x9956,0x9957,
+ 0x9958,0x9959,0x995a,0x995b,0x995c,0x995d,0x995e,0x995f,
+ 0x9960,0x9961,0x9962,0x9963,0x9964,0x9965,0x9966,0x9967,
+ 0x9968,0x9969,0x996a,0x996b,0x996c,0x996d,0x996e,0x996f,
+ 0x9970,0x9971,0x9972,0x9973,0x9974,0x9975,0x9976,0x9977,
+ 0x9978,0x9979,0x997a,0x997b,0x997c,0x997d,0x997e,0x997f,
+ 0x9980,0x9981,0x9982,0x9983,0x9984,0x9985,0x9986,0x9987,
+ 0x9988,0x9989,0x998a,0x998b,0x998c,0x998d,0x998e,0x998f,
+ 0x9990,0x9991,0x9992,0x9993,0x9994,0x9995,0x9996,0x9997,
+ 0x9998,0x9999,0x999a,0x999b,0x999c,0x999d,0x999e,0x999f,
+ 0x99a0,0x99a1,0x99a2,0x99a3,0x99a4,0x99a5,0x99a6,0x99a7,
+ 0x99a8,0x99a9,0x99aa,0x99ab,0x99ac,0x99ad,0x99ae,0x99af,
+ 0x99b0,0x99b1,0x99b2,0x99b3,0x99b4,0x99b5,0x99b6,0x99b7,
+ 0x99b8,0x99b9,0x99ba,0x99bb,0x99bc,0x99bd,0x99be,0x99bf,
+ 0x99c0,0x99c1,0x99c2,0x99c3,0x99c4,0x99c5,0x99c6,0x99c7,
+ 0x99c8,0x99c9,0x99ca,0x99cb,0x99cc,0x99cd,0x99ce,0x99cf,
+ 0x99d0,0x99d1,0x99d2,0x99d3,0x99d4,0x99d5,0x99d6,0x99d7,
+ 0x99d8,0x99d9,0x99da,0x99db,0x99dc,0x99dd,0x99de,0x99df,
+ 0x99e0,0x99e1,0x99e2,0x99e3,0x99e4,0x99e5,0x99e6,0x99e7,
+ 0x99e8,0x99e9,0x99ea,0x99eb,0x99ec,0x99ed,0x99ee,0x99ef,
+ 0x99f0,0x99f1,0x99f2,0x99f3,0x99f4,0x99f5,0x99f6,0x99f7,
+ 0x99f8,0x99f9,0x99fa,0x99fb,0x99fc,0x99fd,0x99fe,0x99ff,
+ 0x9a00,0x9a01,0x9a02,0x9a03,0x9a04,0x9a05,0x9a06,0x9a07,
+ 0x9a08,0x9a09,0x9a0a,0x9a0b,0x9a0c,0x9a0d,0x9a0e,0x9a0f,
+ 0x9a10,0x9a11,0x9a12,0x9a13,0x9a14,0x9a15,0x9a16,0x9a17,
+ 0x9a18,0x9a19,0x9a1a,0x9a1b,0x9a1c,0x9a1d,0x9a1e,0x9a1f,
+ 0x9a20,0x9a21,0x9a22,0x9a23,0x9a24,0x9a25,0x9a26,0x9a27,
+ 0x9a28,0x9a29,0x9a2a,0x9a2b,0x9a2c,0x9a2d,0x9a2e,0x9a2f,
+ 0x9a30,0x9a31,0x9a32,0x9a33,0x9a34,0x9a35,0x9a36,0x9a37,
+ 0x9a38,0x9a39,0x9a3a,0x9a3b,0x9a3c,0x9a3d,0x9a3e,0x9a3f,
+ 0x9a40,0x9a41,0x9a42,0x9a43,0x9a44,0x9a45,0x9a46,0x9a47,
+ 0x9a48,0x9a49,0x9a4a,0x9a4b,0x9a4c,0x9a4d,0x9a4e,0x9a4f,
+ 0x9a50,0x9a51,0x9a52,0x9a53,0x9a54,0x9a55,0x9a56,0x9a57,
+ 0x9a58,0x9a59,0x9a5a,0x9a5b,0x9a5c,0x9a5d,0x9a5e,0x9a5f,
+ 0x9a60,0x9a61,0x9a62,0x9a63,0x9a64,0x9a65,0x9a66,0x9a67,
+ 0x9a68,0x9a69,0x9a6a,0x9a6b,0x9a6c,0x9a6d,0x9a6e,0x9a6f,
+ 0x9a70,0x9a71,0x9a72,0x9a73,0x9a74,0x9a75,0x9a76,0x9a77,
+ 0x9a78,0x9a79,0x9a7a,0x9a7b,0x9a7c,0x9a7d,0x9a7e,0x9a7f,
+ 0x9a80,0x9a81,0x9a82,0x9a83,0x9a84,0x9a85,0x9a86,0x9a87,
+ 0x9a88,0x9a89,0x9a8a,0x9a8b,0x9a8c,0x9a8d,0x9a8e,0x9a8f,
+ 0x9a90,0x9a91,0x9a92,0x9a93,0x9a94,0x9a95,0x9a96,0x9a97,
+ 0x9a98,0x9a99,0x9a9a,0x9a9b,0x9a9c,0x9a9d,0x9a9e,0x9a9f,
+ 0x9aa0,0x9aa1,0x9aa2,0x9aa3,0x9aa4,0x9aa5,0x9aa6,0x9aa7,
+ 0x9aa8,0x9aa9,0x9aaa,0x9aab,0x9aac,0x9aad,0x9aae,0x9aaf,
+ 0x9ab0,0x9ab1,0x9ab2,0x9ab3,0x9ab4,0x9ab5,0x9ab6,0x9ab7,
+ 0x9ab8,0x9ab9,0x9aba,0x9abb,0x9abc,0x9abd,0x9abe,0x9abf,
+ 0x9ac0,0x9ac1,0x9ac2,0x9ac3,0x9ac4,0x9ac5,0x9ac6,0x9ac7,
+ 0x9ac8,0x9ac9,0x9aca,0x9acb,0x9acc,0x9acd,0x9ace,0x9acf,
+ 0x9ad0,0x9ad1,0x9ad2,0x9ad3,0x9ad4,0x9ad5,0x9ad6,0x9ad7,
+ 0x9ad8,0x9ad9,0x9ada,0x9adb,0x9adc,0x9add,0x9ade,0x9adf,
+ 0x9ae0,0x9ae1,0x9ae2,0x9ae3,0x9ae4,0x9ae5,0x9ae6,0x9ae7,
+ 0x9ae8,0x9ae9,0x9aea,0x9aeb,0x9aec,0x9aed,0x9aee,0x9aef,
+ 0x9af0,0x9af1,0x9af2,0x9af3,0x9af4,0x9af5,0x9af6,0x9af7,
+ 0x9af8,0x9af9,0x9afa,0x9afb,0x9afc,0x9afd,0x9afe,0x9aff,
+ 0x9b00,0x9b01,0x9b02,0x9b03,0x9b04,0x9b05,0x9b06,0x9b07,
+ 0x9b08,0x9b09,0x9b0a,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b0f,
+ 0x9b10,0x9b11,0x9b12,0x9b13,0x9b14,0x9b15,0x9b16,0x9b17,
+ 0x9b18,0x9b19,0x9b1a,0x9b1b,0x9b1c,0x9b1d,0x9b1e,0x9b1f,
+ 0x9b20,0x9b21,0x9b22,0x9b23,0x9b24,0x9b25,0x9b26,0x9b27,
+ 0x9b28,0x9b29,0x9b2a,0x9b2b,0x9b2c,0x9b2d,0x9b2e,0x9b2f,
+ 0x9b30,0x9b31,0x9b32,0x9b33,0x9b34,0x9b35,0x9b36,0x9b37,
+ 0x9b38,0x9b39,0x9b3a,0x9b3b,0x9b3c,0x9b3d,0x9b3e,0x9b3f,
+ 0x9b40,0x9b41,0x9b42,0x9b43,0x9b44,0x9b45,0x9b46,0x9b47,
+ 0x9b48,0x9b49,0x9b4a,0x9b4b,0x9b4c,0x9b4d,0x9b4e,0x9b4f,
+ 0x9b50,0x9b51,0x9b52,0x9b53,0x9b54,0x9b55,0x9b56,0x9b57,
+ 0x9b58,0x9b59,0x9b5a,0x9b5b,0x9b5c,0x9b5d,0x9b5e,0x9b5f,
+ 0x9b60,0x9b61,0x9b62,0x9b63,0x9b64,0x9b65,0x9b66,0x9b67,
+ 0x9b68,0x9b69,0x9b6a,0x9b6b,0x9b6c,0x9b6d,0x9b6e,0x9b6f,
+ 0x9b70,0x9b71,0x9b72,0x9b73,0x9b74,0x9b75,0x9b76,0x9b77,
+ 0x9b78,0x9b79,0x9b7a,0x9b7b,0x9b7c,0x9b7d,0x9b7e,0x9b7f,
+ 0x9b80,0x9b81,0x9b82,0x9b83,0x9b84,0x9b85,0x9b86,0x9b87,
+ 0x9b88,0x9b89,0x9b8a,0x9b8b,0x9b8c,0x9b8d,0x9b8e,0x9b8f,
+ 0x9b90,0x9b91,0x9b92,0x9b93,0x9b94,0x9b95,0x9b96,0x9b97,
+ 0x9b98,0x9b99,0x9b9a,0x9b9b,0x9b9c,0x9b9d,0x9b9e,0x9b9f,
+ 0x9ba0,0x9ba1,0x9ba2,0x9ba3,0x9ba4,0x9ba5,0x9ba6,0x9ba7,
+ 0x9ba8,0x9ba9,0x9baa,0x9bab,0x9bac,0x9bad,0x9bae,0x9baf,
+ 0x9bb0,0x9bb1,0x9bb2,0x9bb3,0x9bb4,0x9bb5,0x9bb6,0x9bb7,
+ 0x9bb8,0x9bb9,0x9bba,0x9bbb,0x9bbc,0x9bbd,0x9bbe,0x9bbf,
+ 0x9bc0,0x9bc1,0x9bc2,0x9bc3,0x9bc4,0x9bc5,0x9bc6,0x9bc7,
+ 0x9bc8,0x9bc9,0x9bca,0x9bcb,0x9bcc,0x9bcd,0x9bce,0x9bcf,
+ 0x9bd0,0x9bd1,0x9bd2,0x9bd3,0x9bd4,0x9bd5,0x9bd6,0x9bd7,
+ 0x9bd8,0x9bd9,0x9bda,0x9bdb,0x9bdc,0x9bdd,0x9bde,0x9bdf,
+ 0x9be0,0x9be1,0x9be2,0x9be3,0x9be4,0x9be5,0x9be6,0x9be7,
+ 0x9be8,0x9be9,0x9bea,0x9beb,0x9bec,0x9bed,0x9bee,0x9bef,
+ 0x9bf0,0x9bf1,0x9bf2,0x9bf3,0x9bf4,0x9bf5,0x9bf6,0x9bf7,
+ 0x9bf8,0x9bf9,0x9bfa,0x9bfb,0x9bfc,0x9bfd,0x9bfe,0x9bff,
+ 0x9c00,0x9c01,0x9c02,0x9c03,0x9c04,0x9c05,0x9c06,0x9c07,
+ 0x9c08,0x9c09,0x9c0a,0x9c0b,0x9c0c,0x9c0d,0x9c0e,0x9c0f,
+ 0x9c10,0x9c11,0x9c12,0x9c13,0x9c14,0x9c15,0x9c16,0x9c17,
+ 0x9c18,0x9c19,0x9c1a,0x9c1b,0x9c1c,0x9c1d,0x9c1e,0x9c1f,
+ 0x9c20,0x9c21,0x9c22,0x9c23,0x9c24,0x9c25,0x9c26,0x9c27,
+ 0x9c28,0x9c29,0x9c2a,0x9c2b,0x9c2c,0x9c2d,0x9c2e,0x9c2f,
+ 0x9c30,0x9c31,0x9c32,0x9c33,0x9c34,0x9c35,0x9c36,0x9c37,
+ 0x9c38,0x9c39,0x9c3a,0x9c3b,0x9c3c,0x9c3d,0x9c3e,0x9c3f,
+ 0x9c40,0x9c41,0x9c42,0x9c43,0x9c44,0x9c45,0x9c46,0x9c47,
+ 0x9c48,0x9c49,0x9c4a,0x9c4b,0x9c4c,0x9c4d,0x9c4e,0x9c4f,
+ 0x9c50,0x9c51,0x9c52,0x9c53,0x9c54,0x9c55,0x9c56,0x9c57,
+ 0x9c58,0x9c59,0x9c5a,0x9c5b,0x9c5c,0x9c5d,0x9c5e,0x9c5f,
+ 0x9c60,0x9c61,0x9c62,0x9c63,0x9c64,0x9c65,0x9c66,0x9c67,
+ 0x9c68,0x9c69,0x9c6a,0x9c6b,0x9c6c,0x9c6d,0x9c6e,0x9c6f,
+ 0x9c70,0x9c71,0x9c72,0x9c73,0x9c74,0x9c75,0x9c76,0x9c77,
+ 0x9c78,0x9c79,0x9c7a,0x9c7b,0x9c7c,0x9c7d,0x9c7e,0x9c7f,
+ 0x9c80,0x9c81,0x9c82,0x9c83,0x9c84,0x9c85,0x9c86,0x9c87,
+ 0x9c88,0x9c89,0x9c8a,0x9c8b,0x9c8c,0x9c8d,0x9c8e,0x9c8f,
+ 0x9c90,0x9c91,0x9c92,0x9c93,0x9c94,0x9c95,0x9c96,0x9c97,
+ 0x9c98,0x9c99,0x9c9a,0x9c9b,0x9c9c,0x9c9d,0x9c9e,0x9c9f,
+ 0x9ca0,0x9ca1,0x9ca2,0x9ca3,0x9ca4,0x9ca5,0x9ca6,0x9ca7,
+ 0x9ca8,0x9ca9,0x9caa,0x9cab,0x9cac,0x9cad,0x9cae,0x9caf,
+ 0x9cb0,0x9cb1,0x9cb2,0x9cb3,0x9cb4,0x9cb5,0x9cb6,0x9cb7,
+ 0x9cb8,0x9cb9,0x9cba,0x9cbb,0x9cbc,0x9cbd,0x9cbe,0x9cbf,
+ 0x9cc0,0x9cc1,0x9cc2,0x9cc3,0x9cc4,0x9cc5,0x9cc6,0x9cc7,
+ 0x9cc8,0x9cc9,0x9cca,0x9ccb,0x9ccc,0x9ccd,0x9cce,0x9ccf,
+ 0x9cd0,0x9cd1,0x9cd2,0x9cd3,0x9cd4,0x9cd5,0x9cd6,0x9cd7,
+ 0x9cd8,0x9cd9,0x9cda,0x9cdb,0x9cdc,0x9cdd,0x9cde,0x9cdf,
+ 0x9ce0,0x9ce1,0x9ce2,0x9ce3,0x9ce4,0x9ce5,0x9ce6,0x9ce7,
+ 0x9ce8,0x9ce9,0x9cea,0x9ceb,0x9cec,0x9ced,0x9cee,0x9cef,
+ 0x9cf0,0x9cf1,0x9cf2,0x9cf3,0x9cf4,0x9cf5,0x9cf6,0x9cf7,
+ 0x9cf8,0x9cf9,0x9cfa,0x9cfb,0x9cfc,0x9cfd,0x9cfe,0x9cff,
+ 0x9d00,0x9d01,0x9d02,0x9d03,0x9d04,0x9d05,0x9d06,0x9d07,
+ 0x9d08,0x9d09,0x9d0a,0x9d0b,0x9d0c,0x9d0d,0x9d0e,0x9d0f,
+ 0x9d10,0x9d11,0x9d12,0x9d13,0x9d14,0x9d15,0x9d16,0x9d17,
+ 0x9d18,0x9d19,0x9d1a,0x9d1b,0x9d1c,0x9d1d,0x9d1e,0x9d1f,
+ 0x9d20,0x9d21,0x9d22,0x9d23,0x9d24,0x9d25,0x9d26,0x9d27,
+ 0x9d28,0x9d29,0x9d2a,0x9d2b,0x9d2c,0x9d2d,0x9d2e,0x9d2f,
+ 0x9d30,0x9d31,0x9d32,0x9d33,0x9d34,0x9d35,0x9d36,0x9d37,
+ 0x9d38,0x9d39,0x9d3a,0x9d3b,0x9d3c,0x9d3d,0x9d3e,0x9d3f,
+ 0x9d40,0x9d41,0x9d42,0x9d43,0x9d44,0x9d45,0x9d46,0x9d47,
+ 0x9d48,0x9d49,0x9d4a,0x9d4b,0x9d4c,0x9d4d,0x9d4e,0x9d4f,
+ 0x9d50,0x9d51,0x9d52,0x9d53,0x9d54,0x9d55,0x9d56,0x9d57,
+ 0x9d58,0x9d59,0x9d5a,0x9d5b,0x9d5c,0x9d5d,0x9d5e,0x9d5f,
+ 0x9d60,0x9d61,0x9d62,0x9d63,0x9d64,0x9d65,0x9d66,0x9d67,
+ 0x9d68,0x9d69,0x9d6a,0x9d6b,0x9d6c,0x9d6d,0x9d6e,0x9d6f,
+ 0x9d70,0x9d71,0x9d72,0x9d73,0x9d74,0x9d75,0x9d76,0x9d77,
+ 0x9d78,0x9d79,0x9d7a,0x9d7b,0x9d7c,0x9d7d,0x9d7e,0x9d7f,
+ 0x9d80,0x9d81,0x9d82,0x9d83,0x9d84,0x9d85,0x9d86,0x9d87,
+ 0x9d88,0x9d89,0x9d8a,0x9d8b,0x9d8c,0x9d8d,0x9d8e,0x9d8f,
+ 0x9d90,0x9d91,0x9d92,0x9d93,0x9d94,0x9d95,0x9d96,0x9d97,
+ 0x9d98,0x9d99,0x9d9a,0x9d9b,0x9d9c,0x9d9d,0x9d9e,0x9d9f,
+ 0x9da0,0x9da1,0x9da2,0x9da3,0x9da4,0x9da5,0x9da6,0x9da7,
+ 0x9da8,0x9da9,0x9daa,0x9dab,0x9dac,0x9dad,0x9dae,0x9daf,
+ 0x9db0,0x9db1,0x9db2,0x9db3,0x9db4,0x9db5,0x9db6,0x9db7,
+ 0x9db8,0x9db9,0x9dba,0x9dbb,0x9dbc,0x9dbd,0x9dbe,0x9dbf,
+ 0x9dc0,0x9dc1,0x9dc2,0x9dc3,0x9dc4,0x9dc5,0x9dc6,0x9dc7,
+ 0x9dc8,0x9dc9,0x9dca,0x9dcb,0x9dcc,0x9dcd,0x9dce,0x9dcf,
+ 0x9dd0,0x9dd1,0x9dd2,0x9dd3,0x9dd4,0x9dd5,0x9dd6,0x9dd7,
+ 0x9dd8,0x9dd9,0x9dda,0x9ddb,0x9ddc,0x9ddd,0x9dde,0x9ddf,
+ 0x9de0,0x9de1,0x9de2,0x9de3,0x9de4,0x9de5,0x9de6,0x9de7,
+ 0x9de8,0x9de9,0x9dea,0x9deb,0x9dec,0x9ded,0x9dee,0x9def,
+ 0x9df0,0x9df1,0x9df2,0x9df3,0x9df4,0x9df5,0x9df6,0x9df7,
+ 0x9df8,0x9df9,0x9dfa,0x9dfb,0x9dfc,0x9dfd,0x9dfe,0x9dff,
+ 0x9e00,0x9e01,0x9e02,0x9e03,0x9e04,0x9e05,0x9e06,0x9e07,
+ 0x9e08,0x9e09,0x9e0a,0x9e0b,0x9e0c,0x9e0d,0x9e0e,0x9e0f,
+ 0x9e10,0x9e11,0x9e12,0x9e13,0x9e14,0x9e15,0x9e16,0x9e17,
+ 0x9e18,0x9e19,0x9e1a,0x9e1b,0x9e1c,0x9e1d,0x9e1e,0x9e1f,
+ 0x9e20,0x9e21,0x9e22,0x9e23,0x9e24,0x9e25,0x9e26,0x9e27,
+ 0x9e28,0x9e29,0x9e2a,0x9e2b,0x9e2c,0x9e2d,0x9e2e,0x9e2f,
+ 0x9e30,0x9e31,0x9e32,0x9e33,0x9e34,0x9e35,0x9e36,0x9e37,
+ 0x9e38,0x9e39,0x9e3a,0x9e3b,0x9e3c,0x9e3d,0x9e3e,0x9e3f,
+ 0x9e40,0x9e41,0x9e42,0x9e43,0x9e44,0x9e45,0x9e46,0x9e47,
+ 0x9e48,0x9e49,0x9e4a,0x9e4b,0x9e4c,0x9e4d,0x9e4e,0x9e4f,
+ 0x9e50,0x9e51,0x9e52,0x9e53,0x9e54,0x9e55,0x9e56,0x9e57,
+ 0x9e58,0x9e59,0x9e5a,0x9e5b,0x9e5c,0x9e5d,0x9e5e,0x9e5f,
+ 0x9e60,0x9e61,0x9e62,0x9e63,0x9e64,0x9e65,0x9e66,0x9e67,
+ 0x9e68,0x9e69,0x9e6a,0x9e6b,0x9e6c,0x9e6d,0x9e6e,0x9e6f,
+ 0x9e70,0x9e71,0x9e72,0x9e73,0x9e74,0x9e75,0x9e76,0x9e77,
+ 0x9e78,0x9e79,0x9e7a,0x9e7b,0x9e7c,0x9e7d,0x9e7e,0x9e7f,
+ 0x9e80,0x9e81,0x9e82,0x9e83,0x9e84,0x9e85,0x9e86,0x9e87,
+ 0x9e88,0x9e89,0x9e8a,0x9e8b,0x9e8c,0x9e8d,0x9e8e,0x9e8f,
+ 0x9e90,0x9e91,0x9e92,0x9e93,0x9e94,0x9e95,0x9e96,0x9e97,
+ 0x9e98,0x9e99,0x9e9a,0x9e9b,0x9e9c,0x9e9d,0x9e9e,0x9e9f,
+ 0x9ea0,0x9ea1,0x9ea2,0x9ea3,0x9ea4,0x9ea5,0x9ea6,0x9ea7,
+ 0x9ea8,0x9ea9,0x9eaa,0x9eab,0x9eac,0x9ead,0x9eae,0x9eaf,
+ 0x9eb0,0x9eb1,0x9eb2,0x9eb3,0x9eb4,0x9eb5,0x9eb6,0x9eb7,
+ 0x9eb8,0x9eb9,0x9eba,0x9ebb,0x9ebc,0x9ebd,0x9ebe,0x9ebf,
+ 0x9ec0,0x9ec1,0x9ec2,0x9ec3,0x9ec4,0x9ec5,0x9ec6,0x9ec7,
+ 0x9ec8,0x9ec9,0x9eca,0x9ecb,0x9ecc,0x9ecd,0x9ece,0x9ecf,
+ 0x9ed0,0x9ed1,0x9ed2,0x9ed3,0x9ed4,0x9ed5,0x9ed6,0x9ed7,
+ 0x9ed8,0x9ed9,0x9eda,0x9edb,0x9edc,0x9edd,0x9ede,0x9edf,
+ 0x9ee0,0x9ee1,0x9ee2,0x9ee3,0x9ee4,0x9ee5,0x9ee6,0x9ee7,
+ 0x9ee8,0x9ee9,0x9eea,0x9eeb,0x9eec,0x9eed,0x9eee,0x9eef,
+ 0x9ef0,0x9ef1,0x9ef2,0x9ef3,0x9ef4,0x9ef5,0x9ef6,0x9ef7,
+ 0x9ef8,0x9ef9,0x9efa,0x9efb,0x9efc,0x9efd,0x9efe,0x9eff,
+ 0x9f00,0x9f01,0x9f02,0x9f03,0x9f04,0x9f05,0x9f06,0x9f07,
+ 0x9f08,0x9f09,0x9f0a,0x9f0b,0x9f0c,0x9f0d,0x9f0e,0x9f0f,
+ 0x9f10,0x9f11,0x9f12,0x9f13,0x9f14,0x9f15,0x9f16,0x9f17,
+ 0x9f18,0x9f19,0x9f1a,0x9f1b,0x9f1c,0x9f1d,0x9f1e,0x9f1f,
+ 0x9f20,0x9f21,0x9f22,0x9f23,0x9f24,0x9f25,0x9f26,0x9f27,
+ 0x9f28,0x9f29,0x9f2a,0x9f2b,0x9f2c,0x9f2d,0x9f2e,0x9f2f,
+ 0x9f30,0x9f31,0x9f32,0x9f33,0x9f34,0x9f35,0x9f36,0x9f37,
+ 0x9f38,0x9f39,0x9f3a,0x9f3b,0x9f3c,0x9f3d,0x9f3e,0x9f3f,
+ 0x9f40,0x9f41,0x9f42,0x9f43,0x9f44,0x9f45,0x9f46,0x9f47,
+ 0x9f48,0x9f49,0x9f4a,0x9f4b,0x9f4c,0x9f4d,0x9f4e,0x9f4f,
+ 0x9f50,0x9f51,0x9f52,0x9f53,0x9f54,0x9f55,0x9f56,0x9f57,
+ 0x9f58,0x9f59,0x9f5a,0x9f5b,0x9f5c,0x9f5d,0x9f5e,0x9f5f,
+ 0x9f60,0x9f61,0x9f62,0x9f63,0x9f64,0x9f65,0x9f66,0x9f67,
+ 0x9f68,0x9f69,0x9f6a,0x9f6b,0x9f6c,0x9f6d,0x9f6e,0x9f6f,
+ 0x9f70,0x9f71,0x9f72,0x9f73,0x9f74,0x9f75,0x9f76,0x9f77,
+ 0x9f78,0x9f79,0x9f7a,0x9f7b,0x9f7c,0x9f7d,0x9f7e,0x9f7f,
+ 0x9f80,0x9f81,0x9f82,0x9f83,0x9f84,0x9f85,0x9f86,0x9f87,
+ 0x9f88,0x9f89,0x9f8a,0x9f8b,0x9f8c,0x9f8d,0x9f8e,0x9f8f,
+ 0x9f90,0x9f91,0x9f92,0x9f93,0x9f94,0x9f95,0x9f96,0x9f97,
+ 0x9f98,0x9f99,0x9f9a,0x9f9b,0x9f9c,0x9f9d,0x9f9e,0x9f9f,
+ 0x9fa0,0x9fa1,0x9fa2,0x9fa3,0x9fa4,0x9fa5,0x9fa6,0x9fa7,
+ 0x9fa8,0x9fa9,0x9faa,0x9fab,0x9fac,0x9fad,0x9fae,0x9faf,
+ 0x9fb0,0x9fb1,0x9fb2,0x9fb3,0x9fb4,0x9fb5,0x9fb6,0x9fb7,
+ 0x9fb8,0x9fb9,0x9fba,0x9fbb,0x9fbc,0x9fbd,0x9fbe,0x9fbf,
+ 0x9fc0,0x9fc1,0x9fc2,0x9fc3,0x9fc4,0x9fc5,0x9fc6,0x9fc7,
+ 0x9fc8,0x9fc9,0x9fca,0x9fcb,0x9fcc,0x9fcd,0x9fce,0x9fcf,
+ 0x9fd0,0x9fd1,0x9fd2,0x9fd3,0x9fd4,0x9fd5,0x9fd6,0x9fd7,
+ 0x9fd8,0x9fd9,0x9fda,0x9fdb,0x9fdc,0x9fdd,0x9fde,0x9fdf,
+ 0x9fe0,0x9fe1,0x9fe2,0x9fe3,0x9fe4,0x9fe5,0x9fe6,0x9fe7,
+ 0x9fe8,0x9fe9,0x9fea,0x9feb,0x9fec,0x9fed,0x9fee,0x9fef,
+ 0x9ff0,0x9ff1,0x9ff2,0x9ff3,0x9ff4,0x9ff5,0x9ff6,0x9ff7,
+ 0x9ff8,0x9ff9,0x9ffa,0x9ffb,0x9ffc,0x9ffd,0x9ffe,0x9fff,
+ 0xa000,0xa001,0xa002,0xa003,0xa004,0xa005,0xa006,0xa007,
+ 0xa008,0xa009,0xa00a,0xa00b,0xa00c,0xa00d,0xa00e,0xa00f,
+ 0xa010,0xa011,0xa012,0xa013,0xa014,0xa015,0xa016,0xa017,
+ 0xa018,0xa019,0xa01a,0xa01b,0xa01c,0xa01d,0xa01e,0xa01f,
+ 0xa020,0xa021,0xa022,0xa023,0xa024,0xa025,0xa026,0xa027,
+ 0xa028,0xa029,0xa02a,0xa02b,0xa02c,0xa02d,0xa02e,0xa02f,
+ 0xa030,0xa031,0xa032,0xa033,0xa034,0xa035,0xa036,0xa037,
+ 0xa038,0xa039,0xa03a,0xa03b,0xa03c,0xa03d,0xa03e,0xa03f,
+ 0xa040,0xa041,0xa042,0xa043,0xa044,0xa045,0xa046,0xa047,
+ 0xa048,0xa049,0xa04a,0xa04b,0xa04c,0xa04d,0xa04e,0xa04f,
+ 0xa050,0xa051,0xa052,0xa053,0xa054,0xa055,0xa056,0xa057,
+ 0xa058,0xa059,0xa05a,0xa05b,0xa05c,0xa05d,0xa05e,0xa05f,
+ 0xa060,0xa061,0xa062,0xa063,0xa064,0xa065,0xa066,0xa067,
+ 0xa068,0xa069,0xa06a,0xa06b,0xa06c,0xa06d,0xa06e,0xa06f,
+ 0xa070,0xa071,0xa072,0xa073,0xa074,0xa075,0xa076,0xa077,
+ 0xa078,0xa079,0xa07a,0xa07b,0xa07c,0xa07d,0xa07e,0xa07f,
+ 0xa080,0xa081,0xa082,0xa083,0xa084,0xa085,0xa086,0xa087,
+ 0xa088,0xa089,0xa08a,0xa08b,0xa08c,0xa08d,0xa08e,0xa08f,
+ 0xa090,0xa091,0xa092,0xa093,0xa094,0xa095,0xa096,0xa097,
+ 0xa098,0xa099,0xa09a,0xa09b,0xa09c,0xa09d,0xa09e,0xa09f,
+ 0xa0a0,0xa0a1,0xa0a2,0xa0a3,0xa0a4,0xa0a5,0xa0a6,0xa0a7,
+ 0xa0a8,0xa0a9,0xa0aa,0xa0ab,0xa0ac,0xa0ad,0xa0ae,0xa0af,
+ 0xa0b0,0xa0b1,0xa0b2,0xa0b3,0xa0b4,0xa0b5,0xa0b6,0xa0b7,
+ 0xa0b8,0xa0b9,0xa0ba,0xa0bb,0xa0bc,0xa0bd,0xa0be,0xa0bf,
+ 0xa0c0,0xa0c1,0xa0c2,0xa0c3,0xa0c4,0xa0c5,0xa0c6,0xa0c7,
+ 0xa0c8,0xa0c9,0xa0ca,0xa0cb,0xa0cc,0xa0cd,0xa0ce,0xa0cf,
+ 0xa0d0,0xa0d1,0xa0d2,0xa0d3,0xa0d4,0xa0d5,0xa0d6,0xa0d7,
+ 0xa0d8,0xa0d9,0xa0da,0xa0db,0xa0dc,0xa0dd,0xa0de,0xa0df,
+ 0xa0e0,0xa0e1,0xa0e2,0xa0e3,0xa0e4,0xa0e5,0xa0e6,0xa0e7,
+ 0xa0e8,0xa0e9,0xa0ea,0xa0eb,0xa0ec,0xa0ed,0xa0ee,0xa0ef,
+ 0xa0f0,0xa0f1,0xa0f2,0xa0f3,0xa0f4,0xa0f5,0xa0f6,0xa0f7,
+ 0xa0f8,0xa0f9,0xa0fa,0xa0fb,0xa0fc,0xa0fd,0xa0fe,0xa0ff,
+ 0xa100,0xa101,0xa102,0xa103,0xa104,0xa105,0xa106,0xa107,
+ 0xa108,0xa109,0xa10a,0xa10b,0xa10c,0xa10d,0xa10e,0xa10f,
+ 0xa110,0xa111,0xa112,0xa113,0xa114,0xa115,0xa116,0xa117,
+ 0xa118,0xa119,0xa11a,0xa11b,0xa11c,0xa11d,0xa11e,0xa11f,
+ 0xa120,0xa121,0xa122,0xa123,0xa124,0xa125,0xa126,0xa127,
+ 0xa128,0xa129,0xa12a,0xa12b,0xa12c,0xa12d,0xa12e,0xa12f,
+ 0xa130,0xa131,0xa132,0xa133,0xa134,0xa135,0xa136,0xa137,
+ 0xa138,0xa139,0xa13a,0xa13b,0xa13c,0xa13d,0xa13e,0xa13f,
+ 0xa140,0xa141,0xa142,0xa143,0xa144,0xa145,0xa146,0xa147,
+ 0xa148,0xa149,0xa14a,0xa14b,0xa14c,0xa14d,0xa14e,0xa14f,
+ 0xa150,0xa151,0xa152,0xa153,0xa154,0xa155,0xa156,0xa157,
+ 0xa158,0xa159,0xa15a,0xa15b,0xa15c,0xa15d,0xa15e,0xa15f,
+ 0xa160,0xa161,0xa162,0xa163,0xa164,0xa165,0xa166,0xa167,
+ 0xa168,0xa169,0xa16a,0xa16b,0xa16c,0xa16d,0xa16e,0xa16f,
+ 0xa170,0xa171,0xa172,0xa173,0xa174,0xa175,0xa176,0xa177,
+ 0xa178,0xa179,0xa17a,0xa17b,0xa17c,0xa17d,0xa17e,0xa17f,
+ 0xa180,0xa181,0xa182,0xa183,0xa184,0xa185,0xa186,0xa187,
+ 0xa188,0xa189,0xa18a,0xa18b,0xa18c,0xa18d,0xa18e,0xa18f,
+ 0xa190,0xa191,0xa192,0xa193,0xa194,0xa195,0xa196,0xa197,
+ 0xa198,0xa199,0xa19a,0xa19b,0xa19c,0xa19d,0xa19e,0xa19f,
+ 0xa1a0,0xa1a1,0xa1a2,0xa1a3,0xa1a4,0xa1a5,0xa1a6,0xa1a7,
+ 0xa1a8,0xa1a9,0xa1aa,0xa1ab,0xa1ac,0xa1ad,0xa1ae,0xa1af,
+ 0xa1b0,0xa1b1,0xa1b2,0xa1b3,0xa1b4,0xa1b5,0xa1b6,0xa1b7,
+ 0xa1b8,0xa1b9,0xa1ba,0xa1bb,0xa1bc,0xa1bd,0xa1be,0xa1bf,
+ 0xa1c0,0xa1c1,0xa1c2,0xa1c3,0xa1c4,0xa1c5,0xa1c6,0xa1c7,
+ 0xa1c8,0xa1c9,0xa1ca,0xa1cb,0xa1cc,0xa1cd,0xa1ce,0xa1cf,
+ 0xa1d0,0xa1d1,0xa1d2,0xa1d3,0xa1d4,0xa1d5,0xa1d6,0xa1d7,
+ 0xa1d8,0xa1d9,0xa1da,0xa1db,0xa1dc,0xa1dd,0xa1de,0xa1df,
+ 0xa1e0,0xa1e1,0xa1e2,0xa1e3,0xa1e4,0xa1e5,0xa1e6,0xa1e7,
+ 0xa1e8,0xa1e9,0xa1ea,0xa1eb,0xa1ec,0xa1ed,0xa1ee,0xa1ef,
+ 0xa1f0,0xa1f1,0xa1f2,0xa1f3,0xa1f4,0xa1f5,0xa1f6,0xa1f7,
+ 0xa1f8,0xa1f9,0xa1fa,0xa1fb,0xa1fc,0xa1fd,0xa1fe,0xa1ff,
+ 0xa200,0xa201,0xa202,0xa203,0xa204,0xa205,0xa206,0xa207,
+ 0xa208,0xa209,0xa20a,0xa20b,0xa20c,0xa20d,0xa20e,0xa20f,
+ 0xa210,0xa211,0xa212,0xa213,0xa214,0xa215,0xa216,0xa217,
+ 0xa218,0xa219,0xa21a,0xa21b,0xa21c,0xa21d,0xa21e,0xa21f,
+ 0xa220,0xa221,0xa222,0xa223,0xa224,0xa225,0xa226,0xa227,
+ 0xa228,0xa229,0xa22a,0xa22b,0xa22c,0xa22d,0xa22e,0xa22f,
+ 0xa230,0xa231,0xa232,0xa233,0xa234,0xa235,0xa236,0xa237,
+ 0xa238,0xa239,0xa23a,0xa23b,0xa23c,0xa23d,0xa23e,0xa23f,
+ 0xa240,0xa241,0xa242,0xa243,0xa244,0xa245,0xa246,0xa247,
+ 0xa248,0xa249,0xa24a,0xa24b,0xa24c,0xa24d,0xa24e,0xa24f,
+ 0xa250,0xa251,0xa252,0xa253,0xa254,0xa255,0xa256,0xa257,
+ 0xa258,0xa259,0xa25a,0xa25b,0xa25c,0xa25d,0xa25e,0xa25f,
+ 0xa260,0xa261,0xa262,0xa263,0xa264,0xa265,0xa266,0xa267,
+ 0xa268,0xa269,0xa26a,0xa26b,0xa26c,0xa26d,0xa26e,0xa26f,
+ 0xa270,0xa271,0xa272,0xa273,0xa274,0xa275,0xa276,0xa277,
+ 0xa278,0xa279,0xa27a,0xa27b,0xa27c,0xa27d,0xa27e,0xa27f,
+ 0xa280,0xa281,0xa282,0xa283,0xa284,0xa285,0xa286,0xa287,
+ 0xa288,0xa289,0xa28a,0xa28b,0xa28c,0xa28d,0xa28e,0xa28f,
+ 0xa290,0xa291,0xa292,0xa293,0xa294,0xa295,0xa296,0xa297,
+ 0xa298,0xa299,0xa29a,0xa29b,0xa29c,0xa29d,0xa29e,0xa29f,
+ 0xa2a0,0xa2a1,0xa2a2,0xa2a3,0xa2a4,0xa2a5,0xa2a6,0xa2a7,
+ 0xa2a8,0xa2a9,0xa2aa,0xa2ab,0xa2ac,0xa2ad,0xa2ae,0xa2af,
+ 0xa2b0,0xa2b1,0xa2b2,0xa2b3,0xa2b4,0xa2b5,0xa2b6,0xa2b7,
+ 0xa2b8,0xa2b9,0xa2ba,0xa2bb,0xa2bc,0xa2bd,0xa2be,0xa2bf,
+ 0xa2c0,0xa2c1,0xa2c2,0xa2c3,0xa2c4,0xa2c5,0xa2c6,0xa2c7,
+ 0xa2c8,0xa2c9,0xa2ca,0xa2cb,0xa2cc,0xa2cd,0xa2ce,0xa2cf,
+ 0xa2d0,0xa2d1,0xa2d2,0xa2d3,0xa2d4,0xa2d5,0xa2d6,0xa2d7,
+ 0xa2d8,0xa2d9,0xa2da,0xa2db,0xa2dc,0xa2dd,0xa2de,0xa2df,
+ 0xa2e0,0xa2e1,0xa2e2,0xa2e3,0xa2e4,0xa2e5,0xa2e6,0xa2e7,
+ 0xa2e8,0xa2e9,0xa2ea,0xa2eb,0xa2ec,0xa2ed,0xa2ee,0xa2ef,
+ 0xa2f0,0xa2f1,0xa2f2,0xa2f3,0xa2f4,0xa2f5,0xa2f6,0xa2f7,
+ 0xa2f8,0xa2f9,0xa2fa,0xa2fb,0xa2fc,0xa2fd,0xa2fe,0xa2ff,
+ 0xa300,0xa301,0xa302,0xa303,0xa304,0xa305,0xa306,0xa307,
+ 0xa308,0xa309,0xa30a,0xa30b,0xa30c,0xa30d,0xa30e,0xa30f,
+ 0xa310,0xa311,0xa312,0xa313,0xa314,0xa315,0xa316,0xa317,
+ 0xa318,0xa319,0xa31a,0xa31b,0xa31c,0xa31d,0xa31e,0xa31f,
+ 0xa320,0xa321,0xa322,0xa323,0xa324,0xa325,0xa326,0xa327,
+ 0xa328,0xa329,0xa32a,0xa32b,0xa32c,0xa32d,0xa32e,0xa32f,
+ 0xa330,0xa331,0xa332,0xa333,0xa334,0xa335,0xa336,0xa337,
+ 0xa338,0xa339,0xa33a,0xa33b,0xa33c,0xa33d,0xa33e,0xa33f,
+ 0xa340,0xa341,0xa342,0xa343,0xa344,0xa345,0xa346,0xa347,
+ 0xa348,0xa349,0xa34a,0xa34b,0xa34c,0xa34d,0xa34e,0xa34f,
+ 0xa350,0xa351,0xa352,0xa353,0xa354,0xa355,0xa356,0xa357,
+ 0xa358,0xa359,0xa35a,0xa35b,0xa35c,0xa35d,0xa35e,0xa35f,
+ 0xa360,0xa361,0xa362,0xa363,0xa364,0xa365,0xa366,0xa367,
+ 0xa368,0xa369,0xa36a,0xa36b,0xa36c,0xa36d,0xa36e,0xa36f,
+ 0xa370,0xa371,0xa372,0xa373,0xa374,0xa375,0xa376,0xa377,
+ 0xa378,0xa379,0xa37a,0xa37b,0xa37c,0xa37d,0xa37e,0xa37f,
+ 0xa380,0xa381,0xa382,0xa383,0xa384,0xa385,0xa386,0xa387,
+ 0xa388,0xa389,0xa38a,0xa38b,0xa38c,0xa38d,0xa38e,0xa38f,
+ 0xa390,0xa391,0xa392,0xa393,0xa394,0xa395,0xa396,0xa397,
+ 0xa398,0xa399,0xa39a,0xa39b,0xa39c,0xa39d,0xa39e,0xa39f,
+ 0xa3a0,0xa3a1,0xa3a2,0xa3a3,0xa3a4,0xa3a5,0xa3a6,0xa3a7,
+ 0xa3a8,0xa3a9,0xa3aa,0xa3ab,0xa3ac,0xa3ad,0xa3ae,0xa3af,
+ 0xa3b0,0xa3b1,0xa3b2,0xa3b3,0xa3b4,0xa3b5,0xa3b6,0xa3b7,
+ 0xa3b8,0xa3b9,0xa3ba,0xa3bb,0xa3bc,0xa3bd,0xa3be,0xa3bf,
+ 0xa3c0,0xa3c1,0xa3c2,0xa3c3,0xa3c4,0xa3c5,0xa3c6,0xa3c7,
+ 0xa3c8,0xa3c9,0xa3ca,0xa3cb,0xa3cc,0xa3cd,0xa3ce,0xa3cf,
+ 0xa3d0,0xa3d1,0xa3d2,0xa3d3,0xa3d4,0xa3d5,0xa3d6,0xa3d7,
+ 0xa3d8,0xa3d9,0xa3da,0xa3db,0xa3dc,0xa3dd,0xa3de,0xa3df,
+ 0xa3e0,0xa3e1,0xa3e2,0xa3e3,0xa3e4,0xa3e5,0xa3e6,0xa3e7,
+ 0xa3e8,0xa3e9,0xa3ea,0xa3eb,0xa3ec,0xa3ed,0xa3ee,0xa3ef,
+ 0xa3f0,0xa3f1,0xa3f2,0xa3f3,0xa3f4,0xa3f5,0xa3f6,0xa3f7,
+ 0xa3f8,0xa3f9,0xa3fa,0xa3fb,0xa3fc,0xa3fd,0xa3fe,0xa3ff,
+ 0xa400,0xa401,0xa402,0xa403,0xa404,0xa405,0xa406,0xa407,
+ 0xa408,0xa409,0xa40a,0xa40b,0xa40c,0xa40d,0xa40e,0xa40f,
+ 0xa410,0xa411,0xa412,0xa413,0xa414,0xa415,0xa416,0xa417,
+ 0xa418,0xa419,0xa41a,0xa41b,0xa41c,0xa41d,0xa41e,0xa41f,
+ 0xa420,0xa421,0xa422,0xa423,0xa424,0xa425,0xa426,0xa427,
+ 0xa428,0xa429,0xa42a,0xa42b,0xa42c,0xa42d,0xa42e,0xa42f,
+ 0xa430,0xa431,0xa432,0xa433,0xa434,0xa435,0xa436,0xa437,
+ 0xa438,0xa439,0xa43a,0xa43b,0xa43c,0xa43d,0xa43e,0xa43f,
+ 0xa440,0xa441,0xa442,0xa443,0xa444,0xa445,0xa446,0xa447,
+ 0xa448,0xa449,0xa44a,0xa44b,0xa44c,0xa44d,0xa44e,0xa44f,
+ 0xa450,0xa451,0xa452,0xa453,0xa454,0xa455,0xa456,0xa457,
+ 0xa458,0xa459,0xa45a,0xa45b,0xa45c,0xa45d,0xa45e,0xa45f,
+ 0xa460,0xa461,0xa462,0xa463,0xa464,0xa465,0xa466,0xa467,
+ 0xa468,0xa469,0xa46a,0xa46b,0xa46c,0xa46d,0xa46e,0xa46f,
+ 0xa470,0xa471,0xa472,0xa473,0xa474,0xa475,0xa476,0xa477,
+ 0xa478,0xa479,0xa47a,0xa47b,0xa47c,0xa47d,0xa47e,0xa47f,
+ 0xa480,0xa481,0xa482,0xa483,0xa484,0xa485,0xa486,0xa487,
+ 0xa488,0xa489,0xa48a,0xa48b,0xa48c,0xa48d,0xa48e,0xa48f,
+ 0xa490,0xa491,0xa492,0xa493,0xa494,0xa495,0xa496,0xa497,
+ 0xa498,0xa499,0xa49a,0xa49b,0xa49c,0xa49d,0xa49e,0xa49f,
+ 0xa4a0,0xa4a1,0xa4a2,0xa4a3,0xa4a4,0xa4a5,0xa4a6,0xa4a7,
+ 0xa4a8,0xa4a9,0xa4aa,0xa4ab,0xa4ac,0xa4ad,0xa4ae,0xa4af,
+ 0xa4b0,0xa4b1,0xa4b2,0xa4b3,0xa4b4,0xa4b5,0xa4b6,0xa4b7,
+ 0xa4b8,0xa4b9,0xa4ba,0xa4bb,0xa4bc,0xa4bd,0xa4be,0xa4bf,
+ 0xa4c0,0xa4c1,0xa4c2,0xa4c3,0xa4c4,0xa4c5,0xa4c6,0xa4c7,
+ 0xa4c8,0xa4c9,0xa4ca,0xa4cb,0xa4cc,0xa4cd,0xa4ce,0xa4cf,
+ 0xa4d0,0xa4d1,0xa4d2,0xa4d3,0xa4d4,0xa4d5,0xa4d6,0xa4d7,
+ 0xa4d8,0xa4d9,0xa4da,0xa4db,0xa4dc,0xa4dd,0xa4de,0xa4df,
+ 0xa4e0,0xa4e1,0xa4e2,0xa4e3,0xa4e4,0xa4e5,0xa4e6,0xa4e7,
+ 0xa4e8,0xa4e9,0xa4ea,0xa4eb,0xa4ec,0xa4ed,0xa4ee,0xa4ef,
+ 0xa4f0,0xa4f1,0xa4f2,0xa4f3,0xa4f4,0xa4f5,0xa4f6,0xa4f7,
+ 0xa4f8,0xa4f9,0xa4fa,0xa4fb,0xa4fc,0xa4fd,0xa4fe,0xa4ff,
+ 0xa500,0xa501,0xa502,0xa503,0xa504,0xa505,0xa506,0xa507,
+ 0xa508,0xa509,0xa50a,0xa50b,0xa50c,0xa50d,0xa50e,0xa50f,
+ 0xa510,0xa511,0xa512,0xa513,0xa514,0xa515,0xa516,0xa517,
+ 0xa518,0xa519,0xa51a,0xa51b,0xa51c,0xa51d,0xa51e,0xa51f,
+ 0xa520,0xa521,0xa522,0xa523,0xa524,0xa525,0xa526,0xa527,
+ 0xa528,0xa529,0xa52a,0xa52b,0xa52c,0xa52d,0xa52e,0xa52f,
+ 0xa530,0xa531,0xa532,0xa533,0xa534,0xa535,0xa536,0xa537,
+ 0xa538,0xa539,0xa53a,0xa53b,0xa53c,0xa53d,0xa53e,0xa53f,
+ 0xa540,0xa541,0xa542,0xa543,0xa544,0xa545,0xa546,0xa547,
+ 0xa548,0xa549,0xa54a,0xa54b,0xa54c,0xa54d,0xa54e,0xa54f,
+ 0xa550,0xa551,0xa552,0xa553,0xa554,0xa555,0xa556,0xa557,
+ 0xa558,0xa559,0xa55a,0xa55b,0xa55c,0xa55d,0xa55e,0xa55f,
+ 0xa560,0xa561,0xa562,0xa563,0xa564,0xa565,0xa566,0xa567,
+ 0xa568,0xa569,0xa56a,0xa56b,0xa56c,0xa56d,0xa56e,0xa56f,
+ 0xa570,0xa571,0xa572,0xa573,0xa574,0xa575,0xa576,0xa577,
+ 0xa578,0xa579,0xa57a,0xa57b,0xa57c,0xa57d,0xa57e,0xa57f,
+ 0xa580,0xa581,0xa582,0xa583,0xa584,0xa585,0xa586,0xa587,
+ 0xa588,0xa589,0xa58a,0xa58b,0xa58c,0xa58d,0xa58e,0xa58f,
+ 0xa590,0xa591,0xa592,0xa593,0xa594,0xa595,0xa596,0xa597,
+ 0xa598,0xa599,0xa59a,0xa59b,0xa59c,0xa59d,0xa59e,0xa59f,
+ 0xa5a0,0xa5a1,0xa5a2,0xa5a3,0xa5a4,0xa5a5,0xa5a6,0xa5a7,
+ 0xa5a8,0xa5a9,0xa5aa,0xa5ab,0xa5ac,0xa5ad,0xa5ae,0xa5af,
+ 0xa5b0,0xa5b1,0xa5b2,0xa5b3,0xa5b4,0xa5b5,0xa5b6,0xa5b7,
+ 0xa5b8,0xa5b9,0xa5ba,0xa5bb,0xa5bc,0xa5bd,0xa5be,0xa5bf,
+ 0xa5c0,0xa5c1,0xa5c2,0xa5c3,0xa5c4,0xa5c5,0xa5c6,0xa5c7,
+ 0xa5c8,0xa5c9,0xa5ca,0xa5cb,0xa5cc,0xa5cd,0xa5ce,0xa5cf,
+ 0xa5d0,0xa5d1,0xa5d2,0xa5d3,0xa5d4,0xa5d5,0xa5d6,0xa5d7,
+ 0xa5d8,0xa5d9,0xa5da,0xa5db,0xa5dc,0xa5dd,0xa5de,0xa5df,
+ 0xa5e0,0xa5e1,0xa5e2,0xa5e3,0xa5e4,0xa5e5,0xa5e6,0xa5e7,
+ 0xa5e8,0xa5e9,0xa5ea,0xa5eb,0xa5ec,0xa5ed,0xa5ee,0xa5ef,
+ 0xa5f0,0xa5f1,0xa5f2,0xa5f3,0xa5f4,0xa5f5,0xa5f6,0xa5f7,
+ 0xa5f8,0xa5f9,0xa5fa,0xa5fb,0xa5fc,0xa5fd,0xa5fe,0xa5ff,
+ 0xa600,0xa601,0xa602,0xa603,0xa604,0xa605,0xa606,0xa607,
+ 0xa608,0xa609,0xa60a,0xa60b,0xa60c,0xa60d,0xa60e,0xa60f,
+ 0xa610,0xa611,0xa612,0xa613,0xa614,0xa615,0xa616,0xa617,
+ 0xa618,0xa619,0xa61a,0xa61b,0xa61c,0xa61d,0xa61e,0xa61f,
+ 0xa620,0xa621,0xa622,0xa623,0xa624,0xa625,0xa626,0xa627,
+ 0xa628,0xa629,0xa62a,0xa62b,0xa62c,0xa62d,0xa62e,0xa62f,
+ 0xa630,0xa631,0xa632,0xa633,0xa634,0xa635,0xa636,0xa637,
+ 0xa638,0xa639,0xa63a,0xa63b,0xa63c,0xa63d,0xa63e,0xa63f,
+ 0xa640,0xa641,0xa642,0xa643,0xa644,0xa645,0xa646,0xa647,
+ 0xa648,0xa649,0xa64a,0xa64b,0xa64c,0xa64d,0xa64e,0xa64f,
+ 0xa650,0xa651,0xa652,0xa653,0xa654,0xa655,0xa656,0xa657,
+ 0xa658,0xa659,0xa65a,0xa65b,0xa65c,0xa65d,0xa65e,0xa65f,
+ 0xa660,0xa661,0xa662,0xa663,0xa664,0xa665,0xa666,0xa667,
+ 0xa668,0xa669,0xa66a,0xa66b,0xa66c,0xa66d,0xa66e,0xa66f,
+ 0xa670,0xa671,0xa672,0xa673,0xa674,0xa675,0xa676,0xa677,
+ 0xa678,0xa679,0xa67a,0xa67b,0xa67c,0xa67d,0xa67e,0xa67f,
+ 0xa680,0xa681,0xa682,0xa683,0xa684,0xa685,0xa686,0xa687,
+ 0xa688,0xa689,0xa68a,0xa68b,0xa68c,0xa68d,0xa68e,0xa68f,
+ 0xa690,0xa691,0xa692,0xa693,0xa694,0xa695,0xa696,0xa697,
+ 0xa698,0xa699,0xa69a,0xa69b,0xa69c,0xa69d,0xa69e,0xa69f,
+ 0xa6a0,0xa6a1,0xa6a2,0xa6a3,0xa6a4,0xa6a5,0xa6a6,0xa6a7,
+ 0xa6a8,0xa6a9,0xa6aa,0xa6ab,0xa6ac,0xa6ad,0xa6ae,0xa6af,
+ 0xa6b0,0xa6b1,0xa6b2,0xa6b3,0xa6b4,0xa6b5,0xa6b6,0xa6b7,
+ 0xa6b8,0xa6b9,0xa6ba,0xa6bb,0xa6bc,0xa6bd,0xa6be,0xa6bf,
+ 0xa6c0,0xa6c1,0xa6c2,0xa6c3,0xa6c4,0xa6c5,0xa6c6,0xa6c7,
+ 0xa6c8,0xa6c9,0xa6ca,0xa6cb,0xa6cc,0xa6cd,0xa6ce,0xa6cf,
+ 0xa6d0,0xa6d1,0xa6d2,0xa6d3,0xa6d4,0xa6d5,0xa6d6,0xa6d7,
+ 0xa6d8,0xa6d9,0xa6da,0xa6db,0xa6dc,0xa6dd,0xa6de,0xa6df,
+ 0xa6e0,0xa6e1,0xa6e2,0xa6e3,0xa6e4,0xa6e5,0xa6e6,0xa6e7,
+ 0xa6e8,0xa6e9,0xa6ea,0xa6eb,0xa6ec,0xa6ed,0xa6ee,0xa6ef,
+ 0xa6f0,0xa6f1,0xa6f2,0xa6f3,0xa6f4,0xa6f5,0xa6f6,0xa6f7,
+ 0xa6f8,0xa6f9,0xa6fa,0xa6fb,0xa6fc,0xa6fd,0xa6fe,0xa6ff,
+ 0xa700,0xa701,0xa702,0xa703,0xa704,0xa705,0xa706,0xa707,
+ 0xa708,0xa709,0xa70a,0xa70b,0xa70c,0xa70d,0xa70e,0xa70f,
+ 0xa710,0xa711,0xa712,0xa713,0xa714,0xa715,0xa716,0xa717,
+ 0xa718,0xa719,0xa71a,0xa71b,0xa71c,0xa71d,0xa71e,0xa71f,
+ 0xa720,0xa721,0xa722,0xa723,0xa724,0xa725,0xa726,0xa727,
+ 0xa728,0xa729,0xa72a,0xa72b,0xa72c,0xa72d,0xa72e,0xa72f,
+ 0xa730,0xa731,0xa732,0xa733,0xa734,0xa735,0xa736,0xa737,
+ 0xa738,0xa739,0xa73a,0xa73b,0xa73c,0xa73d,0xa73e,0xa73f,
+ 0xa740,0xa741,0xa742,0xa743,0xa744,0xa745,0xa746,0xa747,
+ 0xa748,0xa749,0xa74a,0xa74b,0xa74c,0xa74d,0xa74e,0xa74f,
+ 0xa750,0xa751,0xa752,0xa753,0xa754,0xa755,0xa756,0xa757,
+ 0xa758,0xa759,0xa75a,0xa75b,0xa75c,0xa75d,0xa75e,0xa75f,
+ 0xa760,0xa761,0xa762,0xa763,0xa764,0xa765,0xa766,0xa767,
+ 0xa768,0xa769,0xa76a,0xa76b,0xa76c,0xa76d,0xa76e,0xa76f,
+ 0xa770,0xa771,0xa772,0xa773,0xa774,0xa775,0xa776,0xa777,
+ 0xa778,0xa779,0xa77a,0xa77b,0xa77c,0xa77d,0xa77e,0xa77f,
+ 0xa780,0xa781,0xa782,0xa783,0xa784,0xa785,0xa786,0xa787,
+ 0xa788,0xa789,0xa78a,0xa78b,0xa78c,0xa78d,0xa78e,0xa78f,
+ 0xa790,0xa791,0xa792,0xa793,0xa794,0xa795,0xa796,0xa797,
+ 0xa798,0xa799,0xa79a,0xa79b,0xa79c,0xa79d,0xa79e,0xa79f,
+ 0xa7a0,0xa7a1,0xa7a2,0xa7a3,0xa7a4,0xa7a5,0xa7a6,0xa7a7,
+ 0xa7a8,0xa7a9,0xa7aa,0xa7ab,0xa7ac,0xa7ad,0xa7ae,0xa7af,
+ 0xa7b0,0xa7b1,0xa7b2,0xa7b3,0xa7b4,0xa7b5,0xa7b6,0xa7b7,
+ 0xa7b8,0xa7b9,0xa7ba,0xa7bb,0xa7bc,0xa7bd,0xa7be,0xa7bf,
+ 0xa7c0,0xa7c1,0xa7c2,0xa7c3,0xa7c4,0xa7c5,0xa7c6,0xa7c7,
+ 0xa7c8,0xa7c9,0xa7ca,0xa7cb,0xa7cc,0xa7cd,0xa7ce,0xa7cf,
+ 0xa7d0,0xa7d1,0xa7d2,0xa7d3,0xa7d4,0xa7d5,0xa7d6,0xa7d7,
+ 0xa7d8,0xa7d9,0xa7da,0xa7db,0xa7dc,0xa7dd,0xa7de,0xa7df,
+ 0xa7e0,0xa7e1,0xa7e2,0xa7e3,0xa7e4,0xa7e5,0xa7e6,0xa7e7,
+ 0xa7e8,0xa7e9,0xa7ea,0xa7eb,0xa7ec,0xa7ed,0xa7ee,0xa7ef,
+ 0xa7f0,0xa7f1,0xa7f2,0xa7f3,0xa7f4,0xa7f5,0xa7f6,0xa7f7,
+ 0xa7f8,0xa7f9,0xa7fa,0xa7fb,0xa7fc,0xa7fd,0xa7fe,0xa7ff,
+ 0xa800,0xa801,0xa802,0xa803,0xa804,0xa805,0xa806,0xa807,
+ 0xa808,0xa809,0xa80a,0xa80b,0xa80c,0xa80d,0xa80e,0xa80f,
+ 0xa810,0xa811,0xa812,0xa813,0xa814,0xa815,0xa816,0xa817,
+ 0xa818,0xa819,0xa81a,0xa81b,0xa81c,0xa81d,0xa81e,0xa81f,
+ 0xa820,0xa821,0xa822,0xa823,0xa824,0xa825,0xa826,0xa827,
+ 0xa828,0xa829,0xa82a,0xa82b,0xa82c,0xa82d,0xa82e,0xa82f,
+ 0xa830,0xa831,0xa832,0xa833,0xa834,0xa835,0xa836,0xa837,
+ 0xa838,0xa839,0xa83a,0xa83b,0xa83c,0xa83d,0xa83e,0xa83f,
+ 0xa840,0xa841,0xa842,0xa843,0xa844,0xa845,0xa846,0xa847,
+ 0xa848,0xa849,0xa84a,0xa84b,0xa84c,0xa84d,0xa84e,0xa84f,
+ 0xa850,0xa851,0xa852,0xa853,0xa854,0xa855,0xa856,0xa857,
+ 0xa858,0xa859,0xa85a,0xa85b,0xa85c,0xa85d,0xa85e,0xa85f,
+ 0xa860,0xa861,0xa862,0xa863,0xa864,0xa865,0xa866,0xa867,
+ 0xa868,0xa869,0xa86a,0xa86b,0xa86c,0xa86d,0xa86e,0xa86f,
+ 0xa870,0xa871,0xa872,0xa873,0xa874,0xa875,0xa876,0xa877,
+ 0xa878,0xa879,0xa87a,0xa87b,0xa87c,0xa87d,0xa87e,0xa87f,
+ 0xa880,0xa881,0xa882,0xa883,0xa884,0xa885,0xa886,0xa887,
+ 0xa888,0xa889,0xa88a,0xa88b,0xa88c,0xa88d,0xa88e,0xa88f,
+ 0xa890,0xa891,0xa892,0xa893,0xa894,0xa895,0xa896,0xa897,
+ 0xa898,0xa899,0xa89a,0xa89b,0xa89c,0xa89d,0xa89e,0xa89f,
+ 0xa8a0,0xa8a1,0xa8a2,0xa8a3,0xa8a4,0xa8a5,0xa8a6,0xa8a7,
+ 0xa8a8,0xa8a9,0xa8aa,0xa8ab,0xa8ac,0xa8ad,0xa8ae,0xa8af,
+ 0xa8b0,0xa8b1,0xa8b2,0xa8b3,0xa8b4,0xa8b5,0xa8b6,0xa8b7,
+ 0xa8b8,0xa8b9,0xa8ba,0xa8bb,0xa8bc,0xa8bd,0xa8be,0xa8bf,
+ 0xa8c0,0xa8c1,0xa8c2,0xa8c3,0xa8c4,0xa8c5,0xa8c6,0xa8c7,
+ 0xa8c8,0xa8c9,0xa8ca,0xa8cb,0xa8cc,0xa8cd,0xa8ce,0xa8cf,
+ 0xa8d0,0xa8d1,0xa8d2,0xa8d3,0xa8d4,0xa8d5,0xa8d6,0xa8d7,
+ 0xa8d8,0xa8d9,0xa8da,0xa8db,0xa8dc,0xa8dd,0xa8de,0xa8df,
+ 0xa8e0,0xa8e1,0xa8e2,0xa8e3,0xa8e4,0xa8e5,0xa8e6,0xa8e7,
+ 0xa8e8,0xa8e9,0xa8ea,0xa8eb,0xa8ec,0xa8ed,0xa8ee,0xa8ef,
+ 0xa8f0,0xa8f1,0xa8f2,0xa8f3,0xa8f4,0xa8f5,0xa8f6,0xa8f7,
+ 0xa8f8,0xa8f9,0xa8fa,0xa8fb,0xa8fc,0xa8fd,0xa8fe,0xa8ff,
+ 0xa900,0xa901,0xa902,0xa903,0xa904,0xa905,0xa906,0xa907,
+ 0xa908,0xa909,0xa90a,0xa90b,0xa90c,0xa90d,0xa90e,0xa90f,
+ 0xa910,0xa911,0xa912,0xa913,0xa914,0xa915,0xa916,0xa917,
+ 0xa918,0xa919,0xa91a,0xa91b,0xa91c,0xa91d,0xa91e,0xa91f,
+ 0xa920,0xa921,0xa922,0xa923,0xa924,0xa925,0xa926,0xa927,
+ 0xa928,0xa929,0xa92a,0xa92b,0xa92c,0xa92d,0xa92e,0xa92f,
+ 0xa930,0xa931,0xa932,0xa933,0xa934,0xa935,0xa936,0xa937,
+ 0xa938,0xa939,0xa93a,0xa93b,0xa93c,0xa93d,0xa93e,0xa93f,
+ 0xa940,0xa941,0xa942,0xa943,0xa944,0xa945,0xa946,0xa947,
+ 0xa948,0xa949,0xa94a,0xa94b,0xa94c,0xa94d,0xa94e,0xa94f,
+ 0xa950,0xa951,0xa952,0xa953,0xa954,0xa955,0xa956,0xa957,
+ 0xa958,0xa959,0xa95a,0xa95b,0xa95c,0xa95d,0xa95e,0xa95f,
+ 0xa960,0xa961,0xa962,0xa963,0xa964,0xa965,0xa966,0xa967,
+ 0xa968,0xa969,0xa96a,0xa96b,0xa96c,0xa96d,0xa96e,0xa96f,
+ 0xa970,0xa971,0xa972,0xa973,0xa974,0xa975,0xa976,0xa977,
+ 0xa978,0xa979,0xa97a,0xa97b,0xa97c,0xa97d,0xa97e,0xa97f,
+ 0xa980,0xa981,0xa982,0xa983,0xa984,0xa985,0xa986,0xa987,
+ 0xa988,0xa989,0xa98a,0xa98b,0xa98c,0xa98d,0xa98e,0xa98f,
+ 0xa990,0xa991,0xa992,0xa993,0xa994,0xa995,0xa996,0xa997,
+ 0xa998,0xa999,0xa99a,0xa99b,0xa99c,0xa99d,0xa99e,0xa99f,
+ 0xa9a0,0xa9a1,0xa9a2,0xa9a3,0xa9a4,0xa9a5,0xa9a6,0xa9a7,
+ 0xa9a8,0xa9a9,0xa9aa,0xa9ab,0xa9ac,0xa9ad,0xa9ae,0xa9af,
+ 0xa9b0,0xa9b1,0xa9b2,0xa9b3,0xa9b4,0xa9b5,0xa9b6,0xa9b7,
+ 0xa9b8,0xa9b9,0xa9ba,0xa9bb,0xa9bc,0xa9bd,0xa9be,0xa9bf,
+ 0xa9c0,0xa9c1,0xa9c2,0xa9c3,0xa9c4,0xa9c5,0xa9c6,0xa9c7,
+ 0xa9c8,0xa9c9,0xa9ca,0xa9cb,0xa9cc,0xa9cd,0xa9ce,0xa9cf,
+ 0xa9d0,0xa9d1,0xa9d2,0xa9d3,0xa9d4,0xa9d5,0xa9d6,0xa9d7,
+ 0xa9d8,0xa9d9,0xa9da,0xa9db,0xa9dc,0xa9dd,0xa9de,0xa9df,
+ 0xa9e0,0xa9e1,0xa9e2,0xa9e3,0xa9e4,0xa9e5,0xa9e6,0xa9e7,
+ 0xa9e8,0xa9e9,0xa9ea,0xa9eb,0xa9ec,0xa9ed,0xa9ee,0xa9ef,
+ 0xa9f0,0xa9f1,0xa9f2,0xa9f3,0xa9f4,0xa9f5,0xa9f6,0xa9f7,
+ 0xa9f8,0xa9f9,0xa9fa,0xa9fb,0xa9fc,0xa9fd,0xa9fe,0xa9ff,
+ 0xaa00,0xaa01,0xaa02,0xaa03,0xaa04,0xaa05,0xaa06,0xaa07,
+ 0xaa08,0xaa09,0xaa0a,0xaa0b,0xaa0c,0xaa0d,0xaa0e,0xaa0f,
+ 0xaa10,0xaa11,0xaa12,0xaa13,0xaa14,0xaa15,0xaa16,0xaa17,
+ 0xaa18,0xaa19,0xaa1a,0xaa1b,0xaa1c,0xaa1d,0xaa1e,0xaa1f,
+ 0xaa20,0xaa21,0xaa22,0xaa23,0xaa24,0xaa25,0xaa26,0xaa27,
+ 0xaa28,0xaa29,0xaa2a,0xaa2b,0xaa2c,0xaa2d,0xaa2e,0xaa2f,
+ 0xaa30,0xaa31,0xaa32,0xaa33,0xaa34,0xaa35,0xaa36,0xaa37,
+ 0xaa38,0xaa39,0xaa3a,0xaa3b,0xaa3c,0xaa3d,0xaa3e,0xaa3f,
+ 0xaa40,0xaa41,0xaa42,0xaa43,0xaa44,0xaa45,0xaa46,0xaa47,
+ 0xaa48,0xaa49,0xaa4a,0xaa4b,0xaa4c,0xaa4d,0xaa4e,0xaa4f,
+ 0xaa50,0xaa51,0xaa52,0xaa53,0xaa54,0xaa55,0xaa56,0xaa57,
+ 0xaa58,0xaa59,0xaa5a,0xaa5b,0xaa5c,0xaa5d,0xaa5e,0xaa5f,
+ 0xaa60,0xaa61,0xaa62,0xaa63,0xaa64,0xaa65,0xaa66,0xaa67,
+ 0xaa68,0xaa69,0xaa6a,0xaa6b,0xaa6c,0xaa6d,0xaa6e,0xaa6f,
+ 0xaa70,0xaa71,0xaa72,0xaa73,0xaa74,0xaa75,0xaa76,0xaa77,
+ 0xaa78,0xaa79,0xaa7a,0xaa7b,0xaa7c,0xaa7d,0xaa7e,0xaa7f,
+ 0xaa80,0xaa81,0xaa82,0xaa83,0xaa84,0xaa85,0xaa86,0xaa87,
+ 0xaa88,0xaa89,0xaa8a,0xaa8b,0xaa8c,0xaa8d,0xaa8e,0xaa8f,
+ 0xaa90,0xaa91,0xaa92,0xaa93,0xaa94,0xaa95,0xaa96,0xaa97,
+ 0xaa98,0xaa99,0xaa9a,0xaa9b,0xaa9c,0xaa9d,0xaa9e,0xaa9f,
+ 0xaaa0,0xaaa1,0xaaa2,0xaaa3,0xaaa4,0xaaa5,0xaaa6,0xaaa7,
+ 0xaaa8,0xaaa9,0xaaaa,0xaaab,0xaaac,0xaaad,0xaaae,0xaaaf,
+ 0xaab0,0xaab1,0xaab2,0xaab3,0xaab4,0xaab5,0xaab6,0xaab7,
+ 0xaab8,0xaab9,0xaaba,0xaabb,0xaabc,0xaabd,0xaabe,0xaabf,
+ 0xaac0,0xaac1,0xaac2,0xaac3,0xaac4,0xaac5,0xaac6,0xaac7,
+ 0xaac8,0xaac9,0xaaca,0xaacb,0xaacc,0xaacd,0xaace,0xaacf,
+ 0xaad0,0xaad1,0xaad2,0xaad3,0xaad4,0xaad5,0xaad6,0xaad7,
+ 0xaad8,0xaad9,0xaada,0xaadb,0xaadc,0xaadd,0xaade,0xaadf,
+ 0xaae0,0xaae1,0xaae2,0xaae3,0xaae4,0xaae5,0xaae6,0xaae7,
+ 0xaae8,0xaae9,0xaaea,0xaaeb,0xaaec,0xaaed,0xaaee,0xaaef,
+ 0xaaf0,0xaaf1,0xaaf2,0xaaf3,0xaaf4,0xaaf5,0xaaf6,0xaaf7,
+ 0xaaf8,0xaaf9,0xaafa,0xaafb,0xaafc,0xaafd,0xaafe,0xaaff,
+ 0xab00,0xab01,0xab02,0xab03,0xab04,0xab05,0xab06,0xab07,
+ 0xab08,0xab09,0xab0a,0xab0b,0xab0c,0xab0d,0xab0e,0xab0f,
+ 0xab10,0xab11,0xab12,0xab13,0xab14,0xab15,0xab16,0xab17,
+ 0xab18,0xab19,0xab1a,0xab1b,0xab1c,0xab1d,0xab1e,0xab1f,
+ 0xab20,0xab21,0xab22,0xab23,0xab24,0xab25,0xab26,0xab27,
+ 0xab28,0xab29,0xab2a,0xab2b,0xab2c,0xab2d,0xab2e,0xab2f,
+ 0xab30,0xab31,0xab32,0xab33,0xab34,0xab35,0xab36,0xab37,
+ 0xab38,0xab39,0xab3a,0xab3b,0xab3c,0xab3d,0xab3e,0xab3f,
+ 0xab40,0xab41,0xab42,0xab43,0xab44,0xab45,0xab46,0xab47,
+ 0xab48,0xab49,0xab4a,0xab4b,0xab4c,0xab4d,0xab4e,0xab4f,
+ 0xab50,0xab51,0xab52,0xab53,0xab54,0xab55,0xab56,0xab57,
+ 0xab58,0xab59,0xab5a,0xab5b,0xab5c,0xab5d,0xab5e,0xab5f,
+ 0xab60,0xab61,0xab62,0xab63,0xab64,0xab65,0xab66,0xab67,
+ 0xab68,0xab69,0xab6a,0xab6b,0xab6c,0xab6d,0xab6e,0xab6f,
+ 0xab70,0xab71,0xab72,0xab73,0xab74,0xab75,0xab76,0xab77,
+ 0xab78,0xab79,0xab7a,0xab7b,0xab7c,0xab7d,0xab7e,0xab7f,
+ 0xab80,0xab81,0xab82,0xab83,0xab84,0xab85,0xab86,0xab87,
+ 0xab88,0xab89,0xab8a,0xab8b,0xab8c,0xab8d,0xab8e,0xab8f,
+ 0xab90,0xab91,0xab92,0xab93,0xab94,0xab95,0xab96,0xab97,
+ 0xab98,0xab99,0xab9a,0xab9b,0xab9c,0xab9d,0xab9e,0xab9f,
+ 0xaba0,0xaba1,0xaba2,0xaba3,0xaba4,0xaba5,0xaba6,0xaba7,
+ 0xaba8,0xaba9,0xabaa,0xabab,0xabac,0xabad,0xabae,0xabaf,
+ 0xabb0,0xabb1,0xabb2,0xabb3,0xabb4,0xabb5,0xabb6,0xabb7,
+ 0xabb8,0xabb9,0xabba,0xabbb,0xabbc,0xabbd,0xabbe,0xabbf,
+ 0xabc0,0xabc1,0xabc2,0xabc3,0xabc4,0xabc5,0xabc6,0xabc7,
+ 0xabc8,0xabc9,0xabca,0xabcb,0xabcc,0xabcd,0xabce,0xabcf,
+ 0xabd0,0xabd1,0xabd2,0xabd3,0xabd4,0xabd5,0xabd6,0xabd7,
+ 0xabd8,0xabd9,0xabda,0xabdb,0xabdc,0xabdd,0xabde,0xabdf,
+ 0xabe0,0xabe1,0xabe2,0xabe3,0xabe4,0xabe5,0xabe6,0xabe7,
+ 0xabe8,0xabe9,0xabea,0xabeb,0xabec,0xabed,0xabee,0xabef,
+ 0xabf0,0xabf1,0xabf2,0xabf3,0xabf4,0xabf5,0xabf6,0xabf7,
+ 0xabf8,0xabf9,0xabfa,0xabfb,0xabfc,0xabfd,0xabfe,0xabff,
+ 0xac00,0xac01,0xac02,0xac03,0xac04,0xac05,0xac06,0xac07,
+ 0xac08,0xac09,0xac0a,0xac0b,0xac0c,0xac0d,0xac0e,0xac0f,
+ 0xac10,0xac11,0xac12,0xac13,0xac14,0xac15,0xac16,0xac17,
+ 0xac18,0xac19,0xac1a,0xac1b,0xac1c,0xac1d,0xac1e,0xac1f,
+ 0xac20,0xac21,0xac22,0xac23,0xac24,0xac25,0xac26,0xac27,
+ 0xac28,0xac29,0xac2a,0xac2b,0xac2c,0xac2d,0xac2e,0xac2f,
+ 0xac30,0xac31,0xac32,0xac33,0xac34,0xac35,0xac36,0xac37,
+ 0xac38,0xac39,0xac3a,0xac3b,0xac3c,0xac3d,0xac3e,0xac3f,
+ 0xac40,0xac41,0xac42,0xac43,0xac44,0xac45,0xac46,0xac47,
+ 0xac48,0xac49,0xac4a,0xac4b,0xac4c,0xac4d,0xac4e,0xac4f,
+ 0xac50,0xac51,0xac52,0xac53,0xac54,0xac55,0xac56,0xac57,
+ 0xac58,0xac59,0xac5a,0xac5b,0xac5c,0xac5d,0xac5e,0xac5f,
+ 0xac60,0xac61,0xac62,0xac63,0xac64,0xac65,0xac66,0xac67,
+ 0xac68,0xac69,0xac6a,0xac6b,0xac6c,0xac6d,0xac6e,0xac6f,
+ 0xac70,0xac71,0xac72,0xac73,0xac74,0xac75,0xac76,0xac77,
+ 0xac78,0xac79,0xac7a,0xac7b,0xac7c,0xac7d,0xac7e,0xac7f,
+ 0xac80,0xac81,0xac82,0xac83,0xac84,0xac85,0xac86,0xac87,
+ 0xac88,0xac89,0xac8a,0xac8b,0xac8c,0xac8d,0xac8e,0xac8f,
+ 0xac90,0xac91,0xac92,0xac93,0xac94,0xac95,0xac96,0xac97,
+ 0xac98,0xac99,0xac9a,0xac9b,0xac9c,0xac9d,0xac9e,0xac9f,
+ 0xaca0,0xaca1,0xaca2,0xaca3,0xaca4,0xaca5,0xaca6,0xaca7,
+ 0xaca8,0xaca9,0xacaa,0xacab,0xacac,0xacad,0xacae,0xacaf,
+ 0xacb0,0xacb1,0xacb2,0xacb3,0xacb4,0xacb5,0xacb6,0xacb7,
+ 0xacb8,0xacb9,0xacba,0xacbb,0xacbc,0xacbd,0xacbe,0xacbf,
+ 0xacc0,0xacc1,0xacc2,0xacc3,0xacc4,0xacc5,0xacc6,0xacc7,
+ 0xacc8,0xacc9,0xacca,0xaccb,0xaccc,0xaccd,0xacce,0xaccf,
+ 0xacd0,0xacd1,0xacd2,0xacd3,0xacd4,0xacd5,0xacd6,0xacd7,
+ 0xacd8,0xacd9,0xacda,0xacdb,0xacdc,0xacdd,0xacde,0xacdf,
+ 0xace0,0xace1,0xace2,0xace3,0xace4,0xace5,0xace6,0xace7,
+ 0xace8,0xace9,0xacea,0xaceb,0xacec,0xaced,0xacee,0xacef,
+ 0xacf0,0xacf1,0xacf2,0xacf3,0xacf4,0xacf5,0xacf6,0xacf7,
+ 0xacf8,0xacf9,0xacfa,0xacfb,0xacfc,0xacfd,0xacfe,0xacff,
+ 0xad00,0xad01,0xad02,0xad03,0xad04,0xad05,0xad06,0xad07,
+ 0xad08,0xad09,0xad0a,0xad0b,0xad0c,0xad0d,0xad0e,0xad0f,
+ 0xad10,0xad11,0xad12,0xad13,0xad14,0xad15,0xad16,0xad17,
+ 0xad18,0xad19,0xad1a,0xad1b,0xad1c,0xad1d,0xad1e,0xad1f,
+ 0xad20,0xad21,0xad22,0xad23,0xad24,0xad25,0xad26,0xad27,
+ 0xad28,0xad29,0xad2a,0xad2b,0xad2c,0xad2d,0xad2e,0xad2f,
+ 0xad30,0xad31,0xad32,0xad33,0xad34,0xad35,0xad36,0xad37,
+ 0xad38,0xad39,0xad3a,0xad3b,0xad3c,0xad3d,0xad3e,0xad3f,
+ 0xad40,0xad41,0xad42,0xad43,0xad44,0xad45,0xad46,0xad47,
+ 0xad48,0xad49,0xad4a,0xad4b,0xad4c,0xad4d,0xad4e,0xad4f,
+ 0xad50,0xad51,0xad52,0xad53,0xad54,0xad55,0xad56,0xad57,
+ 0xad58,0xad59,0xad5a,0xad5b,0xad5c,0xad5d,0xad5e,0xad5f,
+ 0xad60,0xad61,0xad62,0xad63,0xad64,0xad65,0xad66,0xad67,
+ 0xad68,0xad69,0xad6a,0xad6b,0xad6c,0xad6d,0xad6e,0xad6f,
+ 0xad70,0xad71,0xad72,0xad73,0xad74,0xad75,0xad76,0xad77,
+ 0xad78,0xad79,0xad7a,0xad7b,0xad7c,0xad7d,0xad7e,0xad7f,
+ 0xad80,0xad81,0xad82,0xad83,0xad84,0xad85,0xad86,0xad87,
+ 0xad88,0xad89,0xad8a,0xad8b,0xad8c,0xad8d,0xad8e,0xad8f,
+ 0xad90,0xad91,0xad92,0xad93,0xad94,0xad95,0xad96,0xad97,
+ 0xad98,0xad99,0xad9a,0xad9b,0xad9c,0xad9d,0xad9e,0xad9f,
+ 0xada0,0xada1,0xada2,0xada3,0xada4,0xada5,0xada6,0xada7,
+ 0xada8,0xada9,0xadaa,0xadab,0xadac,0xadad,0xadae,0xadaf,
+ 0xadb0,0xadb1,0xadb2,0xadb3,0xadb4,0xadb5,0xadb6,0xadb7,
+ 0xadb8,0xadb9,0xadba,0xadbb,0xadbc,0xadbd,0xadbe,0xadbf,
+ 0xadc0,0xadc1,0xadc2,0xadc3,0xadc4,0xadc5,0xadc6,0xadc7,
+ 0xadc8,0xadc9,0xadca,0xadcb,0xadcc,0xadcd,0xadce,0xadcf,
+ 0xadd0,0xadd1,0xadd2,0xadd3,0xadd4,0xadd5,0xadd6,0xadd7,
+ 0xadd8,0xadd9,0xadda,0xaddb,0xaddc,0xaddd,0xadde,0xaddf,
+ 0xade0,0xade1,0xade2,0xade3,0xade4,0xade5,0xade6,0xade7,
+ 0xade8,0xade9,0xadea,0xadeb,0xadec,0xaded,0xadee,0xadef,
+ 0xadf0,0xadf1,0xadf2,0xadf3,0xadf4,0xadf5,0xadf6,0xadf7,
+ 0xadf8,0xadf9,0xadfa,0xadfb,0xadfc,0xadfd,0xadfe,0xadff,
+ 0xae00,0xae01,0xae02,0xae03,0xae04,0xae05,0xae06,0xae07,
+ 0xae08,0xae09,0xae0a,0xae0b,0xae0c,0xae0d,0xae0e,0xae0f,
+ 0xae10,0xae11,0xae12,0xae13,0xae14,0xae15,0xae16,0xae17,
+ 0xae18,0xae19,0xae1a,0xae1b,0xae1c,0xae1d,0xae1e,0xae1f,
+ 0xae20,0xae21,0xae22,0xae23,0xae24,0xae25,0xae26,0xae27,
+ 0xae28,0xae29,0xae2a,0xae2b,0xae2c,0xae2d,0xae2e,0xae2f,
+ 0xae30,0xae31,0xae32,0xae33,0xae34,0xae35,0xae36,0xae37,
+ 0xae38,0xae39,0xae3a,0xae3b,0xae3c,0xae3d,0xae3e,0xae3f,
+ 0xae40,0xae41,0xae42,0xae43,0xae44,0xae45,0xae46,0xae47,
+ 0xae48,0xae49,0xae4a,0xae4b,0xae4c,0xae4d,0xae4e,0xae4f,
+ 0xae50,0xae51,0xae52,0xae53,0xae54,0xae55,0xae56,0xae57,
+ 0xae58,0xae59,0xae5a,0xae5b,0xae5c,0xae5d,0xae5e,0xae5f,
+ 0xae60,0xae61,0xae62,0xae63,0xae64,0xae65,0xae66,0xae67,
+ 0xae68,0xae69,0xae6a,0xae6b,0xae6c,0xae6d,0xae6e,0xae6f,
+ 0xae70,0xae71,0xae72,0xae73,0xae74,0xae75,0xae76,0xae77,
+ 0xae78,0xae79,0xae7a,0xae7b,0xae7c,0xae7d,0xae7e,0xae7f,
+ 0xae80,0xae81,0xae82,0xae83,0xae84,0xae85,0xae86,0xae87,
+ 0xae88,0xae89,0xae8a,0xae8b,0xae8c,0xae8d,0xae8e,0xae8f,
+ 0xae90,0xae91,0xae92,0xae93,0xae94,0xae95,0xae96,0xae97,
+ 0xae98,0xae99,0xae9a,0xae9b,0xae9c,0xae9d,0xae9e,0xae9f,
+ 0xaea0,0xaea1,0xaea2,0xaea3,0xaea4,0xaea5,0xaea6,0xaea7,
+ 0xaea8,0xaea9,0xaeaa,0xaeab,0xaeac,0xaead,0xaeae,0xaeaf,
+ 0xaeb0,0xaeb1,0xaeb2,0xaeb3,0xaeb4,0xaeb5,0xaeb6,0xaeb7,
+ 0xaeb8,0xaeb9,0xaeba,0xaebb,0xaebc,0xaebd,0xaebe,0xaebf,
+ 0xaec0,0xaec1,0xaec2,0xaec3,0xaec4,0xaec5,0xaec6,0xaec7,
+ 0xaec8,0xaec9,0xaeca,0xaecb,0xaecc,0xaecd,0xaece,0xaecf,
+ 0xaed0,0xaed1,0xaed2,0xaed3,0xaed4,0xaed5,0xaed6,0xaed7,
+ 0xaed8,0xaed9,0xaeda,0xaedb,0xaedc,0xaedd,0xaede,0xaedf,
+ 0xaee0,0xaee1,0xaee2,0xaee3,0xaee4,0xaee5,0xaee6,0xaee7,
+ 0xaee8,0xaee9,0xaeea,0xaeeb,0xaeec,0xaeed,0xaeee,0xaeef,
+ 0xaef0,0xaef1,0xaef2,0xaef3,0xaef4,0xaef5,0xaef6,0xaef7,
+ 0xaef8,0xaef9,0xaefa,0xaefb,0xaefc,0xaefd,0xaefe,0xaeff,
+ 0xaf00,0xaf01,0xaf02,0xaf03,0xaf04,0xaf05,0xaf06,0xaf07,
+ 0xaf08,0xaf09,0xaf0a,0xaf0b,0xaf0c,0xaf0d,0xaf0e,0xaf0f,
+ 0xaf10,0xaf11,0xaf12,0xaf13,0xaf14,0xaf15,0xaf16,0xaf17,
+ 0xaf18,0xaf19,0xaf1a,0xaf1b,0xaf1c,0xaf1d,0xaf1e,0xaf1f,
+ 0xaf20,0xaf21,0xaf22,0xaf23,0xaf24,0xaf25,0xaf26,0xaf27,
+ 0xaf28,0xaf29,0xaf2a,0xaf2b,0xaf2c,0xaf2d,0xaf2e,0xaf2f,
+ 0xaf30,0xaf31,0xaf32,0xaf33,0xaf34,0xaf35,0xaf36,0xaf37,
+ 0xaf38,0xaf39,0xaf3a,0xaf3b,0xaf3c,0xaf3d,0xaf3e,0xaf3f,
+ 0xaf40,0xaf41,0xaf42,0xaf43,0xaf44,0xaf45,0xaf46,0xaf47,
+ 0xaf48,0xaf49,0xaf4a,0xaf4b,0xaf4c,0xaf4d,0xaf4e,0xaf4f,
+ 0xaf50,0xaf51,0xaf52,0xaf53,0xaf54,0xaf55,0xaf56,0xaf57,
+ 0xaf58,0xaf59,0xaf5a,0xaf5b,0xaf5c,0xaf5d,0xaf5e,0xaf5f,
+ 0xaf60,0xaf61,0xaf62,0xaf63,0xaf64,0xaf65,0xaf66,0xaf67,
+ 0xaf68,0xaf69,0xaf6a,0xaf6b,0xaf6c,0xaf6d,0xaf6e,0xaf6f,
+ 0xaf70,0xaf71,0xaf72,0xaf73,0xaf74,0xaf75,0xaf76,0xaf77,
+ 0xaf78,0xaf79,0xaf7a,0xaf7b,0xaf7c,0xaf7d,0xaf7e,0xaf7f,
+ 0xaf80,0xaf81,0xaf82,0xaf83,0xaf84,0xaf85,0xaf86,0xaf87,
+ 0xaf88,0xaf89,0xaf8a,0xaf8b,0xaf8c,0xaf8d,0xaf8e,0xaf8f,
+ 0xaf90,0xaf91,0xaf92,0xaf93,0xaf94,0xaf95,0xaf96,0xaf97,
+ 0xaf98,0xaf99,0xaf9a,0xaf9b,0xaf9c,0xaf9d,0xaf9e,0xaf9f,
+ 0xafa0,0xafa1,0xafa2,0xafa3,0xafa4,0xafa5,0xafa6,0xafa7,
+ 0xafa8,0xafa9,0xafaa,0xafab,0xafac,0xafad,0xafae,0xafaf,
+ 0xafb0,0xafb1,0xafb2,0xafb3,0xafb4,0xafb5,0xafb6,0xafb7,
+ 0xafb8,0xafb9,0xafba,0xafbb,0xafbc,0xafbd,0xafbe,0xafbf,
+ 0xafc0,0xafc1,0xafc2,0xafc3,0xafc4,0xafc5,0xafc6,0xafc7,
+ 0xafc8,0xafc9,0xafca,0xafcb,0xafcc,0xafcd,0xafce,0xafcf,
+ 0xafd0,0xafd1,0xafd2,0xafd3,0xafd4,0xafd5,0xafd6,0xafd7,
+ 0xafd8,0xafd9,0xafda,0xafdb,0xafdc,0xafdd,0xafde,0xafdf,
+ 0xafe0,0xafe1,0xafe2,0xafe3,0xafe4,0xafe5,0xafe6,0xafe7,
+ 0xafe8,0xafe9,0xafea,0xafeb,0xafec,0xafed,0xafee,0xafef,
+ 0xaff0,0xaff1,0xaff2,0xaff3,0xaff4,0xaff5,0xaff6,0xaff7,
+ 0xaff8,0xaff9,0xaffa,0xaffb,0xaffc,0xaffd,0xaffe,0xafff,
+ 0xb000,0xb001,0xb002,0xb003,0xb004,0xb005,0xb006,0xb007,
+ 0xb008,0xb009,0xb00a,0xb00b,0xb00c,0xb00d,0xb00e,0xb00f,
+ 0xb010,0xb011,0xb012,0xb013,0xb014,0xb015,0xb016,0xb017,
+ 0xb018,0xb019,0xb01a,0xb01b,0xb01c,0xb01d,0xb01e,0xb01f,
+ 0xb020,0xb021,0xb022,0xb023,0xb024,0xb025,0xb026,0xb027,
+ 0xb028,0xb029,0xb02a,0xb02b,0xb02c,0xb02d,0xb02e,0xb02f,
+ 0xb030,0xb031,0xb032,0xb033,0xb034,0xb035,0xb036,0xb037,
+ 0xb038,0xb039,0xb03a,0xb03b,0xb03c,0xb03d,0xb03e,0xb03f,
+ 0xb040,0xb041,0xb042,0xb043,0xb044,0xb045,0xb046,0xb047,
+ 0xb048,0xb049,0xb04a,0xb04b,0xb04c,0xb04d,0xb04e,0xb04f,
+ 0xb050,0xb051,0xb052,0xb053,0xb054,0xb055,0xb056,0xb057,
+ 0xb058,0xb059,0xb05a,0xb05b,0xb05c,0xb05d,0xb05e,0xb05f,
+ 0xb060,0xb061,0xb062,0xb063,0xb064,0xb065,0xb066,0xb067,
+ 0xb068,0xb069,0xb06a,0xb06b,0xb06c,0xb06d,0xb06e,0xb06f,
+ 0xb070,0xb071,0xb072,0xb073,0xb074,0xb075,0xb076,0xb077,
+ 0xb078,0xb079,0xb07a,0xb07b,0xb07c,0xb07d,0xb07e,0xb07f,
+ 0xb080,0xb081,0xb082,0xb083,0xb084,0xb085,0xb086,0xb087,
+ 0xb088,0xb089,0xb08a,0xb08b,0xb08c,0xb08d,0xb08e,0xb08f,
+ 0xb090,0xb091,0xb092,0xb093,0xb094,0xb095,0xb096,0xb097,
+ 0xb098,0xb099,0xb09a,0xb09b,0xb09c,0xb09d,0xb09e,0xb09f,
+ 0xb0a0,0xb0a1,0xb0a2,0xb0a3,0xb0a4,0xb0a5,0xb0a6,0xb0a7,
+ 0xb0a8,0xb0a9,0xb0aa,0xb0ab,0xb0ac,0xb0ad,0xb0ae,0xb0af,
+ 0xb0b0,0xb0b1,0xb0b2,0xb0b3,0xb0b4,0xb0b5,0xb0b6,0xb0b7,
+ 0xb0b8,0xb0b9,0xb0ba,0xb0bb,0xb0bc,0xb0bd,0xb0be,0xb0bf,
+ 0xb0c0,0xb0c1,0xb0c2,0xb0c3,0xb0c4,0xb0c5,0xb0c6,0xb0c7,
+ 0xb0c8,0xb0c9,0xb0ca,0xb0cb,0xb0cc,0xb0cd,0xb0ce,0xb0cf,
+ 0xb0d0,0xb0d1,0xb0d2,0xb0d3,0xb0d4,0xb0d5,0xb0d6,0xb0d7,
+ 0xb0d8,0xb0d9,0xb0da,0xb0db,0xb0dc,0xb0dd,0xb0de,0xb0df,
+ 0xb0e0,0xb0e1,0xb0e2,0xb0e3,0xb0e4,0xb0e5,0xb0e6,0xb0e7,
+ 0xb0e8,0xb0e9,0xb0ea,0xb0eb,0xb0ec,0xb0ed,0xb0ee,0xb0ef,
+ 0xb0f0,0xb0f1,0xb0f2,0xb0f3,0xb0f4,0xb0f5,0xb0f6,0xb0f7,
+ 0xb0f8,0xb0f9,0xb0fa,0xb0fb,0xb0fc,0xb0fd,0xb0fe,0xb0ff,
+ 0xb100,0xb101,0xb102,0xb103,0xb104,0xb105,0xb106,0xb107,
+ 0xb108,0xb109,0xb10a,0xb10b,0xb10c,0xb10d,0xb10e,0xb10f,
+ 0xb110,0xb111,0xb112,0xb113,0xb114,0xb115,0xb116,0xb117,
+ 0xb118,0xb119,0xb11a,0xb11b,0xb11c,0xb11d,0xb11e,0xb11f,
+ 0xb120,0xb121,0xb122,0xb123,0xb124,0xb125,0xb126,0xb127,
+ 0xb128,0xb129,0xb12a,0xb12b,0xb12c,0xb12d,0xb12e,0xb12f,
+ 0xb130,0xb131,0xb132,0xb133,0xb134,0xb135,0xb136,0xb137,
+ 0xb138,0xb139,0xb13a,0xb13b,0xb13c,0xb13d,0xb13e,0xb13f,
+ 0xb140,0xb141,0xb142,0xb143,0xb144,0xb145,0xb146,0xb147,
+ 0xb148,0xb149,0xb14a,0xb14b,0xb14c,0xb14d,0xb14e,0xb14f,
+ 0xb150,0xb151,0xb152,0xb153,0xb154,0xb155,0xb156,0xb157,
+ 0xb158,0xb159,0xb15a,0xb15b,0xb15c,0xb15d,0xb15e,0xb15f,
+ 0xb160,0xb161,0xb162,0xb163,0xb164,0xb165,0xb166,0xb167,
+ 0xb168,0xb169,0xb16a,0xb16b,0xb16c,0xb16d,0xb16e,0xb16f,
+ 0xb170,0xb171,0xb172,0xb173,0xb174,0xb175,0xb176,0xb177,
+ 0xb178,0xb179,0xb17a,0xb17b,0xb17c,0xb17d,0xb17e,0xb17f,
+ 0xb180,0xb181,0xb182,0xb183,0xb184,0xb185,0xb186,0xb187,
+ 0xb188,0xb189,0xb18a,0xb18b,0xb18c,0xb18d,0xb18e,0xb18f,
+ 0xb190,0xb191,0xb192,0xb193,0xb194,0xb195,0xb196,0xb197,
+ 0xb198,0xb199,0xb19a,0xb19b,0xb19c,0xb19d,0xb19e,0xb19f,
+ 0xb1a0,0xb1a1,0xb1a2,0xb1a3,0xb1a4,0xb1a5,0xb1a6,0xb1a7,
+ 0xb1a8,0xb1a9,0xb1aa,0xb1ab,0xb1ac,0xb1ad,0xb1ae,0xb1af,
+ 0xb1b0,0xb1b1,0xb1b2,0xb1b3,0xb1b4,0xb1b5,0xb1b6,0xb1b7,
+ 0xb1b8,0xb1b9,0xb1ba,0xb1bb,0xb1bc,0xb1bd,0xb1be,0xb1bf,
+ 0xb1c0,0xb1c1,0xb1c2,0xb1c3,0xb1c4,0xb1c5,0xb1c6,0xb1c7,
+ 0xb1c8,0xb1c9,0xb1ca,0xb1cb,0xb1cc,0xb1cd,0xb1ce,0xb1cf,
+ 0xb1d0,0xb1d1,0xb1d2,0xb1d3,0xb1d4,0xb1d5,0xb1d6,0xb1d7,
+ 0xb1d8,0xb1d9,0xb1da,0xb1db,0xb1dc,0xb1dd,0xb1de,0xb1df,
+ 0xb1e0,0xb1e1,0xb1e2,0xb1e3,0xb1e4,0xb1e5,0xb1e6,0xb1e7,
+ 0xb1e8,0xb1e9,0xb1ea,0xb1eb,0xb1ec,0xb1ed,0xb1ee,0xb1ef,
+ 0xb1f0,0xb1f1,0xb1f2,0xb1f3,0xb1f4,0xb1f5,0xb1f6,0xb1f7,
+ 0xb1f8,0xb1f9,0xb1fa,0xb1fb,0xb1fc,0xb1fd,0xb1fe,0xb1ff,
+ 0xb200,0xb201,0xb202,0xb203,0xb204,0xb205,0xb206,0xb207,
+ 0xb208,0xb209,0xb20a,0xb20b,0xb20c,0xb20d,0xb20e,0xb20f,
+ 0xb210,0xb211,0xb212,0xb213,0xb214,0xb215,0xb216,0xb217,
+ 0xb218,0xb219,0xb21a,0xb21b,0xb21c,0xb21d,0xb21e,0xb21f,
+ 0xb220,0xb221,0xb222,0xb223,0xb224,0xb225,0xb226,0xb227,
+ 0xb228,0xb229,0xb22a,0xb22b,0xb22c,0xb22d,0xb22e,0xb22f,
+ 0xb230,0xb231,0xb232,0xb233,0xb234,0xb235,0xb236,0xb237,
+ 0xb238,0xb239,0xb23a,0xb23b,0xb23c,0xb23d,0xb23e,0xb23f,
+ 0xb240,0xb241,0xb242,0xb243,0xb244,0xb245,0xb246,0xb247,
+ 0xb248,0xb249,0xb24a,0xb24b,0xb24c,0xb24d,0xb24e,0xb24f,
+ 0xb250,0xb251,0xb252,0xb253,0xb254,0xb255,0xb256,0xb257,
+ 0xb258,0xb259,0xb25a,0xb25b,0xb25c,0xb25d,0xb25e,0xb25f,
+ 0xb260,0xb261,0xb262,0xb263,0xb264,0xb265,0xb266,0xb267,
+ 0xb268,0xb269,0xb26a,0xb26b,0xb26c,0xb26d,0xb26e,0xb26f,
+ 0xb270,0xb271,0xb272,0xb273,0xb274,0xb275,0xb276,0xb277,
+ 0xb278,0xb279,0xb27a,0xb27b,0xb27c,0xb27d,0xb27e,0xb27f,
+ 0xb280,0xb281,0xb282,0xb283,0xb284,0xb285,0xb286,0xb287,
+ 0xb288,0xb289,0xb28a,0xb28b,0xb28c,0xb28d,0xb28e,0xb28f,
+ 0xb290,0xb291,0xb292,0xb293,0xb294,0xb295,0xb296,0xb297,
+ 0xb298,0xb299,0xb29a,0xb29b,0xb29c,0xb29d,0xb29e,0xb29f,
+ 0xb2a0,0xb2a1,0xb2a2,0xb2a3,0xb2a4,0xb2a5,0xb2a6,0xb2a7,
+ 0xb2a8,0xb2a9,0xb2aa,0xb2ab,0xb2ac,0xb2ad,0xb2ae,0xb2af,
+ 0xb2b0,0xb2b1,0xb2b2,0xb2b3,0xb2b4,0xb2b5,0xb2b6,0xb2b7,
+ 0xb2b8,0xb2b9,0xb2ba,0xb2bb,0xb2bc,0xb2bd,0xb2be,0xb2bf,
+ 0xb2c0,0xb2c1,0xb2c2,0xb2c3,0xb2c4,0xb2c5,0xb2c6,0xb2c7,
+ 0xb2c8,0xb2c9,0xb2ca,0xb2cb,0xb2cc,0xb2cd,0xb2ce,0xb2cf,
+ 0xb2d0,0xb2d1,0xb2d2,0xb2d3,0xb2d4,0xb2d5,0xb2d6,0xb2d7,
+ 0xb2d8,0xb2d9,0xb2da,0xb2db,0xb2dc,0xb2dd,0xb2de,0xb2df,
+ 0xb2e0,0xb2e1,0xb2e2,0xb2e3,0xb2e4,0xb2e5,0xb2e6,0xb2e7,
+ 0xb2e8,0xb2e9,0xb2ea,0xb2eb,0xb2ec,0xb2ed,0xb2ee,0xb2ef,
+ 0xb2f0,0xb2f1,0xb2f2,0xb2f3,0xb2f4,0xb2f5,0xb2f6,0xb2f7,
+ 0xb2f8,0xb2f9,0xb2fa,0xb2fb,0xb2fc,0xb2fd,0xb2fe,0xb2ff,
+ 0xb300,0xb301,0xb302,0xb303,0xb304,0xb305,0xb306,0xb307,
+ 0xb308,0xb309,0xb30a,0xb30b,0xb30c,0xb30d,0xb30e,0xb30f,
+ 0xb310,0xb311,0xb312,0xb313,0xb314,0xb315,0xb316,0xb317,
+ 0xb318,0xb319,0xb31a,0xb31b,0xb31c,0xb31d,0xb31e,0xb31f,
+ 0xb320,0xb321,0xb322,0xb323,0xb324,0xb325,0xb326,0xb327,
+ 0xb328,0xb329,0xb32a,0xb32b,0xb32c,0xb32d,0xb32e,0xb32f,
+ 0xb330,0xb331,0xb332,0xb333,0xb334,0xb335,0xb336,0xb337,
+ 0xb338,0xb339,0xb33a,0xb33b,0xb33c,0xb33d,0xb33e,0xb33f,
+ 0xb340,0xb341,0xb342,0xb343,0xb344,0xb345,0xb346,0xb347,
+ 0xb348,0xb349,0xb34a,0xb34b,0xb34c,0xb34d,0xb34e,0xb34f,
+ 0xb350,0xb351,0xb352,0xb353,0xb354,0xb355,0xb356,0xb357,
+ 0xb358,0xb359,0xb35a,0xb35b,0xb35c,0xb35d,0xb35e,0xb35f,
+ 0xb360,0xb361,0xb362,0xb363,0xb364,0xb365,0xb366,0xb367,
+ 0xb368,0xb369,0xb36a,0xb36b,0xb36c,0xb36d,0xb36e,0xb36f,
+ 0xb370,0xb371,0xb372,0xb373,0xb374,0xb375,0xb376,0xb377,
+ 0xb378,0xb379,0xb37a,0xb37b,0xb37c,0xb37d,0xb37e,0xb37f,
+ 0xb380,0xb381,0xb382,0xb383,0xb384,0xb385,0xb386,0xb387,
+ 0xb388,0xb389,0xb38a,0xb38b,0xb38c,0xb38d,0xb38e,0xb38f,
+ 0xb390,0xb391,0xb392,0xb393,0xb394,0xb395,0xb396,0xb397,
+ 0xb398,0xb399,0xb39a,0xb39b,0xb39c,0xb39d,0xb39e,0xb39f,
+ 0xb3a0,0xb3a1,0xb3a2,0xb3a3,0xb3a4,0xb3a5,0xb3a6,0xb3a7,
+ 0xb3a8,0xb3a9,0xb3aa,0xb3ab,0xb3ac,0xb3ad,0xb3ae,0xb3af,
+ 0xb3b0,0xb3b1,0xb3b2,0xb3b3,0xb3b4,0xb3b5,0xb3b6,0xb3b7,
+ 0xb3b8,0xb3b9,0xb3ba,0xb3bb,0xb3bc,0xb3bd,0xb3be,0xb3bf,
+ 0xb3c0,0xb3c1,0xb3c2,0xb3c3,0xb3c4,0xb3c5,0xb3c6,0xb3c7,
+ 0xb3c8,0xb3c9,0xb3ca,0xb3cb,0xb3cc,0xb3cd,0xb3ce,0xb3cf,
+ 0xb3d0,0xb3d1,0xb3d2,0xb3d3,0xb3d4,0xb3d5,0xb3d6,0xb3d7,
+ 0xb3d8,0xb3d9,0xb3da,0xb3db,0xb3dc,0xb3dd,0xb3de,0xb3df,
+ 0xb3e0,0xb3e1,0xb3e2,0xb3e3,0xb3e4,0xb3e5,0xb3e6,0xb3e7,
+ 0xb3e8,0xb3e9,0xb3ea,0xb3eb,0xb3ec,0xb3ed,0xb3ee,0xb3ef,
+ 0xb3f0,0xb3f1,0xb3f2,0xb3f3,0xb3f4,0xb3f5,0xb3f6,0xb3f7,
+ 0xb3f8,0xb3f9,0xb3fa,0xb3fb,0xb3fc,0xb3fd,0xb3fe,0xb3ff,
+ 0xb400,0xb401,0xb402,0xb403,0xb404,0xb405,0xb406,0xb407,
+ 0xb408,0xb409,0xb40a,0xb40b,0xb40c,0xb40d,0xb40e,0xb40f,
+ 0xb410,0xb411,0xb412,0xb413,0xb414,0xb415,0xb416,0xb417,
+ 0xb418,0xb419,0xb41a,0xb41b,0xb41c,0xb41d,0xb41e,0xb41f,
+ 0xb420,0xb421,0xb422,0xb423,0xb424,0xb425,0xb426,0xb427,
+ 0xb428,0xb429,0xb42a,0xb42b,0xb42c,0xb42d,0xb42e,0xb42f,
+ 0xb430,0xb431,0xb432,0xb433,0xb434,0xb435,0xb436,0xb437,
+ 0xb438,0xb439,0xb43a,0xb43b,0xb43c,0xb43d,0xb43e,0xb43f,
+ 0xb440,0xb441,0xb442,0xb443,0xb444,0xb445,0xb446,0xb447,
+ 0xb448,0xb449,0xb44a,0xb44b,0xb44c,0xb44d,0xb44e,0xb44f,
+ 0xb450,0xb451,0xb452,0xb453,0xb454,0xb455,0xb456,0xb457,
+ 0xb458,0xb459,0xb45a,0xb45b,0xb45c,0xb45d,0xb45e,0xb45f,
+ 0xb460,0xb461,0xb462,0xb463,0xb464,0xb465,0xb466,0xb467,
+ 0xb468,0xb469,0xb46a,0xb46b,0xb46c,0xb46d,0xb46e,0xb46f,
+ 0xb470,0xb471,0xb472,0xb473,0xb474,0xb475,0xb476,0xb477,
+ 0xb478,0xb479,0xb47a,0xb47b,0xb47c,0xb47d,0xb47e,0xb47f,
+ 0xb480,0xb481,0xb482,0xb483,0xb484,0xb485,0xb486,0xb487,
+ 0xb488,0xb489,0xb48a,0xb48b,0xb48c,0xb48d,0xb48e,0xb48f,
+ 0xb490,0xb491,0xb492,0xb493,0xb494,0xb495,0xb496,0xb497,
+ 0xb498,0xb499,0xb49a,0xb49b,0xb49c,0xb49d,0xb49e,0xb49f,
+ 0xb4a0,0xb4a1,0xb4a2,0xb4a3,0xb4a4,0xb4a5,0xb4a6,0xb4a7,
+ 0xb4a8,0xb4a9,0xb4aa,0xb4ab,0xb4ac,0xb4ad,0xb4ae,0xb4af,
+ 0xb4b0,0xb4b1,0xb4b2,0xb4b3,0xb4b4,0xb4b5,0xb4b6,0xb4b7,
+ 0xb4b8,0xb4b9,0xb4ba,0xb4bb,0xb4bc,0xb4bd,0xb4be,0xb4bf,
+ 0xb4c0,0xb4c1,0xb4c2,0xb4c3,0xb4c4,0xb4c5,0xb4c6,0xb4c7,
+ 0xb4c8,0xb4c9,0xb4ca,0xb4cb,0xb4cc,0xb4cd,0xb4ce,0xb4cf,
+ 0xb4d0,0xb4d1,0xb4d2,0xb4d3,0xb4d4,0xb4d5,0xb4d6,0xb4d7,
+ 0xb4d8,0xb4d9,0xb4da,0xb4db,0xb4dc,0xb4dd,0xb4de,0xb4df,
+ 0xb4e0,0xb4e1,0xb4e2,0xb4e3,0xb4e4,0xb4e5,0xb4e6,0xb4e7,
+ 0xb4e8,0xb4e9,0xb4ea,0xb4eb,0xb4ec,0xb4ed,0xb4ee,0xb4ef,
+ 0xb4f0,0xb4f1,0xb4f2,0xb4f3,0xb4f4,0xb4f5,0xb4f6,0xb4f7,
+ 0xb4f8,0xb4f9,0xb4fa,0xb4fb,0xb4fc,0xb4fd,0xb4fe,0xb4ff,
+ 0xb500,0xb501,0xb502,0xb503,0xb504,0xb505,0xb506,0xb507,
+ 0xb508,0xb509,0xb50a,0xb50b,0xb50c,0xb50d,0xb50e,0xb50f,
+ 0xb510,0xb511,0xb512,0xb513,0xb514,0xb515,0xb516,0xb517,
+ 0xb518,0xb519,0xb51a,0xb51b,0xb51c,0xb51d,0xb51e,0xb51f,
+ 0xb520,0xb521,0xb522,0xb523,0xb524,0xb525,0xb526,0xb527,
+ 0xb528,0xb529,0xb52a,0xb52b,0xb52c,0xb52d,0xb52e,0xb52f,
+ 0xb530,0xb531,0xb532,0xb533,0xb534,0xb535,0xb536,0xb537,
+ 0xb538,0xb539,0xb53a,0xb53b,0xb53c,0xb53d,0xb53e,0xb53f,
+ 0xb540,0xb541,0xb542,0xb543,0xb544,0xb545,0xb546,0xb547,
+ 0xb548,0xb549,0xb54a,0xb54b,0xb54c,0xb54d,0xb54e,0xb54f,
+ 0xb550,0xb551,0xb552,0xb553,0xb554,0xb555,0xb556,0xb557,
+ 0xb558,0xb559,0xb55a,0xb55b,0xb55c,0xb55d,0xb55e,0xb55f,
+ 0xb560,0xb561,0xb562,0xb563,0xb564,0xb565,0xb566,0xb567,
+ 0xb568,0xb569,0xb56a,0xb56b,0xb56c,0xb56d,0xb56e,0xb56f,
+ 0xb570,0xb571,0xb572,0xb573,0xb574,0xb575,0xb576,0xb577,
+ 0xb578,0xb579,0xb57a,0xb57b,0xb57c,0xb57d,0xb57e,0xb57f,
+ 0xb580,0xb581,0xb582,0xb583,0xb584,0xb585,0xb586,0xb587,
+ 0xb588,0xb589,0xb58a,0xb58b,0xb58c,0xb58d,0xb58e,0xb58f,
+ 0xb590,0xb591,0xb592,0xb593,0xb594,0xb595,0xb596,0xb597,
+ 0xb598,0xb599,0xb59a,0xb59b,0xb59c,0xb59d,0xb59e,0xb59f,
+ 0xb5a0,0xb5a1,0xb5a2,0xb5a3,0xb5a4,0xb5a5,0xb5a6,0xb5a7,
+ 0xb5a8,0xb5a9,0xb5aa,0xb5ab,0xb5ac,0xb5ad,0xb5ae,0xb5af,
+ 0xb5b0,0xb5b1,0xb5b2,0xb5b3,0xb5b4,0xb5b5,0xb5b6,0xb5b7,
+ 0xb5b8,0xb5b9,0xb5ba,0xb5bb,0xb5bc,0xb5bd,0xb5be,0xb5bf,
+ 0xb5c0,0xb5c1,0xb5c2,0xb5c3,0xb5c4,0xb5c5,0xb5c6,0xb5c7,
+ 0xb5c8,0xb5c9,0xb5ca,0xb5cb,0xb5cc,0xb5cd,0xb5ce,0xb5cf,
+ 0xb5d0,0xb5d1,0xb5d2,0xb5d3,0xb5d4,0xb5d5,0xb5d6,0xb5d7,
+ 0xb5d8,0xb5d9,0xb5da,0xb5db,0xb5dc,0xb5dd,0xb5de,0xb5df,
+ 0xb5e0,0xb5e1,0xb5e2,0xb5e3,0xb5e4,0xb5e5,0xb5e6,0xb5e7,
+ 0xb5e8,0xb5e9,0xb5ea,0xb5eb,0xb5ec,0xb5ed,0xb5ee,0xb5ef,
+ 0xb5f0,0xb5f1,0xb5f2,0xb5f3,0xb5f4,0xb5f5,0xb5f6,0xb5f7,
+ 0xb5f8,0xb5f9,0xb5fa,0xb5fb,0xb5fc,0xb5fd,0xb5fe,0xb5ff,
+ 0xb600,0xb601,0xb602,0xb603,0xb604,0xb605,0xb606,0xb607,
+ 0xb608,0xb609,0xb60a,0xb60b,0xb60c,0xb60d,0xb60e,0xb60f,
+ 0xb610,0xb611,0xb612,0xb613,0xb614,0xb615,0xb616,0xb617,
+ 0xb618,0xb619,0xb61a,0xb61b,0xb61c,0xb61d,0xb61e,0xb61f,
+ 0xb620,0xb621,0xb622,0xb623,0xb624,0xb625,0xb626,0xb627,
+ 0xb628,0xb629,0xb62a,0xb62b,0xb62c,0xb62d,0xb62e,0xb62f,
+ 0xb630,0xb631,0xb632,0xb633,0xb634,0xb635,0xb636,0xb637,
+ 0xb638,0xb639,0xb63a,0xb63b,0xb63c,0xb63d,0xb63e,0xb63f,
+ 0xb640,0xb641,0xb642,0xb643,0xb644,0xb645,0xb646,0xb647,
+ 0xb648,0xb649,0xb64a,0xb64b,0xb64c,0xb64d,0xb64e,0xb64f,
+ 0xb650,0xb651,0xb652,0xb653,0xb654,0xb655,0xb656,0xb657,
+ 0xb658,0xb659,0xb65a,0xb65b,0xb65c,0xb65d,0xb65e,0xb65f,
+ 0xb660,0xb661,0xb662,0xb663,0xb664,0xb665,0xb666,0xb667,
+ 0xb668,0xb669,0xb66a,0xb66b,0xb66c,0xb66d,0xb66e,0xb66f,
+ 0xb670,0xb671,0xb672,0xb673,0xb674,0xb675,0xb676,0xb677,
+ 0xb678,0xb679,0xb67a,0xb67b,0xb67c,0xb67d,0xb67e,0xb67f,
+ 0xb680,0xb681,0xb682,0xb683,0xb684,0xb685,0xb686,0xb687,
+ 0xb688,0xb689,0xb68a,0xb68b,0xb68c,0xb68d,0xb68e,0xb68f,
+ 0xb690,0xb691,0xb692,0xb693,0xb694,0xb695,0xb696,0xb697,
+ 0xb698,0xb699,0xb69a,0xb69b,0xb69c,0xb69d,0xb69e,0xb69f,
+ 0xb6a0,0xb6a1,0xb6a2,0xb6a3,0xb6a4,0xb6a5,0xb6a6,0xb6a7,
+ 0xb6a8,0xb6a9,0xb6aa,0xb6ab,0xb6ac,0xb6ad,0xb6ae,0xb6af,
+ 0xb6b0,0xb6b1,0xb6b2,0xb6b3,0xb6b4,0xb6b5,0xb6b6,0xb6b7,
+ 0xb6b8,0xb6b9,0xb6ba,0xb6bb,0xb6bc,0xb6bd,0xb6be,0xb6bf,
+ 0xb6c0,0xb6c1,0xb6c2,0xb6c3,0xb6c4,0xb6c5,0xb6c6,0xb6c7,
+ 0xb6c8,0xb6c9,0xb6ca,0xb6cb,0xb6cc,0xb6cd,0xb6ce,0xb6cf,
+ 0xb6d0,0xb6d1,0xb6d2,0xb6d3,0xb6d4,0xb6d5,0xb6d6,0xb6d7,
+ 0xb6d8,0xb6d9,0xb6da,0xb6db,0xb6dc,0xb6dd,0xb6de,0xb6df,
+ 0xb6e0,0xb6e1,0xb6e2,0xb6e3,0xb6e4,0xb6e5,0xb6e6,0xb6e7,
+ 0xb6e8,0xb6e9,0xb6ea,0xb6eb,0xb6ec,0xb6ed,0xb6ee,0xb6ef,
+ 0xb6f0,0xb6f1,0xb6f2,0xb6f3,0xb6f4,0xb6f5,0xb6f6,0xb6f7,
+ 0xb6f8,0xb6f9,0xb6fa,0xb6fb,0xb6fc,0xb6fd,0xb6fe,0xb6ff,
+ 0xb700,0xb701,0xb702,0xb703,0xb704,0xb705,0xb706,0xb707,
+ 0xb708,0xb709,0xb70a,0xb70b,0xb70c,0xb70d,0xb70e,0xb70f,
+ 0xb710,0xb711,0xb712,0xb713,0xb714,0xb715,0xb716,0xb717,
+ 0xb718,0xb719,0xb71a,0xb71b,0xb71c,0xb71d,0xb71e,0xb71f,
+ 0xb720,0xb721,0xb722,0xb723,0xb724,0xb725,0xb726,0xb727,
+ 0xb728,0xb729,0xb72a,0xb72b,0xb72c,0xb72d,0xb72e,0xb72f,
+ 0xb730,0xb731,0xb732,0xb733,0xb734,0xb735,0xb736,0xb737,
+ 0xb738,0xb739,0xb73a,0xb73b,0xb73c,0xb73d,0xb73e,0xb73f,
+ 0xb740,0xb741,0xb742,0xb743,0xb744,0xb745,0xb746,0xb747,
+ 0xb748,0xb749,0xb74a,0xb74b,0xb74c,0xb74d,0xb74e,0xb74f,
+ 0xb750,0xb751,0xb752,0xb753,0xb754,0xb755,0xb756,0xb757,
+ 0xb758,0xb759,0xb75a,0xb75b,0xb75c,0xb75d,0xb75e,0xb75f,
+ 0xb760,0xb761,0xb762,0xb763,0xb764,0xb765,0xb766,0xb767,
+ 0xb768,0xb769,0xb76a,0xb76b,0xb76c,0xb76d,0xb76e,0xb76f,
+ 0xb770,0xb771,0xb772,0xb773,0xb774,0xb775,0xb776,0xb777,
+ 0xb778,0xb779,0xb77a,0xb77b,0xb77c,0xb77d,0xb77e,0xb77f,
+ 0xb780,0xb781,0xb782,0xb783,0xb784,0xb785,0xb786,0xb787,
+ 0xb788,0xb789,0xb78a,0xb78b,0xb78c,0xb78d,0xb78e,0xb78f,
+ 0xb790,0xb791,0xb792,0xb793,0xb794,0xb795,0xb796,0xb797,
+ 0xb798,0xb799,0xb79a,0xb79b,0xb79c,0xb79d,0xb79e,0xb79f,
+ 0xb7a0,0xb7a1,0xb7a2,0xb7a3,0xb7a4,0xb7a5,0xb7a6,0xb7a7,
+ 0xb7a8,0xb7a9,0xb7aa,0xb7ab,0xb7ac,0xb7ad,0xb7ae,0xb7af,
+ 0xb7b0,0xb7b1,0xb7b2,0xb7b3,0xb7b4,0xb7b5,0xb7b6,0xb7b7,
+ 0xb7b8,0xb7b9,0xb7ba,0xb7bb,0xb7bc,0xb7bd,0xb7be,0xb7bf,
+ 0xb7c0,0xb7c1,0xb7c2,0xb7c3,0xb7c4,0xb7c5,0xb7c6,0xb7c7,
+ 0xb7c8,0xb7c9,0xb7ca,0xb7cb,0xb7cc,0xb7cd,0xb7ce,0xb7cf,
+ 0xb7d0,0xb7d1,0xb7d2,0xb7d3,0xb7d4,0xb7d5,0xb7d6,0xb7d7,
+ 0xb7d8,0xb7d9,0xb7da,0xb7db,0xb7dc,0xb7dd,0xb7de,0xb7df,
+ 0xb7e0,0xb7e1,0xb7e2,0xb7e3,0xb7e4,0xb7e5,0xb7e6,0xb7e7,
+ 0xb7e8,0xb7e9,0xb7ea,0xb7eb,0xb7ec,0xb7ed,0xb7ee,0xb7ef,
+ 0xb7f0,0xb7f1,0xb7f2,0xb7f3,0xb7f4,0xb7f5,0xb7f6,0xb7f7,
+ 0xb7f8,0xb7f9,0xb7fa,0xb7fb,0xb7fc,0xb7fd,0xb7fe,0xb7ff,
+ 0xb800,0xb801,0xb802,0xb803,0xb804,0xb805,0xb806,0xb807,
+ 0xb808,0xb809,0xb80a,0xb80b,0xb80c,0xb80d,0xb80e,0xb80f,
+ 0xb810,0xb811,0xb812,0xb813,0xb814,0xb815,0xb816,0xb817,
+ 0xb818,0xb819,0xb81a,0xb81b,0xb81c,0xb81d,0xb81e,0xb81f,
+ 0xb820,0xb821,0xb822,0xb823,0xb824,0xb825,0xb826,0xb827,
+ 0xb828,0xb829,0xb82a,0xb82b,0xb82c,0xb82d,0xb82e,0xb82f,
+ 0xb830,0xb831,0xb832,0xb833,0xb834,0xb835,0xb836,0xb837,
+ 0xb838,0xb839,0xb83a,0xb83b,0xb83c,0xb83d,0xb83e,0xb83f,
+ 0xb840,0xb841,0xb842,0xb843,0xb844,0xb845,0xb846,0xb847,
+ 0xb848,0xb849,0xb84a,0xb84b,0xb84c,0xb84d,0xb84e,0xb84f,
+ 0xb850,0xb851,0xb852,0xb853,0xb854,0xb855,0xb856,0xb857,
+ 0xb858,0xb859,0xb85a,0xb85b,0xb85c,0xb85d,0xb85e,0xb85f,
+ 0xb860,0xb861,0xb862,0xb863,0xb864,0xb865,0xb866,0xb867,
+ 0xb868,0xb869,0xb86a,0xb86b,0xb86c,0xb86d,0xb86e,0xb86f,
+ 0xb870,0xb871,0xb872,0xb873,0xb874,0xb875,0xb876,0xb877,
+ 0xb878,0xb879,0xb87a,0xb87b,0xb87c,0xb87d,0xb87e,0xb87f,
+ 0xb880,0xb881,0xb882,0xb883,0xb884,0xb885,0xb886,0xb887,
+ 0xb888,0xb889,0xb88a,0xb88b,0xb88c,0xb88d,0xb88e,0xb88f,
+ 0xb890,0xb891,0xb892,0xb893,0xb894,0xb895,0xb896,0xb897,
+ 0xb898,0xb899,0xb89a,0xb89b,0xb89c,0xb89d,0xb89e,0xb89f,
+ 0xb8a0,0xb8a1,0xb8a2,0xb8a3,0xb8a4,0xb8a5,0xb8a6,0xb8a7,
+ 0xb8a8,0xb8a9,0xb8aa,0xb8ab,0xb8ac,0xb8ad,0xb8ae,0xb8af,
+ 0xb8b0,0xb8b1,0xb8b2,0xb8b3,0xb8b4,0xb8b5,0xb8b6,0xb8b7,
+ 0xb8b8,0xb8b9,0xb8ba,0xb8bb,0xb8bc,0xb8bd,0xb8be,0xb8bf,
+ 0xb8c0,0xb8c1,0xb8c2,0xb8c3,0xb8c4,0xb8c5,0xb8c6,0xb8c7,
+ 0xb8c8,0xb8c9,0xb8ca,0xb8cb,0xb8cc,0xb8cd,0xb8ce,0xb8cf,
+ 0xb8d0,0xb8d1,0xb8d2,0xb8d3,0xb8d4,0xb8d5,0xb8d6,0xb8d7,
+ 0xb8d8,0xb8d9,0xb8da,0xb8db,0xb8dc,0xb8dd,0xb8de,0xb8df,
+ 0xb8e0,0xb8e1,0xb8e2,0xb8e3,0xb8e4,0xb8e5,0xb8e6,0xb8e7,
+ 0xb8e8,0xb8e9,0xb8ea,0xb8eb,0xb8ec,0xb8ed,0xb8ee,0xb8ef,
+ 0xb8f0,0xb8f1,0xb8f2,0xb8f3,0xb8f4,0xb8f5,0xb8f6,0xb8f7,
+ 0xb8f8,0xb8f9,0xb8fa,0xb8fb,0xb8fc,0xb8fd,0xb8fe,0xb8ff,
+ 0xb900,0xb901,0xb902,0xb903,0xb904,0xb905,0xb906,0xb907,
+ 0xb908,0xb909,0xb90a,0xb90b,0xb90c,0xb90d,0xb90e,0xb90f,
+ 0xb910,0xb911,0xb912,0xb913,0xb914,0xb915,0xb916,0xb917,
+ 0xb918,0xb919,0xb91a,0xb91b,0xb91c,0xb91d,0xb91e,0xb91f,
+ 0xb920,0xb921,0xb922,0xb923,0xb924,0xb925,0xb926,0xb927,
+ 0xb928,0xb929,0xb92a,0xb92b,0xb92c,0xb92d,0xb92e,0xb92f,
+ 0xb930,0xb931,0xb932,0xb933,0xb934,0xb935,0xb936,0xb937,
+ 0xb938,0xb939,0xb93a,0xb93b,0xb93c,0xb93d,0xb93e,0xb93f,
+ 0xb940,0xb941,0xb942,0xb943,0xb944,0xb945,0xb946,0xb947,
+ 0xb948,0xb949,0xb94a,0xb94b,0xb94c,0xb94d,0xb94e,0xb94f,
+ 0xb950,0xb951,0xb952,0xb953,0xb954,0xb955,0xb956,0xb957,
+ 0xb958,0xb959,0xb95a,0xb95b,0xb95c,0xb95d,0xb95e,0xb95f,
+ 0xb960,0xb961,0xb962,0xb963,0xb964,0xb965,0xb966,0xb967,
+ 0xb968,0xb969,0xb96a,0xb96b,0xb96c,0xb96d,0xb96e,0xb96f,
+ 0xb970,0xb971,0xb972,0xb973,0xb974,0xb975,0xb976,0xb977,
+ 0xb978,0xb979,0xb97a,0xb97b,0xb97c,0xb97d,0xb97e,0xb97f,
+ 0xb980,0xb981,0xb982,0xb983,0xb984,0xb985,0xb986,0xb987,
+ 0xb988,0xb989,0xb98a,0xb98b,0xb98c,0xb98d,0xb98e,0xb98f,
+ 0xb990,0xb991,0xb992,0xb993,0xb994,0xb995,0xb996,0xb997,
+ 0xb998,0xb999,0xb99a,0xb99b,0xb99c,0xb99d,0xb99e,0xb99f,
+ 0xb9a0,0xb9a1,0xb9a2,0xb9a3,0xb9a4,0xb9a5,0xb9a6,0xb9a7,
+ 0xb9a8,0xb9a9,0xb9aa,0xb9ab,0xb9ac,0xb9ad,0xb9ae,0xb9af,
+ 0xb9b0,0xb9b1,0xb9b2,0xb9b3,0xb9b4,0xb9b5,0xb9b6,0xb9b7,
+ 0xb9b8,0xb9b9,0xb9ba,0xb9bb,0xb9bc,0xb9bd,0xb9be,0xb9bf,
+ 0xb9c0,0xb9c1,0xb9c2,0xb9c3,0xb9c4,0xb9c5,0xb9c6,0xb9c7,
+ 0xb9c8,0xb9c9,0xb9ca,0xb9cb,0xb9cc,0xb9cd,0xb9ce,0xb9cf,
+ 0xb9d0,0xb9d1,0xb9d2,0xb9d3,0xb9d4,0xb9d5,0xb9d6,0xb9d7,
+ 0xb9d8,0xb9d9,0xb9da,0xb9db,0xb9dc,0xb9dd,0xb9de,0xb9df,
+ 0xb9e0,0xb9e1,0xb9e2,0xb9e3,0xb9e4,0xb9e5,0xb9e6,0xb9e7,
+ 0xb9e8,0xb9e9,0xb9ea,0xb9eb,0xb9ec,0xb9ed,0xb9ee,0xb9ef,
+ 0xb9f0,0xb9f1,0xb9f2,0xb9f3,0xb9f4,0xb9f5,0xb9f6,0xb9f7,
+ 0xb9f8,0xb9f9,0xb9fa,0xb9fb,0xb9fc,0xb9fd,0xb9fe,0xb9ff,
+ 0xba00,0xba01,0xba02,0xba03,0xba04,0xba05,0xba06,0xba07,
+ 0xba08,0xba09,0xba0a,0xba0b,0xba0c,0xba0d,0xba0e,0xba0f,
+ 0xba10,0xba11,0xba12,0xba13,0xba14,0xba15,0xba16,0xba17,
+ 0xba18,0xba19,0xba1a,0xba1b,0xba1c,0xba1d,0xba1e,0xba1f,
+ 0xba20,0xba21,0xba22,0xba23,0xba24,0xba25,0xba26,0xba27,
+ 0xba28,0xba29,0xba2a,0xba2b,0xba2c,0xba2d,0xba2e,0xba2f,
+ 0xba30,0xba31,0xba32,0xba33,0xba34,0xba35,0xba36,0xba37,
+ 0xba38,0xba39,0xba3a,0xba3b,0xba3c,0xba3d,0xba3e,0xba3f,
+ 0xba40,0xba41,0xba42,0xba43,0xba44,0xba45,0xba46,0xba47,
+ 0xba48,0xba49,0xba4a,0xba4b,0xba4c,0xba4d,0xba4e,0xba4f,
+ 0xba50,0xba51,0xba52,0xba53,0xba54,0xba55,0xba56,0xba57,
+ 0xba58,0xba59,0xba5a,0xba5b,0xba5c,0xba5d,0xba5e,0xba5f,
+ 0xba60,0xba61,0xba62,0xba63,0xba64,0xba65,0xba66,0xba67,
+ 0xba68,0xba69,0xba6a,0xba6b,0xba6c,0xba6d,0xba6e,0xba6f,
+ 0xba70,0xba71,0xba72,0xba73,0xba74,0xba75,0xba76,0xba77,
+ 0xba78,0xba79,0xba7a,0xba7b,0xba7c,0xba7d,0xba7e,0xba7f,
+ 0xba80,0xba81,0xba82,0xba83,0xba84,0xba85,0xba86,0xba87,
+ 0xba88,0xba89,0xba8a,0xba8b,0xba8c,0xba8d,0xba8e,0xba8f,
+ 0xba90,0xba91,0xba92,0xba93,0xba94,0xba95,0xba96,0xba97,
+ 0xba98,0xba99,0xba9a,0xba9b,0xba9c,0xba9d,0xba9e,0xba9f,
+ 0xbaa0,0xbaa1,0xbaa2,0xbaa3,0xbaa4,0xbaa5,0xbaa6,0xbaa7,
+ 0xbaa8,0xbaa9,0xbaaa,0xbaab,0xbaac,0xbaad,0xbaae,0xbaaf,
+ 0xbab0,0xbab1,0xbab2,0xbab3,0xbab4,0xbab5,0xbab6,0xbab7,
+ 0xbab8,0xbab9,0xbaba,0xbabb,0xbabc,0xbabd,0xbabe,0xbabf,
+ 0xbac0,0xbac1,0xbac2,0xbac3,0xbac4,0xbac5,0xbac6,0xbac7,
+ 0xbac8,0xbac9,0xbaca,0xbacb,0xbacc,0xbacd,0xbace,0xbacf,
+ 0xbad0,0xbad1,0xbad2,0xbad3,0xbad4,0xbad5,0xbad6,0xbad7,
+ 0xbad8,0xbad9,0xbada,0xbadb,0xbadc,0xbadd,0xbade,0xbadf,
+ 0xbae0,0xbae1,0xbae2,0xbae3,0xbae4,0xbae5,0xbae6,0xbae7,
+ 0xbae8,0xbae9,0xbaea,0xbaeb,0xbaec,0xbaed,0xbaee,0xbaef,
+ 0xbaf0,0xbaf1,0xbaf2,0xbaf3,0xbaf4,0xbaf5,0xbaf6,0xbaf7,
+ 0xbaf8,0xbaf9,0xbafa,0xbafb,0xbafc,0xbafd,0xbafe,0xbaff,
+ 0xbb00,0xbb01,0xbb02,0xbb03,0xbb04,0xbb05,0xbb06,0xbb07,
+ 0xbb08,0xbb09,0xbb0a,0xbb0b,0xbb0c,0xbb0d,0xbb0e,0xbb0f,
+ 0xbb10,0xbb11,0xbb12,0xbb13,0xbb14,0xbb15,0xbb16,0xbb17,
+ 0xbb18,0xbb19,0xbb1a,0xbb1b,0xbb1c,0xbb1d,0xbb1e,0xbb1f,
+ 0xbb20,0xbb21,0xbb22,0xbb23,0xbb24,0xbb25,0xbb26,0xbb27,
+ 0xbb28,0xbb29,0xbb2a,0xbb2b,0xbb2c,0xbb2d,0xbb2e,0xbb2f,
+ 0xbb30,0xbb31,0xbb32,0xbb33,0xbb34,0xbb35,0xbb36,0xbb37,
+ 0xbb38,0xbb39,0xbb3a,0xbb3b,0xbb3c,0xbb3d,0xbb3e,0xbb3f,
+ 0xbb40,0xbb41,0xbb42,0xbb43,0xbb44,0xbb45,0xbb46,0xbb47,
+ 0xbb48,0xbb49,0xbb4a,0xbb4b,0xbb4c,0xbb4d,0xbb4e,0xbb4f,
+ 0xbb50,0xbb51,0xbb52,0xbb53,0xbb54,0xbb55,0xbb56,0xbb57,
+ 0xbb58,0xbb59,0xbb5a,0xbb5b,0xbb5c,0xbb5d,0xbb5e,0xbb5f,
+ 0xbb60,0xbb61,0xbb62,0xbb63,0xbb64,0xbb65,0xbb66,0xbb67,
+ 0xbb68,0xbb69,0xbb6a,0xbb6b,0xbb6c,0xbb6d,0xbb6e,0xbb6f,
+ 0xbb70,0xbb71,0xbb72,0xbb73,0xbb74,0xbb75,0xbb76,0xbb77,
+ 0xbb78,0xbb79,0xbb7a,0xbb7b,0xbb7c,0xbb7d,0xbb7e,0xbb7f,
+ 0xbb80,0xbb81,0xbb82,0xbb83,0xbb84,0xbb85,0xbb86,0xbb87,
+ 0xbb88,0xbb89,0xbb8a,0xbb8b,0xbb8c,0xbb8d,0xbb8e,0xbb8f,
+ 0xbb90,0xbb91,0xbb92,0xbb93,0xbb94,0xbb95,0xbb96,0xbb97,
+ 0xbb98,0xbb99,0xbb9a,0xbb9b,0xbb9c,0xbb9d,0xbb9e,0xbb9f,
+ 0xbba0,0xbba1,0xbba2,0xbba3,0xbba4,0xbba5,0xbba6,0xbba7,
+ 0xbba8,0xbba9,0xbbaa,0xbbab,0xbbac,0xbbad,0xbbae,0xbbaf,
+ 0xbbb0,0xbbb1,0xbbb2,0xbbb3,0xbbb4,0xbbb5,0xbbb6,0xbbb7,
+ 0xbbb8,0xbbb9,0xbbba,0xbbbb,0xbbbc,0xbbbd,0xbbbe,0xbbbf,
+ 0xbbc0,0xbbc1,0xbbc2,0xbbc3,0xbbc4,0xbbc5,0xbbc6,0xbbc7,
+ 0xbbc8,0xbbc9,0xbbca,0xbbcb,0xbbcc,0xbbcd,0xbbce,0xbbcf,
+ 0xbbd0,0xbbd1,0xbbd2,0xbbd3,0xbbd4,0xbbd5,0xbbd6,0xbbd7,
+ 0xbbd8,0xbbd9,0xbbda,0xbbdb,0xbbdc,0xbbdd,0xbbde,0xbbdf,
+ 0xbbe0,0xbbe1,0xbbe2,0xbbe3,0xbbe4,0xbbe5,0xbbe6,0xbbe7,
+ 0xbbe8,0xbbe9,0xbbea,0xbbeb,0xbbec,0xbbed,0xbbee,0xbbef,
+ 0xbbf0,0xbbf1,0xbbf2,0xbbf3,0xbbf4,0xbbf5,0xbbf6,0xbbf7,
+ 0xbbf8,0xbbf9,0xbbfa,0xbbfb,0xbbfc,0xbbfd,0xbbfe,0xbbff,
+ 0xbc00,0xbc01,0xbc02,0xbc03,0xbc04,0xbc05,0xbc06,0xbc07,
+ 0xbc08,0xbc09,0xbc0a,0xbc0b,0xbc0c,0xbc0d,0xbc0e,0xbc0f,
+ 0xbc10,0xbc11,0xbc12,0xbc13,0xbc14,0xbc15,0xbc16,0xbc17,
+ 0xbc18,0xbc19,0xbc1a,0xbc1b,0xbc1c,0xbc1d,0xbc1e,0xbc1f,
+ 0xbc20,0xbc21,0xbc22,0xbc23,0xbc24,0xbc25,0xbc26,0xbc27,
+ 0xbc28,0xbc29,0xbc2a,0xbc2b,0xbc2c,0xbc2d,0xbc2e,0xbc2f,
+ 0xbc30,0xbc31,0xbc32,0xbc33,0xbc34,0xbc35,0xbc36,0xbc37,
+ 0xbc38,0xbc39,0xbc3a,0xbc3b,0xbc3c,0xbc3d,0xbc3e,0xbc3f,
+ 0xbc40,0xbc41,0xbc42,0xbc43,0xbc44,0xbc45,0xbc46,0xbc47,
+ 0xbc48,0xbc49,0xbc4a,0xbc4b,0xbc4c,0xbc4d,0xbc4e,0xbc4f,
+ 0xbc50,0xbc51,0xbc52,0xbc53,0xbc54,0xbc55,0xbc56,0xbc57,
+ 0xbc58,0xbc59,0xbc5a,0xbc5b,0xbc5c,0xbc5d,0xbc5e,0xbc5f,
+ 0xbc60,0xbc61,0xbc62,0xbc63,0xbc64,0xbc65,0xbc66,0xbc67,
+ 0xbc68,0xbc69,0xbc6a,0xbc6b,0xbc6c,0xbc6d,0xbc6e,0xbc6f,
+ 0xbc70,0xbc71,0xbc72,0xbc73,0xbc74,0xbc75,0xbc76,0xbc77,
+ 0xbc78,0xbc79,0xbc7a,0xbc7b,0xbc7c,0xbc7d,0xbc7e,0xbc7f,
+ 0xbc80,0xbc81,0xbc82,0xbc83,0xbc84,0xbc85,0xbc86,0xbc87,
+ 0xbc88,0xbc89,0xbc8a,0xbc8b,0xbc8c,0xbc8d,0xbc8e,0xbc8f,
+ 0xbc90,0xbc91,0xbc92,0xbc93,0xbc94,0xbc95,0xbc96,0xbc97,
+ 0xbc98,0xbc99,0xbc9a,0xbc9b,0xbc9c,0xbc9d,0xbc9e,0xbc9f,
+ 0xbca0,0xbca1,0xbca2,0xbca3,0xbca4,0xbca5,0xbca6,0xbca7,
+ 0xbca8,0xbca9,0xbcaa,0xbcab,0xbcac,0xbcad,0xbcae,0xbcaf,
+ 0xbcb0,0xbcb1,0xbcb2,0xbcb3,0xbcb4,0xbcb5,0xbcb6,0xbcb7,
+ 0xbcb8,0xbcb9,0xbcba,0xbcbb,0xbcbc,0xbcbd,0xbcbe,0xbcbf,
+ 0xbcc0,0xbcc1,0xbcc2,0xbcc3,0xbcc4,0xbcc5,0xbcc6,0xbcc7,
+ 0xbcc8,0xbcc9,0xbcca,0xbccb,0xbccc,0xbccd,0xbcce,0xbccf,
+ 0xbcd0,0xbcd1,0xbcd2,0xbcd3,0xbcd4,0xbcd5,0xbcd6,0xbcd7,
+ 0xbcd8,0xbcd9,0xbcda,0xbcdb,0xbcdc,0xbcdd,0xbcde,0xbcdf,
+ 0xbce0,0xbce1,0xbce2,0xbce3,0xbce4,0xbce5,0xbce6,0xbce7,
+ 0xbce8,0xbce9,0xbcea,0xbceb,0xbcec,0xbced,0xbcee,0xbcef,
+ 0xbcf0,0xbcf1,0xbcf2,0xbcf3,0xbcf4,0xbcf5,0xbcf6,0xbcf7,
+ 0xbcf8,0xbcf9,0xbcfa,0xbcfb,0xbcfc,0xbcfd,0xbcfe,0xbcff,
+ 0xbd00,0xbd01,0xbd02,0xbd03,0xbd04,0xbd05,0xbd06,0xbd07,
+ 0xbd08,0xbd09,0xbd0a,0xbd0b,0xbd0c,0xbd0d,0xbd0e,0xbd0f,
+ 0xbd10,0xbd11,0xbd12,0xbd13,0xbd14,0xbd15,0xbd16,0xbd17,
+ 0xbd18,0xbd19,0xbd1a,0xbd1b,0xbd1c,0xbd1d,0xbd1e,0xbd1f,
+ 0xbd20,0xbd21,0xbd22,0xbd23,0xbd24,0xbd25,0xbd26,0xbd27,
+ 0xbd28,0xbd29,0xbd2a,0xbd2b,0xbd2c,0xbd2d,0xbd2e,0xbd2f,
+ 0xbd30,0xbd31,0xbd32,0xbd33,0xbd34,0xbd35,0xbd36,0xbd37,
+ 0xbd38,0xbd39,0xbd3a,0xbd3b,0xbd3c,0xbd3d,0xbd3e,0xbd3f,
+ 0xbd40,0xbd41,0xbd42,0xbd43,0xbd44,0xbd45,0xbd46,0xbd47,
+ 0xbd48,0xbd49,0xbd4a,0xbd4b,0xbd4c,0xbd4d,0xbd4e,0xbd4f,
+ 0xbd50,0xbd51,0xbd52,0xbd53,0xbd54,0xbd55,0xbd56,0xbd57,
+ 0xbd58,0xbd59,0xbd5a,0xbd5b,0xbd5c,0xbd5d,0xbd5e,0xbd5f,
+ 0xbd60,0xbd61,0xbd62,0xbd63,0xbd64,0xbd65,0xbd66,0xbd67,
+ 0xbd68,0xbd69,0xbd6a,0xbd6b,0xbd6c,0xbd6d,0xbd6e,0xbd6f,
+ 0xbd70,0xbd71,0xbd72,0xbd73,0xbd74,0xbd75,0xbd76,0xbd77,
+ 0xbd78,0xbd79,0xbd7a,0xbd7b,0xbd7c,0xbd7d,0xbd7e,0xbd7f,
+ 0xbd80,0xbd81,0xbd82,0xbd83,0xbd84,0xbd85,0xbd86,0xbd87,
+ 0xbd88,0xbd89,0xbd8a,0xbd8b,0xbd8c,0xbd8d,0xbd8e,0xbd8f,
+ 0xbd90,0xbd91,0xbd92,0xbd93,0xbd94,0xbd95,0xbd96,0xbd97,
+ 0xbd98,0xbd99,0xbd9a,0xbd9b,0xbd9c,0xbd9d,0xbd9e,0xbd9f,
+ 0xbda0,0xbda1,0xbda2,0xbda3,0xbda4,0xbda5,0xbda6,0xbda7,
+ 0xbda8,0xbda9,0xbdaa,0xbdab,0xbdac,0xbdad,0xbdae,0xbdaf,
+ 0xbdb0,0xbdb1,0xbdb2,0xbdb3,0xbdb4,0xbdb5,0xbdb6,0xbdb7,
+ 0xbdb8,0xbdb9,0xbdba,0xbdbb,0xbdbc,0xbdbd,0xbdbe,0xbdbf,
+ 0xbdc0,0xbdc1,0xbdc2,0xbdc3,0xbdc4,0xbdc5,0xbdc6,0xbdc7,
+ 0xbdc8,0xbdc9,0xbdca,0xbdcb,0xbdcc,0xbdcd,0xbdce,0xbdcf,
+ 0xbdd0,0xbdd1,0xbdd2,0xbdd3,0xbdd4,0xbdd5,0xbdd6,0xbdd7,
+ 0xbdd8,0xbdd9,0xbdda,0xbddb,0xbddc,0xbddd,0xbdde,0xbddf,
+ 0xbde0,0xbde1,0xbde2,0xbde3,0xbde4,0xbde5,0xbde6,0xbde7,
+ 0xbde8,0xbde9,0xbdea,0xbdeb,0xbdec,0xbded,0xbdee,0xbdef,
+ 0xbdf0,0xbdf1,0xbdf2,0xbdf3,0xbdf4,0xbdf5,0xbdf6,0xbdf7,
+ 0xbdf8,0xbdf9,0xbdfa,0xbdfb,0xbdfc,0xbdfd,0xbdfe,0xbdff,
+ 0xbe00,0xbe01,0xbe02,0xbe03,0xbe04,0xbe05,0xbe06,0xbe07,
+ 0xbe08,0xbe09,0xbe0a,0xbe0b,0xbe0c,0xbe0d,0xbe0e,0xbe0f,
+ 0xbe10,0xbe11,0xbe12,0xbe13,0xbe14,0xbe15,0xbe16,0xbe17,
+ 0xbe18,0xbe19,0xbe1a,0xbe1b,0xbe1c,0xbe1d,0xbe1e,0xbe1f,
+ 0xbe20,0xbe21,0xbe22,0xbe23,0xbe24,0xbe25,0xbe26,0xbe27,
+ 0xbe28,0xbe29,0xbe2a,0xbe2b,0xbe2c,0xbe2d,0xbe2e,0xbe2f,
+ 0xbe30,0xbe31,0xbe32,0xbe33,0xbe34,0xbe35,0xbe36,0xbe37,
+ 0xbe38,0xbe39,0xbe3a,0xbe3b,0xbe3c,0xbe3d,0xbe3e,0xbe3f,
+ 0xbe40,0xbe41,0xbe42,0xbe43,0xbe44,0xbe45,0xbe46,0xbe47,
+ 0xbe48,0xbe49,0xbe4a,0xbe4b,0xbe4c,0xbe4d,0xbe4e,0xbe4f,
+ 0xbe50,0xbe51,0xbe52,0xbe53,0xbe54,0xbe55,0xbe56,0xbe57,
+ 0xbe58,0xbe59,0xbe5a,0xbe5b,0xbe5c,0xbe5d,0xbe5e,0xbe5f,
+ 0xbe60,0xbe61,0xbe62,0xbe63,0xbe64,0xbe65,0xbe66,0xbe67,
+ 0xbe68,0xbe69,0xbe6a,0xbe6b,0xbe6c,0xbe6d,0xbe6e,0xbe6f,
+ 0xbe70,0xbe71,0xbe72,0xbe73,0xbe74,0xbe75,0xbe76,0xbe77,
+ 0xbe78,0xbe79,0xbe7a,0xbe7b,0xbe7c,0xbe7d,0xbe7e,0xbe7f,
+ 0xbe80,0xbe81,0xbe82,0xbe83,0xbe84,0xbe85,0xbe86,0xbe87,
+ 0xbe88,0xbe89,0xbe8a,0xbe8b,0xbe8c,0xbe8d,0xbe8e,0xbe8f,
+ 0xbe90,0xbe91,0xbe92,0xbe93,0xbe94,0xbe95,0xbe96,0xbe97,
+ 0xbe98,0xbe99,0xbe9a,0xbe9b,0xbe9c,0xbe9d,0xbe9e,0xbe9f,
+ 0xbea0,0xbea1,0xbea2,0xbea3,0xbea4,0xbea5,0xbea6,0xbea7,
+ 0xbea8,0xbea9,0xbeaa,0xbeab,0xbeac,0xbead,0xbeae,0xbeaf,
+ 0xbeb0,0xbeb1,0xbeb2,0xbeb3,0xbeb4,0xbeb5,0xbeb6,0xbeb7,
+ 0xbeb8,0xbeb9,0xbeba,0xbebb,0xbebc,0xbebd,0xbebe,0xbebf,
+ 0xbec0,0xbec1,0xbec2,0xbec3,0xbec4,0xbec5,0xbec6,0xbec7,
+ 0xbec8,0xbec9,0xbeca,0xbecb,0xbecc,0xbecd,0xbece,0xbecf,
+ 0xbed0,0xbed1,0xbed2,0xbed3,0xbed4,0xbed5,0xbed6,0xbed7,
+ 0xbed8,0xbed9,0xbeda,0xbedb,0xbedc,0xbedd,0xbede,0xbedf,
+ 0xbee0,0xbee1,0xbee2,0xbee3,0xbee4,0xbee5,0xbee6,0xbee7,
+ 0xbee8,0xbee9,0xbeea,0xbeeb,0xbeec,0xbeed,0xbeee,0xbeef,
+ 0xbef0,0xbef1,0xbef2,0xbef3,0xbef4,0xbef5,0xbef6,0xbef7,
+ 0xbef8,0xbef9,0xbefa,0xbefb,0xbefc,0xbefd,0xbefe,0xbeff,
+ 0xbf00,0xbf01,0xbf02,0xbf03,0xbf04,0xbf05,0xbf06,0xbf07,
+ 0xbf08,0xbf09,0xbf0a,0xbf0b,0xbf0c,0xbf0d,0xbf0e,0xbf0f,
+ 0xbf10,0xbf11,0xbf12,0xbf13,0xbf14,0xbf15,0xbf16,0xbf17,
+ 0xbf18,0xbf19,0xbf1a,0xbf1b,0xbf1c,0xbf1d,0xbf1e,0xbf1f,
+ 0xbf20,0xbf21,0xbf22,0xbf23,0xbf24,0xbf25,0xbf26,0xbf27,
+ 0xbf28,0xbf29,0xbf2a,0xbf2b,0xbf2c,0xbf2d,0xbf2e,0xbf2f,
+ 0xbf30,0xbf31,0xbf32,0xbf33,0xbf34,0xbf35,0xbf36,0xbf37,
+ 0xbf38,0xbf39,0xbf3a,0xbf3b,0xbf3c,0xbf3d,0xbf3e,0xbf3f,
+ 0xbf40,0xbf41,0xbf42,0xbf43,0xbf44,0xbf45,0xbf46,0xbf47,
+ 0xbf48,0xbf49,0xbf4a,0xbf4b,0xbf4c,0xbf4d,0xbf4e,0xbf4f,
+ 0xbf50,0xbf51,0xbf52,0xbf53,0xbf54,0xbf55,0xbf56,0xbf57,
+ 0xbf58,0xbf59,0xbf5a,0xbf5b,0xbf5c,0xbf5d,0xbf5e,0xbf5f,
+ 0xbf60,0xbf61,0xbf62,0xbf63,0xbf64,0xbf65,0xbf66,0xbf67,
+ 0xbf68,0xbf69,0xbf6a,0xbf6b,0xbf6c,0xbf6d,0xbf6e,0xbf6f,
+ 0xbf70,0xbf71,0xbf72,0xbf73,0xbf74,0xbf75,0xbf76,0xbf77,
+ 0xbf78,0xbf79,0xbf7a,0xbf7b,0xbf7c,0xbf7d,0xbf7e,0xbf7f,
+ 0xbf80,0xbf81,0xbf82,0xbf83,0xbf84,0xbf85,0xbf86,0xbf87,
+ 0xbf88,0xbf89,0xbf8a,0xbf8b,0xbf8c,0xbf8d,0xbf8e,0xbf8f,
+ 0xbf90,0xbf91,0xbf92,0xbf93,0xbf94,0xbf95,0xbf96,0xbf97,
+ 0xbf98,0xbf99,0xbf9a,0xbf9b,0xbf9c,0xbf9d,0xbf9e,0xbf9f,
+ 0xbfa0,0xbfa1,0xbfa2,0xbfa3,0xbfa4,0xbfa5,0xbfa6,0xbfa7,
+ 0xbfa8,0xbfa9,0xbfaa,0xbfab,0xbfac,0xbfad,0xbfae,0xbfaf,
+ 0xbfb0,0xbfb1,0xbfb2,0xbfb3,0xbfb4,0xbfb5,0xbfb6,0xbfb7,
+ 0xbfb8,0xbfb9,0xbfba,0xbfbb,0xbfbc,0xbfbd,0xbfbe,0xbfbf,
+ 0xbfc0,0xbfc1,0xbfc2,0xbfc3,0xbfc4,0xbfc5,0xbfc6,0xbfc7,
+ 0xbfc8,0xbfc9,0xbfca,0xbfcb,0xbfcc,0xbfcd,0xbfce,0xbfcf,
+ 0xbfd0,0xbfd1,0xbfd2,0xbfd3,0xbfd4,0xbfd5,0xbfd6,0xbfd7,
+ 0xbfd8,0xbfd9,0xbfda,0xbfdb,0xbfdc,0xbfdd,0xbfde,0xbfdf,
+ 0xbfe0,0xbfe1,0xbfe2,0xbfe3,0xbfe4,0xbfe5,0xbfe6,0xbfe7,
+ 0xbfe8,0xbfe9,0xbfea,0xbfeb,0xbfec,0xbfed,0xbfee,0xbfef,
+ 0xbff0,0xbff1,0xbff2,0xbff3,0xbff4,0xbff5,0xbff6,0xbff7,
+ 0xbff8,0xbff9,0xbffa,0xbffb,0xbffc,0xbffd,0xbffe,0xbfff,
+ 0xc000,0xc001,0xc002,0xc003,0xc004,0xc005,0xc006,0xc007,
+ 0xc008,0xc009,0xc00a,0xc00b,0xc00c,0xc00d,0xc00e,0xc00f,
+ 0xc010,0xc011,0xc012,0xc013,0xc014,0xc015,0xc016,0xc017,
+ 0xc018,0xc019,0xc01a,0xc01b,0xc01c,0xc01d,0xc01e,0xc01f,
+ 0xc020,0xc021,0xc022,0xc023,0xc024,0xc025,0xc026,0xc027,
+ 0xc028,0xc029,0xc02a,0xc02b,0xc02c,0xc02d,0xc02e,0xc02f,
+ 0xc030,0xc031,0xc032,0xc033,0xc034,0xc035,0xc036,0xc037,
+ 0xc038,0xc039,0xc03a,0xc03b,0xc03c,0xc03d,0xc03e,0xc03f,
+ 0xc040,0xc041,0xc042,0xc043,0xc044,0xc045,0xc046,0xc047,
+ 0xc048,0xc049,0xc04a,0xc04b,0xc04c,0xc04d,0xc04e,0xc04f,
+ 0xc050,0xc051,0xc052,0xc053,0xc054,0xc055,0xc056,0xc057,
+ 0xc058,0xc059,0xc05a,0xc05b,0xc05c,0xc05d,0xc05e,0xc05f,
+ 0xc060,0xc061,0xc062,0xc063,0xc064,0xc065,0xc066,0xc067,
+ 0xc068,0xc069,0xc06a,0xc06b,0xc06c,0xc06d,0xc06e,0xc06f,
+ 0xc070,0xc071,0xc072,0xc073,0xc074,0xc075,0xc076,0xc077,
+ 0xc078,0xc079,0xc07a,0xc07b,0xc07c,0xc07d,0xc07e,0xc07f,
+ 0xc080,0xc081,0xc082,0xc083,0xc084,0xc085,0xc086,0xc087,
+ 0xc088,0xc089,0xc08a,0xc08b,0xc08c,0xc08d,0xc08e,0xc08f,
+ 0xc090,0xc091,0xc092,0xc093,0xc094,0xc095,0xc096,0xc097,
+ 0xc098,0xc099,0xc09a,0xc09b,0xc09c,0xc09d,0xc09e,0xc09f,
+ 0xc0a0,0xc0a1,0xc0a2,0xc0a3,0xc0a4,0xc0a5,0xc0a6,0xc0a7,
+ 0xc0a8,0xc0a9,0xc0aa,0xc0ab,0xc0ac,0xc0ad,0xc0ae,0xc0af,
+ 0xc0b0,0xc0b1,0xc0b2,0xc0b3,0xc0b4,0xc0b5,0xc0b6,0xc0b7,
+ 0xc0b8,0xc0b9,0xc0ba,0xc0bb,0xc0bc,0xc0bd,0xc0be,0xc0bf,
+ 0xc0c0,0xc0c1,0xc0c2,0xc0c3,0xc0c4,0xc0c5,0xc0c6,0xc0c7,
+ 0xc0c8,0xc0c9,0xc0ca,0xc0cb,0xc0cc,0xc0cd,0xc0ce,0xc0cf,
+ 0xc0d0,0xc0d1,0xc0d2,0xc0d3,0xc0d4,0xc0d5,0xc0d6,0xc0d7,
+ 0xc0d8,0xc0d9,0xc0da,0xc0db,0xc0dc,0xc0dd,0xc0de,0xc0df,
+ 0xc0e0,0xc0e1,0xc0e2,0xc0e3,0xc0e4,0xc0e5,0xc0e6,0xc0e7,
+ 0xc0e8,0xc0e9,0xc0ea,0xc0eb,0xc0ec,0xc0ed,0xc0ee,0xc0ef,
+ 0xc0f0,0xc0f1,0xc0f2,0xc0f3,0xc0f4,0xc0f5,0xc0f6,0xc0f7,
+ 0xc0f8,0xc0f9,0xc0fa,0xc0fb,0xc0fc,0xc0fd,0xc0fe,0xc0ff,
+ 0xc100,0xc101,0xc102,0xc103,0xc104,0xc105,0xc106,0xc107,
+ 0xc108,0xc109,0xc10a,0xc10b,0xc10c,0xc10d,0xc10e,0xc10f,
+ 0xc110,0xc111,0xc112,0xc113,0xc114,0xc115,0xc116,0xc117,
+ 0xc118,0xc119,0xc11a,0xc11b,0xc11c,0xc11d,0xc11e,0xc11f,
+ 0xc120,0xc121,0xc122,0xc123,0xc124,0xc125,0xc126,0xc127,
+ 0xc128,0xc129,0xc12a,0xc12b,0xc12c,0xc12d,0xc12e,0xc12f,
+ 0xc130,0xc131,0xc132,0xc133,0xc134,0xc135,0xc136,0xc137,
+ 0xc138,0xc139,0xc13a,0xc13b,0xc13c,0xc13d,0xc13e,0xc13f,
+ 0xc140,0xc141,0xc142,0xc143,0xc144,0xc145,0xc146,0xc147,
+ 0xc148,0xc149,0xc14a,0xc14b,0xc14c,0xc14d,0xc14e,0xc14f,
+ 0xc150,0xc151,0xc152,0xc153,0xc154,0xc155,0xc156,0xc157,
+ 0xc158,0xc159,0xc15a,0xc15b,0xc15c,0xc15d,0xc15e,0xc15f,
+ 0xc160,0xc161,0xc162,0xc163,0xc164,0xc165,0xc166,0xc167,
+ 0xc168,0xc169,0xc16a,0xc16b,0xc16c,0xc16d,0xc16e,0xc16f,
+ 0xc170,0xc171,0xc172,0xc173,0xc174,0xc175,0xc176,0xc177,
+ 0xc178,0xc179,0xc17a,0xc17b,0xc17c,0xc17d,0xc17e,0xc17f,
+ 0xc180,0xc181,0xc182,0xc183,0xc184,0xc185,0xc186,0xc187,
+ 0xc188,0xc189,0xc18a,0xc18b,0xc18c,0xc18d,0xc18e,0xc18f,
+ 0xc190,0xc191,0xc192,0xc193,0xc194,0xc195,0xc196,0xc197,
+ 0xc198,0xc199,0xc19a,0xc19b,0xc19c,0xc19d,0xc19e,0xc19f,
+ 0xc1a0,0xc1a1,0xc1a2,0xc1a3,0xc1a4,0xc1a5,0xc1a6,0xc1a7,
+ 0xc1a8,0xc1a9,0xc1aa,0xc1ab,0xc1ac,0xc1ad,0xc1ae,0xc1af,
+ 0xc1b0,0xc1b1,0xc1b2,0xc1b3,0xc1b4,0xc1b5,0xc1b6,0xc1b7,
+ 0xc1b8,0xc1b9,0xc1ba,0xc1bb,0xc1bc,0xc1bd,0xc1be,0xc1bf,
+ 0xc1c0,0xc1c1,0xc1c2,0xc1c3,0xc1c4,0xc1c5,0xc1c6,0xc1c7,
+ 0xc1c8,0xc1c9,0xc1ca,0xc1cb,0xc1cc,0xc1cd,0xc1ce,0xc1cf,
+ 0xc1d0,0xc1d1,0xc1d2,0xc1d3,0xc1d4,0xc1d5,0xc1d6,0xc1d7,
+ 0xc1d8,0xc1d9,0xc1da,0xc1db,0xc1dc,0xc1dd,0xc1de,0xc1df,
+ 0xc1e0,0xc1e1,0xc1e2,0xc1e3,0xc1e4,0xc1e5,0xc1e6,0xc1e7,
+ 0xc1e8,0xc1e9,0xc1ea,0xc1eb,0xc1ec,0xc1ed,0xc1ee,0xc1ef,
+ 0xc1f0,0xc1f1,0xc1f2,0xc1f3,0xc1f4,0xc1f5,0xc1f6,0xc1f7,
+ 0xc1f8,0xc1f9,0xc1fa,0xc1fb,0xc1fc,0xc1fd,0xc1fe,0xc1ff,
+ 0xc200,0xc201,0xc202,0xc203,0xc204,0xc205,0xc206,0xc207,
+ 0xc208,0xc209,0xc20a,0xc20b,0xc20c,0xc20d,0xc20e,0xc20f,
+ 0xc210,0xc211,0xc212,0xc213,0xc214,0xc215,0xc216,0xc217,
+ 0xc218,0xc219,0xc21a,0xc21b,0xc21c,0xc21d,0xc21e,0xc21f,
+ 0xc220,0xc221,0xc222,0xc223,0xc224,0xc225,0xc226,0xc227,
+ 0xc228,0xc229,0xc22a,0xc22b,0xc22c,0xc22d,0xc22e,0xc22f,
+ 0xc230,0xc231,0xc232,0xc233,0xc234,0xc235,0xc236,0xc237,
+ 0xc238,0xc239,0xc23a,0xc23b,0xc23c,0xc23d,0xc23e,0xc23f,
+ 0xc240,0xc241,0xc242,0xc243,0xc244,0xc245,0xc246,0xc247,
+ 0xc248,0xc249,0xc24a,0xc24b,0xc24c,0xc24d,0xc24e,0xc24f,
+ 0xc250,0xc251,0xc252,0xc253,0xc254,0xc255,0xc256,0xc257,
+ 0xc258,0xc259,0xc25a,0xc25b,0xc25c,0xc25d,0xc25e,0xc25f,
+ 0xc260,0xc261,0xc262,0xc263,0xc264,0xc265,0xc266,0xc267,
+ 0xc268,0xc269,0xc26a,0xc26b,0xc26c,0xc26d,0xc26e,0xc26f,
+ 0xc270,0xc271,0xc272,0xc273,0xc274,0xc275,0xc276,0xc277,
+ 0xc278,0xc279,0xc27a,0xc27b,0xc27c,0xc27d,0xc27e,0xc27f,
+ 0xc280,0xc281,0xc282,0xc283,0xc284,0xc285,0xc286,0xc287,
+ 0xc288,0xc289,0xc28a,0xc28b,0xc28c,0xc28d,0xc28e,0xc28f,
+ 0xc290,0xc291,0xc292,0xc293,0xc294,0xc295,0xc296,0xc297,
+ 0xc298,0xc299,0xc29a,0xc29b,0xc29c,0xc29d,0xc29e,0xc29f,
+ 0xc2a0,0xc2a1,0xc2a2,0xc2a3,0xc2a4,0xc2a5,0xc2a6,0xc2a7,
+ 0xc2a8,0xc2a9,0xc2aa,0xc2ab,0xc2ac,0xc2ad,0xc2ae,0xc2af,
+ 0xc2b0,0xc2b1,0xc2b2,0xc2b3,0xc2b4,0xc2b5,0xc2b6,0xc2b7,
+ 0xc2b8,0xc2b9,0xc2ba,0xc2bb,0xc2bc,0xc2bd,0xc2be,0xc2bf,
+ 0xc2c0,0xc2c1,0xc2c2,0xc2c3,0xc2c4,0xc2c5,0xc2c6,0xc2c7,
+ 0xc2c8,0xc2c9,0xc2ca,0xc2cb,0xc2cc,0xc2cd,0xc2ce,0xc2cf,
+ 0xc2d0,0xc2d1,0xc2d2,0xc2d3,0xc2d4,0xc2d5,0xc2d6,0xc2d7,
+ 0xc2d8,0xc2d9,0xc2da,0xc2db,0xc2dc,0xc2dd,0xc2de,0xc2df,
+ 0xc2e0,0xc2e1,0xc2e2,0xc2e3,0xc2e4,0xc2e5,0xc2e6,0xc2e7,
+ 0xc2e8,0xc2e9,0xc2ea,0xc2eb,0xc2ec,0xc2ed,0xc2ee,0xc2ef,
+ 0xc2f0,0xc2f1,0xc2f2,0xc2f3,0xc2f4,0xc2f5,0xc2f6,0xc2f7,
+ 0xc2f8,0xc2f9,0xc2fa,0xc2fb,0xc2fc,0xc2fd,0xc2fe,0xc2ff,
+ 0xc300,0xc301,0xc302,0xc303,0xc304,0xc305,0xc306,0xc307,
+ 0xc308,0xc309,0xc30a,0xc30b,0xc30c,0xc30d,0xc30e,0xc30f,
+ 0xc310,0xc311,0xc312,0xc313,0xc314,0xc315,0xc316,0xc317,
+ 0xc318,0xc319,0xc31a,0xc31b,0xc31c,0xc31d,0xc31e,0xc31f,
+ 0xc320,0xc321,0xc322,0xc323,0xc324,0xc325,0xc326,0xc327,
+ 0xc328,0xc329,0xc32a,0xc32b,0xc32c,0xc32d,0xc32e,0xc32f,
+ 0xc330,0xc331,0xc332,0xc333,0xc334,0xc335,0xc336,0xc337,
+ 0xc338,0xc339,0xc33a,0xc33b,0xc33c,0xc33d,0xc33e,0xc33f,
+ 0xc340,0xc341,0xc342,0xc343,0xc344,0xc345,0xc346,0xc347,
+ 0xc348,0xc349,0xc34a,0xc34b,0xc34c,0xc34d,0xc34e,0xc34f,
+ 0xc350,0xc351,0xc352,0xc353,0xc354,0xc355,0xc356,0xc357,
+ 0xc358,0xc359,0xc35a,0xc35b,0xc35c,0xc35d,0xc35e,0xc35f,
+ 0xc360,0xc361,0xc362,0xc363,0xc364,0xc365,0xc366,0xc367,
+ 0xc368,0xc369,0xc36a,0xc36b,0xc36c,0xc36d,0xc36e,0xc36f,
+ 0xc370,0xc371,0xc372,0xc373,0xc374,0xc375,0xc376,0xc377,
+ 0xc378,0xc379,0xc37a,0xc37b,0xc37c,0xc37d,0xc37e,0xc37f,
+ 0xc380,0xc381,0xc382,0xc383,0xc384,0xc385,0xc386,0xc387,
+ 0xc388,0xc389,0xc38a,0xc38b,0xc38c,0xc38d,0xc38e,0xc38f,
+ 0xc390,0xc391,0xc392,0xc393,0xc394,0xc395,0xc396,0xc397,
+ 0xc398,0xc399,0xc39a,0xc39b,0xc39c,0xc39d,0xc39e,0xc39f,
+ 0xc3a0,0xc3a1,0xc3a2,0xc3a3,0xc3a4,0xc3a5,0xc3a6,0xc3a7,
+ 0xc3a8,0xc3a9,0xc3aa,0xc3ab,0xc3ac,0xc3ad,0xc3ae,0xc3af,
+ 0xc3b0,0xc3b1,0xc3b2,0xc3b3,0xc3b4,0xc3b5,0xc3b6,0xc3b7,
+ 0xc3b8,0xc3b9,0xc3ba,0xc3bb,0xc3bc,0xc3bd,0xc3be,0xc3bf,
+ 0xc3c0,0xc3c1,0xc3c2,0xc3c3,0xc3c4,0xc3c5,0xc3c6,0xc3c7,
+ 0xc3c8,0xc3c9,0xc3ca,0xc3cb,0xc3cc,0xc3cd,0xc3ce,0xc3cf,
+ 0xc3d0,0xc3d1,0xc3d2,0xc3d3,0xc3d4,0xc3d5,0xc3d6,0xc3d7,
+ 0xc3d8,0xc3d9,0xc3da,0xc3db,0xc3dc,0xc3dd,0xc3de,0xc3df,
+ 0xc3e0,0xc3e1,0xc3e2,0xc3e3,0xc3e4,0xc3e5,0xc3e6,0xc3e7,
+ 0xc3e8,0xc3e9,0xc3ea,0xc3eb,0xc3ec,0xc3ed,0xc3ee,0xc3ef,
+ 0xc3f0,0xc3f1,0xc3f2,0xc3f3,0xc3f4,0xc3f5,0xc3f6,0xc3f7,
+ 0xc3f8,0xc3f9,0xc3fa,0xc3fb,0xc3fc,0xc3fd,0xc3fe,0xc3ff,
+ 0xc400,0xc401,0xc402,0xc403,0xc404,0xc405,0xc406,0xc407,
+ 0xc408,0xc409,0xc40a,0xc40b,0xc40c,0xc40d,0xc40e,0xc40f,
+ 0xc410,0xc411,0xc412,0xc413,0xc414,0xc415,0xc416,0xc417,
+ 0xc418,0xc419,0xc41a,0xc41b,0xc41c,0xc41d,0xc41e,0xc41f,
+ 0xc420,0xc421,0xc422,0xc423,0xc424,0xc425,0xc426,0xc427,
+ 0xc428,0xc429,0xc42a,0xc42b,0xc42c,0xc42d,0xc42e,0xc42f,
+ 0xc430,0xc431,0xc432,0xc433,0xc434,0xc435,0xc436,0xc437,
+ 0xc438,0xc439,0xc43a,0xc43b,0xc43c,0xc43d,0xc43e,0xc43f,
+ 0xc440,0xc441,0xc442,0xc443,0xc444,0xc445,0xc446,0xc447,
+ 0xc448,0xc449,0xc44a,0xc44b,0xc44c,0xc44d,0xc44e,0xc44f,
+ 0xc450,0xc451,0xc452,0xc453,0xc454,0xc455,0xc456,0xc457,
+ 0xc458,0xc459,0xc45a,0xc45b,0xc45c,0xc45d,0xc45e,0xc45f,
+ 0xc460,0xc461,0xc462,0xc463,0xc464,0xc465,0xc466,0xc467,
+ 0xc468,0xc469,0xc46a,0xc46b,0xc46c,0xc46d,0xc46e,0xc46f,
+ 0xc470,0xc471,0xc472,0xc473,0xc474,0xc475,0xc476,0xc477,
+ 0xc478,0xc479,0xc47a,0xc47b,0xc47c,0xc47d,0xc47e,0xc47f,
+ 0xc480,0xc481,0xc482,0xc483,0xc484,0xc485,0xc486,0xc487,
+ 0xc488,0xc489,0xc48a,0xc48b,0xc48c,0xc48d,0xc48e,0xc48f,
+ 0xc490,0xc491,0xc492,0xc493,0xc494,0xc495,0xc496,0xc497,
+ 0xc498,0xc499,0xc49a,0xc49b,0xc49c,0xc49d,0xc49e,0xc49f,
+ 0xc4a0,0xc4a1,0xc4a2,0xc4a3,0xc4a4,0xc4a5,0xc4a6,0xc4a7,
+ 0xc4a8,0xc4a9,0xc4aa,0xc4ab,0xc4ac,0xc4ad,0xc4ae,0xc4af,
+ 0xc4b0,0xc4b1,0xc4b2,0xc4b3,0xc4b4,0xc4b5,0xc4b6,0xc4b7,
+ 0xc4b8,0xc4b9,0xc4ba,0xc4bb,0xc4bc,0xc4bd,0xc4be,0xc4bf,
+ 0xc4c0,0xc4c1,0xc4c2,0xc4c3,0xc4c4,0xc4c5,0xc4c6,0xc4c7,
+ 0xc4c8,0xc4c9,0xc4ca,0xc4cb,0xc4cc,0xc4cd,0xc4ce,0xc4cf,
+ 0xc4d0,0xc4d1,0xc4d2,0xc4d3,0xc4d4,0xc4d5,0xc4d6,0xc4d7,
+ 0xc4d8,0xc4d9,0xc4da,0xc4db,0xc4dc,0xc4dd,0xc4de,0xc4df,
+ 0xc4e0,0xc4e1,0xc4e2,0xc4e3,0xc4e4,0xc4e5,0xc4e6,0xc4e7,
+ 0xc4e8,0xc4e9,0xc4ea,0xc4eb,0xc4ec,0xc4ed,0xc4ee,0xc4ef,
+ 0xc4f0,0xc4f1,0xc4f2,0xc4f3,0xc4f4,0xc4f5,0xc4f6,0xc4f7,
+ 0xc4f8,0xc4f9,0xc4fa,0xc4fb,0xc4fc,0xc4fd,0xc4fe,0xc4ff,
+ 0xc500,0xc501,0xc502,0xc503,0xc504,0xc505,0xc506,0xc507,
+ 0xc508,0xc509,0xc50a,0xc50b,0xc50c,0xc50d,0xc50e,0xc50f,
+ 0xc510,0xc511,0xc512,0xc513,0xc514,0xc515,0xc516,0xc517,
+ 0xc518,0xc519,0xc51a,0xc51b,0xc51c,0xc51d,0xc51e,0xc51f,
+ 0xc520,0xc521,0xc522,0xc523,0xc524,0xc525,0xc526,0xc527,
+ 0xc528,0xc529,0xc52a,0xc52b,0xc52c,0xc52d,0xc52e,0xc52f,
+ 0xc530,0xc531,0xc532,0xc533,0xc534,0xc535,0xc536,0xc537,
+ 0xc538,0xc539,0xc53a,0xc53b,0xc53c,0xc53d,0xc53e,0xc53f,
+ 0xc540,0xc541,0xc542,0xc543,0xc544,0xc545,0xc546,0xc547,
+ 0xc548,0xc549,0xc54a,0xc54b,0xc54c,0xc54d,0xc54e,0xc54f,
+ 0xc550,0xc551,0xc552,0xc553,0xc554,0xc555,0xc556,0xc557,
+ 0xc558,0xc559,0xc55a,0xc55b,0xc55c,0xc55d,0xc55e,0xc55f,
+ 0xc560,0xc561,0xc562,0xc563,0xc564,0xc565,0xc566,0xc567,
+ 0xc568,0xc569,0xc56a,0xc56b,0xc56c,0xc56d,0xc56e,0xc56f,
+ 0xc570,0xc571,0xc572,0xc573,0xc574,0xc575,0xc576,0xc577,
+ 0xc578,0xc579,0xc57a,0xc57b,0xc57c,0xc57d,0xc57e,0xc57f,
+ 0xc580,0xc581,0xc582,0xc583,0xc584,0xc585,0xc586,0xc587,
+ 0xc588,0xc589,0xc58a,0xc58b,0xc58c,0xc58d,0xc58e,0xc58f,
+ 0xc590,0xc591,0xc592,0xc593,0xc594,0xc595,0xc596,0xc597,
+ 0xc598,0xc599,0xc59a,0xc59b,0xc59c,0xc59d,0xc59e,0xc59f,
+ 0xc5a0,0xc5a1,0xc5a2,0xc5a3,0xc5a4,0xc5a5,0xc5a6,0xc5a7,
+ 0xc5a8,0xc5a9,0xc5aa,0xc5ab,0xc5ac,0xc5ad,0xc5ae,0xc5af,
+ 0xc5b0,0xc5b1,0xc5b2,0xc5b3,0xc5b4,0xc5b5,0xc5b6,0xc5b7,
+ 0xc5b8,0xc5b9,0xc5ba,0xc5bb,0xc5bc,0xc5bd,0xc5be,0xc5bf,
+ 0xc5c0,0xc5c1,0xc5c2,0xc5c3,0xc5c4,0xc5c5,0xc5c6,0xc5c7,
+ 0xc5c8,0xc5c9,0xc5ca,0xc5cb,0xc5cc,0xc5cd,0xc5ce,0xc5cf,
+ 0xc5d0,0xc5d1,0xc5d2,0xc5d3,0xc5d4,0xc5d5,0xc5d6,0xc5d7,
+ 0xc5d8,0xc5d9,0xc5da,0xc5db,0xc5dc,0xc5dd,0xc5de,0xc5df,
+ 0xc5e0,0xc5e1,0xc5e2,0xc5e3,0xc5e4,0xc5e5,0xc5e6,0xc5e7,
+ 0xc5e8,0xc5e9,0xc5ea,0xc5eb,0xc5ec,0xc5ed,0xc5ee,0xc5ef,
+ 0xc5f0,0xc5f1,0xc5f2,0xc5f3,0xc5f4,0xc5f5,0xc5f6,0xc5f7,
+ 0xc5f8,0xc5f9,0xc5fa,0xc5fb,0xc5fc,0xc5fd,0xc5fe,0xc5ff,
+ 0xc600,0xc601,0xc602,0xc603,0xc604,0xc605,0xc606,0xc607,
+ 0xc608,0xc609,0xc60a,0xc60b,0xc60c,0xc60d,0xc60e,0xc60f,
+ 0xc610,0xc611,0xc612,0xc613,0xc614,0xc615,0xc616,0xc617,
+ 0xc618,0xc619,0xc61a,0xc61b,0xc61c,0xc61d,0xc61e,0xc61f,
+ 0xc620,0xc621,0xc622,0xc623,0xc624,0xc625,0xc626,0xc627,
+ 0xc628,0xc629,0xc62a,0xc62b,0xc62c,0xc62d,0xc62e,0xc62f,
+ 0xc630,0xc631,0xc632,0xc633,0xc634,0xc635,0xc636,0xc637,
+ 0xc638,0xc639,0xc63a,0xc63b,0xc63c,0xc63d,0xc63e,0xc63f,
+ 0xc640,0xc641,0xc642,0xc643,0xc644,0xc645,0xc646,0xc647,
+ 0xc648,0xc649,0xc64a,0xc64b,0xc64c,0xc64d,0xc64e,0xc64f,
+ 0xc650,0xc651,0xc652,0xc653,0xc654,0xc655,0xc656,0xc657,
+ 0xc658,0xc659,0xc65a,0xc65b,0xc65c,0xc65d,0xc65e,0xc65f,
+ 0xc660,0xc661,0xc662,0xc663,0xc664,0xc665,0xc666,0xc667,
+ 0xc668,0xc669,0xc66a,0xc66b,0xc66c,0xc66d,0xc66e,0xc66f,
+ 0xc670,0xc671,0xc672,0xc673,0xc674,0xc675,0xc676,0xc677,
+ 0xc678,0xc679,0xc67a,0xc67b,0xc67c,0xc67d,0xc67e,0xc67f,
+ 0xc680,0xc681,0xc682,0xc683,0xc684,0xc685,0xc686,0xc687,
+ 0xc688,0xc689,0xc68a,0xc68b,0xc68c,0xc68d,0xc68e,0xc68f,
+ 0xc690,0xc691,0xc692,0xc693,0xc694,0xc695,0xc696,0xc697,
+ 0xc698,0xc699,0xc69a,0xc69b,0xc69c,0xc69d,0xc69e,0xc69f,
+ 0xc6a0,0xc6a1,0xc6a2,0xc6a3,0xc6a4,0xc6a5,0xc6a6,0xc6a7,
+ 0xc6a8,0xc6a9,0xc6aa,0xc6ab,0xc6ac,0xc6ad,0xc6ae,0xc6af,
+ 0xc6b0,0xc6b1,0xc6b2,0xc6b3,0xc6b4,0xc6b5,0xc6b6,0xc6b7,
+ 0xc6b8,0xc6b9,0xc6ba,0xc6bb,0xc6bc,0xc6bd,0xc6be,0xc6bf,
+ 0xc6c0,0xc6c1,0xc6c2,0xc6c3,0xc6c4,0xc6c5,0xc6c6,0xc6c7,
+ 0xc6c8,0xc6c9,0xc6ca,0xc6cb,0xc6cc,0xc6cd,0xc6ce,0xc6cf,
+ 0xc6d0,0xc6d1,0xc6d2,0xc6d3,0xc6d4,0xc6d5,0xc6d6,0xc6d7,
+ 0xc6d8,0xc6d9,0xc6da,0xc6db,0xc6dc,0xc6dd,0xc6de,0xc6df,
+ 0xc6e0,0xc6e1,0xc6e2,0xc6e3,0xc6e4,0xc6e5,0xc6e6,0xc6e7,
+ 0xc6e8,0xc6e9,0xc6ea,0xc6eb,0xc6ec,0xc6ed,0xc6ee,0xc6ef,
+ 0xc6f0,0xc6f1,0xc6f2,0xc6f3,0xc6f4,0xc6f5,0xc6f6,0xc6f7,
+ 0xc6f8,0xc6f9,0xc6fa,0xc6fb,0xc6fc,0xc6fd,0xc6fe,0xc6ff,
+ 0xc700,0xc701,0xc702,0xc703,0xc704,0xc705,0xc706,0xc707,
+ 0xc708,0xc709,0xc70a,0xc70b,0xc70c,0xc70d,0xc70e,0xc70f,
+ 0xc710,0xc711,0xc712,0xc713,0xc714,0xc715,0xc716,0xc717,
+ 0xc718,0xc719,0xc71a,0xc71b,0xc71c,0xc71d,0xc71e,0xc71f,
+ 0xc720,0xc721,0xc722,0xc723,0xc724,0xc725,0xc726,0xc727,
+ 0xc728,0xc729,0xc72a,0xc72b,0xc72c,0xc72d,0xc72e,0xc72f,
+ 0xc730,0xc731,0xc732,0xc733,0xc734,0xc735,0xc736,0xc737,
+ 0xc738,0xc739,0xc73a,0xc73b,0xc73c,0xc73d,0xc73e,0xc73f,
+ 0xc740,0xc741,0xc742,0xc743,0xc744,0xc745,0xc746,0xc747,
+ 0xc748,0xc749,0xc74a,0xc74b,0xc74c,0xc74d,0xc74e,0xc74f,
+ 0xc750,0xc751,0xc752,0xc753,0xc754,0xc755,0xc756,0xc757,
+ 0xc758,0xc759,0xc75a,0xc75b,0xc75c,0xc75d,0xc75e,0xc75f,
+ 0xc760,0xc761,0xc762,0xc763,0xc764,0xc765,0xc766,0xc767,
+ 0xc768,0xc769,0xc76a,0xc76b,0xc76c,0xc76d,0xc76e,0xc76f,
+ 0xc770,0xc771,0xc772,0xc773,0xc774,0xc775,0xc776,0xc777,
+ 0xc778,0xc779,0xc77a,0xc77b,0xc77c,0xc77d,0xc77e,0xc77f,
+ 0xc780,0xc781,0xc782,0xc783,0xc784,0xc785,0xc786,0xc787,
+ 0xc788,0xc789,0xc78a,0xc78b,0xc78c,0xc78d,0xc78e,0xc78f,
+ 0xc790,0xc791,0xc792,0xc793,0xc794,0xc795,0xc796,0xc797,
+ 0xc798,0xc799,0xc79a,0xc79b,0xc79c,0xc79d,0xc79e,0xc79f,
+ 0xc7a0,0xc7a1,0xc7a2,0xc7a3,0xc7a4,0xc7a5,0xc7a6,0xc7a7,
+ 0xc7a8,0xc7a9,0xc7aa,0xc7ab,0xc7ac,0xc7ad,0xc7ae,0xc7af,
+ 0xc7b0,0xc7b1,0xc7b2,0xc7b3,0xc7b4,0xc7b5,0xc7b6,0xc7b7,
+ 0xc7b8,0xc7b9,0xc7ba,0xc7bb,0xc7bc,0xc7bd,0xc7be,0xc7bf,
+ 0xc7c0,0xc7c1,0xc7c2,0xc7c3,0xc7c4,0xc7c5,0xc7c6,0xc7c7,
+ 0xc7c8,0xc7c9,0xc7ca,0xc7cb,0xc7cc,0xc7cd,0xc7ce,0xc7cf,
+ 0xc7d0,0xc7d1,0xc7d2,0xc7d3,0xc7d4,0xc7d5,0xc7d6,0xc7d7,
+ 0xc7d8,0xc7d9,0xc7da,0xc7db,0xc7dc,0xc7dd,0xc7de,0xc7df,
+ 0xc7e0,0xc7e1,0xc7e2,0xc7e3,0xc7e4,0xc7e5,0xc7e6,0xc7e7,
+ 0xc7e8,0xc7e9,0xc7ea,0xc7eb,0xc7ec,0xc7ed,0xc7ee,0xc7ef,
+ 0xc7f0,0xc7f1,0xc7f2,0xc7f3,0xc7f4,0xc7f5,0xc7f6,0xc7f7,
+ 0xc7f8,0xc7f9,0xc7fa,0xc7fb,0xc7fc,0xc7fd,0xc7fe,0xc7ff,
+ 0xc800,0xc801,0xc802,0xc803,0xc804,0xc805,0xc806,0xc807,
+ 0xc808,0xc809,0xc80a,0xc80b,0xc80c,0xc80d,0xc80e,0xc80f,
+ 0xc810,0xc811,0xc812,0xc813,0xc814,0xc815,0xc816,0xc817,
+ 0xc818,0xc819,0xc81a,0xc81b,0xc81c,0xc81d,0xc81e,0xc81f,
+ 0xc820,0xc821,0xc822,0xc823,0xc824,0xc825,0xc826,0xc827,
+ 0xc828,0xc829,0xc82a,0xc82b,0xc82c,0xc82d,0xc82e,0xc82f,
+ 0xc830,0xc831,0xc832,0xc833,0xc834,0xc835,0xc836,0xc837,
+ 0xc838,0xc839,0xc83a,0xc83b,0xc83c,0xc83d,0xc83e,0xc83f,
+ 0xc840,0xc841,0xc842,0xc843,0xc844,0xc845,0xc846,0xc847,
+ 0xc848,0xc849,0xc84a,0xc84b,0xc84c,0xc84d,0xc84e,0xc84f,
+ 0xc850,0xc851,0xc852,0xc853,0xc854,0xc855,0xc856,0xc857,
+ 0xc858,0xc859,0xc85a,0xc85b,0xc85c,0xc85d,0xc85e,0xc85f,
+ 0xc860,0xc861,0xc862,0xc863,0xc864,0xc865,0xc866,0xc867,
+ 0xc868,0xc869,0xc86a,0xc86b,0xc86c,0xc86d,0xc86e,0xc86f,
+ 0xc870,0xc871,0xc872,0xc873,0xc874,0xc875,0xc876,0xc877,
+ 0xc878,0xc879,0xc87a,0xc87b,0xc87c,0xc87d,0xc87e,0xc87f,
+ 0xc880,0xc881,0xc882,0xc883,0xc884,0xc885,0xc886,0xc887,
+ 0xc888,0xc889,0xc88a,0xc88b,0xc88c,0xc88d,0xc88e,0xc88f,
+ 0xc890,0xc891,0xc892,0xc893,0xc894,0xc895,0xc896,0xc897,
+ 0xc898,0xc899,0xc89a,0xc89b,0xc89c,0xc89d,0xc89e,0xc89f,
+ 0xc8a0,0xc8a1,0xc8a2,0xc8a3,0xc8a4,0xc8a5,0xc8a6,0xc8a7,
+ 0xc8a8,0xc8a9,0xc8aa,0xc8ab,0xc8ac,0xc8ad,0xc8ae,0xc8af,
+ 0xc8b0,0xc8b1,0xc8b2,0xc8b3,0xc8b4,0xc8b5,0xc8b6,0xc8b7,
+ 0xc8b8,0xc8b9,0xc8ba,0xc8bb,0xc8bc,0xc8bd,0xc8be,0xc8bf,
+ 0xc8c0,0xc8c1,0xc8c2,0xc8c3,0xc8c4,0xc8c5,0xc8c6,0xc8c7,
+ 0xc8c8,0xc8c9,0xc8ca,0xc8cb,0xc8cc,0xc8cd,0xc8ce,0xc8cf,
+ 0xc8d0,0xc8d1,0xc8d2,0xc8d3,0xc8d4,0xc8d5,0xc8d6,0xc8d7,
+ 0xc8d8,0xc8d9,0xc8da,0xc8db,0xc8dc,0xc8dd,0xc8de,0xc8df,
+ 0xc8e0,0xc8e1,0xc8e2,0xc8e3,0xc8e4,0xc8e5,0xc8e6,0xc8e7,
+ 0xc8e8,0xc8e9,0xc8ea,0xc8eb,0xc8ec,0xc8ed,0xc8ee,0xc8ef,
+ 0xc8f0,0xc8f1,0xc8f2,0xc8f3,0xc8f4,0xc8f5,0xc8f6,0xc8f7,
+ 0xc8f8,0xc8f9,0xc8fa,0xc8fb,0xc8fc,0xc8fd,0xc8fe,0xc8ff,
+ 0xc900,0xc901,0xc902,0xc903,0xc904,0xc905,0xc906,0xc907,
+ 0xc908,0xc909,0xc90a,0xc90b,0xc90c,0xc90d,0xc90e,0xc90f,
+ 0xc910,0xc911,0xc912,0xc913,0xc914,0xc915,0xc916,0xc917,
+ 0xc918,0xc919,0xc91a,0xc91b,0xc91c,0xc91d,0xc91e,0xc91f,
+ 0xc920,0xc921,0xc922,0xc923,0xc924,0xc925,0xc926,0xc927,
+ 0xc928,0xc929,0xc92a,0xc92b,0xc92c,0xc92d,0xc92e,0xc92f,
+ 0xc930,0xc931,0xc932,0xc933,0xc934,0xc935,0xc936,0xc937,
+ 0xc938,0xc939,0xc93a,0xc93b,0xc93c,0xc93d,0xc93e,0xc93f,
+ 0xc940,0xc941,0xc942,0xc943,0xc944,0xc945,0xc946,0xc947,
+ 0xc948,0xc949,0xc94a,0xc94b,0xc94c,0xc94d,0xc94e,0xc94f,
+ 0xc950,0xc951,0xc952,0xc953,0xc954,0xc955,0xc956,0xc957,
+ 0xc958,0xc959,0xc95a,0xc95b,0xc95c,0xc95d,0xc95e,0xc95f,
+ 0xc960,0xc961,0xc962,0xc963,0xc964,0xc965,0xc966,0xc967,
+ 0xc968,0xc969,0xc96a,0xc96b,0xc96c,0xc96d,0xc96e,0xc96f,
+ 0xc970,0xc971,0xc972,0xc973,0xc974,0xc975,0xc976,0xc977,
+ 0xc978,0xc979,0xc97a,0xc97b,0xc97c,0xc97d,0xc97e,0xc97f,
+ 0xc980,0xc981,0xc982,0xc983,0xc984,0xc985,0xc986,0xc987,
+ 0xc988,0xc989,0xc98a,0xc98b,0xc98c,0xc98d,0xc98e,0xc98f,
+ 0xc990,0xc991,0xc992,0xc993,0xc994,0xc995,0xc996,0xc997,
+ 0xc998,0xc999,0xc99a,0xc99b,0xc99c,0xc99d,0xc99e,0xc99f,
+ 0xc9a0,0xc9a1,0xc9a2,0xc9a3,0xc9a4,0xc9a5,0xc9a6,0xc9a7,
+ 0xc9a8,0xc9a9,0xc9aa,0xc9ab,0xc9ac,0xc9ad,0xc9ae,0xc9af,
+ 0xc9b0,0xc9b1,0xc9b2,0xc9b3,0xc9b4,0xc9b5,0xc9b6,0xc9b7,
+ 0xc9b8,0xc9b9,0xc9ba,0xc9bb,0xc9bc,0xc9bd,0xc9be,0xc9bf,
+ 0xc9c0,0xc9c1,0xc9c2,0xc9c3,0xc9c4,0xc9c5,0xc9c6,0xc9c7,
+ 0xc9c8,0xc9c9,0xc9ca,0xc9cb,0xc9cc,0xc9cd,0xc9ce,0xc9cf,
+ 0xc9d0,0xc9d1,0xc9d2,0xc9d3,0xc9d4,0xc9d5,0xc9d6,0xc9d7,
+ 0xc9d8,0xc9d9,0xc9da,0xc9db,0xc9dc,0xc9dd,0xc9de,0xc9df,
+ 0xc9e0,0xc9e1,0xc9e2,0xc9e3,0xc9e4,0xc9e5,0xc9e6,0xc9e7,
+ 0xc9e8,0xc9e9,0xc9ea,0xc9eb,0xc9ec,0xc9ed,0xc9ee,0xc9ef,
+ 0xc9f0,0xc9f1,0xc9f2,0xc9f3,0xc9f4,0xc9f5,0xc9f6,0xc9f7,
+ 0xc9f8,0xc9f9,0xc9fa,0xc9fb,0xc9fc,0xc9fd,0xc9fe,0xc9ff,
+ 0xca00,0xca01,0xca02,0xca03,0xca04,0xca05,0xca06,0xca07,
+ 0xca08,0xca09,0xca0a,0xca0b,0xca0c,0xca0d,0xca0e,0xca0f,
+ 0xca10,0xca11,0xca12,0xca13,0xca14,0xca15,0xca16,0xca17,
+ 0xca18,0xca19,0xca1a,0xca1b,0xca1c,0xca1d,0xca1e,0xca1f,
+ 0xca20,0xca21,0xca22,0xca23,0xca24,0xca25,0xca26,0xca27,
+ 0xca28,0xca29,0xca2a,0xca2b,0xca2c,0xca2d,0xca2e,0xca2f,
+ 0xca30,0xca31,0xca32,0xca33,0xca34,0xca35,0xca36,0xca37,
+ 0xca38,0xca39,0xca3a,0xca3b,0xca3c,0xca3d,0xca3e,0xca3f,
+ 0xca40,0xca41,0xca42,0xca43,0xca44,0xca45,0xca46,0xca47,
+ 0xca48,0xca49,0xca4a,0xca4b,0xca4c,0xca4d,0xca4e,0xca4f,
+ 0xca50,0xca51,0xca52,0xca53,0xca54,0xca55,0xca56,0xca57,
+ 0xca58,0xca59,0xca5a,0xca5b,0xca5c,0xca5d,0xca5e,0xca5f,
+ 0xca60,0xca61,0xca62,0xca63,0xca64,0xca65,0xca66,0xca67,
+ 0xca68,0xca69,0xca6a,0xca6b,0xca6c,0xca6d,0xca6e,0xca6f,
+ 0xca70,0xca71,0xca72,0xca73,0xca74,0xca75,0xca76,0xca77,
+ 0xca78,0xca79,0xca7a,0xca7b,0xca7c,0xca7d,0xca7e,0xca7f,
+ 0xca80,0xca81,0xca82,0xca83,0xca84,0xca85,0xca86,0xca87,
+ 0xca88,0xca89,0xca8a,0xca8b,0xca8c,0xca8d,0xca8e,0xca8f,
+ 0xca90,0xca91,0xca92,0xca93,0xca94,0xca95,0xca96,0xca97,
+ 0xca98,0xca99,0xca9a,0xca9b,0xca9c,0xca9d,0xca9e,0xca9f,
+ 0xcaa0,0xcaa1,0xcaa2,0xcaa3,0xcaa4,0xcaa5,0xcaa6,0xcaa7,
+ 0xcaa8,0xcaa9,0xcaaa,0xcaab,0xcaac,0xcaad,0xcaae,0xcaaf,
+ 0xcab0,0xcab1,0xcab2,0xcab3,0xcab4,0xcab5,0xcab6,0xcab7,
+ 0xcab8,0xcab9,0xcaba,0xcabb,0xcabc,0xcabd,0xcabe,0xcabf,
+ 0xcac0,0xcac1,0xcac2,0xcac3,0xcac4,0xcac5,0xcac6,0xcac7,
+ 0xcac8,0xcac9,0xcaca,0xcacb,0xcacc,0xcacd,0xcace,0xcacf,
+ 0xcad0,0xcad1,0xcad2,0xcad3,0xcad4,0xcad5,0xcad6,0xcad7,
+ 0xcad8,0xcad9,0xcada,0xcadb,0xcadc,0xcadd,0xcade,0xcadf,
+ 0xcae0,0xcae1,0xcae2,0xcae3,0xcae4,0xcae5,0xcae6,0xcae7,
+ 0xcae8,0xcae9,0xcaea,0xcaeb,0xcaec,0xcaed,0xcaee,0xcaef,
+ 0xcaf0,0xcaf1,0xcaf2,0xcaf3,0xcaf4,0xcaf5,0xcaf6,0xcaf7,
+ 0xcaf8,0xcaf9,0xcafa,0xcafb,0xcafc,0xcafd,0xcafe,0xcaff,
+ 0xcb00,0xcb01,0xcb02,0xcb03,0xcb04,0xcb05,0xcb06,0xcb07,
+ 0xcb08,0xcb09,0xcb0a,0xcb0b,0xcb0c,0xcb0d,0xcb0e,0xcb0f,
+ 0xcb10,0xcb11,0xcb12,0xcb13,0xcb14,0xcb15,0xcb16,0xcb17,
+ 0xcb18,0xcb19,0xcb1a,0xcb1b,0xcb1c,0xcb1d,0xcb1e,0xcb1f,
+ 0xcb20,0xcb21,0xcb22,0xcb23,0xcb24,0xcb25,0xcb26,0xcb27,
+ 0xcb28,0xcb29,0xcb2a,0xcb2b,0xcb2c,0xcb2d,0xcb2e,0xcb2f,
+ 0xcb30,0xcb31,0xcb32,0xcb33,0xcb34,0xcb35,0xcb36,0xcb37,
+ 0xcb38,0xcb39,0xcb3a,0xcb3b,0xcb3c,0xcb3d,0xcb3e,0xcb3f,
+ 0xcb40,0xcb41,0xcb42,0xcb43,0xcb44,0xcb45,0xcb46,0xcb47,
+ 0xcb48,0xcb49,0xcb4a,0xcb4b,0xcb4c,0xcb4d,0xcb4e,0xcb4f,
+ 0xcb50,0xcb51,0xcb52,0xcb53,0xcb54,0xcb55,0xcb56,0xcb57,
+ 0xcb58,0xcb59,0xcb5a,0xcb5b,0xcb5c,0xcb5d,0xcb5e,0xcb5f,
+ 0xcb60,0xcb61,0xcb62,0xcb63,0xcb64,0xcb65,0xcb66,0xcb67,
+ 0xcb68,0xcb69,0xcb6a,0xcb6b,0xcb6c,0xcb6d,0xcb6e,0xcb6f,
+ 0xcb70,0xcb71,0xcb72,0xcb73,0xcb74,0xcb75,0xcb76,0xcb77,
+ 0xcb78,0xcb79,0xcb7a,0xcb7b,0xcb7c,0xcb7d,0xcb7e,0xcb7f,
+ 0xcb80,0xcb81,0xcb82,0xcb83,0xcb84,0xcb85,0xcb86,0xcb87,
+ 0xcb88,0xcb89,0xcb8a,0xcb8b,0xcb8c,0xcb8d,0xcb8e,0xcb8f,
+ 0xcb90,0xcb91,0xcb92,0xcb93,0xcb94,0xcb95,0xcb96,0xcb97,
+ 0xcb98,0xcb99,0xcb9a,0xcb9b,0xcb9c,0xcb9d,0xcb9e,0xcb9f,
+ 0xcba0,0xcba1,0xcba2,0xcba3,0xcba4,0xcba5,0xcba6,0xcba7,
+ 0xcba8,0xcba9,0xcbaa,0xcbab,0xcbac,0xcbad,0xcbae,0xcbaf,
+ 0xcbb0,0xcbb1,0xcbb2,0xcbb3,0xcbb4,0xcbb5,0xcbb6,0xcbb7,
+ 0xcbb8,0xcbb9,0xcbba,0xcbbb,0xcbbc,0xcbbd,0xcbbe,0xcbbf,
+ 0xcbc0,0xcbc1,0xcbc2,0xcbc3,0xcbc4,0xcbc5,0xcbc6,0xcbc7,
+ 0xcbc8,0xcbc9,0xcbca,0xcbcb,0xcbcc,0xcbcd,0xcbce,0xcbcf,
+ 0xcbd0,0xcbd1,0xcbd2,0xcbd3,0xcbd4,0xcbd5,0xcbd6,0xcbd7,
+ 0xcbd8,0xcbd9,0xcbda,0xcbdb,0xcbdc,0xcbdd,0xcbde,0xcbdf,
+ 0xcbe0,0xcbe1,0xcbe2,0xcbe3,0xcbe4,0xcbe5,0xcbe6,0xcbe7,
+ 0xcbe8,0xcbe9,0xcbea,0xcbeb,0xcbec,0xcbed,0xcbee,0xcbef,
+ 0xcbf0,0xcbf1,0xcbf2,0xcbf3,0xcbf4,0xcbf5,0xcbf6,0xcbf7,
+ 0xcbf8,0xcbf9,0xcbfa,0xcbfb,0xcbfc,0xcbfd,0xcbfe,0xcbff,
+ 0xcc00,0xcc01,0xcc02,0xcc03,0xcc04,0xcc05,0xcc06,0xcc07,
+ 0xcc08,0xcc09,0xcc0a,0xcc0b,0xcc0c,0xcc0d,0xcc0e,0xcc0f,
+ 0xcc10,0xcc11,0xcc12,0xcc13,0xcc14,0xcc15,0xcc16,0xcc17,
+ 0xcc18,0xcc19,0xcc1a,0xcc1b,0xcc1c,0xcc1d,0xcc1e,0xcc1f,
+ 0xcc20,0xcc21,0xcc22,0xcc23,0xcc24,0xcc25,0xcc26,0xcc27,
+ 0xcc28,0xcc29,0xcc2a,0xcc2b,0xcc2c,0xcc2d,0xcc2e,0xcc2f,
+ 0xcc30,0xcc31,0xcc32,0xcc33,0xcc34,0xcc35,0xcc36,0xcc37,
+ 0xcc38,0xcc39,0xcc3a,0xcc3b,0xcc3c,0xcc3d,0xcc3e,0xcc3f,
+ 0xcc40,0xcc41,0xcc42,0xcc43,0xcc44,0xcc45,0xcc46,0xcc47,
+ 0xcc48,0xcc49,0xcc4a,0xcc4b,0xcc4c,0xcc4d,0xcc4e,0xcc4f,
+ 0xcc50,0xcc51,0xcc52,0xcc53,0xcc54,0xcc55,0xcc56,0xcc57,
+ 0xcc58,0xcc59,0xcc5a,0xcc5b,0xcc5c,0xcc5d,0xcc5e,0xcc5f,
+ 0xcc60,0xcc61,0xcc62,0xcc63,0xcc64,0xcc65,0xcc66,0xcc67,
+ 0xcc68,0xcc69,0xcc6a,0xcc6b,0xcc6c,0xcc6d,0xcc6e,0xcc6f,
+ 0xcc70,0xcc71,0xcc72,0xcc73,0xcc74,0xcc75,0xcc76,0xcc77,
+ 0xcc78,0xcc79,0xcc7a,0xcc7b,0xcc7c,0xcc7d,0xcc7e,0xcc7f,
+ 0xcc80,0xcc81,0xcc82,0xcc83,0xcc84,0xcc85,0xcc86,0xcc87,
+ 0xcc88,0xcc89,0xcc8a,0xcc8b,0xcc8c,0xcc8d,0xcc8e,0xcc8f,
+ 0xcc90,0xcc91,0xcc92,0xcc93,0xcc94,0xcc95,0xcc96,0xcc97,
+ 0xcc98,0xcc99,0xcc9a,0xcc9b,0xcc9c,0xcc9d,0xcc9e,0xcc9f,
+ 0xcca0,0xcca1,0xcca2,0xcca3,0xcca4,0xcca5,0xcca6,0xcca7,
+ 0xcca8,0xcca9,0xccaa,0xccab,0xccac,0xccad,0xccae,0xccaf,
+ 0xccb0,0xccb1,0xccb2,0xccb3,0xccb4,0xccb5,0xccb6,0xccb7,
+ 0xccb8,0xccb9,0xccba,0xccbb,0xccbc,0xccbd,0xccbe,0xccbf,
+ 0xccc0,0xccc1,0xccc2,0xccc3,0xccc4,0xccc5,0xccc6,0xccc7,
+ 0xccc8,0xccc9,0xccca,0xcccb,0xcccc,0xcccd,0xccce,0xcccf,
+ 0xccd0,0xccd1,0xccd2,0xccd3,0xccd4,0xccd5,0xccd6,0xccd7,
+ 0xccd8,0xccd9,0xccda,0xccdb,0xccdc,0xccdd,0xccde,0xccdf,
+ 0xcce0,0xcce1,0xcce2,0xcce3,0xcce4,0xcce5,0xcce6,0xcce7,
+ 0xcce8,0xcce9,0xccea,0xcceb,0xccec,0xcced,0xccee,0xccef,
+ 0xccf0,0xccf1,0xccf2,0xccf3,0xccf4,0xccf5,0xccf6,0xccf7,
+ 0xccf8,0xccf9,0xccfa,0xccfb,0xccfc,0xccfd,0xccfe,0xccff,
+ 0xcd00,0xcd01,0xcd02,0xcd03,0xcd04,0xcd05,0xcd06,0xcd07,
+ 0xcd08,0xcd09,0xcd0a,0xcd0b,0xcd0c,0xcd0d,0xcd0e,0xcd0f,
+ 0xcd10,0xcd11,0xcd12,0xcd13,0xcd14,0xcd15,0xcd16,0xcd17,
+ 0xcd18,0xcd19,0xcd1a,0xcd1b,0xcd1c,0xcd1d,0xcd1e,0xcd1f,
+ 0xcd20,0xcd21,0xcd22,0xcd23,0xcd24,0xcd25,0xcd26,0xcd27,
+ 0xcd28,0xcd29,0xcd2a,0xcd2b,0xcd2c,0xcd2d,0xcd2e,0xcd2f,
+ 0xcd30,0xcd31,0xcd32,0xcd33,0xcd34,0xcd35,0xcd36,0xcd37,
+ 0xcd38,0xcd39,0xcd3a,0xcd3b,0xcd3c,0xcd3d,0xcd3e,0xcd3f,
+ 0xcd40,0xcd41,0xcd42,0xcd43,0xcd44,0xcd45,0xcd46,0xcd47,
+ 0xcd48,0xcd49,0xcd4a,0xcd4b,0xcd4c,0xcd4d,0xcd4e,0xcd4f,
+ 0xcd50,0xcd51,0xcd52,0xcd53,0xcd54,0xcd55,0xcd56,0xcd57,
+ 0xcd58,0xcd59,0xcd5a,0xcd5b,0xcd5c,0xcd5d,0xcd5e,0xcd5f,
+ 0xcd60,0xcd61,0xcd62,0xcd63,0xcd64,0xcd65,0xcd66,0xcd67,
+ 0xcd68,0xcd69,0xcd6a,0xcd6b,0xcd6c,0xcd6d,0xcd6e,0xcd6f,
+ 0xcd70,0xcd71,0xcd72,0xcd73,0xcd74,0xcd75,0xcd76,0xcd77,
+ 0xcd78,0xcd79,0xcd7a,0xcd7b,0xcd7c,0xcd7d,0xcd7e,0xcd7f,
+ 0xcd80,0xcd81,0xcd82,0xcd83,0xcd84,0xcd85,0xcd86,0xcd87,
+ 0xcd88,0xcd89,0xcd8a,0xcd8b,0xcd8c,0xcd8d,0xcd8e,0xcd8f,
+ 0xcd90,0xcd91,0xcd92,0xcd93,0xcd94,0xcd95,0xcd96,0xcd97,
+ 0xcd98,0xcd99,0xcd9a,0xcd9b,0xcd9c,0xcd9d,0xcd9e,0xcd9f,
+ 0xcda0,0xcda1,0xcda2,0xcda3,0xcda4,0xcda5,0xcda6,0xcda7,
+ 0xcda8,0xcda9,0xcdaa,0xcdab,0xcdac,0xcdad,0xcdae,0xcdaf,
+ 0xcdb0,0xcdb1,0xcdb2,0xcdb3,0xcdb4,0xcdb5,0xcdb6,0xcdb7,
+ 0xcdb8,0xcdb9,0xcdba,0xcdbb,0xcdbc,0xcdbd,0xcdbe,0xcdbf,
+ 0xcdc0,0xcdc1,0xcdc2,0xcdc3,0xcdc4,0xcdc5,0xcdc6,0xcdc7,
+ 0xcdc8,0xcdc9,0xcdca,0xcdcb,0xcdcc,0xcdcd,0xcdce,0xcdcf,
+ 0xcdd0,0xcdd1,0xcdd2,0xcdd3,0xcdd4,0xcdd5,0xcdd6,0xcdd7,
+ 0xcdd8,0xcdd9,0xcdda,0xcddb,0xcddc,0xcddd,0xcdde,0xcddf,
+ 0xcde0,0xcde1,0xcde2,0xcde3,0xcde4,0xcde5,0xcde6,0xcde7,
+ 0xcde8,0xcde9,0xcdea,0xcdeb,0xcdec,0xcded,0xcdee,0xcdef,
+ 0xcdf0,0xcdf1,0xcdf2,0xcdf3,0xcdf4,0xcdf5,0xcdf6,0xcdf7,
+ 0xcdf8,0xcdf9,0xcdfa,0xcdfb,0xcdfc,0xcdfd,0xcdfe,0xcdff,
+ 0xce00,0xce01,0xce02,0xce03,0xce04,0xce05,0xce06,0xce07,
+ 0xce08,0xce09,0xce0a,0xce0b,0xce0c,0xce0d,0xce0e,0xce0f,
+ 0xce10,0xce11,0xce12,0xce13,0xce14,0xce15,0xce16,0xce17,
+ 0xce18,0xce19,0xce1a,0xce1b,0xce1c,0xce1d,0xce1e,0xce1f,
+ 0xce20,0xce21,0xce22,0xce23,0xce24,0xce25,0xce26,0xce27,
+ 0xce28,0xce29,0xce2a,0xce2b,0xce2c,0xce2d,0xce2e,0xce2f,
+ 0xce30,0xce31,0xce32,0xce33,0xce34,0xce35,0xce36,0xce37,
+ 0xce38,0xce39,0xce3a,0xce3b,0xce3c,0xce3d,0xce3e,0xce3f,
+ 0xce40,0xce41,0xce42,0xce43,0xce44,0xce45,0xce46,0xce47,
+ 0xce48,0xce49,0xce4a,0xce4b,0xce4c,0xce4d,0xce4e,0xce4f,
+ 0xce50,0xce51,0xce52,0xce53,0xce54,0xce55,0xce56,0xce57,
+ 0xce58,0xce59,0xce5a,0xce5b,0xce5c,0xce5d,0xce5e,0xce5f,
+ 0xce60,0xce61,0xce62,0xce63,0xce64,0xce65,0xce66,0xce67,
+ 0xce68,0xce69,0xce6a,0xce6b,0xce6c,0xce6d,0xce6e,0xce6f,
+ 0xce70,0xce71,0xce72,0xce73,0xce74,0xce75,0xce76,0xce77,
+ 0xce78,0xce79,0xce7a,0xce7b,0xce7c,0xce7d,0xce7e,0xce7f,
+ 0xce80,0xce81,0xce82,0xce83,0xce84,0xce85,0xce86,0xce87,
+ 0xce88,0xce89,0xce8a,0xce8b,0xce8c,0xce8d,0xce8e,0xce8f,
+ 0xce90,0xce91,0xce92,0xce93,0xce94,0xce95,0xce96,0xce97,
+ 0xce98,0xce99,0xce9a,0xce9b,0xce9c,0xce9d,0xce9e,0xce9f,
+ 0xcea0,0xcea1,0xcea2,0xcea3,0xcea4,0xcea5,0xcea6,0xcea7,
+ 0xcea8,0xcea9,0xceaa,0xceab,0xceac,0xcead,0xceae,0xceaf,
+ 0xceb0,0xceb1,0xceb2,0xceb3,0xceb4,0xceb5,0xceb6,0xceb7,
+ 0xceb8,0xceb9,0xceba,0xcebb,0xcebc,0xcebd,0xcebe,0xcebf,
+ 0xcec0,0xcec1,0xcec2,0xcec3,0xcec4,0xcec5,0xcec6,0xcec7,
+ 0xcec8,0xcec9,0xceca,0xcecb,0xcecc,0xcecd,0xcece,0xcecf,
+ 0xced0,0xced1,0xced2,0xced3,0xced4,0xced5,0xced6,0xced7,
+ 0xced8,0xced9,0xceda,0xcedb,0xcedc,0xcedd,0xcede,0xcedf,
+ 0xcee0,0xcee1,0xcee2,0xcee3,0xcee4,0xcee5,0xcee6,0xcee7,
+ 0xcee8,0xcee9,0xceea,0xceeb,0xceec,0xceed,0xceee,0xceef,
+ 0xcef0,0xcef1,0xcef2,0xcef3,0xcef4,0xcef5,0xcef6,0xcef7,
+ 0xcef8,0xcef9,0xcefa,0xcefb,0xcefc,0xcefd,0xcefe,0xceff,
+ 0xcf00,0xcf01,0xcf02,0xcf03,0xcf04,0xcf05,0xcf06,0xcf07,
+ 0xcf08,0xcf09,0xcf0a,0xcf0b,0xcf0c,0xcf0d,0xcf0e,0xcf0f,
+ 0xcf10,0xcf11,0xcf12,0xcf13,0xcf14,0xcf15,0xcf16,0xcf17,
+ 0xcf18,0xcf19,0xcf1a,0xcf1b,0xcf1c,0xcf1d,0xcf1e,0xcf1f,
+ 0xcf20,0xcf21,0xcf22,0xcf23,0xcf24,0xcf25,0xcf26,0xcf27,
+ 0xcf28,0xcf29,0xcf2a,0xcf2b,0xcf2c,0xcf2d,0xcf2e,0xcf2f,
+ 0xcf30,0xcf31,0xcf32,0xcf33,0xcf34,0xcf35,0xcf36,0xcf37,
+ 0xcf38,0xcf39,0xcf3a,0xcf3b,0xcf3c,0xcf3d,0xcf3e,0xcf3f,
+ 0xcf40,0xcf41,0xcf42,0xcf43,0xcf44,0xcf45,0xcf46,0xcf47,
+ 0xcf48,0xcf49,0xcf4a,0xcf4b,0xcf4c,0xcf4d,0xcf4e,0xcf4f,
+ 0xcf50,0xcf51,0xcf52,0xcf53,0xcf54,0xcf55,0xcf56,0xcf57,
+ 0xcf58,0xcf59,0xcf5a,0xcf5b,0xcf5c,0xcf5d,0xcf5e,0xcf5f,
+ 0xcf60,0xcf61,0xcf62,0xcf63,0xcf64,0xcf65,0xcf66,0xcf67,
+ 0xcf68,0xcf69,0xcf6a,0xcf6b,0xcf6c,0xcf6d,0xcf6e,0xcf6f,
+ 0xcf70,0xcf71,0xcf72,0xcf73,0xcf74,0xcf75,0xcf76,0xcf77,
+ 0xcf78,0xcf79,0xcf7a,0xcf7b,0xcf7c,0xcf7d,0xcf7e,0xcf7f,
+ 0xcf80,0xcf81,0xcf82,0xcf83,0xcf84,0xcf85,0xcf86,0xcf87,
+ 0xcf88,0xcf89,0xcf8a,0xcf8b,0xcf8c,0xcf8d,0xcf8e,0xcf8f,
+ 0xcf90,0xcf91,0xcf92,0xcf93,0xcf94,0xcf95,0xcf96,0xcf97,
+ 0xcf98,0xcf99,0xcf9a,0xcf9b,0xcf9c,0xcf9d,0xcf9e,0xcf9f,
+ 0xcfa0,0xcfa1,0xcfa2,0xcfa3,0xcfa4,0xcfa5,0xcfa6,0xcfa7,
+ 0xcfa8,0xcfa9,0xcfaa,0xcfab,0xcfac,0xcfad,0xcfae,0xcfaf,
+ 0xcfb0,0xcfb1,0xcfb2,0xcfb3,0xcfb4,0xcfb5,0xcfb6,0xcfb7,
+ 0xcfb8,0xcfb9,0xcfba,0xcfbb,0xcfbc,0xcfbd,0xcfbe,0xcfbf,
+ 0xcfc0,0xcfc1,0xcfc2,0xcfc3,0xcfc4,0xcfc5,0xcfc6,0xcfc7,
+ 0xcfc8,0xcfc9,0xcfca,0xcfcb,0xcfcc,0xcfcd,0xcfce,0xcfcf,
+ 0xcfd0,0xcfd1,0xcfd2,0xcfd3,0xcfd4,0xcfd5,0xcfd6,0xcfd7,
+ 0xcfd8,0xcfd9,0xcfda,0xcfdb,0xcfdc,0xcfdd,0xcfde,0xcfdf,
+ 0xcfe0,0xcfe1,0xcfe2,0xcfe3,0xcfe4,0xcfe5,0xcfe6,0xcfe7,
+ 0xcfe8,0xcfe9,0xcfea,0xcfeb,0xcfec,0xcfed,0xcfee,0xcfef,
+ 0xcff0,0xcff1,0xcff2,0xcff3,0xcff4,0xcff5,0xcff6,0xcff7,
+ 0xcff8,0xcff9,0xcffa,0xcffb,0xcffc,0xcffd,0xcffe,0xcfff,
+ 0xd000,0xd001,0xd002,0xd003,0xd004,0xd005,0xd006,0xd007,
+ 0xd008,0xd009,0xd00a,0xd00b,0xd00c,0xd00d,0xd00e,0xd00f,
+ 0xd010,0xd011,0xd012,0xd013,0xd014,0xd015,0xd016,0xd017,
+ 0xd018,0xd019,0xd01a,0xd01b,0xd01c,0xd01d,0xd01e,0xd01f,
+ 0xd020,0xd021,0xd022,0xd023,0xd024,0xd025,0xd026,0xd027,
+ 0xd028,0xd029,0xd02a,0xd02b,0xd02c,0xd02d,0xd02e,0xd02f,
+ 0xd030,0xd031,0xd032,0xd033,0xd034,0xd035,0xd036,0xd037,
+ 0xd038,0xd039,0xd03a,0xd03b,0xd03c,0xd03d,0xd03e,0xd03f,
+ 0xd040,0xd041,0xd042,0xd043,0xd044,0xd045,0xd046,0xd047,
+ 0xd048,0xd049,0xd04a,0xd04b,0xd04c,0xd04d,0xd04e,0xd04f,
+ 0xd050,0xd051,0xd052,0xd053,0xd054,0xd055,0xd056,0xd057,
+ 0xd058,0xd059,0xd05a,0xd05b,0xd05c,0xd05d,0xd05e,0xd05f,
+ 0xd060,0xd061,0xd062,0xd063,0xd064,0xd065,0xd066,0xd067,
+ 0xd068,0xd069,0xd06a,0xd06b,0xd06c,0xd06d,0xd06e,0xd06f,
+ 0xd070,0xd071,0xd072,0xd073,0xd074,0xd075,0xd076,0xd077,
+ 0xd078,0xd079,0xd07a,0xd07b,0xd07c,0xd07d,0xd07e,0xd07f,
+ 0xd080,0xd081,0xd082,0xd083,0xd084,0xd085,0xd086,0xd087,
+ 0xd088,0xd089,0xd08a,0xd08b,0xd08c,0xd08d,0xd08e,0xd08f,
+ 0xd090,0xd091,0xd092,0xd093,0xd094,0xd095,0xd096,0xd097,
+ 0xd098,0xd099,0xd09a,0xd09b,0xd09c,0xd09d,0xd09e,0xd09f,
+ 0xd0a0,0xd0a1,0xd0a2,0xd0a3,0xd0a4,0xd0a5,0xd0a6,0xd0a7,
+ 0xd0a8,0xd0a9,0xd0aa,0xd0ab,0xd0ac,0xd0ad,0xd0ae,0xd0af,
+ 0xd0b0,0xd0b1,0xd0b2,0xd0b3,0xd0b4,0xd0b5,0xd0b6,0xd0b7,
+ 0xd0b8,0xd0b9,0xd0ba,0xd0bb,0xd0bc,0xd0bd,0xd0be,0xd0bf,
+ 0xd0c0,0xd0c1,0xd0c2,0xd0c3,0xd0c4,0xd0c5,0xd0c6,0xd0c7,
+ 0xd0c8,0xd0c9,0xd0ca,0xd0cb,0xd0cc,0xd0cd,0xd0ce,0xd0cf,
+ 0xd0d0,0xd0d1,0xd0d2,0xd0d3,0xd0d4,0xd0d5,0xd0d6,0xd0d7,
+ 0xd0d8,0xd0d9,0xd0da,0xd0db,0xd0dc,0xd0dd,0xd0de,0xd0df,
+ 0xd0e0,0xd0e1,0xd0e2,0xd0e3,0xd0e4,0xd0e5,0xd0e6,0xd0e7,
+ 0xd0e8,0xd0e9,0xd0ea,0xd0eb,0xd0ec,0xd0ed,0xd0ee,0xd0ef,
+ 0xd0f0,0xd0f1,0xd0f2,0xd0f3,0xd0f4,0xd0f5,0xd0f6,0xd0f7,
+ 0xd0f8,0xd0f9,0xd0fa,0xd0fb,0xd0fc,0xd0fd,0xd0fe,0xd0ff,
+ 0xd100,0xd101,0xd102,0xd103,0xd104,0xd105,0xd106,0xd107,
+ 0xd108,0xd109,0xd10a,0xd10b,0xd10c,0xd10d,0xd10e,0xd10f,
+ 0xd110,0xd111,0xd112,0xd113,0xd114,0xd115,0xd116,0xd117,
+ 0xd118,0xd119,0xd11a,0xd11b,0xd11c,0xd11d,0xd11e,0xd11f,
+ 0xd120,0xd121,0xd122,0xd123,0xd124,0xd125,0xd126,0xd127,
+ 0xd128,0xd129,0xd12a,0xd12b,0xd12c,0xd12d,0xd12e,0xd12f,
+ 0xd130,0xd131,0xd132,0xd133,0xd134,0xd135,0xd136,0xd137,
+ 0xd138,0xd139,0xd13a,0xd13b,0xd13c,0xd13d,0xd13e,0xd13f,
+ 0xd140,0xd141,0xd142,0xd143,0xd144,0xd145,0xd146,0xd147,
+ 0xd148,0xd149,0xd14a,0xd14b,0xd14c,0xd14d,0xd14e,0xd14f,
+ 0xd150,0xd151,0xd152,0xd153,0xd154,0xd155,0xd156,0xd157,
+ 0xd158,0xd159,0xd15a,0xd15b,0xd15c,0xd15d,0xd15e,0xd15f,
+ 0xd160,0xd161,0xd162,0xd163,0xd164,0xd165,0xd166,0xd167,
+ 0xd168,0xd169,0xd16a,0xd16b,0xd16c,0xd16d,0xd16e,0xd16f,
+ 0xd170,0xd171,0xd172,0xd173,0xd174,0xd175,0xd176,0xd177,
+ 0xd178,0xd179,0xd17a,0xd17b,0xd17c,0xd17d,0xd17e,0xd17f,
+ 0xd180,0xd181,0xd182,0xd183,0xd184,0xd185,0xd186,0xd187,
+ 0xd188,0xd189,0xd18a,0xd18b,0xd18c,0xd18d,0xd18e,0xd18f,
+ 0xd190,0xd191,0xd192,0xd193,0xd194,0xd195,0xd196,0xd197,
+ 0xd198,0xd199,0xd19a,0xd19b,0xd19c,0xd19d,0xd19e,0xd19f,
+ 0xd1a0,0xd1a1,0xd1a2,0xd1a3,0xd1a4,0xd1a5,0xd1a6,0xd1a7,
+ 0xd1a8,0xd1a9,0xd1aa,0xd1ab,0xd1ac,0xd1ad,0xd1ae,0xd1af,
+ 0xd1b0,0xd1b1,0xd1b2,0xd1b3,0xd1b4,0xd1b5,0xd1b6,0xd1b7,
+ 0xd1b8,0xd1b9,0xd1ba,0xd1bb,0xd1bc,0xd1bd,0xd1be,0xd1bf,
+ 0xd1c0,0xd1c1,0xd1c2,0xd1c3,0xd1c4,0xd1c5,0xd1c6,0xd1c7,
+ 0xd1c8,0xd1c9,0xd1ca,0xd1cb,0xd1cc,0xd1cd,0xd1ce,0xd1cf,
+ 0xd1d0,0xd1d1,0xd1d2,0xd1d3,0xd1d4,0xd1d5,0xd1d6,0xd1d7,
+ 0xd1d8,0xd1d9,0xd1da,0xd1db,0xd1dc,0xd1dd,0xd1de,0xd1df,
+ 0xd1e0,0xd1e1,0xd1e2,0xd1e3,0xd1e4,0xd1e5,0xd1e6,0xd1e7,
+ 0xd1e8,0xd1e9,0xd1ea,0xd1eb,0xd1ec,0xd1ed,0xd1ee,0xd1ef,
+ 0xd1f0,0xd1f1,0xd1f2,0xd1f3,0xd1f4,0xd1f5,0xd1f6,0xd1f7,
+ 0xd1f8,0xd1f9,0xd1fa,0xd1fb,0xd1fc,0xd1fd,0xd1fe,0xd1ff,
+ 0xd200,0xd201,0xd202,0xd203,0xd204,0xd205,0xd206,0xd207,
+ 0xd208,0xd209,0xd20a,0xd20b,0xd20c,0xd20d,0xd20e,0xd20f,
+ 0xd210,0xd211,0xd212,0xd213,0xd214,0xd215,0xd216,0xd217,
+ 0xd218,0xd219,0xd21a,0xd21b,0xd21c,0xd21d,0xd21e,0xd21f,
+ 0xd220,0xd221,0xd222,0xd223,0xd224,0xd225,0xd226,0xd227,
+ 0xd228,0xd229,0xd22a,0xd22b,0xd22c,0xd22d,0xd22e,0xd22f,
+ 0xd230,0xd231,0xd232,0xd233,0xd234,0xd235,0xd236,0xd237,
+ 0xd238,0xd239,0xd23a,0xd23b,0xd23c,0xd23d,0xd23e,0xd23f,
+ 0xd240,0xd241,0xd242,0xd243,0xd244,0xd245,0xd246,0xd247,
+ 0xd248,0xd249,0xd24a,0xd24b,0xd24c,0xd24d,0xd24e,0xd24f,
+ 0xd250,0xd251,0xd252,0xd253,0xd254,0xd255,0xd256,0xd257,
+ 0xd258,0xd259,0xd25a,0xd25b,0xd25c,0xd25d,0xd25e,0xd25f,
+ 0xd260,0xd261,0xd262,0xd263,0xd264,0xd265,0xd266,0xd267,
+ 0xd268,0xd269,0xd26a,0xd26b,0xd26c,0xd26d,0xd26e,0xd26f,
+ 0xd270,0xd271,0xd272,0xd273,0xd274,0xd275,0xd276,0xd277,
+ 0xd278,0xd279,0xd27a,0xd27b,0xd27c,0xd27d,0xd27e,0xd27f,
+ 0xd280,0xd281,0xd282,0xd283,0xd284,0xd285,0xd286,0xd287,
+ 0xd288,0xd289,0xd28a,0xd28b,0xd28c,0xd28d,0xd28e,0xd28f,
+ 0xd290,0xd291,0xd292,0xd293,0xd294,0xd295,0xd296,0xd297,
+ 0xd298,0xd299,0xd29a,0xd29b,0xd29c,0xd29d,0xd29e,0xd29f,
+ 0xd2a0,0xd2a1,0xd2a2,0xd2a3,0xd2a4,0xd2a5,0xd2a6,0xd2a7,
+ 0xd2a8,0xd2a9,0xd2aa,0xd2ab,0xd2ac,0xd2ad,0xd2ae,0xd2af,
+ 0xd2b0,0xd2b1,0xd2b2,0xd2b3,0xd2b4,0xd2b5,0xd2b6,0xd2b7,
+ 0xd2b8,0xd2b9,0xd2ba,0xd2bb,0xd2bc,0xd2bd,0xd2be,0xd2bf,
+ 0xd2c0,0xd2c1,0xd2c2,0xd2c3,0xd2c4,0xd2c5,0xd2c6,0xd2c7,
+ 0xd2c8,0xd2c9,0xd2ca,0xd2cb,0xd2cc,0xd2cd,0xd2ce,0xd2cf,
+ 0xd2d0,0xd2d1,0xd2d2,0xd2d3,0xd2d4,0xd2d5,0xd2d6,0xd2d7,
+ 0xd2d8,0xd2d9,0xd2da,0xd2db,0xd2dc,0xd2dd,0xd2de,0xd2df,
+ 0xd2e0,0xd2e1,0xd2e2,0xd2e3,0xd2e4,0xd2e5,0xd2e6,0xd2e7,
+ 0xd2e8,0xd2e9,0xd2ea,0xd2eb,0xd2ec,0xd2ed,0xd2ee,0xd2ef,
+ 0xd2f0,0xd2f1,0xd2f2,0xd2f3,0xd2f4,0xd2f5,0xd2f6,0xd2f7,
+ 0xd2f8,0xd2f9,0xd2fa,0xd2fb,0xd2fc,0xd2fd,0xd2fe,0xd2ff,
+ 0xd300,0xd301,0xd302,0xd303,0xd304,0xd305,0xd306,0xd307,
+ 0xd308,0xd309,0xd30a,0xd30b,0xd30c,0xd30d,0xd30e,0xd30f,
+ 0xd310,0xd311,0xd312,0xd313,0xd314,0xd315,0xd316,0xd317,
+ 0xd318,0xd319,0xd31a,0xd31b,0xd31c,0xd31d,0xd31e,0xd31f,
+ 0xd320,0xd321,0xd322,0xd323,0xd324,0xd325,0xd326,0xd327,
+ 0xd328,0xd329,0xd32a,0xd32b,0xd32c,0xd32d,0xd32e,0xd32f,
+ 0xd330,0xd331,0xd332,0xd333,0xd334,0xd335,0xd336,0xd337,
+ 0xd338,0xd339,0xd33a,0xd33b,0xd33c,0xd33d,0xd33e,0xd33f,
+ 0xd340,0xd341,0xd342,0xd343,0xd344,0xd345,0xd346,0xd347,
+ 0xd348,0xd349,0xd34a,0xd34b,0xd34c,0xd34d,0xd34e,0xd34f,
+ 0xd350,0xd351,0xd352,0xd353,0xd354,0xd355,0xd356,0xd357,
+ 0xd358,0xd359,0xd35a,0xd35b,0xd35c,0xd35d,0xd35e,0xd35f,
+ 0xd360,0xd361,0xd362,0xd363,0xd364,0xd365,0xd366,0xd367,
+ 0xd368,0xd369,0xd36a,0xd36b,0xd36c,0xd36d,0xd36e,0xd36f,
+ 0xd370,0xd371,0xd372,0xd373,0xd374,0xd375,0xd376,0xd377,
+ 0xd378,0xd379,0xd37a,0xd37b,0xd37c,0xd37d,0xd37e,0xd37f,
+ 0xd380,0xd381,0xd382,0xd383,0xd384,0xd385,0xd386,0xd387,
+ 0xd388,0xd389,0xd38a,0xd38b,0xd38c,0xd38d,0xd38e,0xd38f,
+ 0xd390,0xd391,0xd392,0xd393,0xd394,0xd395,0xd396,0xd397,
+ 0xd398,0xd399,0xd39a,0xd39b,0xd39c,0xd39d,0xd39e,0xd39f,
+ 0xd3a0,0xd3a1,0xd3a2,0xd3a3,0xd3a4,0xd3a5,0xd3a6,0xd3a7,
+ 0xd3a8,0xd3a9,0xd3aa,0xd3ab,0xd3ac,0xd3ad,0xd3ae,0xd3af,
+ 0xd3b0,0xd3b1,0xd3b2,0xd3b3,0xd3b4,0xd3b5,0xd3b6,0xd3b7,
+ 0xd3b8,0xd3b9,0xd3ba,0xd3bb,0xd3bc,0xd3bd,0xd3be,0xd3bf,
+ 0xd3c0,0xd3c1,0xd3c2,0xd3c3,0xd3c4,0xd3c5,0xd3c6,0xd3c7,
+ 0xd3c8,0xd3c9,0xd3ca,0xd3cb,0xd3cc,0xd3cd,0xd3ce,0xd3cf,
+ 0xd3d0,0xd3d1,0xd3d2,0xd3d3,0xd3d4,0xd3d5,0xd3d6,0xd3d7,
+ 0xd3d8,0xd3d9,0xd3da,0xd3db,0xd3dc,0xd3dd,0xd3de,0xd3df,
+ 0xd3e0,0xd3e1,0xd3e2,0xd3e3,0xd3e4,0xd3e5,0xd3e6,0xd3e7,
+ 0xd3e8,0xd3e9,0xd3ea,0xd3eb,0xd3ec,0xd3ed,0xd3ee,0xd3ef,
+ 0xd3f0,0xd3f1,0xd3f2,0xd3f3,0xd3f4,0xd3f5,0xd3f6,0xd3f7,
+ 0xd3f8,0xd3f9,0xd3fa,0xd3fb,0xd3fc,0xd3fd,0xd3fe,0xd3ff,
+ 0xd400,0xd401,0xd402,0xd403,0xd404,0xd405,0xd406,0xd407,
+ 0xd408,0xd409,0xd40a,0xd40b,0xd40c,0xd40d,0xd40e,0xd40f,
+ 0xd410,0xd411,0xd412,0xd413,0xd414,0xd415,0xd416,0xd417,
+ 0xd418,0xd419,0xd41a,0xd41b,0xd41c,0xd41d,0xd41e,0xd41f,
+ 0xd420,0xd421,0xd422,0xd423,0xd424,0xd425,0xd426,0xd427,
+ 0xd428,0xd429,0xd42a,0xd42b,0xd42c,0xd42d,0xd42e,0xd42f,
+ 0xd430,0xd431,0xd432,0xd433,0xd434,0xd435,0xd436,0xd437,
+ 0xd438,0xd439,0xd43a,0xd43b,0xd43c,0xd43d,0xd43e,0xd43f,
+ 0xd440,0xd441,0xd442,0xd443,0xd444,0xd445,0xd446,0xd447,
+ 0xd448,0xd449,0xd44a,0xd44b,0xd44c,0xd44d,0xd44e,0xd44f,
+ 0xd450,0xd451,0xd452,0xd453,0xd454,0xd455,0xd456,0xd457,
+ 0xd458,0xd459,0xd45a,0xd45b,0xd45c,0xd45d,0xd45e,0xd45f,
+ 0xd460,0xd461,0xd462,0xd463,0xd464,0xd465,0xd466,0xd467,
+ 0xd468,0xd469,0xd46a,0xd46b,0xd46c,0xd46d,0xd46e,0xd46f,
+ 0xd470,0xd471,0xd472,0xd473,0xd474,0xd475,0xd476,0xd477,
+ 0xd478,0xd479,0xd47a,0xd47b,0xd47c,0xd47d,0xd47e,0xd47f,
+ 0xd480,0xd481,0xd482,0xd483,0xd484,0xd485,0xd486,0xd487,
+ 0xd488,0xd489,0xd48a,0xd48b,0xd48c,0xd48d,0xd48e,0xd48f,
+ 0xd490,0xd491,0xd492,0xd493,0xd494,0xd495,0xd496,0xd497,
+ 0xd498,0xd499,0xd49a,0xd49b,0xd49c,0xd49d,0xd49e,0xd49f,
+ 0xd4a0,0xd4a1,0xd4a2,0xd4a3,0xd4a4,0xd4a5,0xd4a6,0xd4a7,
+ 0xd4a8,0xd4a9,0xd4aa,0xd4ab,0xd4ac,0xd4ad,0xd4ae,0xd4af,
+ 0xd4b0,0xd4b1,0xd4b2,0xd4b3,0xd4b4,0xd4b5,0xd4b6,0xd4b7,
+ 0xd4b8,0xd4b9,0xd4ba,0xd4bb,0xd4bc,0xd4bd,0xd4be,0xd4bf,
+ 0xd4c0,0xd4c1,0xd4c2,0xd4c3,0xd4c4,0xd4c5,0xd4c6,0xd4c7,
+ 0xd4c8,0xd4c9,0xd4ca,0xd4cb,0xd4cc,0xd4cd,0xd4ce,0xd4cf,
+ 0xd4d0,0xd4d1,0xd4d2,0xd4d3,0xd4d4,0xd4d5,0xd4d6,0xd4d7,
+ 0xd4d8,0xd4d9,0xd4da,0xd4db,0xd4dc,0xd4dd,0xd4de,0xd4df,
+ 0xd4e0,0xd4e1,0xd4e2,0xd4e3,0xd4e4,0xd4e5,0xd4e6,0xd4e7,
+ 0xd4e8,0xd4e9,0xd4ea,0xd4eb,0xd4ec,0xd4ed,0xd4ee,0xd4ef,
+ 0xd4f0,0xd4f1,0xd4f2,0xd4f3,0xd4f4,0xd4f5,0xd4f6,0xd4f7,
+ 0xd4f8,0xd4f9,0xd4fa,0xd4fb,0xd4fc,0xd4fd,0xd4fe,0xd4ff,
+ 0xd500,0xd501,0xd502,0xd503,0xd504,0xd505,0xd506,0xd507,
+ 0xd508,0xd509,0xd50a,0xd50b,0xd50c,0xd50d,0xd50e,0xd50f,
+ 0xd510,0xd511,0xd512,0xd513,0xd514,0xd515,0xd516,0xd517,
+ 0xd518,0xd519,0xd51a,0xd51b,0xd51c,0xd51d,0xd51e,0xd51f,
+ 0xd520,0xd521,0xd522,0xd523,0xd524,0xd525,0xd526,0xd527,
+ 0xd528,0xd529,0xd52a,0xd52b,0xd52c,0xd52d,0xd52e,0xd52f,
+ 0xd530,0xd531,0xd532,0xd533,0xd534,0xd535,0xd536,0xd537,
+ 0xd538,0xd539,0xd53a,0xd53b,0xd53c,0xd53d,0xd53e,0xd53f,
+ 0xd540,0xd541,0xd542,0xd543,0xd544,0xd545,0xd546,0xd547,
+ 0xd548,0xd549,0xd54a,0xd54b,0xd54c,0xd54d,0xd54e,0xd54f,
+ 0xd550,0xd551,0xd552,0xd553,0xd554,0xd555,0xd556,0xd557,
+ 0xd558,0xd559,0xd55a,0xd55b,0xd55c,0xd55d,0xd55e,0xd55f,
+ 0xd560,0xd561,0xd562,0xd563,0xd564,0xd565,0xd566,0xd567,
+ 0xd568,0xd569,0xd56a,0xd56b,0xd56c,0xd56d,0xd56e,0xd56f,
+ 0xd570,0xd571,0xd572,0xd573,0xd574,0xd575,0xd576,0xd577,
+ 0xd578,0xd579,0xd57a,0xd57b,0xd57c,0xd57d,0xd57e,0xd57f,
+ 0xd580,0xd581,0xd582,0xd583,0xd584,0xd585,0xd586,0xd587,
+ 0xd588,0xd589,0xd58a,0xd58b,0xd58c,0xd58d,0xd58e,0xd58f,
+ 0xd590,0xd591,0xd592,0xd593,0xd594,0xd595,0xd596,0xd597,
+ 0xd598,0xd599,0xd59a,0xd59b,0xd59c,0xd59d,0xd59e,0xd59f,
+ 0xd5a0,0xd5a1,0xd5a2,0xd5a3,0xd5a4,0xd5a5,0xd5a6,0xd5a7,
+ 0xd5a8,0xd5a9,0xd5aa,0xd5ab,0xd5ac,0xd5ad,0xd5ae,0xd5af,
+ 0xd5b0,0xd5b1,0xd5b2,0xd5b3,0xd5b4,0xd5b5,0xd5b6,0xd5b7,
+ 0xd5b8,0xd5b9,0xd5ba,0xd5bb,0xd5bc,0xd5bd,0xd5be,0xd5bf,
+ 0xd5c0,0xd5c1,0xd5c2,0xd5c3,0xd5c4,0xd5c5,0xd5c6,0xd5c7,
+ 0xd5c8,0xd5c9,0xd5ca,0xd5cb,0xd5cc,0xd5cd,0xd5ce,0xd5cf,
+ 0xd5d0,0xd5d1,0xd5d2,0xd5d3,0xd5d4,0xd5d5,0xd5d6,0xd5d7,
+ 0xd5d8,0xd5d9,0xd5da,0xd5db,0xd5dc,0xd5dd,0xd5de,0xd5df,
+ 0xd5e0,0xd5e1,0xd5e2,0xd5e3,0xd5e4,0xd5e5,0xd5e6,0xd5e7,
+ 0xd5e8,0xd5e9,0xd5ea,0xd5eb,0xd5ec,0xd5ed,0xd5ee,0xd5ef,
+ 0xd5f0,0xd5f1,0xd5f2,0xd5f3,0xd5f4,0xd5f5,0xd5f6,0xd5f7,
+ 0xd5f8,0xd5f9,0xd5fa,0xd5fb,0xd5fc,0xd5fd,0xd5fe,0xd5ff,
+ 0xd600,0xd601,0xd602,0xd603,0xd604,0xd605,0xd606,0xd607,
+ 0xd608,0xd609,0xd60a,0xd60b,0xd60c,0xd60d,0xd60e,0xd60f,
+ 0xd610,0xd611,0xd612,0xd613,0xd614,0xd615,0xd616,0xd617,
+ 0xd618,0xd619,0xd61a,0xd61b,0xd61c,0xd61d,0xd61e,0xd61f,
+ 0xd620,0xd621,0xd622,0xd623,0xd624,0xd625,0xd626,0xd627,
+ 0xd628,0xd629,0xd62a,0xd62b,0xd62c,0xd62d,0xd62e,0xd62f,
+ 0xd630,0xd631,0xd632,0xd633,0xd634,0xd635,0xd636,0xd637,
+ 0xd638,0xd639,0xd63a,0xd63b,0xd63c,0xd63d,0xd63e,0xd63f,
+ 0xd640,0xd641,0xd642,0xd643,0xd644,0xd645,0xd646,0xd647,
+ 0xd648,0xd649,0xd64a,0xd64b,0xd64c,0xd64d,0xd64e,0xd64f,
+ 0xd650,0xd651,0xd652,0xd653,0xd654,0xd655,0xd656,0xd657,
+ 0xd658,0xd659,0xd65a,0xd65b,0xd65c,0xd65d,0xd65e,0xd65f,
+ 0xd660,0xd661,0xd662,0xd663,0xd664,0xd665,0xd666,0xd667,
+ 0xd668,0xd669,0xd66a,0xd66b,0xd66c,0xd66d,0xd66e,0xd66f,
+ 0xd670,0xd671,0xd672,0xd673,0xd674,0xd675,0xd676,0xd677,
+ 0xd678,0xd679,0xd67a,0xd67b,0xd67c,0xd67d,0xd67e,0xd67f,
+ 0xd680,0xd681,0xd682,0xd683,0xd684,0xd685,0xd686,0xd687,
+ 0xd688,0xd689,0xd68a,0xd68b,0xd68c,0xd68d,0xd68e,0xd68f,
+ 0xd690,0xd691,0xd692,0xd693,0xd694,0xd695,0xd696,0xd697,
+ 0xd698,0xd699,0xd69a,0xd69b,0xd69c,0xd69d,0xd69e,0xd69f,
+ 0xd6a0,0xd6a1,0xd6a2,0xd6a3,0xd6a4,0xd6a5,0xd6a6,0xd6a7,
+ 0xd6a8,0xd6a9,0xd6aa,0xd6ab,0xd6ac,0xd6ad,0xd6ae,0xd6af,
+ 0xd6b0,0xd6b1,0xd6b2,0xd6b3,0xd6b4,0xd6b5,0xd6b6,0xd6b7,
+ 0xd6b8,0xd6b9,0xd6ba,0xd6bb,0xd6bc,0xd6bd,0xd6be,0xd6bf,
+ 0xd6c0,0xd6c1,0xd6c2,0xd6c3,0xd6c4,0xd6c5,0xd6c6,0xd6c7,
+ 0xd6c8,0xd6c9,0xd6ca,0xd6cb,0xd6cc,0xd6cd,0xd6ce,0xd6cf,
+ 0xd6d0,0xd6d1,0xd6d2,0xd6d3,0xd6d4,0xd6d5,0xd6d6,0xd6d7,
+ 0xd6d8,0xd6d9,0xd6da,0xd6db,0xd6dc,0xd6dd,0xd6de,0xd6df,
+ 0xd6e0,0xd6e1,0xd6e2,0xd6e3,0xd6e4,0xd6e5,0xd6e6,0xd6e7,
+ 0xd6e8,0xd6e9,0xd6ea,0xd6eb,0xd6ec,0xd6ed,0xd6ee,0xd6ef,
+ 0xd6f0,0xd6f1,0xd6f2,0xd6f3,0xd6f4,0xd6f5,0xd6f6,0xd6f7,
+ 0xd6f8,0xd6f9,0xd6fa,0xd6fb,0xd6fc,0xd6fd,0xd6fe,0xd6ff,
+ 0xd700,0xd701,0xd702,0xd703,0xd704,0xd705,0xd706,0xd707,
+ 0xd708,0xd709,0xd70a,0xd70b,0xd70c,0xd70d,0xd70e,0xd70f,
+ 0xd710,0xd711,0xd712,0xd713,0xd714,0xd715,0xd716,0xd717,
+ 0xd718,0xd719,0xd71a,0xd71b,0xd71c,0xd71d,0xd71e,0xd71f,
+ 0xd720,0xd721,0xd722,0xd723,0xd724,0xd725,0xd726,0xd727,
+ 0xd728,0xd729,0xd72a,0xd72b,0xd72c,0xd72d,0xd72e,0xd72f,
+ 0xd730,0xd731,0xd732,0xd733,0xd734,0xd735,0xd736,0xd737,
+ 0xd738,0xd739,0xd73a,0xd73b,0xd73c,0xd73d,0xd73e,0xd73f,
+ 0xd740,0xd741,0xd742,0xd743,0xd744,0xd745,0xd746,0xd747,
+ 0xd748,0xd749,0xd74a,0xd74b,0xd74c,0xd74d,0xd74e,0xd74f,
+ 0xd750,0xd751,0xd752,0xd753,0xd754,0xd755,0xd756,0xd757,
+ 0xd758,0xd759,0xd75a,0xd75b,0xd75c,0xd75d,0xd75e,0xd75f,
+ 0xd760,0xd761,0xd762,0xd763,0xd764,0xd765,0xd766,0xd767,
+ 0xd768,0xd769,0xd76a,0xd76b,0xd76c,0xd76d,0xd76e,0xd76f,
+ 0xd770,0xd771,0xd772,0xd773,0xd774,0xd775,0xd776,0xd777,
+ 0xd778,0xd779,0xd77a,0xd77b,0xd77c,0xd77d,0xd77e,0xd77f,
+ 0xd780,0xd781,0xd782,0xd783,0xd784,0xd785,0xd786,0xd787,
+ 0xd788,0xd789,0xd78a,0xd78b,0xd78c,0xd78d,0xd78e,0xd78f,
+ 0xd790,0xd791,0xd792,0xd793,0xd794,0xd795,0xd796,0xd797,
+ 0xd798,0xd799,0xd79a,0xd79b,0xd79c,0xd79d,0xd79e,0xd79f,
+ 0xd7a0,0xd7a1,0xd7a2,0xd7a3,0xd7a4,0xd7a5,0xd7a6,0xd7a7,
+ 0xd7a8,0xd7a9,0xd7aa,0xd7ab,0xd7ac,0xd7ad,0xd7ae,0xd7af,
+ 0xd7b0,0xd7b1,0xd7b2,0xd7b3,0xd7b4,0xd7b5,0xd7b6,0xd7b7,
+ 0xd7b8,0xd7b9,0xd7ba,0xd7bb,0xd7bc,0xd7bd,0xd7be,0xd7bf,
+ 0xd7c0,0xd7c1,0xd7c2,0xd7c3,0xd7c4,0xd7c5,0xd7c6,0xd7c7,
+ 0xd7c8,0xd7c9,0xd7ca,0xd7cb,0xd7cc,0xd7cd,0xd7ce,0xd7cf,
+ 0xd7d0,0xd7d1,0xd7d2,0xd7d3,0xd7d4,0xd7d5,0xd7d6,0xd7d7,
+ 0xd7d8,0xd7d9,0xd7da,0xd7db,0xd7dc,0xd7dd,0xd7de,0xd7df,
+ 0xd7e0,0xd7e1,0xd7e2,0xd7e3,0xd7e4,0xd7e5,0xd7e6,0xd7e7,
+ 0xd7e8,0xd7e9,0xd7ea,0xd7eb,0xd7ec,0xd7ed,0xd7ee,0xd7ef,
+ 0xd7f0,0xd7f1,0xd7f2,0xd7f3,0xd7f4,0xd7f5,0xd7f6,0xd7f7,
+ 0xd7f8,0xd7f9,0xd7fa,0xd7fb,0xd7fc,0xd7fd,0xd7fe,0xd7ff,
+ 0xd800,0xd801,0xd802,0xd803,0xd804,0xd805,0xd806,0xd807,
+ 0xd808,0xd809,0xd80a,0xd80b,0xd80c,0xd80d,0xd80e,0xd80f,
+ 0xd810,0xd811,0xd812,0xd813,0xd814,0xd815,0xd816,0xd817,
+ 0xd818,0xd819,0xd81a,0xd81b,0xd81c,0xd81d,0xd81e,0xd81f,
+ 0xd820,0xd821,0xd822,0xd823,0xd824,0xd825,0xd826,0xd827,
+ 0xd828,0xd829,0xd82a,0xd82b,0xd82c,0xd82d,0xd82e,0xd82f,
+ 0xd830,0xd831,0xd832,0xd833,0xd834,0xd835,0xd836,0xd837,
+ 0xd838,0xd839,0xd83a,0xd83b,0xd83c,0xd83d,0xd83e,0xd83f,
+ 0xd840,0xd841,0xd842,0xd843,0xd844,0xd845,0xd846,0xd847,
+ 0xd848,0xd849,0xd84a,0xd84b,0xd84c,0xd84d,0xd84e,0xd84f,
+ 0xd850,0xd851,0xd852,0xd853,0xd854,0xd855,0xd856,0xd857,
+ 0xd858,0xd859,0xd85a,0xd85b,0xd85c,0xd85d,0xd85e,0xd85f,
+ 0xd860,0xd861,0xd862,0xd863,0xd864,0xd865,0xd866,0xd867,
+ 0xd868,0xd869,0xd86a,0xd86b,0xd86c,0xd86d,0xd86e,0xd86f,
+ 0xd870,0xd871,0xd872,0xd873,0xd874,0xd875,0xd876,0xd877,
+ 0xd878,0xd879,0xd87a,0xd87b,0xd87c,0xd87d,0xd87e,0xd87f,
+ 0xd880,0xd881,0xd882,0xd883,0xd884,0xd885,0xd886,0xd887,
+ 0xd888,0xd889,0xd88a,0xd88b,0xd88c,0xd88d,0xd88e,0xd88f,
+ 0xd890,0xd891,0xd892,0xd893,0xd894,0xd895,0xd896,0xd897,
+ 0xd898,0xd899,0xd89a,0xd89b,0xd89c,0xd89d,0xd89e,0xd89f,
+ 0xd8a0,0xd8a1,0xd8a2,0xd8a3,0xd8a4,0xd8a5,0xd8a6,0xd8a7,
+ 0xd8a8,0xd8a9,0xd8aa,0xd8ab,0xd8ac,0xd8ad,0xd8ae,0xd8af,
+ 0xd8b0,0xd8b1,0xd8b2,0xd8b3,0xd8b4,0xd8b5,0xd8b6,0xd8b7,
+ 0xd8b8,0xd8b9,0xd8ba,0xd8bb,0xd8bc,0xd8bd,0xd8be,0xd8bf,
+ 0xd8c0,0xd8c1,0xd8c2,0xd8c3,0xd8c4,0xd8c5,0xd8c6,0xd8c7,
+ 0xd8c8,0xd8c9,0xd8ca,0xd8cb,0xd8cc,0xd8cd,0xd8ce,0xd8cf,
+ 0xd8d0,0xd8d1,0xd8d2,0xd8d3,0xd8d4,0xd8d5,0xd8d6,0xd8d7,
+ 0xd8d8,0xd8d9,0xd8da,0xd8db,0xd8dc,0xd8dd,0xd8de,0xd8df,
+ 0xd8e0,0xd8e1,0xd8e2,0xd8e3,0xd8e4,0xd8e5,0xd8e6,0xd8e7,
+ 0xd8e8,0xd8e9,0xd8ea,0xd8eb,0xd8ec,0xd8ed,0xd8ee,0xd8ef,
+ 0xd8f0,0xd8f1,0xd8f2,0xd8f3,0xd8f4,0xd8f5,0xd8f6,0xd8f7,
+ 0xd8f8,0xd8f9,0xd8fa,0xd8fb,0xd8fc,0xd8fd,0xd8fe,0xd8ff,
+ 0xd900,0xd901,0xd902,0xd903,0xd904,0xd905,0xd906,0xd907,
+ 0xd908,0xd909,0xd90a,0xd90b,0xd90c,0xd90d,0xd90e,0xd90f,
+ 0xd910,0xd911,0xd912,0xd913,0xd914,0xd915,0xd916,0xd917,
+ 0xd918,0xd919,0xd91a,0xd91b,0xd91c,0xd91d,0xd91e,0xd91f,
+ 0xd920,0xd921,0xd922,0xd923,0xd924,0xd925,0xd926,0xd927,
+ 0xd928,0xd929,0xd92a,0xd92b,0xd92c,0xd92d,0xd92e,0xd92f,
+ 0xd930,0xd931,0xd932,0xd933,0xd934,0xd935,0xd936,0xd937,
+ 0xd938,0xd939,0xd93a,0xd93b,0xd93c,0xd93d,0xd93e,0xd93f,
+ 0xd940,0xd941,0xd942,0xd943,0xd944,0xd945,0xd946,0xd947,
+ 0xd948,0xd949,0xd94a,0xd94b,0xd94c,0xd94d,0xd94e,0xd94f,
+ 0xd950,0xd951,0xd952,0xd953,0xd954,0xd955,0xd956,0xd957,
+ 0xd958,0xd959,0xd95a,0xd95b,0xd95c,0xd95d,0xd95e,0xd95f,
+ 0xd960,0xd961,0xd962,0xd963,0xd964,0xd965,0xd966,0xd967,
+ 0xd968,0xd969,0xd96a,0xd96b,0xd96c,0xd96d,0xd96e,0xd96f,
+ 0xd970,0xd971,0xd972,0xd973,0xd974,0xd975,0xd976,0xd977,
+ 0xd978,0xd979,0xd97a,0xd97b,0xd97c,0xd97d,0xd97e,0xd97f,
+ 0xd980,0xd981,0xd982,0xd983,0xd984,0xd985,0xd986,0xd987,
+ 0xd988,0xd989,0xd98a,0xd98b,0xd98c,0xd98d,0xd98e,0xd98f,
+ 0xd990,0xd991,0xd992,0xd993,0xd994,0xd995,0xd996,0xd997,
+ 0xd998,0xd999,0xd99a,0xd99b,0xd99c,0xd99d,0xd99e,0xd99f,
+ 0xd9a0,0xd9a1,0xd9a2,0xd9a3,0xd9a4,0xd9a5,0xd9a6,0xd9a7,
+ 0xd9a8,0xd9a9,0xd9aa,0xd9ab,0xd9ac,0xd9ad,0xd9ae,0xd9af,
+ 0xd9b0,0xd9b1,0xd9b2,0xd9b3,0xd9b4,0xd9b5,0xd9b6,0xd9b7,
+ 0xd9b8,0xd9b9,0xd9ba,0xd9bb,0xd9bc,0xd9bd,0xd9be,0xd9bf,
+ 0xd9c0,0xd9c1,0xd9c2,0xd9c3,0xd9c4,0xd9c5,0xd9c6,0xd9c7,
+ 0xd9c8,0xd9c9,0xd9ca,0xd9cb,0xd9cc,0xd9cd,0xd9ce,0xd9cf,
+ 0xd9d0,0xd9d1,0xd9d2,0xd9d3,0xd9d4,0xd9d5,0xd9d6,0xd9d7,
+ 0xd9d8,0xd9d9,0xd9da,0xd9db,0xd9dc,0xd9dd,0xd9de,0xd9df,
+ 0xd9e0,0xd9e1,0xd9e2,0xd9e3,0xd9e4,0xd9e5,0xd9e6,0xd9e7,
+ 0xd9e8,0xd9e9,0xd9ea,0xd9eb,0xd9ec,0xd9ed,0xd9ee,0xd9ef,
+ 0xd9f0,0xd9f1,0xd9f2,0xd9f3,0xd9f4,0xd9f5,0xd9f6,0xd9f7,
+ 0xd9f8,0xd9f9,0xd9fa,0xd9fb,0xd9fc,0xd9fd,0xd9fe,0xd9ff,
+ 0xda00,0xda01,0xda02,0xda03,0xda04,0xda05,0xda06,0xda07,
+ 0xda08,0xda09,0xda0a,0xda0b,0xda0c,0xda0d,0xda0e,0xda0f,
+ 0xda10,0xda11,0xda12,0xda13,0xda14,0xda15,0xda16,0xda17,
+ 0xda18,0xda19,0xda1a,0xda1b,0xda1c,0xda1d,0xda1e,0xda1f,
+ 0xda20,0xda21,0xda22,0xda23,0xda24,0xda25,0xda26,0xda27,
+ 0xda28,0xda29,0xda2a,0xda2b,0xda2c,0xda2d,0xda2e,0xda2f,
+ 0xda30,0xda31,0xda32,0xda33,0xda34,0xda35,0xda36,0xda37,
+ 0xda38,0xda39,0xda3a,0xda3b,0xda3c,0xda3d,0xda3e,0xda3f,
+ 0xda40,0xda41,0xda42,0xda43,0xda44,0xda45,0xda46,0xda47,
+ 0xda48,0xda49,0xda4a,0xda4b,0xda4c,0xda4d,0xda4e,0xda4f,
+ 0xda50,0xda51,0xda52,0xda53,0xda54,0xda55,0xda56,0xda57,
+ 0xda58,0xda59,0xda5a,0xda5b,0xda5c,0xda5d,0xda5e,0xda5f,
+ 0xda60,0xda61,0xda62,0xda63,0xda64,0xda65,0xda66,0xda67,
+ 0xda68,0xda69,0xda6a,0xda6b,0xda6c,0xda6d,0xda6e,0xda6f,
+ 0xda70,0xda71,0xda72,0xda73,0xda74,0xda75,0xda76,0xda77,
+ 0xda78,0xda79,0xda7a,0xda7b,0xda7c,0xda7d,0xda7e,0xda7f,
+ 0xda80,0xda81,0xda82,0xda83,0xda84,0xda85,0xda86,0xda87,
+ 0xda88,0xda89,0xda8a,0xda8b,0xda8c,0xda8d,0xda8e,0xda8f,
+ 0xda90,0xda91,0xda92,0xda93,0xda94,0xda95,0xda96,0xda97,
+ 0xda98,0xda99,0xda9a,0xda9b,0xda9c,0xda9d,0xda9e,0xda9f,
+ 0xdaa0,0xdaa1,0xdaa2,0xdaa3,0xdaa4,0xdaa5,0xdaa6,0xdaa7,
+ 0xdaa8,0xdaa9,0xdaaa,0xdaab,0xdaac,0xdaad,0xdaae,0xdaaf,
+ 0xdab0,0xdab1,0xdab2,0xdab3,0xdab4,0xdab5,0xdab6,0xdab7,
+ 0xdab8,0xdab9,0xdaba,0xdabb,0xdabc,0xdabd,0xdabe,0xdabf,
+ 0xdac0,0xdac1,0xdac2,0xdac3,0xdac4,0xdac5,0xdac6,0xdac7,
+ 0xdac8,0xdac9,0xdaca,0xdacb,0xdacc,0xdacd,0xdace,0xdacf,
+ 0xdad0,0xdad1,0xdad2,0xdad3,0xdad4,0xdad5,0xdad6,0xdad7,
+ 0xdad8,0xdad9,0xdada,0xdadb,0xdadc,0xdadd,0xdade,0xdadf,
+ 0xdae0,0xdae1,0xdae2,0xdae3,0xdae4,0xdae5,0xdae6,0xdae7,
+ 0xdae8,0xdae9,0xdaea,0xdaeb,0xdaec,0xdaed,0xdaee,0xdaef,
+ 0xdaf0,0xdaf1,0xdaf2,0xdaf3,0xdaf4,0xdaf5,0xdaf6,0xdaf7,
+ 0xdaf8,0xdaf9,0xdafa,0xdafb,0xdafc,0xdafd,0xdafe,0xdaff,
+ 0xdb00,0xdb01,0xdb02,0xdb03,0xdb04,0xdb05,0xdb06,0xdb07,
+ 0xdb08,0xdb09,0xdb0a,0xdb0b,0xdb0c,0xdb0d,0xdb0e,0xdb0f,
+ 0xdb10,0xdb11,0xdb12,0xdb13,0xdb14,0xdb15,0xdb16,0xdb17,
+ 0xdb18,0xdb19,0xdb1a,0xdb1b,0xdb1c,0xdb1d,0xdb1e,0xdb1f,
+ 0xdb20,0xdb21,0xdb22,0xdb23,0xdb24,0xdb25,0xdb26,0xdb27,
+ 0xdb28,0xdb29,0xdb2a,0xdb2b,0xdb2c,0xdb2d,0xdb2e,0xdb2f,
+ 0xdb30,0xdb31,0xdb32,0xdb33,0xdb34,0xdb35,0xdb36,0xdb37,
+ 0xdb38,0xdb39,0xdb3a,0xdb3b,0xdb3c,0xdb3d,0xdb3e,0xdb3f,
+ 0xdb40,0xdb41,0xdb42,0xdb43,0xdb44,0xdb45,0xdb46,0xdb47,
+ 0xdb48,0xdb49,0xdb4a,0xdb4b,0xdb4c,0xdb4d,0xdb4e,0xdb4f,
+ 0xdb50,0xdb51,0xdb52,0xdb53,0xdb54,0xdb55,0xdb56,0xdb57,
+ 0xdb58,0xdb59,0xdb5a,0xdb5b,0xdb5c,0xdb5d,0xdb5e,0xdb5f,
+ 0xdb60,0xdb61,0xdb62,0xdb63,0xdb64,0xdb65,0xdb66,0xdb67,
+ 0xdb68,0xdb69,0xdb6a,0xdb6b,0xdb6c,0xdb6d,0xdb6e,0xdb6f,
+ 0xdb70,0xdb71,0xdb72,0xdb73,0xdb74,0xdb75,0xdb76,0xdb77,
+ 0xdb78,0xdb79,0xdb7a,0xdb7b,0xdb7c,0xdb7d,0xdb7e,0xdb7f,
+ 0xdb80,0xdb81,0xdb82,0xdb83,0xdb84,0xdb85,0xdb86,0xdb87,
+ 0xdb88,0xdb89,0xdb8a,0xdb8b,0xdb8c,0xdb8d,0xdb8e,0xdb8f,
+ 0xdb90,0xdb91,0xdb92,0xdb93,0xdb94,0xdb95,0xdb96,0xdb97,
+ 0xdb98,0xdb99,0xdb9a,0xdb9b,0xdb9c,0xdb9d,0xdb9e,0xdb9f,
+ 0xdba0,0xdba1,0xdba2,0xdba3,0xdba4,0xdba5,0xdba6,0xdba7,
+ 0xdba8,0xdba9,0xdbaa,0xdbab,0xdbac,0xdbad,0xdbae,0xdbaf,
+ 0xdbb0,0xdbb1,0xdbb2,0xdbb3,0xdbb4,0xdbb5,0xdbb6,0xdbb7,
+ 0xdbb8,0xdbb9,0xdbba,0xdbbb,0xdbbc,0xdbbd,0xdbbe,0xdbbf,
+ 0xdbc0,0xdbc1,0xdbc2,0xdbc3,0xdbc4,0xdbc5,0xdbc6,0xdbc7,
+ 0xdbc8,0xdbc9,0xdbca,0xdbcb,0xdbcc,0xdbcd,0xdbce,0xdbcf,
+ 0xdbd0,0xdbd1,0xdbd2,0xdbd3,0xdbd4,0xdbd5,0xdbd6,0xdbd7,
+ 0xdbd8,0xdbd9,0xdbda,0xdbdb,0xdbdc,0xdbdd,0xdbde,0xdbdf,
+ 0xdbe0,0xdbe1,0xdbe2,0xdbe3,0xdbe4,0xdbe5,0xdbe6,0xdbe7,
+ 0xdbe8,0xdbe9,0xdbea,0xdbeb,0xdbec,0xdbed,0xdbee,0xdbef,
+ 0xdbf0,0xdbf1,0xdbf2,0xdbf3,0xdbf4,0xdbf5,0xdbf6,0xdbf7,
+ 0xdbf8,0xdbf9,0xdbfa,0xdbfb,0xdbfc,0xdbfd,0xdbfe,0xdbff,
+ 0xdc00,0xdc01,0xdc02,0xdc03,0xdc04,0xdc05,0xdc06,0xdc07,
+ 0xdc08,0xdc09,0xdc0a,0xdc0b,0xdc0c,0xdc0d,0xdc0e,0xdc0f,
+ 0xdc10,0xdc11,0xdc12,0xdc13,0xdc14,0xdc15,0xdc16,0xdc17,
+ 0xdc18,0xdc19,0xdc1a,0xdc1b,0xdc1c,0xdc1d,0xdc1e,0xdc1f,
+ 0xdc20,0xdc21,0xdc22,0xdc23,0xdc24,0xdc25,0xdc26,0xdc27,
+ 0xdc28,0xdc29,0xdc2a,0xdc2b,0xdc2c,0xdc2d,0xdc2e,0xdc2f,
+ 0xdc30,0xdc31,0xdc32,0xdc33,0xdc34,0xdc35,0xdc36,0xdc37,
+ 0xdc38,0xdc39,0xdc3a,0xdc3b,0xdc3c,0xdc3d,0xdc3e,0xdc3f,
+ 0xdc40,0xdc41,0xdc42,0xdc43,0xdc44,0xdc45,0xdc46,0xdc47,
+ 0xdc48,0xdc49,0xdc4a,0xdc4b,0xdc4c,0xdc4d,0xdc4e,0xdc4f,
+ 0xdc50,0xdc51,0xdc52,0xdc53,0xdc54,0xdc55,0xdc56,0xdc57,
+ 0xdc58,0xdc59,0xdc5a,0xdc5b,0xdc5c,0xdc5d,0xdc5e,0xdc5f,
+ 0xdc60,0xdc61,0xdc62,0xdc63,0xdc64,0xdc65,0xdc66,0xdc67,
+ 0xdc68,0xdc69,0xdc6a,0xdc6b,0xdc6c,0xdc6d,0xdc6e,0xdc6f,
+ 0xdc70,0xdc71,0xdc72,0xdc73,0xdc74,0xdc75,0xdc76,0xdc77,
+ 0xdc78,0xdc79,0xdc7a,0xdc7b,0xdc7c,0xdc7d,0xdc7e,0xdc7f,
+ 0xdc80,0xdc81,0xdc82,0xdc83,0xdc84,0xdc85,0xdc86,0xdc87,
+ 0xdc88,0xdc89,0xdc8a,0xdc8b,0xdc8c,0xdc8d,0xdc8e,0xdc8f,
+ 0xdc90,0xdc91,0xdc92,0xdc93,0xdc94,0xdc95,0xdc96,0xdc97,
+ 0xdc98,0xdc99,0xdc9a,0xdc9b,0xdc9c,0xdc9d,0xdc9e,0xdc9f,
+ 0xdca0,0xdca1,0xdca2,0xdca3,0xdca4,0xdca5,0xdca6,0xdca7,
+ 0xdca8,0xdca9,0xdcaa,0xdcab,0xdcac,0xdcad,0xdcae,0xdcaf,
+ 0xdcb0,0xdcb1,0xdcb2,0xdcb3,0xdcb4,0xdcb5,0xdcb6,0xdcb7,
+ 0xdcb8,0xdcb9,0xdcba,0xdcbb,0xdcbc,0xdcbd,0xdcbe,0xdcbf,
+ 0xdcc0,0xdcc1,0xdcc2,0xdcc3,0xdcc4,0xdcc5,0xdcc6,0xdcc7,
+ 0xdcc8,0xdcc9,0xdcca,0xdccb,0xdccc,0xdccd,0xdcce,0xdccf,
+ 0xdcd0,0xdcd1,0xdcd2,0xdcd3,0xdcd4,0xdcd5,0xdcd6,0xdcd7,
+ 0xdcd8,0xdcd9,0xdcda,0xdcdb,0xdcdc,0xdcdd,0xdcde,0xdcdf,
+ 0xdce0,0xdce1,0xdce2,0xdce3,0xdce4,0xdce5,0xdce6,0xdce7,
+ 0xdce8,0xdce9,0xdcea,0xdceb,0xdcec,0xdced,0xdcee,0xdcef,
+ 0xdcf0,0xdcf1,0xdcf2,0xdcf3,0xdcf4,0xdcf5,0xdcf6,0xdcf7,
+ 0xdcf8,0xdcf9,0xdcfa,0xdcfb,0xdcfc,0xdcfd,0xdcfe,0xdcff,
+ 0xdd00,0xdd01,0xdd02,0xdd03,0xdd04,0xdd05,0xdd06,0xdd07,
+ 0xdd08,0xdd09,0xdd0a,0xdd0b,0xdd0c,0xdd0d,0xdd0e,0xdd0f,
+ 0xdd10,0xdd11,0xdd12,0xdd13,0xdd14,0xdd15,0xdd16,0xdd17,
+ 0xdd18,0xdd19,0xdd1a,0xdd1b,0xdd1c,0xdd1d,0xdd1e,0xdd1f,
+ 0xdd20,0xdd21,0xdd22,0xdd23,0xdd24,0xdd25,0xdd26,0xdd27,
+ 0xdd28,0xdd29,0xdd2a,0xdd2b,0xdd2c,0xdd2d,0xdd2e,0xdd2f,
+ 0xdd30,0xdd31,0xdd32,0xdd33,0xdd34,0xdd35,0xdd36,0xdd37,
+ 0xdd38,0xdd39,0xdd3a,0xdd3b,0xdd3c,0xdd3d,0xdd3e,0xdd3f,
+ 0xdd40,0xdd41,0xdd42,0xdd43,0xdd44,0xdd45,0xdd46,0xdd47,
+ 0xdd48,0xdd49,0xdd4a,0xdd4b,0xdd4c,0xdd4d,0xdd4e,0xdd4f,
+ 0xdd50,0xdd51,0xdd52,0xdd53,0xdd54,0xdd55,0xdd56,0xdd57,
+ 0xdd58,0xdd59,0xdd5a,0xdd5b,0xdd5c,0xdd5d,0xdd5e,0xdd5f,
+ 0xdd60,0xdd61,0xdd62,0xdd63,0xdd64,0xdd65,0xdd66,0xdd67,
+ 0xdd68,0xdd69,0xdd6a,0xdd6b,0xdd6c,0xdd6d,0xdd6e,0xdd6f,
+ 0xdd70,0xdd71,0xdd72,0xdd73,0xdd74,0xdd75,0xdd76,0xdd77,
+ 0xdd78,0xdd79,0xdd7a,0xdd7b,0xdd7c,0xdd7d,0xdd7e,0xdd7f,
+ 0xdd80,0xdd81,0xdd82,0xdd83,0xdd84,0xdd85,0xdd86,0xdd87,
+ 0xdd88,0xdd89,0xdd8a,0xdd8b,0xdd8c,0xdd8d,0xdd8e,0xdd8f,
+ 0xdd90,0xdd91,0xdd92,0xdd93,0xdd94,0xdd95,0xdd96,0xdd97,
+ 0xdd98,0xdd99,0xdd9a,0xdd9b,0xdd9c,0xdd9d,0xdd9e,0xdd9f,
+ 0xdda0,0xdda1,0xdda2,0xdda3,0xdda4,0xdda5,0xdda6,0xdda7,
+ 0xdda8,0xdda9,0xddaa,0xddab,0xddac,0xddad,0xddae,0xddaf,
+ 0xddb0,0xddb1,0xddb2,0xddb3,0xddb4,0xddb5,0xddb6,0xddb7,
+ 0xddb8,0xddb9,0xddba,0xddbb,0xddbc,0xddbd,0xddbe,0xddbf,
+ 0xddc0,0xddc1,0xddc2,0xddc3,0xddc4,0xddc5,0xddc6,0xddc7,
+ 0xddc8,0xddc9,0xddca,0xddcb,0xddcc,0xddcd,0xddce,0xddcf,
+ 0xddd0,0xddd1,0xddd2,0xddd3,0xddd4,0xddd5,0xddd6,0xddd7,
+ 0xddd8,0xddd9,0xddda,0xdddb,0xdddc,0xdddd,0xddde,0xdddf,
+ 0xdde0,0xdde1,0xdde2,0xdde3,0xdde4,0xdde5,0xdde6,0xdde7,
+ 0xdde8,0xdde9,0xddea,0xddeb,0xddec,0xdded,0xddee,0xddef,
+ 0xddf0,0xddf1,0xddf2,0xddf3,0xddf4,0xddf5,0xddf6,0xddf7,
+ 0xddf8,0xddf9,0xddfa,0xddfb,0xddfc,0xddfd,0xddfe,0xddff,
+ 0xde00,0xde01,0xde02,0xde03,0xde04,0xde05,0xde06,0xde07,
+ 0xde08,0xde09,0xde0a,0xde0b,0xde0c,0xde0d,0xde0e,0xde0f,
+ 0xde10,0xde11,0xde12,0xde13,0xde14,0xde15,0xde16,0xde17,
+ 0xde18,0xde19,0xde1a,0xde1b,0xde1c,0xde1d,0xde1e,0xde1f,
+ 0xde20,0xde21,0xde22,0xde23,0xde24,0xde25,0xde26,0xde27,
+ 0xde28,0xde29,0xde2a,0xde2b,0xde2c,0xde2d,0xde2e,0xde2f,
+ 0xde30,0xde31,0xde32,0xde33,0xde34,0xde35,0xde36,0xde37,
+ 0xde38,0xde39,0xde3a,0xde3b,0xde3c,0xde3d,0xde3e,0xde3f,
+ 0xde40,0xde41,0xde42,0xde43,0xde44,0xde45,0xde46,0xde47,
+ 0xde48,0xde49,0xde4a,0xde4b,0xde4c,0xde4d,0xde4e,0xde4f,
+ 0xde50,0xde51,0xde52,0xde53,0xde54,0xde55,0xde56,0xde57,
+ 0xde58,0xde59,0xde5a,0xde5b,0xde5c,0xde5d,0xde5e,0xde5f,
+ 0xde60,0xde61,0xde62,0xde63,0xde64,0xde65,0xde66,0xde67,
+ 0xde68,0xde69,0xde6a,0xde6b,0xde6c,0xde6d,0xde6e,0xde6f,
+ 0xde70,0xde71,0xde72,0xde73,0xde74,0xde75,0xde76,0xde77,
+ 0xde78,0xde79,0xde7a,0xde7b,0xde7c,0xde7d,0xde7e,0xde7f,
+ 0xde80,0xde81,0xde82,0xde83,0xde84,0xde85,0xde86,0xde87,
+ 0xde88,0xde89,0xde8a,0xde8b,0xde8c,0xde8d,0xde8e,0xde8f,
+ 0xde90,0xde91,0xde92,0xde93,0xde94,0xde95,0xde96,0xde97,
+ 0xde98,0xde99,0xde9a,0xde9b,0xde9c,0xde9d,0xde9e,0xde9f,
+ 0xdea0,0xdea1,0xdea2,0xdea3,0xdea4,0xdea5,0xdea6,0xdea7,
+ 0xdea8,0xdea9,0xdeaa,0xdeab,0xdeac,0xdead,0xdeae,0xdeaf,
+ 0xdeb0,0xdeb1,0xdeb2,0xdeb3,0xdeb4,0xdeb5,0xdeb6,0xdeb7,
+ 0xdeb8,0xdeb9,0xdeba,0xdebb,0xdebc,0xdebd,0xdebe,0xdebf,
+ 0xdec0,0xdec1,0xdec2,0xdec3,0xdec4,0xdec5,0xdec6,0xdec7,
+ 0xdec8,0xdec9,0xdeca,0xdecb,0xdecc,0xdecd,0xdece,0xdecf,
+ 0xded0,0xded1,0xded2,0xded3,0xded4,0xded5,0xded6,0xded7,
+ 0xded8,0xded9,0xdeda,0xdedb,0xdedc,0xdedd,0xdede,0xdedf,
+ 0xdee0,0xdee1,0xdee2,0xdee3,0xdee4,0xdee5,0xdee6,0xdee7,
+ 0xdee8,0xdee9,0xdeea,0xdeeb,0xdeec,0xdeed,0xdeee,0xdeef,
+ 0xdef0,0xdef1,0xdef2,0xdef3,0xdef4,0xdef5,0xdef6,0xdef7,
+ 0xdef8,0xdef9,0xdefa,0xdefb,0xdefc,0xdefd,0xdefe,0xdeff,
+ 0xdf00,0xdf01,0xdf02,0xdf03,0xdf04,0xdf05,0xdf06,0xdf07,
+ 0xdf08,0xdf09,0xdf0a,0xdf0b,0xdf0c,0xdf0d,0xdf0e,0xdf0f,
+ 0xdf10,0xdf11,0xdf12,0xdf13,0xdf14,0xdf15,0xdf16,0xdf17,
+ 0xdf18,0xdf19,0xdf1a,0xdf1b,0xdf1c,0xdf1d,0xdf1e,0xdf1f,
+ 0xdf20,0xdf21,0xdf22,0xdf23,0xdf24,0xdf25,0xdf26,0xdf27,
+ 0xdf28,0xdf29,0xdf2a,0xdf2b,0xdf2c,0xdf2d,0xdf2e,0xdf2f,
+ 0xdf30,0xdf31,0xdf32,0xdf33,0xdf34,0xdf35,0xdf36,0xdf37,
+ 0xdf38,0xdf39,0xdf3a,0xdf3b,0xdf3c,0xdf3d,0xdf3e,0xdf3f,
+ 0xdf40,0xdf41,0xdf42,0xdf43,0xdf44,0xdf45,0xdf46,0xdf47,
+ 0xdf48,0xdf49,0xdf4a,0xdf4b,0xdf4c,0xdf4d,0xdf4e,0xdf4f,
+ 0xdf50,0xdf51,0xdf52,0xdf53,0xdf54,0xdf55,0xdf56,0xdf57,
+ 0xdf58,0xdf59,0xdf5a,0xdf5b,0xdf5c,0xdf5d,0xdf5e,0xdf5f,
+ 0xdf60,0xdf61,0xdf62,0xdf63,0xdf64,0xdf65,0xdf66,0xdf67,
+ 0xdf68,0xdf69,0xdf6a,0xdf6b,0xdf6c,0xdf6d,0xdf6e,0xdf6f,
+ 0xdf70,0xdf71,0xdf72,0xdf73,0xdf74,0xdf75,0xdf76,0xdf77,
+ 0xdf78,0xdf79,0xdf7a,0xdf7b,0xdf7c,0xdf7d,0xdf7e,0xdf7f,
+ 0xdf80,0xdf81,0xdf82,0xdf83,0xdf84,0xdf85,0xdf86,0xdf87,
+ 0xdf88,0xdf89,0xdf8a,0xdf8b,0xdf8c,0xdf8d,0xdf8e,0xdf8f,
+ 0xdf90,0xdf91,0xdf92,0xdf93,0xdf94,0xdf95,0xdf96,0xdf97,
+ 0xdf98,0xdf99,0xdf9a,0xdf9b,0xdf9c,0xdf9d,0xdf9e,0xdf9f,
+ 0xdfa0,0xdfa1,0xdfa2,0xdfa3,0xdfa4,0xdfa5,0xdfa6,0xdfa7,
+ 0xdfa8,0xdfa9,0xdfaa,0xdfab,0xdfac,0xdfad,0xdfae,0xdfaf,
+ 0xdfb0,0xdfb1,0xdfb2,0xdfb3,0xdfb4,0xdfb5,0xdfb6,0xdfb7,
+ 0xdfb8,0xdfb9,0xdfba,0xdfbb,0xdfbc,0xdfbd,0xdfbe,0xdfbf,
+ 0xdfc0,0xdfc1,0xdfc2,0xdfc3,0xdfc4,0xdfc5,0xdfc6,0xdfc7,
+ 0xdfc8,0xdfc9,0xdfca,0xdfcb,0xdfcc,0xdfcd,0xdfce,0xdfcf,
+ 0xdfd0,0xdfd1,0xdfd2,0xdfd3,0xdfd4,0xdfd5,0xdfd6,0xdfd7,
+ 0xdfd8,0xdfd9,0xdfda,0xdfdb,0xdfdc,0xdfdd,0xdfde,0xdfdf,
+ 0xdfe0,0xdfe1,0xdfe2,0xdfe3,0xdfe4,0xdfe5,0xdfe6,0xdfe7,
+ 0xdfe8,0xdfe9,0xdfea,0xdfeb,0xdfec,0xdfed,0xdfee,0xdfef,
+ 0xdff0,0xdff1,0xdff2,0xdff3,0xdff4,0xdff5,0xdff6,0xdff7,
+ 0xdff8,0xdff9,0xdffa,0xdffb,0xdffc,0xdffd,0xdffe,0xdfff,
+ 0xe000,0xe001,0xe002,0xe003,0xe004,0xe005,0xe006,0xe007,
+ 0xe008,0xe009,0xe00a,0xe00b,0xe00c,0xe00d,0xe00e,0xe00f,
+ 0xe010,0xe011,0xe012,0xe013,0xe014,0xe015,0xe016,0xe017,
+ 0xe018,0xe019,0xe01a,0xe01b,0xe01c,0xe01d,0xe01e,0xe01f,
+ 0xe020,0xe021,0xe022,0xe023,0xe024,0xe025,0xe026,0xe027,
+ 0xe028,0xe029,0xe02a,0xe02b,0xe02c,0xe02d,0xe02e,0xe02f,
+ 0xe030,0xe031,0xe032,0xe033,0xe034,0xe035,0xe036,0xe037,
+ 0xe038,0xe039,0xe03a,0xe03b,0xe03c,0xe03d,0xe03e,0xe03f,
+ 0xe040,0xe041,0xe042,0xe043,0xe044,0xe045,0xe046,0xe047,
+ 0xe048,0xe049,0xe04a,0xe04b,0xe04c,0xe04d,0xe04e,0xe04f,
+ 0xe050,0xe051,0xe052,0xe053,0xe054,0xe055,0xe056,0xe057,
+ 0xe058,0xe059,0xe05a,0xe05b,0xe05c,0xe05d,0xe05e,0xe05f,
+ 0xe060,0xe061,0xe062,0xe063,0xe064,0xe065,0xe066,0xe067,
+ 0xe068,0xe069,0xe06a,0xe06b,0xe06c,0xe06d,0xe06e,0xe06f,
+ 0xe070,0xe071,0xe072,0xe073,0xe074,0xe075,0xe076,0xe077,
+ 0xe078,0xe079,0xe07a,0xe07b,0xe07c,0xe07d,0xe07e,0xe07f,
+ 0xe080,0xe081,0xe082,0xe083,0xe084,0xe085,0xe086,0xe087,
+ 0xe088,0xe089,0xe08a,0xe08b,0xe08c,0xe08d,0xe08e,0xe08f,
+ 0xe090,0xe091,0xe092,0xe093,0xe094,0xe095,0xe096,0xe097,
+ 0xe098,0xe099,0xe09a,0xe09b,0xe09c,0xe09d,0xe09e,0xe09f,
+ 0xe0a0,0xe0a1,0xe0a2,0xe0a3,0xe0a4,0xe0a5,0xe0a6,0xe0a7,
+ 0xe0a8,0xe0a9,0xe0aa,0xe0ab,0xe0ac,0xe0ad,0xe0ae,0xe0af,
+ 0xe0b0,0xe0b1,0xe0b2,0xe0b3,0xe0b4,0xe0b5,0xe0b6,0xe0b7,
+ 0xe0b8,0xe0b9,0xe0ba,0xe0bb,0xe0bc,0xe0bd,0xe0be,0xe0bf,
+ 0xe0c0,0xe0c1,0xe0c2,0xe0c3,0xe0c4,0xe0c5,0xe0c6,0xe0c7,
+ 0xe0c8,0xe0c9,0xe0ca,0xe0cb,0xe0cc,0xe0cd,0xe0ce,0xe0cf,
+ 0xe0d0,0xe0d1,0xe0d2,0xe0d3,0xe0d4,0xe0d5,0xe0d6,0xe0d7,
+ 0xe0d8,0xe0d9,0xe0da,0xe0db,0xe0dc,0xe0dd,0xe0de,0xe0df,
+ 0xe0e0,0xe0e1,0xe0e2,0xe0e3,0xe0e4,0xe0e5,0xe0e6,0xe0e7,
+ 0xe0e8,0xe0e9,0xe0ea,0xe0eb,0xe0ec,0xe0ed,0xe0ee,0xe0ef,
+ 0xe0f0,0xe0f1,0xe0f2,0xe0f3,0xe0f4,0xe0f5,0xe0f6,0xe0f7,
+ 0xe0f8,0xe0f9,0xe0fa,0xe0fb,0xe0fc,0xe0fd,0xe0fe,0xe0ff,
+ 0xe100,0xe101,0xe102,0xe103,0xe104,0xe105,0xe106,0xe107,
+ 0xe108,0xe109,0xe10a,0xe10b,0xe10c,0xe10d,0xe10e,0xe10f,
+ 0xe110,0xe111,0xe112,0xe113,0xe114,0xe115,0xe116,0xe117,
+ 0xe118,0xe119,0xe11a,0xe11b,0xe11c,0xe11d,0xe11e,0xe11f,
+ 0xe120,0xe121,0xe122,0xe123,0xe124,0xe125,0xe126,0xe127,
+ 0xe128,0xe129,0xe12a,0xe12b,0xe12c,0xe12d,0xe12e,0xe12f,
+ 0xe130,0xe131,0xe132,0xe133,0xe134,0xe135,0xe136,0xe137,
+ 0xe138,0xe139,0xe13a,0xe13b,0xe13c,0xe13d,0xe13e,0xe13f,
+ 0xe140,0xe141,0xe142,0xe143,0xe144,0xe145,0xe146,0xe147,
+ 0xe148,0xe149,0xe14a,0xe14b,0xe14c,0xe14d,0xe14e,0xe14f,
+ 0xe150,0xe151,0xe152,0xe153,0xe154,0xe155,0xe156,0xe157,
+ 0xe158,0xe159,0xe15a,0xe15b,0xe15c,0xe15d,0xe15e,0xe15f,
+ 0xe160,0xe161,0xe162,0xe163,0xe164,0xe165,0xe166,0xe167,
+ 0xe168,0xe169,0xe16a,0xe16b,0xe16c,0xe16d,0xe16e,0xe16f,
+ 0xe170,0xe171,0xe172,0xe173,0xe174,0xe175,0xe176,0xe177,
+ 0xe178,0xe179,0xe17a,0xe17b,0xe17c,0xe17d,0xe17e,0xe17f,
+ 0xe180,0xe181,0xe182,0xe183,0xe184,0xe185,0xe186,0xe187,
+ 0xe188,0xe189,0xe18a,0xe18b,0xe18c,0xe18d,0xe18e,0xe18f,
+ 0xe190,0xe191,0xe192,0xe193,0xe194,0xe195,0xe196,0xe197,
+ 0xe198,0xe199,0xe19a,0xe19b,0xe19c,0xe19d,0xe19e,0xe19f,
+ 0xe1a0,0xe1a1,0xe1a2,0xe1a3,0xe1a4,0xe1a5,0xe1a6,0xe1a7,
+ 0xe1a8,0xe1a9,0xe1aa,0xe1ab,0xe1ac,0xe1ad,0xe1ae,0xe1af,
+ 0xe1b0,0xe1b1,0xe1b2,0xe1b3,0xe1b4,0xe1b5,0xe1b6,0xe1b7,
+ 0xe1b8,0xe1b9,0xe1ba,0xe1bb,0xe1bc,0xe1bd,0xe1be,0xe1bf,
+ 0xe1c0,0xe1c1,0xe1c2,0xe1c3,0xe1c4,0xe1c5,0xe1c6,0xe1c7,
+ 0xe1c8,0xe1c9,0xe1ca,0xe1cb,0xe1cc,0xe1cd,0xe1ce,0xe1cf,
+ 0xe1d0,0xe1d1,0xe1d2,0xe1d3,0xe1d4,0xe1d5,0xe1d6,0xe1d7,
+ 0xe1d8,0xe1d9,0xe1da,0xe1db,0xe1dc,0xe1dd,0xe1de,0xe1df,
+ 0xe1e0,0xe1e1,0xe1e2,0xe1e3,0xe1e4,0xe1e5,0xe1e6,0xe1e7,
+ 0xe1e8,0xe1e9,0xe1ea,0xe1eb,0xe1ec,0xe1ed,0xe1ee,0xe1ef,
+ 0xe1f0,0xe1f1,0xe1f2,0xe1f3,0xe1f4,0xe1f5,0xe1f6,0xe1f7,
+ 0xe1f8,0xe1f9,0xe1fa,0xe1fb,0xe1fc,0xe1fd,0xe1fe,0xe1ff,
+ 0xe200,0xe201,0xe202,0xe203,0xe204,0xe205,0xe206,0xe207,
+ 0xe208,0xe209,0xe20a,0xe20b,0xe20c,0xe20d,0xe20e,0xe20f,
+ 0xe210,0xe211,0xe212,0xe213,0xe214,0xe215,0xe216,0xe217,
+ 0xe218,0xe219,0xe21a,0xe21b,0xe21c,0xe21d,0xe21e,0xe21f,
+ 0xe220,0xe221,0xe222,0xe223,0xe224,0xe225,0xe226,0xe227,
+ 0xe228,0xe229,0xe22a,0xe22b,0xe22c,0xe22d,0xe22e,0xe22f,
+ 0xe230,0xe231,0xe232,0xe233,0xe234,0xe235,0xe236,0xe237,
+ 0xe238,0xe239,0xe23a,0xe23b,0xe23c,0xe23d,0xe23e,0xe23f,
+ 0xe240,0xe241,0xe242,0xe243,0xe244,0xe245,0xe246,0xe247,
+ 0xe248,0xe249,0xe24a,0xe24b,0xe24c,0xe24d,0xe24e,0xe24f,
+ 0xe250,0xe251,0xe252,0xe253,0xe254,0xe255,0xe256,0xe257,
+ 0xe258,0xe259,0xe25a,0xe25b,0xe25c,0xe25d,0xe25e,0xe25f,
+ 0xe260,0xe261,0xe262,0xe263,0xe264,0xe265,0xe266,0xe267,
+ 0xe268,0xe269,0xe26a,0xe26b,0xe26c,0xe26d,0xe26e,0xe26f,
+ 0xe270,0xe271,0xe272,0xe273,0xe274,0xe275,0xe276,0xe277,
+ 0xe278,0xe279,0xe27a,0xe27b,0xe27c,0xe27d,0xe27e,0xe27f,
+ 0xe280,0xe281,0xe282,0xe283,0xe284,0xe285,0xe286,0xe287,
+ 0xe288,0xe289,0xe28a,0xe28b,0xe28c,0xe28d,0xe28e,0xe28f,
+ 0xe290,0xe291,0xe292,0xe293,0xe294,0xe295,0xe296,0xe297,
+ 0xe298,0xe299,0xe29a,0xe29b,0xe29c,0xe29d,0xe29e,0xe29f,
+ 0xe2a0,0xe2a1,0xe2a2,0xe2a3,0xe2a4,0xe2a5,0xe2a6,0xe2a7,
+ 0xe2a8,0xe2a9,0xe2aa,0xe2ab,0xe2ac,0xe2ad,0xe2ae,0xe2af,
+ 0xe2b0,0xe2b1,0xe2b2,0xe2b3,0xe2b4,0xe2b5,0xe2b6,0xe2b7,
+ 0xe2b8,0xe2b9,0xe2ba,0xe2bb,0xe2bc,0xe2bd,0xe2be,0xe2bf,
+ 0xe2c0,0xe2c1,0xe2c2,0xe2c3,0xe2c4,0xe2c5,0xe2c6,0xe2c7,
+ 0xe2c8,0xe2c9,0xe2ca,0xe2cb,0xe2cc,0xe2cd,0xe2ce,0xe2cf,
+ 0xe2d0,0xe2d1,0xe2d2,0xe2d3,0xe2d4,0xe2d5,0xe2d6,0xe2d7,
+ 0xe2d8,0xe2d9,0xe2da,0xe2db,0xe2dc,0xe2dd,0xe2de,0xe2df,
+ 0xe2e0,0xe2e1,0xe2e2,0xe2e3,0xe2e4,0xe2e5,0xe2e6,0xe2e7,
+ 0xe2e8,0xe2e9,0xe2ea,0xe2eb,0xe2ec,0xe2ed,0xe2ee,0xe2ef,
+ 0xe2f0,0xe2f1,0xe2f2,0xe2f3,0xe2f4,0xe2f5,0xe2f6,0xe2f7,
+ 0xe2f8,0xe2f9,0xe2fa,0xe2fb,0xe2fc,0xe2fd,0xe2fe,0xe2ff,
+ 0xe300,0xe301,0xe302,0xe303,0xe304,0xe305,0xe306,0xe307,
+ 0xe308,0xe309,0xe30a,0xe30b,0xe30c,0xe30d,0xe30e,0xe30f,
+ 0xe310,0xe311,0xe312,0xe313,0xe314,0xe315,0xe316,0xe317,
+ 0xe318,0xe319,0xe31a,0xe31b,0xe31c,0xe31d,0xe31e,0xe31f,
+ 0xe320,0xe321,0xe322,0xe323,0xe324,0xe325,0xe326,0xe327,
+ 0xe328,0xe329,0xe32a,0xe32b,0xe32c,0xe32d,0xe32e,0xe32f,
+ 0xe330,0xe331,0xe332,0xe333,0xe334,0xe335,0xe336,0xe337,
+ 0xe338,0xe339,0xe33a,0xe33b,0xe33c,0xe33d,0xe33e,0xe33f,
+ 0xe340,0xe341,0xe342,0xe343,0xe344,0xe345,0xe346,0xe347,
+ 0xe348,0xe349,0xe34a,0xe34b,0xe34c,0xe34d,0xe34e,0xe34f,
+ 0xe350,0xe351,0xe352,0xe353,0xe354,0xe355,0xe356,0xe357,
+ 0xe358,0xe359,0xe35a,0xe35b,0xe35c,0xe35d,0xe35e,0xe35f,
+ 0xe360,0xe361,0xe362,0xe363,0xe364,0xe365,0xe366,0xe367,
+ 0xe368,0xe369,0xe36a,0xe36b,0xe36c,0xe36d,0xe36e,0xe36f,
+ 0xe370,0xe371,0xe372,0xe373,0xe374,0xe375,0xe376,0xe377,
+ 0xe378,0xe379,0xe37a,0xe37b,0xe37c,0xe37d,0xe37e,0xe37f,
+ 0xe380,0xe381,0xe382,0xe383,0xe384,0xe385,0xe386,0xe387,
+ 0xe388,0xe389,0xe38a,0xe38b,0xe38c,0xe38d,0xe38e,0xe38f,
+ 0xe390,0xe391,0xe392,0xe393,0xe394,0xe395,0xe396,0xe397,
+ 0xe398,0xe399,0xe39a,0xe39b,0xe39c,0xe39d,0xe39e,0xe39f,
+ 0xe3a0,0xe3a1,0xe3a2,0xe3a3,0xe3a4,0xe3a5,0xe3a6,0xe3a7,
+ 0xe3a8,0xe3a9,0xe3aa,0xe3ab,0xe3ac,0xe3ad,0xe3ae,0xe3af,
+ 0xe3b0,0xe3b1,0xe3b2,0xe3b3,0xe3b4,0xe3b5,0xe3b6,0xe3b7,
+ 0xe3b8,0xe3b9,0xe3ba,0xe3bb,0xe3bc,0xe3bd,0xe3be,0xe3bf,
+ 0xe3c0,0xe3c1,0xe3c2,0xe3c3,0xe3c4,0xe3c5,0xe3c6,0xe3c7,
+ 0xe3c8,0xe3c9,0xe3ca,0xe3cb,0xe3cc,0xe3cd,0xe3ce,0xe3cf,
+ 0xe3d0,0xe3d1,0xe3d2,0xe3d3,0xe3d4,0xe3d5,0xe3d6,0xe3d7,
+ 0xe3d8,0xe3d9,0xe3da,0xe3db,0xe3dc,0xe3dd,0xe3de,0xe3df,
+ 0xe3e0,0xe3e1,0xe3e2,0xe3e3,0xe3e4,0xe3e5,0xe3e6,0xe3e7,
+ 0xe3e8,0xe3e9,0xe3ea,0xe3eb,0xe3ec,0xe3ed,0xe3ee,0xe3ef,
+ 0xe3f0,0xe3f1,0xe3f2,0xe3f3,0xe3f4,0xe3f5,0xe3f6,0xe3f7,
+ 0xe3f8,0xe3f9,0xe3fa,0xe3fb,0xe3fc,0xe3fd,0xe3fe,0xe3ff,
+ 0xe400,0xe401,0xe402,0xe403,0xe404,0xe405,0xe406,0xe407,
+ 0xe408,0xe409,0xe40a,0xe40b,0xe40c,0xe40d,0xe40e,0xe40f,
+ 0xe410,0xe411,0xe412,0xe413,0xe414,0xe415,0xe416,0xe417,
+ 0xe418,0xe419,0xe41a,0xe41b,0xe41c,0xe41d,0xe41e,0xe41f,
+ 0xe420,0xe421,0xe422,0xe423,0xe424,0xe425,0xe426,0xe427,
+ 0xe428,0xe429,0xe42a,0xe42b,0xe42c,0xe42d,0xe42e,0xe42f,
+ 0xe430,0xe431,0xe432,0xe433,0xe434,0xe435,0xe436,0xe437,
+ 0xe438,0xe439,0xe43a,0xe43b,0xe43c,0xe43d,0xe43e,0xe43f,
+ 0xe440,0xe441,0xe442,0xe443,0xe444,0xe445,0xe446,0xe447,
+ 0xe448,0xe449,0xe44a,0xe44b,0xe44c,0xe44d,0xe44e,0xe44f,
+ 0xe450,0xe451,0xe452,0xe453,0xe454,0xe455,0xe456,0xe457,
+ 0xe458,0xe459,0xe45a,0xe45b,0xe45c,0xe45d,0xe45e,0xe45f,
+ 0xe460,0xe461,0xe462,0xe463,0xe464,0xe465,0xe466,0xe467,
+ 0xe468,0xe469,0xe46a,0xe46b,0xe46c,0xe46d,0xe46e,0xe46f,
+ 0xe470,0xe471,0xe472,0xe473,0xe474,0xe475,0xe476,0xe477,
+ 0xe478,0xe479,0xe47a,0xe47b,0xe47c,0xe47d,0xe47e,0xe47f,
+ 0xe480,0xe481,0xe482,0xe483,0xe484,0xe485,0xe486,0xe487,
+ 0xe488,0xe489,0xe48a,0xe48b,0xe48c,0xe48d,0xe48e,0xe48f,
+ 0xe490,0xe491,0xe492,0xe493,0xe494,0xe495,0xe496,0xe497,
+ 0xe498,0xe499,0xe49a,0xe49b,0xe49c,0xe49d,0xe49e,0xe49f,
+ 0xe4a0,0xe4a1,0xe4a2,0xe4a3,0xe4a4,0xe4a5,0xe4a6,0xe4a7,
+ 0xe4a8,0xe4a9,0xe4aa,0xe4ab,0xe4ac,0xe4ad,0xe4ae,0xe4af,
+ 0xe4b0,0xe4b1,0xe4b2,0xe4b3,0xe4b4,0xe4b5,0xe4b6,0xe4b7,
+ 0xe4b8,0xe4b9,0xe4ba,0xe4bb,0xe4bc,0xe4bd,0xe4be,0xe4bf,
+ 0xe4c0,0xe4c1,0xe4c2,0xe4c3,0xe4c4,0xe4c5,0xe4c6,0xe4c7,
+ 0xe4c8,0xe4c9,0xe4ca,0xe4cb,0xe4cc,0xe4cd,0xe4ce,0xe4cf,
+ 0xe4d0,0xe4d1,0xe4d2,0xe4d3,0xe4d4,0xe4d5,0xe4d6,0xe4d7,
+ 0xe4d8,0xe4d9,0xe4da,0xe4db,0xe4dc,0xe4dd,0xe4de,0xe4df,
+ 0xe4e0,0xe4e1,0xe4e2,0xe4e3,0xe4e4,0xe4e5,0xe4e6,0xe4e7,
+ 0xe4e8,0xe4e9,0xe4ea,0xe4eb,0xe4ec,0xe4ed,0xe4ee,0xe4ef,
+ 0xe4f0,0xe4f1,0xe4f2,0xe4f3,0xe4f4,0xe4f5,0xe4f6,0xe4f7,
+ 0xe4f8,0xe4f9,0xe4fa,0xe4fb,0xe4fc,0xe4fd,0xe4fe,0xe4ff,
+ 0xe500,0xe501,0xe502,0xe503,0xe504,0xe505,0xe506,0xe507,
+ 0xe508,0xe509,0xe50a,0xe50b,0xe50c,0xe50d,0xe50e,0xe50f,
+ 0xe510,0xe511,0xe512,0xe513,0xe514,0xe515,0xe516,0xe517,
+ 0xe518,0xe519,0xe51a,0xe51b,0xe51c,0xe51d,0xe51e,0xe51f,
+ 0xe520,0xe521,0xe522,0xe523,0xe524,0xe525,0xe526,0xe527,
+ 0xe528,0xe529,0xe52a,0xe52b,0xe52c,0xe52d,0xe52e,0xe52f,
+ 0xe530,0xe531,0xe532,0xe533,0xe534,0xe535,0xe536,0xe537,
+ 0xe538,0xe539,0xe53a,0xe53b,0xe53c,0xe53d,0xe53e,0xe53f,
+ 0xe540,0xe541,0xe542,0xe543,0xe544,0xe545,0xe546,0xe547,
+ 0xe548,0xe549,0xe54a,0xe54b,0xe54c,0xe54d,0xe54e,0xe54f,
+ 0xe550,0xe551,0xe552,0xe553,0xe554,0xe555,0xe556,0xe557,
+ 0xe558,0xe559,0xe55a,0xe55b,0xe55c,0xe55d,0xe55e,0xe55f,
+ 0xe560,0xe561,0xe562,0xe563,0xe564,0xe565,0xe566,0xe567,
+ 0xe568,0xe569,0xe56a,0xe56b,0xe56c,0xe56d,0xe56e,0xe56f,
+ 0xe570,0xe571,0xe572,0xe573,0xe574,0xe575,0xe576,0xe577,
+ 0xe578,0xe579,0xe57a,0xe57b,0xe57c,0xe57d,0xe57e,0xe57f,
+ 0xe580,0xe581,0xe582,0xe583,0xe584,0xe585,0xe586,0xe587,
+ 0xe588,0xe589,0xe58a,0xe58b,0xe58c,0xe58d,0xe58e,0xe58f,
+ 0xe590,0xe591,0xe592,0xe593,0xe594,0xe595,0xe596,0xe597,
+ 0xe598,0xe599,0xe59a,0xe59b,0xe59c,0xe59d,0xe59e,0xe59f,
+ 0xe5a0,0xe5a1,0xe5a2,0xe5a3,0xe5a4,0xe5a5,0xe5a6,0xe5a7,
+ 0xe5a8,0xe5a9,0xe5aa,0xe5ab,0xe5ac,0xe5ad,0xe5ae,0xe5af,
+ 0xe5b0,0xe5b1,0xe5b2,0xe5b3,0xe5b4,0xe5b5,0xe5b6,0xe5b7,
+ 0xe5b8,0xe5b9,0xe5ba,0xe5bb,0xe5bc,0xe5bd,0xe5be,0xe5bf,
+ 0xe5c0,0xe5c1,0xe5c2,0xe5c3,0xe5c4,0xe5c5,0xe5c6,0xe5c7,
+ 0xe5c8,0xe5c9,0xe5ca,0xe5cb,0xe5cc,0xe5cd,0xe5ce,0xe5cf,
+ 0xe5d0,0xe5d1,0xe5d2,0xe5d3,0xe5d4,0xe5d5,0xe5d6,0xe5d7,
+ 0xe5d8,0xe5d9,0xe5da,0xe5db,0xe5dc,0xe5dd,0xe5de,0xe5df,
+ 0xe5e0,0xe5e1,0xe5e2,0xe5e3,0xe5e4,0xe5e5,0xe5e6,0xe5e7,
+ 0xe5e8,0xe5e9,0xe5ea,0xe5eb,0xe5ec,0xe5ed,0xe5ee,0xe5ef,
+ 0xe5f0,0xe5f1,0xe5f2,0xe5f3,0xe5f4,0xe5f5,0xe5f6,0xe5f7,
+ 0xe5f8,0xe5f9,0xe5fa,0xe5fb,0xe5fc,0xe5fd,0xe5fe,0xe5ff,
+ 0xe600,0xe601,0xe602,0xe603,0xe604,0xe605,0xe606,0xe607,
+ 0xe608,0xe609,0xe60a,0xe60b,0xe60c,0xe60d,0xe60e,0xe60f,
+ 0xe610,0xe611,0xe612,0xe613,0xe614,0xe615,0xe616,0xe617,
+ 0xe618,0xe619,0xe61a,0xe61b,0xe61c,0xe61d,0xe61e,0xe61f,
+ 0xe620,0xe621,0xe622,0xe623,0xe624,0xe625,0xe626,0xe627,
+ 0xe628,0xe629,0xe62a,0xe62b,0xe62c,0xe62d,0xe62e,0xe62f,
+ 0xe630,0xe631,0xe632,0xe633,0xe634,0xe635,0xe636,0xe637,
+ 0xe638,0xe639,0xe63a,0xe63b,0xe63c,0xe63d,0xe63e,0xe63f,
+ 0xe640,0xe641,0xe642,0xe643,0xe644,0xe645,0xe646,0xe647,
+ 0xe648,0xe649,0xe64a,0xe64b,0xe64c,0xe64d,0xe64e,0xe64f,
+ 0xe650,0xe651,0xe652,0xe653,0xe654,0xe655,0xe656,0xe657,
+ 0xe658,0xe659,0xe65a,0xe65b,0xe65c,0xe65d,0xe65e,0xe65f,
+ 0xe660,0xe661,0xe662,0xe663,0xe664,0xe665,0xe666,0xe667,
+ 0xe668,0xe669,0xe66a,0xe66b,0xe66c,0xe66d,0xe66e,0xe66f,
+ 0xe670,0xe671,0xe672,0xe673,0xe674,0xe675,0xe676,0xe677,
+ 0xe678,0xe679,0xe67a,0xe67b,0xe67c,0xe67d,0xe67e,0xe67f,
+ 0xe680,0xe681,0xe682,0xe683,0xe684,0xe685,0xe686,0xe687,
+ 0xe688,0xe689,0xe68a,0xe68b,0xe68c,0xe68d,0xe68e,0xe68f,
+ 0xe690,0xe691,0xe692,0xe693,0xe694,0xe695,0xe696,0xe697,
+ 0xe698,0xe699,0xe69a,0xe69b,0xe69c,0xe69d,0xe69e,0xe69f,
+ 0xe6a0,0xe6a1,0xe6a2,0xe6a3,0xe6a4,0xe6a5,0xe6a6,0xe6a7,
+ 0xe6a8,0xe6a9,0xe6aa,0xe6ab,0xe6ac,0xe6ad,0xe6ae,0xe6af,
+ 0xe6b0,0xe6b1,0xe6b2,0xe6b3,0xe6b4,0xe6b5,0xe6b6,0xe6b7,
+ 0xe6b8,0xe6b9,0xe6ba,0xe6bb,0xe6bc,0xe6bd,0xe6be,0xe6bf,
+ 0xe6c0,0xe6c1,0xe6c2,0xe6c3,0xe6c4,0xe6c5,0xe6c6,0xe6c7,
+ 0xe6c8,0xe6c9,0xe6ca,0xe6cb,0xe6cc,0xe6cd,0xe6ce,0xe6cf,
+ 0xe6d0,0xe6d1,0xe6d2,0xe6d3,0xe6d4,0xe6d5,0xe6d6,0xe6d7,
+ 0xe6d8,0xe6d9,0xe6da,0xe6db,0xe6dc,0xe6dd,0xe6de,0xe6df,
+ 0xe6e0,0xe6e1,0xe6e2,0xe6e3,0xe6e4,0xe6e5,0xe6e6,0xe6e7,
+ 0xe6e8,0xe6e9,0xe6ea,0xe6eb,0xe6ec,0xe6ed,0xe6ee,0xe6ef,
+ 0xe6f0,0xe6f1,0xe6f2,0xe6f3,0xe6f4,0xe6f5,0xe6f6,0xe6f7,
+ 0xe6f8,0xe6f9,0xe6fa,0xe6fb,0xe6fc,0xe6fd,0xe6fe,0xe6ff,
+ 0xe700,0xe701,0xe702,0xe703,0xe704,0xe705,0xe706,0xe707,
+ 0xe708,0xe709,0xe70a,0xe70b,0xe70c,0xe70d,0xe70e,0xe70f,
+ 0xe710,0xe711,0xe712,0xe713,0xe714,0xe715,0xe716,0xe717,
+ 0xe718,0xe719,0xe71a,0xe71b,0xe71c,0xe71d,0xe71e,0xe71f,
+ 0xe720,0xe721,0xe722,0xe723,0xe724,0xe725,0xe726,0xe727,
+ 0xe728,0xe729,0xe72a,0xe72b,0xe72c,0xe72d,0xe72e,0xe72f,
+ 0xe730,0xe731,0xe732,0xe733,0xe734,0xe735,0xe736,0xe737,
+ 0xe738,0xe739,0xe73a,0xe73b,0xe73c,0xe73d,0xe73e,0xe73f,
+ 0xe740,0xe741,0xe742,0xe743,0xe744,0xe745,0xe746,0xe747,
+ 0xe748,0xe749,0xe74a,0xe74b,0xe74c,0xe74d,0xe74e,0xe74f,
+ 0xe750,0xe751,0xe752,0xe753,0xe754,0xe755,0xe756,0xe757,
+ 0xe758,0xe759,0xe75a,0xe75b,0xe75c,0xe75d,0xe75e,0xe75f,
+ 0xe760,0xe761,0xe762,0xe763,0xe764,0xe765,0xe766,0xe767,
+ 0xe768,0xe769,0xe76a,0xe76b,0xe76c,0xe76d,0xe76e,0xe76f,
+ 0xe770,0xe771,0xe772,0xe773,0xe774,0xe775,0xe776,0xe777,
+ 0xe778,0xe779,0xe77a,0xe77b,0xe77c,0xe77d,0xe77e,0xe77f,
+ 0xe780,0xe781,0xe782,0xe783,0xe784,0xe785,0xe786,0xe787,
+ 0xe788,0xe789,0xe78a,0xe78b,0xe78c,0xe78d,0xe78e,0xe78f,
+ 0xe790,0xe791,0xe792,0xe793,0xe794,0xe795,0xe796,0xe797,
+ 0xe798,0xe799,0xe79a,0xe79b,0xe79c,0xe79d,0xe79e,0xe79f,
+ 0xe7a0,0xe7a1,0xe7a2,0xe7a3,0xe7a4,0xe7a5,0xe7a6,0xe7a7,
+ 0xe7a8,0xe7a9,0xe7aa,0xe7ab,0xe7ac,0xe7ad,0xe7ae,0xe7af,
+ 0xe7b0,0xe7b1,0xe7b2,0xe7b3,0xe7b4,0xe7b5,0xe7b6,0xe7b7,
+ 0xe7b8,0xe7b9,0xe7ba,0xe7bb,0xe7bc,0xe7bd,0xe7be,0xe7bf,
+ 0xe7c0,0xe7c1,0xe7c2,0xe7c3,0xe7c4,0xe7c5,0xe7c6,0xe7c7,
+ 0xe7c8,0xe7c9,0xe7ca,0xe7cb,0xe7cc,0xe7cd,0xe7ce,0xe7cf,
+ 0xe7d0,0xe7d1,0xe7d2,0xe7d3,0xe7d4,0xe7d5,0xe7d6,0xe7d7,
+ 0xe7d8,0xe7d9,0xe7da,0xe7db,0xe7dc,0xe7dd,0xe7de,0xe7df,
+ 0xe7e0,0xe7e1,0xe7e2,0xe7e3,0xe7e4,0xe7e5,0xe7e6,0xe7e7,
+ 0xe7e8,0xe7e9,0xe7ea,0xe7eb,0xe7ec,0xe7ed,0xe7ee,0xe7ef,
+ 0xe7f0,0xe7f1,0xe7f2,0xe7f3,0xe7f4,0xe7f5,0xe7f6,0xe7f7,
+ 0xe7f8,0xe7f9,0xe7fa,0xe7fb,0xe7fc,0xe7fd,0xe7fe,0xe7ff,
+ 0xe800,0xe801,0xe802,0xe803,0xe804,0xe805,0xe806,0xe807,
+ 0xe808,0xe809,0xe80a,0xe80b,0xe80c,0xe80d,0xe80e,0xe80f,
+ 0xe810,0xe811,0xe812,0xe813,0xe814,0xe815,0xe816,0xe817,
+ 0xe818,0xe819,0xe81a,0xe81b,0xe81c,0xe81d,0xe81e,0xe81f,
+ 0xe820,0xe821,0xe822,0xe823,0xe824,0xe825,0xe826,0xe827,
+ 0xe828,0xe829,0xe82a,0xe82b,0xe82c,0xe82d,0xe82e,0xe82f,
+ 0xe830,0xe831,0xe832,0xe833,0xe834,0xe835,0xe836,0xe837,
+ 0xe838,0xe839,0xe83a,0xe83b,0xe83c,0xe83d,0xe83e,0xe83f,
+ 0xe840,0xe841,0xe842,0xe843,0xe844,0xe845,0xe846,0xe847,
+ 0xe848,0xe849,0xe84a,0xe84b,0xe84c,0xe84d,0xe84e,0xe84f,
+ 0xe850,0xe851,0xe852,0xe853,0xe854,0xe855,0xe856,0xe857,
+ 0xe858,0xe859,0xe85a,0xe85b,0xe85c,0xe85d,0xe85e,0xe85f,
+ 0xe860,0xe861,0xe862,0xe863,0xe864,0xe865,0xe866,0xe867,
+ 0xe868,0xe869,0xe86a,0xe86b,0xe86c,0xe86d,0xe86e,0xe86f,
+ 0xe870,0xe871,0xe872,0xe873,0xe874,0xe875,0xe876,0xe877,
+ 0xe878,0xe879,0xe87a,0xe87b,0xe87c,0xe87d,0xe87e,0xe87f,
+ 0xe880,0xe881,0xe882,0xe883,0xe884,0xe885,0xe886,0xe887,
+ 0xe888,0xe889,0xe88a,0xe88b,0xe88c,0xe88d,0xe88e,0xe88f,
+ 0xe890,0xe891,0xe892,0xe893,0xe894,0xe895,0xe896,0xe897,
+ 0xe898,0xe899,0xe89a,0xe89b,0xe89c,0xe89d,0xe89e,0xe89f,
+ 0xe8a0,0xe8a1,0xe8a2,0xe8a3,0xe8a4,0xe8a5,0xe8a6,0xe8a7,
+ 0xe8a8,0xe8a9,0xe8aa,0xe8ab,0xe8ac,0xe8ad,0xe8ae,0xe8af,
+ 0xe8b0,0xe8b1,0xe8b2,0xe8b3,0xe8b4,0xe8b5,0xe8b6,0xe8b7,
+ 0xe8b8,0xe8b9,0xe8ba,0xe8bb,0xe8bc,0xe8bd,0xe8be,0xe8bf,
+ 0xe8c0,0xe8c1,0xe8c2,0xe8c3,0xe8c4,0xe8c5,0xe8c6,0xe8c7,
+ 0xe8c8,0xe8c9,0xe8ca,0xe8cb,0xe8cc,0xe8cd,0xe8ce,0xe8cf,
+ 0xe8d0,0xe8d1,0xe8d2,0xe8d3,0xe8d4,0xe8d5,0xe8d6,0xe8d7,
+ 0xe8d8,0xe8d9,0xe8da,0xe8db,0xe8dc,0xe8dd,0xe8de,0xe8df,
+ 0xe8e0,0xe8e1,0xe8e2,0xe8e3,0xe8e4,0xe8e5,0xe8e6,0xe8e7,
+ 0xe8e8,0xe8e9,0xe8ea,0xe8eb,0xe8ec,0xe8ed,0xe8ee,0xe8ef,
+ 0xe8f0,0xe8f1,0xe8f2,0xe8f3,0xe8f4,0xe8f5,0xe8f6,0xe8f7,
+ 0xe8f8,0xe8f9,0xe8fa,0xe8fb,0xe8fc,0xe8fd,0xe8fe,0xe8ff,
+ 0xe900,0xe901,0xe902,0xe903,0xe904,0xe905,0xe906,0xe907,
+ 0xe908,0xe909,0xe90a,0xe90b,0xe90c,0xe90d,0xe90e,0xe90f,
+ 0xe910,0xe911,0xe912,0xe913,0xe914,0xe915,0xe916,0xe917,
+ 0xe918,0xe919,0xe91a,0xe91b,0xe91c,0xe91d,0xe91e,0xe91f,
+ 0xe920,0xe921,0xe922,0xe923,0xe924,0xe925,0xe926,0xe927,
+ 0xe928,0xe929,0xe92a,0xe92b,0xe92c,0xe92d,0xe92e,0xe92f,
+ 0xe930,0xe931,0xe932,0xe933,0xe934,0xe935,0xe936,0xe937,
+ 0xe938,0xe939,0xe93a,0xe93b,0xe93c,0xe93d,0xe93e,0xe93f,
+ 0xe940,0xe941,0xe942,0xe943,0xe944,0xe945,0xe946,0xe947,
+ 0xe948,0xe949,0xe94a,0xe94b,0xe94c,0xe94d,0xe94e,0xe94f,
+ 0xe950,0xe951,0xe952,0xe953,0xe954,0xe955,0xe956,0xe957,
+ 0xe958,0xe959,0xe95a,0xe95b,0xe95c,0xe95d,0xe95e,0xe95f,
+ 0xe960,0xe961,0xe962,0xe963,0xe964,0xe965,0xe966,0xe967,
+ 0xe968,0xe969,0xe96a,0xe96b,0xe96c,0xe96d,0xe96e,0xe96f,
+ 0xe970,0xe971,0xe972,0xe973,0xe974,0xe975,0xe976,0xe977,
+ 0xe978,0xe979,0xe97a,0xe97b,0xe97c,0xe97d,0xe97e,0xe97f,
+ 0xe980,0xe981,0xe982,0xe983,0xe984,0xe985,0xe986,0xe987,
+ 0xe988,0xe989,0xe98a,0xe98b,0xe98c,0xe98d,0xe98e,0xe98f,
+ 0xe990,0xe991,0xe992,0xe993,0xe994,0xe995,0xe996,0xe997,
+ 0xe998,0xe999,0xe99a,0xe99b,0xe99c,0xe99d,0xe99e,0xe99f,
+ 0xe9a0,0xe9a1,0xe9a2,0xe9a3,0xe9a4,0xe9a5,0xe9a6,0xe9a7,
+ 0xe9a8,0xe9a9,0xe9aa,0xe9ab,0xe9ac,0xe9ad,0xe9ae,0xe9af,
+ 0xe9b0,0xe9b1,0xe9b2,0xe9b3,0xe9b4,0xe9b5,0xe9b6,0xe9b7,
+ 0xe9b8,0xe9b9,0xe9ba,0xe9bb,0xe9bc,0xe9bd,0xe9be,0xe9bf,
+ 0xe9c0,0xe9c1,0xe9c2,0xe9c3,0xe9c4,0xe9c5,0xe9c6,0xe9c7,
+ 0xe9c8,0xe9c9,0xe9ca,0xe9cb,0xe9cc,0xe9cd,0xe9ce,0xe9cf,
+ 0xe9d0,0xe9d1,0xe9d2,0xe9d3,0xe9d4,0xe9d5,0xe9d6,0xe9d7,
+ 0xe9d8,0xe9d9,0xe9da,0xe9db,0xe9dc,0xe9dd,0xe9de,0xe9df,
+ 0xe9e0,0xe9e1,0xe9e2,0xe9e3,0xe9e4,0xe9e5,0xe9e6,0xe9e7,
+ 0xe9e8,0xe9e9,0xe9ea,0xe9eb,0xe9ec,0xe9ed,0xe9ee,0xe9ef,
+ 0xe9f0,0xe9f1,0xe9f2,0xe9f3,0xe9f4,0xe9f5,0xe9f6,0xe9f7,
+ 0xe9f8,0xe9f9,0xe9fa,0xe9fb,0xe9fc,0xe9fd,0xe9fe,0xe9ff,
+ 0xea00,0xea01,0xea02,0xea03,0xea04,0xea05,0xea06,0xea07,
+ 0xea08,0xea09,0xea0a,0xea0b,0xea0c,0xea0d,0xea0e,0xea0f,
+ 0xea10,0xea11,0xea12,0xea13,0xea14,0xea15,0xea16,0xea17,
+ 0xea18,0xea19,0xea1a,0xea1b,0xea1c,0xea1d,0xea1e,0xea1f,
+ 0xea20,0xea21,0xea22,0xea23,0xea24,0xea25,0xea26,0xea27,
+ 0xea28,0xea29,0xea2a,0xea2b,0xea2c,0xea2d,0xea2e,0xea2f,
+ 0xea30,0xea31,0xea32,0xea33,0xea34,0xea35,0xea36,0xea37,
+ 0xea38,0xea39,0xea3a,0xea3b,0xea3c,0xea3d,0xea3e,0xea3f,
+ 0xea40,0xea41,0xea42,0xea43,0xea44,0xea45,0xea46,0xea47,
+ 0xea48,0xea49,0xea4a,0xea4b,0xea4c,0xea4d,0xea4e,0xea4f,
+ 0xea50,0xea51,0xea52,0xea53,0xea54,0xea55,0xea56,0xea57,
+ 0xea58,0xea59,0xea5a,0xea5b,0xea5c,0xea5d,0xea5e,0xea5f,
+ 0xea60,0xea61,0xea62,0xea63,0xea64,0xea65,0xea66,0xea67,
+ 0xea68,0xea69,0xea6a,0xea6b,0xea6c,0xea6d,0xea6e,0xea6f,
+ 0xea70,0xea71,0xea72,0xea73,0xea74,0xea75,0xea76,0xea77,
+ 0xea78,0xea79,0xea7a,0xea7b,0xea7c,0xea7d,0xea7e,0xea7f,
+ 0xea80,0xea81,0xea82,0xea83,0xea84,0xea85,0xea86,0xea87,
+ 0xea88,0xea89,0xea8a,0xea8b,0xea8c,0xea8d,0xea8e,0xea8f,
+ 0xea90,0xea91,0xea92,0xea93,0xea94,0xea95,0xea96,0xea97,
+ 0xea98,0xea99,0xea9a,0xea9b,0xea9c,0xea9d,0xea9e,0xea9f,
+ 0xeaa0,0xeaa1,0xeaa2,0xeaa3,0xeaa4,0xeaa5,0xeaa6,0xeaa7,
+ 0xeaa8,0xeaa9,0xeaaa,0xeaab,0xeaac,0xeaad,0xeaae,0xeaaf,
+ 0xeab0,0xeab1,0xeab2,0xeab3,0xeab4,0xeab5,0xeab6,0xeab7,
+ 0xeab8,0xeab9,0xeaba,0xeabb,0xeabc,0xeabd,0xeabe,0xeabf,
+ 0xeac0,0xeac1,0xeac2,0xeac3,0xeac4,0xeac5,0xeac6,0xeac7,
+ 0xeac8,0xeac9,0xeaca,0xeacb,0xeacc,0xeacd,0xeace,0xeacf,
+ 0xead0,0xead1,0xead2,0xead3,0xead4,0xead5,0xead6,0xead7,
+ 0xead8,0xead9,0xeada,0xeadb,0xeadc,0xeadd,0xeade,0xeadf,
+ 0xeae0,0xeae1,0xeae2,0xeae3,0xeae4,0xeae5,0xeae6,0xeae7,
+ 0xeae8,0xeae9,0xeaea,0xeaeb,0xeaec,0xeaed,0xeaee,0xeaef,
+ 0xeaf0,0xeaf1,0xeaf2,0xeaf3,0xeaf4,0xeaf5,0xeaf6,0xeaf7,
+ 0xeaf8,0xeaf9,0xeafa,0xeafb,0xeafc,0xeafd,0xeafe,0xeaff,
+ 0xeb00,0xeb01,0xeb02,0xeb03,0xeb04,0xeb05,0xeb06,0xeb07,
+ 0xeb08,0xeb09,0xeb0a,0xeb0b,0xeb0c,0xeb0d,0xeb0e,0xeb0f,
+ 0xeb10,0xeb11,0xeb12,0xeb13,0xeb14,0xeb15,0xeb16,0xeb17,
+ 0xeb18,0xeb19,0xeb1a,0xeb1b,0xeb1c,0xeb1d,0xeb1e,0xeb1f,
+ 0xeb20,0xeb21,0xeb22,0xeb23,0xeb24,0xeb25,0xeb26,0xeb27,
+ 0xeb28,0xeb29,0xeb2a,0xeb2b,0xeb2c,0xeb2d,0xeb2e,0xeb2f,
+ 0xeb30,0xeb31,0xeb32,0xeb33,0xeb34,0xeb35,0xeb36,0xeb37,
+ 0xeb38,0xeb39,0xeb3a,0xeb3b,0xeb3c,0xeb3d,0xeb3e,0xeb3f,
+ 0xeb40,0xeb41,0xeb42,0xeb43,0xeb44,0xeb45,0xeb46,0xeb47,
+ 0xeb48,0xeb49,0xeb4a,0xeb4b,0xeb4c,0xeb4d,0xeb4e,0xeb4f,
+ 0xeb50,0xeb51,0xeb52,0xeb53,0xeb54,0xeb55,0xeb56,0xeb57,
+ 0xeb58,0xeb59,0xeb5a,0xeb5b,0xeb5c,0xeb5d,0xeb5e,0xeb5f,
+ 0xeb60,0xeb61,0xeb62,0xeb63,0xeb64,0xeb65,0xeb66,0xeb67,
+ 0xeb68,0xeb69,0xeb6a,0xeb6b,0xeb6c,0xeb6d,0xeb6e,0xeb6f,
+ 0xeb70,0xeb71,0xeb72,0xeb73,0xeb74,0xeb75,0xeb76,0xeb77,
+ 0xeb78,0xeb79,0xeb7a,0xeb7b,0xeb7c,0xeb7d,0xeb7e,0xeb7f,
+ 0xeb80,0xeb81,0xeb82,0xeb83,0xeb84,0xeb85,0xeb86,0xeb87,
+ 0xeb88,0xeb89,0xeb8a,0xeb8b,0xeb8c,0xeb8d,0xeb8e,0xeb8f,
+ 0xeb90,0xeb91,0xeb92,0xeb93,0xeb94,0xeb95,0xeb96,0xeb97,
+ 0xeb98,0xeb99,0xeb9a,0xeb9b,0xeb9c,0xeb9d,0xeb9e,0xeb9f,
+ 0xeba0,0xeba1,0xeba2,0xeba3,0xeba4,0xeba5,0xeba6,0xeba7,
+ 0xeba8,0xeba9,0xebaa,0xebab,0xebac,0xebad,0xebae,0xebaf,
+ 0xebb0,0xebb1,0xebb2,0xebb3,0xebb4,0xebb5,0xebb6,0xebb7,
+ 0xebb8,0xebb9,0xebba,0xebbb,0xebbc,0xebbd,0xebbe,0xebbf,
+ 0xebc0,0xebc1,0xebc2,0xebc3,0xebc4,0xebc5,0xebc6,0xebc7,
+ 0xebc8,0xebc9,0xebca,0xebcb,0xebcc,0xebcd,0xebce,0xebcf,
+ 0xebd0,0xebd1,0xebd2,0xebd3,0xebd4,0xebd5,0xebd6,0xebd7,
+ 0xebd8,0xebd9,0xebda,0xebdb,0xebdc,0xebdd,0xebde,0xebdf,
+ 0xebe0,0xebe1,0xebe2,0xebe3,0xebe4,0xebe5,0xebe6,0xebe7,
+ 0xebe8,0xebe9,0xebea,0xebeb,0xebec,0xebed,0xebee,0xebef,
+ 0xebf0,0xebf1,0xebf2,0xebf3,0xebf4,0xebf5,0xebf6,0xebf7,
+ 0xebf8,0xebf9,0xebfa,0xebfb,0xebfc,0xebfd,0xebfe,0xebff,
+ 0xec00,0xec01,0xec02,0xec03,0xec04,0xec05,0xec06,0xec07,
+ 0xec08,0xec09,0xec0a,0xec0b,0xec0c,0xec0d,0xec0e,0xec0f,
+ 0xec10,0xec11,0xec12,0xec13,0xec14,0xec15,0xec16,0xec17,
+ 0xec18,0xec19,0xec1a,0xec1b,0xec1c,0xec1d,0xec1e,0xec1f,
+ 0xec20,0xec21,0xec22,0xec23,0xec24,0xec25,0xec26,0xec27,
+ 0xec28,0xec29,0xec2a,0xec2b,0xec2c,0xec2d,0xec2e,0xec2f,
+ 0xec30,0xec31,0xec32,0xec33,0xec34,0xec35,0xec36,0xec37,
+ 0xec38,0xec39,0xec3a,0xec3b,0xec3c,0xec3d,0xec3e,0xec3f,
+ 0xec40,0xec41,0xec42,0xec43,0xec44,0xec45,0xec46,0xec47,
+ 0xec48,0xec49,0xec4a,0xec4b,0xec4c,0xec4d,0xec4e,0xec4f,
+ 0xec50,0xec51,0xec52,0xec53,0xec54,0xec55,0xec56,0xec57,
+ 0xec58,0xec59,0xec5a,0xec5b,0xec5c,0xec5d,0xec5e,0xec5f,
+ 0xec60,0xec61,0xec62,0xec63,0xec64,0xec65,0xec66,0xec67,
+ 0xec68,0xec69,0xec6a,0xec6b,0xec6c,0xec6d,0xec6e,0xec6f,
+ 0xec70,0xec71,0xec72,0xec73,0xec74,0xec75,0xec76,0xec77,
+ 0xec78,0xec79,0xec7a,0xec7b,0xec7c,0xec7d,0xec7e,0xec7f,
+ 0xec80,0xec81,0xec82,0xec83,0xec84,0xec85,0xec86,0xec87,
+ 0xec88,0xec89,0xec8a,0xec8b,0xec8c,0xec8d,0xec8e,0xec8f,
+ 0xec90,0xec91,0xec92,0xec93,0xec94,0xec95,0xec96,0xec97,
+ 0xec98,0xec99,0xec9a,0xec9b,0xec9c,0xec9d,0xec9e,0xec9f,
+ 0xeca0,0xeca1,0xeca2,0xeca3,0xeca4,0xeca5,0xeca6,0xeca7,
+ 0xeca8,0xeca9,0xecaa,0xecab,0xecac,0xecad,0xecae,0xecaf,
+ 0xecb0,0xecb1,0xecb2,0xecb3,0xecb4,0xecb5,0xecb6,0xecb7,
+ 0xecb8,0xecb9,0xecba,0xecbb,0xecbc,0xecbd,0xecbe,0xecbf,
+ 0xecc0,0xecc1,0xecc2,0xecc3,0xecc4,0xecc5,0xecc6,0xecc7,
+ 0xecc8,0xecc9,0xecca,0xeccb,0xeccc,0xeccd,0xecce,0xeccf,
+ 0xecd0,0xecd1,0xecd2,0xecd3,0xecd4,0xecd5,0xecd6,0xecd7,
+ 0xecd8,0xecd9,0xecda,0xecdb,0xecdc,0xecdd,0xecde,0xecdf,
+ 0xece0,0xece1,0xece2,0xece3,0xece4,0xece5,0xece6,0xece7,
+ 0xece8,0xece9,0xecea,0xeceb,0xecec,0xeced,0xecee,0xecef,
+ 0xecf0,0xecf1,0xecf2,0xecf3,0xecf4,0xecf5,0xecf6,0xecf7,
+ 0xecf8,0xecf9,0xecfa,0xecfb,0xecfc,0xecfd,0xecfe,0xecff,
+ 0xed00,0xed01,0xed02,0xed03,0xed04,0xed05,0xed06,0xed07,
+ 0xed08,0xed09,0xed0a,0xed0b,0xed0c,0xed0d,0xed0e,0xed0f,
+ 0xed10,0xed11,0xed12,0xed13,0xed14,0xed15,0xed16,0xed17,
+ 0xed18,0xed19,0xed1a,0xed1b,0xed1c,0xed1d,0xed1e,0xed1f,
+ 0xed20,0xed21,0xed22,0xed23,0xed24,0xed25,0xed26,0xed27,
+ 0xed28,0xed29,0xed2a,0xed2b,0xed2c,0xed2d,0xed2e,0xed2f,
+ 0xed30,0xed31,0xed32,0xed33,0xed34,0xed35,0xed36,0xed37,
+ 0xed38,0xed39,0xed3a,0xed3b,0xed3c,0xed3d,0xed3e,0xed3f,
+ 0xed40,0xed41,0xed42,0xed43,0xed44,0xed45,0xed46,0xed47,
+ 0xed48,0xed49,0xed4a,0xed4b,0xed4c,0xed4d,0xed4e,0xed4f,
+ 0xed50,0xed51,0xed52,0xed53,0xed54,0xed55,0xed56,0xed57,
+ 0xed58,0xed59,0xed5a,0xed5b,0xed5c,0xed5d,0xed5e,0xed5f,
+ 0xed60,0xed61,0xed62,0xed63,0xed64,0xed65,0xed66,0xed67,
+ 0xed68,0xed69,0xed6a,0xed6b,0xed6c,0xed6d,0xed6e,0xed6f,
+ 0xed70,0xed71,0xed72,0xed73,0xed74,0xed75,0xed76,0xed77,
+ 0xed78,0xed79,0xed7a,0xed7b,0xed7c,0xed7d,0xed7e,0xed7f,
+ 0xed80,0xed81,0xed82,0xed83,0xed84,0xed85,0xed86,0xed87,
+ 0xed88,0xed89,0xed8a,0xed8b,0xed8c,0xed8d,0xed8e,0xed8f,
+ 0xed90,0xed91,0xed92,0xed93,0xed94,0xed95,0xed96,0xed97,
+ 0xed98,0xed99,0xed9a,0xed9b,0xed9c,0xed9d,0xed9e,0xed9f,
+ 0xeda0,0xeda1,0xeda2,0xeda3,0xeda4,0xeda5,0xeda6,0xeda7,
+ 0xeda8,0xeda9,0xedaa,0xedab,0xedac,0xedad,0xedae,0xedaf,
+ 0xedb0,0xedb1,0xedb2,0xedb3,0xedb4,0xedb5,0xedb6,0xedb7,
+ 0xedb8,0xedb9,0xedba,0xedbb,0xedbc,0xedbd,0xedbe,0xedbf,
+ 0xedc0,0xedc1,0xedc2,0xedc3,0xedc4,0xedc5,0xedc6,0xedc7,
+ 0xedc8,0xedc9,0xedca,0xedcb,0xedcc,0xedcd,0xedce,0xedcf,
+ 0xedd0,0xedd1,0xedd2,0xedd3,0xedd4,0xedd5,0xedd6,0xedd7,
+ 0xedd8,0xedd9,0xedda,0xeddb,0xeddc,0xeddd,0xedde,0xeddf,
+ 0xede0,0xede1,0xede2,0xede3,0xede4,0xede5,0xede6,0xede7,
+ 0xede8,0xede9,0xedea,0xedeb,0xedec,0xeded,0xedee,0xedef,
+ 0xedf0,0xedf1,0xedf2,0xedf3,0xedf4,0xedf5,0xedf6,0xedf7,
+ 0xedf8,0xedf9,0xedfa,0xedfb,0xedfc,0xedfd,0xedfe,0xedff,
+ 0xee00,0xee01,0xee02,0xee03,0xee04,0xee05,0xee06,0xee07,
+ 0xee08,0xee09,0xee0a,0xee0b,0xee0c,0xee0d,0xee0e,0xee0f,
+ 0xee10,0xee11,0xee12,0xee13,0xee14,0xee15,0xee16,0xee17,
+ 0xee18,0xee19,0xee1a,0xee1b,0xee1c,0xee1d,0xee1e,0xee1f,
+ 0xee20,0xee21,0xee22,0xee23,0xee24,0xee25,0xee26,0xee27,
+ 0xee28,0xee29,0xee2a,0xee2b,0xee2c,0xee2d,0xee2e,0xee2f,
+ 0xee30,0xee31,0xee32,0xee33,0xee34,0xee35,0xee36,0xee37,
+ 0xee38,0xee39,0xee3a,0xee3b,0xee3c,0xee3d,0xee3e,0xee3f,
+ 0xee40,0xee41,0xee42,0xee43,0xee44,0xee45,0xee46,0xee47,
+ 0xee48,0xee49,0xee4a,0xee4b,0xee4c,0xee4d,0xee4e,0xee4f,
+ 0xee50,0xee51,0xee52,0xee53,0xee54,0xee55,0xee56,0xee57,
+ 0xee58,0xee59,0xee5a,0xee5b,0xee5c,0xee5d,0xee5e,0xee5f,
+ 0xee60,0xee61,0xee62,0xee63,0xee64,0xee65,0xee66,0xee67,
+ 0xee68,0xee69,0xee6a,0xee6b,0xee6c,0xee6d,0xee6e,0xee6f,
+ 0xee70,0xee71,0xee72,0xee73,0xee74,0xee75,0xee76,0xee77,
+ 0xee78,0xee79,0xee7a,0xee7b,0xee7c,0xee7d,0xee7e,0xee7f,
+ 0xee80,0xee81,0xee82,0xee83,0xee84,0xee85,0xee86,0xee87,
+ 0xee88,0xee89,0xee8a,0xee8b,0xee8c,0xee8d,0xee8e,0xee8f,
+ 0xee90,0xee91,0xee92,0xee93,0xee94,0xee95,0xee96,0xee97,
+ 0xee98,0xee99,0xee9a,0xee9b,0xee9c,0xee9d,0xee9e,0xee9f,
+ 0xeea0,0xeea1,0xeea2,0xeea3,0xeea4,0xeea5,0xeea6,0xeea7,
+ 0xeea8,0xeea9,0xeeaa,0xeeab,0xeeac,0xeead,0xeeae,0xeeaf,
+ 0xeeb0,0xeeb1,0xeeb2,0xeeb3,0xeeb4,0xeeb5,0xeeb6,0xeeb7,
+ 0xeeb8,0xeeb9,0xeeba,0xeebb,0xeebc,0xeebd,0xeebe,0xeebf,
+ 0xeec0,0xeec1,0xeec2,0xeec3,0xeec4,0xeec5,0xeec6,0xeec7,
+ 0xeec8,0xeec9,0xeeca,0xeecb,0xeecc,0xeecd,0xeece,0xeecf,
+ 0xeed0,0xeed1,0xeed2,0xeed3,0xeed4,0xeed5,0xeed6,0xeed7,
+ 0xeed8,0xeed9,0xeeda,0xeedb,0xeedc,0xeedd,0xeede,0xeedf,
+ 0xeee0,0xeee1,0xeee2,0xeee3,0xeee4,0xeee5,0xeee6,0xeee7,
+ 0xeee8,0xeee9,0xeeea,0xeeeb,0xeeec,0xeeed,0xeeee,0xeeef,
+ 0xeef0,0xeef1,0xeef2,0xeef3,0xeef4,0xeef5,0xeef6,0xeef7,
+ 0xeef8,0xeef9,0xeefa,0xeefb,0xeefc,0xeefd,0xeefe,0xeeff,
+ 0xef00,0xef01,0xef02,0xef03,0xef04,0xef05,0xef06,0xef07,
+ 0xef08,0xef09,0xef0a,0xef0b,0xef0c,0xef0d,0xef0e,0xef0f,
+ 0xef10,0xef11,0xef12,0xef13,0xef14,0xef15,0xef16,0xef17,
+ 0xef18,0xef19,0xef1a,0xef1b,0xef1c,0xef1d,0xef1e,0xef1f,
+ 0xef20,0xef21,0xef22,0xef23,0xef24,0xef25,0xef26,0xef27,
+ 0xef28,0xef29,0xef2a,0xef2b,0xef2c,0xef2d,0xef2e,0xef2f,
+ 0xef30,0xef31,0xef32,0xef33,0xef34,0xef35,0xef36,0xef37,
+ 0xef38,0xef39,0xef3a,0xef3b,0xef3c,0xef3d,0xef3e,0xef3f,
+ 0xef40,0xef41,0xef42,0xef43,0xef44,0xef45,0xef46,0xef47,
+ 0xef48,0xef49,0xef4a,0xef4b,0xef4c,0xef4d,0xef4e,0xef4f,
+ 0xef50,0xef51,0xef52,0xef53,0xef54,0xef55,0xef56,0xef57,
+ 0xef58,0xef59,0xef5a,0xef5b,0xef5c,0xef5d,0xef5e,0xef5f,
+ 0xef60,0xef61,0xef62,0xef63,0xef64,0xef65,0xef66,0xef67,
+ 0xef68,0xef69,0xef6a,0xef6b,0xef6c,0xef6d,0xef6e,0xef6f,
+ 0xef70,0xef71,0xef72,0xef73,0xef74,0xef75,0xef76,0xef77,
+ 0xef78,0xef79,0xef7a,0xef7b,0xef7c,0xef7d,0xef7e,0xef7f,
+ 0xef80,0xef81,0xef82,0xef83,0xef84,0xef85,0xef86,0xef87,
+ 0xef88,0xef89,0xef8a,0xef8b,0xef8c,0xef8d,0xef8e,0xef8f,
+ 0xef90,0xef91,0xef92,0xef93,0xef94,0xef95,0xef96,0xef97,
+ 0xef98,0xef99,0xef9a,0xef9b,0xef9c,0xef9d,0xef9e,0xef9f,
+ 0xefa0,0xefa1,0xefa2,0xefa3,0xefa4,0xefa5,0xefa6,0xefa7,
+ 0xefa8,0xefa9,0xefaa,0xefab,0xefac,0xefad,0xefae,0xefaf,
+ 0xefb0,0xefb1,0xefb2,0xefb3,0xefb4,0xefb5,0xefb6,0xefb7,
+ 0xefb8,0xefb9,0xefba,0xefbb,0xefbc,0xefbd,0xefbe,0xefbf,
+ 0xefc0,0xefc1,0xefc2,0xefc3,0xefc4,0xefc5,0xefc6,0xefc7,
+ 0xefc8,0xefc9,0xefca,0xefcb,0xefcc,0xefcd,0xefce,0xefcf,
+ 0xefd0,0xefd1,0xefd2,0xefd3,0xefd4,0xefd5,0xefd6,0xefd7,
+ 0xefd8,0xefd9,0xefda,0xefdb,0xefdc,0xefdd,0xefde,0xefdf,
+ 0xefe0,0xefe1,0xefe2,0xefe3,0xefe4,0xefe5,0xefe6,0xefe7,
+ 0xefe8,0xefe9,0xefea,0xefeb,0xefec,0xefed,0xefee,0xefef,
+ 0xeff0,0xeff1,0xeff2,0xeff3,0xeff4,0xeff5,0xeff6,0xeff7,
+ 0xeff8,0xeff9,0xeffa,0xeffb,0xeffc,0xeffd,0xeffe,0xefff,
+ 0xf000,0xf001,0xf002,0xf003,0xf004,0xf005,0xf006,0xf007,
+ 0xf008,0xf009,0xf00a,0xf00b,0xf00c,0xf00d,0xf00e,0xf00f,
+ 0xf010,0xf011,0xf012,0xf013,0xf014,0xf015,0xf016,0xf017,
+ 0xf018,0xf019,0xf01a,0xf01b,0xf01c,0xf01d,0xf01e,0xf01f,
+ 0xf020,0xf021,0xf022,0xf023,0xf024,0xf025,0xf026,0xf027,
+ 0xf028,0xf029,0xf02a,0xf02b,0xf02c,0xf02d,0xf02e,0xf02f,
+ 0xf030,0xf031,0xf032,0xf033,0xf034,0xf035,0xf036,0xf037,
+ 0xf038,0xf039,0xf03a,0xf03b,0xf03c,0xf03d,0xf03e,0xf03f,
+ 0xf040,0xf041,0xf042,0xf043,0xf044,0xf045,0xf046,0xf047,
+ 0xf048,0xf049,0xf04a,0xf04b,0xf04c,0xf04d,0xf04e,0xf04f,
+ 0xf050,0xf051,0xf052,0xf053,0xf054,0xf055,0xf056,0xf057,
+ 0xf058,0xf059,0xf05a,0xf05b,0xf05c,0xf05d,0xf05e,0xf05f,
+ 0xf060,0xf061,0xf062,0xf063,0xf064,0xf065,0xf066,0xf067,
+ 0xf068,0xf069,0xf06a,0xf06b,0xf06c,0xf06d,0xf06e,0xf06f,
+ 0xf070,0xf071,0xf072,0xf073,0xf074,0xf075,0xf076,0xf077,
+ 0xf078,0xf079,0xf07a,0xf07b,0xf07c,0xf07d,0xf07e,0xf07f,
+ 0xf080,0xf081,0xf082,0xf083,0xf084,0xf085,0xf086,0xf087,
+ 0xf088,0xf089,0xf08a,0xf08b,0xf08c,0xf08d,0xf08e,0xf08f,
+ 0xf090,0xf091,0xf092,0xf093,0xf094,0xf095,0xf096,0xf097,
+ 0xf098,0xf099,0xf09a,0xf09b,0xf09c,0xf09d,0xf09e,0xf09f,
+ 0xf0a0,0xf0a1,0xf0a2,0xf0a3,0xf0a4,0xf0a5,0xf0a6,0xf0a7,
+ 0xf0a8,0xf0a9,0xf0aa,0xf0ab,0xf0ac,0xf0ad,0xf0ae,0xf0af,
+ 0xf0b0,0xf0b1,0xf0b2,0xf0b3,0xf0b4,0xf0b5,0xf0b6,0xf0b7,
+ 0xf0b8,0xf0b9,0xf0ba,0xf0bb,0xf0bc,0xf0bd,0xf0be,0xf0bf,
+ 0xf0c0,0xf0c1,0xf0c2,0xf0c3,0xf0c4,0xf0c5,0xf0c6,0xf0c7,
+ 0xf0c8,0xf0c9,0xf0ca,0xf0cb,0xf0cc,0xf0cd,0xf0ce,0xf0cf,
+ 0xf0d0,0xf0d1,0xf0d2,0xf0d3,0xf0d4,0xf0d5,0xf0d6,0xf0d7,
+ 0xf0d8,0xf0d9,0xf0da,0xf0db,0xf0dc,0xf0dd,0xf0de,0xf0df,
+ 0xf0e0,0xf0e1,0xf0e2,0xf0e3,0xf0e4,0xf0e5,0xf0e6,0xf0e7,
+ 0xf0e8,0xf0e9,0xf0ea,0xf0eb,0xf0ec,0xf0ed,0xf0ee,0xf0ef,
+ 0xf0f0,0xf0f1,0xf0f2,0xf0f3,0xf0f4,0xf0f5,0xf0f6,0xf0f7,
+ 0xf0f8,0xf0f9,0xf0fa,0xf0fb,0xf0fc,0xf0fd,0xf0fe,0xf0ff,
+ 0xf100,0xf101,0xf102,0xf103,0xf104,0xf105,0xf106,0xf107,
+ 0xf108,0xf109,0xf10a,0xf10b,0xf10c,0xf10d,0xf10e,0xf10f,
+ 0xf110,0xf111,0xf112,0xf113,0xf114,0xf115,0xf116,0xf117,
+ 0xf118,0xf119,0xf11a,0xf11b,0xf11c,0xf11d,0xf11e,0xf11f,
+ 0xf120,0xf121,0xf122,0xf123,0xf124,0xf125,0xf126,0xf127,
+ 0xf128,0xf129,0xf12a,0xf12b,0xf12c,0xf12d,0xf12e,0xf12f,
+ 0xf130,0xf131,0xf132,0xf133,0xf134,0xf135,0xf136,0xf137,
+ 0xf138,0xf139,0xf13a,0xf13b,0xf13c,0xf13d,0xf13e,0xf13f,
+ 0xf140,0xf141,0xf142,0xf143,0xf144,0xf145,0xf146,0xf147,
+ 0xf148,0xf149,0xf14a,0xf14b,0xf14c,0xf14d,0xf14e,0xf14f,
+ 0xf150,0xf151,0xf152,0xf153,0xf154,0xf155,0xf156,0xf157,
+ 0xf158,0xf159,0xf15a,0xf15b,0xf15c,0xf15d,0xf15e,0xf15f,
+ 0xf160,0xf161,0xf162,0xf163,0xf164,0xf165,0xf166,0xf167,
+ 0xf168,0xf169,0xf16a,0xf16b,0xf16c,0xf16d,0xf16e,0xf16f,
+ 0xf170,0xf171,0xf172,0xf173,0xf174,0xf175,0xf176,0xf177,
+ 0xf178,0xf179,0xf17a,0xf17b,0xf17c,0xf17d,0xf17e,0xf17f,
+ 0xf180,0xf181,0xf182,0xf183,0xf184,0xf185,0xf186,0xf187,
+ 0xf188,0xf189,0xf18a,0xf18b,0xf18c,0xf18d,0xf18e,0xf18f,
+ 0xf190,0xf191,0xf192,0xf193,0xf194,0xf195,0xf196,0xf197,
+ 0xf198,0xf199,0xf19a,0xf19b,0xf19c,0xf19d,0xf19e,0xf19f,
+ 0xf1a0,0xf1a1,0xf1a2,0xf1a3,0xf1a4,0xf1a5,0xf1a6,0xf1a7,
+ 0xf1a8,0xf1a9,0xf1aa,0xf1ab,0xf1ac,0xf1ad,0xf1ae,0xf1af,
+ 0xf1b0,0xf1b1,0xf1b2,0xf1b3,0xf1b4,0xf1b5,0xf1b6,0xf1b7,
+ 0xf1b8,0xf1b9,0xf1ba,0xf1bb,0xf1bc,0xf1bd,0xf1be,0xf1bf,
+ 0xf1c0,0xf1c1,0xf1c2,0xf1c3,0xf1c4,0xf1c5,0xf1c6,0xf1c7,
+ 0xf1c8,0xf1c9,0xf1ca,0xf1cb,0xf1cc,0xf1cd,0xf1ce,0xf1cf,
+ 0xf1d0,0xf1d1,0xf1d2,0xf1d3,0xf1d4,0xf1d5,0xf1d6,0xf1d7,
+ 0xf1d8,0xf1d9,0xf1da,0xf1db,0xf1dc,0xf1dd,0xf1de,0xf1df,
+ 0xf1e0,0xf1e1,0xf1e2,0xf1e3,0xf1e4,0xf1e5,0xf1e6,0xf1e7,
+ 0xf1e8,0xf1e9,0xf1ea,0xf1eb,0xf1ec,0xf1ed,0xf1ee,0xf1ef,
+ 0xf1f0,0xf1f1,0xf1f2,0xf1f3,0xf1f4,0xf1f5,0xf1f6,0xf1f7,
+ 0xf1f8,0xf1f9,0xf1fa,0xf1fb,0xf1fc,0xf1fd,0xf1fe,0xf1ff,
+ 0xf200,0xf201,0xf202,0xf203,0xf204,0xf205,0xf206,0xf207,
+ 0xf208,0xf209,0xf20a,0xf20b,0xf20c,0xf20d,0xf20e,0xf20f,
+ 0xf210,0xf211,0xf212,0xf213,0xf214,0xf215,0xf216,0xf217,
+ 0xf218,0xf219,0xf21a,0xf21b,0xf21c,0xf21d,0xf21e,0xf21f,
+ 0xf220,0xf221,0xf222,0xf223,0xf224,0xf225,0xf226,0xf227,
+ 0xf228,0xf229,0xf22a,0xf22b,0xf22c,0xf22d,0xf22e,0xf22f,
+ 0xf230,0xf231,0xf232,0xf233,0xf234,0xf235,0xf236,0xf237,
+ 0xf238,0xf239,0xf23a,0xf23b,0xf23c,0xf23d,0xf23e,0xf23f,
+ 0xf240,0xf241,0xf242,0xf243,0xf244,0xf245,0xf246,0xf247,
+ 0xf248,0xf249,0xf24a,0xf24b,0xf24c,0xf24d,0xf24e,0xf24f,
+ 0xf250,0xf251,0xf252,0xf253,0xf254,0xf255,0xf256,0xf257,
+ 0xf258,0xf259,0xf25a,0xf25b,0xf25c,0xf25d,0xf25e,0xf25f,
+ 0xf260,0xf261,0xf262,0xf263,0xf264,0xf265,0xf266,0xf267,
+ 0xf268,0xf269,0xf26a,0xf26b,0xf26c,0xf26d,0xf26e,0xf26f,
+ 0xf270,0xf271,0xf272,0xf273,0xf274,0xf275,0xf276,0xf277,
+ 0xf278,0xf279,0xf27a,0xf27b,0xf27c,0xf27d,0xf27e,0xf27f,
+ 0xf280,0xf281,0xf282,0xf283,0xf284,0xf285,0xf286,0xf287,
+ 0xf288,0xf289,0xf28a,0xf28b,0xf28c,0xf28d,0xf28e,0xf28f,
+ 0xf290,0xf291,0xf292,0xf293,0xf294,0xf295,0xf296,0xf297,
+ 0xf298,0xf299,0xf29a,0xf29b,0xf29c,0xf29d,0xf29e,0xf29f,
+ 0xf2a0,0xf2a1,0xf2a2,0xf2a3,0xf2a4,0xf2a5,0xf2a6,0xf2a7,
+ 0xf2a8,0xf2a9,0xf2aa,0xf2ab,0xf2ac,0xf2ad,0xf2ae,0xf2af,
+ 0xf2b0,0xf2b1,0xf2b2,0xf2b3,0xf2b4,0xf2b5,0xf2b6,0xf2b7,
+ 0xf2b8,0xf2b9,0xf2ba,0xf2bb,0xf2bc,0xf2bd,0xf2be,0xf2bf,
+ 0xf2c0,0xf2c1,0xf2c2,0xf2c3,0xf2c4,0xf2c5,0xf2c6,0xf2c7,
+ 0xf2c8,0xf2c9,0xf2ca,0xf2cb,0xf2cc,0xf2cd,0xf2ce,0xf2cf,
+ 0xf2d0,0xf2d1,0xf2d2,0xf2d3,0xf2d4,0xf2d5,0xf2d6,0xf2d7,
+ 0xf2d8,0xf2d9,0xf2da,0xf2db,0xf2dc,0xf2dd,0xf2de,0xf2df,
+ 0xf2e0,0xf2e1,0xf2e2,0xf2e3,0xf2e4,0xf2e5,0xf2e6,0xf2e7,
+ 0xf2e8,0xf2e9,0xf2ea,0xf2eb,0xf2ec,0xf2ed,0xf2ee,0xf2ef,
+ 0xf2f0,0xf2f1,0xf2f2,0xf2f3,0xf2f4,0xf2f5,0xf2f6,0xf2f7,
+ 0xf2f8,0xf2f9,0xf2fa,0xf2fb,0xf2fc,0xf2fd,0xf2fe,0xf2ff,
+ 0xf300,0xf301,0xf302,0xf303,0xf304,0xf305,0xf306,0xf307,
+ 0xf308,0xf309,0xf30a,0xf30b,0xf30c,0xf30d,0xf30e,0xf30f,
+ 0xf310,0xf311,0xf312,0xf313,0xf314,0xf315,0xf316,0xf317,
+ 0xf318,0xf319,0xf31a,0xf31b,0xf31c,0xf31d,0xf31e,0xf31f,
+ 0xf320,0xf321,0xf322,0xf323,0xf324,0xf325,0xf326,0xf327,
+ 0xf328,0xf329,0xf32a,0xf32b,0xf32c,0xf32d,0xf32e,0xf32f,
+ 0xf330,0xf331,0xf332,0xf333,0xf334,0xf335,0xf336,0xf337,
+ 0xf338,0xf339,0xf33a,0xf33b,0xf33c,0xf33d,0xf33e,0xf33f,
+ 0xf340,0xf341,0xf342,0xf343,0xf344,0xf345,0xf346,0xf347,
+ 0xf348,0xf349,0xf34a,0xf34b,0xf34c,0xf34d,0xf34e,0xf34f,
+ 0xf350,0xf351,0xf352,0xf353,0xf354,0xf355,0xf356,0xf357,
+ 0xf358,0xf359,0xf35a,0xf35b,0xf35c,0xf35d,0xf35e,0xf35f,
+ 0xf360,0xf361,0xf362,0xf363,0xf364,0xf365,0xf366,0xf367,
+ 0xf368,0xf369,0xf36a,0xf36b,0xf36c,0xf36d,0xf36e,0xf36f,
+ 0xf370,0xf371,0xf372,0xf373,0xf374,0xf375,0xf376,0xf377,
+ 0xf378,0xf379,0xf37a,0xf37b,0xf37c,0xf37d,0xf37e,0xf37f,
+ 0xf380,0xf381,0xf382,0xf383,0xf384,0xf385,0xf386,0xf387,
+ 0xf388,0xf389,0xf38a,0xf38b,0xf38c,0xf38d,0xf38e,0xf38f,
+ 0xf390,0xf391,0xf392,0xf393,0xf394,0xf395,0xf396,0xf397,
+ 0xf398,0xf399,0xf39a,0xf39b,0xf39c,0xf39d,0xf39e,0xf39f,
+ 0xf3a0,0xf3a1,0xf3a2,0xf3a3,0xf3a4,0xf3a5,0xf3a6,0xf3a7,
+ 0xf3a8,0xf3a9,0xf3aa,0xf3ab,0xf3ac,0xf3ad,0xf3ae,0xf3af,
+ 0xf3b0,0xf3b1,0xf3b2,0xf3b3,0xf3b4,0xf3b5,0xf3b6,0xf3b7,
+ 0xf3b8,0xf3b9,0xf3ba,0xf3bb,0xf3bc,0xf3bd,0xf3be,0xf3bf,
+ 0xf3c0,0xf3c1,0xf3c2,0xf3c3,0xf3c4,0xf3c5,0xf3c6,0xf3c7,
+ 0xf3c8,0xf3c9,0xf3ca,0xf3cb,0xf3cc,0xf3cd,0xf3ce,0xf3cf,
+ 0xf3d0,0xf3d1,0xf3d2,0xf3d3,0xf3d4,0xf3d5,0xf3d6,0xf3d7,
+ 0xf3d8,0xf3d9,0xf3da,0xf3db,0xf3dc,0xf3dd,0xf3de,0xf3df,
+ 0xf3e0,0xf3e1,0xf3e2,0xf3e3,0xf3e4,0xf3e5,0xf3e6,0xf3e7,
+ 0xf3e8,0xf3e9,0xf3ea,0xf3eb,0xf3ec,0xf3ed,0xf3ee,0xf3ef,
+ 0xf3f0,0xf3f1,0xf3f2,0xf3f3,0xf3f4,0xf3f5,0xf3f6,0xf3f7,
+ 0xf3f8,0xf3f9,0xf3fa,0xf3fb,0xf3fc,0xf3fd,0xf3fe,0xf3ff,
+ 0xf400,0xf401,0xf402,0xf403,0xf404,0xf405,0xf406,0xf407,
+ 0xf408,0xf409,0xf40a,0xf40b,0xf40c,0xf40d,0xf40e,0xf40f,
+ 0xf410,0xf411,0xf412,0xf413,0xf414,0xf415,0xf416,0xf417,
+ 0xf418,0xf419,0xf41a,0xf41b,0xf41c,0xf41d,0xf41e,0xf41f,
+ 0xf420,0xf421,0xf422,0xf423,0xf424,0xf425,0xf426,0xf427,
+ 0xf428,0xf429,0xf42a,0xf42b,0xf42c,0xf42d,0xf42e,0xf42f,
+ 0xf430,0xf431,0xf432,0xf433,0xf434,0xf435,0xf436,0xf437,
+ 0xf438,0xf439,0xf43a,0xf43b,0xf43c,0xf43d,0xf43e,0xf43f,
+ 0xf440,0xf441,0xf442,0xf443,0xf444,0xf445,0xf446,0xf447,
+ 0xf448,0xf449,0xf44a,0xf44b,0xf44c,0xf44d,0xf44e,0xf44f,
+ 0xf450,0xf451,0xf452,0xf453,0xf454,0xf455,0xf456,0xf457,
+ 0xf458,0xf459,0xf45a,0xf45b,0xf45c,0xf45d,0xf45e,0xf45f,
+ 0xf460,0xf461,0xf462,0xf463,0xf464,0xf465,0xf466,0xf467,
+ 0xf468,0xf469,0xf46a,0xf46b,0xf46c,0xf46d,0xf46e,0xf46f,
+ 0xf470,0xf471,0xf472,0xf473,0xf474,0xf475,0xf476,0xf477,
+ 0xf478,0xf479,0xf47a,0xf47b,0xf47c,0xf47d,0xf47e,0xf47f,
+ 0xf480,0xf481,0xf482,0xf483,0xf484,0xf485,0xf486,0xf487,
+ 0xf488,0xf489,0xf48a,0xf48b,0xf48c,0xf48d,0xf48e,0xf48f,
+ 0xf490,0xf491,0xf492,0xf493,0xf494,0xf495,0xf496,0xf497,
+ 0xf498,0xf499,0xf49a,0xf49b,0xf49c,0xf49d,0xf49e,0xf49f,
+ 0xf4a0,0xf4a1,0xf4a2,0xf4a3,0xf4a4,0xf4a5,0xf4a6,0xf4a7,
+ 0xf4a8,0xf4a9,0xf4aa,0xf4ab,0xf4ac,0xf4ad,0xf4ae,0xf4af,
+ 0xf4b0,0xf4b1,0xf4b2,0xf4b3,0xf4b4,0xf4b5,0xf4b6,0xf4b7,
+ 0xf4b8,0xf4b9,0xf4ba,0xf4bb,0xf4bc,0xf4bd,0xf4be,0xf4bf,
+ 0xf4c0,0xf4c1,0xf4c2,0xf4c3,0xf4c4,0xf4c5,0xf4c6,0xf4c7,
+ 0xf4c8,0xf4c9,0xf4ca,0xf4cb,0xf4cc,0xf4cd,0xf4ce,0xf4cf,
+ 0xf4d0,0xf4d1,0xf4d2,0xf4d3,0xf4d4,0xf4d5,0xf4d6,0xf4d7,
+ 0xf4d8,0xf4d9,0xf4da,0xf4db,0xf4dc,0xf4dd,0xf4de,0xf4df,
+ 0xf4e0,0xf4e1,0xf4e2,0xf4e3,0xf4e4,0xf4e5,0xf4e6,0xf4e7,
+ 0xf4e8,0xf4e9,0xf4ea,0xf4eb,0xf4ec,0xf4ed,0xf4ee,0xf4ef,
+ 0xf4f0,0xf4f1,0xf4f2,0xf4f3,0xf4f4,0xf4f5,0xf4f6,0xf4f7,
+ 0xf4f8,0xf4f9,0xf4fa,0xf4fb,0xf4fc,0xf4fd,0xf4fe,0xf4ff,
+ 0xf500,0xf501,0xf502,0xf503,0xf504,0xf505,0xf506,0xf507,
+ 0xf508,0xf509,0xf50a,0xf50b,0xf50c,0xf50d,0xf50e,0xf50f,
+ 0xf510,0xf511,0xf512,0xf513,0xf514,0xf515,0xf516,0xf517,
+ 0xf518,0xf519,0xf51a,0xf51b,0xf51c,0xf51d,0xf51e,0xf51f,
+ 0xf520,0xf521,0xf522,0xf523,0xf524,0xf525,0xf526,0xf527,
+ 0xf528,0xf529,0xf52a,0xf52b,0xf52c,0xf52d,0xf52e,0xf52f,
+ 0xf530,0xf531,0xf532,0xf533,0xf534,0xf535,0xf536,0xf537,
+ 0xf538,0xf539,0xf53a,0xf53b,0xf53c,0xf53d,0xf53e,0xf53f,
+ 0xf540,0xf541,0xf542,0xf543,0xf544,0xf545,0xf546,0xf547,
+ 0xf548,0xf549,0xf54a,0xf54b,0xf54c,0xf54d,0xf54e,0xf54f,
+ 0xf550,0xf551,0xf552,0xf553,0xf554,0xf555,0xf556,0xf557,
+ 0xf558,0xf559,0xf55a,0xf55b,0xf55c,0xf55d,0xf55e,0xf55f,
+ 0xf560,0xf561,0xf562,0xf563,0xf564,0xf565,0xf566,0xf567,
+ 0xf568,0xf569,0xf56a,0xf56b,0xf56c,0xf56d,0xf56e,0xf56f,
+ 0xf570,0xf571,0xf572,0xf573,0xf574,0xf575,0xf576,0xf577,
+ 0xf578,0xf579,0xf57a,0xf57b,0xf57c,0xf57d,0xf57e,0xf57f,
+ 0xf580,0xf581,0xf582,0xf583,0xf584,0xf585,0xf586,0xf587,
+ 0xf588,0xf589,0xf58a,0xf58b,0xf58c,0xf58d,0xf58e,0xf58f,
+ 0xf590,0xf591,0xf592,0xf593,0xf594,0xf595,0xf596,0xf597,
+ 0xf598,0xf599,0xf59a,0xf59b,0xf59c,0xf59d,0xf59e,0xf59f,
+ 0xf5a0,0xf5a1,0xf5a2,0xf5a3,0xf5a4,0xf5a5,0xf5a6,0xf5a7,
+ 0xf5a8,0xf5a9,0xf5aa,0xf5ab,0xf5ac,0xf5ad,0xf5ae,0xf5af,
+ 0xf5b0,0xf5b1,0xf5b2,0xf5b3,0xf5b4,0xf5b5,0xf5b6,0xf5b7,
+ 0xf5b8,0xf5b9,0xf5ba,0xf5bb,0xf5bc,0xf5bd,0xf5be,0xf5bf,
+ 0xf5c0,0xf5c1,0xf5c2,0xf5c3,0xf5c4,0xf5c5,0xf5c6,0xf5c7,
+ 0xf5c8,0xf5c9,0xf5ca,0xf5cb,0xf5cc,0xf5cd,0xf5ce,0xf5cf,
+ 0xf5d0,0xf5d1,0xf5d2,0xf5d3,0xf5d4,0xf5d5,0xf5d6,0xf5d7,
+ 0xf5d8,0xf5d9,0xf5da,0xf5db,0xf5dc,0xf5dd,0xf5de,0xf5df,
+ 0xf5e0,0xf5e1,0xf5e2,0xf5e3,0xf5e4,0xf5e5,0xf5e6,0xf5e7,
+ 0xf5e8,0xf5e9,0xf5ea,0xf5eb,0xf5ec,0xf5ed,0xf5ee,0xf5ef,
+ 0xf5f0,0xf5f1,0xf5f2,0xf5f3,0xf5f4,0xf5f5,0xf5f6,0xf5f7,
+ 0xf5f8,0xf5f9,0xf5fa,0xf5fb,0xf5fc,0xf5fd,0xf5fe,0xf5ff,
+ 0xf600,0xf601,0xf602,0xf603,0xf604,0xf605,0xf606,0xf607,
+ 0xf608,0xf609,0xf60a,0xf60b,0xf60c,0xf60d,0xf60e,0xf60f,
+ 0xf610,0xf611,0xf612,0xf613,0xf614,0xf615,0xf616,0xf617,
+ 0xf618,0xf619,0xf61a,0xf61b,0xf61c,0xf61d,0xf61e,0xf61f,
+ 0xf620,0xf621,0xf622,0xf623,0xf624,0xf625,0xf626,0xf627,
+ 0xf628,0xf629,0xf62a,0xf62b,0xf62c,0xf62d,0xf62e,0xf62f,
+ 0xf630,0xf631,0xf632,0xf633,0xf634,0xf635,0xf636,0xf637,
+ 0xf638,0xf639,0xf63a,0xf63b,0xf63c,0xf63d,0xf63e,0xf63f,
+ 0xf640,0xf641,0xf642,0xf643,0xf644,0xf645,0xf646,0xf647,
+ 0xf648,0xf649,0xf64a,0xf64b,0xf64c,0xf64d,0xf64e,0xf64f,
+ 0xf650,0xf651,0xf652,0xf653,0xf654,0xf655,0xf656,0xf657,
+ 0xf658,0xf659,0xf65a,0xf65b,0xf65c,0xf65d,0xf65e,0xf65f,
+ 0xf660,0xf661,0xf662,0xf663,0xf664,0xf665,0xf666,0xf667,
+ 0xf668,0xf669,0xf66a,0xf66b,0xf66c,0xf66d,0xf66e,0xf66f,
+ 0xf670,0xf671,0xf672,0xf673,0xf674,0xf675,0xf676,0xf677,
+ 0xf678,0xf679,0xf67a,0xf67b,0xf67c,0xf67d,0xf67e,0xf67f,
+ 0xf680,0xf681,0xf682,0xf683,0xf684,0xf685,0xf686,0xf687,
+ 0xf688,0xf689,0xf68a,0xf68b,0xf68c,0xf68d,0xf68e,0xf68f,
+ 0xf690,0xf691,0xf692,0xf693,0xf694,0xf695,0xf696,0xf697,
+ 0xf698,0xf699,0xf69a,0xf69b,0xf69c,0xf69d,0xf69e,0xf69f,
+ 0xf6a0,0xf6a1,0xf6a2,0xf6a3,0xf6a4,0xf6a5,0xf6a6,0xf6a7,
+ 0xf6a8,0xf6a9,0xf6aa,0xf6ab,0xf6ac,0xf6ad,0xf6ae,0xf6af,
+ 0xf6b0,0xf6b1,0xf6b2,0xf6b3,0xf6b4,0xf6b5,0xf6b6,0xf6b7,
+ 0xf6b8,0xf6b9,0xf6ba,0xf6bb,0xf6bc,0xf6bd,0xf6be,0xf6bf,
+ 0xf6c0,0xf6c1,0xf6c2,0xf6c3,0xf6c4,0xf6c5,0xf6c6,0xf6c7,
+ 0xf6c8,0xf6c9,0xf6ca,0xf6cb,0xf6cc,0xf6cd,0xf6ce,0xf6cf,
+ 0xf6d0,0xf6d1,0xf6d2,0xf6d3,0xf6d4,0xf6d5,0xf6d6,0xf6d7,
+ 0xf6d8,0xf6d9,0xf6da,0xf6db,0xf6dc,0xf6dd,0xf6de,0xf6df,
+ 0xf6e0,0xf6e1,0xf6e2,0xf6e3,0xf6e4,0xf6e5,0xf6e6,0xf6e7,
+ 0xf6e8,0xf6e9,0xf6ea,0xf6eb,0xf6ec,0xf6ed,0xf6ee,0xf6ef,
+ 0xf6f0,0xf6f1,0xf6f2,0xf6f3,0xf6f4,0xf6f5,0xf6f6,0xf6f7,
+ 0xf6f8,0xf6f9,0xf6fa,0xf6fb,0xf6fc,0xf6fd,0xf6fe,0xf6ff,
+ 0xf700,0xf701,0xf702,0xf703,0xf704,0xf705,0xf706,0xf707,
+ 0xf708,0xf709,0xf70a,0xf70b,0xf70c,0xf70d,0xf70e,0xf70f,
+ 0xf710,0xf711,0xf712,0xf713,0xf714,0xf715,0xf716,0xf717,
+ 0xf718,0xf719,0xf71a,0xf71b,0xf71c,0xf71d,0xf71e,0xf71f,
+ 0xf720,0xf721,0xf722,0xf723,0xf724,0xf725,0xf726,0xf727,
+ 0xf728,0xf729,0xf72a,0xf72b,0xf72c,0xf72d,0xf72e,0xf72f,
+ 0xf730,0xf731,0xf732,0xf733,0xf734,0xf735,0xf736,0xf737,
+ 0xf738,0xf739,0xf73a,0xf73b,0xf73c,0xf73d,0xf73e,0xf73f,
+ 0xf740,0xf741,0xf742,0xf743,0xf744,0xf745,0xf746,0xf747,
+ 0xf748,0xf749,0xf74a,0xf74b,0xf74c,0xf74d,0xf74e,0xf74f,
+ 0xf750,0xf751,0xf752,0xf753,0xf754,0xf755,0xf756,0xf757,
+ 0xf758,0xf759,0xf75a,0xf75b,0xf75c,0xf75d,0xf75e,0xf75f,
+ 0xf760,0xf761,0xf762,0xf763,0xf764,0xf765,0xf766,0xf767,
+ 0xf768,0xf769,0xf76a,0xf76b,0xf76c,0xf76d,0xf76e,0xf76f,
+ 0xf770,0xf771,0xf772,0xf773,0xf774,0xf775,0xf776,0xf777,
+ 0xf778,0xf779,0xf77a,0xf77b,0xf77c,0xf77d,0xf77e,0xf77f,
+ 0xf780,0xf781,0xf782,0xf783,0xf784,0xf785,0xf786,0xf787,
+ 0xf788,0xf789,0xf78a,0xf78b,0xf78c,0xf78d,0xf78e,0xf78f,
+ 0xf790,0xf791,0xf792,0xf793,0xf794,0xf795,0xf796,0xf797,
+ 0xf798,0xf799,0xf79a,0xf79b,0xf79c,0xf79d,0xf79e,0xf79f,
+ 0xf7a0,0xf7a1,0xf7a2,0xf7a3,0xf7a4,0xf7a5,0xf7a6,0xf7a7,
+ 0xf7a8,0xf7a9,0xf7aa,0xf7ab,0xf7ac,0xf7ad,0xf7ae,0xf7af,
+ 0xf7b0,0xf7b1,0xf7b2,0xf7b3,0xf7b4,0xf7b5,0xf7b6,0xf7b7,
+ 0xf7b8,0xf7b9,0xf7ba,0xf7bb,0xf7bc,0xf7bd,0xf7be,0xf7bf,
+ 0xf7c0,0xf7c1,0xf7c2,0xf7c3,0xf7c4,0xf7c5,0xf7c6,0xf7c7,
+ 0xf7c8,0xf7c9,0xf7ca,0xf7cb,0xf7cc,0xf7cd,0xf7ce,0xf7cf,
+ 0xf7d0,0xf7d1,0xf7d2,0xf7d3,0xf7d4,0xf7d5,0xf7d6,0xf7d7,
+ 0xf7d8,0xf7d9,0xf7da,0xf7db,0xf7dc,0xf7dd,0xf7de,0xf7df,
+ 0xf7e0,0xf7e1,0xf7e2,0xf7e3,0xf7e4,0xf7e5,0xf7e6,0xf7e7,
+ 0xf7e8,0xf7e9,0xf7ea,0xf7eb,0xf7ec,0xf7ed,0xf7ee,0xf7ef,
+ 0xf7f0,0xf7f1,0xf7f2,0xf7f3,0xf7f4,0xf7f5,0xf7f6,0xf7f7,
+ 0xf7f8,0xf7f9,0xf7fa,0xf7fb,0xf7fc,0xf7fd,0xf7fe,0xf7ff,
+ 0xf800,0xf801,0xf802,0xf803,0xf804,0xf805,0xf806,0xf807,
+ 0xf808,0xf809,0xf80a,0xf80b,0xf80c,0xf80d,0xf80e,0xf80f,
+ 0xf810,0xf811,0xf812,0xf813,0xf814,0xf815,0xf816,0xf817,
+ 0xf818,0xf819,0xf81a,0xf81b,0xf81c,0xf81d,0xf81e,0xf81f,
+ 0xf820,0xf821,0xf822,0xf823,0xf824,0xf825,0xf826,0xf827,
+ 0xf828,0xf829,0xf82a,0xf82b,0xf82c,0xf82d,0xf82e,0xf82f,
+ 0xf830,0xf831,0xf832,0xf833,0xf834,0xf835,0xf836,0xf837,
+ 0xf838,0xf839,0xf83a,0xf83b,0xf83c,0xf83d,0xf83e,0xf83f,
+ 0xf840,0xf841,0xf842,0xf843,0xf844,0xf845,0xf846,0xf847,
+ 0xf848,0xf849,0xf84a,0xf84b,0xf84c,0xf84d,0xf84e,0xf84f,
+ 0xf850,0xf851,0xf852,0xf853,0xf854,0xf855,0xf856,0xf857,
+ 0xf858,0xf859,0xf85a,0xf85b,0xf85c,0xf85d,0xf85e,0xf85f,
+ 0xf860,0xf861,0xf862,0xf863,0xf864,0xf865,0xf866,0xf867,
+ 0xf868,0xf869,0xf86a,0xf86b,0xf86c,0xf86d,0xf86e,0xf86f,
+ 0xf870,0xf871,0xf872,0xf873,0xf874,0xf875,0xf876,0xf877,
+ 0xf878,0xf879,0xf87a,0xf87b,0xf87c,0xf87d,0xf87e,0xf87f,
+ 0xf880,0xf881,0xf882,0xf883,0xf884,0xf885,0xf886,0xf887,
+ 0xf888,0xf889,0xf88a,0xf88b,0xf88c,0xf88d,0xf88e,0xf88f,
+ 0xf890,0xf891,0xf892,0xf893,0xf894,0xf895,0xf896,0xf897,
+ 0xf898,0xf899,0xf89a,0xf89b,0xf89c,0xf89d,0xf89e,0xf89f,
+ 0xf8a0,0xf8a1,0xf8a2,0xf8a3,0xf8a4,0xf8a5,0xf8a6,0xf8a7,
+ 0xf8a8,0xf8a9,0xf8aa,0xf8ab,0xf8ac,0xf8ad,0xf8ae,0xf8af,
+ 0xf8b0,0xf8b1,0xf8b2,0xf8b3,0xf8b4,0xf8b5,0xf8b6,0xf8b7,
+ 0xf8b8,0xf8b9,0xf8ba,0xf8bb,0xf8bc,0xf8bd,0xf8be,0xf8bf,
+ 0xf8c0,0xf8c1,0xf8c2,0xf8c3,0xf8c4,0xf8c5,0xf8c6,0xf8c7,
+ 0xf8c8,0xf8c9,0xf8ca,0xf8cb,0xf8cc,0xf8cd,0xf8ce,0xf8cf,
+ 0xf8d0,0xf8d1,0xf8d2,0xf8d3,0xf8d4,0xf8d5,0xf8d6,0xf8d7,
+ 0xf8d8,0xf8d9,0xf8da,0xf8db,0xf8dc,0xf8dd,0xf8de,0xf8df,
+ 0xf8e0,0xf8e1,0xf8e2,0xf8e3,0xf8e4,0xf8e5,0xf8e6,0xf8e7,
+ 0xf8e8,0xf8e9,0xf8ea,0xf8eb,0xf8ec,0xf8ed,0xf8ee,0xf8ef,
+ 0xf8f0,0xf8f1,0xf8f2,0xf8f3,0xf8f4,0xf8f5,0xf8f6,0xf8f7,
+ 0xf8f8,0xf8f9,0xf8fa,0xf8fb,0xf8fc,0xf8fd,0xf8fe,0xf8ff,
+ 0xf900,0xf901,0xf902,0xf903,0xf904,0xf905,0xf906,0xf907,
+ 0xf908,0xf909,0xf90a,0xf90b,0xf90c,0xf90d,0xf90e,0xf90f,
+ 0xf910,0xf911,0xf912,0xf913,0xf914,0xf915,0xf916,0xf917,
+ 0xf918,0xf919,0xf91a,0xf91b,0xf91c,0xf91d,0xf91e,0xf91f,
+ 0xf920,0xf921,0xf922,0xf923,0xf924,0xf925,0xf926,0xf927,
+ 0xf928,0xf929,0xf92a,0xf92b,0xf92c,0xf92d,0xf92e,0xf92f,
+ 0xf930,0xf931,0xf932,0xf933,0xf934,0xf935,0xf936,0xf937,
+ 0xf938,0xf939,0xf93a,0xf93b,0xf93c,0xf93d,0xf93e,0xf93f,
+ 0xf940,0xf941,0xf942,0xf943,0xf944,0xf945,0xf946,0xf947,
+ 0xf948,0xf949,0xf94a,0xf94b,0xf94c,0xf94d,0xf94e,0xf94f,
+ 0xf950,0xf951,0xf952,0xf953,0xf954,0xf955,0xf956,0xf957,
+ 0xf958,0xf959,0xf95a,0xf95b,0xf95c,0xf95d,0xf95e,0xf95f,
+ 0xf960,0xf961,0xf962,0xf963,0xf964,0xf965,0xf966,0xf967,
+ 0xf968,0xf969,0xf96a,0xf96b,0xf96c,0xf96d,0xf96e,0xf96f,
+ 0xf970,0xf971,0xf972,0xf973,0xf974,0xf975,0xf976,0xf977,
+ 0xf978,0xf979,0xf97a,0xf97b,0xf97c,0xf97d,0xf97e,0xf97f,
+ 0xf980,0xf981,0xf982,0xf983,0xf984,0xf985,0xf986,0xf987,
+ 0xf988,0xf989,0xf98a,0xf98b,0xf98c,0xf98d,0xf98e,0xf98f,
+ 0xf990,0xf991,0xf992,0xf993,0xf994,0xf995,0xf996,0xf997,
+ 0xf998,0xf999,0xf99a,0xf99b,0xf99c,0xf99d,0xf99e,0xf99f,
+ 0xf9a0,0xf9a1,0xf9a2,0xf9a3,0xf9a4,0xf9a5,0xf9a6,0xf9a7,
+ 0xf9a8,0xf9a9,0xf9aa,0xf9ab,0xf9ac,0xf9ad,0xf9ae,0xf9af,
+ 0xf9b0,0xf9b1,0xf9b2,0xf9b3,0xf9b4,0xf9b5,0xf9b6,0xf9b7,
+ 0xf9b8,0xf9b9,0xf9ba,0xf9bb,0xf9bc,0xf9bd,0xf9be,0xf9bf,
+ 0xf9c0,0xf9c1,0xf9c2,0xf9c3,0xf9c4,0xf9c5,0xf9c6,0xf9c7,
+ 0xf9c8,0xf9c9,0xf9ca,0xf9cb,0xf9cc,0xf9cd,0xf9ce,0xf9cf,
+ 0xf9d0,0xf9d1,0xf9d2,0xf9d3,0xf9d4,0xf9d5,0xf9d6,0xf9d7,
+ 0xf9d8,0xf9d9,0xf9da,0xf9db,0xf9dc,0xf9dd,0xf9de,0xf9df,
+ 0xf9e0,0xf9e1,0xf9e2,0xf9e3,0xf9e4,0xf9e5,0xf9e6,0xf9e7,
+ 0xf9e8,0xf9e9,0xf9ea,0xf9eb,0xf9ec,0xf9ed,0xf9ee,0xf9ef,
+ 0xf9f0,0xf9f1,0xf9f2,0xf9f3,0xf9f4,0xf9f5,0xf9f6,0xf9f7,
+ 0xf9f8,0xf9f9,0xf9fa,0xf9fb,0xf9fc,0xf9fd,0xf9fe,0xf9ff,
+ 0xfa00,0xfa01,0xfa02,0xfa03,0xfa04,0xfa05,0xfa06,0xfa07,
+ 0xfa08,0xfa09,0xfa0a,0xfa0b,0xfa0c,0xfa0d,0xfa0e,0xfa0f,
+ 0xfa10,0xfa11,0xfa12,0xfa13,0xfa14,0xfa15,0xfa16,0xfa17,
+ 0xfa18,0xfa19,0xfa1a,0xfa1b,0xfa1c,0xfa1d,0xfa1e,0xfa1f,
+ 0xfa20,0xfa21,0xfa22,0xfa23,0xfa24,0xfa25,0xfa26,0xfa27,
+ 0xfa28,0xfa29,0xfa2a,0xfa2b,0xfa2c,0xfa2d,0xfa2e,0xfa2f,
+ 0xfa30,0xfa31,0xfa32,0xfa33,0xfa34,0xfa35,0xfa36,0xfa37,
+ 0xfa38,0xfa39,0xfa3a,0xfa3b,0xfa3c,0xfa3d,0xfa3e,0xfa3f,
+ 0xfa40,0xfa41,0xfa42,0xfa43,0xfa44,0xfa45,0xfa46,0xfa47,
+ 0xfa48,0xfa49,0xfa4a,0xfa4b,0xfa4c,0xfa4d,0xfa4e,0xfa4f,
+ 0xfa50,0xfa51,0xfa52,0xfa53,0xfa54,0xfa55,0xfa56,0xfa57,
+ 0xfa58,0xfa59,0xfa5a,0xfa5b,0xfa5c,0xfa5d,0xfa5e,0xfa5f,
+ 0xfa60,0xfa61,0xfa62,0xfa63,0xfa64,0xfa65,0xfa66,0xfa67,
+ 0xfa68,0xfa69,0xfa6a,0xfa6b,0xfa6c,0xfa6d,0xfa6e,0xfa6f,
+ 0xfa70,0xfa71,0xfa72,0xfa73,0xfa74,0xfa75,0xfa76,0xfa77,
+ 0xfa78,0xfa79,0xfa7a,0xfa7b,0xfa7c,0xfa7d,0xfa7e,0xfa7f,
+ 0xfa80,0xfa81,0xfa82,0xfa83,0xfa84,0xfa85,0xfa86,0xfa87,
+ 0xfa88,0xfa89,0xfa8a,0xfa8b,0xfa8c,0xfa8d,0xfa8e,0xfa8f,
+ 0xfa90,0xfa91,0xfa92,0xfa93,0xfa94,0xfa95,0xfa96,0xfa97,
+ 0xfa98,0xfa99,0xfa9a,0xfa9b,0xfa9c,0xfa9d,0xfa9e,0xfa9f,
+ 0xfaa0,0xfaa1,0xfaa2,0xfaa3,0xfaa4,0xfaa5,0xfaa6,0xfaa7,
+ 0xfaa8,0xfaa9,0xfaaa,0xfaab,0xfaac,0xfaad,0xfaae,0xfaaf,
+ 0xfab0,0xfab1,0xfab2,0xfab3,0xfab4,0xfab5,0xfab6,0xfab7,
+ 0xfab8,0xfab9,0xfaba,0xfabb,0xfabc,0xfabd,0xfabe,0xfabf,
+ 0xfac0,0xfac1,0xfac2,0xfac3,0xfac4,0xfac5,0xfac6,0xfac7,
+ 0xfac8,0xfac9,0xfaca,0xfacb,0xfacc,0xfacd,0xface,0xfacf,
+ 0xfad0,0xfad1,0xfad2,0xfad3,0xfad4,0xfad5,0xfad6,0xfad7,
+ 0xfad8,0xfad9,0xfada,0xfadb,0xfadc,0xfadd,0xfade,0xfadf,
+ 0xfae0,0xfae1,0xfae2,0xfae3,0xfae4,0xfae5,0xfae6,0xfae7,
+ 0xfae8,0xfae9,0xfaea,0xfaeb,0xfaec,0xfaed,0xfaee,0xfaef,
+ 0xfaf0,0xfaf1,0xfaf2,0xfaf3,0xfaf4,0xfaf5,0xfaf6,0xfaf7,
+ 0xfaf8,0xfaf9,0xfafa,0xfafb,0xfafc,0xfafd,0xfafe,0xfaff,
+ 0xfb00,0xfb01,0xfb02,0xfb03,0xfb04,0xfb05,0xfb06,0xfb07,
+ 0xfb08,0xfb09,0xfb0a,0xfb0b,0xfb0c,0xfb0d,0xfb0e,0xfb0f,
+ 0xfb10,0xfb11,0xfb12,0xfb13,0xfb14,0xfb15,0xfb16,0xfb17,
+ 0xfb18,0xfb19,0xfb1a,0xfb1b,0xfb1c,0xfb1d,0xfb1e,0xfb1f,
+ 0xfb20,0xfb21,0xfb22,0xfb23,0xfb24,0xfb25,0xfb26,0xfb27,
+ 0xfb28,0xfb29,0xfb2a,0xfb2b,0xfb2c,0xfb2d,0xfb2e,0xfb2f,
+ 0xfb30,0xfb31,0xfb32,0xfb33,0xfb34,0xfb35,0xfb36,0xfb37,
+ 0xfb38,0xfb39,0xfb3a,0xfb3b,0xfb3c,0xfb3d,0xfb3e,0xfb3f,
+ 0xfb40,0xfb41,0xfb42,0xfb43,0xfb44,0xfb45,0xfb46,0xfb47,
+ 0xfb48,0xfb49,0xfb4a,0xfb4b,0xfb4c,0xfb4d,0xfb4e,0xfb4f,
+ 0xfb50,0xfb51,0xfb52,0xfb53,0xfb54,0xfb55,0xfb56,0xfb57,
+ 0xfb58,0xfb59,0xfb5a,0xfb5b,0xfb5c,0xfb5d,0xfb5e,0xfb5f,
+ 0xfb60,0xfb61,0xfb62,0xfb63,0xfb64,0xfb65,0xfb66,0xfb67,
+ 0xfb68,0xfb69,0xfb6a,0xfb6b,0xfb6c,0xfb6d,0xfb6e,0xfb6f,
+ 0xfb70,0xfb71,0xfb72,0xfb73,0xfb74,0xfb75,0xfb76,0xfb77,
+ 0xfb78,0xfb79,0xfb7a,0xfb7b,0xfb7c,0xfb7d,0xfb7e,0xfb7f,
+ 0xfb80,0xfb81,0xfb82,0xfb83,0xfb84,0xfb85,0xfb86,0xfb87,
+ 0xfb88,0xfb89,0xfb8a,0xfb8b,0xfb8c,0xfb8d,0xfb8e,0xfb8f,
+ 0xfb90,0xfb91,0xfb92,0xfb93,0xfb94,0xfb95,0xfb96,0xfb97,
+ 0xfb98,0xfb99,0xfb9a,0xfb9b,0xfb9c,0xfb9d,0xfb9e,0xfb9f,
+ 0xfba0,0xfba1,0xfba2,0xfba3,0xfba4,0xfba5,0xfba6,0xfba7,
+ 0xfba8,0xfba9,0xfbaa,0xfbab,0xfbac,0xfbad,0xfbae,0xfbaf,
+ 0xfbb0,0xfbb1,0xfbb2,0xfbb3,0xfbb4,0xfbb5,0xfbb6,0xfbb7,
+ 0xfbb8,0xfbb9,0xfbba,0xfbbb,0xfbbc,0xfbbd,0xfbbe,0xfbbf,
+ 0xfbc0,0xfbc1,0xfbc2,0xfbc3,0xfbc4,0xfbc5,0xfbc6,0xfbc7,
+ 0xfbc8,0xfbc9,0xfbca,0xfbcb,0xfbcc,0xfbcd,0xfbce,0xfbcf,
+ 0xfbd0,0xfbd1,0xfbd2,0xfbd3,0xfbd4,0xfbd5,0xfbd6,0xfbd7,
+ 0xfbd8,0xfbd9,0xfbda,0xfbdb,0xfbdc,0xfbdd,0xfbde,0xfbdf,
+ 0xfbe0,0xfbe1,0xfbe2,0xfbe3,0xfbe4,0xfbe5,0xfbe6,0xfbe7,
+ 0xfbe8,0xfbe9,0xfbea,0xfbeb,0xfbec,0xfbed,0xfbee,0xfbef,
+ 0xfbf0,0xfbf1,0xfbf2,0xfbf3,0xfbf4,0xfbf5,0xfbf6,0xfbf7,
+ 0xfbf8,0xfbf9,0xfbfa,0xfbfb,0xfbfc,0xfbfd,0xfbfe,0xfbff,
+ 0xfc00,0xfc01,0xfc02,0xfc03,0xfc04,0xfc05,0xfc06,0xfc07,
+ 0xfc08,0xfc09,0xfc0a,0xfc0b,0xfc0c,0xfc0d,0xfc0e,0xfc0f,
+ 0xfc10,0xfc11,0xfc12,0xfc13,0xfc14,0xfc15,0xfc16,0xfc17,
+ 0xfc18,0xfc19,0xfc1a,0xfc1b,0xfc1c,0xfc1d,0xfc1e,0xfc1f,
+ 0xfc20,0xfc21,0xfc22,0xfc23,0xfc24,0xfc25,0xfc26,0xfc27,
+ 0xfc28,0xfc29,0xfc2a,0xfc2b,0xfc2c,0xfc2d,0xfc2e,0xfc2f,
+ 0xfc30,0xfc31,0xfc32,0xfc33,0xfc34,0xfc35,0xfc36,0xfc37,
+ 0xfc38,0xfc39,0xfc3a,0xfc3b,0xfc3c,0xfc3d,0xfc3e,0xfc3f,
+ 0xfc40,0xfc41,0xfc42,0xfc43,0xfc44,0xfc45,0xfc46,0xfc47,
+ 0xfc48,0xfc49,0xfc4a,0xfc4b,0xfc4c,0xfc4d,0xfc4e,0xfc4f,
+ 0xfc50,0xfc51,0xfc52,0xfc53,0xfc54,0xfc55,0xfc56,0xfc57,
+ 0xfc58,0xfc59,0xfc5a,0xfc5b,0xfc5c,0xfc5d,0xfc5e,0xfc5f,
+ 0xfc60,0xfc61,0xfc62,0xfc63,0xfc64,0xfc65,0xfc66,0xfc67,
+ 0xfc68,0xfc69,0xfc6a,0xfc6b,0xfc6c,0xfc6d,0xfc6e,0xfc6f,
+ 0xfc70,0xfc71,0xfc72,0xfc73,0xfc74,0xfc75,0xfc76,0xfc77,
+ 0xfc78,0xfc79,0xfc7a,0xfc7b,0xfc7c,0xfc7d,0xfc7e,0xfc7f,
+ 0xfc80,0xfc81,0xfc82,0xfc83,0xfc84,0xfc85,0xfc86,0xfc87,
+ 0xfc88,0xfc89,0xfc8a,0xfc8b,0xfc8c,0xfc8d,0xfc8e,0xfc8f,
+ 0xfc90,0xfc91,0xfc92,0xfc93,0xfc94,0xfc95,0xfc96,0xfc97,
+ 0xfc98,0xfc99,0xfc9a,0xfc9b,0xfc9c,0xfc9d,0xfc9e,0xfc9f,
+ 0xfca0,0xfca1,0xfca2,0xfca3,0xfca4,0xfca5,0xfca6,0xfca7,
+ 0xfca8,0xfca9,0xfcaa,0xfcab,0xfcac,0xfcad,0xfcae,0xfcaf,
+ 0xfcb0,0xfcb1,0xfcb2,0xfcb3,0xfcb4,0xfcb5,0xfcb6,0xfcb7,
+ 0xfcb8,0xfcb9,0xfcba,0xfcbb,0xfcbc,0xfcbd,0xfcbe,0xfcbf,
+ 0xfcc0,0xfcc1,0xfcc2,0xfcc3,0xfcc4,0xfcc5,0xfcc6,0xfcc7,
+ 0xfcc8,0xfcc9,0xfcca,0xfccb,0xfccc,0xfccd,0xfcce,0xfccf,
+ 0xfcd0,0xfcd1,0xfcd2,0xfcd3,0xfcd4,0xfcd5,0xfcd6,0xfcd7,
+ 0xfcd8,0xfcd9,0xfcda,0xfcdb,0xfcdc,0xfcdd,0xfcde,0xfcdf,
+ 0xfce0,0xfce1,0xfce2,0xfce3,0xfce4,0xfce5,0xfce6,0xfce7,
+ 0xfce8,0xfce9,0xfcea,0xfceb,0xfcec,0xfced,0xfcee,0xfcef,
+ 0xfcf0,0xfcf1,0xfcf2,0xfcf3,0xfcf4,0xfcf5,0xfcf6,0xfcf7,
+ 0xfcf8,0xfcf9,0xfcfa,0xfcfb,0xfcfc,0xfcfd,0xfcfe,0xfcff,
+ 0xfd00,0xfd01,0xfd02,0xfd03,0xfd04,0xfd05,0xfd06,0xfd07,
+ 0xfd08,0xfd09,0xfd0a,0xfd0b,0xfd0c,0xfd0d,0xfd0e,0xfd0f,
+ 0xfd10,0xfd11,0xfd12,0xfd13,0xfd14,0xfd15,0xfd16,0xfd17,
+ 0xfd18,0xfd19,0xfd1a,0xfd1b,0xfd1c,0xfd1d,0xfd1e,0xfd1f,
+ 0xfd20,0xfd21,0xfd22,0xfd23,0xfd24,0xfd25,0xfd26,0xfd27,
+ 0xfd28,0xfd29,0xfd2a,0xfd2b,0xfd2c,0xfd2d,0xfd2e,0xfd2f,
+ 0xfd30,0xfd31,0xfd32,0xfd33,0xfd34,0xfd35,0xfd36,0xfd37,
+ 0xfd38,0xfd39,0xfd3a,0xfd3b,0xfd3c,0xfd3d,0xfd3e,0xfd3f,
+ 0xfd40,0xfd41,0xfd42,0xfd43,0xfd44,0xfd45,0xfd46,0xfd47,
+ 0xfd48,0xfd49,0xfd4a,0xfd4b,0xfd4c,0xfd4d,0xfd4e,0xfd4f,
+ 0xfd50,0xfd51,0xfd52,0xfd53,0xfd54,0xfd55,0xfd56,0xfd57,
+ 0xfd58,0xfd59,0xfd5a,0xfd5b,0xfd5c,0xfd5d,0xfd5e,0xfd5f,
+ 0xfd60,0xfd61,0xfd62,0xfd63,0xfd64,0xfd65,0xfd66,0xfd67,
+ 0xfd68,0xfd69,0xfd6a,0xfd6b,0xfd6c,0xfd6d,0xfd6e,0xfd6f,
+ 0xfd70,0xfd71,0xfd72,0xfd73,0xfd74,0xfd75,0xfd76,0xfd77,
+ 0xfd78,0xfd79,0xfd7a,0xfd7b,0xfd7c,0xfd7d,0xfd7e,0xfd7f,
+ 0xfd80,0xfd81,0xfd82,0xfd83,0xfd84,0xfd85,0xfd86,0xfd87,
+ 0xfd88,0xfd89,0xfd8a,0xfd8b,0xfd8c,0xfd8d,0xfd8e,0xfd8f,
+ 0xfd90,0xfd91,0xfd92,0xfd93,0xfd94,0xfd95,0xfd96,0xfd97,
+ 0xfd98,0xfd99,0xfd9a,0xfd9b,0xfd9c,0xfd9d,0xfd9e,0xfd9f,
+ 0xfda0,0xfda1,0xfda2,0xfda3,0xfda4,0xfda5,0xfda6,0xfda7,
+ 0xfda8,0xfda9,0xfdaa,0xfdab,0xfdac,0xfdad,0xfdae,0xfdaf,
+ 0xfdb0,0xfdb1,0xfdb2,0xfdb3,0xfdb4,0xfdb5,0xfdb6,0xfdb7,
+ 0xfdb8,0xfdb9,0xfdba,0xfdbb,0xfdbc,0xfdbd,0xfdbe,0xfdbf,
+ 0xfdc0,0xfdc1,0xfdc2,0xfdc3,0xfdc4,0xfdc5,0xfdc6,0xfdc7,
+ 0xfdc8,0xfdc9,0xfdca,0xfdcb,0xfdcc,0xfdcd,0xfdce,0xfdcf,
+ 0xfdd0,0xfdd1,0xfdd2,0xfdd3,0xfdd4,0xfdd5,0xfdd6,0xfdd7,
+ 0xfdd8,0xfdd9,0xfdda,0xfddb,0xfddc,0xfddd,0xfdde,0xfddf,
+ 0xfde0,0xfde1,0xfde2,0xfde3,0xfde4,0xfde5,0xfde6,0xfde7,
+ 0xfde8,0xfde9,0xfdea,0xfdeb,0xfdec,0xfded,0xfdee,0xfdef,
+ 0xfdf0,0xfdf1,0xfdf2,0xfdf3,0xfdf4,0xfdf5,0xfdf6,0xfdf7,
+ 0xfdf8,0xfdf9,0xfdfa,0xfdfb,0xfdfc,0xfdfd,0xfdfe,0xfdff,
+ 0xfe00,0xfe01,0xfe02,0xfe03,0xfe04,0xfe05,0xfe06,0xfe07,
+ 0xfe08,0xfe09,0xfe0a,0xfe0b,0xfe0c,0xfe0d,0xfe0e,0xfe0f,
+ 0xfe10,0xfe11,0xfe12,0xfe13,0xfe14,0xfe15,0xfe16,0xfe17,
+ 0xfe18,0xfe19,0xfe1a,0xfe1b,0xfe1c,0xfe1d,0xfe1e,0xfe1f,
+ 0xfe20,0xfe21,0xfe22,0xfe23,0xfe24,0xfe25,0xfe26,0xfe27,
+ 0xfe28,0xfe29,0xfe2a,0xfe2b,0xfe2c,0xfe2d,0xfe2e,0xfe2f,
+ 0xfe30,0xfe31,0xfe32,0xfe33,0xfe34,0xfe35,0xfe36,0xfe37,
+ 0xfe38,0xfe39,0xfe3a,0xfe3b,0xfe3c,0xfe3d,0xfe3e,0xfe3f,
+ 0xfe40,0xfe41,0xfe42,0xfe43,0xfe44,0xfe45,0xfe46,0xfe47,
+ 0xfe48,0xfe49,0xfe4a,0xfe4b,0xfe4c,0xfe4d,0xfe4e,0xfe4f,
+ 0xfe50,0xfe51,0xfe52,0xfe53,0xfe54,0xfe55,0xfe56,0xfe57,
+ 0xfe58,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e,0xfe5f,
+ 0xfe60,0xfe61,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0xfe67,
+ 0xfe68,0xfe69,0xfe6a,0xfe6b,0xfe6c,0xfe6d,0xfe6e,0xfe6f,
+ 0xfe70,0xfe71,0xfe72,0xfe73,0xfe74,0xfe75,0xfe76,0xfe77,
+ 0xfe78,0xfe79,0xfe7a,0xfe7b,0xfe7c,0xfe7d,0xfe7e,0xfe7f,
+ 0xfe80,0xfe81,0xfe82,0xfe83,0xfe84,0xfe85,0xfe86,0xfe87,
+ 0xfe88,0xfe89,0xfe8a,0xfe8b,0xfe8c,0xfe8d,0xfe8e,0xfe8f,
+ 0xfe90,0xfe91,0xfe92,0xfe93,0xfe94,0xfe95,0xfe96,0xfe97,
+ 0xfe98,0xfe99,0xfe9a,0xfe9b,0xfe9c,0xfe9d,0xfe9e,0xfe9f,
+ 0xfea0,0xfea1,0xfea2,0xfea3,0xfea4,0xfea5,0xfea6,0xfea7,
+ 0xfea8,0xfea9,0xfeaa,0xfeab,0xfeac,0xfead,0xfeae,0xfeaf,
+ 0xfeb0,0xfeb1,0xfeb2,0xfeb3,0xfeb4,0xfeb5,0xfeb6,0xfeb7,
+ 0xfeb8,0xfeb9,0xfeba,0xfebb,0xfebc,0xfebd,0xfebe,0xfebf,
+ 0xfec0,0xfec1,0xfec2,0xfec3,0xfec4,0xfec5,0xfec6,0xfec7,
+ 0xfec8,0xfec9,0xfeca,0xfecb,0xfecc,0xfecd,0xfece,0xfecf,
+ 0xfed0,0xfed1,0xfed2,0xfed3,0xfed4,0xfed5,0xfed6,0xfed7,
+ 0xfed8,0xfed9,0xfeda,0xfedb,0xfedc,0xfedd,0xfede,0xfedf,
+ 0xfee0,0xfee1,0xfee2,0xfee3,0xfee4,0xfee5,0xfee6,0xfee7,
+ 0xfee8,0xfee9,0xfeea,0xfeeb,0xfeec,0xfeed,0xfeee,0xfeef,
+ 0xfef0,0xfef1,0xfef2,0xfef3,0xfef4,0xfef5,0xfef6,0xfef7,
+ 0xfef8,0xfef9,0xfefa,0xfefb,0xfefc,0xfefd,0xfefe,0xfeff,
+ 0xff00,0xff01,0xff02,0xff03,0xff04,0xff05,0xff06,0xff07,
+ 0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,
+ 0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,
+ 0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,
+ 0xff20,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,
+ 0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,
+ 0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,
+ 0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f,
+ 0xff40,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,
+ 0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,
+ 0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,
+ 0xff38,0xff39,0xff3a,0xff5b,0xff5c,0xff5d,0xff5e,0xff5f,
+ 0xff60,0xff61,0xff62,0xff63,0xff64,0xff65,0xff66,0xff67,
+ 0xff68,0xff69,0xff6a,0xff6b,0xff6c,0xff6d,0xff6e,0xff6f,
+ 0xff70,0xff71,0xff72,0xff73,0xff74,0xff75,0xff76,0xff77,
+ 0xff78,0xff79,0xff7a,0xff7b,0xff7c,0xff7d,0xff7e,0xff7f,
+ 0xff80,0xff81,0xff82,0xff83,0xff84,0xff85,0xff86,0xff87,
+ 0xff88,0xff89,0xff8a,0xff8b,0xff8c,0xff8d,0xff8e,0xff8f,
+ 0xff90,0xff91,0xff92,0xff93,0xff94,0xff95,0xff96,0xff97,
+ 0xff98,0xff99,0xff9a,0xff9b,0xff9c,0xff9d,0xff9e,0xff9f,
+ 0xffa0,0xffa1,0xffa2,0xffa3,0xffa4,0xffa5,0xffa6,0xffa7,
+ 0xffa8,0xffa9,0xffaa,0xffab,0xffac,0xffad,0xffae,0xffaf,
+ 0xffb0,0xffb1,0xffb2,0xffb3,0xffb4,0xffb5,0xffb6,0xffb7,
+ 0xffb8,0xffb9,0xffba,0xffbb,0xffbc,0xffbd,0xffbe,0xffbf,
+ 0xffc0,0xffc1,0xffc2,0xffc3,0xffc4,0xffc5,0xffc6,0xffc7,
+ 0xffc8,0xffc9,0xffca,0xffcb,0xffcc,0xffcd,0xffce,0xffcf,
+ 0xffd0,0xffd1,0xffd2,0xffd3,0xffd4,0xffd5,0xffd6,0xffd7,
+ 0xffd8,0xffd9,0xffda,0xffdb,0xffdc,0xffdd,0xffde,0xffdf,
+ 0xffe0,0xffe1,0xffe2,0xffe3,0xffe4,0xffe5,0xffe6,0xffe7,
+ 0xffe8,0xffe9,0xffea,0xffeb,0xffec,0xffed,0xffee,0xffef,
+ 0xfff0,0xfff1,0xfff2,0xfff3,0xfff4,0xfff5,0xfff6,0xfff7,
+ 0xfff8,0xfff9,0xfffa,0xfffb,0xfffc,0xfffd,0xfffe,0xffff
+};
+
+void smb_init_locale(void)
+{
+ /* This is a useful global hook where we can ensure that the
+ * locale is set from the environment. This is needed so that
+ * we can use LOCALE as a codepage */
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, "");
+#endif
+}
+
+/**
+ Convert a codepoint_t to upper case.
+**/
+_PUBLIC_ codepoint_t toupper_m(codepoint_t val)
+{
+ if (val >= ARRAY_SIZE(upcase_table)) {
+ return val;
+ }
+ return upcase_table[val];
+}
+
+/**
+ Convert a codepoint_t to lower case.
+**/
+_PUBLIC_ codepoint_t tolower_m(codepoint_t val)
+{
+ if (val >= ARRAY_SIZE(lowcase_table)) {
+ return val;
+ }
+ return lowcase_table[val];
+}
+
+/**
+ If we upper cased this character, would we get the same character?
+**/
+_PUBLIC_ bool islower_m(codepoint_t val)
+{
+ return (toupper_m(val) != val);
+}
+
+/**
+ If we lower cased this character, would we get the same character?
+**/
+_PUBLIC_ bool isupper_m(codepoint_t val)
+{
+ return (tolower_m(val) != val);
+}
+
+/**
+ compare two codepoints case insensitively
+*/
+_PUBLIC_ int codepoint_cmpi(codepoint_t c1, codepoint_t c2)
+{
+ if (c1 == c2 ||
+ toupper_m(c1) == toupper_m(c2)) {
+ return 0;
+ }
+ return c1 - c2;
+}
+
+
+struct smb_iconv_handle {
+ TALLOC_CTX *child_ctx;
+ const char *unix_charset;
+ const char *dos_charset;
+ const char *display_charset;
+ bool use_builtin_handlers;
+ smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
+};
+
+static struct smb_iconv_handle *global_iconv_handle = NULL;
+
+struct smb_iconv_handle *get_iconv_handle(void)
+{
+ if (global_iconv_handle == NULL) {
+ global_iconv_handle =
+ smb_iconv_handle_reinit(NULL,
+ "ASCII",
+ "UTF-8",
+ true,
+ NULL);
+ }
+
+ return global_iconv_handle;
+}
+
+struct smb_iconv_handle *get_iconv_testing_handle(TALLOC_CTX *mem_ctx,
+ const char *dos_charset,
+ const char *unix_charset,
+ bool use_builtin_handlers)
+{
+ return smb_iconv_handle_reinit(mem_ctx,
+ dos_charset, unix_charset, use_builtin_handlers, NULL);
+}
+
+struct smb_iconv_handle *reinit_iconv_handle(TALLOC_CTX *mem_ctx,
+ const char *dos_charset,
+ const char *unix_charset)
+{
+ global_iconv_handle =
+ smb_iconv_handle_reinit(mem_ctx,
+ dos_charset,
+ unix_charset,
+ true,
+ global_iconv_handle);
+ return global_iconv_handle;
+}
+
+void free_iconv_handle(void)
+{
+ TALLOC_FREE(global_iconv_handle);
+}
+
+/**
+ * Return the name of a charset to give to iconv().
+ **/
+const char *charset_name(struct smb_iconv_handle *ic, charset_t ch)
+{
+ switch (ch) {
+ case CH_UTF16: return "UTF-16LE";
+ case CH_UNIX: return ic->unix_charset;
+ case CH_DOS: return ic->dos_charset;
+ case CH_UTF8: return "UTF8";
+ case CH_UTF16BE: return "UTF-16BE";
+ case CH_UTF16MUNGED: return "UTF16_MUNGED";
+ default:
+ return "ASCII";
+ }
+}
+
+/**
+ re-initialize iconv conversion descriptors
+**/
+static int close_iconv_handle(struct smb_iconv_handle *data)
+{
+ unsigned c1, c2;
+ for (c1=0;c1<NUM_CHARSETS;c1++) {
+ for (c2=0;c2<NUM_CHARSETS;c2++) {
+ if (data->conv_handles[c1][c2] != NULL) {
+ if (data->conv_handles[c1][c2] != (smb_iconv_t)-1) {
+ smb_iconv_close(data->conv_handles[c1][c2]);
+ }
+ data->conv_handles[c1][c2] = NULL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ the old_ic is passed in here as the smb_iconv_handle structure
+ is used as a global pointer in some places (eg. python modules). We
+ don't want to invalidate those global pointers, but we do want to
+ update them with the right charset information when loadparm
+ runs. To do that we need to re-use the structure pointer, but
+ re-fill the elements in the structure with the updated values
+ */
+_PUBLIC_ struct smb_iconv_handle *smb_iconv_handle_reinit(TALLOC_CTX *mem_ctx,
+ const char *dos_charset,
+ const char *unix_charset,
+ bool use_builtin_handlers,
+ struct smb_iconv_handle *old_ic)
+{
+ struct smb_iconv_handle *ret;
+
+ if (old_ic != NULL) {
+ ret = old_ic;
+ close_iconv_handle(ret);
+ talloc_free(ret->child_ctx);
+ ZERO_STRUCTP(ret);
+ } else {
+ ret = talloc_zero(mem_ctx, struct smb_iconv_handle);
+ }
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ /* we use a child context to allow us to free all ptrs without
+ freeing the structure itself */
+ ret->child_ctx = talloc_new(ret);
+ if (ret->child_ctx == NULL) {
+ return NULL;
+ }
+
+ talloc_set_destructor(ret, close_iconv_handle);
+
+ if (strcasecmp(dos_charset, "UTF8") == 0 || strcasecmp(dos_charset, "UTF-8") == 0) {
+ DEBUG(0,("ERROR: invalid DOS charset: 'dos charset' must not be UTF8, using (default value) CP850 instead\n"));
+ dos_charset = "CP850";
+ }
+
+ ret->dos_charset = talloc_strdup(ret->child_ctx, dos_charset);
+ ret->unix_charset = talloc_strdup(ret->child_ctx, unix_charset);
+ ret->use_builtin_handlers = use_builtin_handlers;
+
+ return ret;
+}
+
+/*
+ on-demand initialisation of conversion handles
+*/
+smb_iconv_t get_conv_handle(struct smb_iconv_handle *ic,
+ charset_t from, charset_t to)
+{
+ const char *n1, *n2;
+
+ if (ic->conv_handles[from][to]) {
+ return ic->conv_handles[from][to];
+ }
+
+ n1 = charset_name(ic, from);
+ n2 = charset_name(ic, to);
+
+ ic->conv_handles[from][to] = smb_iconv_open_ex(ic, n2, n1,
+ ic->use_builtin_handlers);
+
+ if (ic->conv_handles[from][to] == (smb_iconv_t)-1) {
+ if ((from == CH_DOS || to == CH_DOS) &&
+ strcasecmp(charset_name(ic, CH_DOS), "ASCII") != 0) {
+ DEBUG(0,("dos charset '%s' unavailable - using ASCII\n",
+ charset_name(ic, CH_DOS)));
+ ic->dos_charset = "ASCII";
+
+ n1 = charset_name(ic, from);
+ n2 = charset_name(ic, to);
+
+ ic->conv_handles[from][to] =
+ smb_iconv_open_ex(ic, n2, n1, ic->use_builtin_handlers);
+ }
+ }
+
+ return ic->conv_handles[from][to];
+}
+
+/**
+ * Return the unicode codepoint for the next character in the input
+ * string in the given src_charset.
+ * The unicode codepoint (codepoint_t) is an unsigned 32 bit value.
+ *
+ * Also return the number of bytes consumed (which tells the caller
+ * how many bytes to skip to get to the next src_charset-character).
+ *
+ * This is implemented (in the non-ascii-case) by first converting the
+ * next character in the input string to UTF16_LE and then calculating
+ * the unicode codepoint from that.
+ *
+ * Return INVALID_CODEPOINT if the next character cannot be converted.
+ */
+_PUBLIC_ codepoint_t next_codepoint_handle_ext(
+ struct smb_iconv_handle *ic,
+ const char *str, size_t len,
+ charset_t src_charset,
+ size_t *bytes_consumed)
+{
+ /* it cannot occupy more than 4 bytes in UTF16 format */
+ uint8_t buf[4];
+ smb_iconv_t descriptor;
+ size_t ilen_orig;
+ size_t ilen;
+ size_t olen;
+ char *outbuf;
+
+
+ if (((str[0] & 0x80) == 0) && (src_charset == CH_DOS ||
+ src_charset == CH_UNIX ||
+ src_charset == CH_UTF8)) {
+ *bytes_consumed = 1;
+ return (codepoint_t)str[0];
+ }
+
+ /*
+ * we assume that no multi-byte character can take more than 5 bytes.
+ * This is OK as we only support codepoints up to 1M (U+100000)
+ */
+ ilen_orig = MIN(len, 5);
+ ilen = ilen_orig;
+
+ descriptor = get_conv_handle(ic, src_charset, CH_UTF16);
+ if (descriptor == (smb_iconv_t)-1) {
+ *bytes_consumed = 1;
+ return INVALID_CODEPOINT;
+ }
+
+ /*
+ * this looks a little strange, but it is needed to cope with
+ * codepoints above 64k (U+1000) which are encoded as per RFC2781.
+ */
+ olen = 2;
+ outbuf = (char *)buf;
+ smb_iconv(descriptor, &str, &ilen, &outbuf, &olen);
+ if (olen == 2) {
+ olen = 4;
+ outbuf = (char *)buf;
+ smb_iconv(descriptor, &str, &ilen, &outbuf, &olen);
+ if (olen == 4) {
+ /* we didn't convert any bytes */
+ *bytes_consumed = 1;
+ return INVALID_CODEPOINT;
+ }
+ olen = 4 - olen;
+ } else {
+ olen = 2 - olen;
+ }
+
+ *bytes_consumed = ilen_orig - ilen;
+
+ if (olen == 2) {
+ return (codepoint_t)SVAL(buf, 0);
+ }
+ if (olen == 4) {
+ /* decode a 4 byte UTF16 character manually */
+ return (codepoint_t)0x10000 +
+ (buf[2] | ((buf[3] & 0x3)<<8) |
+ (buf[0]<<10) | ((buf[1] & 0x3)<<18));
+ }
+
+ /* no other length is valid */
+ return INVALID_CODEPOINT;
+}
+
+/*
+ return the unicode codepoint for the next multi-byte CH_UNIX character
+ in the string
+
+ also return the number of bytes consumed (which tells the caller
+ how many bytes to skip to get to the next CH_UNIX character)
+
+ return INVALID_CODEPOINT if the next character cannot be converted
+*/
+_PUBLIC_ codepoint_t next_codepoint_handle(struct smb_iconv_handle *ic,
+ const char *str, size_t *size)
+{
+ /*
+ * We assume that no multi-byte character can take more than 5 bytes
+ * thus avoiding walking all the way down a long string. This is OK as
+ * Unicode codepoints only go up to (U+10ffff), which can always be
+ * encoded in 4 bytes or less.
+ */
+ return next_codepoint_handle_ext(ic, str, strnlen(str, 5), CH_UNIX,
+ size);
+}
+
+/*
+ push a single codepoint into a CH_UNIX string the target string must
+ be able to hold the full character, which is guaranteed if it is at
+ least 5 bytes in size. The caller may pass less than 5 bytes if they
+ are sure the character will fit (for example, you can assume that
+ uppercase/lowercase of a character will not add more than 1 byte)
+
+ return the number of bytes occupied by the CH_UNIX character, or
+ -1 on failure
+*/
+_PUBLIC_ ssize_t push_codepoint_handle(struct smb_iconv_handle *ic,
+ char *str, codepoint_t c)
+{
+ smb_iconv_t descriptor;
+ uint8_t buf[4];
+ size_t ilen, olen;
+ const char *inbuf;
+
+ if (c < 128) {
+ *str = c;
+ return 1;
+ }
+
+ descriptor = get_conv_handle(ic,
+ CH_UTF16, CH_UNIX);
+ if (descriptor == (smb_iconv_t)-1) {
+ return -1;
+ }
+
+ if (c < 0x10000) {
+ ilen = 2;
+ olen = 5;
+ inbuf = (char *)buf;
+ SSVAL(buf, 0, c);
+ smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
+ if (ilen != 0) {
+ return -1;
+ }
+ return 5 - olen;
+ }
+
+ c -= 0x10000;
+
+ buf[0] = (c>>10) & 0xFF;
+ buf[1] = (c>>18) | 0xd8;
+ buf[2] = c & 0xFF;
+ buf[3] = ((c>>8) & 0x3) | 0xdc;
+
+ ilen = 4;
+ olen = 5;
+ inbuf = (char *)buf;
+
+ smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
+ if (ilen != 0) {
+ return -1;
+ }
+ return 5 - olen;
+}
+
+_PUBLIC_ codepoint_t next_codepoint_ext(const char *str, size_t len,
+ charset_t src_charset, size_t *size)
+{
+ return next_codepoint_handle_ext(get_iconv_handle(), str, len,
+ src_charset, size);
+}
+
+_PUBLIC_ codepoint_t next_codepoint(const char *str, size_t *size)
+{
+ if ((str[0] & 0x80) == 0) {
+ *size = 1;
+ return str[0];
+ }
+ return next_codepoint_handle(get_iconv_handle(), str, size);
+}
+
+_PUBLIC_ ssize_t push_codepoint(char *str, codepoint_t c)
+{
+ return push_codepoint_handle(get_iconv_handle(), str, c);
+}
diff --git a/lib/util/charset/convert_string.c b/lib/util/charset/convert_string.c
new file mode 100644
index 0000000..859b002
--- /dev/null
+++ b/lib/util/charset/convert_string.c
@@ -0,0 +1,556 @@
+/*
+ Unix SMB/CIFS implementation.
+ Character set conversion Extensions
+ Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
+ Copyright (C) Andrew Tridgell 2001-2011
+ Copyright (C) Andrew Bartlett 2011
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Martin Pool 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "replace.h"
+#include "system/iconv.h"
+#include "charset.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+
+/**
+ * @file
+ *
+ * @brief Character-set conversion routines built on our iconv.
+ *
+ * @note Samba's internal character set (at least in the 3.0 series)
+ * is always the same as the one for the Unix filesystem. It is
+ * <b>not</b> necessarily UTF-8 and may be different on machines that
+ * need i18n filenames to be compatible with Unix software. It does
+ * have to be a superset of ASCII. All multibyte sequences must start
+ * with a byte with the high bit set.
+ *
+ * @sa lib/iconv.c
+ */
+
+
+/**
+ * Convert string from one encoding to another, making error checking etc
+ * Slow path version - uses (slow) iconv.
+ *
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string
+ * @param converted size is the number of bytes occupied in the destination
+ *
+ * @returns false and sets errno on fail, true on success.
+ *
+ * Ensure the srclen contains the terminating zero.
+ *
+ **/
+
+static bool convert_string_internal(struct smb_iconv_handle *ic,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen, size_t *converted_size)
+{
+ size_t i_len, o_len;
+ size_t retval;
+ const char* inbuf = (const char*)src;
+ char* outbuf = (char*)dest;
+ smb_iconv_t descriptor;
+
+ descriptor = get_conv_handle(ic, from, to);
+
+ if (srclen == (size_t)-1) {
+ if (from == CH_UTF16LE || from == CH_UTF16BE) {
+ srclen = (strlen_w((const smb_ucs2_t *)src)+1) * 2;
+ } else {
+ srclen = strlen((const char *)src)+1;
+ }
+ }
+
+
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ errno = EINVAL;
+ return false;
+ }
+
+ i_len=srclen;
+ o_len=destlen;
+
+ retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
+ *converted_size = destlen-o_len;
+
+ return (retval != (size_t)-1);
+}
+
+/**
+ * Convert string from one encoding to another, making error checking etc
+ * Fast path version - handles ASCII first.
+ *
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes, or -1 for nul terminated.
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string - *NEVER* -1.
+ * @param converted size is the number of bytes occupied in the destination
+ *
+ * @returns false and sets errno on fail, true on success.
+ *
+ * Ensure the srclen contains the terminating zero.
+ *
+ * This function has been hand-tuned to provide a fast path.
+ * Don't change unless you really know what you are doing. JRA.
+ **/
+
+bool convert_string_error_handle(struct smb_iconv_handle *ic,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen,
+ size_t *converted_size)
+{
+ /*
+ * NB. We deliberately don't do a strlen here if srclen == -1.
+ * This is very expensive over millions of calls and is taken
+ * care of in the slow path in convert_string_internal. JRA.
+ */
+
+#ifdef DEVELOPER
+ SMB_ASSERT(destlen != (size_t)-1);
+#endif
+
+ if (srclen == 0) {
+ *converted_size = 0;
+ return true;
+ }
+
+ if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE && to != CH_UTF16BE) {
+ const unsigned char *p = (const unsigned char *)src;
+ unsigned char *q = (unsigned char *)dest;
+ size_t slen = srclen;
+ size_t dlen = destlen;
+ unsigned char lastp = '\0';
+ size_t retval = 0;
+
+ /* If all characters are ascii, fast path here. */
+ while (slen && dlen) {
+ if ((lastp = *p) <= 0x7f) {
+ *q++ = *p++;
+ if (slen != (size_t)-1) {
+ slen--;
+ }
+ dlen--;
+ retval++;
+ if (!lastp)
+ break;
+ } else {
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ goto general_case;
+#else
+ bool ret = convert_string_internal(ic, from, to, p, slen, q, dlen, converted_size);
+ *converted_size += retval;
+ return ret;
+#endif
+ }
+ }
+
+ *converted_size = retval;
+
+ if (!dlen) {
+ /* Even if we fast path we should note if we ran out of room. */
+ if (((slen != (size_t)-1) && slen) ||
+ ((slen == (size_t)-1) && lastp)) {
+ errno = E2BIG;
+ return false;
+ }
+ }
+ return true;
+ } else if (from == CH_UTF16LE && to != CH_UTF16LE) {
+ const unsigned char *p = (const unsigned char *)src;
+ unsigned char *q = (unsigned char *)dest;
+ size_t retval = 0;
+ size_t slen = srclen;
+ size_t dlen = destlen;
+ unsigned char lastp = '\0';
+#ifndef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ bool ret;
+#endif
+
+ if (slen == (size_t)-1) {
+ while (dlen &&
+ ((lastp = *p) <= 0x7f) && (p[1] == 0)) {
+ *q++ = *p;
+ p += 2;
+ dlen--;
+ retval++;
+ if (!lastp)
+ break;
+ }
+ if (lastp != 0) goto slow_path;
+ } else {
+ while (slen >= 2 && dlen &&
+ (*p <= 0x7f) && (p[1] == 0)) {
+ *q++ = *p;
+ slen -= 2;
+ p += 2;
+ dlen--;
+ retval++;
+ }
+ if (slen != 0) goto slow_path;
+ }
+
+ *converted_size = retval;
+
+ if (!dlen) {
+ /* Even if we fast path we should note if we ran out of room. */
+ if (((slen != (size_t)-1) && slen) ||
+ ((slen == (size_t)-1) && lastp)) {
+ errno = E2BIG;
+ return false;
+ }
+ }
+ return true;
+
+ slow_path:
+ /* come here when we hit a character we can't deal
+ * with in the fast path
+ */
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ goto general_case;
+#else
+ ret = convert_string_internal(ic, from, to, p, slen, q, dlen, converted_size);
+ *converted_size += retval;
+ return ret;
+#endif
+
+ } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
+ const unsigned char *p = (const unsigned char *)src;
+ unsigned char *q = (unsigned char *)dest;
+ size_t retval = 0;
+ size_t slen = srclen;
+ size_t dlen = destlen;
+ unsigned char lastp = '\0';
+
+ /* If all characters are ascii, fast path here. */
+ while (slen && (dlen >= 1)) {
+ if (dlen >=2 && (lastp = *p) <= 0x7F) {
+ *q++ = *p++;
+ *q++ = '\0';
+ if (slen != (size_t)-1) {
+ slen--;
+ }
+ dlen -= 2;
+ retval += 2;
+ if (!lastp)
+ break;
+ } else {
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ goto general_case;
+#else
+ bool ret = convert_string_internal(ic, from, to, p, slen, q, dlen, converted_size);
+ *converted_size += retval;
+ return ret;
+#endif
+ }
+ }
+
+ *converted_size = retval;
+
+ if (!dlen) {
+ /* Even if we fast path we should note if we ran out of room. */
+ if (((slen != (size_t)-1) && slen) ||
+ ((slen == (size_t)-1) && lastp)) {
+ errno = E2BIG;
+ return false;
+ }
+ }
+ return true;
+ }
+
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ general_case:
+#endif
+ return convert_string_internal(ic, from, to, src, srclen, dest, destlen, converted_size);
+}
+
+bool convert_string_handle(struct smb_iconv_handle *ic,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen,
+ size_t *converted_size)
+{
+ bool ret = convert_string_error_handle(ic, from, to, src, srclen, dest, destlen, converted_size);
+
+ if(ret==false) {
+ const char *reason="unknown error";
+ switch(errno) {
+ case EINVAL:
+ reason="Incomplete multibyte sequence";
+ DBG_NOTICE("Conversion error: %s\n",
+ reason);
+ break;
+ case E2BIG:
+ {
+ reason="No more room";
+ if (from == CH_UNIX) {
+ DBG_NOTICE("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u error: %s\n",
+ charset_name(ic, from), charset_name(ic, to),
+ (unsigned int)srclen, (unsigned int)destlen, reason);
+ } else {
+ DBG_NOTICE("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u error: %s\n",
+ charset_name(ic, from), charset_name(ic, to),
+ (unsigned int)srclen, (unsigned int)destlen, reason);
+ }
+ break;
+ }
+ case EILSEQ:
+ reason="Illegal multibyte sequence";
+ DBG_NOTICE("convert_string_internal: Conversion error: %s\n",
+ reason);
+ break;
+ default:
+ DBG_ERR("convert_string_internal: Conversion error: %s\n",
+ reason);
+ break;
+ }
+ /* smb_panic(reason); */
+ }
+ return ret;
+}
+
+
+/**
+ * Convert between character sets, allocating a new buffer using talloc for the result.
+ *
+ * @param srclen length of source buffer.
+ * @param dest always set at least to NULL
+ * @param converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ * @note -1 is not accepted for srclen.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ *
+ * Ensure the srclen contains the terminating zero.
+ */
+bool convert_string_talloc_handle(TALLOC_CTX *ctx, struct smb_iconv_handle *ic,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen, void *dst,
+ size_t *converted_size)
+
+{
+ size_t i_len, o_len, destlen;
+ size_t retval;
+ const char *inbuf = NULL;
+ char *outbuf = NULL, *ob = NULL;
+ smb_iconv_t descriptor;
+ void **dest = dst;
+
+ *dest = NULL;
+ if (converted_size != NULL) {
+ *converted_size = 0;
+ }
+
+ if (src == NULL || srclen == (size_t)-1) {
+ errno = EINVAL;
+ return false;
+ }
+
+ if (srclen == 0) {
+ /* We really should treat this as an error, but
+ there are too many callers that need this to
+ return a NULL terminated string in the correct
+ character set. */
+ if (to == CH_UTF16LE|| to == CH_UTF16BE || to == CH_UTF16MUNGED) {
+ destlen = 2;
+ } else {
+ destlen = 1;
+ }
+ ob = talloc_zero_array(ctx, char, destlen);
+ if (ob == NULL) {
+ DBG_ERR("Could not talloc destination buffer.\n");
+ errno = ENOMEM;
+ return false;
+ }
+ if (converted_size != NULL) {
+ *converted_size = destlen;
+ }
+ *dest = ob;
+ return true;
+ }
+
+ descriptor = get_conv_handle(ic, from, to);
+
+ if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+ DEBUG(0,("convert_string_talloc: Conversion not supported.\n"));
+ errno = EOPNOTSUPP;
+ return false;
+ }
+
+ if (srclen >= (SIZE_MAX - 2) / 3) {
+ DBG_ERR("convert_string_talloc: "
+ "srclen is %zu, destlen would wrap!\n",
+ srclen);
+ errno = EOPNOTSUPP;
+ return false;
+ }
+ destlen = srclen * 3;
+
+ /* +2 is for ucs2 null termination. */
+ ob = talloc_realloc(ctx, ob, char, destlen + 2);
+
+ if (!ob) {
+ DEBUG(0, ("convert_string_talloc: realloc failed!\n"));
+ errno = ENOMEM;
+ return false;
+ }
+ outbuf = ob;
+ i_len = srclen;
+ o_len = destlen;
+ inbuf = (const char *)src;
+
+ retval = smb_iconv(descriptor,
+ &inbuf, &i_len,
+ &outbuf, &o_len);
+ if(retval == (size_t)-1) {
+ const char *reason="unknown error";
+ switch(errno) {
+ case EINVAL:
+ reason="Incomplete multibyte sequence";
+ DBG_NOTICE("Conversion error: %s\n",
+ reason);
+ break;
+ case E2BIG:
+ reason = "output buffer is too small";
+ DBG_ERR("Conversion error: %s\n",
+ reason);
+ break;
+ case EILSEQ:
+ reason="Illegal multibyte sequence";
+ DBG_NOTICE("Conversion error: %s\n",
+ reason);
+ break;
+ default:
+ DBG_ERR("Conversion error: %s\n",
+ reason);
+ break;
+ }
+ /* smb_panic(reason); */
+ TALLOC_FREE(ob);
+ return false;
+ }
+
+ destlen = destlen - o_len;
+ /* Don't shrink unless we're reclaiming a lot of
+ * space. This is in the hot codepath and these
+ * reallocs *cost*. JRA.
+ */
+ if (o_len > 1024) {
+ /* We're shrinking here so we know the +2 is safe from wrap. */
+ ob = talloc_realloc(ctx,ob, char, destlen + 2);
+ }
+
+ if (destlen && !ob) {
+ DEBUG(0, ("convert_string_talloc: out of memory!\n"));
+ errno = ENOMEM;
+ return false;
+ }
+
+ *dest = ob;
+
+ /* Must ucs2 null terminate in the extra space we allocated. */
+ ob[destlen] = '\0';
+ ob[destlen+1] = '\0';
+
+ /* Ensure we can never return a *converted_size of zero. */
+ if (destlen == 0) {
+ /* As we're now returning false on a bad smb_iconv call,
+ this should never happen. But be safe anyway. */
+ if (to == CH_UTF16LE|| to == CH_UTF16BE || to == CH_UTF16MUNGED) {
+ destlen = 2;
+ } else {
+ destlen = 1;
+ }
+ }
+
+ if (converted_size != NULL) {
+ *converted_size = destlen;
+ }
+ return true;
+}
+
+/**
+ * Convert string from one encoding to another, with error checking.
+ * This version produces more logging information than
+ * convert_string_error(), but is otherwise functionally identical.
+ *
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string
+ * @param converted_size the number of bytes occupied in the destination
+ *
+ * @returns true on success, false on fail.
+ **/
+_PUBLIC_ bool convert_string(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen,
+ size_t *converted_size)
+{
+ return convert_string_handle(get_iconv_handle(), from, to,
+ src, srclen,
+ dest, destlen, converted_size);
+}
+
+/**
+ * Convert string from one encoding to another, with error checking.
+ * This version is less verbose than convert_string().
+ *
+ * @param src pointer to source string (multibyte or singlebyte)
+ * @param srclen length of the source string in bytes
+ * @param dest pointer to destination string (multibyte or singlebyte)
+ * @param destlen maximal length allowed for string
+ * @param converted_size the number of bytes occupied in the destination
+ *
+ * @returns true on success, false on fail.
+ **/
+_PUBLIC_ bool convert_string_error(charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t destlen,
+ size_t *converted_size)
+{
+ return convert_string_error_handle(get_iconv_handle(), from, to,
+ src, srclen,
+ dest, destlen, converted_size);
+}
+
+/**
+ * Convert between character sets, allocating a new buffer using talloc for the result.
+ *
+ * @param srclen length of source buffer.
+ * @param dest always set at least to NULL
+ * @param converted_size Size in bytes of the converted string
+ * @note -1 is not accepted for srclen.
+ *
+ * @returns boolean indication whether the conversion succeeded
+ **/
+
+_PUBLIC_ bool convert_string_talloc(TALLOC_CTX *ctx,
+ charset_t from, charset_t to,
+ void const *src, size_t srclen,
+ void *dest, size_t *converted_size)
+{
+ return convert_string_talloc_handle(ctx, get_iconv_handle(),
+ from, to, src, srclen, dest,
+ converted_size);
+}
diff --git a/lib/util/charset/iconv.c b/lib/util/charset/iconv.c
new file mode 100644
index 0000000..131df64
--- /dev/null
+++ b/lib/util/charset/iconv.c
@@ -0,0 +1,1196 @@
+/*
+ Unix SMB/CIFS implementation.
+ minimal iconv implementation
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/iconv.h"
+#include "system/filesys.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/charset/charset.h"
+#include "lib/util/charset/charset_proto.h"
+
+#ifdef HAVE_ICU_I18N
+#include <unicode/ustring.h>
+#include <unicode/utrans.h>
+#endif
+
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
+
+/**
+ * @file
+ *
+ * @brief Samba wrapper/stub for iconv character set conversion.
+ *
+ * iconv is the XPG2 interface for converting between character
+ * encodings. This file provides a Samba wrapper around it, and also
+ * a simple reimplementation that is used if the system does not
+ * implement iconv.
+ *
+ * Samba only works with encodings that are supersets of ASCII: ascii
+ * characters like whitespace can be tested for directly, multibyte
+ * sequences start with a byte with the high bit set, and strings are
+ * terminated by a nul byte.
+ *
+ * Note that the only function provided by iconv is conversion between
+ * characters. It doesn't directly support operations like
+ * uppercasing or comparison. We have to convert to UTF-16LE and
+ * compare there.
+ *
+ * @sa Samba Developers Guide
+ **/
+
+static size_t ascii_pull (void *,const char **, size_t *, char **, size_t *);
+static size_t ascii_push (void *,const char **, size_t *, char **, size_t *);
+static size_t latin1_pull(void *,const char **, size_t *, char **, size_t *);
+static size_t latin1_push(void *,const char **, size_t *, char **, size_t *);
+static size_t utf8_pull (void *,const char **, size_t *, char **, size_t *);
+static size_t utf8_push (void *,const char **, size_t *, char **, size_t *);
+static size_t utf16_munged_pull(void *,const char **, size_t *, char **, size_t *);
+static size_t ucs2hex_pull(void *,const char **, size_t *, char **, size_t *);
+static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *);
+static size_t iconv_copy (void *,const char **, size_t *, char **, size_t *);
+static size_t iconv_swab (void *,const char **, size_t *, char **, size_t *);
+
+static const struct charset_functions builtin_functions[] = {
+ /* windows is closest to UTF-16 */
+ {
+ .name = "UCS-2LE",
+ .pull = iconv_copy,
+ .push = iconv_copy
+ },
+ {
+ .name = "UTF-16LE",
+ .pull = iconv_copy,
+ .push = iconv_copy
+ },
+ {
+ .name = "UCS-2BE",
+ .pull = iconv_swab,
+ .push = iconv_swab
+ },
+ {
+ .name = "UTF-16BE",
+ .pull = iconv_swab,
+ .push = iconv_swab
+ },
+
+ /* we include the UTF-8 alias to cope with differing locale settings */
+ {
+ .name = "UTF8",
+ .pull = utf8_pull,
+ .push = utf8_push
+ },
+ {
+ .name = "UTF-8",
+ .pull = utf8_pull,
+ .push = utf8_push
+ },
+
+ /* this handles the munging needed for String2Key */
+ {
+ .name = "UTF16_MUNGED",
+ .pull = utf16_munged_pull,
+ .push = iconv_copy,
+ .samba_internal_charset = true
+ },
+
+ {
+ .name = "ASCII",
+ .pull = ascii_pull,
+ .push = ascii_push
+ },
+ {
+ .name = "646",
+ .pull = ascii_pull,
+ .push = ascii_push
+ },
+ {
+ .name = "ISO-8859-1",
+ .pull = latin1_pull,
+ .push = latin1_push
+ },
+#ifdef DEVELOPER
+ {
+ .name = "WEIRD",
+ .pull = weird_pull,
+ .push = weird_push,
+ .samba_internal_charset = true
+ },
+#endif
+#ifdef DARWINOS
+ {
+ .name = "MACOSXFS",
+ .pull = macosxfs_encoding_pull,
+ .push = macosxfs_encoding_push,
+ .samba_internal_charset = true
+ },
+#endif
+ {
+ .name = "UCS2-HEX",
+ .pull = ucs2hex_pull,
+ .push = ucs2hex_push,
+ .samba_internal_charset = true
+ }
+};
+
+#ifdef HAVE_NATIVE_ICONV
+/* if there was an error then reset the internal state,
+ this ensures that we don't have a shift state remaining for
+ character sets like SJIS */
+static size_t sys_iconv(void *cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t ret = iconv((iconv_t)cd,
+ discard_const_p(char *, inbuf), inbytesleft,
+ outbuf, outbytesleft);
+ if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
+ return ret;
+}
+#endif
+
+#ifdef HAVE_ICU_I18N
+static size_t sys_uconv(void *cd,
+ const char **inbuf,
+ size_t *inbytesleft,
+ char **outbuf,
+ size_t *outbytesleft)
+{
+ UTransliterator *t = (UTransliterator *)cd;
+ size_t bufsize = *inbytesleft * 2;
+ UChar ustr[bufsize];
+ UChar *up = NULL;
+ char *p = NULL;
+ int32_t ustrlen;
+ int32_t limit;
+ int32_t converted_len;
+ size_t inbuf_consumed;
+ size_t outbut_consumed;
+ UErrorCode ue;
+
+ /* Convert from UTF8 to UCS2 */
+ ue = 0;
+ up = u_strFromUTF8(ustr, /* dst */
+ bufsize, /* dst buflen */
+ &converted_len, /* dst written */
+ *inbuf, /* src */
+ *inbytesleft, /* src length */
+ &ue);
+ if (up == NULL || U_FAILURE(ue)) {
+ return -1;
+ }
+ if (converted_len > bufsize) {
+ /*
+ * u_strFromUTF8() returns the required size in
+ * converted_len. In theory this should never overflow as the
+ * ustr[] array is allocated with a size twice as big as
+ * inbytesleft and converted_len should be equal to inbytesleft,
+ * but you never know...
+ */
+ errno = EOVERFLOW;
+ return -1;
+ }
+ inbuf_consumed = converted_len;
+
+ /*
+ * The following transliteration function takes two parameters, the
+ * length of the text to be converted (converted_len) and a limit which
+ * may be smaller then converted_len. We just set limit to converted_len
+ * and also ignore the value returned in limit.
+ */
+ limit = converted_len;
+
+ /* Inplace transliteration */
+ utrans_transUChars(t,
+ ustr, /* text */
+ &converted_len, /* text length */
+ bufsize, /* text buflen */
+ 0, /* start */
+ &limit, /* limit */
+ &ue);
+ if (U_FAILURE(ue)) {
+ return -1;
+ }
+ if (converted_len > bufsize) {
+ /*
+ * In theory this should never happen as the ustr[] array is
+ * allocated with a size twice as big as inbytesleft and
+ * converted_len should be equal to inbytesleft, but you never
+ * know...
+ */
+ errno = EOVERFLOW;
+ return -1;
+ }
+ ustrlen = converted_len;
+
+ /* Convert from UCS2 back to UTF8 */
+ ue = 0;
+ p = u_strToUTF8(*outbuf, /* dst */
+ *outbytesleft, /* dst buflen */
+ &converted_len, /* dst required length */
+ ustr, /* src */
+ ustrlen, /* src length */
+ &ue);
+ if (p == NULL || U_FAILURE(ue)) {
+ return -1;
+ }
+
+ outbut_consumed = converted_len;
+ if (converted_len > *outbytesleft) {
+ /*
+ * The caller's result buffer is too small...
+ */
+ outbut_consumed = *outbytesleft;
+ }
+
+ *inbuf += inbuf_consumed;
+ *inbytesleft -= inbuf_consumed;
+ *outbuf += outbut_consumed;
+ *outbytesleft -= outbut_consumed;
+
+ return converted_len;
+}
+#endif
+
+/**
+ * This is a simple portable iconv() implementation.
+ *
+ * It only knows about a very small number of character sets - just
+ * enough that Samba works on systems that don't have iconv.
+ **/
+_PUBLIC_ size_t smb_iconv(smb_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ /* in many cases we can go direct */
+ if (cd->direct) {
+ return cd->direct(cd->cd_direct,
+ inbuf, inbytesleft, outbuf, outbytesleft);
+ }
+
+ /* otherwise we have to do it chunks at a time */
+ {
+#ifndef SMB_ICONV_BUFSIZE
+#define SMB_ICONV_BUFSIZE 2048
+#endif
+ size_t bufsize;
+ char cvtbuf[SMB_ICONV_BUFSIZE];
+
+ while (*inbytesleft > 0) {
+ char *bufp1 = cvtbuf;
+ const char *bufp2 = cvtbuf;
+ int saved_errno = errno;
+ bool pull_failed = false;
+ bufsize = SMB_ICONV_BUFSIZE;
+
+ if (cd->pull(cd->cd_pull,
+ inbuf, inbytesleft, &bufp1, &bufsize) == -1
+ && errno != E2BIG) {
+ saved_errno = errno;
+ pull_failed = true;
+ }
+
+ bufsize = SMB_ICONV_BUFSIZE - bufsize;
+
+ if (cd->push(cd->cd_push,
+ &bufp2, &bufsize,
+ outbuf, outbytesleft) == -1) {
+ return -1;
+ } else if (pull_failed) {
+ /* We want the pull errno if possible */
+ errno = saved_errno;
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static bool is_utf16(const char *name)
+{
+ return strcasecmp(name, "UCS-2LE") == 0 ||
+ strcasecmp(name, "UTF-16LE") == 0;
+}
+
+static int smb_iconv_t_destructor(smb_iconv_t hwd)
+{
+#ifdef HAVE_ICU_I18N
+ /*
+ * This has to come first, as the cd_direct member won't be an iconv
+ * handle and must not be passed to iconv_close().
+ */
+ if (hwd->direct == sys_uconv) {
+ utrans_close(hwd->cd_direct);
+ return 0;
+ }
+#endif
+#ifdef HAVE_NATIVE_ICONV
+ if (hwd->cd_pull != NULL && hwd->cd_pull != (iconv_t)-1)
+ iconv_close(hwd->cd_pull);
+ if (hwd->cd_push != NULL && hwd->cd_push != (iconv_t)-1)
+ iconv_close(hwd->cd_push);
+ if (hwd->cd_direct != NULL && hwd->cd_direct != (iconv_t)-1)
+ iconv_close(hwd->cd_direct);
+#endif
+
+ return 0;
+}
+
+_PUBLIC_ smb_iconv_t smb_iconv_open_ex(TALLOC_CTX *mem_ctx, const char *tocode,
+ const char *fromcode, bool use_builtin_handlers)
+{
+ smb_iconv_t ret;
+ const struct charset_functions *from=NULL, *to=NULL;
+ int i;
+
+ ret = (smb_iconv_t)talloc_named(mem_ctx,
+ sizeof(*ret),
+ "iconv(%s,%s)", tocode, fromcode);
+ if (!ret) {
+ errno = ENOMEM;
+ return (smb_iconv_t)-1;
+ }
+ memset(ret, 0, sizeof(*ret));
+ talloc_set_destructor(ret, smb_iconv_t_destructor);
+
+ /* check for the simplest null conversion */
+ if (strcmp(fromcode, tocode) == 0) {
+ ret->direct = iconv_copy;
+ return ret;
+ }
+
+ /* check if we have a builtin function for this conversion */
+ for (i=0;i<ARRAY_SIZE(builtin_functions);i++) {
+ if (strcasecmp(fromcode, builtin_functions[i].name) == 0) {
+ if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
+ from = &builtin_functions[i];
+ }
+ }
+ if (strcasecmp(tocode, builtin_functions[i].name) == 0) {
+ if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
+ to = &builtin_functions[i];
+ }
+ }
+ }
+
+#ifdef HAVE_NATIVE_ICONV
+ /* the from and to variables indicate a samba module or
+ * internal conversion, ret->pull and ret->push are
+ * initialised only in this block for iconv based
+ * conversions */
+
+ if (from == NULL) {
+ ret->cd_pull = iconv_open("UTF-16LE", fromcode);
+ if (ret->cd_pull == (iconv_t)-1)
+ ret->cd_pull = iconv_open("UCS-2LE", fromcode);
+ if (ret->cd_pull != (iconv_t)-1) {
+ ret->pull = sys_iconv;
+ }
+ }
+
+ if (to == NULL) {
+ ret->cd_push = iconv_open(tocode, "UTF-16LE");
+ if (ret->cd_push == (iconv_t)-1)
+ ret->cd_push = iconv_open(tocode, "UCS-2LE");
+ if (ret->cd_push != (iconv_t)-1) {
+ ret->push = sys_iconv;
+ }
+ }
+#endif
+
+#ifdef HAVE_ICU_I18N
+ if (strcasecmp(fromcode, "UTF8-NFD") == 0 &&
+ strcasecmp(tocode, "UTF8-NFC") == 0)
+ {
+ U_STRING_DECL(t, "any-nfc", 7);
+ UErrorCode ue = 0;
+
+ U_STRING_INIT(t, "any-nfc", 7);
+
+ ret->cd_direct = utrans_openU(t,
+ strlen("any-nfc"),
+ UTRANS_FORWARD,
+ NULL,
+ 0,
+ NULL,
+ &ue);
+ if (U_FAILURE(ue)) {
+ return (smb_iconv_t)-1;
+ }
+ ret->direct = sys_uconv;
+ return ret;
+ }
+
+ if (strcasecmp(fromcode, "UTF8-NFC") == 0 &&
+ strcasecmp(tocode, "UTF8-NFD") == 0)
+ {
+ U_STRING_DECL(tname, "any-nfd", 7);
+ UErrorCode ue = 0;
+
+ U_STRING_INIT(tname, "any-nfd", 7);
+
+ ret->cd_direct = utrans_openU(tname,
+ 7,
+ UTRANS_FORWARD,
+ NULL,
+ 0,
+ NULL,
+ &ue);
+ if (U_FAILURE(ue)) {
+ return (smb_iconv_t)-1;
+ }
+ ret->direct = sys_uconv;
+ return ret;
+ }
+#endif
+
+ if (ret->pull == NULL && from == NULL) {
+ goto failed;
+ }
+
+ if (ret->push == NULL && to == NULL) {
+ goto failed;
+ }
+
+ /* check for conversion to/from ucs2 */
+ if (is_utf16(fromcode) && to) {
+ ret->direct = to->push;
+ return ret;
+ }
+ if (is_utf16(tocode) && from) {
+ ret->direct = from->pull;
+ return ret;
+ }
+
+#ifdef HAVE_NATIVE_ICONV
+ if (is_utf16(fromcode)) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_push;
+ ret->cd_push = NULL;
+ return ret;
+ }
+ if (is_utf16(tocode)) {
+ ret->direct = sys_iconv;
+ ret->cd_direct = ret->cd_pull;
+ ret->cd_pull = NULL;
+ return ret;
+ }
+#endif
+
+ /* the general case has to go via a buffer */
+ if (!ret->pull) ret->pull = from->pull;
+ if (!ret->push) ret->push = to->push;
+ return ret;
+
+failed:
+ talloc_free(ret);
+ errno = EINVAL;
+ return (smb_iconv_t)-1;
+}
+
+/*
+ simple iconv_open() wrapper
+ */
+_PUBLIC_ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
+{
+ return smb_iconv_open_ex(NULL, tocode, fromcode, true);
+}
+
+/*
+ simple iconv_close() wrapper
+*/
+_PUBLIC_ int smb_iconv_close(smb_iconv_t cd)
+{
+ talloc_free(cd);
+ return 0;
+}
+
+
+/**********************************************************************
+ the following functions implement the builtin character sets in Samba
+ and also the "test" character sets that are designed to test
+ multi-byte character set support for english users
+***********************************************************************/
+
+/*
+ this takes an ASCII sequence and produces a UTF16 sequence
+
+ The first 127 codepoints of latin1 matches the first 127 codepoints
+ of unicode, and so can be put into the first byte of UTF16LE
+
+ */
+
+static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ if (((*inbuf)[0] & 0x7F) != (*inbuf)[0]) {
+ /* If this is multi-byte, then it isn't legal ASCII */
+ errno = EILSEQ;
+ return -1;
+ }
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ this takes a UTF16 sequence and produces an ASCII sequence
+
+ The first 127 codepoints of ASCII matches the first 127 codepoints
+ of unicode, and so can be read directly from the first byte of UTF16LE
+
+ */
+static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ if (((*inbuf)[0] & 0x7F) != (*inbuf)[0] ||
+ (*inbuf)[1] != 0) {
+ /* If this is multi-byte, then it isn't legal ASCII */
+ errno = EILSEQ;
+ return -1;
+ }
+ (*outbuf)[0] = (*inbuf)[0];
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+/*
+ this takes a latin1/ISO-8859-1 sequence and produces a UTF16 sequence
+
+ The first 256 codepoints of latin1 matches the first 256 codepoints
+ of unicode, and so can be put into the first byte of UTF16LE
+
+ */
+static size_t latin1_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ this takes a UTF16 sequence and produces a latin1/ISO-8859-1 sequence
+
+ The first 256 codepoints of latin1 matches the first 256 codepoints
+ of unicode, and so can be read directly from the first byte of UTF16LE
+
+ */
+static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1] != 0) {
+ /* If this is multi-byte, then it isn't legal latin1 */
+ errno = EILSEQ;
+ return -1;
+ }
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ uint8_t hi = 0, lo = 0;
+ bool ok;
+
+ if ((*inbuf)[0] != '@') {
+ /* seven bit ascii case */
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ continue;
+ }
+ /* it's a hex character */
+ if (*inbytesleft < 5) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ok = hex_byte(&(*inbuf)[1], &hi) && hex_byte(&(*inbuf)[3], &lo);
+ if (!ok) {
+ errno = EILSEQ;
+ return -1;
+ }
+
+ (*outbuf)[0] = lo;
+ (*outbuf)[1] = hi;
+ (*inbytesleft) -= 5;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 5;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ char buf[6];
+
+ if ((*inbuf)[1] == 0 &&
+ ((*inbuf)[0] & 0x80) == 0 &&
+ (*inbuf)[0] != '@') {
+ (*outbuf)[0] = (*inbuf)[0];
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ continue;
+ }
+ if (*outbytesleft < 5) {
+ errno = E2BIG;
+ return -1;
+ }
+ snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
+ memcpy(*outbuf, buf, 5);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 5;
+ (*inbuf) += 2;
+ (*outbuf) += 5;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int n;
+
+ n = MIN(*inbytesleft, *outbytesleft);
+
+ swab(*inbuf, *outbuf, (n&~1));
+ if (n&1) {
+ (*outbuf)[n-1] = 0;
+ }
+
+ (*inbytesleft) -= n;
+ (*outbytesleft) -= n;
+ (*inbuf) += n;
+ (*outbuf) += n;
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int n;
+
+ n = MIN(*inbytesleft, *outbytesleft);
+
+ memmove(*outbuf, *inbuf, n);
+
+ (*inbytesleft) -= n;
+ (*outbytesleft) -= n;
+ (*inbuf) += n;
+ (*outbuf) += n;
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ this takes a UTF8 sequence and produces a UTF16 sequence
+ */
+static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t in_left=*inbytesleft, out_left=*outbytesleft;
+ const uint8_t *c = (const uint8_t *)*inbuf;
+ uint8_t *uc = (uint8_t *)*outbuf;
+
+ while (in_left >= 1 && out_left >= 2) {
+ if ((c[0] & 0x80) == 0) {
+ uc[0] = c[0];
+ uc[1] = 0;
+ c += 1;
+ in_left -= 1;
+ out_left -= 2;
+ uc += 2;
+ continue;
+ }
+
+ if ((c[0] & 0xe0) == 0xc0) {
+ if (in_left < 2 ||
+ (c[1] & 0xc0) != 0x80) {
+ errno = EILSEQ;
+ goto error;
+ }
+ uc[1] = (c[0]>>2) & 0x7;
+ uc[0] = (c[0]<<6) | (c[1]&0x3f);
+ if (uc[1] == 0 && uc[0] < 0x80) {
+ /* this should have been a single byte */
+ errno = EILSEQ;
+ goto error;
+ }
+ c += 2;
+ in_left -= 2;
+ out_left -= 2;
+ uc += 2;
+ continue;
+ }
+
+ if ((c[0] & 0xf0) == 0xe0) {
+ unsigned int codepoint;
+ if (in_left < 3 ||
+ (c[1] & 0xc0) != 0x80 ||
+ (c[2] & 0xc0) != 0x80) {
+ errno = EILSEQ;
+ goto error;
+ }
+ codepoint = ((c[2] & 0x3f) |
+ ((c[1] & 0x3f) << 6) |
+ ((c[0] & 0x0f) << 12));
+
+ if (codepoint < 0x800) {
+ /* this should be a 1 or 2 byte sequence */
+ errno = EILSEQ;
+ goto error;
+ }
+ if (codepoint >= 0xd800 && codepoint <= 0xdfff) {
+ /*
+ * This is an invalid codepoint, per
+ * RFC3629, as it encodes part of a
+ * UTF-16 surrogate pair for a
+ * character over U+10000, which ought
+ * to have been encoded as a four byte
+ * utf-8 sequence.
+ *
+ * Prior to Vista, Windows might
+ * sometimes produce invalid strings
+ * where a utf-16 sequence containing
+ * surrogate pairs was converted
+ * "verbatim" into utf-8, instead of
+ * encoding the actual codepoint. This
+ * format is sometimes called "WTF-8".
+ *
+ * If we were to support that, we'd
+ * have a branch here for the case
+ * where the codepoint is between
+ * 0xd800 and 0xdbff (a "high
+ * surrogate"), and read a *six*
+ * character sequence from there which
+ * would include a low surrogate. But
+ * that would undermine the
+ * hard-learnt principle that each
+ * character should only have one
+ * encoding.
+ */
+ errno = EILSEQ;
+ goto error;
+ }
+
+ uc[0] = codepoint & 0xff;
+ uc[1] = codepoint >> 8;
+ c += 3;
+ in_left -= 3;
+ out_left -= 2;
+ uc += 2;
+ continue;
+ }
+
+ if ((c[0] & 0xf8) == 0xf0) {
+ unsigned int codepoint;
+ if (in_left < 4 ||
+ (c[1] & 0xc0) != 0x80 ||
+ (c[2] & 0xc0) != 0x80 ||
+ (c[3] & 0xc0) != 0x80) {
+ errno = EILSEQ;
+ goto error;
+ }
+ codepoint =
+ (c[3]&0x3f) |
+ ((c[2]&0x3f)<<6) |
+ ((c[1]&0x3f)<<12) |
+ ((c[0]&0x7)<<18);
+ if (codepoint < 0x10000) {
+ /* reject UTF-8 characters that are not
+ minimally packed */
+ errno = EILSEQ;
+ goto error;
+ }
+ if (codepoint > 0x10ffff) {
+ /*
+ * Unicode stops at 0x10ffff, and if
+ * we ignore that, we'll end up
+ * encoding the wrong characters in
+ * the surrogate pair.
+ */
+ errno = EILSEQ;
+ goto error;
+ }
+
+ codepoint -= 0x10000;
+
+ if (out_left < 4) {
+ errno = E2BIG;
+ goto error;
+ }
+
+ uc[0] = (codepoint>>10) & 0xFF;
+ uc[1] = (codepoint>>18) | 0xd8;
+ uc[2] = codepoint & 0xFF;
+ uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
+ c += 4;
+ in_left -= 4;
+ out_left -= 4;
+ uc += 4;
+ continue;
+ }
+
+ /* we don't handle 5 byte sequences */
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (in_left > 0) {
+ errno = E2BIG;
+ goto error;
+ }
+
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (const char *)c;
+ *outbuf = (char *)uc;
+ return 0;
+
+error:
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (const char *)c;
+ *outbuf = (char *)uc;
+ return -1;
+}
+
+
+/*
+ this takes a UTF16 sequence and produces a UTF8 sequence
+ */
+static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t in_left=*inbytesleft, out_left=*outbytesleft;
+ uint8_t *c = (uint8_t *)*outbuf;
+ const uint8_t *uc = (const uint8_t *)*inbuf;
+
+ while (in_left >= 2 && out_left >= 1) {
+ unsigned int codepoint;
+
+ if (uc[1] == 0 && !(uc[0] & 0x80)) {
+ /* simplest case */
+ c[0] = uc[0];
+ in_left -= 2;
+ out_left -= 1;
+ uc += 2;
+ c += 1;
+ continue;
+ }
+
+ if ((uc[1]&0xf8) == 0) {
+ /* next simplest case */
+ if (out_left < 2) {
+ errno = E2BIG;
+ goto error;
+ }
+ c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
+ c[1] = 0x80 | (uc[0] & 0x3f);
+ in_left -= 2;
+ out_left -= 2;
+ uc += 2;
+ c += 2;
+ continue;
+ }
+
+ if ((uc[1] & 0xfc) == 0xdc) {
+ errno = EILSEQ;
+#ifndef HAVE_ICONV_ERRNO_ILLEGAL_MULTIBYTE
+ if (in_left < 4) {
+ errno = EINVAL;
+ }
+#endif
+ goto error;
+ }
+
+ if ((uc[1] & 0xfc) != 0xd8) {
+ codepoint = uc[0] | (uc[1]<<8);
+ if (out_left < 3) {
+ errno = E2BIG;
+ goto error;
+ }
+ c[0] = 0xe0 | (codepoint >> 12);
+ c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
+ c[2] = 0x80 | (codepoint & 0x3f);
+
+ in_left -= 2;
+ out_left -= 3;
+ uc += 2;
+ c += 3;
+ continue;
+ }
+
+ /* its the first part of a 4 byte sequence */
+ if (in_left < 4) {
+ errno = EINVAL;
+ goto error;
+ }
+ if ((uc[3] & 0xfc) != 0xdc) {
+ errno = EILSEQ;
+ goto error;
+ }
+ codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
+ (uc[0]<<10) | ((uc[1] & 0x3)<<18));
+
+ if (out_left < 4) {
+ errno = E2BIG;
+ goto error;
+ }
+ c[0] = 0xf0 | (codepoint >> 18);
+ c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
+ c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
+ c[3] = 0x80 | (codepoint & 0x3f);
+
+ in_left -= 4;
+ out_left -= 4;
+ uc += 4;
+ c += 4;
+ }
+
+ if (in_left == 1) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (in_left > 1) {
+ errno = E2BIG;
+ goto error;
+ }
+
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (const char *)uc;
+ *outbuf = (char *)c;
+
+ return 0;
+
+error:
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (const char *)uc;
+ *outbuf = (char *)c;
+ return -1;
+}
+
+
+/*
+ this takes a UTF16 munged sequence, modifies it according to the
+ string2key rules, and produces a UTF16 sequence
+
+The rules are:
+
+ 1) any 0x0000 characters are mapped to 0x0001
+
+ 2) convert any instance of 0xD800 - 0xDBFF (high surrogate)
+ without an immediately following 0xDC00 - 0x0xDFFF (low surrogate) to
+ U+FFFD (OBJECT REPLACEMENT CHARACTER).
+
+ 3) the same for any low surrogate that was not preceded by a high surrogate.
+
+ */
+static size_t utf16_munged_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ size_t in_left=*inbytesleft, out_left=*outbytesleft;
+ uint8_t *c = (uint8_t *)*outbuf;
+ const uint8_t *uc = (const uint8_t *)*inbuf;
+
+ while (in_left >= 2 && out_left >= 2) {
+ unsigned int codepoint = uc[0] | (uc[1]<<8);
+
+ if (codepoint == 0) {
+ codepoint = 1;
+ }
+
+ if ((codepoint & 0xfc00) == 0xd800) {
+ /* a high surrogate */
+ unsigned int codepoint2;
+ if (in_left < 4) {
+ codepoint = 0xfffd;
+ goto codepoint16;
+ }
+ codepoint2 = uc[2] | (uc[3]<<8);
+ if ((codepoint2 & 0xfc00) != 0xdc00) {
+ /* high surrogate not followed by low
+ surrogate: convert to 0xfffd */
+ codepoint = 0xfffd;
+ goto codepoint16;
+ }
+ if (out_left < 4) {
+ errno = E2BIG;
+ goto error;
+ }
+ memcpy(c, uc, 4);
+ in_left -= 4;
+ out_left -= 4;
+ uc += 4;
+ c += 4;
+ continue;
+ }
+
+ if ((codepoint & 0xfc00) == 0xdc00) {
+ /* low surrogate not preceded by high
+ surrogate: convert to 0xfffd */
+ codepoint = 0xfffd;
+ }
+
+ codepoint16:
+ c[0] = codepoint & 0xFF;
+ c[1] = (codepoint>>8) & 0xFF;
+
+ in_left -= 2;
+ out_left -= 2;
+ uc += 2;
+ c += 2;
+ continue;
+ }
+
+ if (in_left == 1) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (in_left > 1) {
+ errno = E2BIG;
+ goto error;
+ }
+
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (const char *)uc;
+ *outbuf = (char *)c;
+
+ return 0;
+
+error:
+ *inbytesleft = in_left;
+ *outbytesleft = out_left;
+ *inbuf = (const char *)uc;
+ *outbuf = (char *)c;
+ return -1;
+}
+
+
+
diff --git a/lib/util/charset/pull_push.c b/lib/util/charset/pull_push.c
new file mode 100644
index 0000000..8ec6498
--- /dev/null
+++ b/lib/util/charset/pull_push.c
@@ -0,0 +1,160 @@
+/*
+ Unix SMB/CIFS implementation.
+ Character set conversion Extensions
+ Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Martin Pool 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "charset.h"
+
+/**
+ * Copy a string from a unix char* src to a UCS2 destination,
+ * allocating a buffer using talloc().
+ *
+ * @param dest always set at least to NULL
+ * @param converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, src, src_len,
+ (void **)dest, converted_size);
+}
+
+/**
+ * @brief Create a UTF-8 string from a unix charset string.
+ *
+ * The resulting UTF-8 string is talloc'ed.
+ *
+ * @param[in] ctx The talloc memory context.
+ *
+ * @param[in] dest A pointer to store the pointer to the talloc'ed UTF-8
+ * string.
+ *
+ * @param[in] src The unix charset string to convert.
+ *
+ * @param[in] converted_size A pointer to store the length of the talloc'ed
+ * UTF-8 string including the nul-termination bytes.
+ *
+ * The destination string should be free'd using talloc_free() if no longer
+ * needed.
+ *
+ * @return True on success, false otherwise.
+ */
+bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len,
+ (void**)dest, converted_size);
+}
+
+/**
+ * Copy a string from a unix char* src to an ASCII destination,
+ * allocating a buffer using talloc().
+ *
+ * @param dest always set at least to NULL
+ *
+ * @param converted_size The number of bytes occupied by the string in the destination
+ * @returns boolean indicating if the conversion was successful
+ **/
+bool push_ascii_talloc(TALLOC_CTX *mem_ctx, char **dest, const char *src, size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(mem_ctx, CH_UNIX, CH_DOS, src, src_len,
+ (void **)dest, converted_size);
+}
+
+/**
+ * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ * @param converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src,
+ size_t *converted_size)
+{
+ size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
+ (void **)dest, converted_size);
+}
+
+
+/**
+ * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ * @param converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len,
+ (void **)dest, converted_size);
+}
+
+
+/**
+ * Copy a string from a DOS src to a unix char * destination, allocating a buffer using talloc
+ *
+ * @param dest always set at least to NULL
+ * @param converted_size set to the number of bytes occupied by the string in
+ * the destination on success.
+ *
+ * @return true if new buffer was correctly allocated, and string was
+ * converted.
+ **/
+
+bool pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
+ size_t *converted_size)
+{
+ size_t src_len = strlen(src)+1;
+
+ *dest = NULL;
+ return convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len,
+ (void **)dest, converted_size);
+}
diff --git a/lib/util/charset/tests/charset.c b/lib/util/charset/tests/charset.c
new file mode 100644
index 0000000..547dc51
--- /dev/null
+++ b/lib/util/charset/tests/charset.c
@@ -0,0 +1,342 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for the charcnv functions
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+
+#undef strcasecmp
+#undef strncasecmp
+
+struct torture_suite *torture_local_charset(TALLOC_CTX *mem_ctx);
+
+static bool test_toupper_m(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, toupper_m('c'), 'C', "c");
+ torture_assert_int_equal(tctx, toupper_m('Z'), 'Z', "z");
+ torture_assert_int_equal(tctx, toupper_m(0xFFFF4565), 0xFFFF4565, "0xFFFF4565");
+ return true;
+}
+
+static bool test_tolower_m(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, tolower_m('C'), 'c', "c");
+ torture_assert_int_equal(tctx, tolower_m('z'), 'z', "z");
+ torture_assert_int_equal(tctx, tolower_m(0xFFFF4565), 0xFFFF4565, "0xFFFF4565");
+ return true;
+}
+
+static bool test_codepoint_cmpi(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, codepoint_cmpi('a', 'a'), 0, "same char");
+ torture_assert_int_equal(tctx, codepoint_cmpi('A', 'a'), 0, "upcase version");
+ torture_assert_int_equal(tctx, codepoint_cmpi('b', 'a'), 1, "right diff");
+ torture_assert_int_equal(tctx, codepoint_cmpi('a', 'b'), -1, "right diff");
+ return true;
+}
+
+static bool test_strcasecmp(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, strcasecmp("foo", "bar"), 4, "different strings both lower");
+ torture_assert_int_equal(tctx, strcasecmp("foo", "Bar"), 4, "different strings lower/upper");
+ torture_assert_int_equal(tctx, strcasecmp("Foo", "bar"), 4, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strcasecmp("AFoo", "_bar"), 2, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strcasecmp("foo", "foo"), 0, "same case strings");
+ torture_assert_int_equal(tctx, strcasecmp("foo", "Foo"), 0, "different case strings");
+
+ /*
+ * Note that strcasecmp() doesn't allow NULL arguments
+ */
+ return true;
+}
+
+static bool test_strcasecmp_m(struct torture_context *tctx)
+{
+ /* file.{accented e} in iso8859-1 */
+ const char file_iso8859_1[7] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xe9, 0 };
+ /* file.{accented e} in utf8 */
+ const char file_utf8[8] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xc3, 0xa9, 0 };
+ torture_assert_int_equal(tctx, strcasecmp_m("foo", "bar"), 4, "different strings both lower");
+ torture_assert_int_equal(tctx, strcasecmp_m("foo", "Bar"), 4, "different strings lower/upper");
+ torture_assert_int_equal(tctx, strcasecmp_m("Foo", "bar"), 4, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strcasecmp_m("AFoo", "_bar"), 2, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strcasecmp_m("foo", "foo"), 0, "same case strings");
+ torture_assert_int_equal(tctx, strcasecmp_m("foo", "Foo"), 0, "different case strings");
+ torture_assert_int_equal(tctx, strcasecmp_m(NULL, "Foo"), -1, "one NULL");
+ torture_assert_int_equal(tctx, strcasecmp_m("foo", NULL), 1, "other NULL");
+ torture_assert_int_equal(tctx, strcasecmp_m(NULL, NULL), 0, "both NULL");
+ torture_assert_int_equal(tctx, strcasecmp_m(file_iso8859_1, file_utf8), 38,
+ "file.{accented e} should differ");
+ return true;
+}
+
+
+static bool test_strequal_m(struct torture_context *tctx)
+{
+ torture_assert(tctx, !strequal_m("foo", "bar"), "different strings");
+ torture_assert(tctx, strequal_m("foo", "foo"), "same case strings");
+ torture_assert(tctx, strequal_m("foo", "Foo"), "different case strings");
+ torture_assert(tctx, !strequal_m(NULL, "Foo"), "one NULL");
+ torture_assert(tctx, !strequal_m("foo", NULL), "other NULL");
+ torture_assert(tctx, strequal_m(NULL, NULL), "both NULL");
+ return true;
+}
+
+static bool test_strcsequal(struct torture_context *tctx)
+{
+ torture_assert(tctx, !strcsequal("foo", "bar"), "different strings");
+ torture_assert(tctx, strcsequal("foo", "foo"), "same case strings");
+ torture_assert(tctx, !strcsequal("foo", "Foo"), "different case strings");
+ torture_assert(tctx, !strcsequal(NULL, "Foo"), "one NULL");
+ torture_assert(tctx, !strcsequal("foo", NULL), "other NULL");
+ torture_assert(tctx, strcsequal(NULL, NULL), "both NULL");
+ return true;
+}
+
+static bool test_string_replace_m(struct torture_context *tctx)
+{
+ char data[6] = "bla";
+ string_replace_m(data, 'b', 'c');
+ torture_assert_str_equal(tctx, data, "cla", "first char replaced");
+ memcpy(data, "bab", 4);
+ string_replace_m(data, 'b', 'c');
+ torture_assert_str_equal(tctx, data, "cac", "other chars replaced");
+ memcpy(data, "bba", 4);
+ string_replace_m(data, 'b', 'c');
+ torture_assert_str_equal(tctx, data, "cca", "other chars replaced");
+ memcpy(data, "blala", 6);
+ string_replace_m(data, 'o', 'c');
+ torture_assert_str_equal(tctx, data, "blala", "no chars replaced");
+ string_replace_m(NULL, 'b', 'c');
+ return true;
+}
+
+static bool test_strncasecmp(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, strncasecmp("foo", "bar", 3), 4, "different strings both lower");
+ torture_assert_int_equal(tctx, strncasecmp("foo", "Bar", 3), 4, "different strings lower/upper");
+ torture_assert_int_equal(tctx, strncasecmp("Foo", "bar", 3), 4, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strncasecmp("AFoo", "_bar", 4), 2, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strncasecmp("foo", "foo", 3), 0, "same case strings");
+ torture_assert_int_equal(tctx, strncasecmp("foo", "Foo", 3), 0, "different case strings");
+ torture_assert_int_equal(tctx, strncasecmp("fool", "Foo", 3),0, "different case strings");
+ torture_assert_int_equal(tctx, strncasecmp("fool", "Fool", 40), 0, "over size");
+ torture_assert_int_equal(tctx, strncasecmp("BLA", "Fool", 0),0, "empty");
+
+ /*
+ * Note that strncasecmp() doesn't allow NULL arguments
+ */
+ return true;
+}
+
+static bool test_strncasecmp_m(struct torture_context *tctx)
+{
+ /* file.{accented e} in iso8859-1 */
+ const char file_iso8859_1[7] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xe9, 0 };
+ /* file.{accented e} in utf8 */
+ const char file_utf8[8] = { 0x66, 0x69, 0x6c, 0x65, 0x2d, 0xc3, 0xa9, 0 };
+ torture_assert_int_equal(tctx, strncasecmp_m("foo", "bar", 3), 4, "different strings both lower");
+ torture_assert_int_equal(tctx, strncasecmp_m("foo", "Bar", 3), 4, "different strings lower/upper");
+ torture_assert_int_equal(tctx, strncasecmp_m("Foo", "bar", 3), 4, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strncasecmp_m("AFoo", "_bar", 4), 2, "different strings upper/lower");
+ torture_assert_int_equal(tctx, strncasecmp_m("foo", "foo", 3), 0, "same case strings");
+ torture_assert_int_equal(tctx, strncasecmp_m("foo", "Foo", 3), 0, "different case strings");
+ torture_assert_int_equal(tctx, strncasecmp_m("fool", "Foo", 3),0, "different case strings");
+ torture_assert_int_equal(tctx, strncasecmp_m("fool", "Fool", 40), 0, "over size");
+ torture_assert_int_equal(tctx, strncasecmp_m("BLA", "Fool", 0),0, "empty");
+ torture_assert_int_equal(tctx, strncasecmp_m(NULL, "Foo", 3), -1, "one NULL");
+ torture_assert_int_equal(tctx, strncasecmp_m("foo", NULL, 3), 1, "other NULL");
+ torture_assert_int_equal(tctx, strncasecmp_m(NULL, NULL, 3), 0, "both NULL");
+ torture_assert_int_equal(tctx, strncasecmp_m(file_iso8859_1, file_utf8, 6), 38,
+ "file.{accented e} should differ");
+ return true;
+}
+
+static bool test_next_token_null(struct torture_context *tctx)
+{
+ char buf[20];
+ torture_assert(tctx, !next_token(NULL, buf, " ", 20), "null ptr works");
+ return true;
+}
+
+static bool test_next_token(struct torture_context *tctx)
+{
+ const char *teststr = "foo bar bla";
+ char buf[20];
+ torture_assert(tctx, next_token(&teststr, buf, " ", 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "foo", "token matches");
+ torture_assert_str_equal(tctx, teststr, "bar bla", "ptr modified correctly");
+
+ torture_assert(tctx, next_token(&teststr, buf, " ", 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "bar", "token matches");
+ torture_assert_str_equal(tctx, teststr, "bla", "ptr modified correctly");
+
+ torture_assert(tctx, next_token(&teststr, buf, " ", 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "bla", "token matches");
+ torture_assert_str_equal(tctx, teststr, "", "ptr modified correctly");
+
+ torture_assert(tctx, !next_token(&teststr, buf, " ", 20), "finding token doesn't work");
+ return true;
+}
+
+static bool test_next_token_implicit_sep(struct torture_context *tctx)
+{
+ const char *teststr = "foo\tbar\n bla";
+ char buf[20];
+ torture_assert(tctx, next_token(&teststr, buf, NULL, 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "foo", "token matches");
+ torture_assert_str_equal(tctx, teststr, "bar\n bla", "ptr modified correctly");
+
+ torture_assert(tctx, next_token(&teststr, buf, NULL, 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "bar", "token matches");
+ torture_assert_str_equal(tctx, teststr, " bla", "ptr modified correctly");
+
+ torture_assert(tctx, next_token(&teststr, buf, NULL, 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "bla", "token matches");
+ torture_assert_str_equal(tctx, teststr, "", "ptr modified correctly");
+
+ torture_assert(tctx, !next_token(&teststr, buf, NULL, 20), "finding token doesn't work");
+ return true;
+}
+
+static bool test_next_token_seps(struct torture_context *tctx)
+{
+ const char *teststr = ",foo bla";
+ char buf[20];
+ torture_assert(tctx, next_token(&teststr, buf, ",", 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "foo bla", "token matches");
+ torture_assert_str_equal(tctx, teststr, "", "ptr modified correctly");
+
+ torture_assert(tctx, !next_token(&teststr, buf, ",", 20), "finding token doesn't work");
+ return true;
+}
+
+static bool test_next_token_quotes(struct torture_context *tctx)
+{
+ const char *teststr = "\"foo bar\" bla";
+ char buf[20];
+ torture_assert(tctx, next_token(&teststr, buf, " ", 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "foo bar", "token matches");
+ torture_assert_str_equal(tctx, teststr, "bla", "ptr modified correctly");
+
+ torture_assert(tctx, next_token(&teststr, buf, " ", 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "bla", "token matches");
+ torture_assert_str_equal(tctx, teststr, "", "ptr modified correctly");
+
+ torture_assert(tctx, !next_token(&teststr, buf, " ", 20), "finding token doesn't work");
+ return true;
+}
+
+static bool test_next_token_quote_wrong(struct torture_context *tctx)
+{
+ const char *teststr = "\"foo bar bla";
+ char buf[20];
+ torture_assert(tctx, next_token(&teststr, buf, " ", 20), "finding token works");
+ torture_assert_str_equal(tctx, buf, "foo bar bla", "token matches");
+ torture_assert_str_equal(tctx, teststr, "", "ptr modified correctly");
+
+ torture_assert(tctx, !next_token(&teststr, buf, " ", 20), "finding token doesn't work");
+ return true;
+}
+
+static bool test_strlen_m(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, strlen_m("foo"), 3, "simple len");
+ torture_assert_int_equal(tctx, strlen_m("foo\x83l"), 6, "extended len");
+ torture_assert_int_equal(tctx, strlen_m(""), 0, "empty");
+ torture_assert_int_equal(tctx, strlen_m(NULL), 0, "NULL");
+ return true;
+}
+
+static bool test_strlen_m_term(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, strlen_m_term("foo"), 4, "simple len");
+ torture_assert_int_equal(tctx, strlen_m_term("foo\x83l"), 7, "extended len");
+ torture_assert_int_equal(tctx, strlen_m_term(""), 1, "empty");
+ torture_assert_int_equal(tctx, strlen_m_term(NULL), 0, "NULL");
+ return true;
+}
+
+static bool test_strlen_m_term_null(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, strlen_m_term_null("foo"), 4, "simple len");
+ torture_assert_int_equal(tctx, strlen_m_term_null("foo\x83l"), 7, "extended len");
+ torture_assert_int_equal(tctx, strlen_m_term_null(""), 0, "empty");
+ torture_assert_int_equal(tctx, strlen_m_term_null(NULL), 0, "NULL");
+ return true;
+}
+
+static bool test_strhaslower(struct torture_context *tctx)
+{
+ torture_assert(tctx, strhaslower("a"), "one low char");
+ torture_assert(tctx, strhaslower("aB"), "one low, one up char");
+ torture_assert(tctx, !strhaslower("B"), "one up char");
+ torture_assert(tctx, !strhaslower(""), "empty string");
+ torture_assert(tctx, !strhaslower("3"), "one digit");
+ return true;
+}
+
+static bool test_strhasupper(struct torture_context *tctx)
+{
+ torture_assert(tctx, strhasupper("B"), "one up char");
+ torture_assert(tctx, strhasupper("aB"), "one low, one up char");
+ torture_assert(tctx, !strhasupper("a"), "one low char");
+ torture_assert(tctx, !strhasupper(""), "empty string");
+ torture_assert(tctx, !strhasupper("3"), "one digit");
+ return true;
+}
+
+static bool test_count_chars_m(struct torture_context *tctx)
+{
+ torture_assert_int_equal(tctx, count_chars_m("foo", 'o'), 2, "simple");
+ torture_assert_int_equal(tctx, count_chars_m("", 'o'), 0, "empty");
+ torture_assert_int_equal(tctx, count_chars_m("bla", 'o'), 0, "none");
+ torture_assert_int_equal(tctx, count_chars_m("bla", '\0'), 0, "null");
+ return true;
+}
+
+struct torture_suite *torture_local_charset(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "charset");
+
+ torture_suite_add_simple_test(suite, "toupper_m", test_toupper_m);
+ torture_suite_add_simple_test(suite, "tolower_m", test_tolower_m);
+ torture_suite_add_simple_test(suite, "codepoint_cmpi", test_codepoint_cmpi);
+ torture_suite_add_simple_test(suite, "strcasecmp", test_strcasecmp);
+ torture_suite_add_simple_test(suite, "strcasecmp_m", test_strcasecmp_m);
+ torture_suite_add_simple_test(suite, "strequal_m", test_strequal_m);
+ torture_suite_add_simple_test(suite, "strcsequal", test_strcsequal);
+ torture_suite_add_simple_test(suite, "string_replace_m", test_string_replace_m);
+ torture_suite_add_simple_test(suite, "strncasecmp", test_strncasecmp);
+ torture_suite_add_simple_test(suite, "strncasecmp_m", test_strncasecmp_m);
+ torture_suite_add_simple_test(suite, "next_token", test_next_token);
+ torture_suite_add_simple_test(suite, "next_token_null", test_next_token_null);
+ torture_suite_add_simple_test(suite, "next_token_implicit_sep", test_next_token_implicit_sep);
+ torture_suite_add_simple_test(suite, "next_token_quotes", test_next_token_quotes);
+ torture_suite_add_simple_test(suite, "next_token_seps", test_next_token_seps);
+ torture_suite_add_simple_test(suite, "next_token_quote_wrong", test_next_token_quote_wrong);
+ torture_suite_add_simple_test(suite, "strlen_m", test_strlen_m);
+ torture_suite_add_simple_test(suite, "strlen_m_term", test_strlen_m_term);
+ torture_suite_add_simple_test(suite, "strlen_m_term_null", test_strlen_m_term_null);
+ torture_suite_add_simple_test(suite, "strhaslower", test_strhaslower);
+ torture_suite_add_simple_test(suite, "strhasupper", test_strhasupper);
+ torture_suite_add_simple_test(suite, "count_chars_m", test_count_chars_m);
+
+ return suite;
+}
diff --git a/lib/util/charset/tests/convert_string.c b/lib/util/charset/tests/convert_string.c
new file mode 100644
index 0000000..6400ce1
--- /dev/null
+++ b/lib/util/charset/tests/convert_string.c
@@ -0,0 +1,2196 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for the charcnv functions
+
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "lib/util/charset/charset.h"
+#include "param/param.h"
+#include "lib/util/base64.h"
+
+struct torture_suite *torture_local_convert_string_handle(TALLOC_CTX *mem_ctx);
+struct torture_suite *torture_local_string_case_handle(TALLOC_CTX *mem_ctx);
+struct torture_suite *torture_local_convert_string(TALLOC_CTX *mem_ctx);
+struct torture_suite *torture_local_string_case(TALLOC_CTX *mem_ctx);
+
+/* The text below is in ancient and a latin charset transliteration of
+ * greek, and an english translation. It from Apology by Plato and sourced from
+ * http://en.wikipedia.org/w/index.php?title=Ancient_Greek&oldid=421361065#Example_text
+ */
+
+const char *plato_english_ascii =
+ "What you, men of Athens, have learned from my accusers, I do not"
+ " know: but I, for my part, nearly forgot who I was thanks to them since"
+ " they spoke so persuasively. And yet, of the truth, they have spoken,"
+ " one might say, nothing at all.";
+
+const char *plato_english_utf16le_base64 =
+ "VwBoAGEAdAAgAHkAbwB1ACwAIABtAGUAbgAgAG8AZgAgAEEAdABoAGUAbgBzACwAIABoAGEAdgBl"
+ "ACAAbABlAGEAcgBuAGUAZAAgAGYAcgBvAG0AIABtAHkAIABhAGMAYwB1AHMAZQByAHMALAAgAEkA"
+ "IABkAG8AIABuAG8AdAAgAGsAbgBvAHcAOgAgAGIAdQB0ACAASQAsACAAZgBvAHIAIABtAHkAIABw"
+ "AGEAcgB0ACwAIABuAGUAYQByAGwAeQAgAGYAbwByAGcAbwB0ACAAdwBoAG8AIABJACAAdwBhAHMA"
+ "IAB0AGgAYQBuAGsAcwAgAHQAbwAgAHQAaABlAG0AIABzAGkAbgBjAGUAIAB0AGgAZQB5ACAAcwBw"
+ "AG8AawBlACAAcwBvACAAcABlAHIAcwB1AGEAcwBpAHYAZQBsAHkALgAgAEEAbgBkACAAeQBlAHQA"
+ "LAAgAG8AZgAgAHQAaABlACAAdAByAHUAdABoACwAIAB0AGgAZQB5ACAAaABhAHYAZQAgAHMAcABv"
+ "AGsAZQBuACwAIABvAG4AZQAgAG0AaQBnAGgAdAAgAHMAYQB5ACwAIABuAG8AdABoAGkAbgBnACAA"
+ "YQB0ACAAYQBsAGwALgA=";
+
+static const char *plato_utf8_base64 =
+ "4b2Nz4TOuSDOvOG9ss69IOG9kc68zrXhv5bPgiwg4b2mIOG8hM69zrTPgc61z4IgzobOuM63zr3O"
+ "seG/ls6/zrksIM+AzrXPgM+Mzr3OuM6xz4TOtSDhvZHPgOG9uCDPhOG/ts69IOG8kM684b+2zr0g"
+ "zrrOsc+EzrfOs8+Mz4HPic69LCDOv+G9kM66IM6/4by2zrTOsTog4byQzrPhvbwgzrQnIM6/4b2W"
+ "zr0gzrrOseG9tiDOseG9kM+E4b24z4Ig4b2Rz4AnIM6x4b2Qz4Thv7bOvSDhvYDOu86vzrPOv8+F"
+ "IOG8kM68zrHPhc+Ezr/hv6Yg4byQz4DOtc67zrHOuM+MzrzOt869LCDOv+G9lc+Ez4kgz4DOuc64"
+ "zrHOveG/ts+CIOG8lM67zrXOs86/zr0uIM6azrHOr8+Ezr/OuSDhvIDOu863zrjOrc+CIM6zzrUg"
+ "4b2hz4Ig4byUz4DOv8+CIM614bywz4DOteG/ls69IM6/4b2QzrThvbLOvSDOteG8sM+Bzq7Ous6x"
+ "z4POuc69Lg==";
+
+static const char *plato_utf16le_base64 =
+ "TR/EA7kDIAC8A3IfvQMgAFEfvAO1A9YfwgMsACAAZh8gAAQfvQO0A8EDtQPCAyAAhgO4A7cDvQOx"
+ "A9YfvwO5AywAIADAA7UDwAPMA70DuAOxA8QDtQMgAFEfwAN4HyAAxAP2H70DIAAQH7wD9h+9AyAA"
+ "ugOxA8QDtwOzA8wDwQPJA70DLAAgAL8DUB+6AyAAvwM2H7QDsQM6ACAAEB+zA3wfIAC0AycAIAC/"
+ "A1YfvQMgALoDsQN2HyAAsQNQH8QDeB/CAyAAUR/AAycAIACxA1AfxAP2H70DIABAH7sDrwOzA78D"
+ "xQMgABAfvAOxA8UDxAO/A+YfIAAQH8ADtQO7A7EDuAPMA7wDtwO9AywAIAC/A1UfxAPJAyAAwAO5"
+ "A7gDsQO9A/YfwgMgABQfuwO1A7MDvwO9Ay4AIACaA7EDrwPEA78DuQMgAAAfuwO3A7gDrQPCAyAA"
+ "swO1AyAAYR/CAyAAFB/AA78DwgMgALUDMB/AA7UD1h+9AyAAvwNQH7QDch+9AyAAtQMwH8EDrgO6"
+ "A7EDwwO5A70DLgA=";
+
+static const char *plato_latin_utf8_base64 =
+ "SMOzdGkgbcOobiBodW1lw65zLCDDtCDDoW5kcmVzIEF0aMSTbmHDrm9pLCBwZXDDs250aGF0ZSBo"
+ "dXDDsiB0w7RuIGVtw7RuIGthdMSTZ8OzcsWNbiwgb3VrIG/DrmRhOiBlZ+G5kSBkJyBvw7tuIGth"
+ "w6wgYXV0w7JzIGh1cCcgYXV0xY1uIG9sw61nb3UgZW1hdXRvw7sgZXBlbGF0aMOzbcSTbiwgaG/D"
+ "unTFjSBwaXRoYW7DtHMgw6lsZWdvbi4gS2HDrXRvaSBhbMSTdGjDqXMgZ2UgaMWNcyDDqXBvcyBl"
+ "aXBlw65uIG91ZMOobiBlaXLhuJdrYXNpbi4=";
+
+static const char *plato_latin_utf16le_base64 =
+ "SADzAHQAaQAgAG0A6ABuACAAaAB1AG0AZQDuAHMALAAgAPQAIADhAG4AZAByAGUAcwAgAEEAdABo"
+ "ABMBbgBhAO4AbwBpACwAIABwAGUAcADzAG4AdABoAGEAdABlACAAaAB1AHAA8gAgAHQA9ABuACAA"
+ "ZQBtAPQAbgAgAGsAYQB0ABMBZwDzAHIATQFuACwAIABvAHUAawAgAG8A7gBkAGEAOgAgAGUAZwBR"
+ "HiAAZAAnACAAbwD7AG4AIABrAGEA7AAgAGEAdQB0APIAcwAgAGgAdQBwACcAIABhAHUAdABNAW4A"
+ "IABvAGwA7QBnAG8AdQAgAGUAbQBhAHUAdABvAPsAIABlAHAAZQBsAGEAdABoAPMAbQATAW4ALAAg"
+ "AGgAbwD6AHQATQEgAHAAaQB0AGgAYQBuAPQAcwAgAOkAbABlAGcAbwBuAC4AIABLAGEA7QB0AG8A"
+ "aQAgAGEAbAATAXQAaADpAHMAIABnAGUAIABoAE0BcwAgAOkAcABvAHMAIABlAGkAcABlAO4AbgAg"
+ "AG8AdQBkAOgAbgAgAGUAaQByABceawBhAHMAaQBuAC4A";
+
+static const char *gd_utf8_base64 = "R8O8bnRoZXIgRGVzY2huZXI=";
+static const char *gd_utf8_upper_base64 = "R8OcTlRIRVIgREVTQ0hORVI=";
+static const char *gd_utf8_lower_base64 = "Z8O8bnRoZXIgZGVzY2huZXI=";
+static const char *gd_cp850_base64 = "R4FudGhlciBEZXNjaG5lcg==";
+static const char *gd_cp850_upper_base64 = "R5pOVEhFUiBERVNDSE5FUg==";
+static const char *gd_cp850_lower_base64 = "Z4FudGhlciBkZXNjaG5lcg==";
+static const char *gd_iso8859_1_base64 = "R/xudGhlciBEZXNjaG5lcg==";
+static const char *gd_utf16le_base64 = "RwD8AG4AdABoAGUAcgAgAEQAZQBzAGMAaABuAGUAcgA=";
+/* täst */
+static const char *utf8_nfc_base64 = "dMOkc3QA";
+/* täst, where ä = a + combining diaeresis */
+static const char *utf8_nfd_base64 = "dGHMiHN0AA==";
+
+/*
+ * These cp850 bytes correspond to high Unicode codes, stretching out to
+ * 3-byte sequences in utf-8.
+ */
+static const char *cp850_high_points = "\xb9\xba\xbb\xbc\xcd\xce";
+static const char *utf8_high_points = "╣║╗╝═╬";
+
+static bool test_cp850_high_points(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle = NULL;
+ DATA_BLOB cp850 = data_blob_string_const(cp850_high_points);
+ DATA_BLOB utf8;
+ DATA_BLOB cp850_return;
+
+ iconv_handle = get_iconv_testing_handle(tctx, "CP850", "UTF8",
+ lpcfg_parm_bool(tctx->lp_ctx,
+ NULL,
+ "iconv",
+ "use_builtin_handlers",
+ true));
+
+ torture_assert(tctx, iconv_handle, "creating iconv handle");
+
+ torture_assert(tctx,
+ convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF8,
+ cp850.data, cp850.length,
+ (void *)&utf8.data, &utf8.length),
+ "conversion from CP850 to UTF-8");
+
+ torture_assert(tctx, utf8.length == cp850.length * 3,
+ "CP850 high bytes expand to the right size");
+
+ torture_assert(tctx,
+ memcmp(utf8.data, utf8_high_points, utf8.length) == 0,
+ "cp850 converted to utf8 matches expected value");
+
+ torture_assert(tctx,
+ convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_DOS,
+ utf8.data, utf8.length,
+ (void *)&cp850_return.data,
+ &cp850_return.length),
+ "conversion from UTF-8 back to CP850");
+
+ torture_assert(tctx, data_blob_cmp(&cp850_return, &cp850) == 0,
+ "UTF-8 returned to CP850 matches the original");
+ return true;
+}
+
+
+static bool test_gd_iso8859_cp850_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB gd_utf8 = base64_decode_data_blob(gd_utf8_base64);
+ DATA_BLOB gd_cp850 = base64_decode_data_blob(gd_cp850_base64);
+ DATA_BLOB gd_iso8859_1 = base64_decode_data_blob(gd_iso8859_1_base64);
+ DATA_BLOB gd_utf16le = base64_decode_data_blob(gd_utf16le_base64);
+ DATA_BLOB gd_output;
+ DATA_BLOB gd_output2;
+
+ talloc_steal(tctx, gd_utf8.data);
+ talloc_steal(tctx, gd_cp850.data);
+ talloc_steal(tctx, gd_iso8859_1.data);
+ talloc_steal(tctx, gd_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ISO-8859-1", "CP850",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting iconv handle");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from UTF8 to (dos charset) ISO-8859-1");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_iso8859_1, "conversion from UTF8 to (dos charset) ISO-8859-1 incorrect");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length),
+ "conversion from UTF8 to (dos charset) ISO-8859-1");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_iso8859_1, "conversion from UTF8 to (dos charset) ISO-8859-1 incorrect");
+
+ /* Short output handling confirmation */
+ gd_output.length = 1;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ISO-8859-1 should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to (dos charset) ISO-8859-1 should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+ torture_assert_data_blob_equal(tctx, gd_output, data_blob_string_const("G"), "conversion from UTF8 to (dos charset) ISO-8859-1 incorrect");
+
+ /* Short output handling confirmation */
+ gd_output.length = 2;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ISO-8859-1 should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to (dos charset) ISO-8859-1 should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 2, "Should only get 2 char of output");
+
+ /* Short input handling confirmation */
+ gd_output.length = gd_iso8859_1.length;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, 2,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ISO-8859-1 should fail due to too short");
+ torture_assert_errno_equal(tctx, EILSEQ, "conversion from short UTF8 to (dos charset) ISO-8859-1 should fail EINVAL");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+
+ /* Short output handling confirmation */
+ gd_output.length = 1;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le.data, gd_utf16le.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF16 to UTF8 should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16 to (utf8 charset) ISO-8859-1 should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+ torture_assert_data_blob_equal(tctx, gd_output, data_blob_string_const("G"), "conversion from UTF16 to UTF8 incorrect");
+
+ /* Short output handling confirmation */
+ gd_output.length = 3;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le.data, gd_utf16le.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF16 to UTF8 should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16 to (utf8 charset) ISO-8859-1 should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 3, "Should get 3 bytes output for UTF8");
+
+ /* Short input handling confirmation */
+ gd_output.length = gd_utf8.length;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le.data, 3,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF16 to UTF8 should fail due to too short");
+ torture_assert_errno_equal(tctx, EINVAL, "conversion from short UTF16 to UTF8 should fail EINVAL");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UNIX,
+ gd_utf8.data, gd_utf8.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from UTF8 to (unix charset) CP850");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_cp850, "conversion from UTF8 to (unix charset) CP850 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF8,
+ gd_utf8.data, gd_utf8.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from UTF8 to UTF8");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8, "conversion from UTF8 to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_DOS,
+ gd_utf16le.data, gd_utf16le.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from UTF16LE to (dos charset) ISO-8859-1");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_iso8859_1, "conversion from UTF16LE to (dos charset) ISO-8859-1 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF16LE,
+ gd_output.data, gd_output.length,
+ (void *)&gd_output2.data, &gd_output2.length),
+ "round trip conversion from (dos charset) ISO-8859-1 back to UTF16LE");
+ torture_assert_data_blob_equal(tctx, gd_output2, gd_utf16le, "round trip conversion from (dos charset) ISO-8859-1 back to UTF16LE");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UNIX,
+ gd_utf16le.data, gd_utf16le.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from UTF16LE to (unix charset) CP850");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_cp850, "conversion from UTF16LE to (unix charset) CP850 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le.data, gd_utf16le.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from UTF16LE to UTF8");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_DOS,
+ gd_iso8859_1.data, gd_iso8859_1.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from (dos charset) ISO-8859-1 to (dos charset) ISO-8859-1");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_iso8859_1, "conversion from UTF16LE to (dos charset) ISO-8859-1 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UNIX,
+ gd_iso8859_1.data, gd_iso8859_1.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from (dos charset) ISO-8859-1 to (unix charset) CP850");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_cp850, "conversion from UTF16LE to (unix charset) CP850 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF8,
+ gd_iso8859_1.data, gd_iso8859_1.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from (dos charset) ISO-8859-1 to UTF8");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF16LE,
+ gd_iso8859_1.data, gd_iso8859_1.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from (dos charset) ISO-8859-1 to UTF16LE");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf16le, "conversion from (dos charset) ISO-8859-1 to UTF16LE");
+ torture_assert_int_equal(tctx,
+ strlen_m_ext_handle(iconv_handle,
+ (const char *)gd_iso8859_1.data,
+ CH_DOS, CH_UTF16LE),
+ gd_output.length / 2,
+ "checking strlen_m_ext of round trip conversion of UTF16 latin charset greek to UTF8 and back again");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF8,
+ gd_iso8859_1.data, gd_iso8859_1.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from (dos charset) ISO-8859-1 to UTF8");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8, "conversion from (dos charset) ISO-8859-1 to UTF8");
+ torture_assert_int_equal(tctx,
+ strlen_m_ext_handle(iconv_handle,
+ (const char *)gd_iso8859_1.data,
+ CH_DOS, CH_UTF8),
+ gd_output.length,
+ "checking strlen_m_ext of conversion from (dos charset) ISO-8859-1 to UTF8");
+ return true;
+}
+
+static bool test_gd_minus_1_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB gd_utf8 = base64_decode_data_blob(gd_utf8_base64);
+ DATA_BLOB gd_cp850 = base64_decode_data_blob(gd_cp850_base64);
+ DATA_BLOB gd_utf16le = base64_decode_data_blob(gd_utf16le_base64);
+ DATA_BLOB gd_output;
+ DATA_BLOB gd_utf8_terminated;
+ DATA_BLOB gd_cp850_terminated;
+ DATA_BLOB gd_utf16le_terminated;
+
+ talloc_steal(tctx, gd_utf8.data);
+ talloc_steal(tctx, gd_cp850.data);
+ talloc_steal(tctx, gd_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "CP850", "CP850",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting iconv handle");
+
+ gd_utf8_terminated = data_blob_talloc(tctx, NULL, gd_utf8.length + 1);
+ memcpy(gd_utf8_terminated.data, gd_utf8.data, gd_utf8.length);
+ gd_utf8_terminated.data[gd_utf8.length] = '\0';
+
+ gd_cp850_terminated = data_blob_talloc(tctx, NULL, gd_cp850.length + 1);
+ memcpy(gd_cp850_terminated.data, gd_cp850.data, gd_cp850.length);
+ gd_cp850_terminated.data[gd_cp850.length] = '\0';
+
+ gd_utf16le_terminated = data_blob_talloc(tctx, NULL, gd_utf16le.length + 2);
+ memcpy(gd_utf16le_terminated.data, gd_utf16le.data, gd_utf16le.length);
+ gd_utf16le_terminated.data[gd_utf16le.length] = '\0';
+ gd_utf16le_terminated.data[gd_utf16le.length + 1] = '\0';
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ gd_utf8_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf16le.length + 10);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ gd_utf8_terminated.data, -1,
+ (void *)gd_output.data, gd_utf16le.length, &gd_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf16le, "conversion from UTF8 to UTF16LE null terminated");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf16le.length + 10);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ gd_utf8_terminated.data, -1,
+ (void *)gd_output.data, gd_utf16le.length - 1, &gd_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf16le.length + 10);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ gd_utf8_terminated.data, -1,
+ (void *)gd_output.data, gd_utf16le.length - 2, &gd_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf8.length + 10);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_utf8.length, &gd_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8, "conversion from UTF16LE to UTF8 null terminated");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_utf8.length - 1, &gd_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_utf8.length - 2, &gd_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_cp850.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_DOS,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF16LE to CP850 (dos) null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_cp850_terminated, "conversion from UTF16LE to CP850 (dos) null terminated");
+
+ /* Now null terminate the string early, the confirm we don't skip the NULL and convert any further */
+ gd_utf8_terminated.data[3] = '\0';
+ gd_utf8_terminated.length = 4; /* used for the comparison only */
+
+ gd_cp850_terminated.data[2] = '\0';
+ gd_cp850_terminated.length = 3; /* used for the comparison only */
+
+ gd_utf16le_terminated.data[4] = '\0';
+ gd_utf16le_terminated.data[5] = '\0';
+ gd_utf16le_terminated.length = 6; /* used for the comparison only */
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ gd_utf8_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated early");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated early");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_DOS, CH_UTF16LE,
+ gd_cp850_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from CP850 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated early");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_cp850.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_DOS,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_cp850_terminated, "conversion from UTF16LE to UTF8 null terminated early");
+
+ /* Now null terminate the string particularly early, the confirm we don't skip the NULL and convert any further */
+ gd_utf8_terminated.data[1] = '\0';
+ gd_utf8_terminated.length = 2; /* used for the comparison only */
+
+ gd_utf16le_terminated.data[2] = '\0';
+ gd_utf16le_terminated.data[3] = '\0';
+ gd_utf16le_terminated.length = 4; /* used for the comparison only */
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle, CH_UTF8, CH_UTF16LE,
+ gd_utf8_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated very early");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ gd_utf16le_terminated.data, -1,
+ (void *)gd_output.data, gd_output.length, &gd_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, gd_output, gd_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated very early");
+
+ return true;
+}
+
+static bool test_gd_ascii_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB gd_utf8 = base64_decode_data_blob(gd_utf8_base64);
+ DATA_BLOB gd_cp850 = base64_decode_data_blob(gd_cp850_base64);
+ DATA_BLOB gd_iso8859_1 = base64_decode_data_blob(gd_iso8859_1_base64);
+ DATA_BLOB gd_utf16le = base64_decode_data_blob(gd_utf16le_base64);
+ DATA_BLOB gd_output;
+
+ talloc_steal(tctx, gd_utf8.data);
+ talloc_steal(tctx, gd_cp850.data);
+ talloc_steal(tctx, gd_iso8859_1.data);
+ talloc_steal(tctx, gd_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ASCII", "UTF8",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting iconv handle");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)&gd_output.data, &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ASCII should fail");
+
+ gd_output = data_blob_talloc(tctx, NULL, gd_utf8.length);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ASCII should fail");
+ torture_assert_errno_equal(tctx, EILSEQ, "conversion from UTF8 to (dos charset) ISO-8859-1 should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+ torture_assert_data_blob_equal(tctx, gd_output, data_blob_string_const("G"), "partial conversion from UTF8 to (dos charset) ASCII incorrect");
+
+ /* Short output handling confirmation */
+ gd_output.length = 1;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ASCII should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to (dos charset) ASCII too short");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+ torture_assert_data_blob_equal(tctx, gd_output, data_blob_string_const("G"), "conversion from UTF8 to (dos charset) ASCII incorrect");
+
+ /* Short output handling confirmation */
+ gd_output.length = 2;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ASCII should fail due to illegal sequence");
+ torture_assert_errno_equal(tctx, EILSEQ, "conversion from UTF8 to (dos charset) ISO-8859-1 should fail EILSEQ");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 2 char of output");
+
+ /* Short input handling confirmation */
+ gd_output.length = gd_utf8.length;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_DOS,
+ gd_utf8.data, 2,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to (dos charset) ASCII should fail due to too short");
+ torture_assert_errno_equal(tctx, EILSEQ, "conversion from short UTF8 to (dos charset) ASCII should fail EILSEQ");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+ return true;
+}
+
+static bool test_plato_english_iso8859_cp850_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB plato_english_utf8 = data_blob_string_const(plato_english_ascii);
+ DATA_BLOB plato_english_cp850 = plato_english_utf8;
+ DATA_BLOB plato_english_iso8859_1 = plato_english_utf8;
+ DATA_BLOB plato_english_utf16le = base64_decode_data_blob(plato_english_utf16le_base64);
+ DATA_BLOB plato_english_output;
+ DATA_BLOB plato_english_output2;
+
+ talloc_steal(tctx, plato_english_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ISO-8859-1", "CP850",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting iconv handle");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_DOS,
+ plato_english_utf8.data, plato_english_utf8.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from UTF8 to (dos charset) ISO-8859-1");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_iso8859_1, "conversion from UTF8 to (dos charset) ISO-8859-1 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UNIX,
+ plato_english_utf8.data, plato_english_utf8.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from UTF8 to (unix charset) CP850");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_cp850, "conversion from UTF8 to (unix charset) CP850 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF8,
+ plato_english_utf8.data, plato_english_utf8.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from UTF8 to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8, "conversion from UTF8 to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_DOS,
+ plato_english_utf16le.data, plato_english_utf16le.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from UTF16LE to (dos charset) ISO-8859-1");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_iso8859_1, "conversion from UTF16LE to (dos charset) ISO-8859-1 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF16LE,
+ plato_english_output.data, plato_english_output.length,
+ (void *)&plato_english_output2.data, &plato_english_output2.length),
+ "round trip conversion from (dos charset) ISO-8859-1 back to UTF16LE");
+ torture_assert_data_blob_equal(tctx, plato_english_output2, plato_english_utf16le, "round trip conversion from (dos charset) ISO-8859-1 back to UTF16LE");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le.data, plato_english_utf16le.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from UTF16LE to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le.data, plato_english_utf16le.length,
+ (void *)plato_english_output.data, plato_english_output.length,
+ &plato_english_output.length),
+ "conversion from UTF16LE to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ plato_english_output.length = 5;
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le.data, plato_english_utf16le.length,
+ (void *)plato_english_output.data, plato_english_output.length,
+ &plato_english_output.length) == false,
+ "conversion from UTF16LE to UTF8 should fail due to short output");
+ torture_assert_data_blob_equal(tctx, plato_english_output, data_blob_string_const("What "), "conversion from UTF16LE to UTF8 incorrect");
+ torture_assert_int_equal(tctx, plato_english_output.length, 5, "short conversion failed");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UNIX,
+ plato_english_utf16le.data, plato_english_utf16le.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from UTF16LE to (unix charset) CP850");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_cp850, "conversion from UTF16LE to (unix charset) CP850 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le.data, plato_english_utf16le.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from UTF16LE to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_DOS,
+ plato_english_iso8859_1.data, plato_english_iso8859_1.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from (dos charset) ISO-8859-1 to (dos charset) ISO-8859-1");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_iso8859_1, "conversion from UTF16LE to (dos charset) ISO-8859-1 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UNIX,
+ plato_english_iso8859_1.data, plato_english_iso8859_1.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from (dos charset) ISO-8859-1 to (unix charset) CP850");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_cp850, "conversion from UTF16LE to (unix charset) CP850 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF8,
+ plato_english_iso8859_1.data, plato_english_iso8859_1.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from (dos charset) ISO-8859-1 to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_DOS, CH_UTF16LE,
+ plato_english_iso8859_1.data, plato_english_iso8859_1.length,
+ (void *)&plato_english_output.data, &plato_english_output.length),
+ "conversion from (dos charset) ISO-8859-1 to UTF16LE");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf16le, "conversion from (dos charset) ISO-8859-1 to UTF16LE");
+ return true;
+}
+
+static bool test_plato_english_minus_1_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB plato_english_utf8 = data_blob_string_const(plato_english_ascii);
+ DATA_BLOB plato_english_utf16le = base64_decode_data_blob(plato_english_utf16le_base64);
+ DATA_BLOB plato_english_output;
+ DATA_BLOB plato_english_utf8_terminated;
+ DATA_BLOB plato_english_utf16le_terminated;
+
+ talloc_steal(tctx, plato_english_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ISO-8859-1", "CP850",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting iconv handle");
+
+ plato_english_utf8_terminated = data_blob_talloc(tctx, NULL, plato_english_utf8.length + 1);
+ memcpy(plato_english_utf8_terminated.data, plato_english_utf8.data, plato_english_utf8.length);
+ plato_english_utf8_terminated.data[plato_english_utf8.length] = '\0';
+
+ plato_english_utf16le_terminated = data_blob_talloc(tctx, NULL, plato_english_utf16le.length + 2);
+ memcpy(plato_english_utf16le_terminated.data, plato_english_utf16le.data, plato_english_utf16le.length);
+ plato_english_utf16le_terminated.data[plato_english_utf16le.length] = '\0';
+ plato_english_utf16le_terminated.data[plato_english_utf16le.length + 1] = '\0';
+
+ plato_english_output = data_blob_talloc(tctx, NULL, plato_english_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_english_utf8_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_output.length, &plato_english_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_english_utf8_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_utf16le.length, &plato_english_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf16le, "conversion from UTF8 to UTF16LE null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_english_utf8_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_utf16le.length - 1, &plato_english_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_english_utf8_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_utf16le.length - 2, &plato_english_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+
+ plato_english_output = data_blob_talloc(tctx, NULL, plato_english_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_output.length, &plato_english_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_utf8.length, &plato_english_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8, "conversion from UTF16LE to UTF8 null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_utf8.length - 1, &plato_english_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_utf8.length - 2, &plato_english_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+
+ /* Now null terminate the string early, the confirm we don't skip the NULL and convert any further */
+ plato_english_utf8_terminated.data[3] = '\0';
+ plato_english_utf8_terminated.length = 4; /* used for the comparison only */
+
+ plato_english_utf16le_terminated.data[6] = '\0';
+ plato_english_utf16le_terminated.data[7] = '\0';
+ plato_english_utf16le_terminated.length = 8; /* used for the comparison only */
+
+ plato_english_output = data_blob_talloc(tctx, NULL, plato_english_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_english_utf8_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_output.length, &plato_english_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated early");
+
+ plato_english_output = data_blob_talloc(tctx, NULL, plato_english_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_output.length, &plato_english_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated early");
+
+
+ /* Now null terminate the string particularly early, the confirm we don't skip the NULL and convert any further */
+ plato_english_utf8_terminated.data[1] = '\0';
+ plato_english_utf8_terminated.length = 2; /* used for the comparison only */
+
+ plato_english_utf16le_terminated.data[2] = '\0';
+ plato_english_utf16le_terminated.data[3] = '\0';
+ plato_english_utf16le_terminated.length = 4; /* used for the comparison only */
+
+ plato_english_output = data_blob_talloc(tctx, NULL, plato_english_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle, CH_UTF8, CH_UTF16LE,
+ plato_english_utf8_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_output.length, &plato_english_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated very early");
+
+ plato_english_output = data_blob_talloc(tctx, NULL, plato_english_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_english_utf16le_terminated.data, -1,
+ (void *)plato_english_output.data, plato_english_output.length, &plato_english_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, plato_english_output, plato_english_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated very early");
+
+ return true;
+}
+
+static bool test_plato_minus_1_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB plato_utf8 = base64_decode_data_blob(plato_utf8_base64);
+ DATA_BLOB plato_utf16le = base64_decode_data_blob(plato_utf16le_base64);
+ DATA_BLOB plato_output;
+ DATA_BLOB plato_utf8_terminated;
+ DATA_BLOB plato_utf16le_terminated;
+
+ talloc_steal(tctx, plato_utf8.data);
+ talloc_steal(tctx, plato_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ISO-8859-1", "CP850",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting iconv handle");
+
+ plato_utf8_terminated = data_blob_talloc(tctx, NULL, plato_utf8.length + 1);
+ memcpy(plato_utf8_terminated.data, plato_utf8.data, plato_utf8.length);
+ plato_utf8_terminated.data[plato_utf8.length] = '\0';
+
+ plato_utf16le_terminated = data_blob_talloc(tctx, NULL, plato_utf16le.length + 2);
+ memcpy(plato_utf16le_terminated.data, plato_utf16le.data, plato_utf16le.length);
+ plato_utf16le_terminated.data[plato_utf16le.length] = '\0';
+ plato_utf16le_terminated.data[plato_utf16le.length + 1] = '\0';
+
+ plato_output = data_blob_talloc(tctx, NULL, plato_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8_terminated.data, -1,
+ (void *)plato_output.data, plato_output.length, &plato_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8_terminated.data, -1,
+ (void *)plato_output.data, plato_utf16le.length, &plato_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf16le, "conversion from UTF8 to UTF16LE null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8_terminated.data, -1,
+ (void *)plato_output.data, plato_utf16le.length - 1, &plato_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8_terminated.data, -1,
+ (void *)plato_output.data, plato_utf16le.length - 2, &plato_output.length) == false,
+ "conversion from UTF8 to UTF16LE null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to UTF16LE should fail E2BIG");
+
+ plato_output = data_blob_talloc(tctx, NULL, plato_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le_terminated.data, -1,
+ (void *)plato_output.data, plato_output.length, &plato_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le_terminated.data, -1,
+ (void *)plato_output.data, plato_utf8.length, &plato_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8, "conversion from UTF16LE to UTF8 null terminated");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le_terminated.data, -1,
+ (void *)plato_output.data, plato_utf8.length - 1, &plato_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le_terminated.data, -1,
+ (void *)plato_output.data, plato_utf8.length - 2, &plato_output.length) == false,
+ "conversion from UTF16LE to UTF8 null terminated should fail");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16LE to UTF8 should fail E2BIG");
+
+ /* Now null terminate the string early, the confirm we don't skip the NULL and convert any further */
+ plato_utf8_terminated.data[5] = '\0';
+ plato_utf8_terminated.length = 6; /* used for the comparison only */
+
+ plato_utf16le_terminated.data[4] = '\0';
+ plato_utf16le_terminated.data[5] = '\0';
+ plato_utf16le_terminated.length = 6; /* used for the comparison only */
+
+ plato_output = data_blob_talloc(tctx, NULL, plato_utf16le.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8_terminated.data, -1,
+ (void *)plato_output.data, plato_output.length, &plato_output.length),
+ "conversion from UTF8 to UTF16LE null terminated");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf16le_terminated, "conversion from UTF8 to UTF16LE null terminated early");
+
+ plato_output = data_blob_talloc(tctx, NULL, plato_utf8.length + 10);
+
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le_terminated.data, -1,
+ (void *)plato_output.data, plato_output.length, &plato_output.length),
+ "conversion from UTF16LE to UTF8 null terminated");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8_terminated, "conversion from UTF16LE to UTF8 null terminated early");
+
+ return true;
+}
+
+static bool test_plato_cp850_utf8_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB plato_utf8 = base64_decode_data_blob(plato_utf8_base64);
+ DATA_BLOB plato_utf16le = base64_decode_data_blob(plato_utf16le_base64);
+ DATA_BLOB plato_output;
+ DATA_BLOB plato_output2;
+
+ talloc_steal(tctx, plato_utf8.data);
+ talloc_steal(tctx, plato_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "CP850", "UTF8",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "creating iconv handle");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf16le, "conversion from UTF8 to UTF16LE incorrect");
+
+ torture_assert_int_equal(tctx,
+ strlen_m_ext_handle(iconv_handle,
+ (const char *)plato_utf8.data,
+ CH_UTF8, CH_UTF16LE),
+ plato_output.length / 2,
+ "checking strlen_m_ext of conversion of UTF8 to UTF16LE");
+
+ memset(plato_output.data, '\0', plato_output.length);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8.data, plato_utf8.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf16le, "conversion from UTF8 to UTF16LE incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_output.data, plato_output.length,
+ (void *)&plato_output2.data, &plato_output2.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output2, plato_utf8, "conversion from UTF8 to UTF16LE incorrect");
+
+ memset(plato_output2.data, '\0', plato_output2.length);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_output.data, plato_output.length,
+ (void *)plato_output2.data, plato_output2.length, &plato_output2.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output2, plato_utf8, "conversion from UTF8 to UTF16LE incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF8,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF8 to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8,
+ "conversion of UTF8 to UTF8");
+ torture_assert_int_equal(tctx,
+ strlen_m_ext_handle(iconv_handle,
+ (const char *)plato_utf8.data,
+ CH_UTF8, CH_UTF8),
+ plato_output.length,
+ "checking strlen_m_ext of conversion of UTF8 to UTF8");
+ memset(plato_output.data, '\0', plato_output.length);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UTF8,
+ plato_utf8.data, plato_utf8.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length),
+ "conversion of UTF8 to UTF8");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_DOS,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length) == false,
+ "conversion of UTF8 ancient greek to DOS charset CP850 should fail");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UNIX,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF16 ancient greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8, "conversion from UTF8 to (unix charset) UTF8 incorrect");
+
+ memset(plato_output.data, '\0', plato_output.length);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF8, CH_UNIX,
+ plato_utf8.data, plato_utf8.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length),
+ "conversion of UTF16 ancient greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8, "conversion from UTF8 to (unix charset) UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF8,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF16 ancient greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8, "conversion from UTF8 to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_DOS,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)&plato_output.data, &plato_output.length) == false,
+ "conversion of UTF16 ancient greek to DOS charset CP850 should fail");
+
+ /* Allocate enough space, if it were possible do do the conversion */
+ plato_output = data_blob_talloc(tctx, NULL, plato_utf16le.length);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_DOS,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length) == false,
+ "conversion of UTF16 ancient greek to DOS charset CP850 should fail");
+ torture_assert_errno_equal(tctx, EILSEQ, "conversion of UTF16 ancient greek to DOS charset CP850 should fail");
+
+ /* Allocate only enough space for a partial conversion */
+ plato_output = data_blob_talloc(tctx, NULL, 9);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length) == false,
+ "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_int_equal(tctx, plato_output.length, 8,
+ "conversion of UTF16 ancient greek to UTF8 should stop on multibyte boundary");
+
+ plato_output = data_blob_talloc(tctx, NULL, 2);
+ torture_assert(tctx, convert_string_error_handle(iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length) == false,
+ "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_int_equal(tctx, plato_output.length, 0,
+ "conversion of UTF16 ancient greek to UTF8 should stop on multibyte boundary");
+
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UNIX,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF16 ancient greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8, "conversion from UTF16LE to (unix charset) UTF8 incorrect");
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF16 ancient greek to UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8, "conversion from UTF16LE to UTF8 incorrect");
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF16 ancient greek to UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_output.data, plato_output.length,
+ (void *)&plato_output2.data, &plato_output2.length),
+ "round trip conversion of UTF16 ancient greek to UTF8 and back again failed");
+ torture_assert_data_blob_equal(tctx, plato_output2, plato_utf16le,
+ "round trip conversion of UTF16 ancient greek to UTF8 and back again failed");
+ torture_assert_int_equal(tctx,
+ strlen_m_ext_handle(iconv_handle,
+ (const char *)plato_output.data,
+ CH_UTF8, CH_UTF16LE),
+ plato_output2.length / 2,
+ "checking strlen_m_ext of round trip conversion of UTF16 latin charset greek to UTF8 and back again");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF8,
+ plato_output.data, plato_output.length,
+ (void *)&plato_output2.data, &plato_output2.length),
+ "conversion of UTF8 to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_output2, plato_utf8,
+ "conversion of UTF8 to UTF8");
+ torture_assert_int_equal(tctx,
+ strlen_m_ext_handle(iconv_handle,
+ (const char *)plato_output.data,
+ CH_UTF8, CH_UTF8),
+ plato_output2.length,
+ "checking strlen_m_ext of conversion of UTF8 to UTF8");
+ return true;
+}
+
+static bool test_plato_latin_cp850_utf8_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB plato_latin_utf8 = base64_decode_data_blob(plato_latin_utf8_base64);
+ DATA_BLOB plato_latin_utf16le = base64_decode_data_blob(plato_latin_utf16le_base64);
+ DATA_BLOB plato_latin_output;
+ DATA_BLOB plato_latin_output2;
+
+ talloc_steal(tctx, plato_latin_utf8.data);
+ talloc_steal(tctx, plato_latin_utf16le.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "CP850", "UTF8",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "creating iconv handle");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_DOS,
+ plato_latin_utf8.data, plato_latin_utf8.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length) == false,
+ "conversion of UTF8 latin charset greek to DOS charset CP850 should fail");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UNIX,
+ plato_latin_utf8.data, plato_latin_utf8.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length),
+ "conversion of UTF16 latin charset greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_latin_output, plato_latin_utf8, "conversion from UTF8 to (unix charset) UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF8,
+ plato_latin_utf8.data, plato_latin_utf8.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length),
+ "conversion of UTF16 latin charset greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_latin_output, plato_latin_utf8, "conversion from UTF8 to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_DOS,
+ plato_latin_utf16le.data, plato_latin_utf16le.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length) == false,
+ "conversion of UTF16 latin charset greek to DOS charset CP850 should fail");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UNIX,
+ plato_latin_utf16le.data, plato_latin_utf16le.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length),
+ "conversion of UTF16 latin charset greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_latin_output, plato_latin_utf8, "conversion from UTF16LE to (unix charset) CP850 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF16LE, CH_UTF8,
+ plato_latin_utf16le.data, plato_latin_utf16le.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length),
+ "conversion of UTF16 latin charset greek to UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_latin_output, plato_latin_utf8, "conversion from UTF16LE to UTF8 incorrect");
+
+ torture_assert(tctx, convert_string_talloc_handle(tctx, iconv_handle,
+ CH_UTF8, CH_UTF16LE,
+ plato_latin_output.data, plato_latin_output.length,
+ (void *)&plato_latin_output2.data, &plato_latin_output2.length),
+ "round trip conversion of UTF16 latin charset greek to UTF8 and back again failed");
+ torture_assert_data_blob_equal(tctx, plato_latin_output2, plato_latin_utf16le,
+ "round trip conversion of UTF16 latin charset greek to UTF8 and back again failed");
+ torture_assert_int_equal(tctx,
+ strlen_m_ext_handle(iconv_handle,
+ (const char *)plato_latin_output.data,
+ CH_UTF8, CH_UTF16LE),
+ plato_latin_output2.length / 2,
+ "checking strlen_m_ext of round trip conversion of UTF16 latin charset greek to UTF8 and back again");
+ return true;
+}
+
+static bool test_utf8_nfc_to_nfd_overflow(struct torture_context *tctx)
+{
+ smb_iconv_t ic;
+ DATA_BLOB utf8_nfc_blob;
+ DATA_BLOB utf8_nfd_blob;
+ DATA_BLOB src_blob;
+ DATA_BLOB blob;
+ size_t nconv;
+ const char *src = NULL;
+ char *dst = NULL;
+ size_t dst_left;
+ size_t srclen;
+ bool ret = true;
+
+ ic = smb_iconv_open("UTF8-NFD", "UTF8-NFC");
+ torture_assert_goto(tctx, ic != (smb_iconv_t)-1, ret, done,
+ "creating iconv handle\n");
+
+ utf8_nfc_blob = base64_decode_data_blob_talloc(tctx, utf8_nfc_base64);
+ torture_assert_not_null_goto(tctx, utf8_nfc_blob.data, ret, done,
+ "OOM\n");
+
+ utf8_nfd_blob = base64_decode_data_blob_talloc(tctx, utf8_nfd_base64);
+ torture_assert_not_null_goto(tctx, utf8_nfd_blob.data, ret, done,
+ "OOM\n");
+
+ blob = data_blob_talloc_zero(tctx, 255);
+ torture_assert_not_null_goto(tctx, blob.data, ret, done, "OOM\n");
+
+ /*
+ * Unfortunately the current implementation that performs the conversion
+ * (using libicu) returns EINVAL if the result buffer is too small, not
+ * E2BIG like iconv().
+ */
+
+ src = "foo";
+ srclen = 3;
+ dst = (char *)blob.data;
+ dst_left = 0;
+ nconv = smb_iconv(ic,
+ &src,
+ &srclen,
+ &dst,
+ &dst_left);
+ torture_assert_int_equal_goto(tctx, nconv, -1, ret, done,
+ "smb_iconv failed\n");
+ torture_assert_errno_equal_goto(tctx, EINVAL, ret, done,
+ "Wrong errno\n");
+
+ src = "foo";
+ srclen = 3;
+ dst = (char *)blob.data;
+ dst_left = 1;
+ nconv = smb_iconv(ic,
+ &src,
+ &srclen,
+ &dst,
+ &dst_left);
+ torture_assert_int_equal_goto(tctx, nconv, -1, ret, done,
+ "smb_iconv failed\n");
+ torture_assert_errno_equal_goto(tctx, EINVAL, ret, done,
+ "Wrong errno\n");
+
+ src = "foo";
+ srclen = 3;
+ dst = (char *)blob.data;
+ dst_left = 2;
+ nconv = smb_iconv(ic,
+ &src,
+ &srclen,
+ &dst,
+ &dst_left);
+ torture_assert_int_equal_goto(tctx, nconv, -1, ret, done,
+ "smb_iconv failed\n");
+ torture_assert_errno_equal_goto(tctx, EINVAL, ret, done,
+ "Wrong errno\n");
+
+ src_blob = data_blob_const("foo", 3);
+ src = (const char *)src_blob.data;
+ srclen = src_blob.length;
+ dst = (char *)blob.data;
+ dst_left = 3;
+ nconv = smb_iconv(ic,
+ &src,
+ &srclen,
+ &dst,
+ &dst_left);
+ torture_assert_int_equal_goto(tctx, nconv, 3, ret, done,
+ "smb_iconv failed\n");
+
+ blob.length = nconv;
+ torture_assert_data_blob_equal(tctx,
+ src_blob,
+ blob,
+ "Conversion failed\n");
+
+ src_blob = data_blob_const("foo", 4);
+ src = (const char *)src_blob.data;
+ srclen = src_blob.length;
+ dst = (char *)blob.data;
+ dst_left = 4;
+ nconv = smb_iconv(ic,
+ &src,
+ &srclen,
+ &dst,
+ &dst_left);
+ torture_assert_int_equal_goto(tctx, nconv, 4, ret, done,
+ "smb_iconv failed\n");
+
+ blob.length = nconv;
+ torture_assert_data_blob_equal(tctx,
+ src_blob,
+ blob,
+ "Conversion failed\n");
+
+done:
+ return ret;
+}
+
+static bool test_utf8_nfc_to_nfd(struct torture_context *tctx)
+{
+ smb_iconv_t ic;
+ DATA_BLOB utf8_nfc_blob;
+ DATA_BLOB utf8_nfd_blob;
+ DATA_BLOB blob;
+ size_t nconv;
+ const char *src = NULL;
+ char *dst = NULL;
+ size_t dst_left;
+ size_t srclen;
+ bool ret = true;
+
+ ic = smb_iconv_open("UTF8-NFD", "UTF8-NFC");
+ torture_assert_goto(tctx, ic != (smb_iconv_t)-1, ret, done,
+ "creating iconv handle\n");
+
+ utf8_nfc_blob = base64_decode_data_blob_talloc(tctx, utf8_nfc_base64);
+ torture_assert_not_null_goto(tctx, utf8_nfc_blob.data, ret, done,
+ "OOM\n");
+
+ utf8_nfd_blob = base64_decode_data_blob_talloc(tctx, utf8_nfd_base64);
+ torture_assert_not_null_goto(tctx, utf8_nfd_blob.data, ret, done,
+ "OOM\n");
+
+ blob = data_blob_talloc_zero(tctx, 255);
+ torture_assert_not_null_goto(tctx, blob.data, ret, done, "OOM\n");
+
+ dst = (char *)blob.data;
+ dst_left = blob.length;
+ src = (const char *)utf8_nfc_blob.data;
+ srclen = strlen(src);
+
+ nconv = smb_iconv(ic,
+ &src,
+ &srclen,
+ &dst,
+ &dst_left);
+ torture_assert_goto(tctx, nconv != (size_t)-1, ret, done,
+ "smb_iconv failed\n");
+
+ blob.length = nconv + 1; /* +1 for the trailing zero */
+ torture_assert_data_blob_equal(tctx,
+ blob,
+ utf8_nfd_blob,
+ "Conversion failed\n");
+
+done:
+ return ret;
+}
+
+static bool test_utf8_nfd_to_nfc(struct torture_context *tctx)
+{
+ smb_iconv_t ic;
+ DATA_BLOB utf8_nfc_blob;
+ DATA_BLOB utf8_nfd_blob;
+ DATA_BLOB blob;
+ size_t nconv;
+ const char *src = NULL;
+ char *dst = NULL;
+ size_t dst_left;
+ size_t srclen;
+ bool ret = true;
+
+ ic = smb_iconv_open("UTF8-NFC", "UTF8-NFD");
+ torture_assert_goto(tctx, ic != (smb_iconv_t)-1, ret, done,
+ "creating iconv handle\n");
+
+ utf8_nfc_blob = base64_decode_data_blob_talloc(tctx, utf8_nfc_base64);
+ torture_assert_not_null_goto(tctx, utf8_nfc_blob.data, ret, done,
+ "OOM\n");
+
+ utf8_nfd_blob = base64_decode_data_blob_talloc(tctx, utf8_nfd_base64);
+ torture_assert_not_null_goto(tctx, utf8_nfd_blob.data, ret, done,
+ "OOM\n");
+
+ blob = data_blob_talloc_zero(tctx, 255);
+ torture_assert_not_null_goto(tctx, blob.data, ret, done, "OOM\n");
+
+ dst = (char *)blob.data;
+ dst_left = blob.length;
+ src = (const char *)utf8_nfd_blob.data;
+ srclen = strlen(src);
+
+ nconv = smb_iconv(ic,
+ &src,
+ &srclen,
+ &dst,
+ &dst_left);
+ torture_assert_goto(tctx, nconv != (size_t)-1, ret, done,
+ "smb_iconv failed\n");
+
+ blob.length = nconv + 1; /* +1 for the trailing zero */
+ torture_assert_data_blob_equal(tctx,
+ blob,
+ utf8_nfc_blob,
+ "Conversion failed\n");
+
+done:
+ return ret;
+}
+
+static bool test_gd_case_utf8_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB gd_utf8 = base64_decode_data_blob(gd_utf8_base64);
+ DATA_BLOB gd_utf8_upper = base64_decode_data_blob(gd_utf8_upper_base64);
+ DATA_BLOB gd_utf8_lower = base64_decode_data_blob(gd_utf8_lower_base64);
+ char *gd_lower, *gd_upper;
+ talloc_steal(tctx, gd_utf8.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ASCII", "UTF8",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting utf8 iconv handle");
+
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, (const char *)gd_utf8.data),
+ "GD's name has an upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, (const char *)gd_utf8.data),
+ "GD's name has an lower case character");
+ gd_lower = strlower_talloc_handle(iconv_handle, tctx, (const char *)gd_utf8.data);
+ torture_assert(tctx, gd_lower, "failed to convert GD's name into lower case");
+ torture_assert_data_blob_equal(tctx, data_blob_string_const(gd_lower), gd_utf8_lower,
+ "convert GD's name into lower case");
+ gd_upper = strupper_talloc_n_handle(iconv_handle, tctx, (const char *)gd_utf8.data, gd_utf8.length);
+ torture_assert(tctx, gd_lower, "failed to convert GD's name into upper case");
+ torture_assert_data_blob_equal(tctx, data_blob_string_const(gd_upper), gd_utf8_upper,
+ "convert GD's name into upper case");
+
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, gd_upper),
+ "upper case name has an upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, gd_lower),
+ "lower case name has an lower case character");
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, gd_lower) == false,
+ "lower case name has no upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, gd_upper) == false,
+ "upper case name has no lower case character");
+
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, (const char *)gd_utf8.data,
+ gd_upper) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, (const char *)gd_utf8.data,
+ gd_lower) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, gd_upper,
+ gd_lower) == 0,
+ "case insensitive comparison upper/lower");
+
+ /* This string isn't different in length upper/lower */
+ torture_assert(tctx, strncasecmp_m_handle(iconv_handle, (const char *)gd_utf8.data,
+ gd_upper, gd_utf8.length) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strncasecmp_m_handle(iconv_handle, (const char *)gd_utf8.data,
+ gd_lower, gd_utf8.length) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strncasecmp_m_handle(iconv_handle, gd_upper,
+ gd_lower, gd_utf8.length) == 0,
+ "case insensitive comparison upper/lower");
+
+ data_blob_free(&gd_utf8);
+ data_blob_free(&gd_utf8_upper);
+ data_blob_free(&gd_utf8_lower);
+
+ return true;
+}
+
+static bool test_gd_case_cp850_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB gd_cp850 = base64_decode_data_blob(gd_cp850_base64);
+ DATA_BLOB gd_cp850_upper = base64_decode_data_blob(gd_cp850_upper_base64);
+ DATA_BLOB gd_cp850_lower = base64_decode_data_blob(gd_cp850_lower_base64);
+ char *gd_lower, *gd_upper;
+ talloc_steal(tctx, gd_cp850.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ASCII", "CP850",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting cp850 iconv handle");
+
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, (const char *)gd_cp850.data),
+ "GD's name has an upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, (const char *)gd_cp850.data),
+ "GD's name has an lower case character");
+ gd_lower = strlower_talloc_handle(iconv_handle, tctx, (const char *)gd_cp850.data);
+ torture_assert(tctx, gd_lower, "failed to convert GD's name into lower case");
+ torture_assert_data_blob_equal(tctx, data_blob_string_const(gd_lower), gd_cp850_lower,
+ "convert GD's name into lower case");
+ gd_upper = strupper_talloc_n_handle(iconv_handle, tctx, (const char *)gd_cp850.data, gd_cp850.length);
+ torture_assert(tctx, gd_lower, "failed to convert GD's name into upper case");
+ torture_assert_data_blob_equal(tctx, data_blob_string_const(gd_upper), gd_cp850_upper,
+ "convert GD's name into upper case");
+
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, gd_upper),
+ "upper case name has an upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, gd_lower),
+ "lower case name has an lower case character");
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, gd_lower) == false,
+ "lower case name has no upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, gd_upper) == false,
+ "upper case name has no lower case character");
+
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, (const char *)gd_cp850.data,
+ gd_upper) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, (const char *)gd_cp850.data,
+ gd_lower) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, gd_upper,
+ gd_lower) == 0,
+ "case insensitive comparison upper/lower");
+
+ /* This string isn't different in length upper/lower */
+ torture_assert(tctx, strncasecmp_m_handle(iconv_handle, (const char *)gd_cp850.data,
+ gd_upper, gd_cp850.length) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strncasecmp_m_handle(iconv_handle, (const char *)gd_cp850.data,
+ gd_lower, gd_cp850.length) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strncasecmp_m_handle(iconv_handle, gd_upper,
+ gd_lower, gd_cp850.length) == 0,
+ "case insensitive comparison upper/lower");
+
+ data_blob_free(&gd_cp850);
+ data_blob_free(&gd_cp850_upper);
+ data_blob_free(&gd_cp850_lower);
+
+ return true;
+}
+
+static bool test_plato_case_utf8_handle(struct torture_context *tctx)
+{
+ struct smb_iconv_handle *iconv_handle;
+ DATA_BLOB plato_utf8 = base64_decode_data_blob(plato_utf8_base64);
+ char *plato_lower, *plato_upper;
+ talloc_steal(tctx, plato_utf8.data);
+
+ iconv_handle = get_iconv_testing_handle(tctx, "ASCII", "UTF8",
+ lpcfg_parm_bool(tctx->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ torture_assert(tctx, iconv_handle, "getting utf8 iconv handle");
+
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, (const char *)plato_utf8.data),
+ "PLATO's apology has an upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, (const char *)plato_utf8.data),
+ "PLATO's apology has an lower case character");
+ plato_lower = strlower_talloc_handle(iconv_handle, tctx, (const char *)plato_utf8.data);
+ torture_assert(tctx, plato_lower, "failed to convert PLATO's apology into lower case");
+ plato_upper = strupper_talloc_n_handle(iconv_handle, tctx, (const char *)plato_utf8.data, plato_utf8.length);
+ torture_assert(tctx, plato_lower, "failed to convert PLATO's apology into upper case");
+
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, plato_upper),
+ "upper case string has an upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, plato_lower),
+ "lower case string has an lower case character");
+ torture_assert(tctx,
+ strhasupper_handle(iconv_handle, plato_lower) == false,
+ "lower case string has no upper case character");
+ torture_assert(tctx,
+ strhaslower_handle(iconv_handle, plato_upper) == false,
+ "upper case string has no lower case character");
+
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, (const char *)plato_utf8.data,
+ plato_upper) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, (const char *)plato_utf8.data,
+ plato_lower) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strcasecmp_m_handle(iconv_handle, plato_upper,
+ plato_lower) == 0,
+ "case insensitive comparison upper/lower");
+ return true;
+}
+
+static bool test_gd(struct torture_context *tctx)
+{
+ DATA_BLOB gd_utf8 = base64_decode_data_blob(gd_utf8_base64);
+ DATA_BLOB gd_cp850 = base64_decode_data_blob(gd_cp850_base64);
+ DATA_BLOB gd_iso8859_1 = base64_decode_data_blob(gd_iso8859_1_base64);
+ DATA_BLOB gd_utf16le = base64_decode_data_blob(gd_utf16le_base64);
+ DATA_BLOB gd_output;
+ size_t saved_len;
+
+ talloc_steal(tctx, gd_utf8.data);
+ talloc_steal(tctx, gd_cp850.data);
+ talloc_steal(tctx, gd_iso8859_1.data);
+ talloc_steal(tctx, gd_utf16le.data);
+
+ torture_assert(tctx, convert_string_talloc(tctx, CH_UTF8, CH_UTF8,
+ gd_utf8.data, gd_utf8.length,
+ (void *)&gd_output.data, &gd_output.length),
+ "conversion from UTF8 to utf8 charset");
+ saved_len = gd_output.length;
+
+ torture_assert(tctx, convert_string_error(CH_UTF8, CH_UTF8,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length),
+ "conversion from UTF8 to utf8 charset");
+
+ /* Short output handling confirmation */
+ gd_output.length = 1;
+ torture_assert(tctx, convert_string_error(CH_UTF8, CH_UTF8,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to any utf8 charset should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to utf8 charset should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+ torture_assert_data_blob_equal(tctx, gd_output, data_blob_string_const("G"), "conversion from UTF8 to utf8 charset incorrect");
+
+#if 0 /* This currently fails as we just copy like-for-like character conversions */
+ /* Short output handling confirmation */
+ gd_output.length = 2;
+ torture_assert(tctx, convert_string_error(CH_UTF8, CH_UTF8,
+ gd_utf8.data, gd_utf8.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to utf8 charset should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF8 to utf8 charset should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+
+ /* Short input handling confirmation */
+ gd_output.length = saved_len;
+ torture_assert(tctx, convert_string_error(CH_UTF8, CH_UTF8,
+ gd_utf8.data, 2,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF8 to UTF8 should fail due to too short");
+ torture_assert_errno_equal(tctx, EILSEQ, "conversion from short UTF8 to UTF8 should fail EINVAL");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+#endif
+
+ /* Short output handling confirmation */
+ gd_output.length = 1;
+ torture_assert(tctx, convert_string_error(CH_UTF16LE, CH_UTF8,
+ gd_utf16le.data, gd_utf16le.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF16 to UTF8 should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16 to UTF8 should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+ torture_assert_data_blob_equal(tctx, gd_output, data_blob_string_const("G"), "conversion from UTF16 to UTF8 incorrect");
+
+ /* Short output handling confirmation */
+ gd_output.length = 3;
+ torture_assert(tctx, convert_string_error(CH_UTF16LE, CH_UTF8,
+ gd_utf16le.data, gd_utf16le.length,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF16 to UTF8 should fail due to too short");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion from UTF16 to UTF8 should fail E2BIG");
+ torture_assert_int_equal(tctx, gd_output.length, 3, "Should get 3 bytes output for UTF8");
+
+ /* Short input handling confirmation */
+ gd_output.length = saved_len;
+ torture_assert(tctx, convert_string_error(CH_UTF16LE, CH_UTF8,
+ gd_utf16le.data, 3,
+ (void *)gd_output.data, gd_output.length,
+ &gd_output.length) == false,
+ "conversion from UTF16 to UTF8 should fail due to too short");
+ torture_assert_errno_equal(tctx, EINVAL, "conversion from short UTF16 to UTF8 should fail EINVAL");
+ torture_assert_int_equal(tctx, gd_output.length, 1, "Should only get 1 char of output");
+
+ return true;
+}
+
+static bool test_plato(struct torture_context *tctx)
+{
+ DATA_BLOB plato_utf8 = base64_decode_data_blob(plato_utf8_base64);
+ DATA_BLOB plato_utf16le = base64_decode_data_blob(plato_utf16le_base64);
+ DATA_BLOB plato_output;
+ DATA_BLOB plato_output2;
+
+ talloc_steal(tctx, plato_utf8.data);
+ talloc_steal(tctx, plato_utf16le.data);
+
+ torture_assert(tctx, convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf16le, "conversion from UTF8 to UTF16LE incorrect");
+
+ torture_assert_int_equal(tctx,
+ strlen_m_ext((const char *)plato_utf8.data,
+ CH_UTF8, CH_UTF16LE),
+ plato_output.length / 2,
+ "checking strlen_m_ext of conversion of UTF8 to UTF16LE");
+
+ memset(plato_output.data, '\0', plato_output.length);
+ torture_assert(tctx, convert_string_error(CH_UTF8, CH_UTF16LE,
+ plato_utf8.data, plato_utf8.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf16le, "conversion from UTF8 to UTF16LE incorrect");
+
+ torture_assert(tctx, convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ plato_output.data, plato_output.length,
+ (void *)&plato_output2.data, &plato_output2.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output2, plato_utf8, "conversion from UTF8 to UTF16LE incorrect");
+
+ memset(plato_output2.data, '\0', plato_output2.length);
+ torture_assert(tctx, convert_string_error(CH_UTF16LE, CH_UTF8,
+ plato_output.data, plato_output.length,
+ (void *)plato_output2.data, plato_output2.length, &plato_output2.length),
+ "conversion of UTF8 ancient greek to UTF16 failed");
+ torture_assert_data_blob_equal(tctx, plato_output2, plato_utf8, "conversion from UTF8 to UTF16LE incorrect");
+
+ torture_assert(tctx, convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF8,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length),
+ "conversion of UTF8 to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8,
+ "conversion of UTF8 to UTF8");
+ torture_assert_int_equal(tctx,
+ strlen_m_ext((const char *)plato_utf8.data,
+ CH_UTF8, CH_UTF8),
+ plato_output.length,
+ "checking strlen_m_ext of conversion of UTF8 to UTF8");
+ memset(plato_output.data, '\0', plato_output.length);
+ torture_assert(tctx, convert_string_error(CH_UTF8, CH_UTF8,
+ plato_utf8.data, plato_utf8.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length),
+ "conversion of UTF8 to UTF8");
+ torture_assert_data_blob_equal(tctx, plato_output, plato_utf8,
+ "conversion of UTF8 to UTF8");
+
+ memset(plato_output.data, '\0', plato_output.length);
+ torture_assert(tctx, convert_string_error(CH_UTF8, CH_DOS,
+ plato_utf8.data, plato_utf8.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length) == false,
+ "conversion of UTF8 to any dos charset should fail");
+ torture_assert_errno_equal(tctx, EILSEQ, "conversion of UTF16 ancient greek to any DOS charset should fail EILSEQ");
+
+ torture_assert(tctx, convert_string_talloc(tctx,
+ CH_UTF8, CH_DOS,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_output.data, &plato_output.length) == false,
+ "conversion of UTF8 ancient greek to any DOS charset should fail");
+
+ /* Allocate only enough space for a partial conversion */
+ plato_output = data_blob_talloc(tctx, NULL, 9);
+ torture_assert(tctx, convert_string_error(CH_UTF16LE, CH_UTF8,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length) == false,
+ "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_int_equal(tctx, plato_output.length, 8,
+ "conversion of UTF16 ancient greek to UTF8 should stop on multibyte boundary");
+
+ plato_output = data_blob_talloc(tctx, NULL, 2);
+ torture_assert(tctx, convert_string_error(CH_UTF16LE, CH_UTF8,
+ plato_utf16le.data, plato_utf16le.length,
+ (void *)plato_output.data, plato_output.length,
+ &plato_output.length) == false,
+ "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_errno_equal(tctx, E2BIG, "conversion of UTF16 ancient greek to UTF8 should fail, not enough space");
+ torture_assert_int_equal(tctx, plato_output.length, 0,
+ "conversion of UTF16 ancient greek to UTF8 should stop on multibyte boundary");
+
+
+ return true;
+}
+
+
+
+static bool test_short_strings(struct torture_context *tctx)
+{
+ char zeros[6] = {0};
+ char s[6] = {'s'};
+ bool ok;
+ char *out;
+ size_t out_len;
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ zeros, 0,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"\", 0} to utf16 failed");
+ torture_assert(tctx, out_len == 2, "{\"\", 0} length is two");
+ torture_assert(tctx, out[0] == 0 && out[1] == 0, "{\"\", 0} utf16 is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ zeros, 1,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"\\0\", 1} to utf16 failed");
+ torture_assert(tctx, out_len == 2, "{\"\\0\", 1} length is two");
+ torture_assert(tctx, out[0] == 0 && out[1] == 0, "{\"\\0\", 1} utf16 is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ zeros, 2,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"\\0\\0\", 2} to utf16 failed");
+ torture_assert(tctx, out_len == 4, "{\"\\0\\0\", 2} length is four");
+ torture_assert(tctx, out[0] == 0 && out[1] == 0, "{\"\\0\\0\", 2} utf16 is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ s, 0,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"s\", 0} to utf16 failed");
+ torture_assert(tctx, out_len == 2, "{\"s\", 0} length is two");
+ torture_assert(tctx, out[0] == 0 && out[1] == 0,
+ "{\"s\", 0} utf16 is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ s, 1,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"s\", 1} to utf16 failed");
+ torture_assert(tctx, out_len == 2, "{\"s\", 1} length is two");
+ torture_assert(tctx, out[0] == 's' && out[1] == 0,
+ "{\"s\", 1} utf16 is s");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ s, 2,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"s\\0\", 2} to utf16 failed");
+ torture_assert(tctx, out_len == 4, "{\"s\\0\", 2} length is four");
+ torture_assert(tctx, out[0] == 's' && out[1] == 0,
+ "{\"s\\0\", 0} utf16 is s");
+ TALLOC_FREE(out);
+
+
+ /* going to utf8 */
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ zeros, 0,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"\", 0} to utf8 failed");
+ torture_assert(tctx, out_len == 1, "{\"\", 0} length is one");
+ torture_assert(tctx, out[0] == 0, "{\"\", 0} utf8[0] is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ zeros, 2,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"\\0\", 1} to utf8 failed");
+ torture_assert(tctx, out_len == 1, "{\"\\0\", 1} length is one");
+ torture_assert(tctx, out[0] == 0 && out[1] == 0,
+ "{\"\\0\", 1} utf8 is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ zeros, 4,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"\\0\\0\\0\\0\", 4} to utf8 failed");
+ torture_assert(tctx, out_len == 2, "{\"\\0\\0\\0\\0\", 4} length is two");
+ torture_assert(tctx, out[0] == 0 && out[1] == 0,
+ "{\"\\0\\0\\0\\0\", 4} utf8 is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ s, 0,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"s\", 0} to utf8 failed");
+ torture_assert(tctx, out_len == 1, "{\"s\", 0} length is one");
+ torture_assert(tctx, out[0] == 0, "{\"s\", 0} utf8 is zero");
+ TALLOC_FREE(out);
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ s, 2,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"s\\0\", 2} to utf8 failed");
+ torture_assert(tctx, out_len == 1, "{\"s\\0\", 2} length is one");
+ torture_assert(tctx, out[0] == 's' && out[1] == 0,
+ "{\"s\\0\", 2} utf8 is s");
+ TALLOC_FREE(out);
+
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ s, 4,
+ &out, &out_len);
+ torture_assert(tctx, ok, "{\"s\\0\\0\\0\", 4} utf8 failed");
+ torture_assert(tctx, out_len == 2, "\"s\\0\\0\\0\", 4} utf8 length is two");
+ torture_assert(tctx, out[0] == 's' && out[1] == 0,
+ "{\"s\\0\\0\\0\", 4} utf8 is s");
+ TALLOC_FREE(out);
+
+ /* odd numbers of bytes from UTF-16 should fail */
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ s, 1,
+ &out, &out_len);
+ torture_assert(tctx, ! ok, "{\"s\", 1} to utf8 should have failed");
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ s, 3,
+ &out, &out_len);
+ torture_assert(tctx, ! ok, "{\"s\\0\\0\", 3} to utf8 should have failed");
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ zeros, 1,
+ &out, &out_len);
+ torture_assert(tctx, ! ok,
+ "{\"\\0\", 1} to utf8 should have failed");
+
+ ok = convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ zeros, 5,
+ &out, &out_len);
+ torture_assert(tctx, ! ok,
+ "{\"\\0\\0\\0\\0\", 5} to utf8 should have failed");
+
+ return true;
+}
+
+
+static bool test_plato_latin(struct torture_context *tctx)
+{
+ DATA_BLOB plato_latin_utf8 = base64_decode_data_blob(plato_latin_utf8_base64);
+ DATA_BLOB plato_latin_utf16le = base64_decode_data_blob(plato_latin_utf16le_base64);
+ DATA_BLOB plato_latin_output;
+
+ talloc_steal(tctx, plato_latin_utf8.data);
+ talloc_steal(tctx, plato_latin_utf16le.data);
+
+ torture_assert(tctx, convert_string_talloc(tctx,
+ CH_UTF16LE, CH_UTF8,
+ plato_latin_utf16le.data, plato_latin_utf16le.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length),
+ "conversion of UTF16 latin charset greek to unix charset UTF8 failed");
+ torture_assert_data_blob_equal(tctx, plato_latin_output, plato_latin_utf8, "conversion from UTF16 to UTF8 incorrect");
+
+ torture_assert_int_equal(tctx,
+ strlen_m_ext((const char *)plato_latin_output.data,
+ CH_UTF8, CH_UTF16LE),
+ plato_latin_utf16le.length / 2,
+ "checking strlen_m_ext UTF16 latin charset greek to UTF8");
+ torture_assert(tctx, convert_string_talloc(tctx,
+ CH_UTF8, CH_UTF16LE,
+ plato_latin_utf8.data, plato_latin_utf8.length,
+ (void *)&plato_latin_output.data, &plato_latin_output.length),
+ "conversion of UTF16 latin charset greek to UTF16LE failed");
+ torture_assert_data_blob_equal(tctx, plato_latin_output, plato_latin_utf16le, "conversion from UTF8 to UTF16LE incorrect");
+
+ return true;
+}
+
+static bool test_gd_case(struct torture_context *tctx)
+{
+ DATA_BLOB gd_utf8 = base64_decode_data_blob(gd_utf8_base64);
+ char *gd_unix;
+ size_t gd_size;
+ char *gd_lower, *gd_upper;
+ talloc_steal(tctx, gd_utf8.data);
+
+ torture_assert(tctx, convert_string_talloc(tctx, CH_UTF8, CH_UNIX,
+ gd_utf8.data, gd_utf8.length,
+ (void *)&gd_unix, &gd_size),
+ "conversion of unix charset to UTF8");
+
+ gd_lower = strlower_talloc(tctx, gd_unix);
+ torture_assert(tctx, gd_lower, "failed to convert GD's name into lower case");
+ gd_upper = strupper_talloc_n(tctx, gd_unix, gd_size);
+ torture_assert(tctx, gd_lower, "failed to convert GD's name into upper case");
+
+ torture_assert(tctx,
+ strhasupper(gd_unix),
+ "GD's name has an upper case character");
+ torture_assert(tctx,
+ strhaslower(gd_unix),
+ "GD's name has an lower case character");
+ torture_assert(tctx,
+ strhasupper(gd_upper),
+ "upper case name has an upper case character");
+ torture_assert(tctx,
+ strhaslower(gd_lower),
+ "lower case name has an lower case character");
+ torture_assert(tctx,
+ strhasupper(gd_lower) == false,
+ "lower case name has no upper case character");
+ torture_assert(tctx,
+ strhaslower(gd_upper) == false,
+ "upper case name has no lower case character");
+
+ torture_assert(tctx, strcasecmp_m(gd_unix,
+ gd_upper) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strcasecmp_m(gd_unix,
+ gd_lower) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strcasecmp_m(gd_upper,
+ gd_lower) == 0,
+ "case insensitive comparison upper/lower");
+
+ /* This string isn't different in length upper/lower, but just check the first 5 chars */
+ torture_assert(tctx, strncasecmp_m(gd_unix,
+ gd_upper, 5) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strncasecmp_m(gd_unix,
+ gd_lower, 5) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strncasecmp_m(gd_upper,
+ gd_lower, 5) == 0,
+ "case insensitive comparison upper/lower");
+ return true;
+}
+
+static bool test_plato_case(struct torture_context *tctx)
+{
+ DATA_BLOB plato_utf8 = base64_decode_data_blob(plato_utf8_base64);
+ char *plato_unix;
+ size_t plato_length;
+ char *plato_lower, *plato_upper;
+ talloc_steal(tctx, plato_utf8.data);
+
+ torture_assert(tctx, convert_string_talloc(tctx, CH_UTF8, CH_UNIX,
+ plato_utf8.data, plato_utf8.length,
+ (void *)&plato_unix, &plato_length),
+ "conversion of unix charset to UTF8");
+
+ torture_assert(tctx,
+ strhasupper(plato_unix),
+ "PLATO's apology has an upper case character");
+ torture_assert(tctx,
+ strhaslower(plato_unix),
+ "PLATO's apology has an lower case character");
+ plato_lower = strlower_talloc(tctx, plato_unix);
+ torture_assert(tctx, plato_lower, "failed to convert PLATO's apology into lower case");
+ plato_upper = strupper_talloc_n(tctx, plato_unix, plato_utf8.length);
+ torture_assert(tctx, plato_lower, "failed to convert PLATO's apology into upper case");
+
+ torture_assert(tctx,
+ strhasupper(plato_upper),
+ "upper case string has an upper case character");
+ torture_assert(tctx,
+ strhaslower(plato_lower),
+ "lower case string has an lower case character");
+ torture_assert(tctx,
+ strhasupper(plato_lower) == false,
+ "lower case string has no upper case character");
+ torture_assert(tctx,
+ strhaslower(plato_upper) == false,
+ "upper case string has no lower case character");
+
+ torture_assert(tctx, strcasecmp_m(plato_unix,
+ plato_upper) == 0,
+ "case insensitive comparison orig/upper");
+ torture_assert(tctx, strcasecmp_m(plato_unix,
+ plato_lower) == 0,
+ "case insensitive comparison orig/lower");
+ torture_assert(tctx, strcasecmp_m(plato_upper,
+ plato_lower) == 0,
+ "case insensitive comparison upper/lower");
+ return true;
+}
+
+struct torture_suite *torture_local_convert_string_handle(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "convert_string_handle");
+ torture_suite_add_simple_test(suite, "cp850 high points", test_cp850_high_points);
+
+ torture_suite_add_simple_test(suite, "gd_ascii", test_gd_ascii_handle);
+ torture_suite_add_simple_test(suite, "gd_minus_1", test_gd_minus_1_handle);
+ torture_suite_add_simple_test(suite, "gd_iso8859_cp850", test_gd_iso8859_cp850_handle);
+ torture_suite_add_simple_test(suite, "plato_english_iso8859_cp850", test_plato_english_iso8859_cp850_handle);
+ torture_suite_add_simple_test(suite, "plato_english_minus_1", test_plato_english_minus_1_handle);
+ torture_suite_add_simple_test(suite, "plato_cp850_utf8", test_plato_cp850_utf8_handle);
+ torture_suite_add_simple_test(suite, "plato_minus_1", test_plato_minus_1_handle);
+ torture_suite_add_simple_test(suite, "plato_latin_cp850_utf8", test_plato_latin_cp850_utf8_handle);
+ torture_suite_add_simple_test(suite, "utf8-nfc-to-nfd", test_utf8_nfc_to_nfd);
+ torture_suite_add_simple_test(suite, "utf8-nfc-to-nfd-overflow", test_utf8_nfc_to_nfd_overflow);
+ torture_suite_add_simple_test(suite, "utf8-nfd-to-nfc", test_utf8_nfd_to_nfc);
+ return suite;
+}
+
+struct torture_suite *torture_local_string_case_handle(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "string_case_handle");
+
+ torture_suite_add_simple_test(suite, "gd_case_utf8", test_gd_case_utf8_handle);
+ torture_suite_add_simple_test(suite, "gd_case_cp850", test_gd_case_cp850_handle);
+ torture_suite_add_simple_test(suite, "plato_case_utf8", test_plato_case_utf8_handle);
+ return suite;
+}
+
+struct torture_suite *torture_local_convert_string(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "convert_string");
+
+ torture_suite_add_simple_test(suite, "short_strings", test_short_strings);
+ torture_suite_add_simple_test(suite, "gd", test_gd);
+ torture_suite_add_simple_test(suite, "plato", test_plato);
+ torture_suite_add_simple_test(suite, "plato_latin", test_plato_latin);
+ return suite;
+}
+
+struct torture_suite *torture_local_string_case(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "string_case_handle");
+
+ torture_suite_add_simple_test(suite, "gd_case", test_gd_case);
+ torture_suite_add_simple_test(suite, "plato_case", test_plato_case);
+ return suite;
+}
diff --git a/lib/util/charset/tests/iconv.c b/lib/util/charset/tests/iconv.c
new file mode 100644
index 0000000..3733c3c
--- /dev/null
+++ b/lib/util/charset/tests/iconv.c
@@ -0,0 +1,495 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of iconv routines. This tests the system iconv code against
+ the built-in iconv code
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "system/iconv.h"
+#include "system/time.h"
+#include "libcli/raw/libcliraw.h"
+#include "param/param.h"
+#include "torture/util.h"
+#include "torture/local/proto.h"
+#include "talloc.h"
+
+#ifdef HAVE_NATIVE_ICONV
+
+static bool iconv_untestable(struct torture_context *tctx)
+{
+ iconv_t cd;
+
+ cd = iconv_open("UTF-16LE", "UCS-4LE");
+ if (cd == (iconv_t)-1)
+ torture_skip(tctx, "unable to test - system iconv library does not support UTF-16LE -> UCS-4LE");
+ iconv_close(cd);
+
+ cd = iconv_open("UTF-16LE", "CP850");
+ if (cd == (iconv_t)-1)
+ torture_skip(tctx, "unable to test - system iconv library does not support UTF-16LE -> CP850\n");
+ iconv_close(cd);
+
+ return false;
+}
+
+/*
+ generate a UTF-16LE buffer for a given unicode codepoint
+*/
+static int gen_codepoint_utf16(unsigned int codepoint,
+ char *buf, size_t *size)
+{
+ static iconv_t cd;
+ uint8_t in[4];
+ char *ptr_in;
+ size_t size_in, size_out, ret;
+ if (!cd) {
+ cd = iconv_open("UTF-16LE", "UCS-4LE");
+ if (cd == (iconv_t)-1) {
+ cd = NULL;
+ return -1;
+ }
+ }
+
+ in[0] = codepoint & 0xFF;
+ in[1] = (codepoint>>8) & 0xFF;
+ in[2] = (codepoint>>16) & 0xFF;
+ in[3] = (codepoint>>24) & 0xFF;
+
+ ptr_in = (char *)in;
+ size_in = 4;
+ size_out = 8;
+
+ ret = iconv(cd, &ptr_in, &size_in, &buf, &size_out);
+
+ *size = 8 - size_out;
+
+ return ret;
+}
+
+
+/*
+ work out the unicode codepoint of the first UTF-8 character in the buffer
+*/
+static unsigned int get_codepoint(char *buf, size_t size, const char *charset)
+{
+ iconv_t cd;
+ uint8_t out[4];
+ char *ptr_out;
+ size_t size_out, size_in, ret;
+
+ cd = iconv_open("UCS-4LE", charset);
+
+ size_in = size;
+ ptr_out = (char *)out;
+ size_out = sizeof(out);
+ memset(out, 0, sizeof(out));
+
+ ret = iconv(cd, &buf, &size_in, &ptr_out, &size_out);
+ iconv_close(cd);
+ if (ret == (size_t) -1) {
+ return (unsigned int)-1;
+ }
+
+ return out[0] | (out[1]<<8) | (out[2]<<16) | (out[3]<<24);
+}
+
+/*
+ display a buffer with name prefix
+*/
+static void show_buf(const char *name, uint8_t *buf, size_t size)
+{
+ int i;
+ printf("%s ", name);
+ for (i=0;i<size;i++) {
+ printf("%02x ", buf[i]);
+ }
+ printf("\n");
+}
+
+/*
+ given a UTF-16LE buffer, test the system and built-in iconv code to
+ make sure they do exactly the same thing in converting the buffer to
+ "charset", then convert it back again and ensure we get the same
+ buffer back
+*/
+static bool test_buffer(struct torture_context *test,
+ uint8_t *inbuf, size_t size, const char *charset)
+{
+ uint8_t buf1[1000], buf2[1000], buf3[1000];
+ size_t outsize1, outsize2, outsize3;
+ const char *ptr_in1;
+ char *ptr_in2;
+ char *ptr_out;
+ size_t size_in1, size_in2, size_in3;
+ size_t ret1, ret2, ret3, len1, len2;
+ int errno1, errno2;
+ static iconv_t cd;
+ static smb_iconv_t cd2, cd3;
+ static const char *last_charset;
+
+ if (cd && last_charset) {
+ iconv_close(cd);
+ smb_iconv_close(cd2);
+ smb_iconv_close(cd3);
+ cd = NULL;
+ }
+
+ if (!cd) {
+ cd = iconv_open(charset, "UTF-16LE");
+ if (cd == (iconv_t)-1) {
+ torture_fail(test,
+ talloc_asprintf(test,
+ "failed to open %s to UTF-16LE",
+ charset));
+ }
+ cd2 = smb_iconv_open_ex(test, charset, "UTF-16LE", lpcfg_parm_bool(test->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ if (cd2 == (iconv_t)-1) {
+ torture_fail(test,
+ talloc_asprintf(test,
+ "failed to open %s to UTF-16LE via smb_iconv_open_ex",
+ charset));
+ }
+ cd3 = smb_iconv_open_ex(test, "UTF-16LE", charset, lpcfg_parm_bool(test->lp_ctx, NULL, "iconv", "use_builtin_handlers", true));
+ if (cd3 == (iconv_t)-1) {
+ torture_fail(test,
+ talloc_asprintf(test,
+ "failed to open UTF-16LE to %s via smb_iconv_open_ex",
+ charset));
+ }
+ last_charset = charset;
+ }
+
+ /* internal convert to charset - placing result in buf1 */
+ ptr_in1 = (const char *)inbuf;
+ ptr_out = (char *)buf1;
+ size_in1 = size;
+ outsize1 = sizeof(buf1);
+
+ memset(ptr_out, 0, outsize1);
+ errno = 0;
+ ret1 = smb_iconv(cd2, &ptr_in1, &size_in1, &ptr_out, &outsize1);
+ errno1 = errno;
+
+ /* system convert to charset - placing result in buf2 */
+ ptr_in2 = (char *)inbuf;
+ ptr_out = (char *)buf2;
+ size_in2 = size;
+ outsize2 = sizeof(buf2);
+
+ memset(ptr_out, 0, outsize2);
+ errno = 0;
+ ret2 = iconv(cd, &ptr_in2, &size_in2, &ptr_out, &outsize2);
+ errno2 = errno;
+
+ len1 = sizeof(buf1) - outsize1;
+ len2 = sizeof(buf2) - outsize2;
+
+ /* codepoints above 1M are not interesting for now */
+ if (len2 > len1 &&
+ memcmp(buf1, buf2, len1) == 0 &&
+ get_codepoint((char *)(buf2+len1), len2-len1, charset) >= (1<<20)) {
+ return true;
+ }
+ if (len1 > len2 &&
+ memcmp(buf1, buf2, len2) == 0 &&
+ get_codepoint((char *)(buf1+len2), len1-len2, charset) >= (1<<20)) {
+ return true;
+ }
+
+ torture_assert_int_equal(test, ret1, ret2, "ret mismatch");
+
+ if (errno1 != errno2) {
+ show_buf(" rem1:", inbuf+(size-size_in1), size_in1);
+ show_buf(" rem2:", inbuf+(size-size_in2), size_in2);
+ torture_fail(test, talloc_asprintf(test,
+ "errno mismatch with %s internal=%d/%s system=%d/%s",
+ charset,
+ errno1, strerror(errno1),
+ errno2, strerror(errno2)));
+ }
+
+ torture_assert_int_equal(test, outsize1, outsize2, "outsize mismatch");
+
+ torture_assert_int_equal(test, size_in1, size_in2, "size_in mismatch");
+
+ if (len1 != len2 ||
+ memcmp(buf1, buf2, len1) != 0) {
+ torture_comment(test, "size=%d ret1=%d ret2=%d", (int)size, (int)ret1, (int)ret2);
+ show_buf(" IN1:", inbuf, size-size_in1);
+ show_buf(" IN2:", inbuf, size-size_in2);
+ show_buf("OUT1:", buf1, len1);
+ show_buf("OUT2:", buf2, len2);
+ if (len2 > len1 && memcmp(buf1, buf2, len1) == 0) {
+ torture_comment(test, "next codepoint is %u",
+ get_codepoint((char *)(buf2+len1), len2-len1, charset));
+ }
+ if (len1 > len2 && memcmp(buf1, buf2, len2) == 0) {
+ torture_comment(test, "next codepoint is %u",
+ get_codepoint((char *)(buf1+len2),len1-len2, charset));
+ }
+
+ torture_fail(test, "failed");
+ }
+
+ /* convert back to UTF-16, putting result in buf3 */
+ size = size - size_in1;
+ ptr_in1 = (const char *)buf1;
+ ptr_out = (char *)buf3;
+ size_in3 = len1;
+ outsize3 = sizeof(buf3);
+
+ memset(ptr_out, 0, outsize3);
+ ret3 = smb_iconv(cd3, &ptr_in1, &size_in3, &ptr_out, &outsize3);
+
+ /* we only internally support the first 1M codepoints */
+ if (outsize3 != sizeof(buf3) - size &&
+ get_codepoint((char *)(inbuf+sizeof(buf3) - outsize3),
+ size - (sizeof(buf3) - outsize3),
+ "UTF-16LE") >= (1<<20)) {
+ return true;
+ }
+
+ torture_assert_int_equal(test, ret3, 0, talloc_asprintf(test,
+ "pull failed - %s", strerror(errno)));
+
+ if (strncmp(charset, "UTF", 3) != 0) {
+ /* don't expect perfect mappings for non UTF charsets */
+ return true;
+ }
+
+
+ torture_assert_int_equal(test, outsize3, sizeof(buf3) - size,
+ "wrong outsize3");
+
+ if (memcmp(buf3, inbuf, size) != 0) {
+ torture_comment(test, "pull bytes mismatch:");
+ show_buf("inbuf", inbuf, size);
+ show_buf(" buf3", buf3, sizeof(buf3) - outsize3);
+ torture_comment(test, "next codepoint is %u\n",
+ get_codepoint((char *)(inbuf+sizeof(buf3) - outsize3),
+ size - (sizeof(buf3) - outsize3),
+ "UTF-16LE"));
+ torture_fail(test, "");
+ }
+
+ return true;
+}
+
+
+/*
+ test the push_codepoint() and next_codepoint() functions for a given
+ codepoint
+*/
+static bool test_codepoint(struct torture_context *tctx, unsigned int codepoint)
+{
+ uint8_t buf[10];
+ size_t size, size2;
+ codepoint_t c;
+
+ size = push_codepoint_handle(lpcfg_iconv_handle(tctx->lp_ctx), (char *)buf, codepoint);
+ torture_assert(tctx, size != -1 || (codepoint >= 0xd800 && codepoint <= 0x10000),
+ "Invalid Codepoint range");
+
+ if (size == -1) return true;
+
+ buf[size] = random();
+ buf[size+1] = random();
+ buf[size+2] = random();
+ buf[size+3] = random();
+
+ c = next_codepoint_handle(lpcfg_iconv_handle(tctx->lp_ctx), (char *)buf, &size2);
+
+ torture_assert(tctx, c == codepoint,
+ talloc_asprintf(tctx,
+ "next_codepoint(%u) failed - gave %u", codepoint, c));
+
+ torture_assert(tctx, size2 == size,
+ talloc_asprintf(tctx, "next_codepoint(%u) gave wrong size %d (should be %d)\n",
+ codepoint, (int)size2, (int)size));
+
+ return true;
+}
+
+static bool test_next_codepoint(struct torture_context *tctx)
+{
+ unsigned int codepoint;
+ if (iconv_untestable(tctx))
+ return true;
+
+ for (codepoint=0;codepoint<(1<<20);codepoint++) {
+ if (!test_codepoint(tctx, codepoint))
+ return false;
+ }
+ return true;
+}
+
+static bool test_first_1m(struct torture_context *tctx)
+{
+ unsigned int codepoint;
+ size_t size;
+ unsigned char inbuf[1000];
+
+ if (iconv_untestable(tctx))
+ return true;
+
+ for (codepoint=0;codepoint<(1<<20);codepoint++) {
+ if (gen_codepoint_utf16(codepoint, (char *)inbuf, &size) != 0) {
+ continue;
+ }
+
+ if (codepoint % 1000 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "codepoint=%u \r", codepoint);
+ fflush(stdout);
+ }
+ }
+
+ if (!test_buffer(tctx, inbuf, size, "UTF-8"))
+ return false;
+ }
+ return true;
+}
+
+static bool test_random_5m(struct torture_context *tctx)
+{
+ unsigned char inbuf[1000];
+ unsigned int i;
+
+ if (iconv_untestable(tctx))
+ return true;
+
+ for (i=0;i<500000;i++) {
+ size_t size;
+ unsigned int c;
+
+ if (i % 1000 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "i=%u \r", i);
+ fflush(stdout);
+ }
+ }
+
+ size = random() % 100;
+ for (c=0;c<size;c++) {
+ if (random() % 100 < 80) {
+ inbuf[c] = random() % 128;
+ } else {
+ inbuf[c] = random();
+ }
+ if (random() % 10 == 0) {
+ inbuf[c] |= 0xd8;
+ }
+ if (random() % 10 == 0) {
+ inbuf[c] |= 0xdc;
+ }
+ }
+ if (!test_buffer(tctx, inbuf, size, "UTF-8")) {
+ printf("i=%d failed UTF-8\n", i);
+ return false;
+ }
+
+ if (!test_buffer(tctx, inbuf, size, "CP850")) {
+ printf("i=%d failed CP850\n", i);
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static bool test_string2key(struct torture_context *tctx)
+{
+ uint16_t *buf;
+ char *dest = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ size_t len = (random()%1000)+1;
+ const uint16_t in1[10] = { 'a', 0xd805, 'b', 0xdcf0, 'c', 0, 'd', 'e', 'f', 'g' };
+ uint8_t le1[20];
+ uint8_t *munged1;
+ uint8_t *out1;
+ size_t ret;
+ int i;
+ const char *correct = "a\357\277\275b\357\277\275c\001defg";
+
+ buf = talloc_size(mem_ctx, len*2);
+ generate_random_buffer((uint8_t *)buf, len*2);
+
+ torture_comment(tctx, "converting random buffer\n");
+
+ if (!convert_string_talloc(mem_ctx, CH_UTF16MUNGED, CH_UTF8, (void *)buf, len*2, (void**)&dest, &ret)) {
+ torture_fail(tctx, "Failed to convert random buffer\n");
+ }
+
+ for (i=0;i<10;i++) {
+ SSVAL(&le1[2*i], 0, in1[i]);
+ }
+
+ torture_comment(tctx, "converting fixed buffer to UTF16\n");
+
+ if (!convert_string_talloc(mem_ctx, CH_UTF16MUNGED, CH_UTF16, (void *)le1, 20, (void**)&munged1, &ret)) {
+ torture_fail(tctx, "Failed to convert fixed buffer to UTF16_MUNGED\n");
+ }
+
+ torture_assert(tctx, ret == 20, "conversion should give 20 bytes\n");
+
+ torture_comment(tctx, "converting fixed buffer to UTF8\n");
+
+ if (!convert_string_talloc(mem_ctx, CH_UTF16MUNGED, CH_UTF8, (void *)le1, 20, (void**)&out1, &ret)) {
+ torture_fail(tctx, "Failed to convert fixed buffer to UTF8\n");
+ }
+
+ torture_assert(tctx, strcmp(correct, (const char *) out1) == 0,
+ "conversion gave incorrect result\n");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+struct torture_suite *torture_local_iconv(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "iconv");
+
+ torture_suite_add_simple_test(suite, "string2key",
+ test_string2key);
+
+ torture_suite_add_simple_test(suite, "next_codepoint()",
+ test_next_codepoint);
+
+ torture_suite_add_simple_test(suite, "first 1M codepoints",
+ test_first_1m);
+
+ torture_suite_add_simple_test(suite, "5M random UTF-16LE sequences",
+ test_random_5m);
+
+ torture_suite_add_simple_test(suite, "string2key",
+ test_string2key);
+ return suite;
+}
+
+#else
+
+struct torture_suite *torture_local_iconv(TALLOC_CTX *mem_ctx)
+{
+ printf("No native iconv library - can't run iconv test\n");
+ return NULL;
+}
+
+#endif
diff --git a/lib/util/charset/tests/util_unistr.c b/lib/util/charset/tests/util_unistr.c
new file mode 100644
index 0000000..1a9fcaa
--- /dev/null
+++ b/lib/util/charset/tests/util_unistr.c
@@ -0,0 +1,166 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for the util_unistr utility functions
+
+ Copyright (C) Catalyst.Net Ltd. 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+
+#undef strcasecmp
+#undef strncasecmp
+
+struct torture_suite *torture_local_util_unistr(TALLOC_CTX *mem_ctx);
+
+static bool test_utf16_len(struct torture_context *tctx)
+{
+ static const uint16_t empty_string[] = {'\0'};
+ static const uint16_t foo_bar[] = {
+ 'f', 'o', 'o', ' ', 'b', 'a', 'r', '\0'};
+ static const uint16_t foo_bar_alternative[] = {0xd83c,
+ 0xdd75,
+ 0xd83c,
+ 0xdd7e,
+ 0xd83c,
+ 0xdd7e,
+ ' ',
+ 0xd83c,
+ 0xdd31,
+ 0xd83c,
+ 0xdd30,
+ 0xd83c,
+ 0xdd41,
+ '\0'};
+
+ torture_assert_size_equal(tctx,
+ utf16_len(empty_string),
+ 0,
+ "length of empty string");
+ torture_assert_size_equal(tctx,
+ utf16_null_terminated_len(empty_string),
+ 2,
+ "null‐terminated length of empty string");
+ torture_assert_size_equal(tctx,
+ utf16_len(foo_bar),
+ 14,
+ "length of “foo bar”");
+ torture_assert_size_equal(tctx,
+ utf16_null_terminated_len(foo_bar),
+ 16,
+ "null‐terminated length of “foo bar”");
+ torture_assert_size_equal(tctx,
+ utf16_len(foo_bar_alternative),
+ 26,
+ "length of “🅵🅾🅾 🄱🄰🅁”");
+ torture_assert_size_equal(tctx,
+ utf16_null_terminated_len(
+ foo_bar_alternative),
+ 28,
+ "null‐terminated length of “🅵🅾🅾 🄱🄰🅁”");
+
+ return true;
+}
+
+static bool test_utf16_len_n(struct torture_context *tctx)
+{
+ static const uint16_t empty_string[] = {'\0'};
+ static const uint16_t foo_bar[] = {'f', 'o', 'o', ' ', 'b', 'a', 'r'};
+ static const uint16_t null_terminated_foo_bar[] = {
+ 'f', 'o', 'o', ' ', 'b', 'a', 'r', '\0'};
+ static const uint16_t twice_null_terminated_abc[] = {
+ 'a', 'b', 'c', '\0', '\0'};
+
+ torture_assert_size_equal(tctx,
+ utf16_len_n(empty_string, 0),
+ 0,
+ "length of empty string");
+ torture_assert_size_equal(tctx,
+ utf16_null_terminated_len_n(empty_string, 0),
+ 0,
+ "null‐terminated length of empty string");
+
+ torture_assert_size_equal(tctx,
+ utf16_len_n(empty_string,
+ sizeof empty_string),
+ 0,
+ "length of null‐terminated empty string");
+ torture_assert_size_equal(
+ tctx,
+ utf16_null_terminated_len_n(empty_string, sizeof empty_string),
+ 2,
+ "null‐terminated length of null‐terminated empty string");
+
+ torture_assert_size_equal(tctx,
+ utf16_len_n(foo_bar, sizeof foo_bar),
+ 14,
+ "length of “foo bar”");
+ torture_assert_size_equal(tctx,
+ utf16_null_terminated_len_n(foo_bar,
+ sizeof foo_bar),
+ 14,
+ "null‐terminated length of “foo bar”");
+
+ torture_assert_size_equal(tctx,
+ utf16_len_n(null_terminated_foo_bar,
+ sizeof null_terminated_foo_bar),
+ 14,
+ "length of null‐terminated “foo bar”");
+ torture_assert_size_equal(
+ tctx,
+ utf16_null_terminated_len_n(null_terminated_foo_bar,
+ sizeof null_terminated_foo_bar),
+ 16,
+ "null‐terminated length of null‐terminated “foo bar”");
+
+ torture_assert_size_equal(tctx,
+ utf16_len_n(null_terminated_foo_bar,
+ sizeof null_terminated_foo_bar -
+ 1),
+ 14,
+ "length of “foo bar” minus one byte");
+ torture_assert_size_equal(
+ tctx,
+ utf16_null_terminated_len_n(null_terminated_foo_bar,
+ sizeof null_terminated_foo_bar - 1),
+ 14,
+ "null‐terminated length of “foo bar” minus one byte");
+
+ torture_assert_size_equal(tctx,
+ utf16_len_n(twice_null_terminated_abc,
+ sizeof twice_null_terminated_abc),
+ 6,
+ "length of twice–null‐terminated “abc”");
+ torture_assert_size_equal(
+ tctx,
+ utf16_null_terminated_len_n(twice_null_terminated_abc,
+ sizeof twice_null_terminated_abc),
+ 8,
+ "null‐terminated length of twice–null‐terminated “abc”");
+
+ return true;
+}
+
+struct torture_suite *torture_local_util_unistr(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "util_unistr");
+
+ torture_suite_add_simple_test(suite, "utf16_len", test_utf16_len);
+ torture_suite_add_simple_test(suite, "utf16_len_n", test_utf16_len_n);
+
+ return suite;
+}
diff --git a/lib/util/charset/util_str.c b/lib/util/charset/util_str.c
new file mode 100644
index 0000000..1650c9b
--- /dev/null
+++ b/lib/util/charset/util_str.c
@@ -0,0 +1,608 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Andrew Bartlett 2011
+ Copyright (C) Jeremy Allison 1992-2007
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "charset.h"
+#include "lib/util/fault.h"
+
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
+#ifdef strncasecmp
+#undef strncasecmp
+#endif
+
+
+/**
+ Case insensitive string comparison, handle specified for testing
+**/
+_PUBLIC_ int strcasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
+ const char *s1, const char *s2)
+{
+ codepoint_t c1=0, c2=0;
+ codepoint_t u1=0, u2=0;
+ codepoint_t l1=0, l2=0;
+ size_t size1, size2;
+
+ /* handle null ptr comparisons to simplify the use in qsort */
+ if (s1 == s2) return 0;
+ if (s1 == NULL) return -1;
+ if (s2 == NULL) return 1;
+
+ while (*s1 && *s2) {
+ c1 = next_codepoint_handle(iconv_handle, s1, &size1);
+ c2 = next_codepoint_handle(iconv_handle, s2, &size2);
+
+ if (c1 == INVALID_CODEPOINT ||
+ c2 == INVALID_CODEPOINT) {
+ return strcasecmp(s1, s2);
+ }
+
+ s1 += size1;
+ s2 += size2;
+
+ if (c1 == c2) {
+ continue;
+ }
+
+ u1 = toupper_m(c1);
+ u2 = toupper_m(c2);
+ if (u1 == u2) {
+ continue;
+ }
+
+ l1 = tolower_m(c1);
+ l2 = tolower_m(c2);
+ if (l1 == l2) {
+ continue;
+ }
+
+ return l1 - l2;
+ }
+
+ return *s1 - *s2;
+}
+
+/**
+ Case insensitive string comparison
+**/
+_PUBLIC_ int strcasecmp_m(const char *s1, const char *s2)
+{
+ struct smb_iconv_handle *iconv_handle = get_iconv_handle();
+ return strcasecmp_m_handle(iconv_handle, s1, s2);
+}
+
+/**
+ Case insensitive string comparison, length limited, handle specified for
+ testing
+**/
+_PUBLIC_ int strncasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
+ const char *s1, const char *s2, size_t n)
+{
+ codepoint_t c1=0, c2=0;
+ codepoint_t u1=0, u2=0;
+ codepoint_t l1=0, l2=0;
+ size_t size1, size2;
+
+ /* handle null ptr comparisons to simplify the use in qsort */
+ if (s1 == s2) return 0;
+ if (s1 == NULL) return -1;
+ if (s2 == NULL) return 1;
+
+ while (*s1 && *s2 && n) {
+ n--;
+
+ c1 = next_codepoint_handle(iconv_handle, s1, &size1);
+ c2 = next_codepoint_handle(iconv_handle, s2, &size2);
+
+ if (c1 == INVALID_CODEPOINT ||
+ c2 == INVALID_CODEPOINT) {
+ /*
+ * n was specified in characters,
+ * now we must convert it to bytes.
+ * As bytes are the smallest
+ * character unit, the following
+ * increment and strncasecmp is always
+ * safe.
+ *
+ * The source string was already known
+ * to be n characters long, so we are
+ * guaranteed to be able to look at the
+ * (n remaining + size1) bytes from the
+ * s1 position).
+ */
+ n += size1;
+ return strncasecmp(s1, s2, n);
+ }
+
+ s1 += size1;
+ s2 += size2;
+
+ if (c1 == c2) {
+ continue;
+ }
+
+ u1 = toupper_m(c1);
+ u2 = toupper_m(c2);
+ if (u1 == u2) {
+ continue;
+ }
+
+ l1 = tolower_m(c1);
+ l2 = tolower_m(c2);
+ if (l1 == l2) {
+ continue;
+ }
+
+ return l1 - l2;
+ }
+
+ if (n == 0) {
+ return 0;
+ }
+
+ return *s1 - *s2;
+}
+
+/**
+ Case insensitive string comparison, length limited
+**/
+_PUBLIC_ int strncasecmp_m(const char *s1, const char *s2, size_t n)
+{
+ struct smb_iconv_handle *iconv_handle = get_iconv_handle();
+ return strncasecmp_m_handle(iconv_handle, s1, s2, n);
+}
+
+/**
+ * Compare 2 strings.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+_PUBLIC_ bool strequal_m(const char *s1, const char *s2)
+{
+ return strcasecmp_m(s1,s2) == 0;
+}
+
+/**
+ Compare 2 strings (case sensitive).
+**/
+_PUBLIC_ bool strcsequal(const char *s1,const char *s2)
+{
+ if (s1 == s2)
+ return true;
+ if (!s1 || !s2)
+ return false;
+
+ return strcmp(s1,s2) == 0;
+}
+
+/**
+ * Calculate the number of units (8 or 16-bit, depending on the
+ * destination charset) that would be needed to convert the input
+ * string, which is expected to be in src_charset encoding, to the
+ * destination charset (which should be a unicode charset).
+ */
+_PUBLIC_ size_t strlen_m_ext_handle(struct smb_iconv_handle *ic,
+ const char *s, charset_t src_charset, charset_t dst_charset)
+{
+ size_t count = 0;
+
+#ifdef DEVELOPER
+ switch (dst_charset) {
+ case CH_DOS:
+ case CH_UNIX:
+ smb_panic("cannot call strlen_m_ext() with a variable dest charset (must be UTF16* or UTF8)");
+ default:
+ break;
+ }
+
+ switch (src_charset) {
+ case CH_UTF16LE:
+ case CH_UTF16BE:
+ smb_panic("cannot call strlen_m_ext() with a UTF16 src charset (must be DOS, UNIX, DISPLAY or UTF8)");
+ default:
+ break;
+ }
+#endif
+ if (!s) {
+ return 0;
+ }
+
+ while (*s && !(((uint8_t)*s) & 0x80)) {
+ s++;
+ count++;
+ }
+
+ if (!*s) {
+ return count;
+ }
+
+ while (*s) {
+ size_t c_size;
+ codepoint_t c = next_codepoint_handle_ext(ic, s, strnlen(s, 5),
+ src_charset, &c_size);
+ s += c_size;
+
+ switch (dst_charset) {
+ case CH_UTF16LE:
+ case CH_UTF16BE:
+ case CH_UTF16MUNGED:
+ if (c < 0x10000) {
+ /* Unicode char fits into 16 bits. */
+ count += 1;
+ } else {
+ /* Double-width unicode char - 32 bits. */
+ count += 2;
+ }
+ break;
+ case CH_UTF8:
+ /*
+ * this only checks ranges, and does not
+ * check for invalid codepoints
+ */
+ if (c < 0x80) {
+ count += 1;
+ } else if (c < 0x800) {
+ count += 2;
+ } else if (c < 0x10000) {
+ count += 3;
+ } else {
+ count += 4;
+ }
+ break;
+ default:
+ /*
+ * non-unicode encoding:
+ * assume that each codepoint fits into
+ * one unit in the destination encoding.
+ */
+ count += 1;
+ }
+ }
+
+ return count;
+}
+
+/**
+ * Calculate the number of units (8 or 16-bit, depending on the
+ * destination charset) that would be needed to convert the input
+ * string, which is expected to be in src_charset encoding, to the
+ * destination charset (which should be a unicode charset).
+ */
+_PUBLIC_ size_t strlen_m_ext(const char *s, charset_t src_charset, charset_t dst_charset)
+{
+ struct smb_iconv_handle *ic = get_iconv_handle();
+ return strlen_m_ext_handle(ic, s, src_charset, dst_charset);
+}
+
+_PUBLIC_ size_t strlen_m_ext_term(const char *s, const charset_t src_charset,
+ const charset_t dst_charset)
+{
+ if (!s) {
+ return 0;
+ }
+ return strlen_m_ext(s, src_charset, dst_charset) + 1;
+}
+
+_PUBLIC_ size_t strlen_m_ext_term_null(const char *s,
+ const charset_t src_charset,
+ const charset_t dst_charset)
+{
+ size_t len;
+ if (!s) {
+ return 0;
+ }
+ len = strlen_m_ext(s, src_charset, dst_charset);
+ if (len == 0) {
+ return 0;
+ }
+
+ return len+1;
+}
+
+/**
+ * Calculate the number of 16-bit units that would be needed to convert
+ * the input string, which is expected to be in CH_UNIX encoding, to UTF16.
+ *
+ * This will be the same as the number of bytes in a string for single
+ * byte strings, but will be different for multibyte.
+ */
+_PUBLIC_ size_t strlen_m(const char *s)
+{
+ return strlen_m_ext(s, CH_UNIX, CH_UTF16LE);
+}
+
+/**
+ Work out the number of multibyte chars in a string, including the NULL
+ terminator.
+**/
+_PUBLIC_ size_t strlen_m_term(const char *s)
+{
+ return strlen_m_ext_term(s, CH_UNIX, CH_UTF16LE);
+}
+
+/*
+ * Weird helper routine for the winreg pipe: If nothing is around, return 0,
+ * if a string is there, include the terminator.
+ */
+
+_PUBLIC_ size_t strlen_m_term_null(const char *s)
+{
+ return strlen_m_ext_term_null(s, CH_UNIX, CH_UTF16LE);
+}
+
+/**
+ Strchr and strrchr_m are a bit complex on general multi-byte strings.
+**/
+_PUBLIC_ char *strchr_m(const char *src, char c)
+{
+ const char *s;
+ struct smb_iconv_handle *ic = get_iconv_handle();
+ if (src == NULL) {
+ return NULL;
+ }
+ /* characters below 0x3F are guaranteed to not appear in
+ non-initial position in multi-byte charsets */
+ if ((c & 0xC0) == 0) {
+ return strchr(src, c);
+ }
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
+ if (*s == c)
+ return discard_const_p(char, s);
+ }
+
+ if (!*s)
+ return NULL;
+
+#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
+ /* With compose characters we must restart from the beginning. JRA. */
+ s = src;
+#endif
+
+ while (*s) {
+ size_t size;
+ codepoint_t c2 = next_codepoint_handle(ic, s, &size);
+ if (c2 == c) {
+ return discard_const_p(char, s);
+ }
+ s += size;
+ }
+
+ return NULL;
+}
+
+/**
+ * Multibyte-character version of strrchr
+ */
+_PUBLIC_ char *strrchr_m(const char *s, char c)
+{
+ struct smb_iconv_handle *ic;
+ char *ret = NULL;
+
+ if (s == NULL) {
+ return NULL;
+ }
+
+ /* characters below 0x3F are guaranteed to not appear in
+ non-initial position in multi-byte charsets */
+ if ((c & 0xC0) == 0) {
+ return strrchr(s, c);
+ }
+
+ /* this is quite a common operation, so we want it to be
+ fast. We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars). Also, in Samba
+ we only search for ascii characters in 'c' and that
+ in all mb character sets with a compound character
+ containing c, if 'c' is not a match at position
+ p, then p[-1] > 0x7f. JRA. */
+
+ {
+ size_t len = strlen(s);
+ const char *cp = s;
+ bool got_mb = false;
+
+ if (len == 0)
+ return NULL;
+ cp += (len - 1);
+ do {
+ if (c == *cp) {
+ /* Could be a match. Part of a multibyte ? */
+ if ((cp > s) &&
+ (((unsigned char)cp[-1]) & 0x80)) {
+ /* Yep - go slow :-( */
+ got_mb = true;
+ break;
+ }
+ /* No - we have a match ! */
+ return discard_const_p(char , cp);
+ }
+ } while (cp-- != s);
+ if (!got_mb)
+ return NULL;
+ }
+
+ ic = get_iconv_handle();
+
+ while (*s) {
+ size_t size;
+ codepoint_t c2 = next_codepoint_handle(ic, s, &size);
+ if (c2 == c) {
+ ret = discard_const_p(char, s);
+ }
+ s += size;
+ }
+
+ return ret;
+}
+
+/**
+ return True if any (multi-byte) character is lower case
+*/
+_PUBLIC_ bool strhaslower_handle(struct smb_iconv_handle *ic,
+ const char *string)
+{
+ while (*string) {
+ size_t c_size;
+ codepoint_t s;
+ codepoint_t t;
+
+ s = next_codepoint_handle(ic, string, &c_size);
+ string += c_size;
+
+ t = toupper_m(s);
+
+ if (s != t) {
+ return true; /* that means it has lower case chars */
+ }
+ }
+
+ return false;
+}
+
+_PUBLIC_ bool strhaslower(const char *string)
+{
+ struct smb_iconv_handle *ic = get_iconv_handle();
+ return strhaslower_handle(ic, string);
+}
+
+/**
+ return True if any (multi-byte) character is upper case
+*/
+_PUBLIC_ bool strhasupper_handle(struct smb_iconv_handle *ic,
+ const char *string)
+{
+ while (*string) {
+ size_t c_size;
+ codepoint_t s;
+ codepoint_t t;
+
+ s = next_codepoint_handle(ic, string, &c_size);
+ string += c_size;
+
+ t = tolower_m(s);
+
+ if (s != t) {
+ return true; /* that means it has upper case chars */
+ }
+ }
+
+ return false;
+}
+
+_PUBLIC_ bool strhasupper(const char *string)
+{
+ struct smb_iconv_handle *ic = get_iconv_handle();
+ return strhasupper_handle(ic, string);
+}
+
+/***********************************************************************
+ strstr_m - We convert via ucs2 for now.
+***********************************************************************/
+
+char *strstr_m(const char *src, const char *findstr)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ smb_ucs2_t *p;
+ smb_ucs2_t *src_w, *find_w;
+ const char *s;
+ char *s2;
+ char *retp = NULL;
+ size_t converted_size, findstr_len = 0;
+
+ /* for correctness */
+ if (!findstr[0]) {
+ return discard_const_p(char, src);
+ }
+
+ /* Samba does single character findstr calls a *lot*. */
+ if (findstr[1] == '\0')
+ return strchr_m(src, *findstr);
+
+ /* We optimise for the ascii case, knowing that all our
+ supported multi-byte character sets are ascii-compatible
+ (ie. they match for the first 128 chars) */
+
+ for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) {
+ if (*s == *findstr) {
+ if (!findstr_len)
+ findstr_len = strlen(findstr);
+
+ if (strncmp(s, findstr, findstr_len) == 0) {
+ return discard_const_p(char, s);
+ }
+ }
+ }
+
+ if (!*s)
+ return NULL;
+
+#if 1 /* def BROKEN_UNICODE_COMPOSE_CHARACTERS */
+ /* 'make check' fails unless we do this */
+
+ /* With compose characters we must restart from the beginning. JRA. */
+ s = src;
+#endif
+
+ /*
+ * Use get_iconv_handle() just as a non-NULL talloc ctx. In
+ * case we leak memory, this should then be more obvious in
+ * the talloc report.
+ */
+ mem_ctx = talloc_new(get_iconv_handle());
+ if (mem_ctx == NULL) {
+ return NULL;
+ }
+
+ if (!push_ucs2_talloc(mem_ctx, &src_w, src, &converted_size)) {
+ goto done;
+ }
+
+ if (!push_ucs2_talloc(mem_ctx, &find_w, findstr, &converted_size)) {
+ goto done;
+ }
+
+ p = strstr_w(src_w, find_w);
+
+ if (!p) {
+ goto done;
+ }
+
+ *p = 0;
+ if (!pull_ucs2_talloc(mem_ctx, &s2, src_w, &converted_size)) {
+ goto done;
+ }
+ retp = discard_const_p(char, (s+strlen(s2)));
+done:
+ TALLOC_FREE(mem_ctx);
+ return retp;
+}
diff --git a/lib/util/charset/util_unistr.c b/lib/util/charset/util_unistr.c
new file mode 100644
index 0000000..830b480
--- /dev/null
+++ b/lib/util/charset/util_unistr.c
@@ -0,0 +1,644 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "charset.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/fault.h"
+
+/**
+ String replace.
+ NOTE: oldc and newc must be 7 bit characters
+**/
+_PUBLIC_ void string_replace_m(char *s, char oldc, char newc)
+{
+ struct smb_iconv_handle *ic = get_iconv_handle();
+ while (s && *s) {
+ size_t size;
+ codepoint_t c = next_codepoint_handle(ic, s, &size);
+ if (c == oldc) {
+ *s = newc;
+ }
+ s += size;
+ }
+}
+
+/**
+ Convert a string to lower case, allocated with talloc
+**/
+_PUBLIC_ char *strlower_talloc_handle(struct smb_iconv_handle *iconv_handle,
+ TALLOC_CTX *ctx, const char *src)
+{
+ size_t size=0;
+ char *dest;
+
+ if(src == NULL) {
+ return NULL;
+ }
+
+ /* this takes advantage of the fact that upper/lower can't
+ change the length of a character by more than 1 byte */
+ dest = talloc_array(ctx, char, 2*(strlen(src))+1);
+ if (dest == NULL) {
+ return NULL;
+ }
+
+ while (*src) {
+ size_t c_size;
+ codepoint_t c = next_codepoint_handle(iconv_handle, src, &c_size);
+ src += c_size;
+
+ c = tolower_m(c);
+
+ c_size = push_codepoint_handle(iconv_handle, dest+size, c);
+ if (c_size == -1) {
+ talloc_free(dest);
+ return NULL;
+ }
+ size += c_size;
+ }
+
+ dest[size] = 0;
+
+ /* trim it so talloc_append_string() works */
+ dest = talloc_realloc(ctx, dest, char, size+1);
+
+ talloc_set_name_const(dest, dest);
+
+ return dest;
+}
+
+_PUBLIC_ char *strlower_talloc(TALLOC_CTX *ctx, const char *src)
+{
+ struct smb_iconv_handle *iconv_handle = get_iconv_handle();
+ return strlower_talloc_handle(iconv_handle, ctx, src);
+}
+
+/**
+ Convert a string to UPPER case, allocated with talloc
+ source length limited to n bytes, iconv handle supplied
+**/
+_PUBLIC_ char *strupper_talloc_n_handle(struct smb_iconv_handle *iconv_handle,
+ TALLOC_CTX *ctx, const char *src, size_t n)
+{
+ size_t size=0;
+ char *dest;
+
+ if (!src) {
+ return NULL;
+ }
+
+ /* this takes advantage of the fact that upper/lower can't
+ change the length of a character by more than 1 byte */
+ dest = talloc_array(ctx, char, 2*(n+1));
+ if (dest == NULL) {
+ return NULL;
+ }
+
+ while (n && *src) {
+ size_t c_size;
+ codepoint_t c = next_codepoint_handle_ext(iconv_handle, src, n,
+ CH_UNIX, &c_size);
+ src += c_size;
+ n -= c_size;
+
+ c = toupper_m(c);
+
+ c_size = push_codepoint_handle(iconv_handle, dest+size, c);
+ if (c_size == -1) {
+ talloc_free(dest);
+ return NULL;
+ }
+ size += c_size;
+ }
+
+ dest[size] = 0;
+
+ /* trim it so talloc_append_string() works */
+ dest = talloc_realloc(ctx, dest, char, size+1);
+
+ talloc_set_name_const(dest, dest);
+
+ return dest;
+}
+
+/**
+ Convert a string to UPPER case, allocated with talloc
+ source length limited to n bytes
+**/
+_PUBLIC_ char *strupper_talloc_n(TALLOC_CTX *ctx, const char *src, size_t n)
+{
+ struct smb_iconv_handle *iconv_handle = get_iconv_handle();
+ return strupper_talloc_n_handle(iconv_handle, ctx, src, n);
+}
+/**
+ Convert a string to UPPER case, allocated with talloc
+**/
+_PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src)
+{
+ return strupper_talloc_n(ctx, src, src?strlen(src):0);
+}
+
+/**
+ talloc_strdup() a unix string to upper case.
+**/
+_PUBLIC_ char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *src)
+{
+ return strupper_talloc(ctx, src);
+}
+
+/**
+ Find the number of 'c' chars in a string
+**/
+_PUBLIC_ size_t count_chars_m(const char *s, char c)
+{
+ struct smb_iconv_handle *ic = get_iconv_handle();
+ size_t count = 0;
+
+ while (*s) {
+ size_t size;
+ codepoint_t c2 = next_codepoint_handle(ic, s, &size);
+ if (c2 == c) count++;
+ s += size;
+ }
+
+ return count;
+}
+
+size_t ucs2_align(const void *base_ptr, const void *p, int flags)
+{
+ if (flags & (STR_NOALIGN|STR_ASCII)) {
+ return 0;
+ }
+ return PTR_DIFF(p, base_ptr) & 1;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+**/
+size_t utf16_len(const void *buf)
+{
+ size_t len;
+
+ for (len = 0; PULL_LE_U16(buf,len); len += 2) ;
+
+ return len;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+**/
+size_t utf16_null_terminated_len(const void *buf)
+{
+ return utf16_len(buf) + 2;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+limited by 'n' bytes
+**/
+size_t utf16_len_n(const void *src, size_t n)
+{
+ size_t len;
+
+ for (len = 0; (len+2 <= n) && PULL_LE_U16(src, len); len += 2) ;
+
+ return len;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+limited by 'n' bytes
+**/
+size_t utf16_null_terminated_len_n(const void *src, size_t n)
+{
+ size_t len;
+
+ len = utf16_len_n(src, n);
+
+ if (len+2 <= n) {
+ len += 2;
+ }
+
+ return len;
+}
+
+unsigned char *talloc_utf16_strlendup(TALLOC_CTX *mem_ctx, const char *str, size_t len)
+{
+ unsigned char *new_str = NULL;
+
+ /* Check for overflow. */
+ if (len > SIZE_MAX - 2) {
+ return NULL;
+ }
+
+ /*
+ * Allocate the new string, including space for the
+ * UTF‐16 null terminator.
+ */
+ new_str = talloc_size(mem_ctx, len + 2);
+ if (new_str == NULL) {
+ return NULL;
+ }
+
+ memcpy(new_str, str, len);
+
+ /*
+ * Ensure that the UTF‐16 string is
+ * null‐terminated.
+ */
+ new_str[len] = '\0';
+ new_str[len + 1] = '\0';
+
+ return new_str;
+}
+
+unsigned char *talloc_utf16_strdup(TALLOC_CTX *mem_ctx, const char *str)
+{
+ if (str == NULL) {
+ return NULL;
+ }
+ return talloc_utf16_strlendup(mem_ctx, str, utf16_len(str));
+}
+
+unsigned char *talloc_utf16_strndup(TALLOC_CTX *mem_ctx, const char *str, size_t n)
+{
+ if (str == NULL) {
+ return NULL;
+ }
+ return talloc_utf16_strlendup(mem_ctx, str, utf16_len_n(str, n));
+}
+
+/**
+ * Determine the length and validity of a utf-8 string.
+ *
+ * @param input the string pointer
+ * @param maxlen maximum size of the string
+ * @param byte_len receives the length of the valid section
+ * @param char_len receives the number of unicode characters in the valid section
+ * @param utf16_len receives the number of bytes the string would need in UTF16 encoding.
+ *
+ * @return true if the input is valid up to maxlen, or a '\0' byte, otherwise false.
+ */
+bool utf8_check(const char *input, size_t maxlen,
+ size_t *byte_len,
+ size_t *char_len,
+ size_t *utf16_len)
+{
+ const uint8_t *s = (const uint8_t *)input;
+ size_t i;
+ size_t chars = 0;
+ size_t long_chars = 0;
+ uint32_t codepoint;
+ uint8_t a, b, c, d;
+ for (i = 0; i < maxlen; i++, chars++) {
+ if (s[i] == 0) {
+ break;
+ }
+ if (s[i] < 0x80) {
+ continue;
+ }
+ if ((s[i] & 0xe0) == 0xc0) {
+ /* 110xxxxx 10xxxxxx */
+ a = s[i];
+ if (maxlen - i < 2) {
+ goto error;
+ }
+ b = s[i + 1];
+ if ((b & 0xc0) != 0x80) {
+ goto error;
+ }
+ codepoint = (a & 31) << 6 | (b & 63);
+ if (codepoint < 0x80) {
+ goto error;
+ }
+ i++;
+ continue;
+ }
+ if ((s[i] & 0xf0) == 0xe0) {
+ /* 1110xxxx 10xxxxxx 10xxxxxx */
+ if (maxlen - i < 3) {
+ goto error;
+ }
+ a = s[i];
+ b = s[i + 1];
+ c = s[i + 2];
+ if ((b & 0xc0) != 0x80 || (c & 0xc0) != 0x80) {
+ goto error;
+ }
+ codepoint = (c & 63) | (b & 63) << 6 | (a & 15) << 12;
+
+ if (codepoint < 0x800) {
+ goto error;
+ }
+ if (codepoint >= 0xd800 && codepoint <= 0xdfff) {
+ /*
+ * This is an invalid codepoint, per
+ * RFC3629, as it encodes part of a
+ * UTF-16 surrogate pair for a
+ * character over U+10000, which ought
+ * to have been encoded as a four byte
+ * utf-8 sequence.
+ */
+ goto error;
+ }
+ i += 2;
+ continue;
+ }
+
+ if ((s[i] & 0xf8) == 0xf0) {
+ /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ if (maxlen - i < 4) {
+ goto error;
+ }
+ a = s[i];
+ b = s[i + 1];
+ c = s[i + 2];
+ d = s[i + 3];
+
+ if ((b & 0xc0) != 0x80 ||
+ (c & 0xc0) != 0x80 ||
+ (d & 0xc0) != 0x80) {
+ goto error;
+ }
+ codepoint = (d & 63) | (c & 63) << 6 | (b & 63) << 12 | (a & 7) << 18;
+
+ if (codepoint < 0x10000 || codepoint > 0x10ffff) {
+ goto error;
+ }
+ /* this one will need two UTF16 characters */
+ long_chars++;
+ i += 3;
+ continue;
+ }
+ /*
+ * If it wasn't handled yet, it's wrong.
+ */
+ goto error;
+ }
+ *byte_len = i;
+ *char_len = chars;
+ *utf16_len = chars + long_chars;
+ return true;
+
+error:
+ *byte_len = i;
+ *char_len = chars;
+ *utf16_len = chars + long_chars;
+ return false;
+}
+
+
+/**
+ * Copy a string from a char* unix src to a dos codepage string destination.
+ *
+ * @converted_size the number of bytes occupied by the string in the destination.
+ * @return bool true if success.
+ *
+ * @param flags can include
+ * <dl>
+ * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
+ * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
+ * </dl>
+ *
+ * @param dest_len the maximum length in bytes allowed in the
+ * destination. If @p dest_len is -1 then no maximum is used.
+ **/
+static bool push_ascii_string(void *dest, const char *src, size_t dest_len, int flags, size_t *converted_size)
+{
+ size_t src_len;
+ bool ret;
+
+ if (flags & STR_UPPER) {
+ char *tmpbuf = strupper_talloc(NULL, src);
+ if (tmpbuf == NULL) {
+ return false;
+ }
+ ret = push_ascii_string(dest, tmpbuf, dest_len, flags & ~STR_UPPER, converted_size);
+ talloc_free(tmpbuf);
+ return ret;
+ }
+
+ src_len = strlen(src);
+
+ if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
+ src_len++;
+
+ return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, converted_size);
+}
+
+/**
+ * Copy a string from a dos codepage source to a unix char* destination.
+ *
+ * The resulting string in "dest" is always null terminated.
+ *
+ * @param flags can have:
+ * <dl>
+ * <dt>STR_TERMINATE</dt>
+ * <dd>STR_TERMINATE means the string in @p src
+ * is null terminated, and src_len is ignored.</dd>
+ * </dl>
+ *
+ * @param src_len is the length of the source area in bytes.
+ * @returns the number of bytes occupied by the string in @p src.
+ **/
+static ssize_t pull_ascii_string(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
+{
+ size_t size = 0;
+
+ if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
+ if (src_len == (size_t)-1) {
+ src_len = strlen((const char *)src) + 1;
+ } else {
+ size_t len = strnlen((const char *)src, src_len);
+ if (len < src_len)
+ len++;
+ src_len = len;
+ }
+ }
+
+ /* We're ignoring the return here.. */
+ (void)convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, &size);
+
+ if (dest_len)
+ dest[MIN(size, dest_len-1)] = 0;
+
+ return src_len;
+}
+
+/**
+ * Copy a string from a char* src to a unicode destination.
+ *
+ * @returns the number of bytes occupied by the string in the destination.
+ *
+ * @param flags can have:
+ *
+ * <dl>
+ * <dt>STR_TERMINATE <dd>means include the null termination.
+ * <dt>STR_UPPER <dd>means uppercase in the destination.
+ * <dt>STR_NOALIGN <dd>means don't do alignment.
+ * </dl>
+ *
+ * @param dest_len is the maximum length allowed in the
+ * destination. If dest_len is -1 then no maximum is used.
+ **/
+static ssize_t push_ucs2(void *dest, const char *src, size_t dest_len, int flags)
+{
+ size_t len=0;
+ size_t src_len = strlen(src);
+ size_t size = 0;
+ bool ret;
+
+ if (flags & STR_UPPER) {
+ char *tmpbuf = strupper_talloc(NULL, src);
+ ssize_t retval;
+ if (tmpbuf == NULL) {
+ return -1;
+ }
+ retval = push_ucs2(dest, tmpbuf, dest_len, flags & ~STR_UPPER);
+ talloc_free(tmpbuf);
+ return retval;
+ }
+
+ if (flags & STR_TERMINATE)
+ src_len++;
+
+ if (ucs2_align(NULL, dest, flags)) {
+ *(char *)dest = 0;
+ dest = (void *)((char *)dest + 1);
+ if (dest_len) dest_len--;
+ len++;
+ }
+
+ /* ucs2 is always a multiple of 2 bytes */
+ dest_len &= ~1;
+
+ ret = convert_string(CH_UNIX, CH_UTF16, src, src_len, dest, dest_len, &size);
+ if (ret == false) {
+ return 0;
+ }
+
+ len += size;
+
+ return (ssize_t)len;
+}
+
+
+/**
+ Copy a string from a ucs2 source to a unix char* destination.
+ Flags can have:
+ STR_TERMINATE means the string in src is null terminated.
+ STR_NOALIGN means don't try to align.
+ if STR_TERMINATE is set then src_len is ignored if it is -1.
+ src_len is the length of the source area in bytes
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+static size_t pull_ucs2(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
+{
+ size_t size = 0;
+
+ if (ucs2_align(NULL, src, flags)) {
+ src = (const void *)((const char *)src + 1);
+ if (src_len > 0)
+ src_len--;
+ }
+
+ if (flags & STR_TERMINATE) {
+ if (src_len == (size_t)-1) {
+ src_len = utf16_null_terminated_len(src);
+ } else {
+ src_len = utf16_null_terminated_len_n(src, src_len);
+ }
+ }
+
+ /* ucs2 is always a multiple of 2 bytes */
+ if (src_len != (size_t)-1)
+ src_len &= ~1;
+
+ /* We're ignoring the return here.. */
+ (void)convert_string(CH_UTF16, CH_UNIX, src, src_len, dest, dest_len, &size);
+ if (dest_len)
+ dest[MIN(size, dest_len-1)] = 0;
+
+ return src_len;
+}
+
+/**
+ Copy a string from a char* src to a unicode or ascii
+ dos codepage destination choosing unicode or ascii based on the
+ flags in the SMB buffer starting at base_ptr.
+ Return the number of bytes occupied by the string in the destination.
+ flags can have:
+ STR_TERMINATE means include the null termination.
+ STR_UPPER means uppercase in the destination.
+ STR_ASCII use ascii even with unicode packet.
+ STR_NOALIGN means don't do alignment.
+ dest_len is the maximum length allowed in the destination. If dest_len
+ is -1 then no maximum is used.
+**/
+
+_PUBLIC_ ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags)
+{
+ if (flags & STR_ASCII) {
+ size_t size = 0;
+ if (push_ascii_string(dest, src, dest_len, flags, &size)) {
+ return (ssize_t)size;
+ } else {
+ return (ssize_t)-1;
+ }
+ } else if (flags & STR_UNICODE) {
+ return push_ucs2(dest, src, dest_len, flags);
+ } else {
+ smb_panic("push_string requires either STR_ASCII or STR_UNICODE flag to be set");
+ return -1;
+ }
+}
+
+
+/**
+ Copy a string from a unicode or ascii source (depending on
+ the packet flags) to a char* destination.
+ Flags can have:
+ STR_TERMINATE means the string in src is null terminated.
+ STR_UNICODE means to force as unicode.
+ STR_ASCII use ascii even with unicode packet.
+ STR_NOALIGN means don't do alignment.
+ if STR_TERMINATE is set then src_len is ignored is it is -1
+ src_len is the length of the source area in bytes.
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+_PUBLIC_ ssize_t pull_string(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
+{
+ if (flags & STR_ASCII) {
+ return pull_ascii_string(dest, src, dest_len, src_len, flags);
+ } else if (flags & STR_UNICODE) {
+ return pull_ucs2(dest, src, dest_len, src_len, flags);
+ } else {
+ smb_panic("pull_string requires either STR_ASCII or STR_UNICODE flag to be set");
+ return -1;
+ }
+}
diff --git a/lib/util/charset/util_unistr_w.c b/lib/util/charset/util_unistr_w.c
new file mode 100644
index 0000000..88d5531
--- /dev/null
+++ b/lib/util/charset/util_unistr_w.c
@@ -0,0 +1,255 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jeremy Allison 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "charset.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+
+/* Copy into a smb_ucs2_t from a possibly unaligned buffer. Return the copied smb_ucs2_t */
+#define COPY_UCS2_CHAR(dest,src) (((unsigned char *)(dest))[0] = ((const unsigned char *)(src))[0],\
+ ((unsigned char *)(dest))[1] = ((const unsigned char *)(src))[1], (dest))
+
+
+/* return an ascii version of a ucs2 character */
+#define UCS2_TO_CHAR(c) (((c) >> UCS2_SHIFT) & 0xff)
+
+static int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len);
+
+/*******************************************************************
+ Count the number of two-byte pairs in a UTF16 string.
+********************************************************************/
+
+size_t strlen_w(const smb_ucs2_t *src)
+{
+ size_t len;
+ smb_ucs2_t c;
+
+ for(len = 0; *(COPY_UCS2_CHAR(&c,src)); src++, len++) {
+ ;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Count up to max number of characters in a smb_ucs2_t string.
+********************************************************************/
+
+size_t strnlen_w(const smb_ucs2_t *src, size_t max)
+{
+ size_t len;
+ smb_ucs2_t c;
+
+ for(len = 0; (len < max) && *(COPY_UCS2_CHAR(&c,src)); src++, len++) {
+ ;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Wide strchr().
+********************************************************************/
+
+smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ smb_ucs2_t cp;
+ while (*(COPY_UCS2_CHAR(&cp,s))) {
+ if (c == cp) {
+ return discard_const_p(smb_ucs2_t, s);
+ }
+ s++;
+ }
+ if (c == cp) {
+ return discard_const_p(smb_ucs2_t, s);
+ }
+
+ return NULL;
+}
+
+smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
+{
+ return strchr_w(s, UCS2_CHAR(c));
+}
+
+/*******************************************************************
+ Wide strrchr().
+********************************************************************/
+
+smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
+{
+ smb_ucs2_t cp;
+ const smb_ucs2_t *p = s;
+ int len = strlen_w(s);
+
+ if (len == 0) {
+ return NULL;
+ }
+ p += (len - 1);
+ do {
+ if (c == *(COPY_UCS2_CHAR(&cp,p))) {
+ return discard_const_p(smb_ucs2_t, p);
+ }
+ } while (p-- != s);
+ return NULL;
+}
+
+/*******************************************************************
+ Wide version of strrchr that returns after doing strrchr 'n' times.
+********************************************************************/
+
+smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n)
+{
+ smb_ucs2_t cp;
+ const smb_ucs2_t *p = s;
+ int len = strlen_w(s);
+
+ if (len == 0 || !n) {
+ return NULL;
+ }
+ p += (len - 1);
+ do {
+ if (c == *(COPY_UCS2_CHAR(&cp,p))) {
+ n--;
+ }
+
+ if (!n) {
+ return discard_const_p(smb_ucs2_t, p);
+ }
+ } while (p-- != s);
+ return NULL;
+}
+
+/*******************************************************************
+ Wide strstr().
+********************************************************************/
+
+smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
+{
+ const smb_ucs2_t *r;
+ size_t inslen;
+
+ if (!s || !*s || !ins || !*ins) {
+ return NULL;
+ }
+
+ inslen = strlen_w(ins);
+ r = s;
+
+ while ((r = strchr_w(r, *ins))) {
+ if (strncmp_w(r, ins, inslen) == 0) {
+ return discard_const_p(smb_ucs2_t, r);
+ }
+ r++;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+ Convert a string to lower case.
+ return True if any char is converted
+
+ This is unsafe for any string involving a UTF16 character
+********************************************************************/
+
+bool strlower_w(smb_ucs2_t *s)
+{
+ smb_ucs2_t cp;
+ bool ret = false;
+
+ while (*(COPY_UCS2_CHAR(&cp,s))) {
+ smb_ucs2_t v = tolower_m(cp);
+ if (v != cp) {
+ (void)COPY_UCS2_CHAR(s,&v);
+ ret = true;
+ }
+ s++;
+ }
+ return ret;
+}
+
+/*******************************************************************
+ Convert a string to upper case.
+ return True if any char is converted
+
+ This is unsafe for any string involving a UTF16 character
+********************************************************************/
+
+bool strupper_w(smb_ucs2_t *s)
+{
+ smb_ucs2_t cp;
+ bool ret = false;
+ while (*(COPY_UCS2_CHAR(&cp,s))) {
+ smb_ucs2_t v = toupper_m(cp);
+ if (v != cp) {
+ (void)COPY_UCS2_CHAR(s,&v);
+ ret = true;
+ }
+ s++;
+ }
+ return ret;
+}
+
+static int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
+{
+ smb_ucs2_t cpa, cpb;
+ size_t n = 0;
+
+ while ((n < len) && (*(COPY_UCS2_CHAR(&cpb,b))) && (*(COPY_UCS2_CHAR(&cpa,a)) == cpb)) {
+ a++;
+ b++;
+ n++;
+ }
+ return (len - n)?(*(COPY_UCS2_CHAR(&cpa,a)) - *(COPY_UCS2_CHAR(&cpb,b))):0;
+}
+
+/*
+ The *_wa() functions take a combination of 7 bit ascii
+ and wide characters They are used so that you can use string
+ functions combining C string constants with ucs2 strings
+
+ The char* arguments must NOT be multibyte - to be completely sure
+ of this only pass string constants */
+
+int strcmp_wa(const smb_ucs2_t *a, const char *b)
+{
+ smb_ucs2_t cp = 0;
+
+ while (*b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) {
+ a++;
+ b++;
+ }
+ return (*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b));
+}
+
+smb_ucs2_t toupper_w(smb_ucs2_t v)
+{
+ smb_ucs2_t ret;
+ /* LE to native. */
+ codepoint_t cp = SVAL(&v,0);
+ cp = toupper_m(cp);
+ /* native to LE. */
+ SSVAL(&ret,0,cp);
+ return ret;
+}
diff --git a/lib/util/charset/weird.c b/lib/util/charset/weird.c
new file mode 100644
index 0000000..9752e01
--- /dev/null
+++ b/lib/util/charset/weird.c
@@ -0,0 +1,142 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba module with developer tools
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "charset_proto.h"
+
+#ifdef DEVELOPER
+
+static struct {
+ char from;
+ const char *to;
+ int len;
+} weird_table[] = {
+ {
+ .from = 'q',
+ .to = "^q^",
+ .len = 3,
+ },
+ {
+ .from = 'Q',
+ .to = "^Q^",
+ .len = 3,
+ },
+ {
+ .len = 0,
+ }
+};
+
+size_t weird_pull(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ while (*inbytesleft >= 1 && *outbytesleft >= 2) {
+ int i;
+ int done = 0;
+ for (i=0;weird_table[i].from;i++) {
+ if (strncmp((*inbuf),
+ weird_table[i].to,
+ weird_table[i].len) == 0) {
+ if (*inbytesleft < weird_table[i].len) {
+ abort();
+ }
+
+ (*outbuf)[0] = weird_table[i].from;
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= weird_table[i].len;
+ (*outbytesleft) -= 2;
+ (*inbuf) += weird_table[i].len;
+ (*outbuf) += 2;
+ done = 1;
+ break;
+ }
+ }
+ if (done) continue;
+ (*outbuf)[0] = (*inbuf)[0];
+ (*outbuf)[1] = 0;
+ (*inbytesleft) -= 1;
+ (*outbytesleft) -= 2;
+ (*inbuf) += 1;
+ (*outbuf) += 2;
+ }
+
+ if (*inbytesleft > 0) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return 0;
+}
+
+size_t weird_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ int i;
+ int done=0;
+ for (i=0;weird_table[i].from;i++) {
+ if ((*inbuf)[0] == weird_table[i].from &&
+ (*inbuf)[1] == 0) {
+ if (*outbytesleft < weird_table[i].len) {
+ abort();
+ }
+ memcpy(*outbuf,
+ weird_table[i].to,
+ weird_table[i].len);
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= weird_table[i].len;
+ (*inbuf) += 2;
+ (*outbuf) += weird_table[i].len;
+ done = 1;
+ break;
+ }
+ }
+ if (done) continue;
+
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
+
+#else
+void charset_weird_dummy(void);
+void charset_weird_dummy(void)
+{
+ return;
+}
+
+#endif
diff --git a/lib/util/charset/wscript_build b/lib/util/charset/wscript_build
new file mode 100644
index 0000000..c69a171
--- /dev/null
+++ b/lib/util/charset/wscript_build
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('ICONV_WRAPPER',
+ source='''
+ iconv.c
+ weird.c
+ charset_macosxfs.c
+ ''',
+ public_deps='iconv replace talloc ' + bld.env['icu-libs'])
+
+bld.SAMBA_SUBSYSTEM('charset',
+ public_headers='charset.h',
+ source='''
+ codepoints.c
+ convert_string.c
+ util_str.c
+ util_unistr_w.c
+ pull_push.c
+ util_unistr.c
+ ''',
+ deps='DYNCONFIG ICONV_WRAPPER smb-panic samba-debug',
+ public_deps='talloc')
diff --git a/lib/util/charset/wscript_configure b/lib/util/charset/wscript_configure
new file mode 100644
index 0000000..9c27fc6
--- /dev/null
+++ b/lib/util/charset/wscript_configure
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# rather strangely, we need to look for libiconv before checking libc
+# as the external libiconv can use a macro to override iconv_open to libiconv_open
+# and then we may find the wrong iconv.h later due to other packages looking
+# in /usr/local
+# We check for the lib iconv when building a shared lib has some compiler/linker
+# managed to link when specifying -liconv a executable even if there is no
+# libiconv.so or libiconv.a
+
+conf.CHECK_LIB(libs="iconv", shlib=True)
+
+#HP-UX can use libiconv as an add-on package, which has #define iconv_open libiconv_open
+if (conf.CHECK_FUNCS_IN('iconv_open', 'iconv', checklibc=False, headers='iconv.h') or
+ conf.CHECK_FUNCS_IN('libiconv_open', 'iconv', checklibc=False, headers='iconv.h') or
+ conf.CHECK_FUNCS('iconv_open', headers='iconv.h')):
+
+ conf.DEFINE('HAVE_NATIVE_ICONV', 1)
+
+conf.CHECK_CODE('''
+ uint8_t inbuf[2] = { 0x30, 0xdf };
+ uint8_t outbuf[4] = { 0 };
+ char *ptr_in = (char *)inbuf;
+ char *ptr_out = (char *)outbuf;
+ size_t size_in = sizeof(inbuf);
+ size_t size_out = sizeof(outbuf);
+ size_t ret;
+ iconv_t cd;
+ cd = iconv_open("UTF-8", "UTF-16LE");
+ if (cd == 0 || cd == (iconv_t)-1) return -1;
+ ret = iconv(cd, &ptr_in, &size_in, &ptr_out, &size_out);
+ if (ret != (size_t)-1 || errno != EILSEQ) return -1;
+ ''',
+ define='HAVE_ICONV_ERRNO_ILLEGAL_MULTIBYTE',
+ execute=True,
+ msg='Checking errno of iconv for illegal multibyte sequence',
+ lib='iconv',
+ headers='errno.h iconv.h')
+
+if conf.CHECK_CFG(package='icu-i18n',
+ args='--cflags --libs',
+ msg='Checking for icu-i18n',
+ uselib_store='ICU_I18N'):
+ for lib in conf.env['LIB_ICU_I18N']:
+ conf.CHECK_LIB(lib, shlib=True, mandatory=True)
+ conf.env['icu-libs'] = ' '.join(conf.env['LIB_ICU_I18N'])
+ if not conf.CHECK_HEADERS('unicode/ustring.h'):
+ conf.fatal('Found libicu, but unicode/ustring.h is missing')
+ conf.DEFINE('HAVE_UTF8_NORMALISATION', 1)
+else:
+ conf.env['icu-libs'] = ''
diff --git a/lib/util/charset_compat.h b/lib/util/charset_compat.h
new file mode 100644
index 0000000..cb3b625
--- /dev/null
+++ b/lib/util/charset_compat.h
@@ -0,0 +1,9 @@
+#ifndef _SAMBA_CHARSET_COMPAT_H_
+#define _SAMBA_CHARSET_COMPAT_H_
+
+#include <string.h>
+
+#define strchr_m(h, n) strchr(h, n)
+#define strstr_m(h, n) strstr(h, n)
+
+#endif /* _SAMBA_CHARSET_COMPAT_H_ */
diff --git a/lib/util/close_low_fd.c b/lib/util/close_low_fd.c
new file mode 100644
index 0000000..84a6906
--- /dev/null
+++ b/lib/util/close_low_fd.c
@@ -0,0 +1,75 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "close_low_fd.h"
+
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#elif defined(HAVE_VALGRIND_H)
+#include <valgrind.h>
+#else
+#define RUNNING_ON_VALGRIND 0
+#endif
+
+_PUBLIC_ int close_low_fd(int fd)
+{
+ int ret, dev_null;
+
+ if (RUNNING_ON_VALGRIND) {
+ return 0;
+ }
+
+ dev_null = open("/dev/null", O_RDWR, 0);
+
+ if ((dev_null == -1) && (errno == ENFILE)) {
+ /*
+ * Try to free up an fd
+ */
+ ret = close(fd);
+ if (ret != 0) {
+ return errno;
+ }
+ }
+
+ dev_null = open("/dev/null", O_RDWR, 0);
+ if (dev_null == -1) {
+ dev_null = open("/dev/null", O_WRONLY, 0);
+ }
+ if (dev_null == -1) {
+ return errno;
+ }
+
+ if (dev_null == fd) {
+ /*
+ * This can happen in the ENFILE case above
+ */
+ return 0;
+ }
+
+ ret = dup2(dev_null, fd);
+ if (ret == -1) {
+ int err = errno;
+ close(dev_null);
+ return err;
+ }
+ close(dev_null);
+ return 0;
+}
diff --git a/lib/util/close_low_fd.h b/lib/util/close_low_fd.h
new file mode 100644
index 0000000..954d1d2
--- /dev/null
+++ b/lib/util/close_low_fd.h
@@ -0,0 +1,28 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CLOSE_LOW_FD_H
+#define _CLOSE_LOW_FD_H
+
+/*
+ * Redirect "fd" to /dev/null
+ */
+int close_low_fd(int fd);
+
+#endif
diff --git a/lib/util/data_blob.c b/lib/util/data_blob.c
new file mode 100644
index 0000000..69a340c
--- /dev/null
+++ b/lib/util/data_blob.c
@@ -0,0 +1,298 @@
+/*
+ Unix SMB/CIFS implementation.
+ Easy management of byte-length data
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "attr.h"
+#include "data_blob.h"
+#include "lib/util/samba_util.h"
+
+const DATA_BLOB data_blob_null = { NULL, 0 };
+
+/**
+ * @file
+ * @brief Manipulation of arbitrary data blobs
+ **/
+
+/**
+ construct a data blob, must be freed with data_blob_free()
+ you can pass NULL for p and get a blank data blob
+**/
+_PUBLIC_ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name)
+{
+ return data_blob_talloc_named(NULL, p, length, name);
+}
+
+/**
+ construct a data blob, using supplied TALLOC_CTX
+**/
+_PUBLIC_ DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name)
+{
+ DATA_BLOB ret;
+
+ if (p == NULL && length == 0) {
+ ZERO_STRUCT(ret);
+ return ret;
+ }
+
+ if (p) {
+ ret.data = (uint8_t *)talloc_memdup(mem_ctx, p, length);
+ } else {
+ ret.data = talloc_array(mem_ctx, uint8_t, length);
+ }
+ if (ret.data == NULL) {
+ ret.length = 0;
+ return ret;
+ }
+ talloc_set_name_const(ret.data, name);
+ ret.length = length;
+ return ret;
+}
+
+/**
+ construct a zero data blob, using supplied TALLOC_CTX.
+ use this sparingly as it initialises data - better to initialise
+ yourself if you want specific data in the blob
+**/
+_PUBLIC_ DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
+{
+ DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
+ data_blob_clear(&blob);
+ return blob;
+}
+
+/**
+free a data blob
+**/
+_PUBLIC_ void data_blob_free(DATA_BLOB *d)
+{
+ if (d) {
+ TALLOC_FREE(d->data);
+ d->length = 0;
+ }
+}
+
+/**
+clear a DATA_BLOB's contents
+**/
+_PUBLIC_ void data_blob_clear(DATA_BLOB *d)
+{
+ if (d->data) {
+ memset_s(d->data, d->length, 0, d->length);
+ }
+}
+
+/**
+free a data blob and clear its contents
+**/
+_PUBLIC_ void data_blob_clear_free(DATA_BLOB *d)
+{
+ data_blob_clear(d);
+ data_blob_free(d);
+}
+
+
+/**
+check if two data blobs are equal
+**/
+_PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2)
+{
+ int ret;
+ if (d1->data == NULL && d2->data != NULL) {
+ return -1;
+ }
+ if (d1->data != NULL && d2->data == NULL) {
+ return 1;
+ }
+ if (d1->data == d2->data) {
+ return d1->length - d2->length;
+ }
+ ret = memcmp(d1->data, d2->data, MIN(d1->length, d2->length));
+ if (ret == 0) {
+ /* Note this ordering is used in conditional aces */
+ return d1->length - d2->length;
+ }
+ return ret;
+}
+
+/**
+check if two data blobs are equal, where the time taken should not depend on the
+contents of either blob.
+**/
+_PUBLIC_ bool data_blob_equal_const_time(const DATA_BLOB *d1, const DATA_BLOB *d2)
+{
+ bool ret;
+ if (d1->data == NULL && d2->data != NULL) {
+ return false;
+ }
+ if (d1->data != NULL && d2->data == NULL) {
+ return false;
+ }
+ if (d1->length != d2->length) {
+ return false;
+ }
+ if (d1->data == d2->data) {
+ return true;
+ }
+ ret = mem_equal_const_time(d1->data, d2->data, d1->length);
+ return ret;
+}
+
+/**
+print the data_blob as hex string
+**/
+_PUBLIC_ char *data_blob_hex_string_lower(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
+{
+ size_t i;
+ char *hex_string;
+
+ hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
+ if (!hex_string) {
+ return NULL;
+ }
+
+ /* this must be lowercase or w2k8 cannot join a samba domain,
+ as this routine is used to encode extended DNs and windows
+ only accepts lowercase hexadecimal numbers */
+ for (i = 0; i < blob->length; i++)
+ slprintf(&hex_string[i*2], 3, "%02x", blob->data[i]);
+
+ hex_string[(blob->length*2)] = '\0';
+ return hex_string;
+}
+
+_PUBLIC_ char *data_blob_hex_string_upper(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
+{
+ size_t i;
+ char *hex_string;
+
+ hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
+ if (!hex_string) {
+ return NULL;
+ }
+
+ for (i = 0; i < blob->length; i++)
+ slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
+
+ hex_string[(blob->length*2)] = '\0';
+ return hex_string;
+}
+
+/**
+ useful for constructing data blobs in test suites, while
+ avoiding const warnings
+**/
+_PUBLIC_ DATA_BLOB data_blob_string_const(const char *str)
+{
+ DATA_BLOB blob;
+ blob.data = discard_const_p(uint8_t, str);
+ blob.length = str ? strlen(str) : 0;
+ return blob;
+}
+
+/**
+ useful for constructing data blobs in test suites, while
+ avoiding const warnings
+**/
+_PUBLIC_ DATA_BLOB data_blob_string_const_null(const char *str)
+{
+ DATA_BLOB blob;
+ blob.data = discard_const_p(uint8_t, str);
+ blob.length = str ? strlen(str)+1 : 0;
+ return blob;
+}
+
+/**
+ * Create a new data blob from const data
+ */
+
+_PUBLIC_ DATA_BLOB data_blob_const(const void *p, size_t length)
+{
+ DATA_BLOB blob;
+ blob.data = discard_const_p(uint8_t, p);
+ blob.length = length;
+ return blob;
+}
+
+
+/**
+ realloc a data_blob
+**/
+_PUBLIC_ bool data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length)
+{
+ uint8_t *tmp = talloc_realloc(mem_ctx, blob->data, uint8_t, length);
+ if (tmp == NULL) {
+ return false;
+ }
+ blob->data = tmp;
+ blob->length = length;
+ return true;
+}
+
+
+/**
+ append some data to a data blob
+**/
+_PUBLIC_ bool data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+ const void *p, size_t length)
+{
+ size_t old_len = blob->length;
+ size_t new_len = old_len + length;
+
+ if (length == 0) {
+ return true;
+ }
+
+ if (new_len < length || new_len < old_len) {
+ return false;
+ }
+
+ if ((const uint8_t *)p + length < (const uint8_t *)p) {
+ return false;
+ }
+
+ if (!data_blob_realloc(mem_ctx, blob, new_len)) {
+ return false;
+ }
+
+ memcpy(blob->data + old_len, p, length);
+ return true;
+}
+
+/**
+ pad the length of a data blob to a multiple of
+ 'pad'. 'pad' must be a power of two.
+**/
+_PUBLIC_ bool data_blob_pad(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+ size_t pad)
+{
+ size_t old_len = blob->length;
+ size_t new_len = (old_len + pad - 1) & ~(pad - 1);
+
+ if (new_len < old_len) {
+ return false;
+ }
+
+ if (!data_blob_realloc(mem_ctx, blob, new_len)) {
+ return false;
+ }
+
+ memset(blob->data + old_len, 0, new_len - old_len);
+ return true;
+}
diff --git a/lib/util/data_blob.h b/lib/util/data_blob.h
new file mode 100644
index 0000000..6577630
--- /dev/null
+++ b/lib/util/data_blob.h
@@ -0,0 +1,144 @@
+/*
+ Unix SMB/CIFS implementation.
+ DATA BLOB
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This is a public header file that is installed as part of Samba.
+ * If you remove any functions or change their signature, update
+ * the so version number. */
+
+#ifndef _SAMBA_DATABLOB_H_
+#define _SAMBA_DATABLOB_H_
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+#include <talloc.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/* used to hold an arbitrary blob of data */
+typedef struct datablob {
+ uint8_t *data;
+ size_t length;
+} DATA_BLOB;
+
+/* by making struct ldb_val and DATA_BLOB the same, we can simplify
+ a fair bit of code */
+#define ldb_val datablob
+
+#define data_blob(ptr, size) data_blob_named(ptr, size, "DATA_BLOB: " __location__)
+#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, "DATA_BLOB: " __location__)
+#define data_blob_dup_talloc(ctx, blob) data_blob_talloc_named(ctx, (blob).data, (blob).length, "DATA_BLOB: " __location__)
+
+/**
+ construct a data blob, must be freed with data_blob_free()
+ you can pass NULL for p and get a blank data blob
+**/
+_PUBLIC_ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name);
+
+/**
+ construct a data blob, using supplied TALLOC_CTX
+**/
+_PUBLIC_ DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name);
+
+/**
+ construct a zero data blob, using supplied TALLOC_CTX.
+ use this sparingly as it initialises data - better to initialise
+ yourself if you want specific data in the blob
+**/
+_PUBLIC_ DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length);
+
+/**
+free a data blob
+**/
+_PUBLIC_ void data_blob_free(DATA_BLOB *d);
+
+/**
+clear a DATA_BLOB's contents
+**/
+_PUBLIC_ void data_blob_clear(DATA_BLOB *d);
+
+/**
+free a data blob and clear its contents
+**/
+_PUBLIC_ void data_blob_clear_free(DATA_BLOB *d);
+
+/**
+check if two data blobs are equal
+**/
+_PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2);
+
+/**
+check if two data blobs are equal, where the time taken should not depend on the
+contents of either blob.
+**/
+_PUBLIC_ bool data_blob_equal_const_time(const DATA_BLOB *d1, const DATA_BLOB *d2);
+
+/**
+print the data_blob as hex string
+**/
+_PUBLIC_ char *data_blob_hex_string_upper(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob);
+
+/**
+print the data_blob as hex string
+**/
+_PUBLIC_ char *data_blob_hex_string_lower(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob);
+
+/**
+ useful for constructing data blobs in test suites, while
+ avoiding const warnings
+**/
+_PUBLIC_ DATA_BLOB data_blob_string_const(const char *str);
+
+/**
+ useful for constructing data blobs in test suites, while
+ avoiding const warnings
+
+ includes the terminating null character (as opposed to data_blob_string_const)
+**/
+_PUBLIC_ DATA_BLOB data_blob_string_const_null(const char *str);
+
+/**
+ * Create a new data blob from const data
+ */
+_PUBLIC_ DATA_BLOB data_blob_const(const void *p, size_t length);
+
+/**
+ realloc a data_blob
+**/
+_PUBLIC_ bool data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length);
+
+/**
+ append some data to a data blob
+**/
+_PUBLIC_ bool data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+ const void *p, size_t length);
+
+/**
+ pad the length of a data blob to a multiple of
+ 'pad'. 'pad' must be a power of two.
+**/
+_PUBLIC_ bool data_blob_pad(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+ size_t pad);
+
+extern const DATA_BLOB data_blob_null;
+
+#endif /* _SAMBA_DATABLOB_H_ */
diff --git a/lib/util/debug-classes/debug-classname-table.c b/lib/util/debug-classes/debug-classname-table.c
new file mode 100644
index 0000000..9062078
--- /dev/null
+++ b/lib/util/debug-classes/debug-classname-table.c
@@ -0,0 +1,62 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Elrond 2002
+ Copyright (C) Simo Sorce 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+static const char *default_classname_table[] = {
+ [DBGC_ALL] = "all",
+ [DBGC_TDB] = "tdb",
+ [DBGC_PRINTDRIVERS] = "printdrivers",
+ [DBGC_LANMAN] = "lanman",
+ [DBGC_SMB] = "smb",
+ [DBGC_RPC_PARSE] = "rpc_parse",
+ [DBGC_RPC_SRV] = "rpc_srv",
+ [DBGC_RPC_CLI] = "rpc_cli",
+ [DBGC_PASSDB] = "passdb",
+ [DBGC_SAM] = "sam",
+ [DBGC_AUTH] = "auth",
+ [DBGC_WINBIND] = "winbind",
+ [DBGC_VFS] = "vfs",
+ [DBGC_IDMAP] = "idmap",
+ [DBGC_QUOTA] = "quota",
+ [DBGC_ACLS] = "acls",
+ [DBGC_LOCKING] = "locking",
+ [DBGC_MSDFS] = "msdfs",
+ [DBGC_DMAPI] = "dmapi",
+ [DBGC_REGISTRY] = "registry",
+ [DBGC_SCAVENGER] = "scavenger",
+ [DBGC_DNS] = "dns",
+ [DBGC_LDB] = "ldb",
+ [DBGC_TEVENT] = "tevent",
+ [DBGC_AUTH_AUDIT] = "auth_audit",
+ [DBGC_AUTH_AUDIT_JSON] = "auth_json_audit",
+ [DBGC_KERBEROS] = "kerberos",
+ [DBGC_DRS_REPL] = "drs_repl",
+ [DBGC_SMB2] = "smb2",
+ [DBGC_SMB2_CREDITS] = "smb2_credits",
+ [DBGC_DSDB_AUDIT] = "dsdb_audit",
+ [DBGC_DSDB_AUDIT_JSON] = "dsdb_json_audit",
+ [DBGC_DSDB_PWD_AUDIT] = "dsdb_password_audit",
+ [DBGC_DSDB_PWD_AUDIT_JSON] = "dsdb_password_json_audit",
+ [DBGC_DSDB_TXN_AUDIT] = "dsdb_transaction_audit",
+ [DBGC_DSDB_TXN_AUDIT_JSON] = "dsdb_transaction_json_audit",
+ [DBGC_DSDB_GROUP_AUDIT] = "dsdb_group_audit",
+ [DBGC_DSDB_GROUP_AUDIT_JSON] = "dsdb_group_json_audit",
+};
diff --git a/lib/util/debug.c b/lib/util/debug.c
new file mode 100644
index 0000000..86f13f1
--- /dev/null
+++ b/lib/util/debug.c
@@ -0,0 +1,1978 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Elrond 2002
+ Copyright (C) Simo Sorce 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include "system/filesys.h"
+#include "system/syslog.h"
+#include "system/locale.h"
+#include "system/network.h"
+#include "system/time.h"
+#include "time_basic.h"
+#include "close_low_fd.h"
+#include "memory.h"
+#include "util_strlist.h" /* LIST_SEP */
+#include "blocking.h"
+#include "debug.h"
+#include <assert.h>
+
+/* define what facility to use for syslog */
+#ifndef SYSLOG_FACILITY
+#define SYSLOG_FACILITY LOG_DAEMON
+#endif
+
+/* -------------------------------------------------------------------------- **
+ * Defines...
+ */
+
+/*
+ * format_bufr[FORMAT_BUFR_SIZE - 1] should always be reserved
+ * for a terminating null byte.
+ */
+#define FORMAT_BUFR_SIZE 4096
+
+/* -------------------------------------------------------------------------- **
+ * This module implements Samba's debugging utility.
+ *
+ * The syntax of a debugging log file is represented as:
+ *
+ * <debugfile> :== { <debugmsg> }
+ *
+ * <debugmsg> :== <debughdr> '\n' <debugtext>
+ *
+ * <debughdr> :== '[' TIME ',' LEVEL ']' [ [FILENAME ':'] [FUNCTION '()'] ]
+ *
+ * <debugtext> :== { <debugline> }
+ *
+ * <debugline> :== TEXT '\n'
+ *
+ * TEXT is a string of characters excluding the newline character.
+ * LEVEL is the DEBUG level of the message (an integer in the range 0..10).
+ * TIME is a timestamp.
+ * FILENAME is the name of the file from which the debug message was generated.
+ * FUNCTION is the function from which the debug message was generated.
+ *
+ * Basically, what that all means is:
+ *
+ * - A debugging log file is made up of debug messages.
+ *
+ * - Each debug message is made up of a header and text. The header is
+ * separated from the text by a newline.
+ *
+ * - The header begins with the timestamp and debug level of the message
+ * enclosed in brackets. The filename and function from which the
+ * message was generated may follow. The filename is terminated by a
+ * colon, and the function name is terminated by parenthesis.
+ *
+ * - The message text is made up of zero or more lines, each terminated by
+ * a newline.
+ */
+
+/* state variables for the debug system */
+static struct {
+ bool initialized;
+ enum debug_logtype logtype; /* The type of logging we are doing: eg stdout, file, stderr */
+ char prog_name[255];
+ char hostname[HOST_NAME_MAX+1];
+ bool reopening_logs;
+ bool schedule_reopen_logs;
+ int forced_log_priority;
+
+ struct debug_settings settings;
+ debug_callback_fn callback;
+ void *callback_private;
+ char header_str[300];
+ size_t hs_len;
+} state = {
+ .settings = {
+ .timestamp_logs = true
+ },
+};
+
+struct debug_class {
+ /*
+ * The debug loglevel of the class.
+ */
+ int loglevel;
+
+ /*
+ * An optional class specific logfile, may be NULL in which case the
+ * "global" logfile is used and fd is -1.
+ */
+ char *logfile;
+ int fd;
+ /* inode number of the logfile to detect logfile rotation */
+ ino_t ino;
+};
+
+/*
+ * default_classname_table[] is read in from debug-classname-table.c
+ * so that test_logging.c can use it too.
+ */
+#include "lib/util/debug-classes/debug-classname-table.c"
+
+/*
+ * This is to allow reading of dbgc_config before the debug
+ * system has been initialized.
+ */
+static struct debug_class debug_class_list_initial[ARRAY_SIZE(default_classname_table)] = {
+ [DBGC_ALL] = { .fd = 2 },
+};
+
+static size_t debug_num_classes = 0;
+static struct debug_class *dbgc_config = debug_class_list_initial;
+
+static int current_msg_level = 0;
+static int current_msg_class = 0;
+
+/*
+ * DBG_DEV(): when and how to user it.
+ *
+ * As a developer, you sometimes want verbose logging between point A and
+ * point B, where the relationship between these points is not easily defined
+ * in terms of the call stack.
+ *
+ * For example, you might be interested in what is going on in functions in
+ * lib/util/util_str.c in an ldap worker process after a particular query. If
+ * you use gdb, something will time out and you won't get the full
+ * conversation. If you add fprintf() or DBG_ERR()s to util_str.c, you'll get
+ * a massive flood, and there's a chance one will accidentally slip into a
+ * release and the whole world will flood. DBG_DEV is a solution.
+ *
+ * On start-up, DBG_DEV() is switched OFF. Nothing is printed.
+ *
+ * 1. Add `DBG_DEV("formatted msg %d, etc\n", i);` where needed.
+ *
+ * 2. At each point you want to start debugging, add `debug_developer_enable()`.
+ *
+ * 3. At each point you want debugging to stop, add `debug_developer_disable()`.
+ *
+ * In DEVELOPER builds, the message will be printed at level 0, as with
+ * DBG_ERR(). In production builds, the macro resolves to nothing.
+ *
+ * The messages are printed with a "<function_name>:DEV:<pid>:" prefix.
+ */
+
+static bool debug_developer_is_enabled = false;
+
+bool debug_developer_enabled(void)
+{
+ return debug_developer_is_enabled;
+}
+
+/*
+ * debug_developer_disable() will turn DBG_DEV() on in the current
+ * process and children.
+ */
+void debug_developer_enable(void)
+{
+ debug_developer_is_enabled = true;
+}
+
+/*
+ * debug_developer_disable() will make DBG_DEV() do nothing in the current
+ * process (and children).
+ */
+void debug_developer_disable(void)
+{
+ debug_developer_is_enabled = false;
+}
+
+/*
+ * Within debug.c, DBG_DEV() always writes to stderr, because some functions
+ * here will attempt infinite recursion with normal DEBUG macros.
+ */
+#ifdef DEVELOPER
+#undef DBG_DEV
+#define DBG_DEV(fmt, ...) \
+ (void)((debug_developer_enabled()) \
+ && (fprintf(stderr, "%s:DEV:%d: " fmt "%s", \
+ __func__, getpid(), ##__VA_ARGS__, "")) )
+#endif
+
+
+#if defined(WITH_SYSLOG) || defined(HAVE_LIBSYSTEMD_JOURNAL) || defined(HAVE_LIBSYSTEMD)
+static int debug_level_to_priority(int level)
+{
+ /*
+ * map debug levels to syslog() priorities
+ */
+ static const int priority_map[] = {
+ LOG_ERR, /* 0 */
+ LOG_WARNING, /* 1 */
+ LOG_NOTICE, /* 2 */
+ LOG_NOTICE, /* 3 */
+ LOG_NOTICE, /* 4 */
+ LOG_NOTICE, /* 5 */
+ LOG_INFO, /* 6 */
+ LOG_INFO, /* 7 */
+ LOG_INFO, /* 8 */
+ LOG_INFO, /* 9 */
+ };
+ int priority;
+
+ if (state.forced_log_priority != -1) {
+ level = state.forced_log_priority;
+ }
+
+ if (level < 0 || (size_t)level >= ARRAY_SIZE(priority_map))
+ priority = LOG_DEBUG;
+ else
+ priority = priority_map[level];
+
+ return priority;
+}
+#endif
+
+/* -------------------------------------------------------------------------- **
+ * Debug backends. When logging to DEBUG_FILE, send the log entries to
+ * all active backends.
+ */
+
+static void debug_file_log(int msg_level, const char *msg, size_t msg_len)
+{
+ struct iovec iov[] = {
+ {
+ .iov_base = discard_const(state.header_str),
+ .iov_len = state.hs_len,
+ },
+ {
+ .iov_base = discard_const(msg),
+ .iov_len = msg_len,
+ },
+ };
+ ssize_t ret;
+ int fd;
+
+ check_log_size();
+
+ if (dbgc_config[current_msg_class].fd != -1) {
+ fd = dbgc_config[current_msg_class].fd;
+ } else {
+ fd = dbgc_config[DBGC_ALL].fd;
+ }
+
+ do {
+ ret = writev(fd, iov, ARRAY_SIZE(iov));
+ } while (ret == -1 && errno == EINTR);
+}
+
+#ifdef WITH_SYSLOG
+static void debug_syslog_reload(bool enabled, bool previously_enabled,
+ const char *prog_name, char *option)
+{
+ if (enabled && !previously_enabled) {
+ const char *ident = NULL;
+ if ((prog_name != NULL) && (prog_name[0] != '\0')) {
+ ident = prog_name;
+ }
+#ifdef LOG_DAEMON
+ openlog(ident, LOG_PID, SYSLOG_FACILITY);
+#else
+ /* for old systems that have no facility codes. */
+ openlog(ident, LOG_PID);
+#endif
+ return;
+ }
+
+ if (!enabled && previously_enabled) {
+ closelog();
+ }
+}
+
+static void debug_syslog_log(int msg_level, const char *msg, size_t msg_len)
+{
+ int priority;
+
+ priority = debug_level_to_priority(msg_level);
+
+ /*
+ * Specify the facility to interoperate with other syslog
+ * callers (vfs_full_audit for example).
+ */
+ priority |= SYSLOG_FACILITY;
+
+ if (state.hs_len > 0) {
+ syslog(priority, "%s", state.header_str);
+ }
+ syslog(priority, "%s", msg);
+}
+#endif /* WITH_SYSLOG */
+
+#if defined(HAVE_LIBSYSTEMD_JOURNAL) || defined(HAVE_LIBSYSTEMD)
+#include <systemd/sd-journal.h>
+static void debug_systemd_log(int msg_level, const char *msg, size_t msg_len)
+{
+ if (state.hs_len > 0) {
+ size_t len = state.hs_len;
+
+ if (state.header_str[len - 1] == '\n') {
+ len -= 1;
+ }
+
+ sd_journal_send("MESSAGE=%.*s",
+ (int)len,
+ state.header_str,
+ "PRIORITY=%d",
+ debug_level_to_priority(msg_level),
+ "LEVEL=%d",
+ msg_level,
+ NULL);
+ }
+
+ if ((msg_len > 0) && (msg[msg_len - 1] == '\n')) {
+ msg_len -= 1;
+ }
+
+ sd_journal_send("MESSAGE=%.*s",
+ (int)msg_len,
+ msg,
+ "PRIORITY=%d",
+ debug_level_to_priority(msg_level),
+ "LEVEL=%d",
+ msg_level,
+ NULL);
+}
+#endif
+
+#ifdef HAVE_LTTNG_TRACEF
+#include <lttng/tracef.h>
+static void debug_lttng_log(int msg_level, const char *msg, size_t msg_len)
+{
+ if (state.hs_len > 0) {
+ size_t len = state.hs_len;
+
+ if (state.header_str[len - 1] == '\n') {
+ len -= 1;
+ }
+
+ tracef("%.*s", (int)len, state.header_str);
+ }
+
+ if ((msg_len > 0) && (msg[msg_len - 1] == '\n')) {
+ msg_len -= 1;
+ }
+ tracef("%.*s", (int)msg_len, msg);
+}
+#endif /* WITH_LTTNG_TRACEF */
+
+#ifdef HAVE_GPFS
+#include "gpfswrap.h"
+static void debug_gpfs_reload(bool enabled, bool previously_enabled,
+ const char *prog_name, char *option)
+{
+ if (enabled) {
+ gpfswrap_init();
+ }
+
+ if (enabled && !previously_enabled) {
+ gpfswrap_init_trace();
+ return;
+ }
+
+ if (!enabled && previously_enabled) {
+ gpfswrap_fini_trace();
+ return;
+ }
+
+ if (enabled) {
+ /*
+ * Trigger GPFS library to adjust state if necessary.
+ */
+ gpfswrap_query_trace();
+ }
+}
+
+static void copy_no_nl(char *out,
+ size_t out_size,
+ const char *in,
+ size_t in_len)
+{
+ size_t len;
+ /*
+ * Some backends already add an extra newline, so also provide
+ * a buffer without the newline character.
+ */
+ len = MIN(in_len, out_size - 1);
+ if ((len > 0) && (in[len - 1] == '\n')) {
+ len--;
+ }
+
+ memcpy(out, in, len);
+ out[len] = '\0';
+}
+
+static void debug_gpfs_log(int msg_level, const char *msg, size_t msg_len)
+{
+ char no_nl[FORMAT_BUFR_SIZE];
+
+ if (state.hs_len > 0) {
+ copy_no_nl(no_nl,
+ sizeof(no_nl),
+ state.header_str,
+ state.hs_len);
+ gpfswrap_add_trace(msg_level, no_nl);
+ }
+
+ copy_no_nl(no_nl, sizeof(no_nl), msg, msg_len);
+ gpfswrap_add_trace(msg_level, no_nl);
+}
+#endif /* HAVE_GPFS */
+
+#define DEBUG_RINGBUF_SIZE (1024 * 1024)
+#define DEBUG_RINGBUF_SIZE_OPT "size="
+
+static char *debug_ringbuf;
+static size_t debug_ringbuf_size;
+static size_t debug_ringbuf_ofs;
+
+/* We ensure in debug_ringbuf_log() that this is always \0 terminated */
+char *debug_get_ringbuf(void)
+{
+ return debug_ringbuf;
+}
+
+/* Return the size of the ringbuf (including a \0 terminator) */
+size_t debug_get_ringbuf_size(void)
+{
+ return debug_ringbuf_size;
+}
+
+static void debug_ringbuf_reload(bool enabled, bool previously_enabled,
+ const char *prog_name, char *option)
+{
+ bool cmp;
+ size_t optlen = strlen(DEBUG_RINGBUF_SIZE_OPT);
+
+ debug_ringbuf_size = DEBUG_RINGBUF_SIZE;
+ debug_ringbuf_ofs = 0;
+
+ SAFE_FREE(debug_ringbuf);
+
+ if (!enabled) {
+ return;
+ }
+
+ if (option != NULL) {
+ cmp = strncmp(option, DEBUG_RINGBUF_SIZE_OPT, optlen);
+ if (cmp == 0) {
+ debug_ringbuf_size = (size_t)strtoull(
+ option + optlen, NULL, 10);
+ }
+ }
+
+ debug_ringbuf = calloc(debug_ringbuf_size, sizeof(char));
+ if (debug_ringbuf == NULL) {
+ return;
+ }
+}
+
+static void _debug_ringbuf_log(int msg_level, const char *msg, size_t msg_len)
+{
+ size_t allowed_size;
+
+ if (debug_ringbuf == NULL) {
+ return;
+ }
+
+ /* Ensure the buffer is always \0 terminated */
+ allowed_size = debug_ringbuf_size - 1;
+
+ if (msg_len > allowed_size) {
+ return;
+ }
+
+ if ((debug_ringbuf_ofs + msg_len) < debug_ringbuf_ofs) {
+ return;
+ }
+
+ if ((debug_ringbuf_ofs + msg_len) > allowed_size) {
+ debug_ringbuf_ofs = 0;
+ }
+
+ memcpy(debug_ringbuf + debug_ringbuf_ofs, msg, msg_len);
+ debug_ringbuf_ofs += msg_len;
+}
+
+static void debug_ringbuf_log(int msg_level, const char *msg, size_t msg_len)
+{
+ if (state.hs_len > 0) {
+ _debug_ringbuf_log(msg_level, state.header_str, state.hs_len);
+ }
+ _debug_ringbuf_log(msg_level, msg, msg_len);
+}
+
+static struct debug_backend {
+ const char *name;
+ int log_level;
+ int new_log_level;
+ void (*reload)(bool enabled, bool prev_enabled,
+ const char *prog_name, char *option);
+ void (*log)(int msg_level,
+ const char *msg,
+ size_t len);
+ char *option;
+} debug_backends[] = {
+ {
+ .name = "file",
+ .log = debug_file_log,
+ },
+#ifdef WITH_SYSLOG
+ {
+ .name = "syslog",
+ .reload = debug_syslog_reload,
+ .log = debug_syslog_log,
+ },
+#endif
+
+#if defined(HAVE_LIBSYSTEMD_JOURNAL) || defined(HAVE_LIBSYSTEMD)
+ {
+ .name = "systemd",
+ .log = debug_systemd_log,
+ },
+#endif
+
+#ifdef HAVE_LTTNG_TRACEF
+ {
+ .name = "lttng",
+ .log = debug_lttng_log,
+ },
+#endif
+
+#ifdef HAVE_GPFS
+ {
+ .name = "gpfs",
+ .reload = debug_gpfs_reload,
+ .log = debug_gpfs_log,
+ },
+#endif
+ {
+ .name = "ringbuf",
+ .log = debug_ringbuf_log,
+ .reload = debug_ringbuf_reload,
+ },
+};
+
+static struct debug_backend *debug_find_backend(const char *name)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ if (strcmp(name, debug_backends[i].name) == 0) {
+ return &debug_backends[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * parse "backend[:option][@loglevel]
+ */
+static void debug_backend_parse_token(char *tok)
+{
+ char *backend_name_option, *backend_name,*backend_level, *saveptr;
+ char *backend_option;
+ struct debug_backend *b;
+
+ /*
+ * First parse into backend[:option] and loglevel
+ */
+ backend_name_option = strtok_r(tok, "@\0", &saveptr);
+ if (backend_name_option == NULL) {
+ return;
+ }
+
+ backend_level = strtok_r(NULL, "\0", &saveptr);
+
+ /*
+ * Now parse backend[:option]
+ */
+ backend_name = strtok_r(backend_name_option, ":\0", &saveptr);
+ if (backend_name == NULL) {
+ return;
+ }
+
+ backend_option = strtok_r(NULL, "\0", &saveptr);
+
+ /*
+ * Find and update backend
+ */
+ b = debug_find_backend(backend_name);
+ if (b == NULL) {
+ return;
+ }
+
+ if (backend_level == NULL) {
+ b->new_log_level = MAX_DEBUG_LEVEL;
+ } else {
+ b->new_log_level = atoi(backend_level);
+ }
+
+ if (backend_option != NULL) {
+ b->option = strdup(backend_option);
+ if (b->option == NULL) {
+ return;
+ }
+ }
+}
+
+/*
+ * parse "backend1[:option1][@loglevel1] backend2[option2][@loglevel2] ... "
+ * and enable/disable backends accordingly
+ */
+static void debug_set_backends(const char *param)
+{
+ size_t str_len = strlen(param);
+ char str[str_len+1];
+ char *tok, *saveptr;
+ unsigned i;
+
+ /*
+ * initialize new_log_level to detect backends that have been
+ * disabled
+ */
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ SAFE_FREE(debug_backends[i].option);
+ debug_backends[i].new_log_level = -1;
+ }
+
+ memcpy(str, param, str_len + 1);
+
+ tok = strtok_r(str, LIST_SEP, &saveptr);
+ if (tok == NULL) {
+ return;
+ }
+
+ while (tok != NULL) {
+ debug_backend_parse_token(tok);
+ tok = strtok_r(NULL, LIST_SEP, &saveptr);
+ }
+
+ /*
+ * Let backends react to config changes
+ */
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ struct debug_backend *b = &debug_backends[i];
+
+ if (b->reload) {
+ bool enabled = b->new_log_level > -1;
+ bool previously_enabled = b->log_level > -1;
+
+ b->reload(enabled, previously_enabled, state.prog_name,
+ b->option);
+ }
+ b->log_level = b->new_log_level;
+ }
+}
+
+static void debug_backends_log(const char *msg, size_t msg_len, int msg_level)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ if (msg_level <= debug_backends[i].log_level) {
+ debug_backends[i].log(msg_level, msg, msg_len);
+ }
+ }
+
+ /* Only log the header once */
+ state.hs_len = 0;
+}
+
+int debuglevel_get_class(size_t idx)
+{
+ return dbgc_config[idx].loglevel;
+}
+
+void debuglevel_set_class(size_t idx, int level)
+{
+ dbgc_config[idx].loglevel = level;
+}
+
+
+/* -------------------------------------------------------------------------- **
+ * Internal variables.
+ *
+ * debug_count - Number of debug messages that have been output.
+ * Used to check log size.
+ *
+ * current_msg_level - Internal copy of the message debug level. Written by
+ * dbghdr() and read by Debug1().
+ *
+ * format_bufr - Used to format debug messages. The dbgtext() function
+ * prints debug messages to a string, and then passes the
+ * string to format_debug_text(), which uses format_bufr
+ * to build the formatted output.
+ *
+ * format_pos - Marks the first free byte of the format_bufr.
+ *
+ *
+ * log_overflow - When this variable is true, never attempt to check the
+ * size of the log. This is a hack, so that we can write
+ * a message using DEBUG, from open_logs() when we
+ * are unable to open a new log file for some reason.
+ */
+
+static int debug_count = 0;
+static char format_bufr[FORMAT_BUFR_SIZE];
+static size_t format_pos = 0;
+static bool log_overflow = false;
+
+/*
+ * Define all the debug class selection names here. Names *MUST NOT* contain
+ * white space. There must be one name for each DBGC_<class name>, and they
+ * must be in the table in the order of DBGC_<class name>..
+ */
+
+static char **classname_table = NULL;
+
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+static void debug_init(void);
+
+/***************************************************************************
+ Free memory pointed to by global pointers.
+****************************************************************************/
+
+void gfree_debugsyms(void)
+{
+ unsigned i;
+
+ TALLOC_FREE(classname_table);
+
+ if ( dbgc_config != debug_class_list_initial ) {
+ TALLOC_FREE( dbgc_config );
+ dbgc_config = discard_const_p(struct debug_class,
+ debug_class_list_initial);
+ }
+
+ debug_num_classes = 0;
+
+ state.initialized = false;
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ SAFE_FREE(debug_backends[i].option);
+ }
+}
+
+/****************************************************************************
+utility lists registered debug class names's
+****************************************************************************/
+
+char *debug_list_class_names_and_levels(void)
+{
+ char *buf = talloc_strdup(NULL, "");
+ size_t i;
+ /* prepare strings */
+ for (i = 0; i < debug_num_classes; i++) {
+ talloc_asprintf_addbuf(&buf,
+ "%s:%d%s",
+ classname_table[i],
+ dbgc_config[i].loglevel,
+ i == (debug_num_classes - 1) ? "\n" : " ");
+ }
+ return buf;
+}
+
+/****************************************************************************
+ Utility to translate names to debug class index's (internal version).
+****************************************************************************/
+
+static int debug_lookup_classname_int(const char* classname)
+{
+ size_t i;
+
+ if (classname == NULL) {
+ return -1;
+ }
+
+ for (i=0; i < debug_num_classes; i++) {
+ char *entry = classname_table[i];
+ if (entry != NULL && strcmp(classname, entry)==0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/****************************************************************************
+ Add a new debug class to the system.
+****************************************************************************/
+
+int debug_add_class(const char *classname)
+{
+ int ndx;
+ struct debug_class *new_class_list = NULL;
+ char **new_name_list;
+ int default_level;
+
+ if (classname == NULL) {
+ return -1;
+ }
+
+ /* check the init has yet been called */
+ debug_init();
+
+ ndx = debug_lookup_classname_int(classname);
+ if (ndx >= 0) {
+ return ndx;
+ }
+ ndx = debug_num_classes;
+
+ if (dbgc_config == debug_class_list_initial) {
+ /* Initial loading... */
+ new_class_list = NULL;
+ } else {
+ new_class_list = dbgc_config;
+ }
+
+ default_level = dbgc_config[DBGC_ALL].loglevel;
+
+ new_class_list = talloc_realloc(NULL,
+ new_class_list,
+ struct debug_class,
+ ndx + 1);
+ if (new_class_list == NULL) {
+ return -1;
+ }
+
+ dbgc_config = new_class_list;
+
+ dbgc_config[ndx] = (struct debug_class) {
+ .loglevel = default_level,
+ .fd = -1,
+ };
+
+ new_name_list = talloc_realloc(NULL, classname_table, char *, ndx + 1);
+ if (new_name_list == NULL) {
+ return -1;
+ }
+ classname_table = new_name_list;
+
+ classname_table[ndx] = talloc_strdup(classname_table, classname);
+ if (classname_table[ndx] == NULL) {
+ return -1;
+ }
+
+ debug_num_classes = ndx + 1;
+
+ return ndx;
+}
+
+/****************************************************************************
+ Utility to translate names to debug class index's (public version).
+****************************************************************************/
+
+static int debug_lookup_classname(const char *classname)
+{
+ int ndx;
+
+ if (classname == NULL || !*classname)
+ return -1;
+
+ ndx = debug_lookup_classname_int(classname);
+
+ if (ndx != -1)
+ return ndx;
+
+ DBG_WARNING("Unknown classname[%s] -> adding it...\n", classname);
+ return debug_add_class(classname);
+}
+
+/****************************************************************************
+ Dump the current registered debug levels.
+****************************************************************************/
+
+static void debug_dump_status(int level)
+{
+ size_t q;
+
+ DEBUG(level, ("INFO: Current debug levels:\n"));
+ for (q = 0; q < debug_num_classes; q++) {
+ const char *classname = classname_table[q];
+ DEBUGADD(level, (" %s: %d\n",
+ classname,
+ dbgc_config[q].loglevel));
+ }
+}
+
+static bool debug_parse_param(char *param)
+{
+ char *class_name;
+ char *class_file = NULL;
+ char *class_level;
+ char *saveptr = NULL;
+ int ndx;
+
+ class_name = strtok_r(param, ":", &saveptr);
+ if (class_name == NULL) {
+ return false;
+ }
+
+ class_level = strtok_r(NULL, "@\0", &saveptr);
+ if (class_level == NULL) {
+ return false;
+ }
+
+ class_file = strtok_r(NULL, "\0", &saveptr);
+
+ ndx = debug_lookup_classname(class_name);
+ if (ndx == -1) {
+ return false;
+ }
+
+ dbgc_config[ndx].loglevel = atoi(class_level);
+
+ if (class_file == NULL) {
+ return true;
+ }
+
+ TALLOC_FREE(dbgc_config[ndx].logfile);
+
+ dbgc_config[ndx].logfile = talloc_strdup(NULL, class_file);
+ if (dbgc_config[ndx].logfile == NULL) {
+ return false;
+ }
+ return true;
+}
+
+/****************************************************************************
+ Parse the debug levels from smb.conf. Example debug level string:
+ 3 tdb:5 printdrivers:7
+ Note: the 1st param has no "name:" preceding it.
+****************************************************************************/
+
+bool debug_parse_levels(const char *params_str)
+{
+ size_t str_len = strlen(params_str);
+ char str[str_len+1];
+ char *tok, *saveptr;
+ size_t i;
+
+ /* Just in case */
+ debug_init();
+
+ memcpy(str, params_str, str_len+1);
+
+ tok = strtok_r(str, LIST_SEP, &saveptr);
+ if (tok == NULL) {
+ return true;
+ }
+
+ /* Allow DBGC_ALL to be specified w/o requiring its class name e.g."10"
+ * v.s. "all:10", this is the traditional way to set DEBUGLEVEL
+ */
+ if (isdigit(tok[0])) {
+ dbgc_config[DBGC_ALL].loglevel = atoi(tok);
+ tok = strtok_r(NULL, LIST_SEP, &saveptr);
+ } else {
+ dbgc_config[DBGC_ALL].loglevel = 0;
+ }
+
+ /* Array is debug_num_classes long */
+ for (i = DBGC_ALL+1; i < debug_num_classes; i++) {
+ dbgc_config[i].loglevel = dbgc_config[DBGC_ALL].loglevel;
+ TALLOC_FREE(dbgc_config[i].logfile);
+ }
+
+ while (tok != NULL) {
+ bool ok;
+
+ ok = debug_parse_param(tok);
+ if (!ok) {
+ DEBUG(0,("debug_parse_params: unrecognized debug "
+ "class name or format [%s]\n", tok));
+ return false;
+ }
+
+ tok = strtok_r(NULL, LIST_SEP, &saveptr);
+ }
+
+ debug_dump_status(5);
+
+ return true;
+}
+
+/* setup for logging of talloc warnings */
+static void talloc_log_fn(const char *msg)
+{
+ DEBUG(0,("%s", msg));
+}
+
+void debug_setup_talloc_log(void)
+{
+ talloc_set_log_fn(talloc_log_fn);
+}
+
+
+/****************************************************************************
+Init debugging (one time stuff)
+****************************************************************************/
+
+static void debug_init(void)
+{
+ size_t i;
+
+ if (state.initialized)
+ return;
+
+ state.initialized = true;
+
+ debug_setup_talloc_log();
+
+ for (i = 0; i < ARRAY_SIZE(default_classname_table); i++) {
+ debug_add_class(default_classname_table[i]);
+ }
+ dbgc_config[DBGC_ALL].fd = 2;
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ debug_backends[i].log_level = -1;
+ debug_backends[i].new_log_level = -1;
+ }
+}
+
+void debug_set_settings(struct debug_settings *settings,
+ const char *logging_param,
+ int syslog_level, bool syslog_only)
+{
+ char fake_param[256];
+ size_t len = 0;
+
+ /*
+ * This forces in some smb.conf derived values into the debug
+ * system. There are no pointers in this structure, so we can
+ * just structure-assign it in
+ */
+ state.settings = *settings;
+
+ /*
+ * If 'logging' is not set, create backend settings from
+ * deprecated 'syslog' and 'syslog only' parameters
+ */
+ if (logging_param != NULL) {
+ len = strlen(logging_param);
+ }
+ if (len == 0) {
+ if (syslog_only) {
+ snprintf(fake_param, sizeof(fake_param),
+ "syslog@%d", syslog_level - 1);
+ } else {
+ snprintf(fake_param, sizeof(fake_param),
+ "syslog@%d file@%d", syslog_level -1,
+ MAX_DEBUG_LEVEL);
+ }
+
+ logging_param = fake_param;
+ }
+
+ debug_set_backends(logging_param);
+}
+
+static void ensure_hostname(void)
+{
+ int ret;
+
+ if (state.hostname[0] != '\0') {
+ return;
+ }
+
+ ret = gethostname(state.hostname, sizeof(state.hostname));
+ if (ret != 0) {
+ strlcpy(state.hostname, "unknown", sizeof(state.hostname));
+ return;
+ }
+
+ /*
+ * Ensure NUL termination, since POSIX isn't clear about that.
+ *
+ * Don't worry about truncating at the first '.' or similar,
+ * since this is usually not fully qualified. Trying to
+ * truncate opens up the multibyte character gates of hell.
+ */
+ state.hostname[sizeof(state.hostname) - 1] = '\0';
+}
+
+void debug_set_hostname(const char *name)
+{
+ strlcpy(state.hostname, name, sizeof(state.hostname));
+}
+
+void debug_set_forced_log_priority(int forced_log_priority)
+{
+ state.forced_log_priority = forced_log_priority;
+}
+
+/**
+ * Ensure debug logs are initialised.
+ *
+ * setup_logging() is called to direct logging to the correct outputs, whether
+ * those be stderr, stdout, files, or syslog, and set the program name used in
+ * the logs. It can be called multiple times.
+ *
+ * There is an order of precedence to the log type. Once set to DEBUG_FILE, it
+ * cannot be reset DEFAULT_DEBUG_STDERR, but can be set to DEBUG_STDERR, after
+ * which DEBUG_FILE is unavailable). This makes it possible to override for
+ * debug to stderr on the command line, as the smb.conf cannot reset it back
+ * to file-based logging. See enum debug_logtype.
+ *
+ * @param prog_name the program name. Directory path component will be
+ * ignored.
+ *
+ * @param new_logtype the requested destination for the debug log,
+ * as an enum debug_logtype.
+ */
+void setup_logging(const char *prog_name, enum debug_logtype new_logtype)
+{
+ debug_init();
+ if (state.logtype < new_logtype) {
+ state.logtype = new_logtype;
+ }
+ if (prog_name) {
+ const char *p = strrchr(prog_name, '/');
+
+ if (p) {
+ prog_name = p + 1;
+ }
+
+ strlcpy(state.prog_name, prog_name, sizeof(state.prog_name));
+ }
+ reopen_logs_internal();
+}
+
+/***************************************************************************
+ Set the logfile name.
+**************************************************************************/
+
+void debug_set_logfile(const char *name)
+{
+ if (name == NULL || *name == 0) {
+ /* this copes with calls when smb.conf is not loaded yet */
+ return;
+ }
+ TALLOC_FREE(dbgc_config[DBGC_ALL].logfile);
+ dbgc_config[DBGC_ALL].logfile = talloc_strdup(NULL, name);
+
+ reopen_logs_internal();
+}
+
+static void debug_close_fd(int fd)
+{
+ if (fd > 2) {
+ close(fd);
+ }
+}
+
+enum debug_logtype debug_get_log_type(void)
+{
+ return state.logtype;
+}
+
+bool debug_get_output_is_stderr(void)
+{
+ return (state.logtype == DEBUG_DEFAULT_STDERR) || (state.logtype == DEBUG_STDERR);
+}
+
+bool debug_get_output_is_stdout(void)
+{
+ return (state.logtype == DEBUG_DEFAULT_STDOUT) || (state.logtype == DEBUG_STDOUT);
+}
+
+void debug_set_callback(void *private_ptr, debug_callback_fn fn)
+{
+ debug_init();
+ if (fn) {
+ state.logtype = DEBUG_CALLBACK;
+ state.callback_private = private_ptr;
+ state.callback = fn;
+ } else {
+ state.logtype = DEBUG_DEFAULT_STDERR;
+ state.callback_private = NULL;
+ state.callback = NULL;
+ }
+}
+
+static void debug_callback_log(const char *msg, size_t msg_len, int msg_level)
+{
+ char msg_copy[msg_len];
+
+ if ((msg_len > 0) && (msg[msg_len-1] == '\n')) {
+ memcpy(msg_copy, msg, msg_len-1);
+ msg_copy[msg_len-1] = '\0';
+ msg = msg_copy;
+ }
+
+ state.callback(state.callback_private, msg_level, msg);
+}
+
+/**************************************************************************
+ reopen the log files
+ note that we now do this unconditionally
+ We attempt to open the new debug fp before closing the old. This means
+ if we run out of fd's we just keep using the old fd rather than aborting.
+ Fix from dgibson@linuxcare.com.
+**************************************************************************/
+
+static bool reopen_one_log(struct debug_class *config)
+{
+ int old_fd = config->fd;
+ const char *logfile = config->logfile;
+ struct stat st;
+ int new_fd;
+ int ret;
+
+ if (logfile == NULL) {
+ debug_close_fd(old_fd);
+ config->fd = -1;
+ return true;
+ }
+
+ new_fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, 0644);
+ if (new_fd == -1) {
+ log_overflow = true;
+ DBG_ERR("Unable to open new log file '%s': %s\n",
+ logfile, strerror(errno));
+ log_overflow = false;
+ return false;
+ }
+
+ debug_close_fd(old_fd);
+ smb_set_close_on_exec(new_fd);
+ config->fd = new_fd;
+
+ ret = fstat(new_fd, &st);
+ if (ret != 0) {
+ log_overflow = true;
+ DBG_ERR("Unable to fstat() new log file '%s': %s\n",
+ logfile, strerror(errno));
+ log_overflow = false;
+ return false;
+ }
+
+ config->ino = st.st_ino;
+ return true;
+}
+
+/**
+ reopen the log file (usually called because the log file name might have changed)
+*/
+bool reopen_logs_internal(void)
+{
+ struct debug_backend *b = NULL;
+ mode_t oldumask;
+ size_t i;
+ bool ok = true;
+
+ if (state.reopening_logs) {
+ return true;
+ }
+
+ /* Now clear the SIGHUP induced flag */
+ state.schedule_reopen_logs = false;
+
+ switch (state.logtype) {
+ case DEBUG_CALLBACK:
+ return true;
+ case DEBUG_STDOUT:
+ case DEBUG_DEFAULT_STDOUT:
+ debug_close_fd(dbgc_config[DBGC_ALL].fd);
+ dbgc_config[DBGC_ALL].fd = 1;
+ return true;
+
+ case DEBUG_DEFAULT_STDERR:
+ case DEBUG_STDERR:
+ debug_close_fd(dbgc_config[DBGC_ALL].fd);
+ dbgc_config[DBGC_ALL].fd = 2;
+ return true;
+
+ case DEBUG_FILE:
+ b = debug_find_backend("file");
+ assert(b != NULL);
+
+ b->log_level = MAX_DEBUG_LEVEL;
+ break;
+ }
+
+ oldumask = umask( 022 );
+
+ for (i = DBGC_ALL; i < debug_num_classes; i++) {
+ if (dbgc_config[i].logfile != NULL) {
+ break;
+ }
+ }
+ if (i == debug_num_classes) {
+ return false;
+ }
+
+ state.reopening_logs = true;
+
+ for (i = DBGC_ALL; i < debug_num_classes; i++) {
+ ok = reopen_one_log(&dbgc_config[i]);
+ if (!ok) {
+ break;
+ }
+ }
+
+ /* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
+ * to fix problem where smbd's that generate less
+ * than 100 messages keep growing the log.
+ */
+ force_check_log_size();
+ (void)umask(oldumask);
+
+ /*
+ * If log file was opened or created successfully, take over stderr to
+ * catch output into logs.
+ */
+ if (!state.settings.debug_no_stderr_redirect &&
+ dbgc_config[DBGC_ALL].fd > 0) {
+ if (dup2(dbgc_config[DBGC_ALL].fd, 2) == -1) {
+ /* Close stderr too, if dup2 can't point it -
+ at the logfile. There really isn't much
+ that can be done on such a fundamental
+ failure... */
+ close_low_fd(2);
+ }
+ }
+
+ state.reopening_logs = false;
+
+ return ok;
+}
+
+/**************************************************************************
+ Force a check of the log size.
+ ***************************************************************************/
+
+void force_check_log_size( void )
+{
+ debug_count = 100;
+}
+
+_PUBLIC_ void debug_schedule_reopen_logs(void)
+{
+ state.schedule_reopen_logs = true;
+}
+
+
+/***************************************************************************
+ Check to see if there is any need to check if the logfile has grown too big.
+**************************************************************************/
+
+bool need_to_check_log_size(void)
+{
+ int maxlog;
+ size_t i;
+
+ if (debug_count < 100) {
+ return false;
+ }
+
+ maxlog = state.settings.max_log_size * 1024;
+ if (maxlog <= 0) {
+ debug_count = 0;
+ return false;
+ }
+
+ if (dbgc_config[DBGC_ALL].fd > 2) {
+ return true;
+ }
+
+ for (i = DBGC_ALL + 1; i < debug_num_classes; i++) {
+ if (dbgc_config[i].fd != -1) {
+ return true;
+ }
+ }
+
+ debug_count = 0;
+ return false;
+}
+
+/**************************************************************************
+ Check to see if the log has grown to be too big.
+ **************************************************************************/
+
+static void do_one_check_log_size(off_t maxlog, struct debug_class *config)
+{
+ char name[strlen(config->logfile) + 5];
+ struct stat st;
+ int ret;
+ bool reopen = false;
+ bool ok;
+
+ if (maxlog == 0) {
+ return;
+ }
+
+ ret = stat(config->logfile, &st);
+ if (ret != 0) {
+ return;
+ }
+ if (st.st_size >= maxlog ) {
+ reopen = true;
+ }
+
+ if (st.st_ino != config->ino) {
+ reopen = true;
+ }
+
+ if (!reopen) {
+ return;
+ }
+
+ /* reopen_logs_internal() modifies *_fd */
+ (void)reopen_logs_internal();
+
+ if (config->fd <= 2) {
+ return;
+ }
+ ret = fstat(config->fd, &st);
+ if (ret != 0) {
+ config->ino = (ino_t)0;
+ return;
+ }
+
+ config->ino = st.st_ino;
+
+ if (st.st_size < maxlog) {
+ return;
+ }
+
+ snprintf(name, sizeof(name), "%s.old", config->logfile);
+
+ (void)rename(config->logfile, name);
+
+ ok = reopen_logs_internal();
+ if (ok) {
+ return;
+ }
+ /* We failed to reopen a log - continue using the old name. */
+ (void)rename(name, config->logfile);
+}
+
+static void do_check_log_size(off_t maxlog)
+{
+ size_t i;
+
+ for (i = DBGC_ALL; i < debug_num_classes; i++) {
+ if (dbgc_config[i].fd == -1) {
+ continue;
+ }
+ if (dbgc_config[i].logfile == NULL) {
+ continue;
+ }
+ do_one_check_log_size(maxlog, &dbgc_config[i]);
+ }
+}
+
+void check_log_size( void )
+{
+ off_t maxlog;
+
+ if (geteuid() != 0) {
+ /*
+ * We need to be root to change the log file (tests use a fake
+ * geteuid() from third_party/uid_wrapper). Otherwise we skip
+ * this and let the main smbd loop or some other process do
+ * the work.
+ */
+ return;
+ }
+
+ if(log_overflow || (!state.schedule_reopen_logs && !need_to_check_log_size())) {
+ return;
+ }
+
+ maxlog = state.settings.max_log_size * 1024;
+
+ if (state.schedule_reopen_logs) {
+ (void)reopen_logs_internal();
+ }
+
+ do_check_log_size(maxlog);
+
+ /*
+ * Here's where we need to panic if dbgc_config[DBGC_ALL].fd == 0 or -1
+ * (invalid values)
+ */
+
+ if (dbgc_config[DBGC_ALL].fd <= 0) {
+ /* This code should only be reached in very strange
+ * circumstances. If we merely fail to open the new log we
+ * should stick with the old one. ergo this should only be
+ * reached when opening the logs for the first time: at
+ * startup or when the log level is increased from zero.
+ * -dwg 6 June 2000
+ */
+ int fd = open( "/dev/console", O_WRONLY, 0);
+ if (fd != -1) {
+ smb_set_close_on_exec(fd);
+ dbgc_config[DBGC_ALL].fd = fd;
+ DBG_ERR("check_log_size: open of debug file %s failed "
+ "- using console.\n",
+ dbgc_config[DBGC_ALL].logfile);
+ } else {
+ /*
+ * We cannot continue without a debug file handle.
+ */
+ abort();
+ }
+ }
+ debug_count = 0;
+}
+
+/*************************************************************************
+ Write an debug message on the debugfile.
+ This is called by format_debug_text().
+************************************************************************/
+
+static void Debug1(const char *msg, size_t msg_len)
+{
+ int old_errno = errno;
+
+ debug_count++;
+
+ switch(state.logtype) {
+ case DEBUG_CALLBACK:
+ debug_callback_log(msg, msg_len, current_msg_level);
+ break;
+ case DEBUG_STDOUT:
+ case DEBUG_STDERR:
+ case DEBUG_DEFAULT_STDOUT:
+ case DEBUG_DEFAULT_STDERR:
+ if (state.settings.debug_syslog_format ==
+ DEBUG_SYSLOG_FORMAT_ALWAYS) {
+ debug_file_log(current_msg_level, msg, msg_len);
+ } else {
+ if (dbgc_config[DBGC_ALL].fd > 0) {
+ ssize_t ret;
+ do {
+ ret = write(dbgc_config[DBGC_ALL].fd,
+ msg,
+ msg_len);
+ } while (ret == -1 && errno == EINTR);
+ }
+ }
+ break;
+ case DEBUG_FILE:
+ debug_backends_log(msg, msg_len, current_msg_level);
+ break;
+ };
+
+ errno = old_errno;
+}
+
+/**************************************************************************
+ Print the buffer content via Debug1(), then reset the buffer.
+ Input: none
+ Output: none
+****************************************************************************/
+
+static void bufr_print( void )
+{
+ format_bufr[format_pos] = '\0';
+ (void)Debug1(format_bufr, format_pos);
+ format_pos = 0;
+}
+
+/*
+ * If set (by tevent_thread_call_depth_set()) to value > 0, debug code will use
+ * it for the trace indentation.
+ */
+static size_t debug_call_depth = 0;
+
+size_t *debug_call_depth_addr(void)
+{
+ return &debug_call_depth;
+}
+
+/***************************************************************************
+ Format the debug message text.
+
+ Input: msg - Text to be added to the "current" debug message text.
+
+ Output: none.
+
+ Notes: The purpose of this is two-fold. First, each call to syslog()
+ (used by Debug1(), see above) generates a new line of syslog
+ output. This is fixed by storing the partial lines until the
+ newline character is encountered. Second, printing the debug
+ message lines when a newline is encountered allows us to add
+ spaces, thus indenting the body of the message and making it
+ more readable.
+**************************************************************************/
+
+static void format_debug_text( const char *msg )
+{
+ size_t i;
+ bool timestamp = (state.logtype == DEBUG_FILE && (state.settings.timestamp_logs));
+
+ debug_init();
+
+ for( i = 0; msg[i]; i++ ) {
+ /* Indent two spaces at each new line. */
+ if(timestamp && 0 == format_pos) {
+ /* Limit the maximum indentation to 20 levels */
+ size_t depth = MIN(20, debug_call_depth);
+ format_bufr[0] = format_bufr[1] = ' ';
+ format_pos = 2;
+ /*
+ * Indent by four spaces for each depth level,
+ * but only if the current debug level is >= 8.
+ */
+ if (depth > 0 && debuglevel_get() >= 8 &&
+ format_pos + 4 * depth < FORMAT_BUFR_SIZE) {
+ memset(&format_bufr[format_pos],
+ ' ',
+ 4 * depth);
+ format_pos += 4 * depth;
+ }
+ }
+
+ /* If there's room, copy the character to the format buffer. */
+ if (format_pos < FORMAT_BUFR_SIZE - 1)
+ format_bufr[format_pos++] = msg[i];
+
+ /* If a newline is encountered, print & restart. */
+ if( '\n' == msg[i] )
+ bufr_print();
+
+ /* If the buffer is full dump it out, reset it, and put out a line
+ * continuation indicator.
+ */
+ if (format_pos >= FORMAT_BUFR_SIZE - 1) {
+ const char cont[] = " +>\n";
+ bufr_print();
+ (void)Debug1(cont , sizeof(cont) - 1);
+ }
+ }
+
+ /* Just to be safe... */
+ format_bufr[format_pos] = '\0';
+}
+
+/***************************************************************************
+ Flush debug output, including the format buffer content.
+
+ Input: none
+ Output: none
+***************************************************************************/
+
+void dbgflush( void )
+{
+ bufr_print();
+}
+
+bool dbgsetclass(int level, int cls)
+{
+ /* Set current_msg_level. */
+ current_msg_level = level;
+
+ /* Set current message class */
+ current_msg_class = cls;
+
+ return true;
+}
+
+/***************************************************************************
+ Put a Debug Header into header_str.
+
+ Input: level - Debug level of the message (not the system-wide debug
+ level. )
+ cls - Debuglevel class of the calling module.
+ location - Pointer to a string containing the name of the file
+ from which this function was called, or an empty string
+ if the __FILE__ macro is not implemented.
+ func - Pointer to a string containing the name of the function
+ from which this function was called, or an empty string
+ if the __FUNCTION__ macro is not implemented.
+
+ Output: Always true. This makes it easy to fudge a call to dbghdr()
+ in a macro, since the function can be called as part of a test.
+ Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
+
+ Notes: This function takes care of setting current_msg_level.
+
+****************************************************************************/
+
+bool dbghdrclass(int level, int cls, const char *location, const char *func)
+{
+ /* Ensure we don't lose any real errno value. */
+ int old_errno = errno;
+ bool verbose = false;
+ struct timeval tv;
+ struct timeval_buf tvbuf;
+
+ /*
+ * This might be overkill, but if another early return is
+ * added later then initialising these avoids potential
+ * problems
+ */
+ state.hs_len = 0;
+ state.header_str[0] = '\0';
+
+ if( format_pos ) {
+ /* This is a fudge. If there is stuff sitting in the format_bufr, then
+ * the *right* thing to do is to call
+ * format_debug_text( "\n" );
+ * to write the remainder, and then proceed with the new header.
+ * Unfortunately, there are several places in the code at which
+ * the DEBUG() macro is used to build partial lines. That in mind,
+ * we'll work under the assumption that an incomplete line indicates
+ * that a new header is *not* desired.
+ */
+ return( true );
+ }
+
+ dbgsetclass(level, cls);
+
+ /*
+ * Don't print a header if we're logging to stdout,
+ * unless 'debug syslog format = always'
+ */
+ if (state.logtype != DEBUG_FILE &&
+ state.settings.debug_syslog_format != DEBUG_SYSLOG_FORMAT_ALWAYS)
+ {
+ return true;
+ }
+
+ /*
+ * Print the header if timestamps (or debug syslog format) is
+ * turned on. If parameters are not yet loaded, then default
+ * to timestamps on.
+ */
+ if (!(state.settings.timestamp_logs ||
+ state.settings.debug_prefix_timestamp ||
+ state.settings.debug_syslog_format != DEBUG_SYSLOG_FORMAT_NO))
+ {
+ return true;
+ }
+
+ GetTimeOfDay(&tv);
+
+ if (state.settings.debug_syslog_format != DEBUG_SYSLOG_FORMAT_NO) {
+ if (state.settings.debug_hires_timestamp) {
+ timeval_str_buf(&tv, true, true, &tvbuf);
+ } else {
+ time_t t;
+ struct tm *tm;
+
+ t = (time_t)tv.tv_sec;
+ tm = localtime(&t);
+ if (tm != NULL) {
+ size_t len;
+ len = strftime(tvbuf.buf,
+ sizeof(tvbuf.buf),
+ "%b %e %T",
+ tm);
+ if (len == 0) {
+ /* Trigger default time format below */
+ tm = NULL;
+ }
+ }
+ if (tm == NULL) {
+ snprintf(tvbuf.buf,
+ sizeof(tvbuf.buf),
+ "%ld seconds since the Epoch", (long)t);
+ }
+ }
+
+ ensure_hostname();
+ state.hs_len = snprintf(state.header_str,
+ sizeof(state.header_str),
+ "%s %.*s %s[%u]: ",
+ tvbuf.buf,
+ (int)(sizeof(state.hostname) - 1),
+ state.hostname,
+ state.prog_name,
+ (unsigned int) getpid());
+
+ goto full;
+ }
+
+ timeval_str_buf(&tv, false, state.settings.debug_hires_timestamp,
+ &tvbuf);
+
+ state.hs_len = snprintf(state.header_str,
+ sizeof(state.header_str),
+ "[%s, %2d",
+ tvbuf.buf,
+ level);
+ if (state.hs_len >= sizeof(state.header_str) - 1) {
+ goto full;
+ }
+
+ if (unlikely(dbgc_config[cls].loglevel >= 10)) {
+ verbose = true;
+ }
+
+ if (verbose || state.settings.debug_pid) {
+ state.hs_len += snprintf(state.header_str + state.hs_len,
+ sizeof(state.header_str) - state.hs_len,
+ ", pid=%u",
+ (unsigned int)getpid());
+ if (state.hs_len >= sizeof(state.header_str) - 1) {
+ goto full;
+ }
+ }
+
+ if (verbose || state.settings.debug_uid) {
+ state.hs_len += snprintf(state.header_str + state.hs_len,
+ sizeof(state.header_str) - state.hs_len,
+ ", effective(%u, %u), real(%u, %u)",
+ (unsigned int)geteuid(),
+ (unsigned int)getegid(),
+ (unsigned int)getuid(),
+ (unsigned int)getgid());
+ if (state.hs_len >= sizeof(state.header_str) - 1) {
+ goto full;
+ }
+ }
+
+ if ((verbose || state.settings.debug_class)
+ && (cls != DBGC_ALL)) {
+ state.hs_len += snprintf(state.header_str + state.hs_len,
+ sizeof(state.header_str) - state.hs_len,
+ ", class=%s",
+ classname_table[cls]);
+ if (state.hs_len >= sizeof(state.header_str) - 1) {
+ goto full;
+ }
+ }
+
+ if (debug_traceid_get() != 0) {
+ state.hs_len += snprintf(state.header_str + state.hs_len,
+ sizeof(state.header_str) - state.hs_len,
+ ", traceid=%" PRIu64,
+ debug_traceid_get());
+ if (state.hs_len >= sizeof(state.header_str) - 1) {
+ goto full;
+ }
+ }
+
+ if (debug_call_depth > 0) {
+ state.hs_len += snprintf(state.header_str + state.hs_len,
+ sizeof(state.header_str) - state.hs_len,
+ ", depth=%zu",
+ debug_call_depth);
+ if (state.hs_len >= sizeof(state.header_str) - 1) {
+ goto full;
+ }
+ }
+
+ state.header_str[state.hs_len] = ']';
+ state.hs_len++;
+ if (state.hs_len < sizeof(state.header_str) - 1) {
+ state.header_str[state.hs_len] = ' ';
+ state.hs_len++;
+ }
+ state.header_str[state.hs_len] = '\0';
+
+ if (!state.settings.debug_prefix_timestamp) {
+ state.hs_len += snprintf(state.header_str + state.hs_len,
+ sizeof(state.header_str) - state.hs_len,
+ "%s(%s)\n",
+ location,
+ func);
+ if (state.hs_len >= sizeof(state.header_str)) {
+ goto full;
+ }
+ }
+
+full:
+ /*
+ * Above code never overflows state.header_str and always
+ * NUL-terminates correctly. However, state.hs_len can point
+ * past the end of the buffer to indicate that truncation
+ * occurred, so fix it if necessary, since state.hs_len is
+ * expected to be used after return.
+ */
+ if (state.hs_len >= sizeof(state.header_str)) {
+ state.hs_len = sizeof(state.header_str) - 1;
+ }
+
+ errno = old_errno;
+ return( true );
+}
+
+/***************************************************************************
+ Add text to the body of the "current" debug message via the format buffer.
+
+ Input: format_str - Format string, as used in printf(), et. al.
+ ... - Variable argument list.
+
+ ..or.. va_alist - Old style variable parameter list starting point.
+
+ Output: Always true. See dbghdr() for more info, though this is not
+ likely to be used in the same way.
+
+***************************************************************************/
+
+static inline bool __dbgtext_va(const char *format_str, va_list ap) PRINTF_ATTRIBUTE(1,0);
+static inline bool __dbgtext_va(const char *format_str, va_list ap)
+{
+ char *msgbuf = NULL;
+ bool ret = true;
+ int res;
+
+ res = vasprintf(&msgbuf, format_str, ap);
+ if (res != -1) {
+ format_debug_text(msgbuf);
+ } else {
+ ret = false;
+ }
+ SAFE_FREE(msgbuf);
+ return ret;
+}
+
+bool dbgtext_va(const char *format_str, va_list ap)
+{
+ return __dbgtext_va(format_str, ap);
+}
+
+bool dbgtext(const char *format_str, ... )
+{
+ va_list ap;
+ bool ret;
+
+ va_start(ap, format_str);
+ ret = __dbgtext_va(format_str, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+static uint64_t debug_traceid = 0;
+
+uint64_t debug_traceid_set(uint64_t id)
+{
+ uint64_t old_id = debug_traceid;
+ debug_traceid = id;
+ return old_id;
+}
+
+uint64_t debug_traceid_get(void)
+{
+ return debug_traceid;
+}
diff --git a/lib/util/debug.h b/lib/util/debug.h
new file mode 100644
index 0000000..4687ac0
--- /dev/null
+++ b/lib/util/debug.h
@@ -0,0 +1,396 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB debug stuff
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) John H Terpstra 1996-1998
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998
+ Copyright (C) Paul Ashton 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_DEBUG_H
+#define _SAMBA_DEBUG_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include "attr.h"
+
+
+/* -------------------------------------------------------------------------- **
+ * Debugging code. See also debug.c
+ */
+
+/* the maximum debug level to compile into the code. This assumes a good
+ optimising compiler that can remove unused code
+ for embedded or low-memory systems set this to a value like 2 to get
+ only important messages. This gives *much* smaller binaries
+*/
+#ifndef MAX_DEBUG_LEVEL
+#define MAX_DEBUG_LEVEL 1000
+#endif
+
+bool dbgtext_va(const char *, va_list ap) PRINTF_ATTRIBUTE(1,0);
+bool dbgtext( const char *, ... ) PRINTF_ATTRIBUTE(1,2);
+bool dbghdrclass( int level, int cls, const char *location, const char *func);
+bool dbgsetclass(int level, int cls);
+
+/*
+ * Define all new debug classes here. A class is represented by an entry in
+ * the DEBUGLEVEL_CLASS array. Index zero of this array is equivalent to the
+ * old DEBUGLEVEL. Any source file that does NOT add the following lines:
+ *
+ * #undef DBGC_CLASS
+ * #define DBGC_CLASS DBGC_<your class name here>
+ *
+ * at the start of the file (after #include "includes.h") will default to
+ * using index zero, so it will behave just like it always has.
+ */
+#define DBGC_ALL 0 /* index equivalent to DEBUGLEVEL */
+
+#define DBGC_TDB 1
+#define DBGC_PRINTDRIVERS 2
+#define DBGC_LANMAN 3
+#define DBGC_SMB 4
+#define DBGC_RPC_PARSE 5
+#define DBGC_RPC_SRV 6
+#define DBGC_RPC_CLI 7
+#define DBGC_PASSDB 8
+#define DBGC_SAM 9
+#define DBGC_AUTH 10
+#define DBGC_WINBIND 11
+#define DBGC_VFS 12
+#define DBGC_IDMAP 13
+#define DBGC_QUOTA 14
+#define DBGC_ACLS 15
+#define DBGC_LOCKING 16
+#define DBGC_MSDFS 17
+#define DBGC_DMAPI 18
+#define DBGC_REGISTRY 19
+#define DBGC_SCAVENGER 20
+#define DBGC_DNS 21
+#define DBGC_LDB 22
+#define DBGC_TEVENT 23
+#define DBGC_AUTH_AUDIT 24
+#define DBGC_AUTH_AUDIT_JSON 25
+#define DBGC_KERBEROS 26
+#define DBGC_DRS_REPL 27
+#define DBGC_SMB2 28
+#define DBGC_SMB2_CREDITS 29
+#define DBGC_DSDB_AUDIT 30
+#define DBGC_DSDB_AUDIT_JSON 31
+#define DBGC_DSDB_PWD_AUDIT 32
+#define DBGC_DSDB_PWD_AUDIT_JSON 33
+#define DBGC_DSDB_TXN_AUDIT 34
+#define DBGC_DSDB_TXN_AUDIT_JSON 35
+#define DBGC_DSDB_GROUP_AUDIT 36
+#define DBGC_DSDB_GROUP_AUDIT_JSON 37
+
+/* So you can define DBGC_CLASS before including debug.h */
+#ifndef DBGC_CLASS
+#define DBGC_CLASS 0 /* override as shown above */
+#endif
+
+#define DEBUGLEVEL debuglevel_get()
+
+#define debuglevel_get() debuglevel_get_class(DBGC_ALL)
+#define debuglevel_set(lvl) debuglevel_set_class(DBGC_ALL, (lvl))
+
+/* Debugging macros
+ *
+ * DEBUGLVL()
+ * If the 'file specific' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synonym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Returns True if the debug level was <= DEBUGLEVEL.
+ *
+ * Example: if( DEBUGLVL( 2 ) ) dbgtext( "Some text.\n" );
+ *
+ * DEBUG()
+ * If the 'file specific' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synonym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Each call to DEBUG() generates a new header *unless* the
+ * previous debug output was unterminated (i.e. no '\n').
+ * See debug.c:dbghdr() for more info.
+ *
+ * Example: DEBUG( 2, ("Some text and a value %d.\n", value) );
+ *
+ * DEBUGC()
+ * If the 'macro specified' debug class level >= level OR the system-wide
+ * DEBUGLEVEL (synonym for DEBUGLEVEL_CLASS[ DBGC_ALL ]) >= level then
+ * generate a header using the default macros for file, line, and
+ * function name. Each call to DEBUG() generates a new header *unless* the
+ * previous debug output was unterminated (i.e. no '\n').
+ * See debug.c:dbghdr() for more info.
+ *
+ * Example: DEBUGC( DBGC_TDB, 2, ("Some text and a value %d.\n", value) );
+ *
+ * DEBUGADD(), DEBUGADDC()
+ * Same as DEBUG() and DEBUGC() except the text is appended to the previous
+ * DEBUG(), DEBUGC(), DEBUGADD(), DEBUGADDC() with out another interviening
+ * header.
+ *
+ * Example: DEBUGADD( 2, ("Some text and a value %d.\n", value) );
+ * DEBUGADDC( DBGC_TDB, 2, ("Some text and a value %d.\n", value) );
+ *
+ * Note: If the debug class has not be redefined (see above) then the optimizer
+ * will remove the extra conditional test.
+ */
+
+/*
+ * From talloc.c:
+ */
+
+/* these macros gain us a few percent of speed on gcc */
+#if (__GNUC__ >= 3)
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+ as its first argument */
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+int debuglevel_get_class(size_t idx);
+void debuglevel_set_class(size_t idx, int level);
+
+#define CHECK_DEBUGLVL( level ) \
+ ( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(DBGC_CLASS) >= (level)))
+
+#define CHECK_DEBUGLVLC( dbgc_class, level ) \
+ ( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(dbgc_class) >= (level)))
+
+#define DEBUGLVL( level ) \
+ ( CHECK_DEBUGLVL(level) \
+ && dbghdrclass( level, DBGC_CLASS, __location__, __FUNCTION__ ) )
+
+#define DEBUGLVLC( dbgc_class, level ) \
+ ( CHECK_DEBUGLVLC( dbgc_class, level ) \
+ && dbghdrclass( level, dbgc_class, __location__, __FUNCTION__ ) )
+
+#define DEBUG( level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(DBGC_CLASS) >= (level)) \
+ && (dbghdrclass( level, DBGC_CLASS, __location__, __FUNCTION__ )) \
+ && (dbgtext body) )
+
+/**
+ * @brief DEBUGLF is same as DEBUG with explicit location and function arguments
+ *
+ * To be used when passing location and function of a caller appearing earlier in
+ * the call stack instead of some helper function.
+ *
+ * @code
+ * DEBUGLF( 2, ("Some text.\n"), "foo.c:1", "foo" );
+ * DEBUGLF( 5, ("Some text.\n"), location, function );
+ * @endcode
+ *
+ * @return void.
+ */
+#define DEBUGLF( level, body, location, function ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(DBGC_CLASS) >= (level)) \
+ && (dbghdrclass( level, DBGC_CLASS, location, function )) \
+ && (dbgtext body) )
+
+#define DEBUGC( dbgc_class, level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(dbgc_class) >= (level)) \
+ && (dbghdrclass( level, dbgc_class, __location__, __FUNCTION__ )) \
+ && (dbgtext body) )
+
+#define DEBUGADD( level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(DBGC_CLASS) >= (level)) \
+ && (dbgsetclass(level, DBGC_CLASS)) \
+ && (dbgtext body) )
+
+#define DEBUGADDC( dbgc_class, level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely((debuglevel_get_class(dbgc_class) >= (level))) \
+ && (dbgsetclass(level, dbgc_class)) \
+ && (dbgtext body) )
+
+/* Print a separator to the debug log. */
+#define DEBUGSEP(level)\
+ DEBUG((level),("===============================================================\n"))
+
+/* Prefix messages with the function name */
+#define DBG_PREFIX(level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(DBGC_CLASS) >= (level)) \
+ && (dbghdrclass(level, DBGC_CLASS, __location__, __func__ )) \
+ && (dbgtext("%s: ", __func__)) \
+ && (dbgtext body) )
+
+/* Prefix messages with the function name - class specific */
+#define DBGC_PREFIX(dbgc_class, level, body ) \
+ (void)( ((level) <= MAX_DEBUG_LEVEL) && \
+ unlikely(debuglevel_get_class(dbgc_class) >= (level)) \
+ && (dbghdrclass(level, dbgc_class, __location__, __func__ )) \
+ && (dbgtext("%s: ", __func__)) \
+ && (dbgtext body) )
+
+
+#ifdef DEVELOPER
+#define DBG_DEV(...) \
+ (void)( (debug_developer_enabled()) \
+ && (dbgtext("%s:DEV:%d: ", __func__, getpid())) \
+ && (dbgtext(__VA_ARGS__)) )
+#else
+#define DBG_DEV(...) /* DBG_DEV was here */
+#endif
+
+/*
+ * Debug levels matching RFC 3164
+ */
+#define DBGLVL_ERR 0 /* error conditions */
+#define DBGLVL_WARNING 1 /* warning conditions */
+#define DBGLVL_NOTICE 3 /* normal, but significant, condition */
+#define DBGLVL_INFO 5 /* informational message */
+#define DBGLVL_DEBUG 10 /* debug-level message */
+
+#define DBG_STARTUP_NOTICE(...) do { \
+ debug_set_forced_log_priority(DBGLVL_NOTICE); \
+ D_ERR(__VA_ARGS__); \
+ debug_set_forced_log_priority(-1); \
+} while(0)
+
+#define DBG_ERR(...) DBG_PREFIX(DBGLVL_ERR, (__VA_ARGS__))
+#define DBG_WARNING(...) DBG_PREFIX(DBGLVL_WARNING, (__VA_ARGS__))
+#define DBG_NOTICE(...) DBG_PREFIX(DBGLVL_NOTICE, (__VA_ARGS__))
+#define DBG_INFO(...) DBG_PREFIX(DBGLVL_INFO, (__VA_ARGS__))
+#define DBG_DEBUG(...) DBG_PREFIX(DBGLVL_DEBUG, (__VA_ARGS__))
+
+#define DBGC_ERR(dbgc_class, ...) DBGC_PREFIX(dbgc_class, \
+ DBGLVL_ERR, (__VA_ARGS__))
+#define DBGC_WARNING(dbgc_class, ...) DBGC_PREFIX(dbgc_class, \
+ DBGLVL_WARNING, (__VA_ARGS__))
+#define DBGC_NOTICE(dbgc_class, ...) DBGC_PREFIX(dbgc_class, \
+ DBGLVL_NOTICE, (__VA_ARGS__))
+#define DBGC_INFO(dbgc_class, ...) DBGC_PREFIX(dbgc_class, \
+ DBGLVL_INFO, (__VA_ARGS__))
+#define DBGC_DEBUG(dbgc_class, ...) DBGC_PREFIX(dbgc_class, \
+ DBGLVL_DEBUG, (__VA_ARGS__))
+
+#define D_ERR(...) DEBUG(DBGLVL_ERR, (__VA_ARGS__))
+#define D_WARNING(...) DEBUG(DBGLVL_WARNING, (__VA_ARGS__))
+#define D_NOTICE(...) DEBUG(DBGLVL_NOTICE, (__VA_ARGS__))
+#define D_INFO(...) DEBUG(DBGLVL_INFO, (__VA_ARGS__))
+#define D_DEBUG(...) DEBUG(DBGLVL_DEBUG, (__VA_ARGS__))
+
+#define DC_ERR(...) DEBUGC(dbgc_class, \
+ DBGLVL_ERR, (__VA_ARGS__))
+#define DC_WARNING(...) DEBUGC(dbgc_class, \
+ DBGLVL_WARNING, (__VA_ARGS__))
+#define DC_NOTICE(...) DEBUGC(dbgc_class, \
+ DBGLVL_NOTICE, (__VA_ARGS__))
+#define DC_INFO(...) DEBUGC(dbgc_class, \
+ DBGLVL_INFO, (__VA_ARGS__))
+#define DC_DEBUG(...) DEBUGC(dbgc_class, \
+ DBGLVL_DEBUG, (__VA_ARGS__))
+
+/* The following definitions come from lib/debug.c */
+
+/**
+ * Possible destinations for the debug log.
+ *
+ * Set via setup_logging(); higher values have precedence.
+ */
+enum debug_logtype {
+ DEBUG_DEFAULT_STDERR = 0,
+ DEBUG_DEFAULT_STDOUT = 1,
+ DEBUG_FILE = 2,
+ DEBUG_STDOUT = 3,
+ DEBUG_STDERR = 4,
+ DEBUG_CALLBACK = 5
+};
+
+enum debug_syslog_format {
+ DEBUG_SYSLOG_FORMAT_NO = 0,
+ DEBUG_SYSLOG_FORMAT_IN_LOGS = 1,
+ DEBUG_SYSLOG_FORMAT_ALWAYS = 2,
+};
+
+struct debug_settings {
+ size_t max_log_size;
+ bool timestamp_logs;
+ bool debug_prefix_timestamp;
+ bool debug_hires_timestamp;
+ enum debug_syslog_format debug_syslog_format;
+ bool debug_pid;
+ bool debug_uid;
+ bool debug_class;
+ bool debug_no_stderr_redirect;
+};
+
+void setup_logging(const char *prog_name, enum debug_logtype new_logtype);
+
+void gfree_debugsyms(void);
+int debug_add_class(const char *classname);
+bool debug_parse_levels(const char *params_str);
+void debug_setup_talloc_log(void);
+void debug_set_logfile(const char *name);
+void debug_set_settings(struct debug_settings *settings,
+ const char *logging_param,
+ int syslog_level, bool syslog_only);
+void debug_set_hostname(const char *name);
+void debug_set_forced_log_priority(int forced_log_priority);
+bool reopen_logs_internal( void );
+void force_check_log_size( void );
+bool need_to_check_log_size( void );
+void check_log_size( void );
+void dbgflush( void );
+enum debug_logtype debug_get_log_type(void);
+bool debug_get_output_is_stderr(void);
+bool debug_get_output_is_stdout(void);
+void debug_schedule_reopen_logs(void);
+char *debug_list_class_names_and_levels(void);
+bool debug_developer_enabled(void);
+void debug_developer_enable(void);
+void debug_developer_disable(void);
+
+typedef void (*debug_callback_fn)(void *private_ptr, int level, const char *msg);
+
+/**
+ Set a callback for all debug messages. Use in dlz_bind9 to push output to the bind logs
+ */
+void debug_set_callback(void *private_ptr, debug_callback_fn fn);
+
+char *debug_get_ringbuf(void);
+size_t debug_get_ringbuf_size(void);
+
+/* Explicitly set new traceid. The old id is returned. */
+uint64_t debug_traceid_set(uint64_t id);
+
+/* Get the current traceid. */
+uint64_t debug_traceid_get(void);
+
+size_t *debug_call_depth_addr(void);
+
+#endif /* _SAMBA_DEBUG_H */
diff --git a/lib/util/debug_s3.c b/lib/util/debug_s3.c
new file mode 100644
index 0000000..1fd8637
--- /dev/null
+++ b/lib/util/debug_s3.c
@@ -0,0 +1,155 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Bartlett 2011
+ Copyright (C) Andrew Tridgell 1992-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/server_id.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "messages.h"
+#include "lib/util/memory.h"
+
+/* This is the Samba3-specific implementation of reopen_logs(), which
+ * calls out to the s3 loadparm code, and means that we don't depend
+ * on loadparm directly. */
+
+bool reopen_logs(void)
+{
+ if (lp_loaded()) {
+ struct debug_settings settings = {
+ .max_log_size = lp_max_log_size(),
+ .timestamp_logs = lp_timestamp_logs(),
+ .debug_prefix_timestamp = lp_debug_prefix_timestamp(),
+ .debug_hires_timestamp = lp_debug_hires_timestamp(),
+ .debug_syslog_format = lp_debug_syslog_format(),
+ .debug_pid = lp_debug_pid(),
+ .debug_uid = lp_debug_uid(),
+ .debug_class = lp_debug_class(),
+ };
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+
+ debug_set_logfile(lp_logfile(talloc_tos(), lp_sub));
+ debug_parse_levels(lp_log_level(talloc_tos(), lp_sub));
+ debug_set_settings(&settings,
+ lp_logging(talloc_tos(), lp_sub),
+ lp_syslog(),
+ lp_syslog_only());
+ } else {
+ /*
+ * Parameters are not yet loaded - configure debugging with
+ * reasonable defaults to enable logging for early
+ * startup failures.
+ */
+ struct debug_settings settings = {
+ .max_log_size = 5000,
+ .timestamp_logs = true,
+ .debug_prefix_timestamp = false,
+ .debug_hires_timestamp = true,
+ .debug_syslog_format = false,
+ .debug_pid = false,
+ .debug_uid = false,
+ .debug_class = false,
+ };
+ debug_set_settings(&settings,
+ "file",
+ 1,
+ false);
+ }
+ return reopen_logs_internal();
+}
+
+/****************************************************************************
+ Receive a "set debug level" message.
+****************************************************************************/
+
+void debug_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ const char *params_str = (const char *)data->data;
+
+ /* Check, it's a proper string! */
+ if (params_str[(data->length)-1] != '\0') {
+ DEBUG(1, ("Invalid debug message from pid %u to pid %u\n",
+ (unsigned int)procid_to_pid(&src),
+ (unsigned int)getpid()));
+ return;
+ }
+
+ DEBUG(3, ("INFO: Remote set of debug to `%s' (pid %u from pid %u)\n",
+ params_str, (unsigned int)getpid(),
+ (unsigned int)procid_to_pid(&src)));
+
+ debug_parse_levels(params_str);
+}
+
+/****************************************************************************
+ Return current debug level.
+****************************************************************************/
+
+static void debuglevel_message(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ char *message = debug_list_class_names_and_levels();
+ struct server_id_buf tmp;
+
+ if (!message) {
+ DEBUG(0,("debuglevel_message - debug_list_class_names_and_levels returned NULL\n"));
+ return;
+ }
+
+ DEBUG(1, ("INFO: Received REQ_DEBUGLEVEL message from PID %s\n",
+ server_id_str_buf(src, &tmp)));
+ messaging_send_buf(msg_ctx, src, MSG_DEBUGLEVEL,
+ (uint8_t *)message, strlen(message) + 1);
+
+ TALLOC_FREE(message);
+}
+
+static void debug_ringbuf_log(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ DATA_BLOB *data)
+{
+ char *log = debug_get_ringbuf();
+ size_t logsize = debug_get_ringbuf_size();
+
+ if (log == NULL) {
+ log = discard_const_p(char, "*disabled*\n");
+ logsize = strlen(log) + 1;
+ }
+
+ messaging_send_buf(msg_ctx, src, MSG_RINGBUF_LOG, (uint8_t *)log,
+ logsize);
+}
+
+void debug_register_msgs(struct messaging_context *msg_ctx)
+{
+ messaging_register(msg_ctx, NULL, MSG_DEBUG, debug_message);
+ messaging_register(msg_ctx, NULL, MSG_REQ_DEBUGLEVEL,
+ debuglevel_message);
+ messaging_register(msg_ctx, NULL, MSG_REQ_RINGBUF_LOG,
+ debug_ringbuf_log);
+}
diff --git a/lib/util/debug_s3.h b/lib/util/debug_s3.h
new file mode 100644
index 0000000..9e5211b
--- /dev/null
+++ b/lib/util/debug_s3.h
@@ -0,0 +1,26 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB debug stuff
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "librpc/gen_ndr/server_id.h"
+
+struct messaging_context;
+struct server_id;
+void debug_message(struct messaging_context *msg_ctx, void *private_data, uint32_t msg_type, struct server_id src, DATA_BLOB *data);
+void debug_register_msgs(struct messaging_context *msg_ctx);
+bool reopen_logs( void );
diff --git a/lib/util/discard.h b/lib/util/discard.h
new file mode 100644
index 0000000..d2b74ac
--- /dev/null
+++ b/lib/util/discard.h
@@ -0,0 +1,51 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_DISCARD_H_
+#define _SAMBA_DISCARD_H_
+
+/**
+ this is a warning hack. The idea is to use this everywhere that we
+ get the "discarding const" warning from gcc. That doesn't actually
+ fix the problem of course, but it means that when we do get to
+ cleaning them up we can do it by searching the code for
+ discard_const.
+
+ It also means that other error types aren't as swamped by the noise
+ of hundreds of const warnings, so we are more likely to notice when
+ we get new errors.
+
+ Please only add more uses of this macro when you find it
+ _really_ hard to fix const warnings. Our aim is to eventually use
+ this function in only a very few places.
+
+ Also, please call this via the discard_const_p() macro interface, as that
+ makes the return type safe.
+*/
+#ifndef discard_const
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+#endif
+
+/** Type-safe version of discard_const */
+#ifndef discard_const_p
+#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
+#endif
+
+#endif /* _SAMBA_DISCARD_H_ */
diff --git a/lib/util/dlinklist.h b/lib/util/dlinklist.h
new file mode 100644
index 0000000..49a135a
--- /dev/null
+++ b/lib/util/dlinklist.h
@@ -0,0 +1,198 @@
+/*
+ Unix SMB/CIFS implementation.
+ some simple double linked list macros
+
+ Copyright (C) Andrew Tridgell 1998-2010
+
+ ** NOTE! The following LGPL license applies to this file (*dlinklist.h).
+ ** This does NOT imply that all of Samba is released under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* To use these macros you must have a structure containing a next and
+ prev pointer */
+
+#ifndef _DLINKLIST_H
+#define _DLINKLIST_H
+
+/*
+ February 2010 - changed list format to have a prev pointer from the
+ list head. This makes DLIST_ADD_END() O(1) even though we only have
+ one list pointer.
+
+ The scheme is as follows:
+
+ 1) with no entries in the list:
+ list_head == NULL
+
+ 2) with 1 entry in the list:
+ list_head->next == NULL
+ list_head->prev == list_head
+
+ 3) with 2 entries in the list:
+ list_head->next == element2
+ list_head->prev == element2
+ element2->prev == list_head
+ element2->next == NULL
+
+ 4) with N entries in the list:
+ list_head->next == element2
+ list_head->prev == elementN
+ elementN->prev == element{N-1}
+ elementN->next == NULL
+
+ This allows us to find the tail of the list by using
+ list_head->prev, which means we can add to the end of the list in
+ O(1) time
+ */
+
+
+/*
+ add an element at the front of a list
+*/
+#define DLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (p)->prev = (list) = (p); \
+ (p)->next = NULL; \
+ } else { \
+ (p)->prev = (list)->prev; \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (list) = (p); \
+ } \
+} while (0)
+
+/*
+ remove an element from a list
+ Note that the element doesn't have to be in the list. If it
+ isn't then this is a no-op
+*/
+#define DLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ (list) = (p)->next; \
+ } else if ((p)->prev && (list) && (p) == (list)->prev) { \
+ (p)->prev->next = NULL; \
+ (list)->prev = (p)->prev; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) != (list)) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+/*
+ find the head of the list given any element in it.
+ Note that this costs O(N), so you should avoid this macro
+ if at all possible!
+*/
+#define DLIST_HEAD(p, result_head) \
+do { \
+ (result_head) = (p); \
+ while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
+} while(0)
+
+/* return the last element in the list */
+#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
+
+/* return the previous element in the list. */
+#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
+
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+ this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
+do { \
+ if (!(list) || !(el)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ (p)->prev = (el); \
+ (p)->next = (el)->next; \
+ (el)->next = (p); \
+ if ((p)->next) (p)->next->prev = (p); \
+ if ((list)->prev == (el)) (list)->prev = (p); \
+ }\
+} while (0)
+
+
+/*
+ add to the end of a list.
+*/
+#define DLIST_ADD_END(list, p) \
+do { \
+ if (!(list)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ DLIST_ADD_AFTER(list, p, (list)->prev); \
+ } \
+} while (0)
+
+/* promote an element to the front of a list */
+#define DLIST_PROMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD(list, p); \
+} while (0)
+
+/*
+ demote an element to the end of a list.
+*/
+#define DLIST_DEMOTE(list, p) \
+do { \
+ DLIST_REMOVE(list, p); \
+ DLIST_ADD_END(list, p); \
+} while (0)
+
+/*
+ * like DLIST_DEMOTE(), but optimized
+ * for short lists with 0, 1 or 2 elements
+ */
+#define DLIST_DEMOTE_SHORT(list, p) \
+do { \
+ if ((list) == NULL) { \
+ /* no reason to demote, just add */ \
+ DLIST_ADD(list, p); \
+ } else if ((list)->prev == (p)) { \
+ /* optimize if p is last */ \
+ } else if ((list) == (p)) { \
+ /* optimize if p is first */ \
+ (list)->prev->next = (p); \
+ (list) = (p)->next; \
+ (p)->next = NULL; \
+ } else { \
+ DLIST_DEMOTE(list, p); \
+ } \
+} while (0)
+
+/*
+ concatenate two lists - putting all elements of the 2nd list at the
+ end of the first list.
+*/
+#define DLIST_CONCATENATE(list1, list2) \
+do { \
+ if (!(list1)) { \
+ (list1) = (list2); \
+ } else { \
+ (list1)->prev->next = (list2); \
+ if (list2) { \
+ void *_tmplist = (void *)(list1)->prev; \
+ (list1)->prev = (list2)->prev; \
+ (list2)->prev = _tmplist; \
+ } \
+ } \
+} while (0)
+
+#endif /* _DLINKLIST_H */
diff --git a/lib/util/dprintf.c b/lib/util/dprintf.c
new file mode 100644
index 0000000..9d1573f
--- /dev/null
+++ b/lib/util/dprintf.c
@@ -0,0 +1,80 @@
+/*
+ Unix SMB/CIFS implementation.
+ display print functions
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+ this module provides functions for printing internal strings in the
+ "display charset".
+
+ This charset may be quite different from the chosen unix charset.
+
+ Eventually these functions will need to take care of column count constraints
+
+ The d_ prefix on print functions in Samba refers to the display character set
+ conversion
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "lib/util/samba_util.h"
+
+static int d_vfprintf(FILE *f, const char *format, va_list ap)
+ PRINTF_ATTRIBUTE(2,0);
+
+static int d_vfprintf(FILE *f, const char *format, va_list ap)
+{
+ return vfprintf(f, format, ap);
+}
+
+
+_PUBLIC_ int d_fprintf(FILE *f, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, format);
+ ret = d_vfprintf(f, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+static FILE *outfile;
+
+_PUBLIC_ int d_printf(const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ if (!outfile) outfile = stdout;
+
+ va_start(ap, format);
+ ret = d_vfprintf(outfile, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/* interactive programs need a way of tell d_*() to write to stderr instead
+ of stdout */
+void display_set_stderr(void)
+{
+ outfile = stderr;
+}
diff --git a/lib/util/fault.c b/lib/util/fault.c
new file mode 100644
index 0000000..10c3720
--- /dev/null
+++ b/lib/util/fault.c
@@ -0,0 +1,318 @@
+/*
+ Unix SMB/CIFS implementation.
+ Critical Fault handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Prouty 2009
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "version.h"
+
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
+
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
+#include "debug.h"
+#include "lib/util/signal.h" /* Avoid /usr/include/signal.h */
+#include "fault.h"
+#include "util_process.h"
+
+static struct {
+ bool disabled;
+ smb_panic_handler_t panic_handler;
+} fault_state;
+
+
+/*******************************************************************
+setup variables used for fault handling
+********************************************************************/
+void fault_configure(smb_panic_handler_t panic_handler)
+{
+ fault_state.panic_handler = panic_handler;
+}
+
+
+/**
+ disable setting up fault handlers
+ This is used for the bind9 dlz module, as we
+ don't want a Samba module in bind9 to override the bind
+ fault handling
+**/
+_PUBLIC_ void fault_setup_disable(void)
+{
+ fault_state.disabled = true;
+}
+
+
+#if !defined(HAVE_DISABLE_FAULT_HANDLING)
+/*******************************************************************
+report a fault
+********************************************************************/
+static void fault_report(int sig)
+{
+ static int counter;
+ char signal_string[128];
+
+ if (counter) _exit(1);
+
+ counter++;
+
+ snprintf(signal_string, sizeof(signal_string),
+ "Signal %d: %s", sig, strsignal(sig));
+ smb_panic(signal_string);
+
+ /* smb_panic() never returns, so this is really redundant */
+ exit(1);
+}
+
+/****************************************************************************
+catch serious errors
+****************************************************************************/
+static void sig_fault(int sig)
+{
+ fault_report(sig);
+}
+#endif
+/*******************************************************************
+setup our fault handlers
+********************************************************************/
+void fault_setup(void)
+{
+ if (fault_state.disabled) {
+ return;
+ }
+#if !defined(HAVE_DISABLE_FAULT_HANDLING)
+#ifdef SIGSEGV
+ CatchSignal(SIGSEGV, sig_fault);
+#endif
+#ifdef SIGBUS
+ CatchSignal(SIGBUS, sig_fault);
+#endif
+#ifdef SIGABRT
+ CatchSignal(SIGABRT, sig_fault);
+#endif
+#endif
+}
+
+_PUBLIC_ const char *panic_action = NULL;
+
+/*
+ default smb_panic() implementation
+*/
+static void smb_panic_default(const char *why) _NORETURN_;
+static void smb_panic_default(const char *why)
+{
+#if defined(HAVE_PRCTL) && defined(PR_SET_PTRACER)
+ /*
+ * Make sure all children can attach a debugger.
+ */
+ prctl(PR_SET_PTRACER, getpid(), 0, 0, 0);
+#endif
+
+ if (panic_action && *panic_action) {
+ char cmdstring[200];
+ if (strlcpy(cmdstring, panic_action, sizeof(cmdstring)) < sizeof(cmdstring)) {
+ int result;
+ char pidstr[20];
+ char subst[200];
+ char *p = NULL;
+ snprintf(pidstr, sizeof(pidstr), "%d", (int) getpid());
+
+ p = strstr(cmdstring, "%d");
+ if (p != NULL) {
+ snprintf(subst,
+ sizeof(subst),
+ "%.*s%s%s",
+ (int)(p-cmdstring),
+ cmdstring,
+ pidstr,
+ p+2);
+ strlcpy(cmdstring, subst, sizeof(cmdstring));
+ }
+
+ DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
+ result = system(cmdstring);
+
+ if (result == -1)
+ DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
+ strerror(errno)));
+ else
+ DEBUG(0, ("smb_panic(): action returned status %d\n",
+ WEXITSTATUS(result)));
+ }
+ }
+
+#ifdef SIGABRT
+ CatchSignal(SIGABRT, SIG_DFL);
+#endif
+ abort();
+}
+
+_PUBLIC_ void smb_panic_log(const char *why)
+{
+ const char *binary_name = process_get_saved_binary_name();
+ const char *short_title = process_get_short_title();
+ const char *long_title = process_get_long_title();
+
+ DEBUGSEP(0);
+ DEBUG(0,("INTERNAL ERROR: %s in %s (%s) (%s) pid %lld (%s)\n",
+ why,
+ binary_name,
+ short_title,
+ long_title,
+ (unsigned long long)getpid(),
+ SAMBA_VERSION_STRING));
+ DEBUG(0,("If you are running a recent Samba version, and "
+ "if you think this problem is not yet fixed in the "
+ "latest versions, please consider reporting this "
+ "bug, see "
+ "https://wiki.samba.org/index.php/Bug_Reporting\n"));
+ DEBUGSEP(0);
+ DEBUG(0,("PANIC (pid %llu): %s in " SAMBA_VERSION_STRING "\n",
+ (unsigned long long)getpid(), why));
+
+ log_stack_trace();
+}
+
+/**
+ Something really nasty happened - panic !
+
+ This function is in this file to allow sharing the last set process
+ title into the logs before the backtrace
+**/
+_PUBLIC_ void smb_panic(const char *why)
+{
+ smb_panic_log(why);
+
+ if (fault_state.panic_handler) {
+ fault_state.panic_handler(why);
+ _exit(1);
+ }
+ smb_panic_default(why);
+}
+
+/*******************************************************************
+ Print a backtrace of the stack to the debug log. This function
+ DELIBERATELY LEAKS MEMORY. The expectation is that you should
+ exit shortly after calling it.
+********************************************************************/
+
+/* Buffer size to use when printing backtraces */
+#define BACKTRACE_STACK_SIZE 64
+
+
+#ifdef HAVE_LIBUNWIND_H
+#include <libunwind.h>
+#endif
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+void log_stack_trace(void)
+{
+#ifdef HAVE_LIBUNWIND
+ /*
+ * --with-libunwind is required to use libunwind, the
+ * backtrace_symbols() code below is the default.
+ *
+ * This code is available because a previous version of this
+ * comment asserted that on ia64 libunwind correctly walks the
+ * stack in more circumstances than backtrace.
+ */
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unsigned i = 0;
+
+ char procname[256];
+ unw_word_t ip, sp, off;
+
+ procname[sizeof(procname) - 1] = '\0';
+
+ if (unw_getcontext(&uc) != 0) {
+ goto libunwind_failed;
+ }
+
+ if (unw_init_local(&cursor, &uc) != 0) {
+ goto libunwind_failed;
+ }
+
+ DEBUG(0, ("BACKTRACE:\n"));
+
+ do {
+ ip = sp = 0;
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+
+ switch (unw_get_proc_name(&cursor,
+ procname, sizeof(procname) - 1, &off) ) {
+ case 0:
+ /* Name found. */
+ case -UNW_ENOMEM:
+ /* Name truncated. */
+ DEBUGADD(0, (" #%u %s + %#llx [ip=%#llx] [sp=%#llx]\n",
+ i, procname, (long long)off,
+ (long long)ip, (long long) sp));
+ break;
+ default:
+ /* case -UNW_ENOINFO: */
+ /* case -UNW_EUNSPEC: */
+ /* No symbol name found. */
+ DEBUGADD(0, (" #%u %s [ip=%#llx] [sp=%#llx]\n",
+ i, "<unknown symbol>",
+ (long long)ip, (long long) sp));
+ }
+ ++i;
+ } while (unw_step(&cursor) > 0);
+
+ return;
+
+libunwind_failed:
+ DEBUG(0, ("unable to produce a stack trace with libunwind\n"));
+
+#elif defined(HAVE_BACKTRACE_SYMBOLS)
+ void *backtrace_stack[BACKTRACE_STACK_SIZE];
+ size_t backtrace_size;
+ char **backtrace_strings;
+
+ /* get the backtrace (stack frames) */
+ backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
+ backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
+
+ DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
+ (unsigned long)backtrace_size));
+
+ if (backtrace_strings) {
+ size_t i;
+
+ for (i = 0; i < backtrace_size; i++)
+ DEBUGADD(0, (" #%zu %s\n", i, backtrace_strings[i]));
+
+ /* Leak the backtrace_strings, rather than risk what free() might do */
+ }
+
+#else
+ DEBUG(0, ("unable to produce a stack trace on this platform\n"));
+#endif
+}
diff --git a/lib/util/fault.h b/lib/util/fault.h
new file mode 100644
index 0000000..6aceaf6
--- /dev/null
+++ b/lib/util/fault.h
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+ Critical Fault handling
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Tim Prouty 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_FAULT_H_
+#define _SAMBA_FAULT_H_
+
+#include <sys/types.h>
+
+#include "attr.h"
+
+/* Please include header file debug.h if you want to use macro SMB_ASSERT */
+
+/**
+ * assert macros
+ */
+#ifdef _SAMBA_DEBUG_H
+#define SMB_ASSERT(b) \
+do { \
+ if (unlikely(!(b))) { \
+ DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
+ __FILE__, __LINE__, #b)); \
+ smb_panic("assert failed: " #b); \
+ } \
+} while(0)
+#endif /* _SAMBA_DEBUG_H */
+
+extern const char *panic_action;
+
+/**
+ Something really nasty happened - panic !
+**/
+typedef void (*smb_panic_handler_t)(const char *why);
+
+void fault_configure(smb_panic_handler_t panic_handler);
+void fault_setup(void);
+void fault_setup_disable(void);
+_NORETURN_ void smb_panic(const char *reason);
+void smb_panic_log(const char *reason);
+
+void log_stack_trace(void);
+
+#endif /* _SAMBA_FAULT_H_ */
diff --git a/lib/util/fsusage.c b/lib/util/fsusage.c
new file mode 100644
index 0000000..d769b45
--- /dev/null
+++ b/lib/util/fsusage.c
@@ -0,0 +1,160 @@
+/*
+ Unix SMB/CIFS implementation.
+ functions to calculate the free disk space
+ Copyright (C) Andrew Tridgell 1998-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/samba_util.h"
+#include "system/filesys.h"
+
+/**
+ * @file
+ * @brief Utility functions for getting the amount of free disk space
+ */
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+*/
+static uint64_t adjust_blocks(uint64_t blocks, uint64_t fromsize, uint64_t tosize)
+{
+ if (fromsize == tosize) { /* e.g., from 512 to 512 */
+ return blocks;
+ } else if (fromsize > tosize) { /* e.g., from 2048 to 512 */
+ return blocks * (fromsize / tosize);
+ } else { /* e.g., from 256 to 512 */
+ /* Protect against broken filesystems... */
+ if (fromsize == 0) {
+ fromsize = tosize;
+ }
+ return (blocks + 1) / (tosize / fromsize);
+ }
+}
+
+/**
+ * Retrieve amount of free disk space.
+ * this does all of the system specific guff to get the free disk space.
+ * It is derived from code in the GNU fileutils package, but has been
+ * considerably mangled for use here
+ *
+ * results are returned in *dfree and *dsize, in 512 byte units
+*/
+_PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize)
+{
+#ifdef STAT_STATFS3_OSF1
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
+ return -1;
+#endif /* STAT_STATFS3_OSF1 */
+
+#ifdef STAT_STATFS2_FS_DATA /* Ultrix */
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)1024, (uint64_t)512)
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+
+ (*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot);
+ (*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen);
+#endif /* STAT_STATFS2_FS_DATA */
+
+#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512)
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+
+#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+ /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+ struct statfs are truncated to 2GB. These conditions detect that
+ truncation, presumably without botching the 4.1.1 case, in which
+ the values are not truncated. The correct counts are stored in
+ undocumented spare fields. */
+ if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) {
+ fsd.f_blocks = fsd.f_spare[0];
+ fsd.f_bfree = fsd.f_spare[1];
+ fsd.f_bavail = fsd.f_spare[2];
+ }
+#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+#endif /* STAT_STATFS2_BSIZE */
+
+
+#ifdef STAT_STATFS2_FSIZE /* 4.4BSD */
+#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512)
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#endif /* STAT_STATFS2_FSIZE */
+
+#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
+# if _AIX || defined(_CRAY)
+# define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512)
+# ifdef _CRAY
+# define f_bavail f_bfree
+# endif
+# else
+# define CONVERT_BLOCKS(B) ((uint64_t)B)
+# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */
+# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
+# define f_bavail f_bfree
+# endif
+# endif
+# endif
+
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+
+#endif /* STAT_STATFS4 */
+
+#if defined(STAT_STATVFS) /* SVR4 */
+#ifdef HAVE_FRSIZE
+# define CONVERT_BLOCKS(B) \
+ adjust_blocks ((uint64_t)(B), fsd.f_frsize ? (uint64_t)fsd.f_frsize : (uint64_t)fsd.f_bsize, (uint64_t)512)
+#else
+# define CONVERT_BLOCKS(B) \
+ adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512)
+#endif
+
+ struct statvfs fsd;
+ if (statvfs(path, &fsd) < 0) return -1;
+
+ /* f_frsize isn't guaranteed to be supported. */
+
+#endif /* STAT_STATVFS */
+
+#ifndef CONVERT_BLOCKS
+ /* we don't have any dfree code! */
+ return -1;
+#else
+#if !defined(STAT_STATFS2_FS_DATA)
+ /* !Ultrix */
+ (*dsize) = CONVERT_BLOCKS (fsd.f_blocks);
+ (*dfree) = CONVERT_BLOCKS (fsd.f_bavail);
+#endif /* not STAT_STATFS2_FS_DATA */
+#endif
+
+ return 0;
+}
diff --git a/lib/util/genrand.c b/lib/util/genrand.c
new file mode 100644
index 0000000..d0b49db
--- /dev/null
+++ b/lib/util/genrand.c
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Functions to create reasonable random numbers for crypto use.
+
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/fault.h"
+#include "lib/util/genrand.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+/*
+ * Details about the GnuTLS CSPRNG:
+ *
+ * https://nikmav.blogspot.com/2017/03/improving-by-simplifying-gnutls-prng.html
+ */
+
+
+_NORETURN_ static void genrand_panic(int err,
+ const char *location,
+ const char *func)
+{
+ char buf[200];
+ snprintf(buf, sizeof(buf),
+ "%s:%s: GnuTLS could not generate a random buffer: %s [%d]\n",
+ location, func, gnutls_strerror_name(err), err);
+ smb_panic(buf);
+}
+
+
+_PUBLIC_ void generate_random_buffer(uint8_t *out, size_t len)
+{
+ /* Random number generator for temporary keys. */
+ int ret = gnutls_rnd(GNUTLS_RND_RANDOM, out, len);
+ if (ret != 0) {
+ genrand_panic(ret, __location__, __func__);
+ }
+}
+
+_PUBLIC_ void generate_secret_buffer(uint8_t *out, size_t len)
+{
+ /*
+ * Random number generator for long term keys.
+ *
+ * The key generator, will re-seed after a fixed amount of bytes is
+ * generated (typically less than the nonce), and will also re-seed
+ * based on time, i.e., after few hours of operation without reaching
+ * the limit for a re-seed. For its re-seed it mixes data obtained
+ * from the OS random device with the previous key.
+ */
+ int ret = gnutls_rnd(GNUTLS_RND_KEY, out, len);
+ if (ret != 0) {
+ genrand_panic(ret, __location__, __func__);
+ }
+}
+
+_PUBLIC_ void generate_nonce_buffer(uint8_t *out, size_t len)
+{
+ /*
+ * Random number generator for nonce and initialization vectors.
+ *
+ * The nonce generator will reseed after outputting a fixed amount of
+ * bytes (typically few megabytes), or after few hours of operation
+ * without reaching the limit has passed.
+ */
+ int ret = gnutls_rnd(GNUTLS_RND_NONCE, out, len);
+ if (ret != 0) {
+ genrand_panic(ret, __location__, __func__);
+ }
+}
diff --git a/lib/util/genrand.h b/lib/util/genrand.h
new file mode 100644
index 0000000..76e9b98
--- /dev/null
+++ b/lib/util/genrand.h
@@ -0,0 +1,49 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Functions to create reasonable random numbers for crypto use.
+
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @brief Generate random values for session and temporary keys.
+ *
+ * @param[in] out A pointer to the buffer to fill with random data.
+ *
+ * @param[in] len The size of the buffer to fill.
+ */
+void generate_random_buffer(uint8_t *out, size_t len);
+
+/**
+ * @brief Generate random values for long term keys and passwords.
+ *
+ * @param[in] out A pointer to the buffer to fill with random data.
+ *
+ * @param[in] len The size of the buffer to fill.
+ */
+void generate_secret_buffer(uint8_t *out, size_t len);
+
+/**
+ * @brief Generate random values for a nonce buffer.
+ *
+ * This is also known as initialization vector.
+ *
+ * @param[in] out A pointer to the buffer to fill with random data.
+ *
+ * @param[in] len The size of the buffer to fill.
+ */
+void generate_nonce_buffer(uint8_t *out, size_t len);
diff --git a/lib/util/genrand_util.c b/lib/util/genrand_util.c
new file mode 100644
index 0000000..43005c5
--- /dev/null
+++ b/lib/util/genrand_util.c
@@ -0,0 +1,531 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Functions to create reasonable random numbers for crypto use.
+
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include <tevent.h>
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+
+/**
+ * @file
+ * @brief Random number generation
+ */
+
+/**
+ generate a single random uint32_t
+**/
+_PUBLIC_ uint32_t generate_random(void)
+{
+ uint8_t v[4];
+ generate_random_buffer(v, 4);
+ return IVAL(v, 0);
+}
+
+/**
+ @brief generate a random uint64
+**/
+_PUBLIC_ uint64_t generate_random_u64(void)
+{
+ uint8_t v[8];
+ generate_random_buffer(v, 8);
+ return BVAL(v, 0);
+}
+
+/**
+ * @brief Generate a random number in the given range.
+ *
+ * @param lower The lower value of the range
+
+ * @param upper The upper value of the range
+ *
+ * @return A random number bigger than than lower and smaller than upper.
+ */
+_PUBLIC_ uint64_t generate_random_u64_range(uint64_t lower, uint64_t upper)
+{
+ return generate_random_u64() % (upper - lower) + lower;
+}
+
+_PUBLIC_ uint64_t generate_unique_u64(uint64_t veto_value)
+{
+ static struct generate_unique_u64_state {
+ uint64_t next_value;
+ int pid;
+ } generate_unique_u64_state;
+
+ int pid = tevent_cached_getpid();
+
+ if (unlikely(pid != generate_unique_u64_state.pid)) {
+ generate_unique_u64_state = (struct generate_unique_u64_state) {
+ .pid = pid,
+ .next_value = veto_value,
+ };
+ }
+
+ while (unlikely(generate_unique_u64_state.next_value == veto_value)) {
+ generate_nonce_buffer(
+ (void *)&generate_unique_u64_state.next_value,
+ sizeof(generate_unique_u64_state.next_value));
+ }
+
+ return generate_unique_u64_state.next_value++;
+}
+
+/**
+ Microsoft composed the following rules (among others) for quality
+ checks. This is an abridgment from
+ http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
+
+ Passwords must contain characters from three of the following five
+ categories:
+
+ - Uppercase characters of European languages (A through Z, with
+ diacritic marks, Greek and Cyrillic characters)
+ - Lowercase characters of European languages (a through z, sharp-s,
+ with diacritic marks, Greek and Cyrillic characters)
+ - Base 10 digits (0 through 9)
+ - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
+ - Any Unicode character that is categorized as an alphabetic character
+ but is not uppercase or lowercase. This includes Unicode characters
+ from Asian languages.
+
+ Note: for now do not check if the unicode category is
+ alphabetic character
+**/
+_PUBLIC_ bool check_password_quality(const char *pwd)
+{
+ size_t ofs = 0;
+ size_t num_digits = 0;
+ size_t num_upper = 0;
+ size_t num_lower = 0;
+ size_t num_nonalpha = 0;
+ size_t num_unicode = 0;
+ size_t num_categories = 0;
+
+ if (pwd == NULL) {
+ return false;
+ }
+
+ while (true) {
+ const char *s = &pwd[ofs];
+ size_t len = 0;
+ codepoint_t c;
+
+ c = next_codepoint(s, &len);
+ if (c == INVALID_CODEPOINT) {
+ return false;
+ } else if (c == 0) {
+ break;
+ }
+ ofs += len;
+
+ if (len == 1) {
+ const char *na = "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
+
+ if (isdigit(c)) {
+ num_digits += 1;
+ continue;
+ }
+
+ if (isupper(c)) {
+ num_upper += 1;
+ continue;
+ }
+
+ if (islower(c)) {
+ num_lower += 1;
+ continue;
+ }
+
+ if (strchr(na, c)) {
+ num_nonalpha += 1;
+ continue;
+ }
+
+ /*
+ * the rest does not belong to
+ * a category.
+ */
+ continue;
+ }
+
+ if (isupper_m(c)) {
+ num_upper += 1;
+ continue;
+ }
+
+ if (islower_m(c)) {
+ num_lower += 1;
+ continue;
+ }
+
+ /*
+ * Note: for now do not check if the unicode category is
+ * alphabetic character
+ *
+ * We would have to import the details from
+ * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
+ */
+ num_unicode += 1;
+ continue;
+ }
+
+ if (num_digits > 0) {
+ num_categories += 1;
+ }
+ if (num_upper > 0) {
+ num_categories += 1;
+ }
+ if (num_lower > 0) {
+ num_categories += 1;
+ }
+ if (num_nonalpha > 0) {
+ num_categories += 1;
+ }
+ if (num_unicode > 0) {
+ num_categories += 1;
+ }
+
+ if (num_categories >= 3) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ Use the random number generator to generate a random string.
+**/
+
+_PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
+{
+ size_t i;
+ size_t list_len = strlen(list);
+
+ char *retstr = talloc_array(mem_ctx, char, len + 1);
+ if (!retstr) return NULL;
+
+ generate_secret_buffer((uint8_t *)retstr, len);
+ for (i = 0; i < len; i++) {
+ retstr[i] = list[retstr[i] % list_len];
+ }
+ retstr[i] = '\0';
+
+ return retstr;
+}
+
+/**
+ * Generate a random text string consisting of the specified length.
+ * The returned string will be allocated.
+ *
+ * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
+ */
+
+_PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
+{
+ char *retstr;
+ const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
+
+again:
+ retstr = generate_random_str_list(mem_ctx, len, c_list);
+ if (!retstr) return NULL;
+
+ /* we need to make sure the random string passes basic quality tests
+ or it might be rejected by windows as a password */
+ if (len >= 7 && !check_password_quality(retstr)) {
+ talloc_free(retstr);
+ goto again;
+ }
+
+ return retstr;
+}
+
+/**
+ * Generate a random text password (based on printable ascii characters).
+ */
+
+_PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
+{
+ char *retstr;
+ /* This list does not include { or } because they cause
+ * problems for our provision (it can create a substring
+ * ${...}, and for Fedora DS (which treats {...} at the start
+ * of a stored password as special
+ * -- Andrew Bartlett 2010-03-11
+ */
+ const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
+ size_t len = max;
+ size_t diff;
+
+ if (min > max) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ diff = max - min;
+
+ if (diff > 0 ) {
+ size_t tmp;
+
+ generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
+
+ tmp %= diff;
+
+ len = min + tmp;
+ }
+
+again:
+ retstr = generate_random_str_list(mem_ctx, len, c_list);
+ if (!retstr) return NULL;
+
+ /* we need to make sure the random string passes basic quality tests
+ or it might be rejected by windows as a password */
+ if (len >= 7 && !check_password_quality(retstr)) {
+ talloc_free(retstr);
+ goto again;
+ }
+
+ return retstr;
+}
+
+/**
+ * Generate a random machine password (based on random utf16 characters,
+ * converted to utf8). min must be at least 14, max must be at most 255.
+ *
+ * If 'unix charset' is not utf8, the password consist of random ascii
+ * values!
+ *
+ * The return value is a talloc string with destructor talloc_keep_secret() set.
+ * The content will be overwritten by zeros when the mem_ctx is destroyed.
+ */
+
+_PUBLIC_ char *generate_random_machine_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
+{
+ TALLOC_CTX *frame = NULL;
+ struct generate_random_machine_password_state {
+ uint8_t password_buffer[256 * 2];
+ uint8_t tmp;
+ } *state;
+ char *new_pw = NULL;
+ size_t len = max;
+ char *utf8_pw = NULL;
+ size_t utf8_len = 0;
+ char *unix_pw = NULL;
+ size_t unix_len = 0;
+ size_t diff;
+ size_t i;
+ bool ok;
+ int cmp;
+
+ if (max > 255) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (min < 14) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (min > max) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ frame = talloc_stackframe_pool(2048);
+ state = talloc_zero(frame, struct generate_random_machine_password_state);
+ talloc_keep_secret(state);
+
+ diff = max - min;
+
+ if (diff > 0) {
+ size_t tmp;
+
+ generate_secret_buffer((uint8_t *)&tmp, sizeof(tmp));
+
+ tmp %= diff;
+
+ len = min + tmp;
+ }
+
+ /*
+ * Create a random machine account password
+ * We create a random buffer and convert that to utf8.
+ * This is similar to what windows is doing.
+ *
+ * In future we may store the raw random buffer,
+ * but for now we need to pass the password as
+ * char pointer through some layers.
+ *
+ * As most kerberos keys are derived from the
+ * utf8 password we need to fallback to
+ * ASCII passwords if "unix charset" is not utf8.
+ */
+ generate_secret_buffer(state->password_buffer, len * 2);
+ for (i = 0; i < len; i++) {
+ size_t idx = i*2;
+ uint16_t c;
+
+ /*
+ * both MIT krb5 and HEIMDAL only
+ * handle codepoints up to 0xffff.
+ *
+ * It means we need to avoid
+ * 0xD800 - 0xDBFF (high surrogate)
+ * and
+ * 0xDC00 - 0xDFFF (low surrogate)
+ * in the random utf16 data.
+ *
+ * 55296 0xD800 0154000 0b1101100000000000
+ * 57343 0xDFFF 0157777 0b1101111111111111
+ * 8192 0x2000 020000 0b10000000000000
+ *
+ * The above values show that we can check
+ * for 0xD800 and just add 0x2000 to avoid
+ * the surrogate ranges.
+ *
+ * The rest will be handled by CH_UTF16MUNGED
+ * see utf16_munged_pull().
+ */
+ c = SVAL(state->password_buffer, idx);
+ if (c & 0xD800) {
+ c |= 0x2000;
+ }
+ SSVAL(state->password_buffer, idx, c);
+ }
+ ok = convert_string_talloc(frame,
+ CH_UTF16MUNGED, CH_UTF8,
+ state->password_buffer, len * 2,
+ (void *)&utf8_pw, &utf8_len);
+ if (!ok) {
+ DEBUG(0, ("%s: convert_string_talloc() failed\n",
+ __func__));
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ talloc_keep_secret(utf8_pw);
+
+ ok = convert_string_talloc(frame,
+ CH_UTF16MUNGED, CH_UNIX,
+ state->password_buffer, len * 2,
+ (void *)&unix_pw, &unix_len);
+ if (!ok) {
+ goto ascii_fallback;
+ }
+ talloc_keep_secret(unix_pw);
+
+ if (utf8_len != unix_len) {
+ goto ascii_fallback;
+ }
+
+ cmp = memcmp((const uint8_t *)utf8_pw,
+ (const uint8_t *)unix_pw,
+ utf8_len);
+ if (cmp != 0) {
+ goto ascii_fallback;
+ }
+
+ new_pw = talloc_strdup(mem_ctx, utf8_pw);
+ if (new_pw == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ talloc_keep_secret(new_pw);
+ talloc_set_name_const(new_pw, __func__);
+ TALLOC_FREE(frame);
+ return new_pw;
+
+ascii_fallback:
+ for (i = 0; i < len; i++) {
+ /*
+ * truncate to ascii
+ */
+ state->tmp = state->password_buffer[i] & 0x7f;
+ if (state->tmp == 0) {
+ state->tmp = state->password_buffer[i] >> 1;
+ }
+ if (state->tmp == 0) {
+ state->tmp = 0x01;
+ }
+ state->password_buffer[i] = state->tmp;
+ }
+ state->password_buffer[i] = '\0';
+
+ new_pw = talloc_strdup(mem_ctx, (const char *)state->password_buffer);
+ if (new_pw == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ talloc_keep_secret(new_pw);
+ talloc_set_name_const(new_pw, __func__);
+ TALLOC_FREE(frame);
+ return new_pw;
+}
+
+/**
+ * Generate an array of unique text strings all of the same length.
+ * The returned string will be allocated.
+ * Returns NULL if the number of unique combinations cannot be created.
+ *
+ * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
+ */
+_PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
+ uint32_t num)
+{
+ const char *c_list = "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
+ const unsigned c_size = 42;
+ size_t i, j;
+ unsigned rem;
+ char ** strs = NULL;
+
+ if (num == 0 || len == 0)
+ return NULL;
+
+ strs = talloc_array(mem_ctx, char *, num);
+ if (strs == NULL) return NULL;
+
+ for (i = 0; i < num; i++) {
+ char *retstr = (char *)talloc_size(strs, len + 1);
+ if (retstr == NULL) {
+ talloc_free(strs);
+ return NULL;
+ }
+ rem = i;
+ for (j = 0; j < len; j++) {
+ retstr[j] = c_list[rem % c_size];
+ rem = rem / c_size;
+ }
+ retstr[j] = 0;
+ strs[i] = retstr;
+ if (rem != 0) {
+ /* we were not able to fit the number of
+ * combinations asked for in the length
+ * specified */
+ DEBUG(0,(__location__ ": Too many combinations %u for length %u\n",
+ num, (unsigned)len));
+
+ talloc_free(strs);
+ return NULL;
+ }
+ }
+
+ return strs;
+}
diff --git a/lib/util/getpass.c b/lib/util/getpass.c
new file mode 100644
index 0000000..0cbc7dd
--- /dev/null
+++ b/lib/util/getpass.c
@@ -0,0 +1,230 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * getpass.c - platform independent getpass function.
+ *
+ * Copyright (c) 2010-2012 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "system/filesys.h"
+#include "system/terminal.h"
+
+#if !defined(SMB_MALLOC)
+#undef malloc
+#define SMB_MALLOC(s) malloc((s))
+#endif
+
+/**
+ * @internal
+ *
+ * @brief Get the password from the console.
+ *
+ * @param[in] prompt The prompt to display.
+ *
+ * @param[in] buf The buffer to fill.
+ *
+ * @param[in] len The length of the buffer.
+ *
+ * @param[in] verify Should the password be verified?
+ *
+ * @return 1 on success, 0 on error.
+ */
+static int samba_gets(const char *prompt, char *buf, size_t len, bool verify)
+{
+ char *tmp;
+ char *ptr = NULL;
+ int ok = 0;
+
+ tmp = SMB_MALLOC(len);
+ if (tmp == NULL) {
+ return 0;
+ }
+ memset(tmp,'\0',len);
+
+ /* read the password */
+ while (!ok) {
+ if (buf[0] != '\0') {
+ fprintf(stdout, "%s[%s] ", prompt, buf);
+ } else {
+ fprintf(stdout, "%s", prompt);
+ }
+ fflush(stdout);
+ if (fgets(tmp, len, stdin) == NULL) {
+ free(tmp);
+ return 0;
+ }
+
+ if ((ptr = strchr(tmp, '\n'))) {
+ *ptr = '\0';
+ }
+ fprintf(stdout, "\n");
+
+ if (*tmp) {
+ strncpy(buf, tmp, len);
+ }
+
+ if (verify) {
+ char *key_string;
+
+ key_string = SMB_MALLOC(len);
+ if (key_string == NULL) {
+ break;
+ }
+ memset(key_string, '\0', len);
+
+ fprintf(stdout, "\nVerifying, please re-enter. %s", prompt);
+ fflush(stdout);
+ if (! fgets(key_string, len, stdin)) {
+ memset(key_string, '\0', len);
+ SAFE_FREE(key_string);
+ clearerr(stdin);
+ continue;
+ }
+ if ((ptr = strchr(key_string, '\n'))) {
+ *ptr = '\0';
+ }
+ fprintf(stdout, "\n");
+ if (strcmp(buf, key_string)) {
+ printf("\n\07\07Mismatch - try again\n");
+ memset(key_string, '\0', len);
+ SAFE_FREE(key_string);
+ fflush(stdout);
+ continue;
+ }
+ memset(key_string, '\0', len);
+ SAFE_FREE(key_string);
+ }
+ ok = 1;
+ }
+ memset(tmp, '\0', len);
+ free(tmp);
+
+ return ok;
+}
+
+/**
+ * @brief Get a password from the console.
+ *
+ * You should make sure that the buffer is an empty string!
+ *
+ * You can also use this function to ask for a username. Then you can fill the
+ * buffer with the username and it is shows to the users. If the users just
+ * presses enter the buffer will be untouched.
+ *
+ * @code
+ * char username[128];
+ *
+ * snprintf(username, sizeof(username), "john");
+ *
+ * samba_getpass("Username:", username, sizeof(username), 1, 0);
+ * @endcode
+ *
+ * The prompt will look like this:
+ *
+ * Username: [john]
+ *
+ * If you press enter then john is used as the username, or you can type it in
+ * to change it.
+ *
+ * @param[in] prompt The prompt to show to ask for the password.
+ *
+ * @param[out] buf The buffer the password should be stored. It NEEDS to be
+ * empty or filled out.
+ *
+ * @param[in] len The length of the buffer.
+ *
+ * @param[in] echo Should we echo what you type.
+ *
+ * @param[in] verify Should we ask for the password twice.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int samba_getpass(const char *prompt,
+ char *buf,
+ size_t len,
+ bool echo,
+ bool verify)
+{
+ struct termios attr;
+ struct termios old_attr;
+ int ok = 0;
+ int fd = -1;
+
+ /* fgets needs at least len - 1 */
+ if (prompt == NULL || buf == NULL || len < 2) {
+ return -1;
+ }
+
+ if (isatty (STDIN_FILENO)) {
+
+ ZERO_STRUCT(attr);
+ ZERO_STRUCT(old_attr);
+
+ /* get local terminal attributes */
+ if (tcgetattr(STDIN_FILENO, &attr) < 0) {
+ perror("tcgetattr");
+ return -1;
+ }
+
+ /* save terminal attributes */
+ memcpy(&old_attr, &attr, sizeof(attr));
+ if((fd = fcntl(0, F_GETFL, 0)) < 0) {
+ perror("fcntl");
+ return -1;
+ }
+
+ /* disable echo */
+ if (!echo) {
+ attr.c_lflag &= ~(ECHO);
+ }
+
+ /* write attributes to terminal */
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) < 0) {
+ perror("tcsetattr");
+ return -1;
+ }
+ }
+
+ /* disable nonblocking I/O */
+ if (fd & O_NDELAY) {
+ fcntl(0, F_SETFL, fd & ~O_NDELAY);
+ }
+
+ ok = samba_gets(prompt, buf, len, verify);
+
+ if (isatty (STDIN_FILENO)) {
+
+ /* reset terminal */
+ tcsetattr(STDIN_FILENO, TCSANOW, &old_attr);
+ }
+
+ /* close fd */
+ if (fd & O_NDELAY) {
+ fcntl(0, F_SETFL, fd);
+ }
+
+ if (!ok) {
+ memset (buf, '\0', len);
+ return -1;
+ }
+
+ /* force termination */
+ buf[len - 1] = '\0';
+
+ return 0;
+}
diff --git a/lib/util/gpfswrap.c b/lib/util/gpfswrap.c
new file mode 100644
index 0000000..2f15bf4
--- /dev/null
+++ b/lib/util/gpfswrap.c
@@ -0,0 +1,296 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Wrapper for GPFS library
+ * Copyright (C) Volker Lendecke 2005
+ * Copyright (C) Christof Schmitt 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "gpfswrap.h"
+
+static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny);
+static int (*gpfs_set_lease_fn)(int fd, unsigned int type);
+static int (*gpfs_fgetacl_fn)(int fd, int flags, void *acl);
+static int (*gpfs_putacl_fn)(const char *pathname, int flags, void *acl);
+static int (*gpfs_get_realfilename_path_fn)(const char *pathname,
+ char *filenamep,
+ int *len);
+static int (*gpfs_register_cifs_export_fn)(void);
+static int (*gpfs_set_winattrs_path_fn)(const char *pathname,
+ int flags,
+ struct gpfs_winattr *attrs);
+static int (*gpfs_set_winattrs_fn)(int fd, int flags,
+ struct gpfs_winattr *attrs);
+static int (*gpfs_get_winattrs_fn)(int fd, struct gpfs_winattr *attrs);
+static int (*gpfs_ftruncate_fn)(int fd, gpfs_off64_t length);
+static int (*gpfs_lib_init_fn)(int flags);
+static int (*gpfs_set_times_fn)(int fd, int flags, gpfs_timestruc_t times[4]);
+static int (*gpfs_set_times_path_fn)(char *path,
+ int flags,
+ gpfs_timestruc_t times[4]);
+static int (*gpfs_quotactl_fn)(const char *pathname,
+ int cmd,
+ int id,
+ void *bufp);
+static int (*gpfs_init_trace_fn)(void);
+static int (*gpfs_query_trace_fn)(void);
+static void (*gpfs_add_trace_fn)(int level, const char *msg);
+static void (*gpfs_fini_trace_fn)(void);
+static int (*gpfs_fstat_x_fn)(int fd, unsigned int *litemask,
+ struct gpfs_iattr64 *iattr, size_t len);
+static int (*gpfs_stat_x_fn)(const char *pathname, unsigned int *litemask,
+ struct gpfs_iattr64 *iattr, size_t len);
+
+int gpfswrap_init(void)
+{
+ static void *l;
+
+ if (l != NULL) {
+ return 0;
+ }
+
+ l = dlopen("libgpfs.so", RTLD_LAZY);
+ if (l == NULL) {
+ return -1;
+ }
+
+ gpfs_set_share_fn = dlsym(l, "gpfs_set_share");
+ gpfs_set_lease_fn = dlsym(l, "gpfs_set_lease");
+ gpfs_fgetacl_fn = dlsym(l, "gpfs_getacl_fd");
+ gpfs_putacl_fn = dlsym(l, "gpfs_putacl");
+ gpfs_get_realfilename_path_fn = dlsym(l, "gpfs_get_realfilename_path");
+ gpfs_register_cifs_export_fn = dlsym(l, "gpfs_register_cifs_export");
+ gpfs_set_winattrs_path_fn = dlsym(l, "gpfs_set_winattrs_path");
+ gpfs_set_winattrs_fn = dlsym(l, "gpfs_set_winattrs");
+ gpfs_get_winattrs_fn = dlsym(l, "gpfs_get_winattrs");
+ gpfs_ftruncate_fn = dlsym(l, "gpfs_ftruncate");
+ gpfs_lib_init_fn = dlsym(l, "gpfs_lib_init");
+ gpfs_set_times_fn = dlsym(l, "gpfs_set_times");
+ gpfs_set_times_path_fn = dlsym(l, "gpfs_set_times_path");
+ gpfs_quotactl_fn = dlsym(l, "gpfs_quotactl");
+ gpfs_init_trace_fn = dlsym(l, "gpfs_init_trace");
+ gpfs_query_trace_fn = dlsym(l, "gpfs_query_trace");
+ gpfs_add_trace_fn = dlsym(l, "gpfs_add_trace");
+ gpfs_fini_trace_fn = dlsym(l, "gpfs_fini_trace");
+ gpfs_fstat_x_fn = dlsym(l, "gpfs_fstat_x");
+ gpfs_stat_x_fn = dlsym(l, "gpfs_stat_x");
+
+ return 0;
+}
+
+int gpfswrap_set_share(int fd, unsigned int allow, unsigned int deny)
+{
+ if (gpfs_set_share_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_set_share_fn(fd, allow, deny);
+}
+
+int gpfswrap_set_lease(int fd, unsigned int type)
+{
+ if (gpfs_set_lease_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_set_lease_fn(fd, type);
+}
+
+int gpfswrap_fgetacl(int fd, int flags, void *acl)
+{
+ if (gpfs_fgetacl_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_fgetacl_fn(fd, flags, acl);
+}
+
+int gpfswrap_putacl(const char *pathname, int flags, void *acl)
+{
+ if (gpfs_putacl_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_putacl_fn(pathname, flags, acl);
+}
+
+int gpfswrap_get_realfilename_path(const char *pathname,
+ char *filenamep,
+ int *len)
+{
+ if (gpfs_get_realfilename_path_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_get_realfilename_path_fn(pathname, filenamep, len);
+}
+
+int gpfswrap_register_cifs_export(void)
+{
+ if (gpfs_register_cifs_export_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_register_cifs_export_fn();
+}
+
+int gpfswrap_set_winattrs_path(const char *pathname,
+ int flags,
+ struct gpfs_winattr *attrs)
+{
+ if (gpfs_set_winattrs_path_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_set_winattrs_path_fn(pathname, flags, attrs);
+}
+
+int gpfswrap_set_winattrs(int fd, int flags, struct gpfs_winattr *attrs)
+{
+ if (gpfs_set_winattrs_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_set_winattrs_fn(fd, flags, attrs);
+}
+
+int gpfswrap_get_winattrs(int fd, struct gpfs_winattr *attrs)
+{
+ if (gpfs_get_winattrs_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_get_winattrs_fn(fd, attrs);
+}
+
+int gpfswrap_ftruncate(int fd, gpfs_off64_t length)
+{
+ if (gpfs_ftruncate_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_ftruncate_fn(fd, length);
+}
+
+int gpfswrap_lib_init(int flags)
+{
+ if (gpfs_lib_init_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_lib_init_fn(flags);
+}
+
+int gpfswrap_set_times(int fd, int flags, gpfs_timestruc_t times[4])
+{
+ if (gpfs_set_times_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_set_times_fn(fd, flags, times);
+}
+
+int gpfswrap_set_times_path(char *path, int flags, gpfs_timestruc_t times[4])
+{
+ if (gpfs_set_times_path_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_set_times_path_fn(path, flags, times);
+}
+
+int gpfswrap_quotactl(const char *pathname, int cmd, int id, void *bufp)
+{
+ if (gpfs_quotactl_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_quotactl_fn(pathname, cmd, id, bufp);
+}
+
+int gpfswrap_init_trace(void)
+{
+ if (gpfs_init_trace_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_init_trace_fn();
+}
+
+int gpfswrap_query_trace(void)
+{
+ if (gpfs_query_trace_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_query_trace_fn();
+}
+
+void gpfswrap_add_trace(int level, const char *msg)
+{
+ if (gpfs_add_trace_fn == NULL) {
+ return;
+ }
+
+ gpfs_add_trace_fn(level, msg);
+}
+
+void gpfswrap_fini_trace(void)
+{
+ if (gpfs_fini_trace_fn == NULL) {
+ return;
+ }
+
+ gpfs_fini_trace_fn();
+}
+
+int gpfswrap_fstat_x(int fd, unsigned int *litemask,
+ struct gpfs_iattr64 *iattr, size_t len)
+{
+ if (gpfs_fstat_x_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_fstat_x_fn(fd, litemask, iattr, len);
+}
+
+int gpfswrap_stat_x(const char *pathname, unsigned int *litemask,
+ struct gpfs_iattr64 *iattr, size_t len)
+{
+ if (gpfs_stat_x_fn == NULL) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return gpfs_stat_x_fn(pathname, litemask, iattr, len);
+}
diff --git a/lib/util/gpfswrap.h b/lib/util/gpfswrap.h
new file mode 100644
index 0000000..e387a56
--- /dev/null
+++ b/lib/util/gpfswrap.h
@@ -0,0 +1,57 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Wrapper for GPFS library
+ * Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
+ * Copyright (C) Christof Schmitt 2015
+ *
+ * Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
+ * and Gomati Mohanan <gomati.mohanan@in.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GPFSWRAP_H__
+#define __GPFSWRAP_H__
+
+#include <gpfs.h>
+
+int gpfswrap_init(void);
+int gpfswrap_set_share(int fd, unsigned int allow, unsigned int deny);
+int gpfswrap_set_lease(int fd, unsigned int type);
+int gpfswrap_fgetacl(int fd, int flags, void *acl);
+int gpfswrap_putacl(const char *pathname, int flags, void *acl);
+int gpfswrap_get_realfilename_path(const char *pathname,
+ char *filenamep,
+ int *len);
+int gpfswrap_register_cifs_export(void);
+int gpfswrap_set_winattrs_path(const char *pathname,
+ int flags,
+ struct gpfs_winattr *attrs);
+int gpfswrap_set_winattrs(int fd, int flags, struct gpfs_winattr *attrs);
+int gpfswrap_get_winattrs(int fd, struct gpfs_winattr *attrs);
+int gpfswrap_ftruncate(int fd, gpfs_off64_t length);
+int gpfswrap_lib_init(int flags);
+int gpfswrap_set_times(int fd, int flags, gpfs_timestruc_t times[4]);
+int gpfswrap_set_times_path(char *path, int flags, gpfs_timestruc_t times[4]);
+int gpfswrap_quotactl(const char *pathname, int cmd, int id, void *bufp);
+int gpfswrap_init_trace(void);
+int gpfswrap_query_trace(void);
+void gpfswrap_add_trace(int level, const char *msg);
+void gpfswrap_fini_trace(void);
+int gpfswrap_fstat_x(int fd, unsigned int *litemask,
+ struct gpfs_iattr64 *iattr, size_t len);
+int gpfswrap_stat_x(const char *pathname, unsigned int *litemask,
+ struct gpfs_iattr64 *iattr, size_t len);
+
+#endif
diff --git a/lib/util/idtree.c b/lib/util/idtree.c
new file mode 100644
index 0000000..7f08b42
--- /dev/null
+++ b/lib/util/idtree.c
@@ -0,0 +1,395 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ very efficient functions to manage mapping a id (such as a fnum) to
+ a pointer. This is used for fnum and search id allocation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
+ written by Jim Houston jim.houston@ccur.com, and is
+ Copyright (C) 2002 by Concurrent Computer Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ see the section marked "public interface" below for documentation
+*/
+
+/**
+ * @file
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "debug.h"
+#include "idtree.h"
+
+#define IDR_BITS 5
+#define IDR_FULL 0xfffffffful
+#if 0 /* unused */
+#define TOP_LEVEL_FULL (IDR_FULL >> 30)
+#endif
+#define IDR_SIZE (1 << IDR_BITS)
+#define IDR_MASK ((1 << IDR_BITS)-1)
+#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
+#define MAX_ID_MASK (MAX_ID_BIT - 1)
+#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
+#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
+
+#define set_bit(bit, v) (v) |= (1U<<(bit))
+#define clear_bit(bit, v) (v) &= ~(1U<<(bit))
+#define test_bit(bit, v) ((v) & (1U<<(bit)))
+
+struct idr_layer {
+ uint32_t bitmap;
+ struct idr_layer *ary[IDR_SIZE];
+ int count;
+};
+
+struct idr_context {
+ struct idr_layer *top;
+ struct idr_layer *id_free;
+ int layers;
+ int id_free_cnt;
+};
+
+static struct idr_layer *alloc_layer(struct idr_context *idp)
+{
+ struct idr_layer *p;
+
+ if (!(p = idp->id_free))
+ return NULL;
+ idp->id_free = p->ary[0];
+ idp->id_free_cnt--;
+ p->ary[0] = NULL;
+ return p;
+}
+
+static int find_next_bit(uint32_t bm, int maxid, int n)
+{
+ while (n<maxid && !test_bit(n, bm)) n++;
+ return n;
+}
+
+static void free_layer(struct idr_context *idp, struct idr_layer *p)
+{
+ p->ary[0] = idp->id_free;
+ idp->id_free = p;
+ idp->id_free_cnt++;
+}
+
+static int idr_pre_get(struct idr_context *idp)
+{
+ while (idp->id_free_cnt < IDR_FREE_MAX) {
+ struct idr_layer *pn = talloc_zero(idp, struct idr_layer);
+ if(pn == NULL)
+ return (0);
+ free_layer(idp, pn);
+ }
+ return 1;
+}
+
+static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
+{
+ int n, m, sh;
+ struct idr_layer *p, *pn;
+ struct idr_layer *pa[MAX_LEVEL+1];
+ unsigned int l, id, oid;
+ uint32_t bm;
+
+ memset(pa, 0, sizeof(pa));
+
+ id = *starting_id;
+restart:
+ p = idp->top;
+ l = idp->layers;
+ pa[l--] = NULL;
+ while (1) {
+ /*
+ * We run around this while until we reach the leaf node...
+ */
+ n = (id >> (IDR_BITS*l)) & IDR_MASK;
+ bm = ~p->bitmap;
+ m = find_next_bit(bm, IDR_SIZE, n);
+ if (m == IDR_SIZE) {
+ /* no space available go back to previous layer. */
+ l++;
+ oid = id;
+ id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
+
+ /* if already at the top layer, we need to grow */
+ if (!(p = pa[l])) {
+ *starting_id = id;
+ return -2;
+ }
+
+ /* If we need to go up one layer, continue the
+ * loop; otherwise, restart from the top.
+ */
+ sh = IDR_BITS * (l + 1);
+ if (oid >> sh == id >> sh)
+ continue;
+ else
+ goto restart;
+ }
+ if (m != n) {
+ sh = IDR_BITS*l;
+ id = ((id >> sh) ^ n ^ m) << sh;
+ }
+ if (id >= MAX_ID_BIT)
+ return -1;
+ if (l == 0)
+ break;
+ /*
+ * Create the layer below if it is missing.
+ */
+ if (!p->ary[m]) {
+ if (!(pn = alloc_layer(idp)))
+ return -1;
+ p->ary[m] = pn;
+ p->count++;
+ }
+ pa[l--] = p;
+ p = p->ary[m];
+ }
+ /*
+ * We have reached the leaf node, plant the
+ * users pointer and return the raw id.
+ */
+ p->ary[m] = (struct idr_layer *)ptr;
+ set_bit(m, p->bitmap);
+ p->count++;
+ /*
+ * If this layer is full mark the bit in the layer above
+ * to show that this part of the radix tree is full.
+ * This may complete the layer above and require walking
+ * up the radix tree.
+ */
+ n = id;
+ while (p->bitmap == IDR_FULL) {
+ if (l >= MAX_LEVEL) {
+ break;
+ }
+ p = pa[++l];
+ if (p == NULL) {
+ break;
+ }
+ n = n >> IDR_BITS;
+ set_bit((n & IDR_MASK), p->bitmap);
+ }
+ return(id);
+}
+
+static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id)
+{
+ struct idr_layer *p, *pn;
+ int layers, v, id;
+
+ idr_pre_get(idp);
+
+ id = starting_id;
+build_up:
+ p = idp->top;
+ layers = idp->layers;
+ if (!p) {
+ if (!(p = alloc_layer(idp)))
+ return -1;
+ layers = 1;
+ }
+ /*
+ * Add a new layer to the top of the tree if the requested
+ * id is larger than the currently allocated space.
+ */
+ while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
+ layers++;
+ if (!p->count)
+ continue;
+ if (!(pn = alloc_layer(idp))) {
+ /*
+ * The allocation failed. If we built part of
+ * the structure tear it down.
+ */
+ for (pn = p; p && p != idp->top; pn = p) {
+ p = p->ary[0];
+ pn->ary[0] = NULL;
+ pn->bitmap = pn->count = 0;
+ free_layer(idp, pn);
+ }
+ return -1;
+ }
+ pn->ary[0] = p;
+ pn->count = 1;
+ if (p->bitmap == IDR_FULL)
+ set_bit(0, pn->bitmap);
+ p = pn;
+ }
+ idp->top = p;
+ idp->layers = layers;
+ v = sub_alloc(idp, ptr, &id);
+ if (v == -2)
+ goto build_up;
+ return(v);
+}
+
+static int sub_remove(struct idr_context *idp, int shift, int id)
+{
+ struct idr_layer *p = idp->top;
+ struct idr_layer **pa[1+MAX_LEVEL];
+ struct idr_layer ***paa = &pa[0];
+ int n;
+
+ *paa = NULL;
+ *++paa = &idp->top;
+
+ while ((shift > 0) && p) {
+ n = (id >> shift) & IDR_MASK;
+ clear_bit(n, p->bitmap);
+ *++paa = &p->ary[n];
+ p = p->ary[n];
+ shift -= IDR_BITS;
+ }
+ n = id & IDR_MASK;
+ if (p != NULL && test_bit(n, p->bitmap)) {
+ clear_bit(n, p->bitmap);
+ p->ary[n] = NULL;
+ while(*paa && ! --((**paa)->count)){
+ free_layer(idp, **paa);
+ **paa-- = NULL;
+ }
+ if ( ! *paa )
+ idp->layers = 0;
+ return 0;
+ }
+ return -1;
+}
+
+static void *_idr_find(struct idr_context *idp, int id)
+{
+ int n;
+ struct idr_layer *p;
+
+ n = idp->layers * IDR_BITS;
+ p = idp->top;
+ /*
+ * This tests to see if bits outside the current tree are
+ * present. If so, tain't one of ours!
+ */
+ if (n + IDR_BITS < 31 &&
+ ((id & ~(~0U << MAX_ID_SHIFT)) >> (n + IDR_BITS))) {
+ return NULL;
+ }
+
+ /* Mask off upper bits we don't use for the search. */
+ id &= MAX_ID_MASK;
+
+ while (n >= IDR_BITS && p) {
+ n -= IDR_BITS;
+ p = p->ary[(id >> n) & IDR_MASK];
+ }
+ return((void *)p);
+}
+
+static int _idr_remove(struct idr_context *idp, int id)
+{
+ struct idr_layer *p;
+
+ /* Mask off upper bits we don't use for the search. */
+ id &= MAX_ID_MASK;
+
+ if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) {
+ return -1;
+ }
+
+ if ( idp->top && idp->top->count == 1 &&
+ (idp->layers > 1) &&
+ idp->top->ary[0]) {
+ /* We can drop a layer */
+ p = idp->top->ary[0];
+ idp->top->bitmap = idp->top->count = 0;
+ free_layer(idp, idp->top);
+ idp->top = p;
+ --idp->layers;
+ }
+ while (idp->id_free_cnt >= IDR_FREE_MAX) {
+ p = alloc_layer(idp);
+ talloc_free(p);
+ }
+ return 0;
+}
+
+/************************************************************************
+ this is the public interface
+**************************************************************************/
+
+/**
+ initialise a idr tree. The context return value must be passed to
+ all subsequent idr calls. To destroy the idr tree use talloc_free()
+ on this context
+ */
+_PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, struct idr_context);
+}
+
+/**
+ allocate the next available id, and assign 'ptr' into its slot.
+ you can retrieve later this pointer using idr_find()
+*/
+_PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit)
+{
+ int ret = idr_get_new_above_int(idp, ptr, 0);
+ if (ret > limit) {
+ idr_remove(idp, ret);
+ return -1;
+ }
+ return ret;
+}
+
+/**
+ allocate a new id, giving the first available value greater than or
+ equal to the given starting id
+*/
+_PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit)
+{
+ int ret = idr_get_new_above_int(idp, ptr, starting_id);
+ if (ret > limit) {
+ idr_remove(idp, ret);
+ return -1;
+ }
+ return ret;
+}
+
+/**
+ find a pointer value previously set with idr_get_new given an id
+*/
+_PUBLIC_ void *idr_find(struct idr_context *idp, int id)
+{
+ return _idr_find(idp, id);
+}
+
+/**
+ remove an id from the idr tree
+*/
+_PUBLIC_ int idr_remove(struct idr_context *idp, int id)
+{
+ int ret;
+ ret = _idr_remove((struct idr_context *)idp, id);
+ if (ret != 0) {
+ DEBUG(0,("WARNING: attempt to remove unset id %d in idtree\n", id));
+ }
+ return ret;
+}
diff --git a/lib/util/idtree.h b/lib/util/idtree.h
new file mode 100644
index 0000000..79d2d8c
--- /dev/null
+++ b/lib/util/idtree.h
@@ -0,0 +1,63 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ very efficient functions to manage mapping a id (such as a fnum) to
+ a pointer. This is used for fnum and search id allocation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
+ written by Jim Houston jim.houston@ccur.com, and is
+ Copyright (C) 2002 by Concurrent Computer Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_IDTREE_H_
+#define _SAMBA_IDTREE_H_
+
+#include <talloc.h>
+
+struct idr_context;
+
+/**
+ initialise a idr tree. The context return value must be passed to
+ all subsequent idr calls. To destroy the idr tree use talloc_free()
+ on this context
+ */
+struct idr_context *idr_init(TALLOC_CTX *mem_ctx);
+
+/**
+ allocate the next available id, and assign 'ptr' into its slot.
+ you can retrieve later this pointer using idr_find()
+*/
+int idr_get_new(struct idr_context *idp, void *ptr, int limit);
+
+/**
+ allocate a new id, giving the first available value greater than or
+ equal to the given starting id
+*/
+int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit);
+
+/**
+ find a pointer value previously set with idr_get_new given an id
+*/
+void *idr_find(struct idr_context *idp, int id);
+
+/**
+ remove an id from the idr tree
+*/
+int idr_remove(struct idr_context *idp, int id);
+
+#endif /* _SAMBA_IDTREE_H_ */
diff --git a/lib/util/idtree_random.c b/lib/util/idtree_random.c
new file mode 100644
index 0000000..d22245a
--- /dev/null
+++ b/lib/util/idtree_random.c
@@ -0,0 +1,68 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ very efficient functions to manage mapping a id (such as a fnum) to
+ a pointer. This is used for fnum and search id allocation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
+ written by Jim Houston jim.houston@ccur.com, and is
+ Copyright (C) 2002 by Concurrent Computer Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ see the section marked "public interface" below for documentation
+*/
+
+/**
+ * @file
+ */
+
+#include "replace.h"
+#include "samba_util.h" /* generate_random() */
+#include "idtree.h"
+#include "idtree_random.h"
+
+/**
+ allocate a new id randomly in the given range
+*/
+_PUBLIC_ int idr_get_new_random(struct idr_context *idp,
+ void *ptr,
+ int starting_id,
+ int limit)
+{
+ int id;
+
+ /* first try a random starting point in the whole range, and if that fails,
+ then start randomly in the bottom half of the range. This can only
+ fail if the range is over half full, and finally fallback to any
+ free id */
+ id = idr_get_new_above(
+ idp, ptr, starting_id+(generate_random() % limit), limit);
+ if (id == -1) {
+ id = idr_get_new_above(
+ idp,
+ ptr,
+ starting_id+(generate_random()%(limit/2)),
+ limit);
+ }
+ if (id == -1) {
+ id = idr_get_new_above(idp, ptr, starting_id, limit);
+ }
+
+ return id;
+}
diff --git a/lib/util/idtree_random.h b/lib/util/idtree_random.h
new file mode 100644
index 0000000..623147c
--- /dev/null
+++ b/lib/util/idtree_random.h
@@ -0,0 +1,41 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ very efficient functions to manage mapping a id (such as a fnum) to
+ a pointer. This is used for fnum and search id allocation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
+ written by Jim Houston jim.houston@ccur.com, and is
+ Copyright (C) 2002 by Concurrent Computer Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_IDTREE_RANDOM_H_
+#define _SAMBA_IDTREE_RANDOM_H_
+
+#include <talloc.h>
+#include "idtree.h"
+
+/**
+ allocate a new id randomly in the given range
+*/
+int idr_get_new_random(struct idr_context *idp,
+ void *ptr,
+ int starting_id,
+ int limit);
+
+#endif /* _SAMBA_IDTREE_RANDOM_H_ */
diff --git a/lib/util/iov_buf.c b/lib/util/iov_buf.c
new file mode 100644
index 0000000..0c18466
--- /dev/null
+++ b/lib/util/iov_buf.c
@@ -0,0 +1,43 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "iov_buf.h"
+#include <talloc.h>
+
+uint8_t *iov_concat(TALLOC_CTX *mem_ctx, const struct iovec *iov, int count)
+{
+ ssize_t buflen;
+ uint8_t *buf;
+
+ buflen = iov_buflen(iov, count);
+ if (buflen == -1) {
+ return NULL;
+ }
+
+ buf = talloc_array(mem_ctx, uint8_t, buflen);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ iov_buf(iov, count, buf, buflen);
+
+ return buf;
+}
diff --git a/lib/util/iov_buf.h b/lib/util/iov_buf.h
new file mode 100644
index 0000000..cb330de
--- /dev/null
+++ b/lib/util/iov_buf.h
@@ -0,0 +1,102 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_IOV_BUF_H__
+#define __LIB_IOV_BUF_H__
+
+#include "replace.h"
+#include <talloc.h>
+#include "system/filesys.h"
+
+static inline
+ssize_t iov_buf(const struct iovec *iov, int iovcnt,
+ uint8_t *buf, size_t buflen)
+{
+ size_t needed = 0;
+ uint8_t *p = buf;
+ int i;
+
+ for (i=0; i<iovcnt; i++) {
+ size_t thislen = iov[i].iov_len;
+ size_t tmp;
+
+ tmp = needed + thislen;
+
+ if (tmp < needed) {
+ /* wrap */
+ return -1;
+ }
+ needed = tmp;
+
+ if ((p != NULL) && needed <= buflen && thislen > 0) {
+ memcpy(p, iov[i].iov_base, thislen);
+ p += thislen;
+ }
+ }
+
+ return needed;
+}
+
+static inline
+ssize_t iov_buflen(const struct iovec *iov, int iovcnt)
+{
+ return iov_buf(iov, iovcnt, NULL, 0);
+}
+
+static inline
+bool iov_advance(struct iovec **iov, int *iovcnt, size_t n)
+{
+ struct iovec *v = *iov;
+ int cnt = *iovcnt;
+
+ while (n > 0) {
+ if (cnt == 0) {
+ return false;
+ }
+ if (n < v->iov_len) {
+ v->iov_base = (char *)v->iov_base + n;
+ v->iov_len -= n;
+ break;
+ }
+ n -= v->iov_len;
+ v += 1;
+ cnt -= 1;
+ }
+
+ /*
+ * Skip 0-length iovec's
+ *
+ * There might be empty buffers at the end of iov. Next time we do a
+ * readv/writev based on this iov would give 0 transferred bytes, also
+ * known as EPIPE. So we need to be careful discarding them.
+ */
+
+ while ((cnt > 0) && (v->iov_len == 0)) {
+ v += 1;
+ cnt -= 1;
+ }
+
+ *iov = v;
+ *iovcnt = cnt;
+ return true;
+}
+
+uint8_t *iov_concat(TALLOC_CTX *mem_ctx, const struct iovec *iov, int count);
+
+#endif
diff --git a/lib/util/mainpage.dox b/lib/util/mainpage.dox
new file mode 100644
index 0000000..464151e
--- /dev/null
+++ b/lib/util/mainpage.dox
@@ -0,0 +1,11 @@
+/**
+
+\mainpage util
+
+\section Introduction
+
+This library contains convenience functions that are used heavily
+throughout Samba. None of these functions are SMB or Samba-specific.
+It's a bit to Samba what GLib is to the GNOME folks.
+
+*/
diff --git a/lib/util/memcache.c b/lib/util/memcache.c
new file mode 100644
index 0000000..98e317c
--- /dev/null
+++ b/lib/util/memcache.c
@@ -0,0 +1,467 @@
+/*
+ Unix SMB/CIFS implementation.
+ In-memory cache
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include "../lib/util/debug.h"
+#include "../lib/util/samba_util.h"
+#include "../lib/util/dlinklist.h"
+#include "../lib/util/rbtree.h"
+#include "memcache.h"
+
+static struct memcache *global_cache;
+
+struct memcache_talloc_value {
+ void *ptr;
+ size_t len;
+};
+
+struct memcache_element {
+ struct rb_node rb_node;
+ struct memcache_element *prev, *next;
+ size_t keylength, valuelength;
+ uint8_t n; /* This is really an enum, but save memory */
+ char data[1]; /* placeholder for offsetof */
+};
+
+struct memcache {
+ struct memcache_element *mru;
+ struct rb_root tree;
+ size_t size;
+ size_t max_size;
+};
+
+static void memcache_element_parse(struct memcache_element *e,
+ DATA_BLOB *key, DATA_BLOB *value);
+
+static bool memcache_is_talloc(enum memcache_number n)
+{
+ bool result;
+
+ switch (n) {
+ case GETPWNAM_CACHE:
+ case PDB_GETPWSID_CACHE:
+ case SINGLETON_CACHE_TALLOC:
+ case SHARE_MODE_LOCK_CACHE:
+ case GETWD_CACHE:
+ case VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC:
+ result = true;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static int memcache_destructor(struct memcache *cache) {
+ struct memcache_element *e, *next;
+
+ for (e = cache->mru; e != NULL; e = next) {
+ next = e->next;
+ TALLOC_FREE(e);
+ }
+ return 0;
+}
+
+struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size)
+{
+ struct memcache *result;
+
+ result = talloc_zero(mem_ctx, struct memcache);
+ if (result == NULL) {
+ return NULL;
+ }
+ result->max_size = max_size;
+ talloc_set_destructor(result, memcache_destructor);
+ return result;
+}
+
+void memcache_set_global(struct memcache *cache)
+{
+ TALLOC_FREE(global_cache);
+ global_cache = cache;
+}
+
+static struct memcache_element *memcache_node2elem(struct rb_node *node)
+{
+ return (struct memcache_element *)
+ ((char *)node - offsetof(struct memcache_element, rb_node));
+}
+
+static void memcache_element_parse(struct memcache_element *e,
+ DATA_BLOB *key, DATA_BLOB *value)
+{
+ key->data = ((uint8_t *)e) + offsetof(struct memcache_element, data);
+ key->length = e->keylength;
+ value->data = key->data + e->keylength;
+ value->length = e->valuelength;
+}
+
+static size_t memcache_element_size(size_t key_length, size_t value_length)
+{
+ return sizeof(struct memcache_element) - 1 + key_length + value_length;
+}
+
+static int memcache_compare(struct memcache_element *e, enum memcache_number n,
+ DATA_BLOB key)
+{
+ DATA_BLOB this_key, this_value;
+
+ if ((int)e->n < (int)n) return 1;
+ if ((int)e->n > (int)n) return -1;
+
+ if (e->keylength < key.length) return 1;
+ if (e->keylength > key.length) return -1;
+
+ memcache_element_parse(e, &this_key, &this_value);
+ return memcmp(this_key.data, key.data, key.length);
+}
+
+static struct memcache_element *memcache_find(
+ struct memcache *cache, enum memcache_number n, DATA_BLOB key)
+{
+ struct rb_node *node;
+
+ node = cache->tree.rb_node;
+
+ while (node != NULL) {
+ struct memcache_element *elem = memcache_node2elem(node);
+ int cmp;
+
+ cmp = memcache_compare(elem, n, key);
+ if (cmp == 0) {
+ return elem;
+ }
+ node = (cmp < 0) ? node->rb_left : node->rb_right;
+ }
+
+ return NULL;
+}
+
+bool memcache_lookup(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB *value)
+{
+ struct memcache_element *e;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return false;
+ }
+
+ e = memcache_find(cache, n, key);
+ if (e == NULL) {
+ return false;
+ }
+
+ if (cache->size != 0) {
+ DLIST_PROMOTE(cache->mru, e);
+ }
+
+ memcache_element_parse(e, &key, value);
+ return true;
+}
+
+void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key)
+{
+ DATA_BLOB value;
+ struct memcache_talloc_value mtv;
+
+ if (!memcache_lookup(cache, n, key, &value)) {
+ return NULL;
+ }
+
+ if (value.length != sizeof(mtv)) {
+ return NULL;
+ }
+
+ memcpy(&mtv, value.data, sizeof(mtv));
+
+ return mtv.ptr;
+}
+
+static void memcache_delete_element(struct memcache *cache,
+ struct memcache_element *e)
+{
+ rb_erase(&e->rb_node, &cache->tree);
+
+ DLIST_REMOVE(cache->mru, e);
+
+ if (memcache_is_talloc(e->n)) {
+ DATA_BLOB cache_key, cache_value;
+ struct memcache_talloc_value mtv;
+
+ memcache_element_parse(e, &cache_key, &cache_value);
+ SMB_ASSERT(cache_value.length == sizeof(mtv));
+ memcpy(&mtv, cache_value.data, sizeof(mtv));
+ cache->size -= mtv.len;
+ TALLOC_FREE(mtv.ptr);
+ }
+
+ cache->size -= memcache_element_size(e->keylength, e->valuelength);
+
+ TALLOC_FREE(e);
+}
+
+static void memcache_trim(struct memcache *cache, struct memcache_element *e)
+{
+ struct memcache_element *tail = NULL;
+
+ if (cache->max_size == 0) {
+ return;
+ }
+
+ for (tail = DLIST_TAIL(cache->mru);
+ (cache->size > cache->max_size) && (tail != NULL);
+ tail = DLIST_TAIL(cache->mru))
+ {
+ if (tail == e) {
+ tail = DLIST_PREV(tail);
+ if (tail == NULL) {
+ break;
+ }
+ }
+ memcache_delete_element(cache, tail);
+ }
+}
+
+void memcache_delete(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key)
+{
+ struct memcache_element *e;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return;
+ }
+
+ e = memcache_find(cache, n, key);
+ if (e == NULL) {
+ return;
+ }
+
+ memcache_delete_element(cache, e);
+}
+
+bool memcache_add(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB value)
+{
+ struct memcache_element *e;
+ struct rb_node **p;
+ struct rb_node *parent;
+ DATA_BLOB cache_key, cache_value;
+ size_t element_size;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return false;
+ }
+
+ if (key.length == 0) {
+ return false;
+ }
+
+ e = memcache_find(cache, n, key);
+
+ if (e != NULL) {
+ memcache_element_parse(e, &cache_key, &cache_value);
+
+ if (value.length <= cache_value.length) {
+ if (memcache_is_talloc(e->n)) {
+ struct memcache_talloc_value mtv;
+
+ SMB_ASSERT(cache_value.length == sizeof(mtv));
+ memcpy(&mtv, cache_value.data, sizeof(mtv));
+ cache->size -= mtv.len;
+ TALLOC_FREE(mtv.ptr);
+ }
+ /*
+ * We can reuse the existing record
+ */
+ memcpy(cache_value.data, value.data, value.length);
+ e->valuelength = value.length;
+
+ if (memcache_is_talloc(e->n)) {
+ struct memcache_talloc_value mtv;
+
+ SMB_ASSERT(cache_value.length == sizeof(mtv));
+ memcpy(&mtv, cache_value.data, sizeof(mtv));
+ cache->size += mtv.len;
+ }
+ return true;
+ }
+
+ memcache_delete_element(cache, e);
+ }
+
+ element_size = memcache_element_size(key.length, value.length);
+
+ e = talloc_size(cache, element_size);
+ if (e == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return false;
+ }
+ talloc_set_type(e, struct memcache_element);
+
+ e->n = n;
+ e->keylength = key.length;
+ e->valuelength = value.length;
+
+ memcache_element_parse(e, &cache_key, &cache_value);
+ memcpy(cache_key.data, key.data, key.length);
+ memcpy(cache_value.data, value.data, value.length);
+
+ parent = NULL;
+ p = &cache->tree.rb_node;
+
+ while (*p) {
+ struct memcache_element *elem = memcache_node2elem(*p);
+ int cmp;
+
+ parent = (*p);
+
+ cmp = memcache_compare(elem, n, key);
+
+ p = (cmp < 0) ? &(*p)->rb_left : &(*p)->rb_right;
+ }
+
+ rb_link_node(&e->rb_node, parent, p);
+ rb_insert_color(&e->rb_node, &cache->tree);
+
+ DLIST_ADD(cache->mru, e);
+
+ cache->size += element_size;
+ if (memcache_is_talloc(e->n)) {
+ struct memcache_talloc_value mtv;
+
+ SMB_ASSERT(cache_value.length == sizeof(mtv));
+ memcpy(&mtv, cache_value.data, sizeof(mtv));
+ cache->size += mtv.len;
+ }
+ memcache_trim(cache, e);
+
+ return true;
+}
+
+bool memcache_add_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, void *pptr)
+{
+ struct memcache_talloc_value mtv;
+ void **ptr = (void **)pptr;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return false;
+ }
+
+ mtv.len = talloc_total_size(*ptr);
+ mtv.ptr = talloc_move(cache, ptr);
+
+ return memcache_add(cache, n, key, data_blob_const(&mtv, sizeof(mtv)));
+}
+
+void memcache_flush(struct memcache *cache, enum memcache_number n)
+{
+ struct rb_node *node;
+
+ if (cache == NULL) {
+ cache = global_cache;
+ }
+ if (cache == NULL) {
+ return;
+ }
+
+ /*
+ * Find the smallest element of number n
+ */
+
+ node = cache->tree.rb_node;
+ if (node == NULL) {
+ return;
+ }
+
+ /*
+ * First, find *any* element of number n
+ */
+
+ while (true) {
+ struct memcache_element *elem = memcache_node2elem(node);
+ struct rb_node *next;
+
+ if ((int)elem->n == (int)n) {
+ break;
+ }
+
+ if ((int)elem->n < (int)n) {
+ next = node->rb_right;
+ }
+ else {
+ next = node->rb_left;
+ }
+ if (next == NULL) {
+ break;
+ }
+ node = next;
+ }
+
+ /*
+ * Then, find the leftmost element with number n
+ */
+
+ while (true) {
+ struct rb_node *prev = rb_prev(node);
+ struct memcache_element *elem;
+
+ if (prev == NULL) {
+ break;
+ }
+ elem = memcache_node2elem(prev);
+ if ((int)elem->n != (int)n) {
+ break;
+ }
+ node = prev;
+ }
+
+ while (node != NULL) {
+ struct memcache_element *e = memcache_node2elem(node);
+ struct rb_node *next = rb_next(node);
+
+ if (e->n != n) {
+ break;
+ }
+
+ memcache_delete_element(cache, e);
+ node = next;
+ }
+}
+
+void gfree_memcache(void)
+{
+ TALLOC_FREE(global_cache);
+}
diff --git a/lib/util/memcache.h b/lib/util/memcache.h
new file mode 100644
index 0000000..6986760
--- /dev/null
+++ b/lib/util/memcache.h
@@ -0,0 +1,119 @@
+/*
+ Unix SMB/CIFS implementation.
+ In-memory cache
+ Copyright (C) Volker Lendecke 2007-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __MEMCACHE_H__
+#define __MEMCACHE_H__
+
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+
+struct memcache;
+
+/*
+ * A memcache can store different subkeys with overlapping keys, the
+ * memcache_number becomes part of the key. Feel free to add caches of your
+ * own here.
+ *
+ * If you add talloc type caches, also note this in the switch statement in
+ * memcache_is_talloc().
+ */
+
+enum memcache_number {
+ STAT_CACHE,
+ GETREALFILENAME_CACHE,
+ GETWD_CACHE,
+ GETPWNAM_CACHE, /* talloc */
+ MANGLE_HASH2_CACHE,
+ PDB_GETPWSID_CACHE, /* talloc */
+ SINGLETON_CACHE_TALLOC, /* talloc */
+ SINGLETON_CACHE,
+ SMB1_SEARCH_OFFSET_MAP,
+ SHARE_MODE_LOCK_CACHE, /* talloc */
+ VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC, /* talloc */
+ DFREE_CACHE,
+};
+
+/*
+ * Create a memcache structure. max_size is in bytes, if you set it 0 it will
+ * not forget anything.
+ */
+
+struct memcache *memcache_init(TALLOC_CTX *mem_ctx, size_t max_size);
+
+/*
+ * If you set this global memcache, use it as the default cache when NULL is
+ * passed to the memcache functions below. This is a workaround for many
+ * situations where passing the cache everywhere would be a big hassle.
+ */
+
+void memcache_set_global(struct memcache *cache);
+
+/*
+ * Add a data blob to the cache
+ */
+
+bool memcache_add(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB value);
+
+/*
+ * Add a talloc object to the cache. The difference to memcache_add() is that
+ * when the objects is to be discarded, talloc_free is called for it. Also
+ * talloc_move() ownership of the object to the cache.
+ *
+ * Please note that the current implementation has a fixed relationship
+ * between what cache subtypes store talloc objects and which ones store plain
+ * blobs. We can fix this, but for now we don't have a mixed use of blobs vs
+ * talloc objects in the cache types.
+ */
+
+bool memcache_add_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, void *ptr);
+
+/*
+ * Delete an object from the cache
+ */
+
+void memcache_delete(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key);
+
+/*
+ * Look up an object from the cache. Memory still belongs to the cache, so
+ * make a copy of it if needed.
+ */
+
+bool memcache_lookup(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key, DATA_BLOB *value);
+
+/*
+ * Look up an object from the cache. Memory still belongs to the cache, so
+ * make a copy of it if needed.
+ */
+
+void *memcache_lookup_talloc(struct memcache *cache, enum memcache_number n,
+ DATA_BLOB key);
+
+/*
+ * Flush a complete cache subset.
+ */
+
+void memcache_flush(struct memcache *cache, enum memcache_number n);
+
+void gfree_memcache(void);
+
+#endif
diff --git a/lib/util/memory.h b/lib/util/memory.h
new file mode 100644
index 0000000..40c66d8
--- /dev/null
+++ b/lib/util/memory.h
@@ -0,0 +1,129 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_MEMORY_H_
+#define _SAMBA_MEMORY_H_
+
+#ifndef SAFE_FREE /* Oh no this is also defined in tdb.h */
+/**
+ * Free memory if the pointer and zero the pointer.
+ *
+ * @note You are explicitly allowed to pass NULL pointers -- they will
+ * always be ignored.
+ **/
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
+/**
+ * Zero string and free memory if the pointer and zero the pointer.
+ *
+ * @note You are explicitly allowed to pass NULL pointers -- they will
+ * always be ignored.
+ **/
+#define BURN_FREE_STR(x) do { \
+ if ((x) != NULL) { \
+ size_t s = strlen(x); \
+ memset_s((x), s, 0, s); \
+ free(x); (x) = NULL; \
+ } \
+ } while(0)
+
+/**
+ * Zero and free memory if the pointer and zero the pointer.
+ *
+ * @note You are explicitly allowed to pass NULL pointers -- they will
+ * always be ignored.
+ **/
+#define BURN_FREE(x, s) do { \
+ if ((x) != NULL) { \
+ memset_s((x), (s), 0, (s)); \
+ free(x); (x) = NULL; \
+ } \
+ } while(0)
+
+/**
+ * Type-safe version of malloc. Allocated one copy of the
+ * specified data type.
+ */
+#define malloc_p(type) (type *)malloc(sizeof(type))
+
+/**
+ * Allocate an array of elements of one data type. Does type-checking.
+ */
+#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count, false)
+
+/**
+ * Resize an array of elements of one data type. Does type-checking.
+ */
+#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count, false)
+
+/**
+ * Zero a structure.
+ */
+#ifndef ZERO_STRUCT
+#define ZERO_STRUCT(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x))
+#endif
+
+/**
+ * Zero a structure given a pointer to the structure.
+ */
+#ifndef ZERO_STRUCTP
+#define ZERO_STRUCTP(x) do { \
+ if ((x) != NULL) { \
+ memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x))); \
+ } \
+} while(0)
+#endif
+
+/**
+ * Zero a structure given a pointer to the structure - no zero check.
+ */
+#ifndef ZERO_STRUCTPN
+#define ZERO_STRUCTPN(x) memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x)))
+#endif
+
+/**
+ * Zero an array - note that sizeof(array) must work - ie. it must not be a
+ * pointer.
+ */
+#ifndef ZERO_ARRAY
+#define ZERO_ARRAY(x) memset_s((char *)(x), sizeof(x), 0, sizeof(x))
+#endif
+
+/**
+ * Zero a given len of an array
+ */
+#define ZERO_ARRAY_LEN(x, l) memset_s((char *)(x), (l), 0, (l))
+
+/**
+ * Work out how many elements there are in a static array
+ */
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#endif
+
+/**
+ * Pointer difference macro.
+ */
+#ifndef PTR_DIFF
+#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
+#endif
+
+#endif /* _SAMBA_MEMORY_H_ */
diff --git a/lib/util/mkdir_p.c b/lib/util/mkdir_p.c
new file mode 100644
index 0000000..87a3f79
--- /dev/null
+++ b/lib/util/mkdir_p.c
@@ -0,0 +1,70 @@
+/*
+ mkdir -p
+
+ Copyright (C) Amitay Isaacs 2014
+ Copyright (C) Martin Schwenke 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "replace.h"
+#include <sys/stat.h>
+#include <libgen.h>
+#include "mkdir_p.h"
+
+int mkdir_p(const char *dir, int mode)
+{
+ char t[PATH_MAX];
+ ssize_t len;
+ int ret;
+
+ if (strcmp(dir, "/") == 0) {
+ return 0;
+ }
+
+ if (strcmp(dir, ".") == 0) {
+ return 0;
+ }
+
+ /* Try to create directory */
+ ret = mkdir(dir, mode);
+ /* Succeed if that worked or if it already existed */
+ if (ret == 0 || errno == EEXIST) {
+ return 0;
+ }
+ /* Fail on anything else except ENOENT */
+ if (errno != ENOENT) {
+ return ret;
+ }
+
+ /* Create ancestors */
+ len = strlen(dir);
+ ret = snprintf(t, sizeof(t), "%s", dir);
+ if (ret != len) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ ret = mkdir_p(dirname(t), mode);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Create directory */
+ ret = mkdir(dir, mode);
+ if ((ret == -1) && (errno == EEXIST)) {
+ ret = 0;
+ }
+
+ return ret;
+}
diff --git a/lib/util/mkdir_p.h b/lib/util/mkdir_p.h
new file mode 100644
index 0000000..9281de8
--- /dev/null
+++ b/lib/util/mkdir_p.h
@@ -0,0 +1,21 @@
+/*
+ mkdir -p
+
+ Copyright (C) Amitay Isaacs 2014
+ Copyright (C) Martin Schwenke 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+int mkdir_p(const char *dir, int mode);
diff --git a/lib/util/modules.c b/lib/util/modules.c
new file mode 100644
index 0000000..4260234
--- /dev/null
+++ b/lib/util/modules.c
@@ -0,0 +1,320 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij 2002-2003,2005-2007
+ Copyright (C) Stefan (metze) Metzmacher 2003
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "dynconfig/dynconfig.h"
+#include "lib/util/samba_modules.h"
+#include "lib/util/util_paths.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+
+/**
+ * Obtain the init function from a shared library file
+ */
+init_module_fn load_module(const char *path, bool is_probe, void **handle_out)
+{
+ void *handle;
+ void *init_fn;
+ char *error;
+
+ /* This should be a WAF build, where modules should be built
+ * with no undefined symbols and are already linked against
+ * the libraries that they are loaded by */
+ handle = dlopen(path, RTLD_NOW);
+
+ /* This call should reset any possible non-fatal errors that
+ occurred since last call to dl* functions */
+ error = dlerror();
+
+ if (handle == NULL) {
+ int level = is_probe ? 5 : 0;
+ DEBUG(level, ("Error loading module '%s': %s\n", path, error ? error : ""));
+ return NULL;
+ }
+
+ init_fn = (init_module_fn)dlsym(handle, SAMBA_INIT_MODULE);
+
+ /* we could check dlerror() to determine if it worked, because
+ dlsym() can validly return NULL, but what would we do with
+ a NULL pointer as a module init function? */
+
+ if (init_fn == NULL) {
+ DEBUG(0, ("Unable to find %s() in %s: %s\n",
+ SAMBA_INIT_MODULE, path, dlerror()));
+ DEBUG(1, ("Loading module '%s' failed\n", path));
+ dlclose(handle);
+ return NULL;
+ }
+
+ if (handle_out) {
+ *handle_out = handle;
+ }
+
+ return (init_module_fn)init_fn;
+}
+
+/**
+ * Obtain list of init functions from the modules in the specified
+ * directory
+ */
+static init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char *filename;
+ int success = 0;
+ init_module_fn *ret = talloc_array(mem_ctx, init_module_fn, 2);
+
+ ret[0] = NULL;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ while((entry = readdir(dir))) {
+ if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name))
+ continue;
+
+ filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name);
+
+ ret[success] = load_module(filename, true, NULL);
+ if (ret[success]) {
+ ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2);
+ success++;
+ ret[success] = NULL;
+ }
+
+ talloc_free(filename);
+ }
+
+ closedir(dir);
+
+ return ret;
+}
+
+/**
+ * Run the specified init functions.
+ *
+ * @return true if all functions ran successfully, false otherwise
+ */
+bool run_init_functions(TALLOC_CTX *ctx, init_module_fn *fns)
+{
+ int i;
+ bool ret = true;
+
+ if (fns == NULL)
+ return true;
+
+ for (i = 0; fns[i]; i++) { ret &= (bool)NT_STATUS_IS_OK(fns[i](ctx)); }
+
+ return ret;
+}
+
+/**
+ * Load the initialization functions from DSO files for a specific subsystem.
+ *
+ * Will return an array of function pointers to initialization functions
+ */
+
+init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem)
+{
+ char *path = modules_path(mem_ctx, subsystem);
+ init_module_fn *ret;
+
+ ret = load_modules(mem_ctx, path);
+
+ talloc_free(path);
+
+ return ret;
+}
+
+static NTSTATUS load_module_absolute_path(const char *module_path,
+ bool is_probe)
+{
+ void *handle;
+ init_module_fn init;
+ NTSTATUS status;
+
+ DBG_INFO("%s module '%s'\n",
+ is_probe ? "Probing" : "Loading",
+ module_path);
+
+ init = load_module(module_path, is_probe, &handle);
+ if (init == NULL) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DBG_NOTICE("Module '%s' loaded\n", module_path);
+
+ status = init(NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Module '%s' initialization failed: %s\n",
+ module_path,
+ get_friendly_nt_error_msg(status));
+ dlclose(handle);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* Load all modules in list and return number of
+ * modules that has been successfully loaded */
+int smb_load_all_modules_absoute_path(const char **modules)
+{
+ int i;
+ int success = 0;
+
+ for(i = 0; modules[i] != NULL; i++) {
+ const char *module = modules[i];
+ NTSTATUS status;
+
+ if (module[0] != '/') {
+ continue;
+ }
+
+ status = load_module_absolute_path(module, false);
+ if (NT_STATUS_IS_OK(status)) {
+ success++;
+ }
+ }
+
+ DEBUG(2, ("%d modules successfully loaded\n", success));
+
+ return success;
+}
+
+/**
+ * @brief Check if a module exist and load it.
+ *
+ * @param[in] subsystem The name of the subsystem the module belongs too.
+ *
+ * @param[in] module The name of the module
+ *
+ * @return A NTSTATUS code
+ */
+NTSTATUS smb_probe_module(const char *subsystem, const char *module)
+{
+ NTSTATUS status;
+ char *module_path = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if (subsystem == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ if (module == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (strchr(module, '/')) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ module_path = talloc_asprintf(tmp_ctx,
+ "%s/%s.%s",
+ modules_path(tmp_ctx, subsystem),
+ module,
+ shlib_ext());
+ if (module_path == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = load_module_absolute_path(module_path, true);
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return status;
+}
+
+/**
+ * @brief Check if a module exist and load it.
+ *
+ * Warning: Using this function can have security implecations!
+ *
+ * @param[in] subsystem The name of the subsystem the module belongs too.
+ *
+ * @param[in] module Load a module using an absolute path.
+ *
+ * @return A NTSTATUS code
+ */
+NTSTATUS smb_probe_module_absolute_path(const char *module)
+{
+ if (module == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (module[0] != '/') {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return load_module_absolute_path(module, true);
+}
+
+/**
+ * @brief Load a module.
+ *
+ * @param[in] subsystem The name of the subsystem the module belongs too.
+ *
+ * @param[in] module Check if a module exists and load it.
+ *
+ * @return A NTSTATUS code
+ */
+NTSTATUS smb_load_module(const char *subsystem, const char *module)
+{
+ NTSTATUS status;
+ char *module_path = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+ if (subsystem == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ if (module == NULL) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (strchr(module, '/')) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ module_path = talloc_asprintf(tmp_ctx,
+ "%s/%s.%s",
+ modules_path(tmp_ctx, subsystem),
+ module,
+ shlib_ext());
+ if (module_path == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = load_module_absolute_path(module_path, false);
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return status;
+}
diff --git a/lib/util/ms_fnmatch.c b/lib/util/ms_fnmatch.c
new file mode 100644
index 0000000..48454a8
--- /dev/null
+++ b/lib/util/ms_fnmatch.c
@@ -0,0 +1,249 @@
+/*
+ Unix SMB/CIFS implementation.
+ filename matching routine
+ Copyright (C) Andrew Tridgell 1992-2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This module was originally based on fnmatch.c copyright by the Free
+ Software Foundation. It bears little (if any) resemblance to that
+ code now
+*/
+
+/**
+ * @file
+ * @brief MS-style Filename matching
+ */
+
+#include "replace.h"
+#include "lib/util/samba_util.h"
+#include "libcli/smb/smb_constants.h"
+
+static int null_match(const char *p)
+{
+ for (;*p;p++) {
+ if (*p != '*' &&
+ *p != '<' &&
+ *p != '"' &&
+ *p != '>') return -1;
+ }
+ return 0;
+}
+
+/*
+ the max_n structure is purely for efficiency, it doesn't contribute
+ to the matching algorithm except by ensuring that the algorithm does
+ not grow exponentially
+*/
+struct max_n {
+ const char *predot;
+ const char *postdot;
+};
+
+
+/*
+ p and n are the pattern and string being matched. The max_n array is
+ an optimisation only. The ldot pointer is NULL if the string does
+ not contain a '.', otherwise it points at the last dot in 'n'.
+*/
+static int ms_fnmatch_core(const char *p, const char *n,
+ struct max_n *max_n, const char *ldot,
+ bool is_case_sensitive)
+{
+ codepoint_t c, c2;
+ int i;
+ size_t size, size_n;
+
+ while ((c = next_codepoint(p, &size))) {
+ p += size;
+
+ switch (c) {
+ case '*':
+ /* a '*' matches zero or more characters of any type */
+ if (max_n != NULL && max_n->predot &&
+ max_n->predot <= n) {
+ return null_match(p);
+ }
+ for (i=0; n[i]; i += size_n) {
+ next_codepoint(n+i, &size_n);
+ if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) {
+ return 0;
+ }
+ }
+ if (max_n != NULL && (!max_n->predot ||
+ max_n->predot > n)) {
+ max_n->predot = n;
+ }
+ return null_match(p);
+
+ case '<':
+ /* a '<' matches zero or more characters of
+ any type, but stops matching at the last
+ '.' in the string. */
+ if (max_n != NULL && max_n->predot &&
+ max_n->predot <= n) {
+ return null_match(p);
+ }
+ if (max_n != NULL && max_n->postdot &&
+ max_n->postdot <= n && n <= ldot) {
+ return -1;
+ }
+ for (i=0; n[i]; i += size_n) {
+ next_codepoint(n+i, &size_n);
+ if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) return 0;
+ if (n+i == ldot) {
+ if (ms_fnmatch_core(p, n+i+size_n, max_n+1, ldot, is_case_sensitive) == 0) return 0;
+ if (max_n != NULL) {
+ if (!max_n->postdot ||
+ max_n->postdot > n) {
+ max_n->postdot = n;
+ }
+ }
+ return -1;
+ }
+ }
+ if (max_n != NULL && (!max_n->predot ||
+ max_n->predot > n)) {
+ max_n->predot = n;
+ }
+ return null_match(p);
+
+ case '?':
+ /* a '?' matches any single character */
+ if (! *n) {
+ return -1;
+ }
+ next_codepoint(n, &size_n);
+ n += size_n;
+ break;
+
+ case '>':
+ /* a '?' matches any single character, but
+ treats '.' specially */
+ if (n[0] == '.') {
+ if (! n[1] && null_match(p) == 0) {
+ return 0;
+ }
+ break;
+ }
+ if (! *n) return null_match(p);
+ next_codepoint(n, &size_n);
+ n += size_n;
+ break;
+
+ case '"':
+ /* a bit like a soft '.' */
+ if (*n == 0 && null_match(p) == 0) {
+ return 0;
+ }
+ if (*n != '.') return -1;
+ next_codepoint(n, &size_n);
+ n += size_n;
+ break;
+
+ default:
+ c2 = next_codepoint(n, &size_n);
+ if (c != c2) {
+ if (is_case_sensitive) {
+ return -1;
+ }
+ if (codepoint_cmpi(c, c2) != 0) {
+ return -1;
+ }
+ }
+ n += size_n;
+ break;
+ }
+ }
+
+ if (! *n) {
+ return 0;
+ }
+
+ return -1;
+}
+
+int ms_fnmatch_protocol(const char *pattern, const char *string, int protocol,
+ bool is_case_sensitive)
+{
+ int ret = -1;
+ size_t count, i;
+
+ if (strcmp(string, "..") == 0) {
+ string = ".";
+ }
+
+ if (strpbrk(pattern, "<>*?\"") == NULL) {
+ /* this is not just an optimisation - it is essential
+ for LANMAN1 correctness */
+ return strcasecmp_m(pattern, string);
+ }
+
+ if (protocol <= PROTOCOL_LANMAN2) {
+ char *p = talloc_strdup(NULL, pattern);
+ if (p == NULL) {
+ return -1;
+ }
+ /*
+ for older negotiated protocols it is possible to
+ translate the pattern to produce a "new style"
+ pattern that exactly matches w2k behaviour
+ */
+ for (i=0;p[i];i++) {
+ if (p[i] == '?') {
+ p[i] = '>';
+ } else if (p[i] == '.' &&
+ (p[i+1] == '?' ||
+ p[i+1] == '*' ||
+ p[i+1] == 0)) {
+ p[i] = '"';
+ } else if (p[i] == '*' &&
+ p[i+1] == '.') {
+ p[i] = '<';
+ }
+ }
+ ret = ms_fnmatch_protocol(p, string, PROTOCOL_NT1,
+ is_case_sensitive);
+ talloc_free(p);
+ return ret;
+ }
+
+ for (count=i=0;pattern[i];i++) {
+ if (pattern[i] == '*' || pattern[i] == '<') count++;
+ }
+
+ /* If the pattern includes '*' or '<' */
+ if (count >= 1) {
+ struct max_n max_n[count];
+
+ memset(max_n, 0, sizeof(struct max_n) * count);
+
+ ret = ms_fnmatch_core(pattern, string, max_n, strrchr(string, '.'),
+ is_case_sensitive);
+ } else {
+ ret = ms_fnmatch_core(pattern, string, NULL, strrchr(string, '.'),
+ is_case_sensitive);
+ }
+
+ return ret;
+}
+
+
+/** a generic fnmatch function - uses for non-CIFS pattern matching */
+int gen_fnmatch(const char *pattern, const char *string)
+{
+ return ms_fnmatch_protocol(pattern, string, PROTOCOL_NT1, false);
+}
diff --git a/lib/util/msghdr.c b/lib/util/msghdr.c
new file mode 100644
index 0000000..3a1d6f5
--- /dev/null
+++ b/lib/util/msghdr.c
@@ -0,0 +1,273 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "lib/util/msghdr.h"
+#include "lib/util/iov_buf.h"
+#include <sys/socket.h>
+
+#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ const int *fds, size_t num_fds)
+{
+ size_t fds_size = sizeof(int) * MIN(num_fds, INT8_MAX);
+ size_t cmsg_len = CMSG_LEN(fds_size);
+ size_t cmsg_space = CMSG_SPACE(fds_size);
+ struct cmsghdr *cmsg;
+ void *fdptr;
+
+ if (num_fds == 0) {
+ if (msg != NULL) {
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+ }
+ /*
+ * C99 doesn't allow 0-length arrays
+ */
+ return 1;
+ }
+ if (num_fds > INT8_MAX) {
+ return -1;
+ }
+ if ((msg == NULL) || (cmsg_space > bufsize)) {
+ /*
+ * C99 doesn't allow 0-length arrays
+ */
+ return MAX(cmsg_space, 1);
+ }
+
+ msg->msg_control = buf;
+ msg->msg_controllen = cmsg_space;
+
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = cmsg_len;
+ fdptr = CMSG_DATA(cmsg);
+ memcpy(fdptr, fds, fds_size);
+ msg->msg_controllen = cmsg->cmsg_len;
+
+ return cmsg_space;
+}
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ size_t num_fds)
+{
+ size_t ret = CMSG_SPACE(sizeof(int) * num_fds);
+
+ if (bufsize < ret) {
+ return ret;
+ }
+ if (msg != NULL) {
+ if (num_fds != 0) {
+ msg->msg_control = buf;
+ msg->msg_controllen = ret;
+ } else {
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+ }
+ }
+ return ret;
+}
+
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
+{
+ struct cmsghdr *cmsg;
+ size_t num_fds;
+
+ for(cmsg = CMSG_FIRSTHDR(msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msg, cmsg))
+ {
+ if ((cmsg->cmsg_type == SCM_RIGHTS) &&
+ (cmsg->cmsg_level == SOL_SOCKET)) {
+ break;
+ }
+ }
+
+ if (cmsg == NULL) {
+ return 0;
+ }
+
+ num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+ if ((num_fds != 0) && (fds != NULL) && (fds_size >= num_fds)) {
+ memcpy(fds, CMSG_DATA(cmsg), num_fds * sizeof(int));
+ }
+
+ return num_fds;
+}
+
+#elif defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ const int *fds, size_t num_fds)
+{
+ size_t needed;
+
+ if (num_fds > INT8_MAX) {
+ return -1;
+ }
+
+ needed = sizeof(int) * num_fds;
+
+ if ((msg == NULL) || (needed > bufsize)) {
+ return needed;
+ }
+
+ memcpy(buf, fds, needed);
+
+ msg->msg_accrights = (caddr_t) buf;
+ msg->msg_accrightslen = needed;
+
+ return needed;
+}
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ size_t num_fds)
+{
+ size_t ret = num_fds * sizeof(int);
+
+ if (bufsize < ret) {
+ return ret;
+ }
+
+ if (msg != NULL) {
+ if (num_fds != 0) {
+ msg->msg_accrights = (caddr_t) buf;
+ msg->msg_accrightslen = ret;
+ } else {
+ msg->msg_accrights = NULL;
+ msg->msg_accrightslen = 0;
+ }
+ }
+ return ret;
+}
+
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
+{
+ size_t num_fds = msg->msg_accrightslen / sizeof(int);
+
+ if ((fds != 0) && (num_fds <= fds_size)) {
+ memcpy(fds, msg->msg_accrights, msg->msg_accrightslen);
+ }
+
+ return num_fds;
+}
+
+#else
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ const int *fds, size_t num_fds)
+{
+ return -1;
+}
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ size_t num_fds)
+{
+ return 0;
+}
+
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
+{
+ return 0;
+}
+
+#endif
+
+struct msghdr_buf {
+ struct msghdr msg;
+ struct sockaddr_storage addr;
+ struct iovec iov;
+ uint8_t buf[];
+};
+
+ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
+ const void *addr, socklen_t addrlen,
+ const struct iovec *iov, int iovcnt,
+ const int *fds, size_t num_fds)
+{
+ ssize_t fd_len;
+ size_t iov_len, needed, bufsize;
+
+ bufsize = (msgsize > offsetof(struct msghdr_buf, buf)) ?
+ msgsize - offsetof(struct msghdr_buf, buf) : 0;
+
+ if (msg != NULL) {
+ msg->msg = (struct msghdr) { 0 };
+
+ fd_len = msghdr_prep_fds(&msg->msg, msg->buf, bufsize,
+ fds, num_fds);
+ } else {
+ fd_len = msghdr_prep_fds(NULL, NULL, bufsize, fds, num_fds);
+ }
+
+ if (fd_len == -1) {
+ return -1;
+ }
+
+ if (bufsize >= (size_t)fd_len) {
+ bufsize -= fd_len;
+ } else {
+ bufsize = 0;
+ }
+
+ if (msg != NULL) {
+
+ if (addr != NULL) {
+ if (addrlen > sizeof(struct sockaddr_storage)) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+ memcpy(&msg->addr, addr, addrlen);
+ msg->msg.msg_name = &msg->addr;
+ msg->msg.msg_namelen = addrlen;
+ } else {
+ msg->msg.msg_name = NULL;
+ msg->msg.msg_namelen = 0;
+ }
+
+ msg->iov.iov_base = msg->buf + fd_len;
+ msg->iov.iov_len = iov_buf(
+ iov, iovcnt, msg->iov.iov_base, bufsize);
+ iov_len = msg->iov.iov_len;
+
+ msg->msg.msg_iov = &msg->iov;
+ msg->msg.msg_iovlen = 1;
+ } else {
+ iov_len = iov_buflen(iov, iovcnt);
+ }
+
+ needed = offsetof(struct msghdr_buf, buf) + fd_len;
+ if (needed < (size_t)fd_len) {
+ return -1;
+ }
+ needed += iov_len;
+ if (needed < iov_len) {
+ return -1;
+ }
+
+ return needed;
+}
+
+struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg)
+{
+ return &msg->msg;
+}
diff --git a/lib/util/msghdr.h b/lib/util/msghdr.h
new file mode 100644
index 0000000..c1676d2
--- /dev/null
+++ b/lib/util/msghdr.h
@@ -0,0 +1,42 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_MSGHDR_H__
+#define __LIB_MSGHDR_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ const int *fds, size_t num_fds);
+
+struct msghdr_buf;
+
+ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
+ const void *addr, socklen_t addrlen,
+ const struct iovec *iov, int iovcnt,
+ const int *fds, size_t num_fds);
+struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg);
+
+size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
+ size_t num_fds);
+size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t num_fds);
+
+#endif
diff --git a/lib/util/params.c b/lib/util/params.c
new file mode 100644
index 0000000..dac7782
--- /dev/null
+++ b/lib/util/params.c
@@ -0,0 +1,116 @@
+/* -------------------------------------------------------------------------- **
+ * Microsoft Network Services for Unix, AKA., Andrew Tridgell's SAMBA.
+ *
+ * This module Copyright (C) 1990-1998 Karl Auer
+ *
+ * Rewritten almost completely by Christopher R. Hertel
+ * at the University of Minnesota, September, 1997.
+ * This module Copyright (C) 1997-1998 by the University of Minnesota
+ * -------------------------------------------------------------------------- **
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Module name: params
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This module performs lexical analysis and initial parsing of a
+ * Windows-like parameter file. It recognizes and handles four token
+ * types: section-name, parameter-name, parameter-value, and
+ * end-of-file. Comments and line continuation are handled
+ * internally.
+ *
+ * The entry point to the module is function pm_process(). This
+ * function opens the source file, calls the Parse() function to parse
+ * the input, and then closes the file when either the EOF is reached
+ * or a fatal error is encountered.
+ *
+ * A sample parameter file might look like this:
+ *
+ * [section one]
+ * parameter one = value string
+ * parameter two = another value
+ * [section two]
+ * new parameter = some value or t'other
+ *
+ * The parameter file is divided into sections by section headers:
+ * section names enclosed in square brackets (eg. [section one]).
+ * Each section contains parameter lines, each of which consist of a
+ * parameter name and value delimited by an equal sign. Roughly, the
+ * syntax is:
+ *
+ * <file> :== { <section> } EOF
+ *
+ * <section> :== <section header> { <parameter line> }
+ *
+ * <section header> :== '[' NAME ']'
+ *
+ * <parameter line> :== NAME '=' VALUE '\n'
+ *
+ * Blank lines and comment lines are ignored. Comment lines are lines
+ * beginning with either a semicolon (';') or a pound sign ('#').
+ *
+ * All whitespace in section names and parameter names is compressed
+ * to single spaces. Leading and trailing whitespace is stripped from
+ * both names and values.
+ *
+ * Only the first equals sign in a parameter line is significant.
+ * Parameter values may contain equals signs, square brackets and
+ * semicolons. Internal whitespace is retained in parameter values,
+ * with the exception of the '\r' character, which is stripped for
+ * historic reasons. Parameter names may not start with a left square
+ * bracket, an equal sign, a pound sign, or a semicolon, because these
+ * are used to identify other tokens.
+ *
+ * -------------------------------------------------------------------------- **
+ */
+
+#include "replace.h"
+#include "lib/util/samba_util.h"
+#include "tini.h"
+
+bool pm_process(const char *filename,
+ bool (*sfunc)(const char *section, void *private_data),
+ bool (*pfunc)(const char *name, const char *value,
+ void *private_data),
+ void *private_data)
+{
+ bool ret = pm_process_with_flags(
+ filename, false, sfunc, pfunc, private_data);
+ return ret;
+}
+
+bool pm_process_with_flags(const char *filename,
+ bool allow_empty_values,
+ bool (*sfunc)(const char *section, void *private_data),
+ bool (*pfunc)(const char *name, const char *value,
+ void *private_data),
+ void *private_data)
+{
+ FILE *f;
+ bool ret;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ return false;
+ }
+
+ ret = tini_parse(f, allow_empty_values, sfunc, pfunc, private_data);
+
+ fclose(f);
+
+ return ret;
+}
diff --git a/lib/util/pidfile.c b/lib/util/pidfile.c
new file mode 100644
index 0000000..6ffbbea
--- /dev/null
+++ b/lib/util/pidfile.c
@@ -0,0 +1,238 @@
+/*
+ Unix SMB/CIFS implementation.
+ pidfile handling
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Amitay Isaccs 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include "lib/util/blocking.h"
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h" /* For process_exists_by_pid() */
+
+#include "lib/util/pidfile.h"
+
+int pidfile_path_create(const char *path, int *pfd, pid_t *existing_pid)
+{
+ struct flock lck;
+ char tmp[64] = { 0 };
+ int fd, ret = 0;
+ int len;
+ ssize_t nwritten;
+ bool retried = false;
+
+ fd = open(path, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
+ if (fd == -1) {
+ return errno;
+ }
+
+ if (! set_close_on_exec(fd)) {
+ ret = errno;
+ goto fail;
+ }
+
+retry:
+ lck = (struct flock) {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ };
+
+ do {
+ ret = fcntl(fd, F_SETLK, &lck);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret != 0) {
+ ret = errno;
+
+ if ((ret == EACCES) || (ret == EAGAIN)) {
+ do {
+ ret = fcntl(fd, F_GETLK, &lck);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret == -1) {
+ ret = errno;
+ goto fail;
+ }
+
+ if (lck.l_type == F_UNLCK) {
+ if (!retried) {
+ /* Lock holder died, retry once */
+ retried = true;
+ goto retry;
+ }
+ /* Something badly wrong */
+ ret = EIO;
+ goto fail;
+ }
+
+ if (existing_pid != NULL) {
+ *existing_pid = lck.l_pid;
+ }
+ return EAGAIN;
+ }
+ goto fail;
+ }
+
+ /*
+ * PID file is locked by us so from here on we should unlink
+ * on failure
+ */
+ len = snprintf(tmp, sizeof(tmp), "%u\n", getpid());
+ if (len < 0) {
+ ret = errno;
+ goto fail_unlink;
+ }
+ if ((size_t)len >= sizeof(tmp)) {
+ ret = ENOSPC;
+ goto fail_unlink;
+ }
+
+ do {
+ nwritten = write(fd, tmp, len);
+ } while ((nwritten == -1) && (errno == EINTR));
+
+ if ((nwritten == -1) || (nwritten != len)) {
+ ret = errno;
+ goto fail_unlink;
+ }
+
+ do {
+ ret = ftruncate(fd, len);
+ } while ((ret == -1) && (errno == EINTR));
+
+ if (ret == -1) {
+ ret = errno;
+ goto fail_unlink;
+ }
+
+ *pfd = fd;
+ return 0;
+
+fail_unlink:
+ unlink(path);
+fail:
+ close(fd);
+ return ret;
+}
+
+void pidfile_fd_close(int fd)
+{
+ struct flock lck = {
+ .l_type = F_UNLCK,
+ .l_whence = SEEK_SET,
+ };
+ int ret;
+
+ do {
+ ret = fcntl(fd, F_SETLK, &lck);
+ } while ((ret == -1) && (errno == EINTR));
+
+ do {
+ ret = close(fd);
+ } while ((ret == -1) && (errno == EINTR));
+}
+
+
+/**
+ * return the pid in a pidfile. return 0 if the process (or pidfile)
+ * does not exist
+ */
+pid_t pidfile_pid(const char *piddir, const char *name)
+{
+ size_t len = strlen(piddir) + strlen(name) + 6;
+ char pidFile[len];
+ int fd;
+ char pidstr[20] = { 0, };
+ pid_t ret = -1;
+
+ snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
+
+ fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
+
+ if (fd == -1) {
+ return 0;
+ }
+
+ if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
+ goto noproc;
+ }
+
+ ret = (pid_t)atoi(pidstr);
+ if (ret <= 0) {
+ DEBUG(1, ("Could not parse contents of pidfile %s\n",
+ pidFile));
+ goto noproc;
+ }
+
+ if (!process_exists_by_pid(ret)) {
+ DEBUG(10, ("Process with PID=%d does not exist.\n", (int)ret));
+ goto noproc;
+ }
+
+ if (fcntl_lock(fd,F_SETLK,0,1,F_RDLCK)) {
+ /* we could get the lock - it can't be a Samba process */
+ DEBUG(10, ("Process with PID=%d is not a Samba process.\n",
+ (int)ret));
+ goto noproc;
+ }
+
+ close(fd);
+ DEBUG(10, ("Process with PID=%d is running.\n", (int)ret));
+ return ret;
+
+ noproc:
+ close(fd);
+ return 0;
+}
+
+/**
+ * create a pid file in the pid directory. open it and leave it locked
+ */
+void pidfile_create(const char *piddir, const char *name)
+{
+ size_t len = strlen(piddir) + strlen(name) + 6;
+ char pidFile[len];
+ pid_t pid = (pid_t)-1;
+ int ret, fd;
+
+ snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
+
+ ret = pidfile_path_create(pidFile, &fd, &pid);
+ if (ret == EAGAIN) {
+ DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
+ name, pidFile, (int)pid));
+ exit(1);
+ }
+
+ /* Leave pid file open & locked for the duration... */
+}
+
+void pidfile_unlink(const char *piddir, const char *name)
+{
+ size_t len = strlen(piddir) + strlen(name) + 6;
+ char pidFile[len];
+ int ret;
+
+ snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
+
+ ret = unlink(pidFile);
+ if (ret == -1) {
+ DEBUG(0,("Failed to delete pidfile %s. Error was %s\n",
+ pidFile, strerror(errno)));
+ }
+}
diff --git a/lib/util/pidfile.h b/lib/util/pidfile.h
new file mode 100644
index 0000000..6f345a9
--- /dev/null
+++ b/lib/util/pidfile.h
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jeremy Allison 2012.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_PIDFILE_H_
+#define _SAMBA_PIDFILE_H_
+
+/**
+ * @file pidfile.h
+ *
+ * @brief PID file handling
+ */
+
+/**
+ * @brief Create a PID file
+ *
+ * Opens file, locks it, and writes PID. Returns EAGAIN if another
+ * process has the PID file locked. Use unlink(2) and
+ * pidfile_fd_close() to remove the PID file.
+ *
+ * @param[in] path PID file name
+ * @param[out] outfd File descriptor of open/locked PID file
+ * @param[out] existing_pid Return existing PID on EAGAIN
+ * @return 0 on success, errno on failure
+ */
+int pidfile_path_create(
+ const char *path, int *outfd, pid_t *existing_pid);
+
+/**
+ * @brief Unlock and close a PID file
+ *
+ * @param[in] fd File descriptor of open/locked PID file
+ */
+void pidfile_fd_close(int fd);
+
+/**
+ * @brief Check a PID file
+ *
+ * PID file name is <piddir>/<name>.pid
+ *
+ * @param[in] piddir Directory for PID file
+ * @param[in] name PID file process name
+ * @return PID of active process, 0 if PID file missing/stale/error
+ */
+pid_t pidfile_pid(const char *piddir, const char *name);
+
+/**
+ * @brief Create a PID file
+ *
+ * Leave PID file open/locked on success, exit on failure. On
+ * success, use pidfile_unlink() to remove PID file before exiting.
+ *
+ * PID file name is <piddir>/<name>.pid
+ *
+ * @param[in] piddir Directory for PID file
+ * @param[in] name PID file process name
+ */
+void pidfile_create(const char *piddir, const char *name);
+
+/**
+ * @brief Remove a PID file
+ *
+ * PID file name is <piddir>/<name>.pid
+ *
+ * @param[in] piddir Directory for PID file
+ * @param[in] name PID file process name
+ */
+void pidfile_unlink(const char *piddir, const char *name);
+
+#endif
diff --git a/lib/util/rbtree.c b/lib/util/rbtree.c
new file mode 100644
index 0000000..aa663f4
--- /dev/null
+++ b/lib/util/rbtree.c
@@ -0,0 +1,429 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+ (C) 2002 David Woodhouse <dwmw2@infradead.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/lib/rbtree.c
+*/
+
+#include "replace.h"
+#include "rbtree.h"
+#include "fault.h"
+
+#define RB_RED 0
+#define RB_BLACK 1
+
+#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r) ((r)->rb_parent_color & 1)
+#define rb_is_red(r) (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
+
+static void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static void rb_set_color(struct rb_node *rb, int color)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+
+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *right = node->rb_right;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_right = right->rb_left))
+ rb_set_parent(right->rb_left, node);
+ right->rb_left = node;
+
+ rb_set_parent(right, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_left)
+ parent->rb_left = right;
+ else
+ parent->rb_right = right;
+ }
+ else
+ root->rb_node = right;
+ rb_set_parent(node, right);
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *left = node->rb_left;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_left = left->rb_right))
+ rb_set_parent(left->rb_right, node);
+ left->rb_right = node;
+
+ rb_set_parent(left, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_right)
+ parent->rb_right = left;
+ else
+ parent->rb_left = left;
+ }
+ else
+ root->rb_node = left;
+ rb_set_parent(node, left);
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *parent, *gparent;
+
+ while ((parent = rb_parent(node)) && rb_is_red(parent))
+ {
+ gparent = rb_parent(parent);
+
+ if (parent == gparent->rb_left)
+ {
+ {
+ register struct rb_node *uncle = gparent->rb_right;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_right == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_left(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_right(gparent, root);
+ } else {
+ {
+ register struct rb_node *uncle = gparent->rb_left;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_left == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_right(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_left(gparent, root);
+ }
+ }
+
+ rb_set_black(root->rb_node);
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+ struct rb_root *root)
+{
+ struct rb_node *other;
+
+ while ((!node || rb_is_black(node)) && node != root->rb_node)
+ {
+ if (parent->rb_left == node)
+ {
+ other = parent->rb_right;
+ if (other == NULL) {
+ /* we should never get here */
+ smb_panic("corrupted rb tree");
+ /* satisfy static checkers */
+ return;
+ }
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_left(parent, root);
+ other = parent->rb_right;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_right || rb_is_black(other->rb_right))
+ {
+ struct rb_node *o_left;
+ if ((o_left = other->rb_left))
+ rb_set_black(o_left);
+ rb_set_red(other);
+ __rb_rotate_right(other, root);
+ other = parent->rb_right;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_right)
+ rb_set_black(other->rb_right);
+ __rb_rotate_left(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ else
+ {
+ other = parent->rb_left;
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_right(parent, root);
+ other = parent->rb_left;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_left || rb_is_black(other->rb_left))
+ {
+ register struct rb_node *o_right;
+ if ((o_right = other->rb_right))
+ rb_set_black(o_right);
+ rb_set_red(other);
+ __rb_rotate_left(other, root);
+ other = parent->rb_left;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_left)
+ rb_set_black(other->rb_left);
+ __rb_rotate_right(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ }
+ if (node)
+ rb_set_black(node);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *child, *parent;
+ int color;
+
+ if (!node->rb_left)
+ child = node->rb_right;
+ else if (!node->rb_right)
+ child = node->rb_left;
+ else
+ {
+ struct rb_node *old = node, *left;
+
+ node = node->rb_right;
+ while ((left = node->rb_left) != NULL)
+ node = left;
+ child = node->rb_right;
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent == old) {
+ parent->rb_right = child;
+ parent = node;
+ } else
+ parent->rb_left = child;
+
+ node->rb_parent_color = old->rb_parent_color;
+ node->rb_right = old->rb_right;
+ node->rb_left = old->rb_left;
+
+ if (rb_parent(old))
+ {
+ if (rb_parent(old)->rb_left == old)
+ rb_parent(old)->rb_left = node;
+ else
+ rb_parent(old)->rb_right = node;
+ } else
+ root->rb_node = node;
+
+ rb_set_parent(old->rb_left, node);
+ if (old->rb_right)
+ rb_set_parent(old->rb_right, node);
+ goto color;
+ }
+
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent)
+ {
+ if (parent->rb_left == node)
+ parent->rb_left = child;
+ else
+ parent->rb_right = child;
+ }
+ else
+ root->rb_node = child;
+
+ color:
+ if (color == RB_BLACK)
+ __rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_left)
+ n = n->rb_left;
+ return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_right)
+ n = n->rb_right;
+ return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a right-hand child, go down and then left as far
+ as we can. */
+ if (node->rb_right) {
+ node = node->rb_right;
+ while (node->rb_left)
+ node=node->rb_left;
+ return node;
+ }
+
+ /* No right-hand children. Everything down and left is
+ smaller than us, so any 'next' node must be in the general
+ direction of our parent. Go up the tree; any time the
+ ancestor is a right-hand child of its parent, keep going
+ up. First time it's a left-hand child of its parent, said
+ parent is our 'next' node. */
+ while ((parent = rb_parent(node)) && node == parent->rb_right)
+ node = parent;
+
+ return parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a left-hand child, go down and then right as far
+ as we can. */
+ if (node->rb_left) {
+ node = node->rb_left;
+ while (node->rb_right)
+ node=node->rb_right;
+ return node;
+ }
+
+ /* No left-hand children. Go up till we find an ancestor which
+ is a right-hand child of its parent */
+ while ((parent = rb_parent(node)) && node == parent->rb_left)
+ node = parent;
+
+ return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new_node,
+ struct rb_root *root)
+{
+ struct rb_node *parent = rb_parent(victim);
+
+ /* Set the surrounding nodes to point to the replacement */
+ if (parent) {
+ if (victim == parent->rb_left)
+ parent->rb_left = new_node;
+ else
+ parent->rb_right = new_node;
+ } else {
+ root->rb_node = new_node;
+ }
+ if (victim->rb_left)
+ rb_set_parent(victim->rb_left, new_node);
+ if (victim->rb_right)
+ rb_set_parent(victim->rb_right, new_node);
+
+ /* Copy the pointers/colour from the victim to the replacement */
+ *new_node = *victim;
+}
+
+void rb_link_node(struct rb_node * node, struct rb_node * parent,
+ struct rb_node ** rb_link)
+{
+ node->rb_parent_color = (unsigned long )parent;
+ node->rb_left = node->rb_right = NULL;
+
+ *rb_link = node;
+}
diff --git a/lib/util/rbtree.h b/lib/util/rbtree.h
new file mode 100644
index 0000000..1cfd346
--- /dev/null
+++ b/lib/util/rbtree.h
@@ -0,0 +1,132 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/include/linux/rbtree.h
+
+ To use rbtrees you'll have to implement your own insert and search cores.
+ This will avoid us to use callbacks and to drop drammatically performances.
+ I know it's not the cleaner way, but in C (not in C++) to get
+ performances and genericity...
+
+ Some example of insert and search follows here. The search is a plain
+ normal search over an ordered tree. The insert instead must be implemented
+ int two steps: as first thing the code must insert the element in
+ order as a red leaf in the tree, then the support library function
+ rb_insert_color() must be called. Such function will do the
+ not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+ unsigned long offset)
+{
+ struct rb_node * n = inode->i_rb_page_cache.rb_node;
+ struct page * page;
+
+ while (n)
+ {
+ page = rb_entry(n, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ n = n->rb_left;
+ else if (offset > page->offset)
+ n = n->rb_right;
+ else
+ return page;
+ }
+ return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+ struct rb_node * parent = NULL;
+ struct page * page;
+
+ while (*p)
+ {
+ parent = *p;
+ page = rb_entry(parent, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ p = &(*p)->rb_left;
+ else if (offset > page->offset)
+ p = &(*p)->rb_right;
+ else
+ return page;
+ }
+
+ rb_link_node(node, parent, p);
+
+ return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct page * ret;
+ if ((ret = __rb_insert_page_cache(inode, offset, node)))
+ goto out;
+ rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+ return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef _LINUX_RBTREE_H
+#define _LINUX_RBTREE_H
+
+struct rb_node
+{
+ unsigned long rb_parent_color;
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
+};
+
+struct rb_root
+{
+ struct rb_node *rb_node;
+};
+
+
+#define RB_ROOT (struct rb_root) { NULL, }
+
+#if 0
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+#endif
+
+void rb_insert_color(struct rb_node *, struct rb_root *);
+void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+struct rb_node *rb_next(struct rb_node *);
+struct rb_node *rb_prev(struct rb_node *);
+struct rb_node *rb_first(struct rb_root *);
+struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_node,
+ struct rb_root *root);
+
+void rb_link_node(struct rb_node * node, struct rb_node * parent,
+ struct rb_node ** rb_link);
+
+#endif /* _LINUX_RBTREE_H */
diff --git a/lib/util/rfc1738.c b/lib/util/rfc1738.c
new file mode 100644
index 0000000..7b8db11
--- /dev/null
+++ b/lib/util/rfc1738.c
@@ -0,0 +1,198 @@
+/*
+ * Functions for RFC 3986 percent-encoding.
+ *
+ * NOTE:
+ *
+ * This file was originally imported from the Squid project but has been
+ * significantly altered. The licence below is reproduced intact, but refers
+ * to files in Squid's repository, not in Samba. See COPYING for the GPLv3
+ * notice (being the later version mentioned below).
+ */
+
+/*
+ * $Id$
+ *
+ * DEBUG:
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/samba_util.h"
+
+#define RFC1738_ENCODE 1
+#define RFC1738_RESERVED 2
+
+/*
+ * According to RFC 1738, "$-_.+!*'()," are not reserved or unsafe, but as
+ * that has been obsolete since 2004, we sm instead for RFC 3986, where:
+ *
+ * reserved = : / ? # [ ] @ ! $ & ' ( ) * + , ; =
+ * unreserved = ALPHA DIGIT - . _ ~
+ *
+ * and whatever is not in either of those are what RFC 1738 called "unsafe",
+ * meaning that they should are canonically but not mandatorily escaped.
+ *
+ * Characters below 0x20 or above 0x7E are always encoded.
+ */
+
+static const unsigned char escapees[127] = {
+ [' '] = RFC1738_ENCODE,
+ ['"'] = RFC1738_ENCODE,
+ ['%'] = RFC1738_ENCODE,
+ ['<'] = RFC1738_ENCODE,
+ ['>'] = RFC1738_ENCODE,
+ ['\\'] = RFC1738_ENCODE,
+ ['^'] = RFC1738_ENCODE,
+ ['`'] = RFC1738_ENCODE,
+ ['{'] = RFC1738_ENCODE,
+ ['|'] = RFC1738_ENCODE,
+ ['}'] = RFC1738_ENCODE,
+ /* reserved : / ? # [ ] @ ! $ & ' ( ) * + , ; = */
+ [':'] = RFC1738_RESERVED,
+ ['/'] = RFC1738_RESERVED,
+ ['?'] = RFC1738_RESERVED,
+ ['#'] = RFC1738_RESERVED,
+ ['['] = RFC1738_RESERVED,
+ [']'] = RFC1738_RESERVED,
+ ['@'] = RFC1738_RESERVED,
+ ['!'] = RFC1738_RESERVED,
+ ['$'] = RFC1738_RESERVED,
+ ['&'] = RFC1738_RESERVED,
+ ['\''] = RFC1738_RESERVED,
+ ['('] = RFC1738_RESERVED,
+ [')'] = RFC1738_RESERVED,
+ ['*'] = RFC1738_RESERVED,
+ ['+'] = RFC1738_RESERVED,
+ [','] = RFC1738_RESERVED,
+ [';'] = RFC1738_RESERVED,
+ ['='] = RFC1738_RESERVED,
+};
+
+/*
+ * rfc1738_do_escape - fills a preallocated buffer with an escaped version of
+ * the given string.
+ *
+ * For canonical escaping, mask should be RFC1738_ENCODE | RFC1738_RESERVED.
+ * For mandatory escaping, mask should be RFC1738_RESERVED.
+ */
+static char *
+rfc1738_do_escape(char *buf, size_t bufsize,
+ const char *url, size_t len, unsigned char mask)
+{
+ size_t i;
+ size_t j = 0;
+ for (i = 0; i < len; i++) {
+ unsigned int c = (unsigned char) url[i];
+ if (c > 126 || c < 32 || (escapees[c] & mask)) {
+ if (j + 3 >= bufsize) {
+ return NULL;
+ }
+ (void) snprintf(&buf[j], 4, "%%%02X", c);
+ j += 3;
+ } else {
+ if (j + 1 >= bufsize) {
+ return NULL;
+ }
+ buf[j] = c;
+ j++;
+ }
+ }
+ buf[j] = '\0';
+ return buf;
+}
+
+/*
+ * rfc1738_escape_part - Returns a talloced buffer that contains the RFC 3986
+ * compliant, escaped version of the given url segment.
+ */
+char *
+rfc1738_escape_part(TALLOC_CTX *mem_ctx, const char *url)
+{
+ size_t bufsize = 0;
+ char *buf = NULL;
+
+ size_t len = strlen(url);
+ if (len >= SIZE_MAX / 3) {
+ return NULL;
+ }
+
+ bufsize = len * 3 + 1;
+ buf = talloc_array(mem_ctx, char, bufsize);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ talloc_set_name_const(buf, buf);
+
+ return rfc1738_do_escape(buf, bufsize, url, len,
+ RFC1738_ENCODE | RFC1738_RESERVED);
+}
+
+/*
+ * rfc1738_unescape() - Converts url-escaped characters in the string.
+ *
+ * The two characters following a '%' in a string should be hex digits that
+ * describe an encoded byte. For example, "%25" is hex 0x25 or '%' in ASCII;
+ * this is the only way to include a % in the unescaped string. Any character
+ * can be escaped, including plain letters (e.g. "%61" for "a"). Anything
+ * other than 2 hex characters following the % is an error.
+ *
+ * The conversion is done in-place, which is always safe as unescapes can only
+ * shorten the string.
+ *
+ * Returns a pointer to the end of the string (that is, the '\0' byte), or
+ * NULL on error, at which point s is in an undefined state.
+ *
+ * Note that after `char *e = rfc_unescape(s)`, `strlen(s)` will not equal
+ * `e - s` if s originally contained "%00". You might want to check for this.
+ */
+
+_PUBLIC_ char *rfc1738_unescape(char *s)
+{
+ size_t i, j; /* i is write, j is read */
+ for (i = 0, j = 0; s[j] != '\0'; i++, j++) {
+ if (s[j] == '%') {
+ uint8_t v;
+ bool ok;
+
+ ok = hex_byte(&s[j+1], &v);
+ if (!ok) {
+ return NULL;
+ }
+ j += 2; /* OK; hex_byte() has checked ahead */
+ s[i] = (unsigned char)v;
+ } else {
+ s[i] = s[j];
+ }
+ }
+ s[i] = '\0';
+ return s + i;
+}
diff --git a/lib/util/safe_string.h b/lib/util/safe_string.h
new file mode 100644
index 0000000..edff296
--- /dev/null
+++ b/lib/util/safe_string.h
@@ -0,0 +1,64 @@
+/*
+ Unix SMB/CIFS implementation.
+ Safe string handling routines.
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAFE_STRING_H
+#define _SAFE_STRING_H
+#ifndef _SPLINT_ /* http://www.splint.org */
+
+/* Some macros to ensure people don't use buffer overflow vulnerable string
+ functions. */
+
+#ifdef bcopy
+#undef bcopy
+#endif /* bcopy */
+#define bcopy(src,dest,size) __ERROR__XX__NEVER_USE_BCOPY___;
+
+#ifdef strcpy
+#undef strcpy
+#endif /* strcpy */
+#define strcpy(dest,src) __ERROR__XX__NEVER_USE_STRCPY___;
+
+#ifdef strcat
+#undef strcat
+#endif /* strcat */
+#define strcat(dest,src) __ERROR__XX__NEVER_USE_STRCAT___;
+
+#ifdef sprintf
+#undef sprintf
+#endif /* sprintf */
+#define sprintf __ERROR__XX__NEVER_USE_SPRINTF__;
+
+/*
+ * strcasecmp/strncasecmp aren't an error, but it means you're not thinking about
+ * multibyte. Don't use them. JRA.
+ */
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
+#define strcasecmp __ERROR__XX__NEVER_USE_STRCASECMP__;
+
+#ifdef strncasecmp
+#undef strncasecmp
+#endif
+#define strncasecmp __ERROR__XX__NEVER_USE_STRNCASECMP__;
+
+#endif /* !_SPLINT_ */
+
+#endif
diff --git a/lib/util/samba-util.pc.in b/lib/util/samba-util.pc.in
new file mode 100644
index 0000000..65876c4
--- /dev/null
+++ b/lib/util/samba-util.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: samba-util
+Description: Samba utility functions
+Requires: talloc tevent
+Version: @PACKAGE_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -lsamba-util
+Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1
diff --git a/lib/util/samba_modules.h b/lib/util/samba_modules.h
new file mode 100644
index 0000000..c698691
--- /dev/null
+++ b/lib/util/samba_modules.h
@@ -0,0 +1,61 @@
+/*
+ Unix SMB/CIFS implementation.
+ Handling of idle/exit events
+ Copyright (C) Stefan (metze) Metzmacher 2003
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_MODULES_H
+#define _SAMBA_MODULES_H
+
+/* Module support */
+typedef NTSTATUS (*init_module_fn) (TALLOC_CTX *ctx);
+
+NTSTATUS samba_init_module(TALLOC_CTX *ctx);
+
+/* this needs to be a string which is not in the C library. We
+ previously used "init_module", but that meant that modules which
+ did not define this function ended up calling the C library
+ function init_module() which makes a system call */
+#define SAMBA_INIT_MODULE "samba_init_module"
+
+/**
+ * Obtain the init function from a shared library file.
+ *
+ * The handle to dlclose() in case of error is returns in *handle if handle is not NULL
+ */
+init_module_fn load_module(const char *path, bool is_probe, void **handle);
+
+/**
+ * Run the specified init functions.
+ *
+ * @return true if all functions ran successfully, false otherwise
+ */
+bool run_init_functions(TALLOC_CTX *ctx, init_module_fn *fns);
+
+/**
+ * Load the initialization functions from DSO files for a specific subsystem.
+ *
+ * Will return an array of function pointers to initialization functions
+ */
+init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem);
+
+int smb_load_all_modules_absoute_path(const char **modules);
+NTSTATUS smb_probe_module(const char *subsystem, const char *module);
+NTSTATUS smb_probe_module_absolute_path(const char *module);
+NTSTATUS smb_load_module(const char *subsystem, const char *module);
+
+#endif /* _SAMBA_MODULES_H */
diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h
new file mode 100644
index 0000000..e672b4b
--- /dev/null
+++ b/lib/util/samba_util.h
@@ -0,0 +1,708 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for Samba
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_UTIL_H_
+#define _SAMBA_UTIL_H_
+
+#ifndef SAMBA_UTIL_CORE_ONLY
+#include "lib/util/charset/charset.h"
+#else
+#include "charset_compat.h"
+#endif
+
+#include "lib/util/attr.h"
+
+/* for TALLOC_CTX */
+#include <talloc.h>
+
+/* for struct stat */
+#include <sys/stat.h>
+
+/**
+ * @file
+ * @brief Helpful macros
+ */
+
+struct smbsrv_tcon;
+
+extern const char *panic_action;
+
+#include "lib/util/time.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/talloc_keep_secret.h"
+
+#ifndef ABS
+#define ABS(a) ((a)>0?(a):(-(a)))
+#endif
+
+#include "lib/util/memory.h"
+#include "lib/util/discard.h"
+
+#include "fault.h"
+
+#include "lib/util/util.h"
+
+/**
+ * Write backtrace to debug log
+ */
+_PUBLIC_ void dump_core_setup(const char *progname, const char *logfile);
+
+/**
+ register a fault handler.
+ Should only be called once in the execution of smbd.
+*/
+_PUBLIC_ bool register_fault_handler(const char *name, void (*fault_handler)(int sig));
+
+#include "lib/util/signal.h" /* Avoid /usr/include/signal.h */
+
+struct sockaddr;
+
+_PUBLIC_ int sys_getnameinfo(const struct sockaddr *psa,
+ int salen,
+ char *host,
+ size_t hostlen,
+ char *service,
+ size_t servlen,
+ int flags);
+
+/* The following definitions come from lib/util/genrand.c */
+
+#include "lib/util/genrand.h"
+
+/**
+ generate a single random uint32_t
+**/
+_PUBLIC_ uint32_t generate_random(void);
+
+/**
+ * generate a single random uint64_t
+ * @see generate_unique_u64
+**/
+_PUBLIC_ uint64_t generate_random_u64(void);
+
+_PUBLIC_ uint64_t generate_random_u64_range(uint64_t lower, uint64_t upper);
+
+/**
+ * @brief Generate random nonces usable for re-use detection.
+ *
+ * We have a lot of places which require a unique id that can
+ * be used as a unique identitier for caching states.
+ *
+ * Always using generate_nonce_buffer() has it's performance costs,
+ * it's typically much better than generate_random_buffer(), but
+ * still it's overhead we want to avoid in performance critical
+ * workloads.
+ *
+ * We call generate_nonce_buffer() just once per given state
+ * and process.
+ *
+ * This is much lighter than generate_random_u64() and it's
+ * designed for performance critical code paths.
+ *
+ * @veto_value It is guaranteed that the return value is different from
+ * the veto_value.
+ *
+ * @return a unique value per given state and process
+ *
+ * @see generate_random_u64
+ */
+uint64_t generate_unique_u64(uint64_t veto_value);
+
+/**
+ very basic password quality checker
+**/
+_PUBLIC_ bool check_password_quality(const char *s);
+
+/**
+ * Generate a random text password (based on printable ascii characters).
+ * This function is designed to provide a password that
+ * meats the complexity requirements of UF_NORMAL_ACCOUNT objects
+ * and they should be human readable and writeable on any keyboard layout.
+ *
+ * Characters used are:
+ * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~
+ */
+_PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max);
+
+/**
+ * Generate a random machine password
+ *
+ * min and max are the number of utf16 characters used
+ * to generate on utf8 compatible password.
+ *
+ * Note: if 'unix charset' is not 'utf8' (the default)
+ * then each utf16 character is only filled with
+ * values from 0x01 to 0x7f (ascii values without 0x00).
+ * This is important as the password neets to be
+ * a valid value as utf8 string and at the same time
+ * a valid value in the 'unix charset'.
+ *
+ * If 'unix charset' is 'utf8' (the default) then
+ * each utf16 character is a random value from 0x0000
+ * 0xFFFF (excluding the surrogate ranges from 0xD800-0xDFFF)
+ * while the translation from CH_UTF16MUNGED
+ * to CH_UTF8 replaces invalid values (see utf16_munged_pull()).
+ *
+ * Note: these passwords may not pass the complexity requirements
+ * for UF_NORMAL_ACCOUNT objects (except krbtgt accounts).
+ */
+_PUBLIC_ char *generate_random_machine_password(TALLOC_CTX *mem_ctx, size_t min, size_t max);
+
+/**
+ Use the random number generator to generate a random string.
+**/
+_PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list);
+
+/**
+ * Generate a random text string consisting of the specified length.
+ * The returned string will be allocated.
+ *
+ * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
+ */
+_PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len);
+
+/**
+ * Generate an array of unique text strings all of the same length.
+ * The returned strings will be allocated.
+ * Returns NULL if the number of unique combinations cannot be created.
+ *
+ * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
+ */
+_PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
+ uint32_t num);
+
+/* The following definitions come from lib/util/dprintf.c */
+
+_PUBLIC_ int d_fprintf(FILE *f, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+_PUBLIC_ int d_printf(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
+_PUBLIC_ void display_set_stderr(void);
+
+/* The following definitions come from lib/util/util_str.c */
+
+bool next_token_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep);
+
+/**
+ * Get the next token from a string, return false if none found. Handles
+ * double-quotes. This version does not trim leading separator characters
+ * before looking for a token.
+ */
+bool next_token_no_ltrim_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep);
+
+
+/**
+ Trim the specified elements off the front and back of a string.
+**/
+_PUBLIC_ bool trim_string(char *s, const char *front, const char *back);
+
+/**
+ Find the number of 'c' chars in a string
+**/
+_PUBLIC_ _PURE_ size_t count_chars(const char *s, char c);
+
+/**
+ Routine to get hex characters and turn them into a 16 byte array.
+ the array can be variable length, and any non-hex-numeric
+ characters are skipped. "0xnn" or "0Xnn" is specially catered
+ for.
+
+ valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
+
+
+**/
+_PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len);
+
+/**
+ * Parse a hex string and return a data blob.
+ */
+_PUBLIC_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) ;
+
+/**
+ * Parse a hex dump and return a data blob
+ */
+_PUBLIC_ DATA_BLOB hexdump_to_data_blob(TALLOC_CTX *mem_ctx, const char *hexdump, size_t len);
+
+/**
+ * Print a buf in hex. Assumes dst is at least (srclen*2)+1 large.
+ */
+_PUBLIC_ void hex_encode_buf(char *dst, const uint8_t *src, size_t srclen);
+
+/**
+ * talloc version of hex_encode_buf()
+ */
+_PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len);
+
+#include "substitute.h"
+
+/**
+ Unescape a URL encoded string, in place.
+**/
+_PUBLIC_ char *rfc1738_unescape(char *buf);
+
+/**
+ * rfc1738_escape_part
+ * Returns a static buffer that contains the RFC
+ * 1738 compliant, escaped version of the given url segment. (escapes
+ * unsafe, reserved and % chars) It would mangle the :// in http://,
+ * and mangle paths (because of /).
+ **/
+_PUBLIC_ char *rfc1738_escape_part(TALLOC_CTX *mem_ctx, const char *url);
+
+/**
+ variant of strcmp() that handles NULL ptrs
+**/
+_PUBLIC_ int strcmp_safe(const char *s1, const char *s2);
+
+/**
+return the number of bytes occupied by a buffer in ASCII format
+the result includes the null termination
+limited by 'n' bytes
+**/
+_PUBLIC_ size_t ascii_len_n(const char *src, size_t n);
+
+/**
+ Set a boolean variable from the text value stored in the passed string.
+ Returns true in success, false if the passed string does not correctly
+ represent a boolean.
+**/
+_PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean);
+
+/**
+ * Parse a string containing a boolean value.
+ *
+ * val will be set to the read value.
+ *
+ * @retval true if a boolean value was parsed, false otherwise.
+ */
+_PUBLIC_ bool conv_str_bool(const char * str, bool * val);
+
+/**
+ * Convert a size specification like 16K into an integral number of bytes.
+ **/
+_PUBLIC_ bool conv_str_size_error(const char * str, uint64_t * val);
+
+/**
+ * Parse a uint64_t value from a string
+ *
+ * val will be set to the value read.
+ *
+ * @retval true if parsing was successful, false otherwise
+ */
+_PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val);
+
+/**
+ * @brief Constant time compare to memory regions.
+ *
+ * @param[in] s1 The first memory region to compare.
+ *
+ * @param[in] s2 The second memory region to compare.
+ *
+ * @param[in] n The length of the memory to compare.
+ *
+ * @return true when the memory regions are equal, false if not.
+ */
+_PUBLIC_ bool mem_equal_const_time(const void *s1, const void *s2, size_t n);
+
+/**
+Do a case-insensitive, whitespace-ignoring string compare.
+**/
+_PUBLIC_ int strwicmp(const char *psz1, const char *psz2);
+
+/**
+ String replace.
+**/
+_PUBLIC_ void string_replace(char *s, char oldc, char newc);
+
+/**
+ * Compare 2 strings.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+_PUBLIC_ bool strequal(const char *s1, const char *s2);
+
+#include "util_strlist.h"
+
+/* The following definitions come from lib/util/util_strlist_v3.c */
+
+/**
+ * Needed for making an "unconst" list "const"
+ */
+_PUBLIC_ const char **const_str_list(char **list);
+
+/**
+ * str_list_make, v3 version. The v4 version does not
+ * look at quoted strings with embedded blanks, so
+ * do NOT merge this function please!
+ */
+char **str_list_make_v3(TALLOC_CTX *mem_ctx, const char *string,
+ const char *sep);
+
+
+const char **str_list_make_v3_const(TALLOC_CTX *mem_ctx,
+ const char *string,
+ const char *sep);
+
+/* The following definitions come from lib/util/util_file.c */
+
+
+/**
+ * Read one line (data until next newline or eof) and allocate it
+ */
+_PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint);
+
+char *fgets_slash(TALLOC_CTX *mem_ctx, char *s2, size_t maxlen, FILE *f);
+
+/**
+load a file into memory from a fd.
+**/
+_PUBLIC_ char *fd_load(int fd, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
+
+
+char **file_lines_parse(const char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx);
+
+/**
+load a file into memory
+**/
+_PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
+
+/**
+load a file into memory and return an array of pointers to lines in the file
+must be freed with talloc_free().
+**/
+_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
+
+/**
+load a fd into memory and return an array of pointers to lines in the file
+must be freed with talloc_free(). If convert is true calls unix_to_dos on
+the list.
+**/
+_PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
+
+_PUBLIC_ bool file_save_mode(const char *fname, const void *packet,
+ size_t length, mode_t mode);
+/**
+ save a lump of data into a file. Mostly used for debugging
+*/
+_PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length);
+_PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
+_PUBLIC_ int fdprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+
+/*
+ compare two files, return true if the two files have the same content
+ */
+bool file_compare(const char *path1, const char *path2);
+
+/*
+ load from a pipe into memory.
+ */
+char *file_ploadv(char * const argl[], size_t *size);
+
+/* The following definitions come from lib/util/util.c */
+
+
+/**
+ Find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call.
+**/
+_PUBLIC_ const char *tmpdir(void);
+
+/**
+ * Creates and immediately unlinks a file. Returns open file descriptor.
+ **/
+_PUBLIC_ int create_unlink_tmp(const char *dir);
+
+/**
+ Check if a file exists - call vfs_file_exist for samba files.
+**/
+_PUBLIC_ bool file_exist(const char *fname);
+
+/**
+ * @brief Return a files modification time.
+ *
+ * @param fname The name of the file.
+ *
+ * @param mt A pointer to store the modification time.
+ *
+ * @return 0 on success, errno otherwise.
+ */
+_PUBLIC_ int file_modtime(const char *fname, struct timespec *mt);
+
+/**
+ Check if a directory exists.
+**/
+_PUBLIC_ bool directory_exist(const char *dname);
+
+/**
+ Check file permissions.
+**/
+_PUBLIC_ bool file_check_permissions(const char *fname,
+ uid_t uid,
+ mode_t file_perms,
+ struct stat *pst);
+
+/**
+ * Try to create the specified directory if it didn't exist.
+ *
+ * @retval true if the directory already existed and has the right permissions
+ * or was successfully created.
+ */
+_PUBLIC_ bool directory_create_or_exist(const char *dname, mode_t dir_perms);
+
+/**
+ * @brief Try to create a specified directory and the parent directory if they
+ * don't exist.
+ *
+ * @param[in] dname The directory path to create.
+ *
+ * @param[in] dir_perms The permission of the directories.
+ *
+ * @return true on success, false otherwise.
+ */
+_PUBLIC_ bool directory_create_or_exists_recursive(
+ const char *dname,
+ mode_t dir_perms);
+
+_PUBLIC_ bool directory_create_or_exist_strict(const char *dname,
+ uid_t uid,
+ mode_t dir_perms);
+
+#include "blocking.h"
+
+/**
+ Sleep for a specified number of milliseconds.
+**/
+_PUBLIC_ void smb_msleep(unsigned int t);
+
+/**
+ Get my own name, return in talloc'ed storage.
+**/
+_PUBLIC_ char* get_myname(TALLOC_CTX *mem_ctx);
+
+/**
+ Check if a process exists. Does this work on all unixes?
+**/
+_PUBLIC_ bool process_exists_by_pid(pid_t pid);
+
+/**
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+**/
+_PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type);
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level.
+ * 16 zero bytes in a row are omitted
+ */
+_PUBLIC_ void dump_data_skip_zeros(int level, const uint8_t *buf, int len);
+
+/**
+ malloc that aborts with smb_panic on fail or zero size.
+**/
+_PUBLIC_ void *smb_xmalloc(size_t size);
+
+/**
+ Memdup with smb_panic on fail.
+**/
+_PUBLIC_ void *smb_xmemdup(const void *p, size_t size);
+
+/**
+ strdup that aborts on malloc fail.
+**/
+_PUBLIC_ char *smb_xstrdup(const char *s);
+
+char *smb_xstrndup(const char *s, size_t n);
+
+/**
+ Like strdup but for memory.
+**/
+_PUBLIC_ void *smb_memdup(const void *p, size_t size);
+
+/**
+ * see if a range of memory is all zero. A NULL pointer is considered
+ * to be all zero
+ */
+_PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size);
+
+/**
+ realloc an array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail);
+
+void *malloc_array(size_t el_size, unsigned int count);
+
+void *memalign_array(size_t el_size, size_t align, unsigned int count);
+
+void *calloc_array(size_t size, size_t nmemb);
+
+/* The following definitions come from lib/util/fsusage.c */
+
+
+/**
+ * Retrieve amount of free disk space.
+ * this does all of the system specific guff to get the free disk space.
+ * It is derived from code in the GNU fileutils package, but has been
+ * considerably mangled for use here
+ *
+ * results are returned in *dfree and *dsize, in 512 byte units
+*/
+_PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize);
+
+/* The following definitions come from lib/util/ms_fnmatch.c */
+
+
+/**
+ * @file
+ * @brief MS-style Filename matching
+ */
+
+int ms_fnmatch_protocol(const char *pattern, const char *string, int protocol,
+ bool is_case_sensitive);
+
+/** a generic fnmatch function - uses for non-CIFS pattern matching */
+int gen_fnmatch(const char *pattern, const char *string);
+
+#include "become_daemon.h"
+
+/**
+ * @brief Get a password from the console.
+ *
+ * You should make sure that the buffer is an empty string!
+ *
+ * You can also use this function to ask for a username. Then you can fill the
+ * buffer with the username and it is shows to the users. If the users just
+ * presses enter the buffer will be untouched.
+ *
+ * @code
+ * char username[128];
+ *
+ * snprintf(username, sizeof(username), "john");
+ *
+ * smb_getpass("Username:", username, sizeof(username), 1, 0);
+ * @endcode
+ *
+ * The prompt will look like this:
+ *
+ * Username: [john]
+ *
+ * If you press enter then john is used as the username, or you can type it in
+ * to change it.
+ *
+ * @param[in] prompt The prompt to show to ask for the password.
+ *
+ * @param[out] buf The buffer the password should be stored. It NEEDS to be
+ * empty or filled out.
+ *
+ * @param[in] len The length of the buffer.
+ *
+ * @param[in] echo Should we echo what you type.
+ *
+ * @param[in] verify Should we ask for the password twice.
+ *
+ * @return 0 on success, -1 on error.
+ */
+_PUBLIC_ int samba_getpass(const char *prompt, char *buf, size_t len,
+ bool echo, bool verify);
+
+/**
+ * Load a ini-style file.
+ */
+bool pm_process( const char *fileName,
+ bool (*sfunc)(const char *, void *),
+ bool (*pfunc)(const char *, const char *, void *),
+ void *userdata);
+bool pm_process_with_flags(const char *filename,
+ bool allow_empty_values,
+ bool (*sfunc)(const char *section, void *private_data),
+ bool (*pfunc)(const char *name, const char *value,
+ void *private_data),
+ void *private_data);
+
+void print_asc(int level, const uint8_t *buf,int len);
+void print_asc_cb(const uint8_t *buf, int len,
+ void (*cb)(const char *buf, void *private_data),
+ void *private_data);
+
+/**
+ * Add an id to an array of ids.
+ *
+ * num should be a pointer to an integer that holds the current
+ * number of elements in ids. It will be updated by this function.
+ */
+
+bool add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid,
+ uid_t **uids, uint32_t *num_uids);
+bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid,
+ gid_t **gids, uint32_t *num_gids);
+
+/**
+ * Allocate anonymous shared memory of the given size
+ */
+void *anonymous_shared_allocate(size_t bufsz);
+void *anonymous_shared_resize(void *ptr, size_t new_size, bool maymove);
+void anonymous_shared_free(void *ptr);
+
+/*
+ run a command as a child process, with a timeout.
+
+ any stdout/stderr from the child will appear in the Samba logs with
+ the specified log levels
+
+ If callback is set then the callback is called on completion
+ with the return code from the command
+ */
+struct tevent_context;
+struct tevent_req;
+struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval endtime,
+ int stdout_log_level,
+ int stderr_log_level,
+ const char * const *argv0, ...);
+int samba_runcmd_recv(struct tevent_req *req, int *perrno);
+int samba_runcmd_export_stdin(struct tevent_req *req);
+
+#ifdef DEVELOPER
+void samba_start_debugger(void);
+#endif
+
+/*
+ * Samba code should use samba_tevent_context_init() instead of
+ * tevent_context_init() in order to get the debug output.
+ */
+struct tevent_context *samba_tevent_context_init(TALLOC_CTX *mem_ctx);
+
+/*
+ * if same samba code needs to use a specific tevent backend
+ * it can use something like this:
+ *
+ * samba_tevent_set_debug(ev, "pysmb_tevent");
+ */
+void samba_tevent_set_debug(struct tevent_context *ev, const char *name);
+
+#endif /* _SAMBA_UTIL_H_ */
diff --git a/lib/util/select.c b/lib/util/select.c
new file mode 100644
index 0000000..dc79a27
--- /dev/null
+++ b/lib/util/select.c
@@ -0,0 +1,61 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba select/poll implementation
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "lib/util/select.h"
+#include "lib/util/time.h"
+
+int sys_poll_intr(struct pollfd *fds, int num_fds, int timeout)
+{
+ int orig_timeout = timeout;
+ struct timespec start;
+ int ret;
+
+ clock_gettime_mono(&start);
+
+ while (true) {
+ struct timespec now;
+ int64_t elapsed;
+
+ ret = poll(fds, num_fds, timeout);
+ if (ret != -1) {
+ break;
+ }
+ if (errno != EINTR) {
+ break;
+ }
+ /* Infinite timeout, no need to adjust. */
+ if (timeout < 0) {
+ continue;
+ }
+ clock_gettime_mono(&now);
+ elapsed = nsec_time_diff(&now, &start) / 1000000;
+ timeout = orig_timeout - elapsed;
+ /* Unlikely, but might happen eg. when getting traced.
+ * Make sure we're not hanging in this case.
+ */
+ if (timeout < 0) {
+ timeout = 0;
+ }
+ };
+ return ret;
+}
diff --git a/lib/util/select.h b/lib/util/select.h
new file mode 100644
index 0000000..fa1970e
--- /dev/null
+++ b/lib/util/select.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/Netbios implementation.
+ Samba select/poll implementation
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _select_h_
+#define _select_h_
+
+#include "system/select.h"
+
+/* The following definitions come from lib/util/select.c */
+
+int sys_poll_intr(struct pollfd *fds, int num_fds, int timeout);
+
+#endif
diff --git a/lib/util/server_id.c b/lib/util/server_id.c
new file mode 100644
index 0000000..690b9dd
--- /dev/null
+++ b/lib/util/server_id.c
@@ -0,0 +1,229 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "lib/util/server_id.h"
+#include "lib/util/byteorder.h"
+#include "librpc/gen_ndr/server_id.h"
+
+bool server_id_same_process(const struct server_id *p1,
+ const struct server_id *p2)
+{
+ return ((p1->pid == p2->pid) && (p1->vnn == p2->vnn));
+}
+
+int server_id_cmp(const struct server_id *p1, const struct server_id *p2)
+{
+ if (p1->vnn != p2->vnn) {
+ return (p1->vnn < p2->vnn) ? -1 : 1;
+ }
+ if (p1->pid != p2->pid) {
+ return (p1->pid < p2->pid) ? -1 : 1;
+ }
+ if (p1->task_id != p2->task_id) {
+ return (p1->task_id < p2->task_id) ? -1 : 1;
+ }
+ if (p1->unique_id != p2->unique_id) {
+ return (p1->unique_id < p2->unique_id) ? -1 : 1;
+ }
+ return 0;
+}
+
+bool server_id_equal(const struct server_id *p1, const struct server_id *p2)
+{
+ int cmp = server_id_cmp(p1, p2);
+ return (cmp == 0);
+}
+
+char *server_id_str_buf(struct server_id id, struct server_id_buf *dst)
+{
+ if (server_id_is_disconnected(&id)) {
+ strlcpy(dst->buf, "disconnected", sizeof(dst->buf));
+ } else if ((id.vnn == NONCLUSTER_VNN) && (id.task_id == 0)) {
+ snprintf(dst->buf, sizeof(dst->buf), "%llu",
+ (unsigned long long)id.pid);
+ } else if (id.vnn == NONCLUSTER_VNN) {
+ snprintf(dst->buf, sizeof(dst->buf), "%llu.%u",
+ (unsigned long long)id.pid, (unsigned)id.task_id);
+ } else if (id.task_id == 0) {
+ snprintf(dst->buf, sizeof(dst->buf), "%u:%llu",
+ (unsigned)id.vnn, (unsigned long long)id.pid);
+ } else {
+ snprintf(dst->buf, sizeof(dst->buf), "%u:%llu.%u",
+ (unsigned)id.vnn,
+ (unsigned long long)id.pid,
+ (unsigned)id.task_id);
+ }
+ return dst->buf;
+}
+
+size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen)
+{
+ struct server_id_buf idbuf;
+ char unique_buf[21]; /* 2^64 is 18446744073709551616, 20 chars */
+ size_t idlen, unique_len, needed;
+
+ server_id_str_buf(id, &idbuf);
+
+ idlen = strlen(idbuf.buf);
+ unique_len = snprintf(unique_buf, sizeof(unique_buf), "%"PRIu64,
+ id.unique_id);
+ needed = idlen + unique_len + 2;
+
+ if (buflen >= needed) {
+ memcpy(buf, idbuf.buf, idlen);
+ buf[idlen] = '/';
+ memcpy(buf + idlen + 1, unique_buf, unique_len+1);
+ }
+
+ return needed;
+}
+
+struct server_id server_id_from_string(uint32_t local_vnn,
+ const char *pid_string)
+{
+ struct server_id templ = {
+ .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX
+ };
+ struct server_id result;
+ int ret;
+
+ /*
+ * We accept various forms with 1, 2 or 3 component forms
+ * because the server_id_str_buf() can print different forms, and
+ * we want backwards compatibility for scripts that may call
+ * smbclient.
+ */
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64,
+ &result.vnn, &result.pid, &result.task_id,
+ &result.unique_id);
+ if (ret == 4) {
+ return result;
+ }
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32,
+ &result.vnn, &result.pid, &result.task_id);
+ if (ret == 3) {
+ return result;
+ }
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64,
+ &result.vnn, &result.pid, &result.unique_id);
+ if (ret == 3) {
+ return result;
+ }
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu32":%"SCNu64,
+ &result.vnn, &result.pid);
+ if (ret == 2) {
+ return result;
+ }
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64,
+ &result.pid, &result.task_id, &result.unique_id);
+ if (ret == 3) {
+ result.vnn = local_vnn;
+ return result;
+ }
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu64".%"SCNu32,
+ &result.pid, &result.task_id);
+ if (ret == 2) {
+ result.vnn = local_vnn;
+ return result;
+ }
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64,
+ &result.pid, &result.unique_id);
+ if (ret == 2) {
+ result.vnn = local_vnn;
+ return result;
+ }
+
+ result = templ;
+ ret = sscanf(pid_string, "%"SCNu64, &result.pid);
+ if (ret == 1) {
+ result.vnn = local_vnn;
+ return result;
+ }
+
+ if (strcmp(pid_string, "disconnected") == 0) {
+ server_id_set_disconnected(&result);
+ return result;
+ }
+
+ return templ;
+}
+
+/**
+ * Set the serverid to the special value that represents a disconnected
+ * client for (e.g.) durable handles.
+ */
+void server_id_set_disconnected(struct server_id *id)
+{
+ *id = (struct server_id) {
+ .pid = UINT64_MAX,
+ .task_id = UINT32_MAX,
+ .vnn = NONCLUSTER_VNN,
+ .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY,
+ };
+}
+
+/**
+ * check whether a serverid is the special placeholder for
+ * a disconnected client
+ */
+bool server_id_is_disconnected(const struct server_id *id)
+{
+ struct server_id dis;
+
+ SMB_ASSERT(id != NULL);
+
+ server_id_set_disconnected(&dis);
+
+ return server_id_equal(id, &dis);
+}
+
+void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH],
+ const struct server_id id)
+{
+ SBVAL(buf, 0, id.pid);
+ SIVAL(buf, 8, id.task_id);
+ SIVAL(buf, 12, id.vnn);
+ SBVAL(buf, 16, id.unique_id);
+}
+
+void server_id_get(struct server_id *id,
+ const uint8_t buf[SERVER_ID_BUF_LENGTH])
+{
+ id->pid = BVAL(buf, 0);
+ id->task_id = IVAL(buf, 8);
+ id->vnn = IVAL(buf, 12);
+ id->unique_id = BVAL(buf, 16);
+}
diff --git a/lib/util/server_id.h b/lib/util/server_id.h
new file mode 100644
index 0000000..5b723d5
--- /dev/null
+++ b/lib/util/server_id.h
@@ -0,0 +1,57 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIB_UTIL_SERVER_ID_H__
+#define __LIB_UTIL_SERVER_ID_H__
+
+#include "replace.h"
+
+struct server_id;
+
+struct server_id_buf { char buf[48]; }; /* probably a bit too large ... */
+
+bool server_id_same_process(const struct server_id *p1,
+ const struct server_id *p2);
+int server_id_cmp(const struct server_id *p1, const struct server_id *p2);
+bool server_id_equal(const struct server_id *p1, const struct server_id *p2);
+char *server_id_str_buf(struct server_id id, struct server_id_buf *dst);
+size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen);
+
+struct server_id server_id_from_string(uint32_t local_vnn,
+ const char *pid_string);
+
+/**
+ * Set the serverid to the special value that represents a disconnected
+ * client for (e.g.) durable handles.
+ */
+void server_id_set_disconnected(struct server_id *id);
+
+/**
+ * check whether a serverid is the special placeholder for
+ * a disconnected client
+ */
+bool server_id_is_disconnected(const struct server_id *id);
+
+#define SERVER_ID_BUF_LENGTH 24
+void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH],
+ const struct server_id id);
+void server_id_get(struct server_id *id,
+ const uint8_t buf[SERVER_ID_BUF_LENGTH]);
+
+#endif
diff --git a/lib/util/server_id_db.c b/lib/util/server_id_db.c
new file mode 100644
index 0000000..17b1577
--- /dev/null
+++ b/lib/util/server_id_db.c
@@ -0,0 +1,355 @@
+/*
+ * Map names to server_ids
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "lib/util/server_id.h"
+#include "lib/util/server_id_db.h"
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/strv.h"
+#include "lib/util/util_tdb.h"
+#include "lib/util/samba_util.h"
+
+static TDB_DATA talloc_tdb_data(void *ptr)
+{
+ return (TDB_DATA) { .dptr = ptr, .dsize = talloc_get_size(ptr) };
+}
+
+struct server_id_db {
+ struct server_id pid;
+ struct tdb_wrap *tdb;
+ char *names;
+};
+
+static int server_id_db_destructor(struct server_id_db *db);
+
+struct server_id_db *server_id_db_init(TALLOC_CTX *mem_ctx,
+ struct server_id pid,
+ const char *base_path,
+ int hash_size, int tdb_flags)
+{
+ struct server_id_db *db;
+ size_t pathlen = strlen(base_path) + 11;
+ char path[pathlen];
+
+ db = talloc(mem_ctx, struct server_id_db);
+ if (db == NULL) {
+ return NULL;
+ }
+ db->pid = pid;
+ db->names = NULL;
+
+ snprintf(path, pathlen, "%s/names.tdb", base_path);
+
+ db->tdb = tdb_wrap_open(db, path, hash_size, tdb_flags,
+ O_RDWR|O_CREAT, 0660);
+ if (db->tdb == NULL) {
+ TALLOC_FREE(db);
+ return NULL;
+ }
+
+ talloc_set_destructor(db, server_id_db_destructor);
+
+ return db;
+}
+
+void server_id_db_reinit(struct server_id_db *db, struct server_id pid)
+{
+ db->pid = pid;
+ TALLOC_FREE(db->names);
+}
+
+struct server_id server_id_db_pid(struct server_id_db *db)
+{
+ return db->pid;
+}
+
+static int server_id_db_destructor(struct server_id_db *db)
+{
+ char *name = NULL;
+
+ while ((name = strv_next(db->names, name)) != NULL) {
+ server_id_db_remove(db, name);
+ }
+
+ return 0;
+}
+
+int server_id_db_add(struct server_id_db *db, const char *name)
+{
+ struct tdb_context *tdb = db->tdb->tdb;
+ TDB_DATA key;
+ char *n;
+ int ret;
+
+ n = strv_find(db->names, name);
+ if (n != NULL) {
+ return EEXIST;
+ }
+
+ ret = strv_add(db, &db->names, name);
+ if (ret != 0) {
+ return ret;
+ }
+
+ key = string_term_tdb_data(name);
+
+ {
+ size_t idlen = server_id_str_buf_unique(db->pid, NULL, 0);
+ char idbuf[idlen];
+
+ server_id_str_buf_unique(db->pid, idbuf, idlen);
+
+ ret = tdb_append(
+ tdb, key,
+ (TDB_DATA) { .dptr = (uint8_t *)idbuf, .dsize = idlen });
+ }
+
+ if (ret != 0) {
+ enum TDB_ERROR err = tdb_error(tdb);
+ strv_delete(&db->names, strv_find(db->names, name));
+ return map_unix_error_from_tdb(err);
+ }
+
+ return 0;
+}
+
+int server_id_db_prune_name(struct server_id_db *db, const char *name,
+ struct server_id server)
+{
+ struct tdb_context *tdb = db->tdb->tdb;
+ size_t idbuf_len = server_id_str_buf_unique(server, NULL, 0);
+ char idbuf[idbuf_len];
+ TDB_DATA key;
+ uint8_t *data;
+ size_t datalen;
+ char *ids, *id;
+ int ret;
+
+ key = string_term_tdb_data(name);
+ server_id_str_buf_unique(server, idbuf, idbuf_len);
+
+ ret = tdb_chainlock(tdb, key);
+ if (ret == -1) {
+ enum TDB_ERROR err = tdb_error(tdb);
+ return map_unix_error_from_tdb(err);
+ }
+
+ ret = tdb_fetch_talloc(tdb, key, db, &data);
+ if (ret != 0) {
+ tdb_chainunlock(tdb, key);
+ return ret;
+ }
+
+ datalen = talloc_get_size(data);
+ if ((datalen == 0) || (data[datalen-1] != '\0')) {
+ tdb_chainunlock(tdb, key);
+ TALLOC_FREE(data);
+ return EINVAL;
+ }
+
+ ids = (char *)data;
+
+ id = strv_find(ids, idbuf);
+ if (id == NULL) {
+ tdb_chainunlock(tdb, key);
+ TALLOC_FREE(data);
+ return ENOENT;
+ }
+
+ strv_delete(&ids, id);
+
+ if (talloc_get_size(ids) == 0) {
+ ret = tdb_delete(tdb, key);
+ } else {
+ ret = tdb_store(tdb, key, talloc_tdb_data(ids), TDB_MODIFY);
+ }
+ TALLOC_FREE(data);
+
+ tdb_chainunlock(tdb, key);
+
+ if (ret == -1) {
+ enum TDB_ERROR err = tdb_error(tdb);
+ return map_unix_error_from_tdb(err);
+ }
+
+ return 0;
+}
+
+int server_id_db_remove(struct server_id_db *db, const char *name)
+{
+ char *n;
+ int ret;
+
+ n = strv_find(db->names, name);
+ if (n == NULL) {
+ return ENOENT;
+ }
+
+ ret = server_id_db_prune_name(db, name, db->pid);
+ if (ret != 0) {
+ return ret;
+ }
+
+ strv_delete(&db->names, n);
+ return 0;
+}
+
+int server_id_db_lookup(struct server_id_db *db, const char *name,
+ TALLOC_CTX *mem_ctx, unsigned *pnum_servers,
+ struct server_id **pservers)
+{
+ struct tdb_context *tdb = db->tdb->tdb;
+ TDB_DATA key;
+ uint8_t *data;
+ size_t datalen;
+ char *ids, *id;
+ unsigned num_servers;
+ struct server_id *servers;
+ int i, ret;
+
+ key = string_term_tdb_data(name);
+
+ ret = tdb_fetch_talloc(tdb, key, mem_ctx, &data);
+ if (ret != 0) {
+ return ret;
+ }
+
+ datalen = talloc_get_size(data);
+ if ((datalen == 0) || (data[datalen-1] != '\0')) {
+ TALLOC_FREE(data);
+ return EINVAL;
+ }
+
+ ids = (char *)data;
+ num_servers = strv_count(ids);
+
+ servers = talloc_array(mem_ctx, struct server_id, num_servers);
+ if (servers == NULL) {
+ TALLOC_FREE(data);
+ return ENOMEM;
+ }
+
+ i = 0;
+
+ for (id = ids; id != NULL; id = strv_next(ids, id)) {
+ servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
+ }
+
+ TALLOC_FREE(data);
+
+ *pnum_servers = num_servers;
+ *pservers = servers;
+
+ return 0;
+}
+
+bool server_id_db_lookup_one(struct server_id_db *db, const char *name,
+ struct server_id *server)
+{
+ int ret;
+ unsigned num_servers;
+ struct server_id *servers;
+
+ ret = server_id_db_lookup(db, name, db, &num_servers, &servers);
+ if (ret != 0) {
+ return false;
+ }
+ if (num_servers == 0) {
+ TALLOC_FREE(servers);
+ return false;
+ }
+ *server = servers[0];
+ TALLOC_FREE(servers);
+ return true;
+}
+
+struct server_id_db_traverse_state {
+ TALLOC_CTX *mem_ctx;
+ int (*fn)(const char *name,
+ unsigned num_servers,
+ const struct server_id *servers,
+ void *private_data);
+ void *private_data;
+};
+
+static int server_id_db_traverse_fn(struct tdb_context *tdb,
+ TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct server_id_db_traverse_state *state = private_data;
+ const char *name;
+ char *ids, *id;
+ unsigned num_servers;
+ struct server_id *servers;
+ int i, ret;
+
+ if (key.dsize == 0) {
+ return 0;
+ }
+ if (key.dptr[key.dsize-1] != '\0') {
+ return 0;
+ }
+ name = (const char *)key.dptr;
+
+ ids = (char *)talloc_memdup(state->mem_ctx, data.dptr, data.dsize);
+ if (ids == NULL) {
+ return 0;
+ }
+
+ num_servers = strv_count(ids);
+ servers = talloc_array(ids, struct server_id, num_servers);
+
+ i = 0;
+
+ for (id = ids; id != NULL; id = strv_next(ids, id)) {
+ servers[i++] = server_id_from_string(NONCLUSTER_VNN, id);
+ }
+
+ ret = state->fn(name, num_servers, servers, state->private_data);
+
+ TALLOC_FREE(ids);
+
+ return ret;
+}
+
+int server_id_db_traverse_read(struct server_id_db *db,
+ int (*fn)(const char *name,
+ unsigned num_servers,
+ const struct server_id *servers,
+ void *private_data),
+ void *private_data)
+{
+ struct server_id_db_traverse_state state;
+ int ret;
+
+ state = (struct server_id_db_traverse_state) {
+ .fn = fn, .private_data = private_data,
+ .mem_ctx = talloc_new(db)
+ };
+
+ if (state.mem_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = tdb_traverse_read(db->tdb->tdb, server_id_db_traverse_fn,
+ &state);
+ TALLOC_FREE(state.mem_ctx);
+ return ret;
+}
diff --git a/lib/util/server_id_db.h b/lib/util/server_id_db.h
new file mode 100644
index 0000000..2dcce62
--- /dev/null
+++ b/lib/util/server_id_db.h
@@ -0,0 +1,50 @@
+/*
+ * Namedb
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SERVER_ID_DB_H_
+#define _SERVER_ID_DB_H_
+
+#include "talloc.h"
+#include "librpc/gen_ndr/server_id.h"
+
+struct server_id_db;
+
+struct server_id_db *server_id_db_init(TALLOC_CTX *mem_ctx,
+ struct server_id pid,
+ const char *base_path,
+ int hash_size, int tdb_flags);
+void server_id_db_reinit(struct server_id_db *db, struct server_id pid);
+struct server_id server_id_db_pid(struct server_id_db *db);
+int server_id_db_add(struct server_id_db *db, const char *name);
+int server_id_db_remove(struct server_id_db *db, const char *name);
+int server_id_db_prune_name(struct server_id_db *db, const char *name,
+ struct server_id server);
+int server_id_db_lookup(struct server_id_db *db, const char *name,
+ TALLOC_CTX *mem_ctx, unsigned *num_servers,
+ struct server_id **servers);
+bool server_id_db_lookup_one(struct server_id_db *db, const char *name,
+ struct server_id *server);
+int server_id_db_traverse_read(struct server_id_db *db,
+ int (*fn)(const char *name,
+ unsigned num_servers,
+ const struct server_id *servers,
+ void *private_data),
+ void *private_data);
+
+#endif
diff --git a/lib/util/setid.c b/lib/util/setid.c
new file mode 100644
index 0000000..1001461
--- /dev/null
+++ b/lib/util/setid.c
@@ -0,0 +1,249 @@
+/*
+ Unix SMB/CIFS implementation.
+ setXXid() functions for Samba.
+ Copyright (C) Jeremy Allison 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef AUTOCONF_TEST
+#include "replace.h"
+#include "system/passwd.h"
+
+#include "../lib/util/setid.h"
+
+#else
+
+/* Inside autoconf test. */
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_PRIV_H
+#include <sys/priv.h>
+#endif
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
+#endif
+
+/* autoconf tests don't include setid.h */
+int samba_setresuid(uid_t ruid, uid_t euid, uid_t suid);
+int samba_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+int samba_setreuid(uid_t ruid, uid_t euid);
+int samba_setregid(gid_t rgid, gid_t egid);
+int samba_seteuid(uid_t euid);
+int samba_setegid(gid_t egid);
+int samba_setuid(uid_t uid);
+int samba_setgid(gid_t gid);
+int samba_setuidx(int flags, uid_t uid);
+int samba_setgidx(int flags, gid_t gid);
+int samba_setgroups(size_t setlen, const gid_t *gidset);
+
+#endif
+
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h>
+#endif
+
+#if defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h>
+#endif
+
+/* Ensure we can't compile in a mixed syscall setup. */
+#if !defined(USE_LINUX_32BIT_SYSCALLS)
+#if defined(SYS_setresuid32) || defined(SYS_setresgid32) || defined(SYS_setreuid32) || defined(SYS_setregid32) || defined(SYS_setuid32) || defined(SYS_setgid32) || defined(SYS_setgroups32)
+#error Mixture of 32-bit Linux system calls and 64-bit calls.
+#endif
+#endif
+
+#endif
+
+/* All the setXX[ug]id functions and setgroups Samba uses. */
+int samba_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ return syscall(SYS_setresuid32, ruid, euid, suid);
+#else
+ return syscall(SYS_setresuid, ruid, euid, suid);
+#endif
+#elif defined(HAVE_SETRESUID)
+ return setresuid(ruid, euid, suid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ return syscall(SYS_setresgid32, rgid, egid, sgid);
+#else
+ return syscall(SYS_setresgid, rgid, egid, sgid);
+#endif
+#elif defined(HAVE_SETRESGID)
+ return setresgid(rgid, egid, sgid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setreuid(uid_t ruid, uid_t euid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ return syscall(SYS_setreuid32, ruid, euid);
+#else
+ return syscall(SYS_setreuid, ruid, euid);
+#endif
+#elif defined(HAVE_SETREUID)
+ return setreuid(ruid, euid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setregid(gid_t rgid, gid_t egid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ return syscall(SYS_setregid32, rgid, egid);
+#else
+ return syscall(SYS_setregid, rgid, egid);
+#endif
+#elif defined(HAVE_SETREGID)
+ return setregid(rgid, egid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_seteuid(uid_t euid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ /* seteuid is not a separate system call. */
+ return syscall(SYS_setresuid32, -1, euid, -1);
+#else
+ /* seteuid is not a separate system call. */
+ return syscall(SYS_setresuid, -1, euid, -1);
+#endif
+#elif defined(HAVE_SETEUID)
+ return seteuid(euid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setegid(gid_t egid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ /* setegid is not a separate system call. */
+ return syscall(SYS_setresgid32, -1, egid, -1);
+#else
+ /* setegid is not a separate system call. */
+ return syscall(SYS_setresgid, -1, egid, -1);
+#endif
+#elif defined(HAVE_SETEGID)
+ return setegid(egid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setuid(uid_t uid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ return syscall(SYS_setuid32, uid);
+#else
+ return syscall(SYS_setuid, uid);
+#endif
+#elif defined(HAVE_SETUID)
+ return setuid(uid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setgid(gid_t gid)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ return syscall(SYS_setgid32, gid);
+#else
+ return syscall(SYS_setgid, gid);
+#endif
+#elif defined(HAVE_SETGID)
+ return setgid(gid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setuidx(int flags, uid_t uid)
+{
+#if defined(HAVE_SETUIDX)
+ return setuidx(flags, uid);
+#else
+ /* HAVE_LINUX_THREAD_CREDENTIALS doesn't have this. */
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setgidx(int flags, gid_t gid)
+{
+#if defined(HAVE_SETGIDX)
+ return setgidx(flags, gid);
+#else
+ /* HAVE_LINUX_THREAD_CREDENTIALS doesn't have this. */
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int samba_setgroups(size_t setlen, const gid_t *gidset)
+{
+#if defined(HAVE_LINUX_THREAD_CREDENTIALS)
+#if defined(USE_LINUX_32BIT_SYSCALLS)
+ return syscall(SYS_setgroups32, setlen, gidset);
+#else
+ return syscall(SYS_setgroups, setlen, gidset);
+#endif
+#elif defined(HAVE_SETGROUPS)
+ return setgroups(setlen, gidset);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
diff --git a/lib/util/setid.h b/lib/util/setid.h
new file mode 100644
index 0000000..59ae44c
--- /dev/null
+++ b/lib/util/setid.h
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+ setXXid() functions for Samba.
+ Copyright (C) Jeremy Allison 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SETID_H
+#define _SETID_H
+
+/*
+ * NB. We don't wrap initgroups although on some systems
+ * this can call setgroups. On systems with thread-specific
+ * credentials (Linux so far) we know they have getgrouplist()
+ * which doesn't make a system call.
+ */
+
+/* All the setXX[ug]id functions and setgroups Samba uses. */
+int samba_setresuid(uid_t ruid, uid_t euid, uid_t suid);
+int samba_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+int samba_setreuid(uid_t ruid, uid_t euid);
+int samba_setregid(gid_t rgid, gid_t egid);
+int samba_seteuid(uid_t euid);
+int samba_setegid(gid_t egid);
+int samba_setuid(uid_t uid);
+int samba_setgid(gid_t gid);
+int samba_setuidx(int flags, uid_t uid);
+int samba_setgidx(int flags, gid_t gid);
+int samba_setgroups(size_t setlen, const gid_t *gidset);
+
+#endif
diff --git a/lib/util/signal.c b/lib/util/signal.c
new file mode 100644
index 0000000..3fc63b2
--- /dev/null
+++ b/lib/util/signal.c
@@ -0,0 +1,146 @@
+/*
+ Unix SMB/CIFS implementation.
+ signal handling functions
+
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/wait.h"
+#include "debug.h"
+#include "lib/util/signal.h" /* Avoid /usr/include/signal.h */
+
+/**
+ * @file
+ * @brief Signal handling
+ */
+
+/****************************************************************************
+ Catch child exits and reap the child zombie status.
+****************************************************************************/
+
+static void sig_cld(int signum)
+{
+ while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
+ ;
+
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld);
+#endif
+}
+
+/****************************************************************************
+catch child exits - leave status;
+****************************************************************************/
+
+static void sig_cld_leave_status(int signum)
+{
+ /*
+ * Turns out it's *really* important not to
+ * restore the signal handler here if we have real POSIX
+ * signal handling. If we do, then we get the signal re-delivered
+ * immediately - hey presto - instant loop ! JRA.
+ */
+
+#if !defined(HAVE_SIGACTION)
+ CatchSignal(SIGCLD, sig_cld_leave_status);
+#endif
+}
+
+/**
+ Block sigs.
+**/
+
+void BlockSignals(bool block, int signum)
+{
+#ifdef HAVE_SIGPROCMASK
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,signum);
+ sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
+#elif defined(HAVE_SIGBLOCK)
+ if (block) {
+ sigblock(sigmask(signum));
+ } else {
+ sigsetmask(siggetmask() & ~sigmask(signum));
+ }
+#else
+ /* yikes! This platform can't block signals? */
+ static int done;
+ if (!done) {
+ DEBUG(0,("WARNING: No signal blocking available\n"));
+ done=1;
+ }
+#endif
+}
+
+/**
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+**/
+
+void (*CatchSignal(int signum,void (*handler)(int )))(int)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+ struct sigaction oldact;
+
+ ZERO_STRUCT(act);
+
+ act.sa_handler = handler;
+#ifdef SA_RESTART
+ /*
+ * We *want* SIGALRM to interrupt a system call.
+ */
+ if(signum != SIGALRM)
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,signum);
+ sigaction(signum,&act,&oldact);
+ return oldact.sa_handler;
+#else /* !HAVE_SIGACTION */
+ /* FIXME: need to handle sigvec and systems with broken signal() */
+ return signal(signum, handler);
+#endif
+}
+
+/**
+ Ignore SIGCLD via whatever means is necessary for this OS.
+**/
+
+void (*CatchChild(void))(int)
+{
+ return CatchSignal(SIGCLD, sig_cld);
+}
+
+/**
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+**/
+
+void (*CatchChildLeaveStatus(void))(int)
+{
+ return CatchSignal(SIGCLD, sig_cld_leave_status);
+}
diff --git a/lib/util/signal.h b/lib/util/signal.h
new file mode 100644
index 0000000..f662ee1
--- /dev/null
+++ b/lib/util/signal.h
@@ -0,0 +1,50 @@
+/*
+ Unix SMB/CIFS implementation.
+ signal handling functions
+
+ Copyright (C) Andrew Tridgell 1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_UTIL_SIGNAL_H_
+#define _SAMBA_UTIL_SIGNAL_H_
+
+#include <signal.h>
+#include <stdbool.h>
+
+/**
+ Block sigs.
+**/
+void BlockSignals(bool block, int signum);
+
+/**
+ Catch a signal. This should implement the following semantics:
+
+ 1) The handler remains installed after being called.
+ 2) The signal should be blocked during handler execution.
+**/
+void (*CatchSignal(int signum,void (*handler)(int )))(int);
+
+/**
+ Ignore SIGCLD via whatever means is necessary for this OS.
+**/
+void (*CatchChild(void))(int);
+
+/**
+ Catch SIGCLD but leave the child around so it's status can be reaped.
+**/
+void (*CatchChildLeaveStatus(void))(int);
+
+#endif /* _SAMBA_UTIL_SIGNAL_H_ */
diff --git a/lib/util/smb_strtox.c b/lib/util/smb_strtox.c
new file mode 100644
index 0000000..7a477dc
--- /dev/null
+++ b/lib/util/smb_strtox.c
@@ -0,0 +1,177 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Swen Schillig 2019
+ *
+ * ** NOTE! The following LGPL license applies to this file.
+ * ** This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "smb_strtox.h"
+
+/**
+ * Convert a string to an unsigned long integer
+ *
+ * @param nptr pointer to string which is to be converted
+ * @param endptr [optional] reference to remainder of the string
+ * @param base base of the numbering scheme
+ * @param err error occurred during conversion
+ * @flags controlling conversion feature
+ * @result result of the conversion as provided by strtoul
+ *
+ * The following flags are supported
+ * SMB_STR_STANDARD # raise error if negative or non-numeric
+ * SMB_STR_ALLOW_NEGATIVE # allow strings with a leading "-"
+ * SMB_STR_FULL_STR_CONV # entire string must be converted
+ * SMB_STR_ALLOW_NO_CONVERSION # allow empty strings or non-numeric
+ * SMB_STR_GLIBC_STANDARD # act exactly as the standard glibc strtoul
+ *
+ * The following errors are detected
+ * - wrong base
+ * - value overflow
+ * - string with a leading "-" indicating a negative number
+ * - no conversion due to empty string or not representing a number
+ */
+unsigned long int
+smb_strtoul(const char *nptr, char **endptr, int base, int *err, int flags)
+{
+ unsigned long int val;
+ int saved_errno = errno;
+ char *needle = NULL;
+ char *tmp_endptr = NULL;
+
+ errno = 0;
+ *err = 0;
+
+ val = strtoul(nptr, &tmp_endptr, base);
+
+ if (endptr != NULL) {
+ *endptr = tmp_endptr;
+ }
+
+ if (errno != 0) {
+ *err = errno;
+ errno = saved_errno;
+ return val;
+ }
+
+ if ((flags & SMB_STR_ALLOW_NO_CONVERSION) == 0) {
+ /* got an invalid number-string resulting in no conversion */
+ if (nptr == tmp_endptr) {
+ *err = EINVAL;
+ goto out;
+ }
+ }
+
+ if ((flags & SMB_STR_ALLOW_NEGATIVE ) == 0) {
+ /* did we convert a negative "number" ? */
+ needle = strchr(nptr, '-');
+ if (needle != NULL && needle < tmp_endptr) {
+ *err = EINVAL;
+ goto out;
+ }
+ }
+
+ if ((flags & SMB_STR_FULL_STR_CONV) != 0) {
+ /* did we convert the entire string ? */
+ if (tmp_endptr[0] != '\0') {
+ *err = EINVAL;
+ goto out;
+ }
+ }
+
+out:
+ errno = saved_errno;
+ return val;
+}
+
+/**
+ * Convert a string to an unsigned long long integer
+ *
+ * @param nptr pointer to string which is to be converted
+ * @param endptr [optional] reference to remainder of the string
+ * @param base base of the numbering scheme
+ * @param err error occurred during conversion
+ * @flags controlling conversion feature
+ * @result result of the conversion as provided by strtoull
+ *
+ * The following flags are supported
+ * SMB_STR_STANDARD # raise error if negative or non-numeric
+ * SMB_STR_ALLOW_NEGATIVE # allow strings with a leading "-"
+ * SMB_STR_FULL_STR_CONV # entire string must be converted
+ * SMB_STR_ALLOW_NO_CONVERSION # allow empty strings or non-numeric
+ * SMB_STR_GLIBC_STANDARD # act exactly as the standard glibc strtoul
+ *
+ * The following errors are detected
+ * - wrong base
+ * - value overflow
+ * - string with a leading "-" indicating a negative number
+ * - no conversion due to empty string or not representing a number
+ */
+unsigned long long int
+smb_strtoull(const char *nptr, char **endptr, int base, int *err, int flags)
+{
+ unsigned long long int val;
+ int saved_errno = errno;
+ char *needle = NULL;
+ char *tmp_endptr = NULL;
+
+ errno = 0;
+ *err = 0;
+
+ val = strtoull(nptr, &tmp_endptr, base);
+
+ if (endptr != NULL) {
+ *endptr = tmp_endptr;
+ }
+
+ if (errno != 0) {
+ *err = errno;
+ errno = saved_errno;
+ return val;
+ }
+
+ if ((flags & SMB_STR_ALLOW_NO_CONVERSION) == 0) {
+ /* got an invalid number-string resulting in no conversion */
+ if (nptr == tmp_endptr) {
+ *err = EINVAL;
+ goto out;
+ }
+ }
+
+ if ((flags & SMB_STR_ALLOW_NEGATIVE ) == 0) {
+ /* did we convert a negative "number" ? */
+ needle = strchr(nptr, '-');
+ if (needle != NULL && needle < tmp_endptr) {
+ *err = EINVAL;
+ goto out;
+ }
+ }
+
+ if ((flags & SMB_STR_FULL_STR_CONV) != 0) {
+ /* did we convert the entire string ? */
+ if (tmp_endptr[0] != '\0') {
+ *err = EINVAL;
+ goto out;
+ }
+ }
+
+out:
+ errno = saved_errno;
+ return val;
+}
diff --git a/lib/util/smb_strtox.h b/lib/util/smb_strtox.h
new file mode 100644
index 0000000..fcbedbe
--- /dev/null
+++ b/lib/util/smb_strtox.h
@@ -0,0 +1,40 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Swen Schillig 2019
+ *
+ * ** NOTE! The following LGPL license applies to this file.
+ * ** This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SMB_STRTOX_H
+#define SMB_STRTOX_H
+
+#define SMB_STR_STANDARD 0x00
+#define SMB_STR_ALLOW_NEGATIVE 0x01
+#define SMB_STR_FULL_STR_CONV 0x02
+#define SMB_STR_ALLOW_NO_CONVERSION 0x04
+#define SMB_STR_GLIBC_STANDARD (SMB_STR_ALLOW_NO_CONVERSION | \
+ SMB_STR_ALLOW_NEGATIVE)
+
+unsigned long int
+smb_strtoul(const char *nptr, char **endptr, int base, int *err, int flags);
+
+unsigned long long int
+smb_strtoull(const char *nptr, char **endptr, int base, int *err, int flags);
+
+#endif
diff --git a/lib/util/smb_threads.c b/lib/util/smb_threads.c
new file mode 100644
index 0000000..421dac9
--- /dev/null
+++ b/lib/util/smb_threads.c
@@ -0,0 +1,206 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client library implementation (thread interface functions).
+ Copyright (C) Jeremy Allison, 2009.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This code is based in the ideas in openssl
+ * but somewhat simpler and expended to include
+ * thread local storage.
+ */
+
+#include "replace.h"
+#include "smb_threads.h"
+#include "smb_threads_internal.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "lib/util/memory.h"
+
+/*********************************************************
+ Functions to vector the locking primitives used internally
+ by libsmbclient.
+*********************************************************/
+
+const struct smb_thread_functions *global_tfp;
+
+/*********************************************************
+ Dynamic lock array.
+*********************************************************/
+
+void **global_lock_array;
+
+/*********************************************************
+ Mutex used for our internal "once" function
+*********************************************************/
+
+static void *once_mutex = NULL;
+
+
+/*********************************************************
+ Function to set the locking primitives used by libsmbclient.
+*********************************************************/
+
+int smb_thread_set_functions(const struct smb_thread_functions *tf)
+{
+ int i;
+
+ global_tfp = tf;
+
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef malloc
+#undef malloc
+#endif
+#endif
+
+ /* Here we initialize any static locks we're using. */
+ global_lock_array = (void **)malloc(sizeof(void *) *NUM_GLOBAL_LOCKS);
+
+#if defined(PARANOID_MALLOC_CHECKER)
+#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+#endif
+
+ if (global_lock_array == NULL) {
+ return ENOMEM;
+ }
+
+ for (i = 0; i < NUM_GLOBAL_LOCKS; i++) {
+ char *name = NULL;
+ if (asprintf(&name, "global_lock_%d", i) == -1) {
+ SAFE_FREE(global_lock_array);
+ return ENOMEM;
+ }
+ if (global_tfp->create_mutex(name,
+ &global_lock_array[i],
+ __location__)) {
+ smb_panic("smb_thread_set_functions: create mutexes failed");
+ }
+ SAFE_FREE(name);
+ }
+
+ /* Create the mutex we'll use for our "once" function */
+ if (SMB_THREAD_CREATE_MUTEX("smb_once", once_mutex) != 0) {
+ smb_panic("smb_thread_set_functions: failed to create 'once' mutex");
+ }
+
+ return 0;
+}
+
+/*******************************************************************
+ Call a function only once. We implement this ourselves
+ using our own mutex rather than using the thread implementation's
+ *_once() function because each implementation has its own
+ type for the variable which keeps track of whether the function
+ has been called, and there's no easy way to allocate the correct
+ size variable in code internal to Samba without knowing the
+ implementation's "once" type.
+********************************************************************/
+
+int smb_thread_once(smb_thread_once_t *ponce,
+ void (*init_fn)(void *pdata),
+ void *pdata)
+{
+ int ret;
+
+ /* Lock our "once" mutex in order to test and initialize ponce */
+ if (SMB_THREAD_LOCK(once_mutex) != 0) {
+ smb_panic("error locking 'once'");
+ }
+
+ /* Keep track of whether we ran their init function */
+ ret = ! *ponce;
+
+ /*
+ * See if another thread got here after we tested it initially but
+ * before we got our lock.
+ */
+ if (! *ponce) {
+ /* Nope, we need to run the initialization function */
+ (*init_fn)(pdata);
+
+ /* Now we can indicate that the function has been run */
+ *ponce = true;
+ }
+
+ /* Unlock the mutex */
+ if (SMB_THREAD_UNLOCK(once_mutex) != 0) {
+ smb_panic("error unlocking 'once'");
+ }
+
+ /*
+ * Tell 'em whether we ran their init function. If they passed a data
+ * pointer to the init function and the init function could change
+ * something in the pointed-to data, this will tell them whether that
+ * data is valid or not.
+ */
+ return ret;
+}
+
+
+#if 0
+/* Test. - pthread implementations. */
+#include <pthread.h>
+
+#ifdef malloc
+#undef malloc
+#endif
+
+SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf);
+
+static smb_thread_once_t ot = SMB_THREAD_ONCE_INIT;
+void *pkey = NULL;
+
+static void init_fn(void)
+{
+ int ret;
+
+ if (!global_tfp) {
+ /* Non-thread safe init case. */
+ if (ot) {
+ return;
+ }
+ ot = true;
+ }
+
+ if ((ret = SMB_THREAD_CREATE_TLS("test_tls", pkey)) != 0) {
+ printf("Create tls once error: %d\n", ret);
+ }
+}
+
+/* Test function. */
+int test_threads(void)
+{
+ int ret;
+ void *plock = NULL;
+ smb_thread_set_functions(&tf);
+
+ SMB_THREAD_ONCE(&ot, init_fn);
+
+ if ((ret = SMB_THREAD_CREATE_MUTEX("test", plock)) != 0) {
+ printf("Create lock error: %d\n", ret);
+ }
+ if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_LOCK)) != 0) {
+ printf("lock error: %d\n", ret);
+ }
+ if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) {
+ printf("unlock error: %d\n", ret);
+ }
+ SMB_THREAD_DESTROY_MUTEX(plock);
+ SMB_THREAD_DESTROY_TLS(pkey);
+
+ return 0;
+}
+#endif
diff --git a/lib/util/smb_threads.h b/lib/util/smb_threads.h
new file mode 100644
index 0000000..67d05b8
--- /dev/null
+++ b/lib/util/smb_threads.h
@@ -0,0 +1,137 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB thread interface functions.
+ Copyright (C) Jeremy Allison, 2009.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _smb_threads_h_
+#define _smb_threads_h_
+
+typedef bool smb_thread_once_t;
+#define SMB_THREAD_ONCE_INIT false
+
+enum smb_thread_lock_type {
+ SMB_THREAD_LOCK = 1,
+ SMB_THREAD_UNLOCK
+};
+
+struct smb_thread_functions {
+ /* Mutex and tls functions. */
+ int (*create_mutex)(const char *lockname,
+ void **pplock,
+ const char *location);
+ void (*destroy_mutex)(void *plock,
+ const char *location);
+ int (*lock_mutex)(void *plock,
+ int lock_type,
+ const char *location);
+
+ /* Thread local storage. */
+ int (*create_tls)(const char *keyname,
+ void **ppkey,
+ const char *location);
+ void (*destroy_tls)(void **pkey,
+ const char *location);
+ int (*set_tls)(void *pkey, const void *pval, const char *location);
+ void *(*get_tls)(void *pkey, const char *location);
+};
+
+int smb_thread_set_functions(const struct smb_thread_functions *tf);
+int smb_thread_once(smb_thread_once_t *ponce,
+ void (*init_fn)(void *pdata),
+ void *pdata);
+
+extern const struct smb_thread_functions *global_tfp;
+
+/* Define the pthread version of the functions. */
+
+#define SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf) \
+ \
+static int smb_create_mutex_pthread(const char *lockname, void **pplock, const char *location) \
+{ \
+ pthread_mutex_t *pmut = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); \
+ if (!pmut) { \
+ return ENOMEM; \
+ } \
+ pthread_mutex_init(pmut, NULL); \
+ *pplock = (void *)pmut; \
+ return 0; \
+} \
+ \
+static void smb_destroy_mutex_pthread(void *plock, const char *location) \
+{ \
+ pthread_mutex_destroy((pthread_mutex_t *)plock); \
+ free(plock); \
+} \
+ \
+static int smb_lock_pthread(void *plock, int lock_type, const char *location) \
+{ \
+ if (lock_type == SMB_THREAD_UNLOCK) { \
+ return pthread_mutex_unlock((pthread_mutex_t *)plock); \
+ } else { \
+ return pthread_mutex_lock((pthread_mutex_t *)plock); \
+ } \
+} \
+ \
+static int smb_create_tls_pthread(const char *keyname, void **ppkey, const char *location) \
+{ \
+ int ret; \
+ pthread_key_t *pkey; \
+ pkey = (pthread_key_t *)malloc(sizeof(pthread_key_t)); \
+ if (!pkey) { \
+ return ENOMEM; \
+ } \
+ ret = pthread_key_create(pkey, NULL); \
+ if (ret) { \
+ free(pkey); \
+ return ret; \
+ } \
+ *ppkey = (void *)pkey; \
+ return 0; \
+} \
+ \
+static void smb_destroy_tls_pthread(void **ppkey, const char *location) \
+{ \
+ if (*ppkey) { \
+ pthread_key_delete(*(pthread_key_t *)ppkey); \
+ free(*ppkey); \
+ *ppkey = NULL; \
+ } \
+} \
+ \
+static int smb_set_tls_pthread(void *pkey, const void *pval, const char *location) \
+{ \
+ return pthread_setspecific(*(pthread_key_t *)pkey, pval); \
+} \
+ \
+static void *smb_get_tls_pthread(void *pkey, const char *location) \
+{ \
+ if (pkey == NULL) { \
+ return NULL; \
+ } \
+ return pthread_getspecific(*(pthread_key_t *)pkey); \
+} \
+ \
+static const struct smb_thread_functions (tf) = { \
+ smb_create_mutex_pthread, \
+ smb_destroy_mutex_pthread, \
+ smb_lock_pthread, \
+ smb_create_tls_pthread, \
+ smb_destroy_tls_pthread, \
+ smb_set_tls_pthread, \
+ smb_get_tls_pthread }
+
+#endif
diff --git a/lib/util/smb_threads_internal.h b/lib/util/smb_threads_internal.h
new file mode 100644
index 0000000..afd7559
--- /dev/null
+++ b/lib/util/smb_threads_internal.h
@@ -0,0 +1,74 @@
+/*
+ SMB/CIFS implementation.
+ SMB thread interface internal macros.
+ Copyright (C) Jeremy Allison, 2009.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _smb_threads_internal_h_
+#define _smb_threads_internal_h_
+
+#define SMB_THREAD_CREATE_MUTEX(name, lockvar) \
+ (global_tfp ? global_tfp->create_mutex((name), &(lockvar), __location__) : 0)
+
+#define SMB_THREAD_DESTROY_MUTEX(plock) \
+ do { \
+ if (global_tfp) { \
+ global_tfp->destroy_mutex(plock, __location__); \
+ }; \
+ } while (0)
+
+#define SMB_THREAD_LOCK_INTERNAL(plock, type, location) \
+ (global_tfp ? global_tfp->lock_mutex((plock), (type), location) : 0)
+
+#define SMB_THREAD_LOCK(plock) \
+ SMB_THREAD_LOCK_INTERNAL(plock, SMB_THREAD_LOCK, __location__)
+
+#define SMB_THREAD_UNLOCK(plock) \
+ SMB_THREAD_LOCK_INTERNAL(plock, SMB_THREAD_UNLOCK, __location__)
+
+#define SMB_THREAD_ONCE(ponce, init_fn, pdata) \
+ (global_tfp \
+ ? (! *(ponce) \
+ ? smb_thread_once((ponce), (init_fn), (pdata)) \
+ : 0) \
+ : ((init_fn(pdata)), *(ponce) = true, 1))
+
+#define SMB_THREAD_CREATE_TLS(keyname, key) \
+ (global_tfp ? global_tfp->create_tls((keyname), &(key), __location__) : 0)
+
+#define SMB_THREAD_DESTROY_TLS(key) \
+ do { \
+ if (global_tfp) { \
+ global_tfp->destroy_tls(&(key), __location__); \
+ }; \
+ } while (0)
+
+#define SMB_THREAD_SET_TLS(key, val) \
+ (global_tfp ? global_tfp->set_tls((key),(val),__location__) : \
+ ((key) = (val), 0))
+
+#define SMB_THREAD_GET_TLS(key) \
+ (global_tfp ? global_tfp->get_tls((key), __location__) : (key))
+
+/*
+ * Global thread lock list.
+ */
+
+#define NUM_GLOBAL_LOCKS 1
+
+#define GLOBAL_LOCK(locknum) (global_lock_array ? global_lock_array[(locknum)] : NULL)
+
+#endif
diff --git a/lib/util/stable_sort.c b/lib/util/stable_sort.c
new file mode 100644
index 0000000..47667c4
--- /dev/null
+++ b/lib/util/stable_sort.c
@@ -0,0 +1,250 @@
+/*
+ Stable sort routines
+
+ Copyright © Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+
+ ** NOTE! The following LGPL license applies to this file which is used by
+ ** the ldb library. This does NOT imply that all of Samba is released
+ ** under the LGPL.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <talloc.h>
+#include "replace.h"
+#include "stable_sort.h"
+
+static void sort_few(char *array, char *aux,
+ size_t n,
+ size_t s,
+ samba_compare_with_context_fn_t cmpfn,
+ void *opaque)
+{
+ /* a kind of insertion sort for small n. */
+ int i, j, dist;
+ int cmp;
+ char *a, *b;
+
+ for (i = 1; i < n; i++) {
+ a = &array[i * s];
+ /* leftwards is sorted. look until we find this one's place */
+ for (j = i - 1; j >= 0; j--) {
+ b = &array[j * s];
+ cmp = cmpfn(a, b, opaque);
+ if (cmp >= 0) {
+ break;
+ }
+ }
+ dist = i - 1 - j;
+ if (dist == 0) {
+ /* a is already in the right place */
+ continue;
+ }
+
+ b = &array[(i - dist) * s];
+ memcpy(aux, a, s);
+ memmove(b + s, b, s * dist);
+ memcpy(b, aux, s);
+ }
+}
+
+
+static void merge(char *dest,
+ char *a, size_t alen,
+ char *b, size_t blen,
+ size_t s,
+ samba_compare_with_context_fn_t cmpfn,
+ void *opaque)
+{
+ size_t ai = 0;
+ size_t bi = 0;
+ size_t di = 0;
+ while (ai < alen && bi < blen) {
+ int cmp = cmpfn(&a[ai * s], &b[bi * s], opaque);
+ if (cmp <= 0) {
+ memcpy(&dest[di * s], &a[ai * s], s);
+ ai++;
+ } else {
+ memcpy(&dest[di * s], &b[bi * s], s);
+ bi++;
+ }
+ di++;
+ }
+ if (ai < alen) {
+ memcpy(&dest[di * s], &a[ai * s], s * (alen - ai));
+ } else if (bi < blen) {
+ memcpy(&dest[di * s], &b[bi * s], s * (blen - bi));
+ }
+}
+
+
+bool stable_sort_r(void *array, void *aux,
+ size_t n,
+ size_t s,
+ samba_compare_with_context_fn_t cmpfn,
+ void * opaque)
+{
+ char *src = array, *dest = aux, *tmp = NULL;
+ size_t i, j, k;
+ size_t runsize;
+ if (array == NULL || aux == NULL) {
+ return false;
+ }
+
+ if (n < 20) {
+ sort_few(array, aux, n, s, cmpfn, opaque);
+ return true;
+ }
+
+ if (n > SIZE_MAX / s) {
+ /*
+ * We will have an integer overflow if we continue.
+ *
+ * This means that the *supposed* size of the allocated buffer
+ * is greater than SIZE_MAX, which is not possible in theory
+ * or practice, and is a sign the caller has got very
+ * confused.
+ */
+ return false;
+ }
+
+ /*
+ * This is kind of a bottom-up merge sort.
+ *
+ * We start but sorting into a whole lot of little runs, using an
+ * insertion sort which is efficient for small numbers. Empirically,
+ * on 2 machines, a run size of around 8 seems optimal, but the peak
+ * is wide, and it seems worth adapting the size to avoid an
+ * unbalanced final merge at the top. That is, if we pick the right
+ * runsize now, we will finish with a merge of roughly n/2:n/2, and
+ * not have to follow that with an merge of roughly n:[a few], which
+ * we would sometimes do with a fixed size at the lowest level.
+ *
+ * The aim is a runsize of n / (a power of 2) rounded up, in the
+ * target range.
+ */
+
+ runsize = n;
+ while (runsize > 10) {
+ runsize++;
+ runsize >>= 1;
+ }
+
+ for (i = 0; i < n; i += runsize) {
+ size_t nn = MIN(n - i, runsize);
+ sort_few(&src[i * s], aux, nn, s, cmpfn, opaque);
+ }
+
+ while (runsize < n) {
+ for (i = 0; i < n; i += runsize * 2) {
+ j = i + runsize;
+ if (j >= n) {
+ /*
+ * first run doesn't fit, meaning this chunk
+ * is already sorted. We just need to copy
+ * it.
+ */
+ size_t nn = n - i;
+ memcpy(&dest[i * s], &src[i * s], nn * s);
+ break;
+ }
+ k = j + runsize;
+ if (k > n) {
+ merge(&dest[i * s],
+ &src[i * s], runsize,
+ &src[j * s], n - j,
+ s,
+ cmpfn, opaque);
+ } else {
+ merge(&dest[i * s],
+ &src[i * s], runsize,
+ &src[j * s], runsize,
+ s,
+ cmpfn, opaque);
+ }
+ }
+
+ tmp = src;
+ src = dest;
+ dest = tmp;
+ runsize *= 2;
+ }
+ /*
+ * We have sorted the array into src, which is either array or aux.
+ */
+ if (src != array) {
+ memcpy(array, src, n * s);
+ }
+ return true;
+}
+
+
+
+/*
+ * A wrapper that allocates (and frees) the temporary buffer if necessary.
+ *
+ * returns false on allocation error, true otherwise.
+ */
+
+bool stable_sort_talloc_r(TALLOC_CTX *mem_ctx,
+ void *array,
+ size_t n,
+ size_t s,
+ samba_compare_with_context_fn_t cmpfn,
+ void *opaque)
+{
+ bool ok;
+ char *mem = talloc_array_size(mem_ctx, s, n);
+ if (mem == NULL) {
+ return false;
+ }
+ ok = stable_sort_r(array, mem, n, s, cmpfn, opaque);
+ talloc_free(mem);
+ return ok;
+}
+
+
+bool stable_sort(void *array, void *aux,
+ size_t n,
+ size_t s,
+ samba_compare_fn_t cmpfn)
+{
+ /*
+ * What is this magic, casting cmpfn into a different type that takes
+ * an extra parameter? Is that allowed?
+ *
+ * A: Yes. It's fine. The extra argument will be passed on the stack
+ * or (more likely) a register, and the cmpfn will remain blissfully
+ * unaware.
+ */
+ return stable_sort_r(array, aux, n, s,
+ (samba_compare_with_context_fn_t)cmpfn,
+ NULL);
+}
+
+
+bool stable_sort_talloc(TALLOC_CTX *mem_ctx,
+ void *array,
+ size_t n,
+ size_t s,
+ samba_compare_fn_t cmpfn)
+{
+ return stable_sort_talloc_r(mem_ctx, array, n, s,
+ (samba_compare_with_context_fn_t)cmpfn,
+ NULL);
+}
diff --git a/lib/util/stable_sort.h b/lib/util/stable_sort.h
new file mode 100644
index 0000000..17329b8
--- /dev/null
+++ b/lib/util/stable_sort.h
@@ -0,0 +1,46 @@
+#ifndef HAVE_STABLE_SORT_H
+#define HAVE_STABLE_SORT_H 1
+
+#ifdef __COMPAR_FN_T
+typedef __compar_fn_t samba_compare_fn_t;
+
+#ifdef __USE_GNU
+/* glibc defines __compar_d_fn_t for qsort_r */
+typedef __compar_d_fn_t samba_compare_with_context_fn_t;
+#endif
+
+#else
+typedef int (*samba_compare_fn_t) (const void *, const void *);
+typedef int (*samba_compare_with_context_fn_t) (const void *, const void *, void *);
+#endif
+
+
+
+bool stable_sort_r(void *array, void *aux,
+ size_t n,
+ size_t s,
+ samba_compare_with_context_fn_t cmpfn,
+ void *opaque);
+
+bool stable_sort(void *array, void *aux,
+ size_t n,
+ size_t s,
+ samba_compare_fn_t cmpfn);
+
+
+bool stable_sort_talloc_r(TALLOC_CTX *mem_ctx,
+ void *array,
+ size_t n,
+ size_t s,
+ samba_compare_with_context_fn_t cmpfn,
+ void *opaque);
+
+
+bool stable_sort_talloc(TALLOC_CTX *mem_ctx,
+ void *array,
+ size_t n,
+ size_t s,
+ samba_compare_fn_t cmpfn);
+
+
+#endif /* HAVE_STABLE_SORT_H */
diff --git a/lib/util/string_wrappers.h b/lib/util/string_wrappers.h
new file mode 100644
index 0000000..7625cd0
--- /dev/null
+++ b/lib/util/string_wrappers.h
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ string wrappers, for checking string sizes
+
+ Copyright (C) Andrew Tridgell 1994-2011
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _STRING_WRAPPERS_H
+#define _STRING_WRAPPERS_H
+
+#include "lib/replace/replace.h" /* for config symbols */
+
+#define strlcpy_base(dest, src, base, size) \
+do { \
+ const char *_strlcpy_base_src = (const char *)src; \
+ strlcpy((dest), _strlcpy_base_src? _strlcpy_base_src : "", (size)-PTR_DIFF((dest),(base))); \
+} while (0)
+
+/* String copy functions - macro hell below adds 'type checking' (limited,
+ but the best we can do in C) */
+
+#define fstrcpy(d,s) \
+do { \
+ const char *_fstrcpy_src = (const char *)(s); \
+ strlcpy((d),_fstrcpy_src ? _fstrcpy_src : "",sizeof(fstring)); \
+} while (0)
+
+#define fstrcat(d,s) \
+do { \
+ const char *_fstrcat_src = (const char *)(s); \
+ strlcat((d),_fstrcat_src ? _fstrcat_src : "",sizeof(fstring)); \
+} while (0)
+#define unstrcpy(d,s) \
+do { \
+ const char *_unstrcpy_src = (const char *)(s); \
+ strlcpy((d),_unstrcpy_src ? _unstrcpy_src : "",sizeof(unstring)); \
+} while (0)
+
+#ifdef HAVE_COMPILER_WILL_OPTIMIZE_OUT_FNS
+
+/* We need a number of different prototypes for our
+ non-existent functions */
+char * __unsafe_string_function_usage_here__(void);
+
+size_t __unsafe_string_function_usage_here_size_t__(void);
+
+NTSTATUS __unsafe_string_function_usage_here_NTSTATUS__(void);
+
+#define CHECK_STRING_SIZE(d, len) (sizeof(d) != (len) && sizeof(d) != sizeof(char *))
+
+/* if the compiler will optimize out function calls, then use this to tell if we are
+ have the correct types (this works only where sizeof() returns the size of the buffer, not
+ the size of the pointer). */
+
+#define push_string_check(dest, src, dest_len, flags) \
+ (CHECK_STRING_SIZE(dest, dest_len) \
+ ? __unsafe_string_function_usage_here_size_t__() \
+ : push_string_check_fn(dest, src, dest_len, flags))
+
+#define srvstr_push(base_ptr, smb_flags2, dest, src, dest_len, flags, ret_len) \
+ (CHECK_STRING_SIZE(dest, dest_len) \
+ ? __unsafe_string_function_usage_here_NTSTATUS__() \
+ : srvstr_push_fn(base_ptr, smb_flags2, dest, src, dest_len, flags, ret_len))
+
+/* This allows the developer to choose to check the arguments to
+ strlcpy. if the compiler will optimize out function calls, then
+ use this to tell if we are have the correct size buffer (this works only
+ where sizeof() returns the size of the buffer, not the size of the
+ pointer), so stack and static variables only */
+
+#define checked_strlcpy(dest, src, size) \
+ (sizeof(dest) != (size) \
+ ? __unsafe_string_function_usage_here_size_t__() \
+ : strlcpy(dest, src, size))
+
+#else
+
+#define push_string_check push_string_check_fn
+#define srvstr_push srvstr_push_fn
+#define checked_strlcpy strlcpy
+
+#endif
+
+#endif
diff --git a/lib/util/strv.c b/lib/util/strv.c
new file mode 100644
index 0000000..83d84d9
--- /dev/null
+++ b/lib/util/strv.c
@@ -0,0 +1,191 @@
+/*
+ * String Vector functions modeled after glibc argv_* functions
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "strv.h"
+#include "talloc.h"
+#include <string.h>
+
+static int _strv_append(TALLOC_CTX *mem_ctx, char **dst, const char *src,
+ size_t srclen)
+{
+ size_t dstlen = talloc_array_length(*dst);
+ size_t newlen = dstlen + srclen;
+ char *new_dst;
+
+ if ((newlen < srclen) || (newlen < dstlen)) {
+ return ERANGE;
+ }
+
+ new_dst = talloc_realloc(mem_ctx, *dst, char, newlen);
+ if (new_dst == NULL) {
+ return ENOMEM;
+ }
+ memcpy(&new_dst[dstlen], src, srclen);
+
+ *dst = new_dst;
+ return 0;
+}
+
+int strv_add(TALLOC_CTX *mem_ctx, char **strv, const char *string)
+{
+ return _strv_append(mem_ctx, strv, string, strlen(string)+1);
+}
+
+int strv_addn(TALLOC_CTX *mem_ctx, char **strv, const char *string, size_t n)
+{
+ char t[n+1];
+
+ memcpy(t, string, n);
+ t[n] = '\0';
+ return _strv_append(mem_ctx, strv, t, n+1);
+}
+
+int strv_append(TALLOC_CTX *mem_ctx, char **strv, const char *src)
+{
+ return _strv_append(mem_ctx, strv, src, talloc_array_length(src));
+}
+
+static bool strv_valid_entry(const char *strv, size_t strv_len,
+ const char *entry, size_t *entry_len)
+{
+ if (strv_len == 0) {
+ return false;
+ }
+ if (strv[strv_len-1] != '\0') {
+ return false;
+ }
+
+ if (entry < strv) {
+ return false;
+ }
+ if (entry >= (strv+strv_len)) {
+ return false;
+ }
+
+ if (entry_len != NULL) {
+ *entry_len = strlen(entry);
+ }
+
+ return true;
+}
+
+const char *strv_len_next(const char *strv, size_t strv_len,
+ const char *entry)
+{
+ size_t entry_len;
+
+ if (entry == NULL) {
+ if (strv_valid_entry(strv, strv_len, strv, NULL)) {
+ return strv;
+ }
+ return NULL;
+ }
+
+ if (!strv_valid_entry(strv, strv_len, entry, &entry_len)) {
+ return NULL;
+ }
+
+ entry += entry_len+1;
+
+ if (entry >= (strv + strv_len)) {
+ return NULL;
+ }
+ return entry;
+}
+
+char *strv_next(char *strv, const char *entry)
+{
+ size_t len = talloc_array_length(strv);
+ const char *result;
+
+ result = strv_len_next(strv, len, entry);
+ return discard_const_p(char, result);
+}
+
+size_t strv_count(char *strv)
+{
+ char *entry;
+ size_t count = 0;
+
+ for (entry = strv; entry != NULL; entry = strv_next(strv, entry)) {
+ count += 1;
+ }
+
+ return count;
+}
+
+char *strv_find(char *strv, const char *entry)
+{
+ char *e = NULL;
+
+ while ((e = strv_next(strv, e)) != NULL) {
+ if (strcmp(e, entry) == 0) {
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+void strv_delete(char **strv, char *entry)
+{
+ size_t len = talloc_array_length(*strv);
+ size_t entry_len;
+
+ if (entry == NULL) {
+ return;
+ }
+
+ if (!strv_valid_entry(*strv, len, entry, &entry_len)) {
+ return;
+ }
+ entry_len += 1;
+
+ memmove(entry, entry+entry_len,
+ len - entry_len - (entry - *strv));
+
+ *strv = talloc_realloc(NULL, *strv, char, len - entry_len);
+}
+
+char * const *strv_to_env(TALLOC_CTX *mem_ctx, char *strv)
+{
+ char **data;
+ char *next = NULL;
+ size_t i;
+ size_t count = strv_count(strv);
+
+ if (strv == NULL) {
+ return NULL;
+ }
+
+ data = talloc_array(mem_ctx, char *, count + 1);
+
+ if (data == NULL) {
+ return NULL;
+ }
+
+ for(i = 0; i < count; i++) {
+ next = strv_next(strv, next);
+ data[i] = next;
+ }
+ data[count] = NULL;
+
+ return data;
+}
diff --git a/lib/util/strv.h b/lib/util/strv.h
new file mode 100644
index 0000000..a6197e5
--- /dev/null
+++ b/lib/util/strv.h
@@ -0,0 +1,37 @@
+/*
+ * String Vector functions modeled after glibc argv_* functions
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _STRV_H_
+#define _STRV_H_
+
+#include "replace.h"
+#include <talloc.h>
+
+int strv_add(TALLOC_CTX *mem_ctx, char **strv, const char *string);
+int strv_addn(TALLOC_CTX *mem_ctx, char **strv, const char *src, size_t srclen);
+int strv_append(TALLOC_CTX *mem_ctx, char **strv, const char *src);
+char *strv_next(char *strv, const char *entry);
+const char *strv_len_next(const char *strv, size_t strv_len,
+ const char *entry);
+char *strv_find(char *strv, const char *entry);
+size_t strv_count(char *strv);
+void strv_delete(char **strv, char *entry);
+char * const *strv_to_env(TALLOC_CTX *mem_ctx, char *strv);
+
+#endif
diff --git a/lib/util/strv_util.c b/lib/util/strv_util.c
new file mode 100644
index 0000000..9da3eb2
--- /dev/null
+++ b/lib/util/strv_util.c
@@ -0,0 +1,61 @@
+/*
+ * strv-based utilities
+ *
+ * Copyright Martin Schwenke <martin@meltin.net> 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+
+#include <string.h>
+#include <talloc.h>
+
+#include "strv.h"
+
+#include "strv_util.h"
+
+int strv_split(TALLOC_CTX *mem_ctx, char **strv,
+ const char *src, const char *sep)
+{
+ const char *s;
+
+ if (src == NULL) {
+ return 0;
+ }
+
+ s = src;
+ while (*s != '\0') {
+ size_t len;
+
+ /* Skip separators */
+ len = strspn(s, sep);
+ if (len != 0) {
+ s += len;
+ }
+
+ /* Find non-separator substring */
+ len = strcspn(s, sep);
+ if (len != 0) {
+ int ret = strv_addn(mem_ctx, strv, s, len);
+ if (ret != 0) {
+ TALLOC_FREE(*strv);
+ return ret;
+ }
+ s += len;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/util/strv_util.h b/lib/util/strv_util.h
new file mode 100644
index 0000000..9456d43
--- /dev/null
+++ b/lib/util/strv_util.h
@@ -0,0 +1,30 @@
+/*
+ * strv-based utilities
+ *
+ * Copyright Martin Schwenke <martin@meltin.net> 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _STRV_UTIL_H_
+#define _STRV_UTIL_H_
+
+#include <talloc.h>
+
+/* Split string at characters in sep, adding non-separator words to
+ * *strv. On failure *strv is undefined. */
+int strv_split(TALLOC_CTX *mem_ctx, char **strv,
+ const char *string, const char *sep);
+
+#endif
diff --git a/lib/util/substitute.c b/lib/util/substitute.c
new file mode 100644
index 0000000..b7b5588
--- /dev/null
+++ b/lib/util/substitute.c
@@ -0,0 +1,280 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "debug.h"
+#ifndef SAMBA_UTIL_CORE_ONLY
+#include "charset/charset.h"
+#else
+#include "charset_compat.h"
+#endif
+#include "substitute.h"
+
+/**
+ * @file
+ * @brief Substitute utilities.
+ **/
+
+/**
+ Substitute a string for a pattern in another string. Make sure there is
+ enough room!
+
+ This routine looks for pattern in s and replaces it with
+ insert. It may do multiple replacements or just one.
+
+ Any of " ; ' $ or ` in the insert string are replaced with _
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+static void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
+ bool remove_unsafe_characters, bool replace_once,
+ bool allow_trailing_dollar)
+{
+ char *p;
+ size_t ls, lp, li, i;
+
+ if (!insert || !pattern || !*pattern || !s)
+ return;
+
+ ls = strlen(s);
+ lp = strlen(pattern);
+ li = strlen(insert);
+
+ if (len == 0)
+ len = ls + 1; /* len is number of *bytes* */
+
+ while (lp <= ls && (p = strstr_m(s,pattern))) {
+ if (ls + li - lp >= len) {
+ DBG_ERR("ERROR: string overflow by "
+ "%zu in string_sub(%.50s, %zu)\n",
+ ls + li - lp + 1 - len,
+ pattern,
+ len);
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ for (i=0;i<li;i++) {
+ switch (insert[i]) {
+ case '$':
+ /* allow a trailing $
+ * (as in machine accounts) */
+ if (allow_trailing_dollar && (i == li - 1 )) {
+ p[i] = insert[i];
+ break;
+ }
+ FALL_THROUGH;
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '%':
+ case '\r':
+ case '\n':
+ if ( remove_unsafe_characters ) {
+ p[i] = '_';
+ /* yes this break should be here
+ * since we want to fall throw if
+ * not replacing unsafe chars */
+ break;
+ }
+ FALL_THROUGH;
+ default:
+ p[i] = insert[i];
+ }
+ }
+ s = p + li;
+ ls = ls + li - lp;
+
+ if (replace_once)
+ break;
+ }
+}
+
+void string_sub(char *s,const char *pattern, const char *insert, size_t len)
+{
+ string_sub2( s, pattern, insert, len, true, false, false );
+}
+
+/**
+ Similar to string_sub() but allows for any character to be substituted.
+ Use with caution!
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+
+_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
+{
+ char *p;
+ size_t ls,lp,li;
+
+ if (!insert || !pattern || !s)
+ return;
+
+ ls = strlen(s);
+ lp = strlen(pattern);
+ li = strlen(insert);
+
+ if (!*pattern)
+ return;
+
+ if (len == 0)
+ len = ls + 1; /* len is number of *bytes* */
+
+ while (lp <= ls && (p = strstr_m(s,pattern))) {
+ if (ls + li - lp >= len) {
+ DBG_ERR("ERROR: string overflow by "
+ "%zu in all_string_sub(%.50s, %zu)\n",
+ ls + li - lp + 1 - len,
+ pattern,
+ len);
+ break;
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, insert, li);
+ s = p + li;
+ ls = ls + li - lp;
+ }
+}
+
+/*
+ * Internal guts of talloc_string_sub and talloc_all_string_sub.
+ * talloc version of string_sub2.
+ */
+
+char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
+ const char *pattern,
+ const char *insert,
+ bool remove_unsafe_characters,
+ bool replace_once,
+ bool allow_trailing_dollar)
+{
+ char *p, *in;
+ char *s;
+ char *string;
+ ssize_t ls,lp,li,ld, i;
+
+ if (!insert || !pattern || !*pattern || !src) {
+ return NULL;
+ }
+
+ string = talloc_strdup(mem_ctx, src);
+ if (string == NULL) {
+ DEBUG(0, ("talloc_string_sub2: "
+ "talloc_strdup failed\n"));
+ return NULL;
+ }
+
+ s = string;
+
+ in = talloc_strdup(mem_ctx, insert);
+ if (!in) {
+ DEBUG(0, ("talloc_string_sub2: ENOMEM\n"));
+ talloc_free(string);
+ return NULL;
+ }
+ ls = (ssize_t)strlen(s);
+ lp = (ssize_t)strlen(pattern);
+ li = (ssize_t)strlen(insert);
+ ld = li - lp;
+
+ for (i=0;i<li;i++) {
+ switch (in[i]) {
+ case '$':
+ /* allow a trailing $
+ * (as in machine accounts) */
+ if (allow_trailing_dollar && (i == li - 1 )) {
+ break;
+ }
+
+ FALL_THROUGH;
+ case '`':
+ case '"':
+ case '\'':
+ case ';':
+ case '%':
+ case '\r':
+ case '\n':
+ if (remove_unsafe_characters) {
+ in[i] = '_';
+ break;
+ }
+
+ FALL_THROUGH;
+ default:
+ /* ok */
+ break;
+ }
+ }
+
+ while ((p = strstr_m(s,pattern))) {
+ if (ld > 0) {
+ int offset = PTR_DIFF(s,string);
+ string = (char *)talloc_realloc_size(mem_ctx, string,
+ ls + ld + 1);
+ if (!string) {
+ DEBUG(0, ("talloc_string_sub: out of "
+ "memory!\n"));
+ TALLOC_FREE(in);
+ return NULL;
+ }
+ p = string + offset + (p - s);
+ }
+ if (li != lp) {
+ memmove(p+li,p+lp,strlen(p+lp)+1);
+ }
+ memcpy(p, in, li);
+ s = p + li;
+ ls += ld;
+
+ if (replace_once) {
+ break;
+ }
+ }
+ TALLOC_FREE(in);
+ return string;
+}
+
+/* Same as string_sub, but returns a talloc'ed string */
+
+char *talloc_string_sub(TALLOC_CTX *mem_ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert)
+{
+ return talloc_string_sub2(mem_ctx, src, pattern, insert,
+ true, false, false);
+}
+
+char *talloc_all_string_sub(TALLOC_CTX *ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert)
+{
+ return talloc_string_sub2(ctx, src, pattern, insert,
+ false, false, false);
+}
diff --git a/lib/util/substitute.h b/lib/util/substitute.h
new file mode 100644
index 0000000..3134cfc
--- /dev/null
+++ b/lib/util/substitute.h
@@ -0,0 +1,64 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_SUBSTITUTE_H_
+#define _SAMBA_SUBSTITUTE_H_
+
+#include <talloc.h>
+
+/**
+ Substitute a string for a pattern in another string. Make sure there is
+ enough room!
+
+ This routine looks for pattern in s and replaces it with
+ insert. It may do multiple replacements.
+
+ Any of " ; ' $ or ` in the insert string are replaced with _
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+void string_sub(char *s,const char *pattern, const char *insert, size_t len);
+
+/**
+ Similar to string_sub() but allows for any character to be substituted.
+ Use with caution!
+ if len==0 then the string cannot be extended. This is different from the old
+ use of len==0 which was for no length checks to be done.
+**/
+void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
+
+char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
+ const char *pattern,
+ const char *insert,
+ bool remove_unsafe_characters,
+ bool replace_once,
+ bool allow_trailing_dollar);
+char *talloc_string_sub(TALLOC_CTX *mem_ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert);
+char *talloc_all_string_sub(TALLOC_CTX *ctx,
+ const char *src,
+ const char *pattern,
+ const char *insert);
+#endif /* _SAMBA_SUBSTITUTE_H_ */
diff --git a/lib/util/sys_popen.c b/lib/util/sys_popen.c
new file mode 100644
index 0000000..f62199b
--- /dev/null
+++ b/lib/util/sys_popen.c
@@ -0,0 +1,177 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Jeremy Allison 2000
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+#include <talloc.h>
+#include "lib/util/sys_popen.h"
+#include "lib/util/debug.h"
+
+/**************************************************************************
+ Wrapper for popen. Safer as it doesn't search a path.
+ Modified from the glibc sources.
+ modified by tridge to return a file descriptor. We must kick our FILE* habit
+****************************************************************************/
+
+typedef struct _popen_list
+{
+ int fd;
+ pid_t child_pid;
+ struct _popen_list *next;
+} popen_list;
+
+static popen_list *popen_chain;
+
+int sys_popenv(char * const argl[])
+{
+ int parent_end, child_end;
+ int pipe_fds[2];
+ popen_list *entry = NULL;
+ const char *command = NULL;
+ int ret;
+
+ if (argl == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ command = argl[0];
+
+ if (!*command) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = pipe(pipe_fds);
+ if (ret < 0) {
+ DBG_ERR("error opening pipe: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ parent_end = pipe_fds[0];
+ child_end = pipe_fds[1];
+
+ entry = talloc_zero(NULL, popen_list);
+ if (entry == NULL) {
+ DBG_ERR("talloc failed\n");
+ goto err_exit;
+ }
+
+ entry->child_pid = fork();
+
+ if (entry->child_pid == -1) {
+ DBG_ERR("fork failed: %s\n", strerror(errno));
+ goto err_exit;
+ }
+
+ if (entry->child_pid == 0) {
+
+ /*
+ * Child !
+ */
+
+ int child_std_end = STDOUT_FILENO;
+ popen_list *p;
+
+ close(parent_end);
+ if (child_end != child_std_end) {
+ dup2 (child_end, child_std_end);
+ close (child_end);
+ }
+
+ /*
+ * POSIX.2: "popen() shall ensure that any streams from previous
+ * popen() calls that remain open in the parent process are closed
+ * in the new child process."
+ */
+
+ for (p = popen_chain; p; p = p->next)
+ close(p->fd);
+
+ ret = execv(argl[0], argl);
+ if (ret == -1) {
+ DBG_ERR("ERROR executing command "
+ "'%s': %s\n", command, strerror(errno));
+ }
+ _exit (127);
+ }
+
+ /*
+ * Parent.
+ */
+
+ close (child_end);
+
+ /* Link into popen_chain. */
+ entry->next = popen_chain;
+ popen_chain = entry;
+ entry->fd = parent_end;
+
+ return entry->fd;
+
+err_exit:
+
+ TALLOC_FREE(entry);
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ return -1;
+}
+
+/**************************************************************************
+ Wrapper for pclose. Modified from the glibc sources.
+****************************************************************************/
+
+int sys_pclose(int fd)
+{
+ int wstatus;
+ popen_list **ptr = &popen_chain;
+ popen_list *entry = NULL;
+ pid_t wait_pid;
+ int status = -1;
+
+ /* Unlink from popen_chain. */
+ for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
+ if ((*ptr)->fd == fd) {
+ entry = *ptr;
+ *ptr = (*ptr)->next;
+ status = 0;
+ break;
+ }
+ }
+
+ if (status < 0 || close(entry->fd) < 0)
+ return -1;
+
+ /*
+ * As Samba is catching and eating child process
+ * exits we don't really care about the child exit
+ * code, a -1 with errno = ECHILD will do fine for us.
+ */
+
+ do {
+ wait_pid = waitpid (entry->child_pid, &wstatus, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+
+ TALLOC_FREE(entry);
+
+ if (wait_pid == -1)
+ return -1;
+ return wstatus;
+}
diff --git a/lib/util/sys_popen.h b/lib/util/sys_popen.h
new file mode 100644
index 0000000..be43748
--- /dev/null
+++ b/lib/util/sys_popen.h
@@ -0,0 +1,26 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Jeremy Allison 2000
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_SYS_POPEN_H__
+#define __LIB_SYS_POPEN_H__
+
+int sys_popenv(char * const argl[]);
+int sys_pclose(int fd);
+
+#endif
diff --git a/lib/util/sys_rw.c b/lib/util/sys_rw.c
new file mode 100644
index 0000000..d25a42b
--- /dev/null
+++ b/lib/util/sys_rw.c
@@ -0,0 +1,295 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 1998-2005
+ * Copyright (C) Timur Bakeyev 2005
+ * Copyright (C) Bjoern Jacke 2006-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "lib/util/sys_rw.h"
+#include <assert.h>
+
+bool sys_valid_io_range(off_t offset, size_t length)
+{
+ uint64_t last_byte_ofs;
+
+ if (offset < 0) {
+ return false;
+ }
+
+ if (offset > INT64_MAX) {
+ return false;
+ }
+
+ if (length > UINT32_MAX) {
+ return false;
+ }
+
+ last_byte_ofs = (uint64_t)offset + (uint64_t)length;
+ if (last_byte_ofs > INT64_MAX) {
+ return false;
+ }
+
+ return true;
+}
+
+bool sys_io_ranges_overlap(size_t c1, off_t o1,
+ size_t c2, off_t o2)
+{
+ if (c1 == 0 || c2 == 0) {
+ return false;
+ }
+ if (o2 < o1) {
+ /*
+ * o1
+ * |····c1····|
+ * o2
+ * |····c2···| ?
+ */
+ return (o2 + c2 > o1);
+ } else {
+ /*
+ * o1
+ * |····c1···|
+ * o2
+ * |····c2····| ?
+ */
+ return (o1 + c1 > o2);
+ }
+}
+
+off_t sys_block_align_truncate(off_t len, off_t align)
+{
+ assert(align > 1);
+ assert(((align - 1) & align) == 0);
+ return len & (~align + 1);
+}
+
+off_t sys_block_align(off_t len, off_t align)
+{
+ assert(align > 1);
+ assert(((align - 1) & align) == 0);
+ return (len + (align - 1)) & ~(align - 1);
+}
+
+/*******************************************************************
+A read wrapper that will deal with EINTR/EWOULDBLOCK
+********************************************************************/
+
+ssize_t sys_read(int fd, void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = read(fd, buf, count);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
+ errno == EWOULDBLOCK));
+
+ return ret;
+}
+
+/**
+ * read wrapper, void variant:
+ * This is intended to be used as a void variant of
+ * read in situations where the caller wants to ignore
+ * the result. Hence not checking for EAGAIN|EWOULDBLOCK.
+ */
+void sys_read_v(int fd, void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = read(fd, buf, count);
+ } while (ret == -1 && errno == EINTR);
+}
+
+
+/*******************************************************************
+A write wrapper that will deal with EINTR/EWOULDBLOCK.
+********************************************************************/
+
+ssize_t sys_write(int fd, const void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = write(fd, buf, count);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
+ errno == EWOULDBLOCK));
+
+ return ret;
+}
+
+/**
+ * write wrapper to deal with EINTR and friends.
+ * void-variant that ignores the number of bytes written.
+ * This is intended to be used as a void variant of
+ * write in situations where the caller wants to ignore
+ * the result. Hence not checking for EAGAIN|EWOULDBLOCK.
+ */
+void sys_write_v(int fd, const void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = write(fd, buf, count);
+ } while (ret == -1 && errno == EINTR);
+}
+
+
+/*******************************************************************
+A writev wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret;
+
+ do {
+ ret = writev(fd, iov, iovcnt);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
+ errno == EWOULDBLOCK));
+
+ return ret;
+}
+
+/*******************************************************************
+A pread wrapper that will deal with EINTR
+********************************************************************/
+
+ssize_t sys_pread(int fd, void *buf, size_t count, off_t off)
+{
+ ssize_t ret;
+
+ do {
+ ret = pread(fd, buf, count, off);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+ A pread wrapper that will deal with EINTR and never return a short
+ read unless pread returns zero meaning EOF.
+********************************************************************/
+
+ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off)
+{
+ ssize_t total_read = 0;
+ uint8_t *curr_buf = (uint8_t *)buf;
+ size_t curr_count = count;
+ off_t curr_off = off;
+ bool ok;
+
+ ok = sys_valid_io_range(off, count);
+ if (!ok) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (curr_count != 0) {
+ ssize_t ret = sys_pread(fd,
+ curr_buf,
+ curr_count,
+ curr_off);
+
+ if (ret == -1) {
+ return -1;
+ }
+ if (ret == 0) {
+ /* EOF */
+ break;
+ }
+
+ if (ret > curr_count) {
+ errno = EIO;
+ return -1;
+ }
+
+ curr_buf += ret;
+ curr_count -= ret;
+ curr_off += ret;
+
+ total_read += ret;
+ }
+
+ return total_read;
+}
+
+/*******************************************************************
+A write wrapper that will deal with EINTR
+********************************************************************/
+
+ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off)
+{
+ ssize_t ret;
+
+ do {
+ ret = pwrite(fd, buf, count, off);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+/*******************************************************************
+ A pwrite wrapper that will deal with EINTR and never allow a short
+ write unless the file system returns an error.
+********************************************************************/
+
+ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off)
+{
+ ssize_t total_written = 0;
+ const uint8_t *curr_buf = (const uint8_t *)buf;
+ size_t curr_count = count;
+ off_t curr_off = off;
+ bool ok;
+
+ ok = sys_valid_io_range(off, count);
+ if (!ok) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (curr_count != 0) {
+ ssize_t ret = sys_pwrite(fd,
+ curr_buf,
+ curr_count,
+ curr_off);
+
+ if (ret == -1) {
+ return -1;
+ }
+ if (ret == 0) {
+ /* Ensure we can never spin. */
+ errno = ENOSPC;
+ return -1;
+ }
+
+ if (ret > curr_count) {
+ errno = EIO;
+ return -1;
+ }
+
+ curr_buf += ret;
+ curr_count -= ret;
+ curr_off += ret;
+
+ total_written += ret;
+ }
+
+ return total_written;
+}
diff --git a/lib/util/sys_rw.h b/lib/util/sys_rw.h
new file mode 100644
index 0000000..3812159
--- /dev/null
+++ b/lib/util/sys_rw.h
@@ -0,0 +1,45 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 1998-2005
+ * Copyright (C) Timur Bakeyev 2005
+ * Copyright (C) Bjoern Jacke 2006-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_SYS_RW_H__
+#define __LIB_SYS_RW_H__
+
+#include <unistd.h>
+
+struct iovec;
+
+off_t sys_block_align_truncate(off_t len, off_t align);
+off_t sys_block_align(off_t len, off_t align);
+bool sys_valid_io_range(off_t offset, size_t length);
+bool sys_io_ranges_overlap(size_t c1, off_t o1,
+ size_t c2, off_t o2);
+ssize_t sys_read(int fd, void *buf, size_t count);
+void sys_read_v(int fd, void *buf, size_t count);
+ssize_t sys_write(int fd, const void *buf, size_t count);
+void sys_write_v(int fd, const void *buf, size_t count);
+ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt);
+ssize_t sys_pread(int fd, void *buf, size_t count, off_t off);
+ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off);
+ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off);
+ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off);
+
+#endif
diff --git a/lib/util/sys_rw_data.c b/lib/util/sys_rw_data.c
new file mode 100644
index 0000000..a0d69f7
--- /dev/null
+++ b/lib/util/sys_rw_data.c
@@ -0,0 +1,117 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 1998-2005
+ * Copyright (C) Timur Bakeyev 2005
+ * Copyright (C) Bjoern Jacke 2006-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "lib/util/sys_rw_data.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/iov_buf.h"
+
+/****************************************************************************
+ Write all data from an iov array
+ NB. This can be called with a non-socket fd, don't add dependencies
+ on socket calls.
+****************************************************************************/
+
+ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt)
+{
+ ssize_t to_send;
+ ssize_t thistime;
+ size_t sent;
+ struct iovec iov_copy[iovcnt];
+ struct iovec *iov;
+
+ to_send = iov_buflen(orig_iov, iovcnt);
+ if (to_send == -1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ thistime = sys_writev(fd, orig_iov, iovcnt);
+ if ((thistime <= 0) || (thistime == to_send)) {
+ return thistime;
+ }
+ sent = thistime;
+
+ /*
+ * We could not send everything in one call. Make a copy of iov that
+ * we can mess with.
+ */
+
+ memcpy(iov_copy, orig_iov, sizeof(struct iovec) * iovcnt);
+ iov = iov_copy;
+
+ while (sent < (size_t)to_send) {
+ bool ok;
+
+ ok = iov_advance(&iov, &iovcnt, thistime);
+ if (!ok) {
+ errno = EIO;
+ return -1;
+ }
+
+ thistime = sys_writev(fd, iov, iovcnt);
+ if (thistime <= 0) {
+ break;
+ }
+ sent += thistime;
+ }
+
+ return sent;
+}
+
+/****************************************************************************
+ Write data to a fd.
+ NB. This can be called with a non-socket fd, don't add dependencies
+ on socket calls.
+****************************************************************************/
+
+ssize_t write_data(int fd, const void *buffer, size_t n)
+{
+ struct iovec iov;
+
+ iov.iov_base = discard_const_p(void, buffer);
+ iov.iov_len = n;
+ return write_data_iov(fd, &iov, 1);
+}
+
+/*
+ * Blocking read n bytes from a fd
+ */
+
+ssize_t read_data(int fd, void *buffer, size_t n)
+{
+ ssize_t nread;
+
+ nread = 0;
+
+ while ((size_t)nread < n) {
+ ssize_t ret;
+ ret = sys_read(fd, ((char *)buffer) + nread, n - nread);
+ if (ret <= 0) {
+ return ret;
+ }
+ nread += ret;
+ }
+
+ return nread;
+}
diff --git a/lib/util/sys_rw_data.h b/lib/util/sys_rw_data.h
new file mode 100644
index 0000000..bda3795
--- /dev/null
+++ b/lib/util/sys_rw_data.h
@@ -0,0 +1,34 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba system utilities
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 1998-2005
+ * Copyright (C) Timur Bakeyev 2005
+ * Copyright (C) Bjoern Jacke 2006-2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_SYS_RW_DATA_H__
+#define __LIB_SYS_RW_DATA_H__
+
+#include <unistd.h>
+
+struct iovec;
+
+ssize_t write_data_iov(int fd, const struct iovec *iov, int iovcnt);
+ssize_t write_data(int fd, const void *buffer, size_t n);
+ssize_t read_data(int fd, void *buffer, size_t n);
+
+#endif
diff --git a/lib/util/system.c b/lib/util/system.c
new file mode 100644
index 0000000..558aa5b
--- /dev/null
+++ b/lib/util/system.c
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#undef malloc
+
+/*
+ The idea is that this file will eventually have wrappers around all
+ important system calls in samba. The aims are:
+
+ - to enable easier porting by putting OS dependent stuff in here
+
+ - to allow for hooks into other "pseudo-filesystems"
+
+ - to allow easier integration of things like the japanese extensions
+
+ - to support the philosophy of Samba to expose the features of
+ the OS within the SMB model. In general whatever file/printer/variable
+ expansions/etc make sense to the OS should be acceptable to Samba.
+*/
+
+
+_PUBLIC_ int sys_getnameinfo(const struct sockaddr *psa,
+ int salen,
+ char *host,
+ size_t hostlen,
+ char *service,
+ size_t servlen,
+ int flags)
+{
+ /*
+ * For Solaris we must make sure salen is the
+ * correct length for the incoming sa_family.
+ */
+
+ if (salen == sizeof(struct sockaddr_storage)) {
+ salen = sizeof(struct sockaddr_in);
+#if defined(HAVE_IPV6)
+ if (psa->sa_family == AF_INET6) {
+ salen = sizeof(struct sockaddr_in6);
+ }
+#endif
+ }
+ return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
+}
diff --git a/lib/util/talloc_keep_secret.c b/lib/util/talloc_keep_secret.c
new file mode 100644
index 0000000..2104865
--- /dev/null
+++ b/lib/util/talloc_keep_secret.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/fault.h"
+#include "talloc_keep_secret.h"
+
+static int talloc_keep_secret_destructor(void *ptr)
+{
+ int ret;
+ size_t size = talloc_get_size(ptr);
+
+ if (unlikely(size == 0)) {
+ return 0;
+ }
+
+ ret = memset_s(ptr, size, 0, size);
+ if (unlikely(ret != 0)) {
+ char *msg = NULL;
+ int ret2;
+ ret2 = asprintf(&msg,
+ "talloc_keep_secret_destructor: memset_s() failed: %s",
+ strerror(ret));
+ if (ret2 != -1) {
+ smb_panic(msg);
+ } else {
+ smb_panic("talloc_keep_secret_destructor: memset_s() failed");
+ }
+ }
+
+ return 0;
+}
+
+void _talloc_keep_secret(void *ptr, const char *name)
+{
+ size_t size;
+
+ if (unlikely(ptr == NULL)) {
+#ifdef DEVELOPER
+ smb_panic("Invalid talloc pointer");
+#endif
+ return;
+ }
+
+ size = talloc_get_size(ptr);
+ if (unlikely(size == 0)) {
+ return;
+ }
+
+ talloc_set_name_const(ptr, name);
+ talloc_set_destructor(ptr, talloc_keep_secret_destructor);
+}
diff --git a/lib/util/talloc_keep_secret.h b/lib/util/talloc_keep_secret.h
new file mode 100644
index 0000000..44a26ae
--- /dev/null
+++ b/lib/util/talloc_keep_secret.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TALLOC_KEEP_SECRET_H
+#define _TALLOC_KEEP_SECRET_H
+
+#ifdef DOXYGEN
+/**
+ * @brief Keep the memory secret when freeing.
+ *
+ * This can be used to define memory as secret. For example memory which holds
+ * passwords or other secrets like session keys. The memory will be zeroed
+ * before is being freed.
+ *
+ * If you duplicate memory, e.g. using talloc_strdup() or talloc_asprintf() you
+ * need to call talloc_keep_secret() on the newly allocated memory too!
+ *
+ * @param[in] ptr The talloc chunk to mark as secure.
+ *
+ * @warning Do not use this in combination with talloc_realloc().
+ */
+void talloc_keep_secret(const void *ptr);
+#else
+#define talloc_keep_secret(ptr) _talloc_keep_secret(ptr, #ptr);
+void _talloc_keep_secret(void *ptr, const char *name);
+#endif
+
+#endif /* _TALLOC_KEEP_SECRET_H */
diff --git a/lib/util/talloc_report.c b/lib/util/talloc_report.c
new file mode 100644
index 0000000..0aec966
--- /dev/null
+++ b/lib/util/talloc_report.c
@@ -0,0 +1,184 @@
+/*
+ * talloc_report into a string
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "talloc_report.h"
+
+/*
+ * talloc_vasprintf into a buffer that doubles its size. The real string
+ * length is maintained in "pstr_len".
+ */
+
+static char *talloc_vasprintf_append_largebuf(char *buf, ssize_t *pstr_len,
+ const char *fmt, va_list ap)
+ PRINTF_ATTRIBUTE(3,0);
+
+static char *talloc_vasprintf_append_largebuf(char *buf, ssize_t *pstr_len,
+ const char *fmt, va_list ap)
+{
+ ssize_t str_len = *pstr_len;
+ size_t buflen, needed, space = 0;
+ char *start = NULL, *tmpbuf = NULL;
+ va_list ap2;
+ int printlen;
+
+ if (str_len == -1) {
+ return NULL;
+ }
+ if (buf == NULL) {
+ return NULL;
+ }
+ if (fmt == NULL) {
+ return NULL;
+ }
+ buflen = talloc_get_size(buf);
+
+ if (buflen > (size_t)str_len) {
+ start = buf + str_len;
+ space = buflen - str_len;
+ } else {
+ return NULL;
+ }
+
+ va_copy(ap2, ap);
+ printlen = vsnprintf(start, space, fmt, ap2);
+ va_end(ap2);
+
+ if (printlen < 0) {
+ goto fail;
+ }
+
+ needed = str_len + printlen + 1;
+
+ if (needed > buflen) {
+ buflen = MAX(128, buflen);
+
+ while (buflen < needed) {
+ buflen *= 2;
+ }
+
+ tmpbuf = talloc_realloc(NULL, buf, char, buflen);
+ if (tmpbuf == NULL) {
+ goto fail;
+ }
+ buf = tmpbuf;
+
+ va_copy(ap2, ap);
+ vsnprintf(buf + str_len, buflen - str_len, fmt, ap2);
+ va_end(ap2);
+ }
+ *pstr_len = (needed - 1);
+ return buf;
+fail:
+ *pstr_len = -1;
+ return buf;
+}
+
+static char *talloc_asprintf_append_largebuf(char *buf, ssize_t *pstr_len,
+ const char *fmt, ...)
+ PRINTF_ATTRIBUTE(3,4);
+
+static char *talloc_asprintf_append_largebuf(char *buf, ssize_t *pstr_len,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ buf = talloc_vasprintf_append_largebuf(buf, pstr_len, fmt, ap);
+ va_end(ap);
+ return buf;
+}
+
+struct talloc_report_str_state {
+ ssize_t str_len;
+ char *s;
+};
+
+static void talloc_report_str_helper(const void *ptr, int depth, int max_depth,
+ int is_ref, void *private_data)
+{
+ struct talloc_report_str_state *state = private_data;
+ const char *name = talloc_get_name(ptr);
+
+ if (ptr == state->s) {
+ return;
+ }
+
+ if (is_ref) {
+ state->s = talloc_asprintf_append_largebuf(
+ state->s, &state->str_len,
+ "%*sreference to: %s\n", depth*4, "", name);
+ return;
+ }
+
+ if (depth == 0) {
+ state->s = talloc_asprintf_append_largebuf(
+ state->s, &state->str_len,
+ "%stalloc report on '%s' "
+ "(total %6lu bytes in %3lu blocks)\n",
+ (max_depth < 0 ? "full " :""), name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr));
+ return;
+ }
+
+ if (strcmp(name, "char") == 0) {
+ /*
+ * Print out the first 50 bytes of the string
+ */
+ state->s = talloc_asprintf_append_largebuf(
+ state->s, &state->str_len,
+ "%*s%-30s contains %6lu bytes in %3lu blocks "
+ "(ref %zu): %*s\n", depth*4, "", name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr),
+ talloc_reference_count(ptr),
+ (int)MIN(50, talloc_get_size(ptr)),
+ (const char *)ptr);
+ return;
+ }
+
+ state->s = talloc_asprintf_append_largebuf(
+ state->s, &state->str_len,
+ "%*s%-30s contains %6lu bytes in %3lu blocks (ref %zu) %p\n",
+ depth*4, "", name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr),
+ talloc_reference_count(ptr), ptr);
+}
+
+char *talloc_report_str(TALLOC_CTX *mem_ctx, TALLOC_CTX *root)
+{
+ struct talloc_report_str_state state;
+
+ state.s = talloc_strdup(mem_ctx, "");
+ if (state.s == NULL) {
+ return NULL;
+ }
+ state.str_len = 0;
+
+ talloc_report_depth_cb(root, 0, -1, talloc_report_str_helper, &state);
+
+ if (state.str_len == -1) {
+ talloc_free(state.s);
+ return NULL;
+ }
+
+ return talloc_realloc(mem_ctx, state.s, char, state.str_len+1);
+}
diff --git a/lib/util/talloc_report.h b/lib/util/talloc_report.h
new file mode 100644
index 0000000..53d0385
--- /dev/null
+++ b/lib/util/talloc_report.h
@@ -0,0 +1,27 @@
+/*
+ * talloc_report into a string
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TALLOC_REPORT_H_
+#define _TALLOC_REPORT_H_
+
+#include <talloc.h>
+
+char *talloc_report_str(TALLOC_CTX *mem_ctx, TALLOC_CTX *root);
+
+#endif
diff --git a/lib/util/talloc_report_printf.c b/lib/util/talloc_report_printf.c
new file mode 100644
index 0000000..3011c62
--- /dev/null
+++ b/lib/util/talloc_report_printf.c
@@ -0,0 +1,134 @@
+/*
+ * talloc_report into a FILE
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "talloc_report_printf.h"
+
+static void talloc_report_printf_helper(
+ const void *ptr,
+ int depth,
+ int max_depth,
+ int is_ref,
+ void *private_data)
+{
+ FILE *f = private_data;
+ const char *name = talloc_get_name(ptr);
+
+ if (is_ref) {
+ fprintf(f,
+ "%*sreference to: %s\n",
+ depth*4,
+ "",
+ name);
+ return;
+ }
+
+ if (depth == 0) {
+ fprintf(f,
+ "%stalloc report on '%s' "
+ "(total %6zu bytes in %3zu blocks)\n",
+ (max_depth < 0 ? "full " :""), name,
+ talloc_total_size(ptr),
+ talloc_total_blocks(ptr));
+ return;
+ }
+
+ if (strcmp(name, "char") == 0) {
+ /*
+ * Print out the first 50 bytes of the string
+ */
+ fprintf(f,
+ "%*s%-30s contains %6zu bytes in %3zu blocks "
+ "(ref %zu): %*s\n", depth*4, "", name,
+ talloc_total_size(ptr),
+ talloc_total_blocks(ptr),
+ talloc_reference_count(ptr),
+ (int)MIN(50, talloc_get_size(ptr)),
+ (const char *)ptr);
+ return;
+ }
+
+ fprintf(f,
+ "%*s%-30s contains %6zu bytes in %3zu blocks (ref %zu) %p\n",
+ depth*4, "", name,
+ talloc_total_size(ptr),
+ talloc_total_blocks(ptr),
+ talloc_reference_count(ptr),
+ ptr);
+}
+
+void talloc_full_report_printf(TALLOC_CTX *root, FILE *f)
+{
+ talloc_report_depth_cb(root, 0, -1, talloc_report_printf_helper, f);
+#if defined(HAVE_MALLINFO2)
+ {
+ struct mallinfo2 mi2 = mallinfo2();
+
+ fprintf(f,
+ "mallinfo:\n"
+ " arena: %zu\n"
+ " ordblks: %zu\n"
+ " smblks: %zu\n"
+ " hblks: %zu\n"
+ " hblkhd: %zu\n"
+ " usmblks: %zu\n"
+ " fsmblks: %zu\n"
+ " uordblks: %zu\n"
+ " fordblks: %zu\n"
+ " keepcost: %zu\n",
+ mi2.arena,
+ mi2.ordblks,
+ mi2.smblks,
+ mi2.hblks,
+ mi2.hblkhd,
+ mi2.usmblks,
+ mi2.fsmblks,
+ mi2.uordblks,
+ mi2.fordblks,
+ mi2.keepcost);
+ }
+#elif defined(HAVE_MALLINFO)
+ {
+ struct mallinfo mi = mallinfo();
+
+ fprintf(f,
+ "mallinfo:\n"
+ " arena: %d\n"
+ " ordblks: %d\n"
+ " smblks: %d\n"
+ " hblks: %d\n"
+ " hblkhd: %d\n"
+ " usmblks: %d\n"
+ " fsmblks: %d\n"
+ " uordblks: %d\n"
+ " fordblks: %d\n"
+ " keepcost: %d\n",
+ mi.arena,
+ mi.ordblks,
+ mi.smblks,
+ mi.hblks,
+ mi.hblkhd,
+ mi.usmblks,
+ mi.fsmblks,
+ mi.uordblks,
+ mi.fordblks,
+ mi.keepcost);
+ }
+#endif /* HAVE_MALLINFO2 or HAVE_MALLINFO */
+}
diff --git a/lib/util/talloc_report_printf.h b/lib/util/talloc_report_printf.h
new file mode 100644
index 0000000..7881e65
--- /dev/null
+++ b/lib/util/talloc_report_printf.h
@@ -0,0 +1,29 @@
+/*
+ * talloc_report into a FILE
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TALLOC_REPORT_PRINTF_H_
+#define _TALLOC_REPORT_PRINTF_H_
+
+#include "replace.h"
+#include "system/filesys.h"
+#include <talloc.h>
+
+void talloc_full_report_printf(TALLOC_CTX *root, FILE *f);
+
+#endif
diff --git a/lib/util/talloc_stack.c b/lib/util/talloc_stack.c
new file mode 100644
index 0000000..fdd0a30
--- /dev/null
+++ b/lib/util/talloc_stack.c
@@ -0,0 +1,259 @@
+/*
+ Unix SMB/CIFS implementation.
+ Implement a stack of talloc contexts
+ Copyright (C) Volker Lendecke 2007
+ Copyright (C) Jeremy Allison 2009 - made thread safe.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * Implement a stack of talloc frames.
+ *
+ * When a new talloc stackframe is allocated with talloc_stackframe(), then
+ * the TALLOC_CTX returned with talloc_tos() is reset to that new
+ * frame. Whenever that stack frame is TALLOC_FREE()'ed, then the reverse
+ * happens: The previous talloc_tos() is restored.
+ *
+ * This API is designed to be robust in the sense that if someone forgets to
+ * TALLOC_FREE() a stackframe, then the next outer one correctly cleans up and
+ * resets the talloc_tos().
+ *
+ * This robustness feature means that we can't rely on a linked list with
+ * talloc destructors because in a hierarchy of talloc destructors the parent
+ * destructor is called before its children destructors. The child destructor
+ * called after the parent would set the talloc_tos() to the wrong value.
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/talloc_stack.h"
+#include "lib/util/smb_threads.h"
+#include "lib/util/smb_threads_internal.h"
+#include "lib/util/fault.h"
+#include "lib/util/debug.h"
+
+struct talloc_stackframe {
+ int talloc_stacksize;
+ int talloc_stack_arraysize;
+ TALLOC_CTX **talloc_stack;
+};
+
+/*
+ * In the single threaded case this is a pointer
+ * to the global talloc_stackframe. In the MT-case
+ * this is the pointer to the thread-specific key
+ * used to look up the per-thread talloc_stackframe
+ * pointer.
+ */
+
+static void *global_ts;
+
+/* Variable to ensure TLS value is only initialized once. */
+static smb_thread_once_t ts_initialized = SMB_THREAD_ONCE_INIT;
+
+static void talloc_stackframe_init(void * unused)
+{
+ if (SMB_THREAD_CREATE_TLS("talloc_stackframe", global_ts)) {
+ smb_panic("talloc_stackframe_init create_tls failed");
+ }
+}
+
+static struct talloc_stackframe *talloc_stackframe_create(void)
+{
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef calloc
+#undef calloc
+#endif
+#endif
+ struct talloc_stackframe *ts = (struct talloc_stackframe *)calloc(
+ 1, sizeof(struct talloc_stackframe));
+#if defined(PARANOID_MALLOC_CHECKER)
+#define calloc(n, s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+#endif
+
+ if (!ts) {
+ smb_panic("talloc_stackframe_init malloc failed");
+ }
+
+ SMB_THREAD_ONCE(&ts_initialized, talloc_stackframe_init, NULL);
+
+ if (SMB_THREAD_SET_TLS(global_ts, ts)) {
+ smb_panic("talloc_stackframe_init set_tls failed");
+ }
+ return ts;
+}
+
+static int talloc_pop(TALLOC_CTX *frame)
+{
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+ size_t blocks;
+ int i;
+
+ /* Catch lazy frame-freeing. */
+ if (ts->talloc_stack[ts->talloc_stacksize-1] != frame) {
+ DEBUG(0, ("Freed frame %s, expected %s.\n",
+ talloc_get_name(frame),
+ talloc_get_name(ts->talloc_stack
+ [ts->talloc_stacksize-1])));
+#ifdef DEVELOPER
+ smb_panic("Frame not freed in order.");
+#endif
+ }
+
+ for (i=0; i<10; i++) {
+
+ /*
+ * We have to free our children first, calling all
+ * destructors. If a destructor hanging deeply off
+ * "frame" uses talloc_tos() itself while freeing the
+ * toplevel frame, we panic because that nested
+ * talloc_tos() in the destructor does not find a
+ * stackframe anymore.
+ *
+ * Do it in a loop up to 10 times as the destructors
+ * might use more of talloc_tos().
+ */
+
+ talloc_free_children(frame);
+
+ blocks = talloc_total_blocks(frame);
+ if (blocks == 1) {
+ break;
+ }
+ }
+
+ if (blocks != 1) {
+ DBG_WARNING("Left %zu blocks after %i "
+ "talloc_free_children(frame) calls\n",
+ blocks, i);
+ }
+
+ for (i=ts->talloc_stacksize-1; i>0; i--) {
+ if (frame == ts->talloc_stack[i]) {
+ break;
+ }
+ TALLOC_FREE(ts->talloc_stack[i]);
+ }
+
+ ts->talloc_stack[i] = NULL;
+ ts->talloc_stacksize = i;
+ return 0;
+}
+
+/*
+ * Create a new talloc stack frame.
+ *
+ * When free'd, it frees all stack frames that were created after this one and
+ * not explicitly freed.
+ */
+
+static TALLOC_CTX *talloc_stackframe_internal(const char *location,
+ size_t poolsize)
+{
+ TALLOC_CTX **tmp, *top;
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+
+ if (ts == NULL) {
+ ts = talloc_stackframe_create();
+ }
+
+ if (ts->talloc_stack_arraysize < ts->talloc_stacksize + 1) {
+ tmp = talloc_realloc(NULL, ts->talloc_stack, TALLOC_CTX *,
+ ts->talloc_stacksize + 1);
+ if (tmp == NULL) {
+ goto fail;
+ }
+ ts->talloc_stack = tmp;
+ ts->talloc_stack_arraysize = ts->talloc_stacksize + 1;
+ }
+
+ if (poolsize) {
+ top = talloc_pool(ts->talloc_stack, poolsize);
+ } else {
+ TALLOC_CTX *parent;
+ /* We chain parentage, so if one is a pool we draw from it. */
+ if (ts->talloc_stacksize == 0) {
+ parent = ts->talloc_stack;
+ } else {
+ parent = ts->talloc_stack[ts->talloc_stacksize-1];
+ }
+ top = talloc_new(parent);
+ }
+
+ if (top == NULL) {
+ goto fail;
+ }
+ talloc_set_name_const(top, location);
+ talloc_set_destructor(top, talloc_pop);
+
+ ts->talloc_stack[ts->talloc_stacksize++] = top;
+ return top;
+
+ fail:
+ smb_panic("talloc_stackframe failed");
+ return NULL;
+}
+
+TALLOC_CTX *_talloc_stackframe(const char *location)
+{
+ return talloc_stackframe_internal(location, 0);
+}
+
+TALLOC_CTX *_talloc_stackframe_pool(const char *location, size_t poolsize)
+{
+ return talloc_stackframe_internal(location, poolsize);
+}
+
+/*
+ * Get us the current top of the talloc stack.
+ */
+
+TALLOC_CTX *_talloc_tos(const char *location)
+{
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+
+ if (ts == NULL || ts->talloc_stacksize == 0) {
+ _talloc_stackframe(location);
+ ts = (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+ DEBUG(0, ("no talloc stackframe at %s, leaking memory\n",
+ location));
+#ifdef DEVELOPER
+ smb_panic("No talloc stackframe");
+#endif
+ }
+
+ return ts->talloc_stack[ts->talloc_stacksize-1];
+}
+
+/*
+ * return true if a talloc stackframe exists
+ * this can be used to prevent memory leaks for code that can
+ * optionally use a talloc stackframe (eg. nt_errstr())
+ */
+
+bool talloc_stackframe_exists(void)
+{
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+
+ if (ts == NULL || ts->talloc_stacksize == 0) {
+ return false;
+ }
+ return true;
+}
diff --git a/lib/util/talloc_stack.h b/lib/util/talloc_stack.h
new file mode 100644
index 0000000..fceb41f
--- /dev/null
+++ b/lib/util/talloc_stack.h
@@ -0,0 +1,66 @@
+/*
+ Unix SMB/CIFS implementation.
+ Implement a stack of talloc contexts
+ Copyright (C) Volker Lendecke 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Implement a stack of talloc frames.
+ *
+ * When a new talloc stackframe is allocated with talloc_stackframe(), then
+ * the TALLOC_CTX returned with talloc_tos() is reset to that new
+ * frame. Whenever that stack frame is TALLOC_FREE()'ed, then the reverse
+ * happens: The previous talloc_tos() is restored.
+ *
+ * This API is designed to be robust in the sense that if someone forgets to
+ * TALLOC_FREE() a stackframe, then the next outer one correctly cleans up and
+ * resets the talloc_tos().
+ *
+ */
+
+#ifndef _TALLOC_STACK_H
+#define _TALLOC_STACK_H
+
+#include <talloc.h>
+
+/*
+ * Create a new talloc stack frame.
+ *
+ * When free'd, it frees all stack frames that were created after this one and
+ * not explicitly freed.
+ */
+
+#define talloc_stackframe() _talloc_stackframe(__location__)
+#define talloc_stackframe_pool(sz) _talloc_stackframe_pool(__location__, (sz))
+TALLOC_CTX *_talloc_stackframe(const char *location);
+TALLOC_CTX *_talloc_stackframe_pool(const char *location, size_t poolsize);
+
+/*
+ * Get us the current top of the talloc stack.
+ */
+
+#define talloc_tos() _talloc_tos(__location__)
+TALLOC_CTX *_talloc_tos(const char *location);
+
+/*
+ * return true if a talloc stackframe exists
+ * this can be used to prevent memory leaks for code that can
+ * optionally use a talloc stackframe (eg. nt_errstr())
+ */
+
+bool talloc_stackframe_exists(void);
+
+#endif
diff --git a/lib/util/tests/README b/lib/util/tests/README
new file mode 100644
index 0000000..c1337d5
--- /dev/null
+++ b/lib/util/tests/README
@@ -0,0 +1,22 @@
+tfork tests
+===========
+
+To run the tfork torture testsuite under valgrind with the helgrind or drd
+thread checkers, run valgrind with the --suppress option passing a suppressions
+file.
+
+For helgrind:
+
+$ valgrind \
+ --trace-children=yes \
+ --tool=helgrind \
+ --suppressions=lib/util/tests/tfork-helgrind.supp \
+ ./bin/smbtorture ncalrpc:localhost local.tfork.tfork_threads
+
+For drd:
+
+$ valgrind \
+ --trace-children=yes \
+ --tool=drd \
+ --suppressions=lib/util/tests/tfork-drd.supp \
+ ./bin/smbtorture ncalrpc:localhost local.tfork.tfork_threads
diff --git a/lib/util/tests/anonymous_shared.c b/lib/util/tests/anonymous_shared.c
new file mode 100644
index 0000000..512a53f
--- /dev/null
+++ b/lib/util/tests/anonymous_shared.c
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ anonymous_shared testing
+
+ Copyright (C) Stefan Metzmacher 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+static bool test_anonymous_shared_simple(struct torture_context *tctx)
+{
+ void *ptr;
+ size_t len;
+
+ torture_comment(tctx, "anonymous_shared_free(NULL)\n");
+ anonymous_shared_free(NULL);
+
+ len = 500;
+ torture_comment(tctx, "anonymous_shared_allocate(%llu)\n",
+ (unsigned long long)len);
+ ptr = anonymous_shared_allocate(len);
+ torture_assert(tctx, ptr, "valid pointer");
+ memset(ptr, 0xfe, len);
+ torture_comment(tctx, "anonymous_shared_free(ptr)\n");
+ anonymous_shared_free(ptr);
+
+ len = 50000;
+ torture_comment(tctx, "anonymous_shared_allocate(%llu)\n",
+ (unsigned long long)len);
+ ptr = anonymous_shared_allocate(len);
+ torture_assert(tctx, ptr, "valid pointer");
+ memset(ptr, 0xfe, len);
+ torture_comment(tctx, "anonymous_shared_free(ptr)\n");
+ anonymous_shared_free(ptr);
+
+ memset(&len, 0xFF, sizeof(len));
+ torture_comment(tctx, "anonymous_shared_allocate(%llu)\n",
+ (unsigned long long)len);
+ ptr = anonymous_shared_allocate(len);
+ torture_assert(tctx, ptr == NULL, "null pointer");
+
+ return true;
+}
+
+/* local.anonymous_shared test suite creation */
+struct torture_suite *torture_local_util_anonymous_shared(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "anonymous_shared");
+
+ torture_suite_add_simple_test(suite, "simple",
+ test_anonymous_shared_simple);
+
+ return suite;
+}
diff --git a/lib/util/tests/asn1_tests.c b/lib/util/tests/asn1_tests.c
new file mode 100644
index 0000000..f2bd163
--- /dev/null
+++ b/lib/util/tests/asn1_tests.c
@@ -0,0 +1,383 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ util_asn1 testing
+
+ Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "../asn1.h"
+
+struct oid_data {
+ const char *oid; /* String OID */
+ const char *bin_oid; /* Binary OID represented as string */
+};
+
+/* Data for successful OIDs conversions */
+static const struct oid_data oid_data_ok[] = {
+ {
+ .oid = "2.5.4.0",
+ .bin_oid = "550400"
+ },
+ {
+ .oid = "2.5.4.1",
+ .bin_oid = "550401"
+ },
+ {
+ .oid = "2.5.4.130",
+ .bin_oid = "55048102"
+ },
+ {
+ .oid = "2.5.130.4",
+ .bin_oid = "55810204"
+ },
+ {
+ .oid = "2.5.4.16387",
+ .bin_oid = "5504818003"
+ },
+ {
+ .oid = "2.5.16387.4",
+ .bin_oid = "5581800304"
+ },
+ {
+ .oid = "2.5.2097155.4",
+ .bin_oid = "558180800304"
+ },
+ {
+ .oid = "2.5.4.130.16387.2097155.268435459",
+ .bin_oid = "55048102818003818080038180808003"
+ },
+};
+
+/* Data for successful OIDs conversions */
+static const char *oid_data_err[] = {
+ "", /* empty OID */
+ ".2.5.4.130", /* first sub-identifier is empty */
+ "2.5.4.130.", /* last sub-identifier is empty */
+ "2..5.4.130", /* second sub-identifier is empty */
+ "2.5..4.130", /* third sub-identifier is empty */
+ "2.abc.4.130", /* invalid sub-identifier */
+ "2.5abc.4.130", /* invalid sub-identifier (alphanumeric)*/
+};
+
+/* Data for successful Partial OIDs conversions */
+static const struct oid_data partial_oid_data_ok[] = {
+ {
+ .oid = "2.5.4.130:0x81",
+ .bin_oid = "5504810281"
+ },
+ {
+ .oid = "2.5.4.16387:0x8180",
+ .bin_oid = "55048180038180"
+ },
+ {
+ .oid = "2.5.4.16387:0x81",
+ .bin_oid = "550481800381"
+ },
+ {
+ .oid = "2.5.2097155.4:0x818080",
+ .bin_oid = "558180800304818080"
+ },
+ {
+ .oid = "2.5.2097155.4:0x8180",
+ .bin_oid = "5581808003048180"
+ },
+ {
+ .oid = "2.5.2097155.4:0x81",
+ .bin_oid = "55818080030481"
+ },
+};
+
+static const struct {
+ DATA_BLOB blob;
+ int value;
+} integer_tests[] = {
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x01\x00"), 3},
+ .value = 0
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x01\x7f"), 3},
+ .value = 127
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x02\x00\x80"), 4},
+ .value = 128
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x02\x01\x00"), 4},
+ .value = 256
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x01\x80"), 3},
+ .value = -128
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x02\xff\x7f"), 4},
+ .value = -129
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x01\xff"), 3},
+ .value = -1
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x02\xff\x01"), 4},
+ .value = -255
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x02\x00\xff"), 4},
+ .value = 255
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x04\x80\x00\x00\x00"), 6},
+ .value = 0x80000000
+ },
+ {
+ .blob = { discard_const_p(uint8_t, "\x02\x04\x7f\xff\xff\xff"), 6},
+ .value = 0x7fffffff
+ }
+};
+
+/* Testing ber_write_OID_String() function */
+static bool test_ber_write_OID_String(struct torture_context *tctx)
+{
+ int i;
+ char *hex_str;
+ DATA_BLOB blob;
+ TALLOC_CTX *mem_ctx;
+ const struct oid_data *data = oid_data_ok;
+
+ mem_ctx = talloc_new(tctx);
+
+ /* check for valid OIDs */
+ for (i = 0; i < ARRAY_SIZE(oid_data_ok); i++) {
+ torture_assert(tctx, ber_write_OID_String(mem_ctx, &blob, data[i].oid),
+ "ber_write_OID_String failed");
+
+ hex_str = hex_encode_talloc(mem_ctx, blob.data, blob.length);
+ torture_assert(tctx, hex_str, "No memory!");
+
+ torture_assert(tctx, strequal(data[i].bin_oid, hex_str),
+ talloc_asprintf(mem_ctx,
+ "Failed: oid=%s, bin_oid:%s",
+ data[i].oid, data[i].bin_oid));
+ }
+
+ /* check for invalid OIDs */
+ for (i = 0; i < ARRAY_SIZE(oid_data_err); i++) {
+ torture_assert(tctx,
+ !ber_write_OID_String(mem_ctx, &blob, oid_data_err[i]),
+ talloc_asprintf(mem_ctx,
+ "Should fail for [%s] -> %s",
+ oid_data_err[i],
+ hex_encode_talloc(mem_ctx, blob.data, blob.length)));
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/* Testing ber_read_OID_String() function */
+static bool test_ber_read_OID_String(struct torture_context *tctx)
+{
+ int i;
+ char *oid;
+ DATA_BLOB oid_blob;
+ TALLOC_CTX *mem_ctx;
+ const struct oid_data *data = oid_data_ok;
+
+ mem_ctx = talloc_new(tctx);
+
+ for (i = 0; i < ARRAY_SIZE(oid_data_ok); i++) {
+ oid_blob = strhex_to_data_blob(mem_ctx, data[i].bin_oid);
+
+ torture_assert(tctx, ber_read_OID_String(mem_ctx, oid_blob, &oid),
+ "ber_read_OID_String failed");
+
+ torture_assert(tctx, strequal(data[i].oid, oid),
+ talloc_asprintf(mem_ctx,
+ "Failed: oid=%s, bin_oid:%s",
+ data[i].oid, data[i].bin_oid));
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/* Testing ber_write_partial_OID_String() function */
+static bool test_ber_write_partial_OID_String(struct torture_context *tctx)
+{
+ int i;
+ char *hex_str;
+ DATA_BLOB blob;
+ TALLOC_CTX *mem_ctx;
+ const struct oid_data *data = oid_data_ok;
+
+ mem_ctx = talloc_new(tctx);
+
+ /* ber_write_partial_OID_String() should work with not partial OIDs also */
+ for (i = 0; i < ARRAY_SIZE(oid_data_ok); i++) {
+ torture_assert(tctx, ber_write_partial_OID_String(mem_ctx, &blob, data[i].oid),
+ "ber_write_partial_OID_String failed");
+
+ hex_str = hex_encode_talloc(mem_ctx, blob.data, blob.length);
+ torture_assert(tctx, hex_str, "No memory!");
+
+ torture_assert(tctx, strequal(data[i].bin_oid, hex_str),
+ talloc_asprintf(mem_ctx,
+ "Failed: oid=%s, bin_oid:%s",
+ data[i].oid, data[i].bin_oid));
+ }
+
+ /* ber_write_partial_OID_String() test with partial OIDs */
+ data = partial_oid_data_ok;
+ for (i = 0; i < ARRAY_SIZE(partial_oid_data_ok); i++) {
+ torture_assert(tctx, ber_write_partial_OID_String(mem_ctx, &blob, data[i].oid),
+ "ber_write_partial_OID_String failed");
+
+ hex_str = hex_encode_talloc(mem_ctx, blob.data, blob.length);
+ torture_assert(tctx, hex_str, "No memory!");
+
+ torture_assert(tctx, strequal(data[i].bin_oid, hex_str),
+ talloc_asprintf(mem_ctx,
+ "Failed: oid=%s, bin_oid:%s",
+ data[i].oid, data[i].bin_oid));
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/* Testing ber_read_partial_OID_String() function */
+static bool test_ber_read_partial_OID_String(struct torture_context *tctx)
+{
+ int i;
+ char *oid;
+ DATA_BLOB oid_blob;
+ TALLOC_CTX *mem_ctx;
+ const struct oid_data *data = oid_data_ok;
+
+ mem_ctx = talloc_new(tctx);
+
+ /* ber_read_partial_OID_String() should work with not partial OIDs also */
+ for (i = 0; i < ARRAY_SIZE(oid_data_ok); i++) {
+ oid_blob = strhex_to_data_blob(mem_ctx, data[i].bin_oid);
+
+ torture_assert(tctx, ber_read_partial_OID_String(mem_ctx, oid_blob, &oid),
+ "ber_read_partial_OID_String failed");
+
+ torture_assert(tctx, strequal(data[i].oid, oid),
+ talloc_asprintf(mem_ctx,
+ "Failed: oid=%s, bin_oid:%s",
+ data[i].oid, data[i].bin_oid));
+ }
+
+ /* ber_read_partial_OID_String() test with partial OIDs */
+ data = partial_oid_data_ok;
+ for (i = 0; i < ARRAY_SIZE(partial_oid_data_ok); i++) {
+ oid_blob = strhex_to_data_blob(mem_ctx, data[i].bin_oid);
+
+ torture_assert(tctx, ber_read_partial_OID_String(mem_ctx, oid_blob, &oid),
+ "ber_read_partial_OID_String failed");
+
+ torture_assert(tctx, strequal(data[i].oid, oid),
+ talloc_asprintf(mem_ctx,
+ "Failed: oid=%s, bin_oid:%s",
+ data[i].oid, data[i].bin_oid));
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/*
+ * Testing asn1_read_Integer and asn1_write_Integer functions,
+ * inspired by Love Hornquist Astrand
+ */
+
+static bool test_asn1_Integer(struct torture_context *tctx)
+{
+ int i;
+ TALLOC_CTX *mem_ctx;
+ bool ret = false;
+
+ mem_ctx = talloc_new(tctx);
+
+ for (i = 0; i < ARRAY_SIZE(integer_tests); i++) {
+ ASN1_DATA *data;
+ DATA_BLOB blob;
+ int val;
+
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+ if (!data) {
+ goto err;
+ }
+
+ if (!asn1_write_Integer(data, integer_tests[i].value)) goto err;
+
+ if (!asn1_blob(data, &blob)) {
+ goto err;
+ }
+
+ torture_assert_data_blob_equal(tctx, blob, integer_tests[i].blob, "asn1_write_Integer gave incorrect result");
+
+ if (!asn1_load(data, blob)) goto err;
+ torture_assert(tctx, asn1_read_Integer(data, &val), "asn1_write_Integer output could not be read by asn1_read_Integer()");
+
+ torture_assert_int_equal(tctx, val, integer_tests[i].value,
+ "readback of asn1_write_Integer output by asn1_read_Integer() failed");
+ }
+
+ ret = true;
+
+ err:
+
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+/* LOCAL-ASN1 test suite creation */
+struct torture_suite *torture_local_util_asn1(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "asn1");
+
+ torture_suite_add_simple_test(suite, "ber_write_OID_String",
+ test_ber_write_OID_String);
+
+ torture_suite_add_simple_test(suite, "ber_read_OID_String",
+ test_ber_read_OID_String);
+
+ torture_suite_add_simple_test(suite, "ber_write_partial_OID_String",
+ test_ber_write_partial_OID_String);
+
+ torture_suite_add_simple_test(suite, "ber_read_partial_OID_String",
+ test_ber_read_partial_OID_String);
+
+ torture_suite_add_simple_test(suite, "asn1_Integer",
+ test_asn1_Integer);
+
+ return suite;
+}
diff --git a/lib/util/tests/binsearch.c b/lib/util/tests/binsearch.c
new file mode 100644
index 0000000..b3ecda1
--- /dev/null
+++ b/lib/util/tests/binsearch.c
@@ -0,0 +1,173 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Tests for binsearch.h macros.
+
+ Copyright Catalyst IT 2016.
+
+ Written by Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/binsearch.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+static int int_cmp(int a, int b)
+{
+ return a - b;
+}
+
+static int int_cmp_p(int a, int *b)
+{
+ return a - *b;
+}
+
+static bool test_binsearch_v(struct torture_context *tctx)
+{
+ int array[] = { -11, -7, 0, 1, 723, 1000000};
+ int misses[] = { -121, 17, -10, 10, -1, -723, 1000002};
+ int i;
+ int *result = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(misses); i++) {
+ BINARY_ARRAY_SEARCH_V(array, ARRAY_SIZE(array),
+ misses[i], int_cmp, result);
+ torture_comment(tctx, "looking for misses[%d] == %d\n", i, misses[i]);
+ torture_assert(tctx, result == NULL, "failed to miss");
+ }
+
+ for (i = 0; i < ARRAY_SIZE(array); i++) {
+ BINARY_ARRAY_SEARCH_V(array, ARRAY_SIZE(array),
+ array[i], int_cmp, result);
+ torture_comment(tctx, "looking for array[%d] == %d, %p; got %p\n",
+ i, array[i], &array[i], result);
+ torture_assert(tctx, result == &array[i],
+ "failed to find element");
+ }
+ return true;
+}
+
+static bool test_binsearch_gte(struct torture_context *tctx)
+{
+ int array[] = { -11, -7, -7, -7, -1, 0, 0, 1, 723, 723, 723,
+ 724, 724, 10000};
+ size_t a_len = ARRAY_SIZE(array);
+ int targets[] = { -121, -8, -7, -6, 17, -10, 10, -1, 723,
+ 724, 725, 10002, 10000, 0, -11, 1, 11};
+ int i, j, target;
+ int *result = NULL, *next = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(targets); i++) {
+ target = targets[i];
+ torture_comment(tctx, "looking for targets[%d] %d\n",
+ i, target);
+
+ BINARY_ARRAY_SEARCH_GTE(array, a_len, target,
+ int_cmp_p, result, next);
+
+ if (result == NULL) {
+ /* we think there is no exact match */
+ for (j = 0; j < a_len; j++) {
+ if (target == array[j]) {
+ torture_comment(tctx,
+ "failed to find %d\n",
+ targets[i]);
+ torture_fail(tctx,
+ "result is wrongly NULL");
+ }
+ }
+ if (next != NULL) {
+ torture_assert(tctx, (next >= array &&
+ next < array + a_len),
+ "next is out of bounds");
+
+ torture_assert(tctx, *next > target,
+ "next <= target");
+ if (target <= array[0]) {
+ torture_assert(tctx, next == array,
+ "search before start failed");
+ }
+ if (next != array) {
+ torture_assert(tctx, next[-1] < target,
+ "next[-1] >= target");
+ }
+ }
+ else {
+ torture_assert(tctx, array[a_len - 1] < target,
+ "next was not found\n");
+ }
+ } else {
+ /* we think we found an exact match */
+ torture_assert(tctx, *result == target,
+ "result has wrong value");
+
+ torture_assert(tctx, (result >= array &&
+ result < array + a_len),
+ "result is out of bounds!");
+
+ torture_assert(tctx, next == NULL,
+ "next should be NULL on exact match\n");
+ if (result != array) {
+ torture_assert(tctx, result[-1] != target,
+ "didn't find first target\n");
+ }
+ }
+ if (target >= array[a_len - 1]) {
+ torture_assert(tctx, next == NULL,
+ "next is not NULL at array end\n");
+ }
+ }
+
+ /* try again, with result and next the same pointer */
+ for (i = 0; i < ARRAY_SIZE(targets); i++) {
+ target = targets[i];
+ torture_comment(tctx, "looking for targets[%d] %d\n",
+ i, target);
+
+ BINARY_ARRAY_SEARCH_GTE(array, a_len, target,
+ int_cmp_p, result, result);
+
+ if (result == NULL) {
+ /* we think the target is greater than all elements */
+ torture_assert(tctx, array[a_len - 1] < target,
+ "element >= target not found\n");
+ } else {
+ /* we think an element is >= target */
+ torture_assert(tctx, *result >= target,
+ "result has wrong value");
+
+ torture_assert(tctx, (result >= array &&
+ result < array + a_len),
+ "result is out of bounds!");
+
+ if (result != array) {
+ torture_assert(tctx, result[-1] < target,
+ "didn't find first target\n");
+ }
+ }
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_local_util_binsearch(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "binsearch");
+ torture_suite_add_simple_test(suite, "binsearch_v", test_binsearch_v);
+ torture_suite_add_simple_test(suite, "binsearch_gte", test_binsearch_gte);
+ return suite;
+}
diff --git a/lib/util/tests/data_blob.c b/lib/util/tests/data_blob.c
new file mode 100644
index 0000000..e1e8129
--- /dev/null
+++ b/lib/util/tests/data_blob.c
@@ -0,0 +1,172 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ data blob testing
+
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+static bool test_string(struct torture_context *tctx)
+{
+ DATA_BLOB blob = data_blob_string_const("bla");
+
+ torture_assert_int_equal(tctx, blob.length, 3, "blob length");
+ torture_assert_str_equal(tctx, (char *)blob.data, "bla", "blob data");
+
+ return true;
+}
+
+static bool test_string_null(struct torture_context *tctx)
+{
+ DATA_BLOB blob = data_blob_string_const_null("bla");
+
+ torture_assert_int_equal(tctx, blob.length, 4, "blob length");
+ torture_assert_str_equal(tctx, (char *)blob.data, "bla", "blob data");
+
+ return true;
+}
+
+static bool test_zero(struct torture_context *tctx)
+{
+ int i;
+ DATA_BLOB z = data_blob_talloc_zero(tctx, 4);
+ torture_assert_int_equal(tctx, z.length, 4, "length");
+ for (i = 0; i < z.length; i++)
+ torture_assert_int_equal(tctx, z.data[i], 0, "contents");
+ data_blob_free(&z);
+ return true;
+}
+
+
+static bool test_clear(struct torture_context *tctx)
+{
+ int i;
+ DATA_BLOB z = data_blob("lalala", 6);
+ torture_assert_int_equal(tctx, z.length, 6, "length");
+ data_blob_clear(&z);
+ for (i = 0; i < z.length; i++)
+ torture_assert_int_equal(tctx, z.data[i], 0, "contents");
+ data_blob_free(&z);
+ return true;
+}
+
+static bool test_cmp(struct torture_context *tctx)
+{
+ DATA_BLOB a = data_blob_string_const("bla");
+ DATA_BLOB b = data_blob_string_const("blae");
+ torture_assert(tctx, data_blob_cmp(&a, &b) != 0, "cmp different");
+ torture_assert(tctx, data_blob_cmp(&a, &a) == 0, "cmp self");
+ return true;
+}
+
+static bool test_equal_const_time(struct torture_context *tctx)
+{
+ const char *test_string = "foobarfoo";
+
+ DATA_BLOB null = data_blob_const(NULL, 0);
+ DATA_BLOB foobar = data_blob_const(test_string, 6);
+ DATA_BLOB bar = data_blob_const(test_string + 3, 3);
+
+ /* These data blobs both contain 'foo', but at different addresses. */
+ DATA_BLOB foo_same = data_blob_const(test_string, 3);
+ DATA_BLOB foo_other = data_blob_const(test_string + 6, 3);
+
+ /* Test all equality combinations behave as expected. */
+ torture_assert(tctx, data_blob_equal_const_time(&null, &null), "null == null");
+ torture_assert(tctx, !data_blob_equal_const_time(&null, &foobar), "null != 'foobar'");
+ torture_assert(tctx, !data_blob_equal_const_time(&null, &bar), "null != 'bar'");
+ torture_assert(tctx, !data_blob_equal_const_time(&null, &foo_same), "null != 'foo'");
+ torture_assert(tctx, !data_blob_equal_const_time(&null, &foo_other), "null != 'foo'");
+
+ torture_assert(tctx, !data_blob_equal_const_time(&foobar, &null), "'foobar' != null");
+ torture_assert(tctx, data_blob_equal_const_time(&foobar, &foobar), "'foobar' == 'foobar'");
+ torture_assert(tctx, !data_blob_equal_const_time(&foobar, &bar), "'foobar' != 'bar'");
+ torture_assert(tctx, !data_blob_equal_const_time(&foobar, &foo_same), "'foobar' != 'foo'");
+ torture_assert(tctx, !data_blob_equal_const_time(&foobar, &foo_other), "'foobar' != 'foo'");
+
+ torture_assert(tctx, !data_blob_equal_const_time(&foo_same, &null), "'foo' != null");
+ torture_assert(tctx, !data_blob_equal_const_time(&foo_same, &foobar), "'foo' != 'foobar'");
+ torture_assert(tctx, !data_blob_equal_const_time(&foo_same, &bar), "'foo' != 'bar'");
+ torture_assert(tctx, data_blob_equal_const_time(&foo_same, &foo_same), "'foo' == 'foo'");
+ torture_assert(tctx, data_blob_equal_const_time(&foo_same, &foo_other), "'foo' == 'foo'");
+
+ torture_assert(tctx, !data_blob_equal_const_time(&foo_other, &null), "'foo' != null");
+ torture_assert(tctx, !data_blob_equal_const_time(&foo_other, &foobar), "'foo' != 'foobar'");
+ torture_assert(tctx, !data_blob_equal_const_time(&foo_other, &bar), "'foo' != 'bar'");
+ torture_assert(tctx, data_blob_equal_const_time(&foo_other, &foo_same), "'foo' == 'foo'");
+ torture_assert(tctx, data_blob_equal_const_time(&foo_other, &foo_other), "'foo' == 'foo'");
+
+ torture_assert(tctx, !data_blob_equal_const_time(&bar, &null), "'bar' != null");
+ torture_assert(tctx, !data_blob_equal_const_time(&bar, &foobar), "'bar' != 'foobar'");
+ torture_assert(tctx, data_blob_equal_const_time(&bar, &bar), "'bar' == 'bar'");
+ torture_assert(tctx, !data_blob_equal_const_time(&bar, &foo_same), "'bar' != 'foo'");
+ torture_assert(tctx, !data_blob_equal_const_time(&bar, &foo_other), "'bar' != 'foo'");
+
+ return true;
+}
+
+static bool test_hex_string(struct torture_context *tctx)
+{
+ DATA_BLOB a = data_blob_string_const("\xC\xA\xF\xE");
+ torture_assert_str_equal(tctx, data_blob_hex_string_lower(tctx, &a), "0c0a0f0e", "hex string");
+ torture_assert_str_equal(tctx, data_blob_hex_string_upper(tctx, &a), "0C0A0F0E", "hex string");
+ return true;
+}
+
+static bool test_append_NULL_0(struct torture_context *tctx)
+{
+ DATA_BLOB z = data_blob_talloc_zero(tctx, 0);
+ torture_assert_int_equal(tctx, z.length, 0, "length");
+ torture_assert(tctx, z.data == NULL, "data");
+ torture_assert(tctx, data_blob_append(NULL, &z, NULL, 0), "append NULL,0");
+ torture_assert(tctx, data_blob_append(NULL, &z, "", 0), "append '',0");
+ torture_assert_int_equal(tctx, z.length, 0, "length");
+ torture_assert(tctx, z.data == NULL, "data");
+ return true;
+}
+
+static bool test_append_empty_0(struct torture_context *tctx)
+{
+ DATA_BLOB e = data_blob_talloc(tctx, "", 0);
+ torture_assert_int_equal(tctx, e.length, 0, "length");
+ torture_assert(tctx, e.data != NULL, "data");
+ torture_assert(tctx, data_blob_append(NULL, &e, NULL, 0), "append NULL,0");
+ torture_assert(tctx, data_blob_append(NULL, &e, "", 0), "append '',0");
+ torture_assert_int_equal(tctx, e.length, 0, "length");
+ torture_assert(tctx, e.data != NULL, "data");
+ return true;
+}
+
+struct torture_suite *torture_local_util_data_blob(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "datablob");
+
+ torture_suite_add_simple_test(suite, "string", test_string);
+ torture_suite_add_simple_test(suite, "string_null", test_string_null);
+ torture_suite_add_simple_test(suite, "zero", test_zero);;
+ torture_suite_add_simple_test(suite, "clear", test_clear);
+ torture_suite_add_simple_test(suite, "cmp", test_cmp);
+ torture_suite_add_simple_test(suite, "equal_const_time", test_equal_const_time);
+ torture_suite_add_simple_test(suite, "hex string", test_hex_string);
+ torture_suite_add_simple_test(suite, "append_NULL_0", test_append_NULL_0);
+ torture_suite_add_simple_test(suite, "append_empty_0", test_append_empty_0);
+
+ return suite;
+}
diff --git a/lib/util/tests/dlinklist.c b/lib/util/tests/dlinklist.c
new file mode 100644
index 0000000..50adab3
--- /dev/null
+++ b/lib/util/tests/dlinklist.c
@@ -0,0 +1,131 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of DLIST_*() macros
+
+ Copyright (C) Andrew Tridgell 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/util/dlinklist.h"
+
+struct listel {
+ struct listel *next, *prev;
+};
+
+static bool torture_local_dlinklist_simple(struct torture_context *tctx)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct listel *l1 = NULL, *l2 = NULL, *el, *el2;
+ int i;
+
+ torture_comment(tctx, "add 5 elements at front\n");
+ for (i=0; i<5; i++) {
+ el = talloc(mem_ctx, struct listel);
+ DLIST_ADD(l1, el);
+ }
+
+ torture_comment(tctx, "add 5 elements at end\n");
+ for (i=0; i<5; i++) {
+ el = talloc(mem_ctx, struct listel);
+ DLIST_ADD_END(l1, el);
+ }
+
+ torture_comment(tctx, "delete 3 from front\n");
+ for (i=0; i < 3; i++) {
+ el = l1;
+ DLIST_REMOVE(l1, l1);
+ DLIST_ADD(l2, el);
+ }
+
+ torture_comment(tctx, "delete 3 from back\n");
+ for (i=0; i < 3; i++) {
+ el = DLIST_TAIL(l1);
+ DLIST_REMOVE(l1, el);
+ DLIST_ADD_END(l2, el);
+ }
+
+ torture_comment(tctx, "count forward\n");
+ for (i=0,el=l1; el; el=el->next) i++;
+ torture_assert_int_equal(tctx, i, 4, "should have 4 elements");
+
+ torture_comment(tctx, "count backwards\n");
+ for (i=0,el=DLIST_TAIL(l1); el; el=DLIST_PREV(el)) i++;
+ torture_assert_int_equal(tctx, i, 4, "should have 4 elements");
+
+ torture_comment(tctx, "check DLIST_HEAD\n");
+ el = DLIST_TAIL(l1);
+ DLIST_HEAD(el, el2);
+ torture_assert(tctx, el2 == l1, "should find head");
+
+ torture_comment(tctx, "check DLIST_ADD_AFTER\n");
+ el = talloc(mem_ctx, struct listel);
+ el2 = talloc(mem_ctx, struct listel);
+ DLIST_ADD_AFTER(l1, el, l1);
+ DLIST_ADD_AFTER(l1, el2, el);
+ torture_assert(tctx, l1->next == el, "2nd in list");
+ torture_assert(tctx, el->next == el2, "3rd in list");
+
+ torture_comment(tctx, "check DLIST_PROMOTE\n");
+ DLIST_PROMOTE(l1, el2);
+ torture_assert(tctx, el2==l1, "1st in list");
+ torture_assert(tctx, el2->next->next == el, "3rd in list");
+
+ torture_comment(tctx, "check DLIST_DEMOTE\n");
+ DLIST_DEMOTE(l1, el);
+ torture_assert(tctx, el->next == NULL, "last in list");
+ torture_assert(tctx, el2->prev == el, "backlink from head");
+
+ torture_comment(tctx, "count forward\n");
+ for (i=0,el=l1; el; el=el->next) i++;
+ torture_assert_int_equal(tctx, i, 6, "should have 6 elements");
+
+ torture_comment(tctx, "count backwards\n");
+ for (i=0,el=DLIST_TAIL(l1); el; el=DLIST_PREV(el)) i++;
+ torture_assert_int_equal(tctx, i, 6, "should have 6 elements");
+
+ torture_comment(tctx, "check DLIST_CONCATENATE\n");
+ DLIST_CONCATENATE(l1, l2);
+ torture_comment(tctx, "count forward\n");
+ for (i=0,el=l1; el; el=el->next) i++;
+ torture_assert_int_equal(tctx, i, 12, "should have 12 elements");
+
+ torture_comment(tctx, "count backwards\n");
+ for (i=0,el=DLIST_TAIL(l1); el; el=DLIST_PREV(el)) i++;
+ torture_assert_int_equal(tctx, i, 12, "should have 12 elements");
+
+ torture_comment(tctx, "free forwards\n");
+ for (el=l1; el; el=el2) {
+ el2 = el->next;
+ DLIST_REMOVE(l1, el);
+ talloc_free(el);
+ }
+
+ torture_assert(tctx, l1 == NULL, "list empty");
+ torture_assert_int_equal(tctx, talloc_total_blocks(mem_ctx), 1, "1 block");
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+struct torture_suite *torture_local_dlinklist(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "dlinklist");
+ torture_suite_add_simple_test(suite, "dlinklist", torture_local_dlinklist_simple);
+ return suite;
+}
diff --git a/lib/util/tests/file.c b/lib/util/tests/file.c
new file mode 100644
index 0000000..3501c7e
--- /dev/null
+++ b/lib/util/tests/file.c
@@ -0,0 +1,291 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ util_file testing
+
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+#define TEST_FILENAME "utilfile.test"
+#define TEST_LINE1 "This is list line 1..."
+#define TEST_LINE2 ".. and this is line 2"
+#define TEST_LINE3 "and end of the file"
+
+#define TEST_DATA TEST_LINE1 "\n" TEST_LINE2 "\n" TEST_LINE3
+
+static bool test_file_load_save(struct torture_context *tctx)
+{
+ size_t len;
+ char *data;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ torture_assert(tctx, file_save(TEST_FILENAME, TEST_DATA, strlen(TEST_DATA)),
+ "saving file");
+
+ torture_assert_file_contains_text(tctx, TEST_FILENAME, TEST_DATA,
+ "file contents");
+
+ data = file_load(TEST_FILENAME, &len, 0, mem_ctx);
+ torture_assert(tctx, data, "loading file");
+
+ torture_assert_int_equal(tctx, len, strlen(TEST_DATA), "Length");
+
+ torture_assert_mem_equal(tctx, data, TEST_DATA, len, "Contents");
+
+ data = file_load(TEST_FILENAME, &len, 5, mem_ctx);
+
+ torture_assert_int_equal(tctx, len, 5, "Length");
+
+ torture_assert_mem_equal(tctx, data, TEST_DATA, len, "Contents");
+
+ unlink(TEST_FILENAME);
+ return true;
+}
+
+#define TEST_DATA_WITH_NEWLINE TEST_DATA "\n"
+#define TEST_DATA_NO_NEWLINE TEST_DATA
+#define TEST_DATA_EMPTY ""
+#define TEST_DATA_BLANKS_ONLY "\n\n\n\n\n"
+#define TEST_DATA_WITH_TRAILING_BLANKS TEST_DATA TEST_DATA_BLANKS_ONLY
+
+static bool test_file_lines_load(struct torture_context *tctx)
+{
+ char **lines;
+ int numlines;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ /*
+ * Last line has trailing whitespace
+ */
+
+ torture_assert(tctx,
+ file_save(TEST_FILENAME,
+ TEST_DATA_WITH_NEWLINE,
+ strlen(TEST_DATA_WITH_NEWLINE)),
+ "saving file");
+
+ lines = file_lines_load(TEST_FILENAME, &numlines, 0, mem_ctx);
+
+ torture_assert_int_equal(tctx, numlines, 3, "Lines");
+
+ torture_assert_mem_equal(tctx,
+ lines[0],
+ TEST_LINE1,
+ strlen(TEST_LINE1),
+ "Line 1");
+
+ torture_assert_mem_equal(tctx,
+ lines[1],
+ TEST_LINE2,
+ strlen(TEST_LINE2),
+ "Line 2");
+
+ torture_assert_mem_equal(tctx,
+ lines[2],
+ TEST_LINE3,
+ strlen(TEST_LINE3),
+ "Line 3");
+
+ unlink(TEST_FILENAME);
+
+ /*
+ * Last line has NO trailing whitespace
+ */
+
+ torture_assert(tctx,
+ file_save(TEST_FILENAME,
+ TEST_DATA_NO_NEWLINE,
+ strlen(TEST_DATA_NO_NEWLINE)),
+ "saving file");
+
+ lines = file_lines_load(TEST_FILENAME, &numlines, 0, mem_ctx);
+
+ torture_assert_int_equal(tctx, numlines, 3, "Lines");
+
+ torture_assert_mem_equal(tctx,
+ lines[0],
+ TEST_LINE1,
+ strlen(TEST_LINE1),
+ "Line 1");
+
+ torture_assert_mem_equal(tctx,
+ lines[1],
+ TEST_LINE2,
+ strlen(TEST_LINE2),
+ "Line 2");
+
+ torture_assert_mem_equal(tctx,
+ lines[2],
+ TEST_LINE3,
+ strlen(TEST_LINE3),
+ "Line 3");
+
+ unlink(TEST_FILENAME);
+
+ /*
+ * Empty file
+ */
+
+ torture_assert(tctx,
+ file_save(TEST_FILENAME,
+ TEST_DATA_EMPTY,
+ strlen(TEST_DATA_EMPTY)),
+ "saving file");
+
+ (void)file_lines_load(TEST_FILENAME, &numlines, 0, mem_ctx);
+
+ torture_assert_int_equal(tctx, numlines, 0, "Lines");
+
+ unlink(TEST_FILENAME);
+
+ /*
+ * Just blank lines
+ */
+
+ torture_assert(tctx,
+ file_save(TEST_FILENAME,
+ TEST_DATA_BLANKS_ONLY,
+ strlen(TEST_DATA_BLANKS_ONLY)),
+ "saving file");
+
+ lines = file_lines_load(TEST_FILENAME, &numlines, 0, mem_ctx);
+
+ torture_assert_int_equal(tctx, numlines, 0, "Lines");
+
+ unlink(TEST_FILENAME);
+
+ /*
+ * Several trailing blank lines
+ */
+
+ torture_assert(tctx,
+ file_save(TEST_FILENAME,
+ TEST_DATA_WITH_TRAILING_BLANKS,
+ strlen(TEST_DATA_WITH_TRAILING_BLANKS)),
+ "saving file");
+
+ lines = file_lines_load(TEST_FILENAME, &numlines, 0, mem_ctx);
+
+ torture_assert_int_equal(tctx, numlines, 3, "Lines");
+
+ torture_assert_mem_equal(tctx,
+ lines[0],
+ TEST_LINE1,
+ strlen(TEST_LINE1),
+ "Line 1");
+
+ torture_assert_mem_equal(tctx,
+ lines[1],
+ TEST_LINE2,
+ strlen(TEST_LINE2),
+ "Line 2");
+
+ torture_assert_mem_equal(tctx,
+ lines[2],
+ TEST_LINE3,
+ strlen(TEST_LINE3),
+ "Line 3");
+
+ unlink(TEST_FILENAME);
+
+ return true;
+}
+
+static bool test_afdgets(struct torture_context *tctx)
+{
+ int fd;
+ char *line;
+ TALLOC_CTX *mem_ctx = tctx;
+ bool ret = false;
+
+ torture_assert(tctx, file_save(TEST_FILENAME, (const void *)TEST_DATA,
+ strlen(TEST_DATA)),
+ "saving file");
+
+ fd = open(TEST_FILENAME, O_RDONLY);
+
+ torture_assert(tctx, fd != -1, "opening file");
+
+ line = afdgets(fd, mem_ctx, 8);
+ torture_assert_goto(tctx, strcmp(line, TEST_LINE1) == 0, ret, done,
+ "line 1 mismatch");
+
+ line = afdgets(fd, mem_ctx, 8);
+ torture_assert_goto(tctx, strcmp(line, TEST_LINE2) == 0, ret, done,
+ "line 2 mismatch");
+
+ line = afdgets(fd, mem_ctx, 8);
+ torture_assert_goto(tctx, strcmp(line, TEST_LINE3) == 0, ret, done,
+ "line 3 mismatch");
+ ret = true;
+done:
+ close(fd);
+
+ unlink(TEST_FILENAME);
+ return ret;
+}
+
+static bool test_file_lines_parse(struct torture_context *tctx)
+{
+ char **lines;
+ int numlines;
+ TALLOC_CTX *mem_ctx = tctx;
+ char *buf;
+ size_t size;
+
+ torture_assert(tctx, file_save(TEST_FILENAME,
+ (const void *)TEST_DATA,
+ strlen(TEST_DATA)),
+ "saving file");
+
+ buf = file_load(TEST_FILENAME, &size, 0, mem_ctx);
+ torture_assert(tctx, buf, "failed to load file");
+ unlink(TEST_FILENAME);
+
+ lines = file_lines_parse(buf,
+ size,
+ &numlines,
+ mem_ctx);
+ torture_assert(tctx, lines, "failed to parse lines");
+
+ TALLOC_FREE(lines);
+ TALLOC_FREE(buf);
+ return true;
+}
+
+struct torture_suite *torture_local_util_file(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "file");
+
+ torture_suite_add_simple_test(suite, "file_load_save",
+ test_file_load_save);
+
+ torture_suite_add_simple_test(suite,
+ "file_lines_load",
+ test_file_lines_load);
+
+ torture_suite_add_simple_test(suite, "afdgets", test_afdgets);
+
+ torture_suite_add_simple_test(suite, "file_lines_parse",
+ test_file_lines_parse);
+
+ return suite;
+}
diff --git a/lib/util/tests/genrand.c b/lib/util/tests/genrand.c
new file mode 100644
index 0000000..3987c33
--- /dev/null
+++ b/lib/util/tests/genrand.c
@@ -0,0 +1,61 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of random data routines.
+
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+static bool test_check_password_quality(struct torture_context *tctx)
+{
+ torture_assert(tctx, !check_password_quality(""), "empty password");
+ torture_assert(tctx, !check_password_quality("a"), "one char password");
+ torture_assert(tctx, !check_password_quality("aaaaaaaaaaaa"), "same char password");
+ torture_assert(tctx, !check_password_quality("BLA"), "multiple upcases password");
+ torture_assert(tctx, !check_password_quality("123"), "digits only");
+ torture_assert(tctx, !check_password_quality("matthiéu"), "not enough high symbols");
+ torture_assert(tctx, !check_password_quality("abcdééàçè"), "only lower case");
+ torture_assert(tctx, !check_password_quality("abcdééàçè+"), "only lower and symbols");
+ torture_assert(tctx, check_password_quality("abcdééàçè+ढ"), "valid");
+ torture_assert(tctx, check_password_quality("ç+ढ"), "valid");
+ torture_assert(tctx, check_password_quality("A2e"), "valid");
+ torture_assert(tctx, check_password_quality("BA2eLi443"), "valid");
+ return true;
+}
+
+static bool test_generate_random_str(struct torture_context *tctx)
+{
+ TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
+ char *r = generate_random_str(mem_ctx, 10);
+ torture_assert_int_equal(tctx, strlen(r), 10, "right length generated");
+ r = generate_random_str(mem_ctx, 5);
+ torture_assert_int_equal(tctx, strlen(r), 5, "right length generated");
+
+ TALLOC_FREE(mem_ctx);
+ return true;
+}
+
+struct torture_suite *torture_local_genrand(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "genrand");
+ torture_suite_add_simple_test(suite, "check_password_quality", test_check_password_quality);
+ torture_suite_add_simple_test(suite, "generate_random_str", test_generate_random_str);
+ return suite;
+}
diff --git a/lib/util/tests/genrandperf.c b/lib/util/tests/genrandperf.c
new file mode 100644
index 0000000..32d19ab
--- /dev/null
+++ b/lib/util/tests/genrandperf.c
@@ -0,0 +1,39 @@
+/*
+ Unix SMB/CIFS implementation.
+ local testing of random data routines.
+ Copyright (C) Volker Lendecke <vl@samba.org> 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/genrand.h"
+
+int main(int argc, const char *argv[])
+{
+ int i, num;
+ uint64_t val;
+
+ if (argc != 2) {
+ fprintf(stderr, "genrandperf <num>\n");
+ exit(1);
+ }
+ num = atoi(argv[1]);
+
+ for(i=0; i<num; i++) {
+ generate_random_buffer((uint8_t *)&val, sizeof(val));
+ }
+ printf("%"PRIu64"\n", val);
+ return 0;
+}
diff --git a/lib/util/tests/idtree.c b/lib/util/tests/idtree.c
new file mode 100644
index 0000000..d54ab27
--- /dev/null
+++ b/lib/util/tests/idtree.c
@@ -0,0 +1,123 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of idtree routines.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/util/idtree.h"
+
+static bool torture_local_idtree_simple(struct torture_context *tctx)
+{
+ struct idr_context *idr;
+ int i, ret;
+ int *ids;
+ int *present;
+ extern int torture_numops;
+ int n = torture_numops;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ idr = idr_init(mem_ctx);
+
+ ids = talloc_zero_array(mem_ctx, int, n);
+ present = talloc_zero_array(mem_ctx, int, n);
+
+ for (i=0;i<n;i++) {
+ ids[i] = -1;
+ }
+
+ for (i=0;i<n;i++) {
+ int ii = random() % n;
+ void *p = idr_find(idr, ids[ii]);
+ if (present[ii]) {
+ if (p != &ids[ii]) {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "wrong ptr at %d - %p should be %p",
+ ii, p, &ids[ii]));
+ }
+ if (random() % 7 == 0) {
+ if (idr_remove(idr, ids[ii]) != 0) {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "remove failed at %d (id=%d)",
+ i, ids[ii]));
+ }
+ present[ii] = 0;
+ ids[ii] = -1;
+ }
+ } else {
+ if (p != NULL) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "non-present at %d gave %p (would be %d)",
+ ii, p,
+ (int)((((char *)p) - (char *)(&ids[0])) / sizeof(int))));
+ }
+ if (random() % 5) {
+ ids[ii] = idr_get_new(idr, &ids[ii], n);
+ if (ids[ii] < 0) {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "alloc failure at %d (ret=%d)",
+ ii, ids[ii]));
+ } else {
+ present[ii] = 1;
+ }
+ }
+ }
+ }
+
+ torture_comment(tctx, "done %d random ops\n", i);
+
+ for (i=0;i<n;i++) {
+ if (present[i]) {
+ if (idr_remove(idr, ids[i]) != 0) {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "delete failed on cleanup at %d (id=%d)",
+ i, ids[i]));
+ }
+ }
+ }
+
+ /* now test some limits */
+ for (i=0;i<25000;i++) {
+ ret = idr_get_new_above(idr, &ids[0], random() % 25000, 0x10000-3);
+ torture_assert(tctx, ret != -1, "idr_get_new_above failed");
+ }
+
+ ret = idr_get_new_above(idr, &ids[0], 0x10000-2, 0x10000);
+ torture_assert_int_equal(tctx, ret, 0x10000-2, "idr_get_new_above failed");
+ ret = idr_get_new_above(idr, &ids[0], 0x10000-1, 0x10000);
+ torture_assert_int_equal(tctx, ret, 0x10000-1, "idr_get_new_above failed");
+ ret = idr_get_new_above(idr, &ids[0], 0x10000, 0x10000);
+ torture_assert_int_equal(tctx, ret, 0x10000, "idr_get_new_above failed");
+ ret = idr_get_new_above(idr, &ids[0], 0x10000+1, 0x10000);
+ torture_assert_int_equal(tctx, ret, -1, "idr_get_new_above succeeded above limit");
+ ret = idr_get_new_above(idr, &ids[0], 0x10000+2, 0x10000);
+ torture_assert_int_equal(tctx, ret, -1, "idr_get_new_above succeeded above limit");
+
+ torture_comment(tctx, "cleaned up\n");
+ return true;
+}
+
+struct torture_suite *torture_local_idtree(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "idtree");
+ torture_suite_add_simple_test(suite, "idtree", torture_local_idtree_simple);
+ return suite;
+}
diff --git a/lib/util/tests/rfc1738.c b/lib/util/tests/rfc1738.c
new file mode 100644
index 0000000..4f7eced
--- /dev/null
+++ b/lib/util/tests/rfc1738.c
@@ -0,0 +1,411 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <cmocka.h>
+#include "lib/replace/replace.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <ctype.h>
+#include <string.h>
+#include "lib/util/samba_util.h"
+
+/* These flags say what can be asserted about a relationship between a string
+ and its supposedly escaped equivalent.
+
+ The first part of the flag name indicates the direction of transformation;
+ the second part is the expected result. For example, ESCAPE_EQ means the
+ escape is expected to succeed and result is expected to be equal to the
+ given answer. ESCAPE_EQ_CASECMP is only equal when compared
+ case-insensitively. UNESCAPE_ERR means unescaping the escaped string should
+ result in an error.
+*/
+#define UNESCAPE_ERR 1
+#define ESCAPE_ERR 2
+#define ESCAPE_EQ 4
+#define UNESCAPE_EQ 8
+#define ESCAPE_NE 16
+#define UNESCAPE_NE 32
+#define ESCAPE_EQ_CASECMP 64
+
+struct rfc1738_test {
+ const char *escaped; /* original for unescape; result for escape */
+ const char *unescaped; /* result in unescape; original for escape */
+ uint32_t flags; /* see above */
+ int unesc_len; /* end - start will be this */
+ int unesc_strlen; /* strlen() will say this */
+ int esc_len; /* escaped string length */
+};
+
+/* unreserved = ALPHA DIGIT - . _ ~ */
+
+char spectrum[255 + 1];
+char spectrum_escaped[255 * 3 + 1];
+
+struct rfc1738_test examples[] = {
+
+#define SIMPLE1 "this_is_a_simple-string._With_no_escapes~" /* maps to self */
+ {
+ SIMPLE1,
+ SIMPLE1,
+ ESCAPE_EQ | UNESCAPE_EQ, /* round trip should work */
+ sizeof(SIMPLE1) - 1,
+ sizeof(SIMPLE1) - 1,
+ sizeof(SIMPLE1) - 1,
+ },
+#define SIMPLE2 "no escapes, but\n non-printables \xc5\x8d\x99"
+#define SIMPLE2_ESC "no%20escapes%2C%20but%0A%20non-printables%20%C5%8D%99"
+ {
+ SIMPLE2_ESC,
+ SIMPLE2,
+ ESCAPE_EQ | UNESCAPE_EQ,
+ sizeof(SIMPLE2) - 1,
+ sizeof(SIMPLE2) - 1,
+ sizeof(SIMPLE2_ESC) - 1,
+ },
+#define SIMPLE3 "this @#$^&*()_+{}:;"
+#define SIMPLE3_ESC "this%20%40%23%24%5E%26%2A%28%29_%2B%7B%7D%3A%3B"
+ {
+ SIMPLE3_ESC,
+ SIMPLE3,
+ ESCAPE_EQ | UNESCAPE_EQ,
+ sizeof(SIMPLE3) - 1,
+ sizeof(SIMPLE3) - 1,
+ sizeof(SIMPLE3_ESC) - 1,
+ },
+
+#define ESCAPE1 "%/\x06this string has expected escapes"
+#define ESCAPE1_ESC "%25%2F%06this%20string%20has%20expected%20escapes"
+#define ESCAPE1_ESC_ESC "%2525%252F%2506this%2520string%2520has%2520expected"\
+ "%2520escapes"
+ {
+ ESCAPE1_ESC,
+ ESCAPE1,
+ ESCAPE_EQ | UNESCAPE_EQ,
+ sizeof(ESCAPE1) - 1,
+ sizeof(ESCAPE1) - 1,
+ sizeof(ESCAPE1_ESC) - 1,
+ },
+ {
+ ESCAPE1_ESC_ESC, /*re-escaping */
+ ESCAPE1_ESC,
+ ESCAPE_EQ | UNESCAPE_EQ,
+ sizeof(ESCAPE1_ESC) - 1,
+ sizeof(ESCAPE1_ESC) - 1,
+ sizeof(ESCAPE1_ESC_ESC) - 1,
+ },
+#define ESCAPE2 "%25%2f%06-this-string-has-expected-lowercase-escapes-%ab"
+#define ESCAPE2_UNESC "%/\x06-this-string-has-expected-lowercase-escapes-\xab"
+ {
+ ESCAPE2,
+ ESCAPE2_UNESC,
+ ESCAPE_EQ_CASECMP | UNESCAPE_EQ, /* escape won't match case */
+ sizeof(ESCAPE2_UNESC) - 1,
+ sizeof(ESCAPE2_UNESC) - 1,
+ sizeof(ESCAPE2) - 1,
+ },
+#define ESCAPE3 "%25%2f%06 %32 %44 %6a%AA THIS string h%61s random escapes %ab"
+#define ESCAPE3_UNESC "%/\x06 2 D j\xAA THIS string has random escapes \xab"
+ {
+ ESCAPE3,
+ ESCAPE3_UNESC,
+ ESCAPE_NE | UNESCAPE_EQ, /* escape will have escaped spaces */
+ sizeof(ESCAPE3_UNESC) - 1,
+ sizeof(ESCAPE3_UNESC) - 1,
+ sizeof(ESCAPE3) - 1,
+ },
+#define ESCAPE4 "%25%25%25" /* */
+#define ESCAPE4_UNESC "%%%" /* */
+#define ESCAPE4_ESC "%2525%2525%2525"
+ {
+ ESCAPE4,
+ ESCAPE4_UNESC,
+ ESCAPE_EQ | UNESCAPE_EQ,
+ sizeof(ESCAPE4_UNESC) - 1,
+ sizeof(ESCAPE4_UNESC) - 1,
+ sizeof(ESCAPE4) - 1,
+ },
+ {
+ ESCAPE4_ESC,
+ ESCAPE4,
+ ESCAPE_EQ | UNESCAPE_EQ,
+ sizeof(ESCAPE4) - 1,
+ sizeof(ESCAPE4) - 1,
+ sizeof(ESCAPE4_ESC) - 1,
+ },
+#define BAD1 "trailing percent is bad %"
+#define BAD1_ESC "trailing%20percent%20is%20bad%20%25"
+ {
+ BAD1_ESC,
+ BAD1,
+ UNESCAPE_EQ |ESCAPE_EQ,
+ sizeof(BAD1) - 1,
+ sizeof(BAD1) - 1,
+ sizeof(BAD1_ESC) - 1,
+ },
+ {
+ BAD1,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD1) - 1,
+ },
+#define BAD2 "trailing percent is bad %1"
+#define BAD3 "bad characters %1 "
+ {
+ BAD2,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD2) - 1,
+ },
+ {
+ BAD3,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD3) - 1,
+ },
+#define BAD4 "bad characters %1 "
+ {
+ BAD4,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD4) - 1,
+ },
+#define BAD5 "bad characters %1- "
+ {
+ BAD5,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD5) - 1,
+ },
+#define BAD6 "bad characters %1G "
+ {
+ BAD6,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD6) - 1,
+ },
+#define BAD7 "bad characters %%1 "
+ {
+ BAD7,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD7) - 1,
+ },
+#define BAD8 "bad characters %sb "
+ {
+ BAD8,
+ NULL,
+ UNESCAPE_ERR,
+ 0,
+ 0,
+ sizeof(BAD8) - 1,
+ },
+#define BAD_SSCANF "sscanf would be happy with this\n"
+#define BAD_SSCANF_ESC "sscanf would be happy with this% a"
+ {
+ BAD_SSCANF_ESC,
+ BAD_SSCANF,
+ ESCAPE_NE | UNESCAPE_ERR,
+ sizeof(BAD_SSCANF) - 1,
+ sizeof(BAD_SSCANF) - 1,
+ sizeof(BAD_SSCANF_ESC) - 1,
+ },
+ /* now try some with zeros in. escaping can't see past zeros, and the result is truncated */
+#define ZERO "%00"
+#define ZERO_UNESC "\0"
+ {
+ ESCAPE4 ZERO ESCAPE4,
+ ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC,
+ ESCAPE_NE | UNESCAPE_EQ,
+ sizeof(ESCAPE4_UNESC ZERO_UNESC ESCAPE4_UNESC) - 1,
+ sizeof(ESCAPE4_UNESC) - 1,
+ sizeof(ESCAPE4 ZERO ESCAPE4) - 1,
+ },
+ {
+ ZERO ESCAPE4,
+ ZERO_UNESC ESCAPE4_UNESC,
+ ESCAPE_NE | UNESCAPE_EQ,
+ sizeof(ZERO_UNESC ESCAPE4_UNESC) - 1,
+ 0,
+ sizeof(ZERO ESCAPE4) - 1,
+ },
+ {
+ ZERO,
+ ZERO_UNESC,
+ ESCAPE_NE | UNESCAPE_EQ,
+ sizeof(ZERO_UNESC) - 1,
+ 0,
+ sizeof(ZERO) - 1,
+ },
+ {
+ spectrum_escaped,
+ spectrum,
+ ESCAPE_EQ | UNESCAPE_EQ,
+ 255,
+ 255,
+ 255 * 3,
+ },
+};
+
+static struct rfc1738_test * dup_test(struct rfc1738_test *src)
+{
+ struct rfc1738_test *dest = malloc(sizeof(*dest));
+ char *esc = NULL, *unesc = NULL;
+ if (dest == NULL) {
+ return NULL;
+ }
+ *dest = *src;
+ if (src->esc_len) {
+ esc = malloc(src->esc_len + 1);
+ if (esc == NULL) {
+ free(dest);
+ return NULL;
+ }
+ memcpy(esc, src->escaped, src->esc_len + 1);
+ dest->escaped = esc;
+ }
+
+ if (src->unesc_len) {
+ unesc = malloc(src->unesc_len + 1);
+ if (unesc == NULL) {
+ free(esc);
+ free(dest);
+ return NULL;
+ }
+ memcpy(unesc, src->unescaped, src->unesc_len + 1);
+ dest->unescaped = unesc;
+ }
+
+ return dest;
+}
+
+static void free_test(struct rfc1738_test *t)
+{
+ free(discard_const_p(char, t->escaped));
+ free(discard_const_p(char, t->unescaped));
+ free(t);
+}
+
+
+static void test_unescape(void **state)
+{
+ uint i;
+ char *s, *e;
+ struct rfc1738_test *test, *orig;
+ for (i = 0; i < ARRAY_SIZE(examples); i++) {
+ orig = &examples[i];
+ if ((orig->flags & (UNESCAPE_ERR |
+ UNESCAPE_EQ |
+ UNESCAPE_NE)) == 0) {
+ continue;
+ }
+ test = dup_test(&examples[i]);
+ s = discard_const_p(char, test->escaped);
+ e = rfc1738_unescape(s);
+ if (test->flags & UNESCAPE_ERR) {
+ assert_null(e);
+ free_test(test);
+ continue;
+ }
+ assert_non_null(e);
+ assert_int_equal(e - s, test->unesc_len);
+
+ if (test->flags & UNESCAPE_EQ) {
+ assert_memory_equal(s,
+ orig->unescaped,
+ orig->unesc_len);
+ assert_int_equal(strlen(s),
+ orig->unesc_strlen);
+ } else {
+ assert_memory_not_equal(s,
+ orig->unescaped,
+ orig->unesc_len);
+ assert_int_equal(strlen(s),
+ orig->unesc_strlen);
+ }
+ free_test(test);
+ }
+}
+
+static void test_escape(void **state)
+{
+ uint i;
+ char *s, *e;
+ struct rfc1738_test *test, *orig;
+ for (i = 0; i < ARRAY_SIZE(examples); i++) {
+ orig = &examples[i];
+ if ((orig->flags & (ESCAPE_EQ |
+ ESCAPE_EQ_CASECMP |
+ ESCAPE_NE)) == 0) {
+ continue;
+ }
+ test = dup_test(&examples[i]);
+ s = discard_const_p(char, test->unescaped);
+ e = rfc1738_escape_part(NULL, s);
+ if (test->flags & ESCAPE_EQ) {
+ assert_memory_equal(e, test->escaped,
+ test->esc_len + 1);
+ } else if (test->flags & ESCAPE_EQ_CASECMP) {
+ int cmp = strcasecmp(e, test->escaped);
+ assert_int_equal(cmp, 0);
+ assert_string_not_equal(e, test->escaped);
+ } else {
+ assert_string_not_equal(e, test->escaped);
+ }
+ free_test(test);
+ }
+}
+
+
+static void gen_spectrum(void)
+{
+ int i, j = 0;
+ const char *lut = "0123456789ABCDEF";
+ for (i = 1; i < 256; i++) {
+ spectrum[i - 1] = i;
+ if (isalnum(i) ||
+ i == '-' ||
+ i == '.' ||
+ i == '_' ||
+ i == '-' ||
+ i == '~') {
+ spectrum_escaped[j] = i;
+ j++;
+ } else {
+ spectrum_escaped[j] = '%';
+ spectrum_escaped[j + 1] = lut[i >> 4];
+ spectrum_escaped[j + 2] = lut[i & 15];
+ j += 3;
+ }
+ }
+ spectrum[i - 1] = '\0';
+ spectrum_escaped[j] = '\0';
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_escape),
+ cmocka_unit_test(test_unescape),
+ };
+
+ gen_spectrum();
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/util/tests/str.c b/lib/util/tests/str.c
new file mode 100644
index 0000000..41a2836
--- /dev/null
+++ b/lib/util/tests/str.c
@@ -0,0 +1,180 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ util_str testing
+
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+static bool test_string_sub_simple(struct torture_context *tctx)
+{
+ char tmp[100];
+ strlcpy(tmp, "foobar", sizeof(tmp));
+ string_sub(tmp, "foo", "bar", sizeof(tmp));
+ torture_assert_str_equal(tctx, tmp, "barbar", "invalid sub");
+ return true;
+}
+
+static bool test_string_sub_multiple(struct torture_context *tctx)
+{
+ char tmp[100];
+ strlcpy(tmp, "fooblafoo", sizeof(tmp));
+ string_sub(tmp, "foo", "bar", sizeof(tmp));
+ torture_assert_str_equal(tctx, tmp, "barblabar", "invalid sub");
+ return true;
+}
+
+static bool test_string_sub_longer(struct torture_context *tctx)
+{
+ char tmp[100];
+ strlcpy(tmp, "foobla", sizeof(tmp));
+ string_sub(tmp, "foo", "blie", sizeof(tmp));
+ torture_assert_str_equal(tctx, tmp, "bliebla", "invalid sub");
+ return true;
+}
+
+static bool test_string_sub_shorter(struct torture_context *tctx)
+{
+ char tmp[100];
+ strlcpy(tmp, "foobla", sizeof(tmp));
+ string_sub(tmp, "foo", "bl", sizeof(tmp));
+ torture_assert_str_equal(tctx, tmp, "blbla", "invalid sub");
+ return true;
+}
+
+static bool test_string_sub_special_char(struct torture_context *tctx)
+{
+ char tmp[100];
+ strlcpy(tmp, "foobla", sizeof(tmp));
+ string_sub(tmp, "foo", "%b;l", sizeof(tmp));
+ torture_assert_str_equal(tctx, tmp, "_b_lbla", "invalid sub");
+ return true;
+}
+
+static bool test_talloc_string_sub_simple(struct torture_context *tctx)
+{
+ char *t;
+
+ t = talloc_string_sub(tctx, "foobla", "foo", "bl");
+
+ torture_assert_str_equal(tctx, t, "blbla", "invalid sub");
+
+ return true;
+}
+
+static bool test_talloc_string_sub_multiple(struct torture_context *tctx)
+{
+ char *t;
+
+ t = talloc_string_sub(tctx, "fooblafoo", "foo", "aapnootmies");
+
+ torture_assert_str_equal(tctx, t, "aapnootmiesblaaapnootmies",
+ "invalid sub");
+
+ return true;
+}
+
+/*
+ * with these next three tests, the failure is that the pattern looks like
+ * "+++" because the \x.. bytes encode a zero byte in UTF-8. If we are not
+ * careful with these strings we will see crashes instead of failures.
+ */
+
+static bool test_talloc_string_sub_tricky_utf8_4(struct torture_context *tctx)
+{
+ const char string[] = "++++--\xD8\xBB";
+ const char pattern[] = "+++\xF0\x80\x80\x80++";
+ const char replace[] = "...";
+
+ char *t = talloc_string_sub(tctx, string, pattern, replace);
+ torture_assert_str_equal(tctx, t, string,
+ "should reject 4 byte NUL char");
+ talloc_free(t);
+ return true;
+}
+
+static bool test_talloc_string_sub_tricky_utf8_3(struct torture_context *tctx)
+{
+ const char string[] = "++++--\xD8\xBB";
+ const char pattern[] = "+++\xE0\x80\x80++";
+ const char replace[] = "...";
+
+ char *t = talloc_string_sub(tctx, string, pattern, replace);
+ torture_assert_str_equal(tctx, t, string,
+ "should reject 3 byte NUL char");
+ talloc_free(t);
+ return true;
+}
+
+static bool test_talloc_string_sub_tricky_utf8_2(struct torture_context *tctx)
+{
+ const char string[] = "++++--\xD8\xBB";
+ const char pattern[] = "+++\xC0\x80++";
+ const char replace[] = "...";
+
+ char *t = talloc_string_sub(tctx, string, pattern, replace);
+ torture_assert_str_equal(tctx, t, string,
+ "should reject 2 byte NUL char");
+ talloc_free(t);
+ return true;
+}
+
+
+
+
+struct torture_suite *torture_local_util_str(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "str");
+
+ torture_suite_add_simple_test(suite, "string_sub_simple",
+ test_string_sub_simple);
+
+ torture_suite_add_simple_test(suite, "string_sub_multiple",
+ test_string_sub_multiple);
+
+ torture_suite_add_simple_test(suite, "string_sub_shorter",
+ test_string_sub_shorter);
+
+ torture_suite_add_simple_test(suite, "string_sub_longer",
+ test_string_sub_longer);
+
+ torture_suite_add_simple_test(suite, "string_sub_special_chars",
+ test_string_sub_special_char);
+
+ torture_suite_add_simple_test(suite, "talloc_string_sub_simple",
+ test_talloc_string_sub_simple);
+
+ torture_suite_add_simple_test(suite, "string_sub_talloc_multiple",
+ test_talloc_string_sub_multiple);
+
+ torture_suite_add_simple_test(suite,
+ "test_talloc_string_sub_tricky_utf8_4",
+ test_talloc_string_sub_tricky_utf8_4);
+
+ torture_suite_add_simple_test(suite,
+ "test_talloc_string_sub_tricky_utf8_3",
+ test_talloc_string_sub_tricky_utf8_3);
+
+ torture_suite_add_simple_test(suite,
+ "test_talloc_string_sub_tricky_utf8_2",
+ test_talloc_string_sub_tricky_utf8_2);
+
+ return suite;
+}
diff --git a/lib/util/tests/strlist.c b/lib/util/tests/strlist.c
new file mode 100644
index 0000000..a9306b8
--- /dev/null
+++ b/lib/util/tests/strlist.c
@@ -0,0 +1,558 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ util_strlist testing
+
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "param/param.h"
+
+struct test_list_element {
+ const char *list_as_string;
+ const char *separators;
+ const char *list[5];
+};
+
+const struct test_list_element test_lists_strings[] = {
+ {
+ .list_as_string = "",
+ .list = { NULL }
+ },
+ {
+ .list_as_string = "foo",
+ .list = { "foo", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo", "bar", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo bar", NULL },
+ .separators = ";"
+ },
+ {
+ .list_as_string = "\"foo bar\"",
+ .list = { "\"foo", "bar\"", NULL }
+ },
+ {
+ .list_as_string = "\"foo bar\",comma\ttab",
+ .list = { "\"foo", "bar\"", "comma", "tab", NULL }
+ },
+ {
+ .list_as_string = "\"foo bar\",comma;semicolon",
+ .list = { "\"foo bar\",comma", "semicolon", NULL },
+ .separators = ";"
+ }
+};
+
+const struct test_list_element test_lists_shell_strings[] = {
+ {
+ .list_as_string = "",
+ .list = { NULL }
+ },
+ {
+ .list_as_string = "foo",
+ .list = { "foo", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo", "bar", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo bar", NULL },
+ .separators = ";"
+ },
+ {
+ .list_as_string = "\"foo bar\"",
+ .list = { "foo bar", NULL }
+ },
+ {
+ .list_as_string = "foo bar \"bla \"",
+ .list = { "foo", "bar", "bla ", NULL }
+ },
+ {
+ .list_as_string = "foo \"\" bla",
+ .list = { "foo", "", "bla", NULL },
+ },
+ {
+ .list_as_string = "bla \"\"\"\" blie",
+ .list = { "bla", "", "", "blie", NULL },
+ }
+};
+
+static bool test_lists_shell(struct torture_context *tctx, const void *data)
+{
+ const struct test_list_element *element = data;
+
+ char **ret1, **ret2, *tmp;
+ bool match = true;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ ret1 = str_list_make_shell(mem_ctx, element->list_as_string, element->separators);
+
+ torture_assert(tctx, ret1, "str_list_make_shell() must not return NULL");
+ tmp = str_list_join_shell(mem_ctx, discard_const_p(const char *, ret1),
+ element->separators ? *element->separators : ' ');
+ ret2 = str_list_make_shell(mem_ctx, tmp, element->separators);
+
+ if ((ret1 == NULL || ret2 == NULL) && ret2 != ret1) {
+ match = false;
+ } else {
+ int j;
+ for (j = 0; ret1[j] && ret2[j]; j++) {
+ if (strcmp(ret1[j], ret2[j]) != 0) {
+ match = false;
+ break;
+ }
+ }
+
+ if (ret1[j] || ret2[j])
+ match = false;
+ }
+
+ torture_assert(tctx, match, talloc_asprintf(tctx,
+ "str_list_{make,join}_shell: Error double parsing, first run:\n%s\nSecond run: \n%s", element->list_as_string, tmp));
+ torture_assert(tctx, str_list_equal((const char * const *) ret1,
+ element->list),
+ talloc_asprintf(tctx,
+ "str_list_make_shell(%s) failed to create correct list",
+ element->list_as_string));
+
+ return true;
+}
+
+static bool test_list_make(struct torture_context *tctx, const void *data)
+{
+ const struct test_list_element *element = data;
+
+ char **result;
+ result = str_list_make(tctx, element->list_as_string, element->separators);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ torture_assert(tctx, str_list_equal((const char * const *) result,
+ element->list),
+ talloc_asprintf(tctx,
+ "str_list_make(%s) failed to create correct list",
+ element->list_as_string));
+ return true;
+}
+
+static bool test_list_copy(struct torture_context *tctx)
+{
+ const char **result;
+ const char *list[] = { "foo", "bar", NULL };
+ const char *empty_list[] = { NULL };
+ const char **null_list = NULL;
+ char **l;
+
+ l = str_list_copy(tctx, list);
+ result = discard_const_p(const char *, l);
+ torture_assert_int_equal(tctx, str_list_length(result), 2, "list length");
+ torture_assert_str_equal(tctx, result[0], "foo", "element 0");
+ torture_assert_str_equal(tctx, result[1], "bar", "element 1");
+ torture_assert_str_equal(tctx, result[2], NULL, "element 2");
+
+ l = str_list_copy(tctx, empty_list);
+ result = discard_const_p(const char *, l);
+ torture_assert_int_equal(tctx, str_list_length(result), 0, "list length");
+ torture_assert_str_equal(tctx, result[0], NULL, "element 0");
+
+ l = str_list_copy(tctx, null_list);
+ result = discard_const_p(const char *, l);
+ torture_assert(tctx, result == NULL, "result NULL");
+
+ return true;
+}
+
+static bool test_list_make_empty(struct torture_context *tctx)
+{
+ char **result;
+
+ result = str_list_make_empty(tctx);
+ torture_assert(tctx, result, "str_list_make_empty() must not return NULL");
+ torture_assert(tctx, result[0] == NULL, "first element in str_list_make_empty() result must be NULL");
+
+ result = str_list_make(tctx, NULL, NULL);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ torture_assert(tctx, result[0] == NULL, "first element in str_list_make(ctx, NULL, NULL) result must be NULL");
+
+ result = str_list_make(tctx, "", NULL);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ torture_assert(tctx, result[0] == NULL, "first element in str_list_make(ctx, "", NULL) result must be NULL");
+
+ return true;
+}
+
+static bool test_list_make_single(struct torture_context *tctx)
+{
+ char **result;
+
+ result = str_list_make_single(tctx, "foo");
+
+ torture_assert(tctx, result, "str_list_make_single() must not return NULL");
+ torture_assert_str_equal(tctx, result[0], "foo", "element 0");
+ torture_assert(tctx, result[1] == NULL, "second element in result must be NULL");
+
+ return true;
+}
+
+static bool test_list_copy_const(struct torture_context *tctx)
+{
+ const char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ result = str_list_copy_const(tctx, list);
+ torture_assert(tctx, result, "str_list_copy() must not return NULL");
+ torture_assert(tctx, str_list_equal(result, list),
+ "str_list_copy() failed");
+
+ return true;
+}
+
+static bool test_list_length(struct torture_context *tctx)
+{
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ const char *list2[] = {
+ NULL
+ };
+ torture_assert_int_equal(tctx, str_list_length(list), 4,
+ "str_list_length() failed");
+
+ torture_assert_int_equal(tctx, str_list_length(list2), 0,
+ "str_list_length() failed");
+
+ torture_assert_int_equal(tctx, str_list_length(NULL), 0,
+ "str_list_length() failed");
+
+ return true;
+}
+
+static bool test_list_add(struct torture_context *tctx)
+{
+ const char **result, **result2;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ char **l;
+
+ l = str_list_make(tctx, "element_0, element_1, element_2", NULL);
+ result = discard_const_p(const char *, l);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ result2 = str_list_add(result, "element_3");
+ torture_assert(tctx, result2, "str_list_add() must not return NULL");
+ torture_assert(tctx, str_list_equal(result2, list),
+ "str_list_add() failed");
+
+ return true;
+}
+
+static bool test_list_add_const(struct torture_context *tctx)
+{
+ const char **result, **result2;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ char **l;
+
+ l = str_list_make(tctx, "element_0, element_1, element_2", NULL);
+ result = discard_const_p(const char *, l);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ result2 = str_list_add_const(result, "element_3");
+ torture_assert(tctx, result2, "str_list_add_const() must not return NULL");
+ torture_assert(tctx, str_list_equal(result2, list),
+ "str_list_add() failed");
+
+ return true;
+}
+
+static bool test_list_remove(struct torture_context *tctx)
+{
+ const char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_3",
+ NULL
+ };
+ char **l;
+
+ l = str_list_make(tctx, "element_0, element_1, element_2, element_3", NULL);
+ result = discard_const_p(const char *, l);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ str_list_remove(result, "element_2");
+ torture_assert(tctx, str_list_equal(result, list),
+ "str_list_remove() failed");
+
+ return true;
+}
+
+static bool test_list_check(struct torture_context *tctx)
+{
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ torture_assert(tctx, str_list_check(list, "element_1"),
+ "str_list_check() failed");
+
+ return true;
+}
+
+static bool test_list_check_ci(struct torture_context *tctx)
+{
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ torture_assert(tctx, str_list_check_ci(list, "ELEMENT_1"),
+ "str_list_check_ci() failed");
+
+ return true;
+}
+
+static bool test_list_unique(struct torture_context *tctx)
+{
+ const char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ const char *list_dup[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_0",
+ "element_2",
+ "element_1",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ char **l;
+
+ l = str_list_copy(tctx, list_dup);
+ result = discard_const_p(const char *, l);
+ /* We must copy the list, as str_list_unique does a talloc_realloc() on it's parameter */
+ result = str_list_unique(result);
+ torture_assert(tctx, result, "str_list_unique() must not return NULL");
+
+ torture_assert(tctx, str_list_equal(list, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
+static bool test_list_unique_2(struct torture_context *tctx)
+{
+ int i;
+ int count, num_dups;
+ const char **result;
+ char **l1 = str_list_make_empty(tctx);
+ char **l2 = str_list_make_empty(tctx);
+ const char **list = discard_const_p(const char *, l1);
+ const char **list_dup = discard_const_p(const char *, l2);
+ char **l;
+
+ count = lpcfg_parm_int(tctx->lp_ctx, NULL, "list_unique", "count", 9);
+ num_dups = lpcfg_parm_int(tctx->lp_ctx, NULL, "list_unique", "dups", 7);
+ torture_comment(tctx, "test_list_unique_2() with %d elements and %d dups\n", count, num_dups);
+
+ for (i = 0; i < count; i++) {
+ list = str_list_add_const(list, (const char *)talloc_asprintf(tctx, "element_%03d", i));
+ }
+
+ for (i = 0; i < num_dups; i++) {
+ list_dup = str_list_append(list_dup, list);
+ }
+
+ l = str_list_copy(tctx, list_dup);
+ result = discard_const_p(const char *, l);
+ /* We must copy the list, as str_list_unique does a talloc_realloc() on it's parameter */
+ result = str_list_unique(result);
+ torture_assert(tctx, result, "str_list_unique() must not return NULL");
+
+ torture_assert(tctx, str_list_equal(list, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
+static bool test_list_append(struct torture_context *tctx)
+{
+ const char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ const char *list2[] = {
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ const char *list_combined[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ char **l;
+ l = str_list_copy(tctx, list);
+ result = discard_const_p(const char *, l);
+ torture_assert(tctx, result, "str_list_copy() must not return NULL");
+ result = str_list_append(result, list2);
+ torture_assert(tctx, result, "str_list_append() must not return NULL");
+ torture_assert(tctx, str_list_equal(list_combined, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
+static bool test_list_append_const(struct torture_context *tctx)
+{
+ const char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ const char *list2[] = {
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ const char *list_combined[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ char **l;
+ l = str_list_copy(tctx, list);
+ result = discard_const_p(const char *, l);
+ torture_assert(tctx, result, "str_list_copy() must not return NULL");
+ result = str_list_append_const(result, list2);
+ torture_assert(tctx, result, "str_list_append_const() must not return NULL");
+ torture_assert(tctx, str_list_equal(list_combined, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
+static bool test_list_add_printf_NULL(struct torture_context *tctx)
+{
+ char **list = NULL;
+ str_list_add_printf(&list, "x=%d", 1);
+ torture_assert(tctx, list==NULL, "str_list_add_printf must keep NULL");
+ return true;
+}
+
+static bool test_list_add_printf(struct torture_context *tctx)
+{
+ const char *list2[] = { "foo", "bar=baz", NULL };
+ char **list = str_list_make_empty(tctx);
+ str_list_add_printf(&list, "foo");
+ str_list_add_printf(&list, "bar=%s", "baz");
+ torture_assert(
+ tctx,
+ str_list_equal((const char * const *)list, list2),
+ "str_list_add_printf failed");
+ TALLOC_FREE(list);
+ return true;
+}
+
+struct torture_suite *torture_local_util_strlist(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "strlist");
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(test_lists_shell_strings); i++) {
+ char *name;
+ name = talloc_asprintf(suite, "lists_shell(%s)",
+ test_lists_shell_strings[i].list_as_string);
+ torture_suite_add_simple_tcase_const(suite, name,
+ test_lists_shell, &test_lists_shell_strings[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(test_lists_strings); i++) {
+ char *name;
+ name = talloc_asprintf(suite, "list_make(%s)",
+ test_lists_strings[i].list_as_string);
+ torture_suite_add_simple_tcase_const(suite, name,
+ test_list_make, &test_lists_strings[i]);
+ }
+
+ torture_suite_add_simple_test(suite, "list_copy", test_list_copy);
+ torture_suite_add_simple_test(suite, "make_empty", test_list_make_empty);
+ torture_suite_add_simple_test(suite, "make_single", test_list_make_single);
+ torture_suite_add_simple_test(suite, "list_copy_const", test_list_copy_const);
+ torture_suite_add_simple_test(suite, "list_length", test_list_length);
+ torture_suite_add_simple_test(suite, "list_add", test_list_add);
+ torture_suite_add_simple_test(suite, "list_add_const", test_list_add_const);
+ torture_suite_add_simple_test(suite, "list_remove", test_list_remove);
+ torture_suite_add_simple_test(suite, "list_check", test_list_check);
+ torture_suite_add_simple_test(suite, "list_check_ci", test_list_check_ci);
+ torture_suite_add_simple_test(suite, "list_unique", test_list_unique);
+ torture_suite_add_simple_test(suite, "list_unique_2", test_list_unique_2);
+ torture_suite_add_simple_test(suite, "list_append", test_list_append);
+ torture_suite_add_simple_test(suite, "list_append_const", test_list_append_const);
+ torture_suite_add_simple_test(
+ suite, "list_add_printf_NULL", test_list_add_printf_NULL);
+ torture_suite_add_simple_test(
+ suite, "list_add_printf", test_list_add_printf);
+ return suite;
+}
diff --git a/lib/util/tests/strv.c b/lib/util/tests/strv.c
new file mode 100644
index 0000000..c79ed5c
--- /dev/null
+++ b/lib/util/tests/strv.c
@@ -0,0 +1,201 @@
+/*
+ * Tests for strv
+ *
+ * Copyright Martin Schwenke <martin@meltin.net> 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <talloc.h>
+
+#include "replace.h"
+
+#include "libcli/util/ntstatus.h"
+#include "torture/torture.h"
+#include "lib/util/data_blob.h"
+#include "torture/local/proto.h"
+
+#include "lib/util/strv.h"
+
+static bool test_strv_empty(struct torture_context *tctx)
+{
+ /* NULL strv contains 0 entries */
+ torture_assert_int_equal(tctx,
+ strv_count(NULL),
+ 0,
+ "strv_count() on NULL failed");
+
+ /* NULL strv has no next entry */
+ torture_assert(tctx,
+ strv_next(NULL, NULL) == NULL,
+ "strv_next() on NULL failed");
+
+ return true;
+}
+
+static bool test_strv_single(struct torture_context *tctx)
+{
+ const char *data = "foo";
+ char *strv = NULL;
+ char *t;
+ int ret;
+
+ /* Add an item */
+ ret = strv_add(tctx, &strv, data);
+ torture_assert(tctx, ret == 0, "strv_add() failed");
+
+ /* Is there 1 item? */
+ torture_assert_int_equal(tctx,
+ strv_count(strv), 1,
+ "strv_count() failed");
+
+ /* Is the expected item the first one? */
+ t = strv_next(strv, NULL);
+ torture_assert(tctx,
+ strcmp(t, data) == 0,
+ "strv_next() failed");
+
+ /* Can the expected item be found? */
+ t = strv_find(strv, data);
+ torture_assert(tctx,
+ strcmp(t, data) == 0,
+ "strv_next() failed");
+
+ /* Delete it */
+ strv_delete(&strv, t);
+
+ /* Should have no items */
+ torture_assert_int_equal(tctx,
+ strv_count(strv), 0,
+ "strv_count() failed");
+ return true;
+}
+
+static bool test_strv_multi(struct torture_context *tctx)
+{
+ const char *data[] = { "foo", "bar", "", "samba", "x"};
+ char *strv = NULL;
+ char *t;
+ int i, ret;
+ const int num = ARRAY_SIZE(data);
+
+ /* Add items */
+ for (i = 0; i < num; i++) {
+ ret = strv_add(tctx, &strv, data[i]);
+ torture_assert(tctx, ret == 0, "strv_add() failed");
+ }
+
+ torture_assert_int_equal(tctx,
+ strv_count(strv), num,
+ "strv_count() failed");
+
+ /* Check that strv_next() finds the expected values */
+ t = NULL;
+ for (i = 0; i < num; i++) {
+ t = strv_next(strv, t);
+ torture_assert(tctx,
+ strcmp(t, data[i]) == 0,
+ "strv_next() failed");
+ }
+
+
+ /* Check that strv_next() finds the expected values */
+ t = NULL;
+ for (i = 0; i < num; i++) {
+ t = strv_next(strv, t);
+ torture_assert(tctx,
+ strcmp(t, data[i]) == 0,
+ "strv_next() failed");
+ }
+
+ /* Find each item, delete it, check count */
+ for (i = 0; i < num; i++) {
+ t = strv_find(strv, data[i]);
+ torture_assert(tctx,
+ strcmp(t, data[i]) == 0,
+ "strv_next() failed");
+ strv_delete(&strv, t);
+ torture_assert_int_equal(tctx,
+ strv_count(strv), num - i - 1,
+ "strv_delete() failed");
+ }
+
+ /* Add items */
+ for (i = 0; i < num; i++) {
+ ret = strv_add(tctx, &strv, data[i]);
+ torture_assert(tctx, ret == 0, "strv_add() failed");
+ }
+
+ torture_assert_int_equal(tctx,
+ strv_count(strv), num,
+ "strv_count() failed");
+
+ /* Find items in reverse, delete, check count */
+ for (i = num - 1; i >= 0; i--) {
+ t = strv_find(strv, data[i]);
+ torture_assert(tctx,
+ strcmp(t, data[i]) == 0,
+ "strv_next() failed");
+ strv_delete(&strv, t);
+ torture_assert_int_equal(tctx,
+ strv_count(strv), i,
+ "strv_delete() failed");
+ }
+
+ return true;
+}
+
+/* Similar to above but only add/check first 2 chars of each string */
+static bool test_strv_addn(struct torture_context *tctx)
+{
+ const char *data[] = { "foo", "bar", "samba" };
+ char *strv = NULL;
+ char *t;
+ int i, ret;
+ const int num = ARRAY_SIZE(data);
+
+ /* Add first 2 chars of each item */
+ for (i = 0; i < num; i++) {
+ ret = strv_addn(tctx, &strv, data[i], 2);
+ torture_assert(tctx, ret == 0, "strv_add() failed");
+ }
+
+ torture_assert_int_equal(tctx,
+ strv_count(strv), num,
+ "strv_count() failed");
+
+ /* Check that strv_next() finds the expected values */
+ t = NULL;
+ for (i = 0; i < num; i++) {
+ t = strv_next(strv, t);
+ torture_assert(tctx,
+ strncmp(t, data[i], 2) == 0,
+ "strv_next() failed");
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_local_util_strv(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "strv");
+
+ torture_suite_add_simple_test(suite, "strv_empty", test_strv_empty);
+ torture_suite_add_simple_test(suite, "strv_single", test_strv_single);
+ torture_suite_add_simple_test(suite, "strv_multi", test_strv_multi);
+ torture_suite_add_simple_test(suite, "strv_addn", test_strv_addn);
+
+ return suite;
+}
diff --git a/lib/util/tests/strv_util.c b/lib/util/tests/strv_util.c
new file mode 100644
index 0000000..b1496c7
--- /dev/null
+++ b/lib/util/tests/strv_util.c
@@ -0,0 +1,150 @@
+/*
+ * Tests for strv_util
+ *
+ * Copyright Martin Schwenke <martin@meltin.net> 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <talloc.h>
+
+#include "replace.h"
+
+#include "libcli/util/ntstatus.h"
+#include "torture/torture.h"
+#include "lib/util/data_blob.h"
+#include "torture/local/proto.h"
+
+#include "lib/util/strv.h"
+#include "lib/util/strv_util.h"
+
+static bool test_strv_split_none(struct torture_context *tctx)
+{
+ char *strv = NULL;
+ int ret;
+
+ /* NULL has 0 entries */
+ ret = strv_split(tctx, &strv, NULL, " ");
+ torture_assert(tctx, ret == 0, "strv_split() on NULL failed");
+ torture_assert_int_equal(tctx,
+ strv_count(strv),
+ 0,
+ "strv_split() on NULL failed");
+ TALLOC_FREE(strv);
+
+ /* Empty string has 0 entries */
+ ret = strv_split(tctx, &strv, "", " ");
+ torture_assert(tctx, ret == 0, "strv_split() on NULL failed");
+ torture_assert_int_equal(tctx,
+ strv_count(strv),
+ 0,
+ "strv_split() on \"\" failed");
+ TALLOC_FREE(strv);
+
+ /* String containing only separators has 0 entries */
+ ret = strv_split(tctx, &strv, "abcabcabc", "cba ");
+ torture_assert(tctx, ret == 0, "strv_split() on NULL failed");
+ torture_assert_int_equal(tctx,
+ strv_count(strv),
+ 0,
+ "strv_split() on seps-only failed");
+ TALLOC_FREE(strv);
+
+ return true;
+}
+
+struct test_str_split_data {
+ const char *in;
+ const char *sep;
+ const char *out[10]; /* Hardcoded maximum! */
+};
+
+static bool test_strv_split_some(struct torture_context *tctx)
+{
+ const struct test_str_split_data data[] = {
+ {
+ /* Single string */
+ .in = "foo",
+ .sep = " \t",
+ .out = { "foo" }
+ },
+ {
+ /* Single string, single leading separator */
+ .in = " foo",
+ .sep = " \t",
+ .out = { "foo" }
+ },
+ {
+ /* Single string, single trailing separator */
+ .in = " foo",
+ .sep = " \t",
+ .out = { "foo" }
+ },
+ {
+ /* Single string, lots of separators */
+ .in = " \t foo\t ",
+ .sep = " \t",
+ .out = { "foo" }
+ },
+ {
+ /* Multiple strings, many separators */
+ .in = " \t foo bar\t\tx\t samba\t ",
+ .sep = " \t",
+ .out = { "foo", "bar", "x", "samba" }
+ },
+ };
+ const char *t;
+ char *strv = NULL;
+ size_t j;
+
+ for (j = 0; j < ARRAY_SIZE(data); j++) {
+ size_t i, num;
+ int ret;
+ const struct test_str_split_data *d = &data[j];
+
+ num = 0;
+ while (num < ARRAY_SIZE(d->out) && d->out[num] != NULL) {
+ num++;
+ }
+ ret = strv_split(tctx, &strv, d->in, d->sep);
+ torture_assert(tctx, ret == 0, "strv_split() on NULL failed");
+ torture_assert_int_equal(tctx,
+ strv_count(strv),
+ num,
+ "strv_split() failed");
+ t = NULL;
+ for (i = 0; i < num; i++) {
+ t = strv_next(strv, t);
+ torture_assert(tctx,
+ strcmp(t, d->out[i]) == 0,
+ "strv_split() failed");
+ }
+ TALLOC_FREE(strv);
+ }
+ return true;
+}
+
+struct torture_suite *torture_local_util_strv_util(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(mem_ctx, "strv_util");
+
+ torture_suite_add_simple_test(suite,
+ "strv_split_none",
+ test_strv_split_none);
+ torture_suite_add_simple_test(suite,
+ "strv_split_some",
+ test_strv_split_some);
+ return suite;
+}
diff --git a/lib/util/tests/test_bytearray.c b/lib/util/tests/test_bytearray.c
new file mode 100644
index 0000000..fcf63d8
--- /dev/null
+++ b/lib/util/tests/test_bytearray.c
@@ -0,0 +1,435 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018-2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/bytearray.h"
+
+static void torture_pull_le_u8(void **state)
+{
+ uint8_t data[2] = {0};
+ uint8_t result;
+
+ (void)state;
+
+ result = PULL_LE_U8(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ result = PULL_LE_U8(data, 0);
+ assert_int_equal(result, 42);
+
+
+ data[0] = 0xf;
+ result = PULL_LE_U8(data, 0);
+ assert_int_equal(result, 0xf);
+
+ data[0] = 0xff;
+ result = PULL_LE_U8(data, 0);
+ assert_int_equal(result, 0xff);
+
+ data[1] = 0x2a;
+ result = PULL_LE_U8(data, 1);
+ assert_int_equal(result, 42);
+}
+
+static void torture_pull_le_u16(void **state)
+{
+ uint8_t data[2] = {0, 0};
+ uint16_t result;
+
+ (void)state;
+
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ data[1] = 0x00;
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 0xffff);
+}
+
+static void torture_pull_le_u32(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint32_t result;
+
+ (void)state;
+
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0xff;
+ data[3] = 0x00;
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xff0000);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0xff;
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xff000000);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ data[2] = 0xff;
+ data[3] = 0xff;
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xffffffff);
+}
+
+static void torture_push_le_u8(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {42, 42, 42, 42};
+
+ (void)state;
+
+ PUSH_LE_U8(data, 0, 42);
+ PUSH_LE_U8(data, 1, 42);
+ PUSH_LE_U8(data, 2, 42);
+ PUSH_LE_U8(data, 3, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+}
+
+static void torture_push_le_u16(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {0xa6, 0x7f, 0x2a, 0x00};
+ uint16_t result;
+
+ (void)state;
+
+ PUSH_LE_U16(data, 0, 32678);
+ PUSH_LE_U16(data, 2, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = PULL_LE_U16(data, 2);
+ assert_int_equal(result, 42);
+
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 32678);
+}
+
+static void torture_push_le_u32(void **state)
+{
+ uint8_t data[8] = {0};
+ uint8_t data2[8] = {0xa6, 0x7f, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00};
+ uint32_t result;
+
+ (void)state;
+
+ PUSH_LE_U32(data, 0, 32678);
+ PUSH_LE_U32(data, 4, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = PULL_LE_U32(data, 4);
+ assert_int_equal(result, 42);
+
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 32678);
+
+ PUSH_LE_U32(data, 0, 0xfffefffe);
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xfffefffe);
+}
+
+static void torture_push_le_u64(void **state)
+{
+ uint8_t data[16] = {0};
+ uint64_t result;
+
+ (void)state;
+
+ PUSH_LE_U64(data, 0, 32678);
+
+ result = PULL_LE_U64(data, 0);
+ assert_int_equal(result, 32678);
+
+ PUSH_LE_U64(data, 0, 0xfffefffefffefffeUL);
+
+ result = PULL_LE_U64(data, 0);
+ assert_int_equal(result, 0xfffefffefffefffeUL);
+}
+
+/****************** BIG ENDIAN ********************/
+
+static void torture_pull_be_u8(void **state)
+{
+ uint8_t data[2] = {0};
+ uint8_t result;
+
+ (void)state;
+
+ result = PULL_BE_U8(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ result = PULL_BE_U8(data, 0);
+ assert_int_equal(result, 42);
+
+
+ data[0] = 0xf;
+ result = PULL_BE_U8(data, 0);
+ assert_int_equal(result, 0xf);
+
+ data[0] = 0xff;
+ result = PULL_BE_U8(data, 0);
+ assert_int_equal(result, 0xff);
+
+ data[1] = 0x2a;
+ result = PULL_BE_U8(data, 1);
+ assert_int_equal(result, 42);
+}
+
+static void torture_pull_be_u16(void **state)
+{
+ uint8_t data[2] = {0, 0};
+ uint16_t result;
+
+ (void)state;
+
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x00;
+ data[1] = 0x2a;
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 0xffff);
+}
+
+static void torture_pull_be_u32(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint32_t result;
+
+ (void)state;
+
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x2a;
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0xff;
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0xff;
+ data[3] = 0x00;
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0xff0000);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0xff000000);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ data[2] = 0xff;
+ data[3] = 0xff;
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0xffffffff);
+}
+
+static void torture_push_be_u8(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {42, 42, 42, 42};
+
+ (void)state;
+
+ PUSH_BE_U8(data, 0, 42);
+ PUSH_BE_U8(data, 1, 42);
+ PUSH_BE_U8(data, 2, 42);
+ PUSH_BE_U8(data, 3, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+}
+
+static void torture_push_be_u16(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {0x7f, 0xa6, 0x00, 0x2a};
+ uint16_t result;
+
+ (void)state;
+
+ PUSH_BE_U16(data, 0, 32678);
+ PUSH_BE_U16(data, 2, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = PULL_BE_U16(data, 2);
+ assert_int_equal(result, 42);
+
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 32678);
+}
+
+static void torture_push_be_u32(void **state)
+{
+ uint8_t data[8] = {0};
+ uint8_t data2[8] = {0x00, 0x00, 0x7f, 0xa6, 0x00, 0x00, 0x00, 0x2a};
+ uint32_t result;
+
+ (void)state;
+
+ PUSH_BE_U32(data, 0, 32678);
+ PUSH_BE_U32(data, 4, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = PULL_BE_U32(data, 4);
+ assert_int_equal(result, 42);
+
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 32678);
+
+ PUSH_BE_U32(data, 0, 0xfffefffe);
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0xfffefffe);
+}
+
+static void torture_push_be_u64(void **state)
+{
+ uint8_t data[16] = {0};
+ uint64_t result;
+
+ (void)state;
+
+ PUSH_BE_U64(data, 0, 32678);
+
+ result = PULL_BE_U64(data, 0);
+ assert_int_equal(result, 32678);
+
+ PUSH_LE_U64(data, 8, 0xfffefffe);
+
+ result = PULL_LE_U64(data, 8);
+ assert_int_equal(result, 0xfffefffe);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_pull_le_u8),
+ cmocka_unit_test(torture_pull_le_u16),
+ cmocka_unit_test(torture_pull_le_u32),
+
+ cmocka_unit_test(torture_push_le_u8),
+ cmocka_unit_test(torture_push_le_u16),
+ cmocka_unit_test(torture_push_le_u32),
+ cmocka_unit_test(torture_push_le_u64),
+
+ /* BIG ENDIAN */
+ cmocka_unit_test(torture_pull_be_u8),
+ cmocka_unit_test(torture_pull_be_u16),
+ cmocka_unit_test(torture_pull_be_u32),
+
+ cmocka_unit_test(torture_push_be_u8),
+ cmocka_unit_test(torture_push_be_u16),
+ cmocka_unit_test(torture_push_be_u32),
+ cmocka_unit_test(torture_push_be_u64),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/lib/util/tests/test_byteorder.c b/lib/util/tests/test_byteorder.c
new file mode 100644
index 0000000..9faa038
--- /dev/null
+++ b/lib/util/tests/test_byteorder.c
@@ -0,0 +1,435 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018-2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/byteorder.h"
+
+static void torture_pull_le_u8(void **state)
+{
+ uint8_t data[2] = {0};
+ uint8_t result;
+
+ (void)state;
+
+ result = CVAL(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ result = CVAL(data, 0);
+ assert_int_equal(result, 42);
+
+
+ data[0] = 0xf;
+ result = CVAL(data, 0);
+ assert_int_equal(result, 0xf);
+
+ data[0] = 0xff;
+ result = CVAL(data, 0);
+ assert_int_equal(result, 0xff);
+
+ data[1] = 0x2a;
+ result = CVAL(data, 1);
+ assert_int_equal(result, 42);
+}
+
+static void torture_pull_le_u16(void **state)
+{
+ uint8_t data[2] = {0, 0};
+ uint16_t result;
+
+ (void)state;
+
+ result = SVAL(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ data[1] = 0x00;
+ result = SVAL(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ result = SVAL(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ result = SVAL(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ result = SVAL(data, 0);
+ assert_int_equal(result, 0xffff);
+}
+
+static void torture_pull_le_u32(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint32_t result;
+
+ (void)state;
+
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = IVAL(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0xff;
+ data[3] = 0x00;
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0xff0000);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0xff;
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0xff000000);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ data[2] = 0xff;
+ data[3] = 0xff;
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0xffffffff);
+}
+
+static void torture_push_le_u8(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {42, 42, 42, 42};
+
+ (void)state;
+
+ SCVAL(data, 0, 42);
+ SCVAL(data, 1, 42);
+ SCVAL(data, 2, 42);
+ SCVAL(data, 3, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+}
+
+static void torture_push_le_u16(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {0xa6, 0x7f, 0x2a, 0x00};
+ uint16_t result;
+
+ (void)state;
+
+ SSVALX(data, 0, 32678);
+ SSVALX(data, 2, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = SVAL(data, 2);
+ assert_int_equal(result, 42);
+
+ result = SVAL(data, 0);
+ assert_int_equal(result, 32678);
+}
+
+static void torture_push_le_u32(void **state)
+{
+ uint8_t data[8] = {0};
+ uint8_t data2[8] = {0xa6, 0x7f, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00};
+ uint32_t result;
+
+ (void)state;
+
+ SIVALX(data, 0, 32678);
+ SIVALX(data, 4, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = IVAL(data, 4);
+ assert_int_equal(result, 42);
+
+ result = IVAL(data, 0);
+ assert_int_equal(result, 32678);
+
+ SIVALX(data, 0, 0xfffefffe);
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0xfffefffe);
+}
+
+static void torture_push_le_u64(void **state)
+{
+ uint8_t data[16] = {0};
+ uint64_t result;
+
+ (void)state;
+
+ SBVAL(data, 0, 32678);
+
+ result = BVAL(data, 0);
+ assert_int_equal(result, 32678);
+
+ SBVAL(data, 0, 0xfffefffefffefffeUL);
+
+ result = BVAL(data, 0);
+ assert_int_equal(result, 0xfffefffefffefffeUL);
+}
+
+/****************** BIG ENDIAN ********************/
+
+static void torture_pull_be_u8(void **state)
+{
+ uint8_t data[2] = {0};
+ uint8_t result;
+
+ (void)state;
+
+ result = CVAL(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x2a;
+ result = CVAL(data, 0);
+ assert_int_equal(result, 42);
+
+
+ data[0] = 0xf;
+ result = CVAL(data, 0);
+ assert_int_equal(result, 0xf);
+
+ data[0] = 0xff;
+ result = CVAL(data, 0);
+ assert_int_equal(result, 0xff);
+
+ data[1] = 0x2a;
+ result = CVAL(data, 1);
+ assert_int_equal(result, 42);
+}
+
+static void torture_pull_be_u16(void **state)
+{
+ uint8_t data[2] = {0, 0};
+ uint16_t result;
+
+ (void)state;
+
+ result = RSVAL(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x00;
+ data[1] = 0x2a;
+ result = RSVAL(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ result = RSVAL(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ result = RSVAL(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ result = RSVAL(data, 0);
+ assert_int_equal(result, 0xffff);
+}
+
+static void torture_pull_be_u32(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint32_t result;
+
+ (void)state;
+
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x2a;
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 42);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0xff;
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0xff;
+ data[3] = 0x00;
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ data[0] = 0x00;
+ data[1] = 0xff;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0xff0000);
+
+ data[0] = 0xff;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0xff000000);
+
+ data[0] = 0xff;
+ data[1] = 0xff;
+ data[2] = 0xff;
+ data[3] = 0xff;
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0xffffffff);
+}
+
+static void torture_push_be_u8(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {42, 42, 42, 42};
+
+ (void)state;
+
+ SCVAL(data, 0, 42);
+ SCVAL(data, 1, 42);
+ SCVAL(data, 2, 42);
+ SCVAL(data, 3, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+}
+
+static void torture_push_be_u16(void **state)
+{
+ uint8_t data[4] = {0, 0, 0, 0};
+ uint8_t data2[4] = {0x7f, 0xa6, 0x00, 0x2a};
+ uint16_t result;
+
+ (void)state;
+
+ RSSVALS(data, 0, 32678);
+ RSSVALS(data, 2, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = RSVAL(data, 2);
+ assert_int_equal(result, 42);
+
+ result = RSVAL(data, 0);
+ assert_int_equal(result, 32678);
+}
+
+static void torture_push_be_u32(void **state)
+{
+ uint8_t data[8] = {0};
+ uint8_t data2[8] = {0x00, 0x00, 0x7f, 0xa6, 0x00, 0x00, 0x00, 0x2a};
+ uint32_t result;
+
+ (void)state;
+
+ RSIVALS(data, 0, 32678);
+ RSIVALS(data, 4, 42);
+ assert_memory_equal(data, data2, sizeof(data));
+
+ result = RIVAL(data, 4);
+ assert_int_equal(result, 42);
+
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 32678);
+
+ RSIVALS(data, 0, 0xfffefffe);
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0xfffefffe);
+}
+
+static void torture_push_be_u64(void **state)
+{
+ uint8_t data[16] = {0};
+ uint64_t result;
+
+ (void)state;
+
+ RSBVALS(data, 0, 32678);
+
+ result = RBVAL(data, 0);
+ assert_int_equal(result, 32678);
+
+ SBVAL(data, 8, 0xfffefffe);
+
+ result = BVAL(data, 8);
+ assert_int_equal(result, 0xfffefffe);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_pull_le_u8),
+ cmocka_unit_test(torture_pull_le_u16),
+ cmocka_unit_test(torture_pull_le_u32),
+
+ cmocka_unit_test(torture_push_le_u8),
+ cmocka_unit_test(torture_push_le_u16),
+ cmocka_unit_test(torture_push_le_u32),
+ cmocka_unit_test(torture_push_le_u64),
+
+ /* BIG ENDIAN */
+ cmocka_unit_test(torture_pull_be_u8),
+ cmocka_unit_test(torture_pull_be_u16),
+ cmocka_unit_test(torture_pull_be_u32),
+
+ cmocka_unit_test(torture_push_be_u8),
+ cmocka_unit_test(torture_push_be_u16),
+ cmocka_unit_test(torture_push_be_u32),
+ cmocka_unit_test(torture_push_be_u64),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/lib/util/tests/test_byteorder_verify.c b/lib/util/tests/test_byteorder_verify.c
new file mode 100644
index 0000000..a18ddad
--- /dev/null
+++ b/lib/util/tests/test_byteorder_verify.c
@@ -0,0 +1,273 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018-2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/bytearray.h"
+#include "lib/util/byteorder.h"
+
+static void torture_le_u8(void **state)
+{
+ uint8_t data[2] = {0};
+ uint8_t result;
+
+ (void)state;
+
+ /* Test CVAL and SCVAL */
+ PUSH_LE_U8(data, 0, 23);
+ PUSH_LE_U8(data, 1, 42);
+
+ result = CVAL(data, 0);
+ assert_int_equal(result, 23);
+
+ result = CVAL(data, 1);
+ assert_int_equal(result, 42);
+
+ /* Test CVAL_NC and PVAL */
+ PUSH_LE_U8(data, 0, 23);
+ PUSH_LE_U8(data, 1, 42);
+
+ result = CVAL_NC(data, 0);
+ assert_int_equal(result, 23);
+
+ result = PVAL(data, 1);
+ assert_int_equal(result, 42);
+
+ /* Test SCVAL */
+ SCVAL(data, 0, 42);
+ SCVAL(data, 1, 23);
+
+ result = PULL_LE_U8(data, 0);
+ assert_int_equal(result, 42);
+
+ result = PULL_LE_U8(data, 1);
+ assert_int_equal(result, 23);
+}
+
+static void torture_le_u16(void **state)
+{
+ uint8_t data[2] = {0};
+ uint16_t result;
+
+ (void)state;
+
+ /* Test SVAL */
+ PUSH_LE_U16(data, 0, 0xff00);
+ result = SVAL(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ /* Test SSVAL */
+ SSVAL(data, 0, 0x00ff);
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ /* Test SSVALX */
+ SSVALX(data, 0, 0x00fa);
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 0x00fa);
+
+ /* Test SSVALS */
+ SSVALS(data, 0, 0x00fb);
+ result = PULL_LE_U16(data, 0);
+ assert_int_equal(result, 0x00fb);
+}
+
+static void torture_le_u32(void **state)
+{
+ uint8_t data[4] = {0};
+ uint32_t result;
+
+ (void)state;
+
+ /* Test IVAL */
+ PUSH_LE_U32(data, 0, 0xff000000);
+ result = IVAL(data, 0);
+ assert_int_equal(result, 0xff000000);
+
+ /* Test SIVAL */
+ SIVAL(data, 0, 0xffaabbcc);
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xffaabbcc);
+
+ /* Test SIVALX */
+ SIVALX(data, 0, 0xffbbccdd);
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xffbbccdd);
+
+ /* Test SIVALS */
+ SIVALS(data, 0, 0xffccddee);
+ result = PULL_LE_U32(data, 0);
+ assert_int_equal(result, 0xffccddee);
+}
+
+static void torture_le_u64(void **state)
+{
+ uint8_t data[8] = {0};
+ uint64_t result;
+
+ (void)state;
+
+ PUSH_LE_U64(data, 0, 0xfffefffefffefffeUL);
+ result = BVAL(data, 0);
+ assert_int_equal(result, 0xfffefffefffefffeUL);
+
+ SBVAL(data, 0, 0xfffafffafffafffaUL);
+ result = PULL_LE_U64(data, 0);
+ assert_int_equal(result, 0xfffafffafffafffaUL);
+}
+
+static void torture_be_u8(void **state)
+{
+ uint8_t data[2] = {0};
+ uint8_t result;
+
+ (void)state;
+
+ PUSH_BE_U8(data, 0, 23);
+ PUSH_BE_U8(data, 1, 42);
+
+ result = CVAL(data, 0);
+ assert_int_equal(result, 23);
+
+ result = CVAL(data, 1);
+ assert_int_equal(result, 42);
+
+ SCVAL(data, 0, 42);
+ SCVAL(data, 1, 23);
+
+ result = PULL_BE_U8(data, 0);
+ assert_int_equal(result, 42);
+
+ result = PULL_BE_U8(data, 1);
+ assert_int_equal(result, 23);
+}
+
+static void torture_be_u16(void **state)
+{
+ uint8_t data[2] = {0};
+ uint16_t result;
+
+ (void)state;
+
+ /* Test RSVAL */
+ PUSH_BE_U16(data, 0, 0xff00);
+ result = RSVAL(data, 0);
+ assert_int_equal(result, 0xff00);
+
+ /* Test RSVALS */
+ PUSH_BE_U16(data, 0, 0xffaa);
+ result = RSVALS(data, 0);
+ assert_int_equal(result, 0xffaa);
+
+ /* Test RSSVAL */
+ RSSVAL(data, 0, 0x00ff);
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 0x00ff);
+
+ /* Test RSSVALS */
+ RSSVALS(data, 0, 0x00fa);
+ result = PULL_BE_U16(data, 0);
+ assert_int_equal(result, 0x00fa);
+}
+
+static void torture_be_u32(void **state)
+{
+ uint8_t data[4] = {0};
+ uint32_t result;
+
+ (void)state;
+
+ /* Test RIVAL */
+ PUSH_BE_U32(data, 0, 0xff000000);
+ result = RIVAL(data, 0);
+ assert_int_equal(result, 0xff000000);
+
+ /* Test RIVALS */
+ PUSH_BE_U32(data, 0, 0xff0000aa);
+ result = RIVALS(data, 0);
+ assert_int_equal(result, 0xff0000aa);
+
+ /* Test RSIVAL */
+ RSIVAL(data, 0, 0xffeeddcc);
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0xffeeddcc);
+
+ /* Test RSIVALS */
+ RSIVALS(data, 0, 0xffaaddcc);
+ result = PULL_BE_U32(data, 0);
+ assert_int_equal(result, 0xffaaddcc);
+}
+
+static void torture_be_u64(void **state)
+{
+ uint8_t data[8] = {0};
+ uint64_t result;
+
+ (void)state;
+
+ /* Test RBVAL */
+ PUSH_BE_U64(data, 0, 0xfffefffefffefffeUL);
+ result = RBVAL(data, 0);
+ assert_int_equal(result, 0xfffefffefffefffeUL);
+
+ /* Test RBVALS */
+ PUSH_BE_U64(data, 0, 0xfffafffafffafffaUL);
+ result = RBVALS(data, 0);
+ assert_int_equal(result, 0xfffafffafffafffaUL);
+
+ /* Test RSBVAL */
+ RSBVAL(data, 0, 0xfffbfffbfffbfffbUL);
+ result = PULL_BE_U64(data, 0);
+ assert_int_equal(result, 0xfffbfffbfffbfffbUL);
+
+ /* Test RSBVALS */
+ RSBVALS(data, 0, 0xfffcfffcfffcfffcUL);
+ result = PULL_BE_U64(data, 0);
+ assert_int_equal(result, 0xfffcfffcfffcfffcUL);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_le_u8),
+ cmocka_unit_test(torture_le_u16),
+ cmocka_unit_test(torture_le_u32),
+ cmocka_unit_test(torture_le_u64),
+
+ cmocka_unit_test(torture_be_u8),
+ cmocka_unit_test(torture_be_u16),
+ cmocka_unit_test(torture_be_u32),
+ cmocka_unit_test(torture_be_u64),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/lib/util/tests/test_logging.c b/lib/util/tests/test_logging.c
new file mode 100644
index 0000000..9b13b05
--- /dev/null
+++ b/lib/util/tests/test_logging.c
@@ -0,0 +1,146 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ A test server that only does logging.
+
+ Copyright (C) Andrew Tridgell 1992-2005
+ Copyright (C) Martin Pool 2002
+ Copyright (C) Jelmer Vernooij 2002
+ Copyright (C) James J Myers 2003 <myersjj@samba.org>
+ Copyright (C) Douglas Bagnall 2022
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+
+#ifdef USING_CMDLINE_S3
+#include "lib/util/debug_s3.h"
+#endif
+
+#define BINARY_NAME "test_s4_logging"
+
+static int log_level = 1;
+
+
+#include "lib/util/debug-classes/debug-classname-table.c"
+
+static int log_all_classes(int level)
+{
+ size_t i;
+ const char *name = NULL;
+ for (i = 0; i < ARRAY_SIZE(default_classname_table); i++) {
+ name = default_classname_table[i];
+ DEBUGC(i, level,
+ ("logging for '%s' [%zu], at level %d\n",
+ name, i, level));
+
+ /*
+ * That's it for the tests *here*. The invoker of this
+ * process will have set up an smb.conf that directs the
+ * output in particular ways, and will be looking to see that
+ * happens correctly.
+ */
+ }
+ return 0;
+}
+
+
+static int init_daemon(TALLOC_CTX *mem_ctx,
+ int argc,
+ const char *argv[],
+ const char **error)
+{
+ poptContext pc;
+ int opt;
+ bool ok;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {
+ .longName = "level",
+ .shortName = 'L',
+ .argInfo = POPT_ARG_INT,
+ .arg = &log_level,
+ .descrip = "log at this level",
+ .argDescrip = "LEVEL",
+ },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_DAEMON
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+
+ setproctitle(BINARY_NAME);
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_SERVER,
+ true /* require_smbconf */);
+ if (!ok) {
+ *error = "Failed to init cmdline parser!\n";
+ return EINVAL;
+ }
+
+ pc = samba_popt_get_context(BINARY_NAME,
+ argc,
+ argv,
+ long_options,
+ 0);
+ if (pc == NULL) {
+ *error = "Failed to setup popt context!\n";
+ return ENOTRECOVERABLE;
+ }
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+
+ poptFreeContext(pc);
+
+#ifdef USING_CMDLINE_S3
+ reopen_logs();
+#endif
+ return 0;
+}
+
+
+int main(int argc, const char *argv[])
+{
+ int rc;
+ const char *error = NULL;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+ if (mem_ctx == NULL) {
+ exit(ENOMEM);
+ }
+
+ setproctitle_init(argc, discard_const(argv), environ);
+
+ rc = init_daemon(mem_ctx, argc, argv, &error);
+ if (rc != 0) {
+ fprintf(stderr, "error [%d]: %s\n", rc, error);
+ exit_daemon(error, rc);
+ }
+
+ rc = log_all_classes(log_level);
+ if (rc != 0) {
+ fprintf(stderr, "error in log_all_classes [%d]\n", rc);
+ exit_daemon("logging error", rc);
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return rc;
+}
diff --git a/lib/util/tests/test_memcache.c b/lib/util/tests/test_memcache.c
new file mode 100644
index 0000000..8a39978
--- /dev/null
+++ b/lib/util/tests/test_memcache.c
@@ -0,0 +1,161 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2021 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/memcache.h"
+
+static int setup_talloc_context(void **state)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ *state = frame;
+ return 0;
+}
+
+static int teardown_talloc_context(void **state)
+{
+ TALLOC_CTX *frame = *state;
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+static void torture_memcache_init(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ struct memcache *cache = NULL;
+
+ cache = memcache_init(mem_ctx, 0);
+ assert_non_null(cache);
+
+ TALLOC_FREE(cache);
+
+ cache = memcache_init(mem_ctx, 10);
+ assert_non_null(cache);
+
+ TALLOC_FREE(cache);
+}
+
+static void torture_memcache_add_lookup_delete(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ struct memcache *cache = NULL;
+ DATA_BLOB key1, key2;
+ char *path1 = NULL, *path2 = NULL;
+
+ cache = memcache_init(mem_ctx, 0);
+ assert_non_null(cache);
+
+ key1 = data_blob_const("key1", 4);
+ path1 = talloc_strdup(mem_ctx, "/tmp/one");
+ assert_non_null(path1);
+
+ key2 = data_blob_const("key2", 4);
+ path2 = talloc_strdup(mem_ctx, "/tmp/two");
+ assert_non_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key1, &path1);
+ assert_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key2, &path2);
+ assert_null(path2);
+
+ path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+ assert_non_null(path1);
+ assert_string_equal(path1, "/tmp/one");
+
+ path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+ assert_non_null(path2);
+ assert_string_equal(path2, "/tmp/two");
+
+ memcache_delete(cache, GETWD_CACHE, key1);
+ path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+ assert_null(path1);
+
+ memcache_flush(cache, GETWD_CACHE);
+ path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+ assert_null(path2);
+
+ TALLOC_FREE(path1);
+ TALLOC_FREE(path2);
+ TALLOC_FREE(cache);
+}
+
+static void torture_memcache_add_oversize(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ struct memcache *cache = NULL;
+ DATA_BLOB key1, key2;
+ char *path1 = NULL, *path2 = NULL;
+
+ cache = memcache_init(mem_ctx, 10);
+ assert_non_null(cache);
+
+ key1 = data_blob_const("key1", 4);
+ path1 = talloc_strdup(mem_ctx, "/tmp/one");
+ assert_non_null(path1);
+
+ key2 = data_blob_const("key2", 4);
+ path2 = talloc_strdup(mem_ctx, "/tmp/two");
+ assert_non_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key1, &path1);
+ assert_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key2, &path2);
+ assert_null(path2);
+
+ path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+ assert_null(path1);
+
+ path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+ assert_non_null(path2);
+ assert_string_equal(path2, "/tmp/two");
+
+ TALLOC_FREE(path1);
+ TALLOC_FREE(path2);
+ TALLOC_FREE(cache);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_memcache_init),
+ cmocka_unit_test(torture_memcache_add_lookup_delete),
+ cmocka_unit_test(torture_memcache_add_oversize),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests,
+ setup_talloc_context,
+ teardown_talloc_context);
+
+ return rc;
+}
diff --git a/lib/util/tests/test_ms_fnmatch.c b/lib/util/tests/test_ms_fnmatch.c
new file mode 100644
index 0000000..d11c7be
--- /dev/null
+++ b/lib/util/tests/test_ms_fnmatch.c
@@ -0,0 +1,114 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018 David Disseldorp <ddiss@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/samba_util.h"
+#include "libcli/smb/smb_constants.h"
+
+static void test_ms_fn_match_protocol_no_wildcard(void **state)
+{
+ int cmp;
+
+ /* no wildcards in pattern, a simple strcasecmp_m */
+ cmp = ms_fnmatch_protocol("pattern", "string", PROTOCOL_COREPLUS,
+ true); /* case sensitive */
+ assert_int_equal(cmp, -3);
+}
+
+static void test_ms_fn_match_protocol_pattern_upgraded(void **state)
+{
+ int cmp;
+
+ /* protocol < PROTOCOL_NT1 pattern is "upgraded" */
+ cmp = ms_fnmatch_protocol("??????", "string", PROTOCOL_COREPLUS,
+ false);
+ assert_int_equal(cmp, 0);
+}
+
+static void test_ms_fn_match_protocol_match_zero_or_more(void **state)
+{
+ int cmp;
+
+ /* '*' matches zero or more characters. handled via recursive calls */
+ cmp = ms_fnmatch_protocol("********", "string", PROTOCOL_COREPLUS,
+ true);
+ assert_int_equal(cmp, 0);
+}
+
+static void test_ms_fn_match_protocol_mapped_char(void **state)
+{
+ int cmp;
+
+ /* '?' is mapped to '>', which matches any char or a '\0' */
+ cmp = ms_fnmatch_protocol("???????", "string", PROTOCOL_COREPLUS,
+ false);
+ assert_int_equal(cmp, 0);
+}
+
+static void test_ms_fn_match_protocol_nt1_any_char(void **state)
+{
+ int cmp;
+
+ /* PROTOCOL_NT1 '?' matches any char, '\0' is not included */
+ cmp = ms_fnmatch_protocol("???????", "string", PROTOCOL_NT1,
+ false);
+ assert_int_equal(cmp, -1);
+}
+
+static void test_ms_fn_match_protocol_nt1_case_sensitive(void **state)
+{
+ int cmp;
+
+ cmp = ms_fnmatch_protocol("StRinG", "string", PROTOCOL_NT1,
+ true); /* case sensitive */
+ assert_int_equal(cmp, 0);
+
+ cmp = ms_fnmatch_protocol("StRin?", "string", PROTOCOL_NT1,
+ true); /* case sensitive */
+ assert_int_equal(cmp, -1);
+
+ cmp = ms_fnmatch_protocol("StRin?", "string", PROTOCOL_NT1,
+ false);
+ assert_int_equal(cmp, 0);
+ cmp = ms_fnmatch_protocol("strin?", "string", PROTOCOL_NT1,
+ true); /* case sensitive */
+ assert_int_equal(cmp, 0);
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_ms_fn_match_protocol_no_wildcard),
+ cmocka_unit_test(test_ms_fn_match_protocol_pattern_upgraded),
+ cmocka_unit_test(test_ms_fn_match_protocol_match_zero_or_more),
+ cmocka_unit_test(test_ms_fn_match_protocol_mapped_char),
+ cmocka_unit_test(test_ms_fn_match_protocol_nt1_any_char),
+ cmocka_unit_test(test_ms_fn_match_protocol_nt1_case_sensitive),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/util/tests/test_stable_sort.c b/lib/util/tests/test_stable_sort.c
new file mode 100644
index 0000000..ae4b1f3
--- /dev/null
+++ b/lib/util/tests/test_stable_sort.c
@@ -0,0 +1,317 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018 Andreas Schneider <asn@samba.org>
+ * Copyright (C) 2022 Douglas Bagnall <dbagnall@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdbool.h>
+#include "replace.h"
+#include <talloc.h>
+
+#include "../stable_sort.h"
+
+
+static int cmp_integer(int *a, int *b)
+{
+ if (a == NULL || b == NULL) {
+ return 0;
+ }
+
+ if (*a > *b) {
+ return 1;
+ }
+
+ if (*a < *b) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void test_stable_sort(void **state)
+{
+ int a[6] = { 6, 3, 2, 7, 9, 4 };
+ int tmp[6];
+ bool ok;
+ ok = stable_sort(a, tmp,
+ 6, sizeof(int), (samba_compare_fn_t)cmp_integer);
+
+ assert_true(ok);
+ assert_int_equal(a[0], 2);
+ assert_int_equal(a[1], 3);
+ assert_int_equal(a[2], 4);
+ assert_int_equal(a[3], 6);
+ assert_int_equal(a[4], 7);
+ assert_int_equal(a[5], 9);
+}
+
+static void test_stable_sort_talloc_short(void **state)
+{
+ int a[6] = { 6, 3, 2, 7, 9, 4 };
+ int ret;
+ ret = stable_sort_talloc(NULL, a, 6, sizeof(int),
+ (samba_compare_fn_t)cmp_integer);
+ assert_true(ret);
+
+ assert_int_equal(a[0], 2);
+ assert_int_equal(a[1], 3);
+ assert_int_equal(a[2], 4);
+ assert_int_equal(a[3], 6);
+ assert_int_equal(a[4], 7);
+ assert_int_equal(a[5], 9);
+}
+
+static void test_stable_sort_talloc_long(void **state)
+{
+ int i, ret;
+ size_t n = 1500;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ int *a = talloc_array(mem_ctx, int, n);
+ for (i = 0; i < n; i++) {
+ a[i] = n - i;
+ }
+
+ ret = stable_sort_talloc(mem_ctx, a, n, sizeof(int),
+ (samba_compare_fn_t)cmp_integer);
+ assert_true(ret);
+
+ for (i = 0; i < n; i++) {
+ assert_int_equal(a[i], 1 + i);
+ }
+}
+
+
+/*
+ * Sort an array of structs with:
+ * - unwieldy uneven size
+ * - sort key not at the start
+ * - comparison depends on context
+ *
+ * which are things we sometimes do.
+ */
+
+struct contrived_struct {
+ char padding_1[13];
+ int key[3];
+ char padding_2[18];
+ size_t *index;
+};
+
+
+static int cmp_contrived_struct(struct contrived_struct *as,
+ struct contrived_struct *bs)
+{
+ int i = *as->index;
+ int a = as->key[i];
+ int b = bs->key[i];
+ return a - b;
+}
+
+static int cmp_contrived_struct_rev(struct contrived_struct *as,
+ struct contrived_struct *bs)
+{
+ /* will sort in reverseo order */
+ int i = *as->index;
+ int a = as->key[i];
+ int b = bs->key[i];
+ return b - a;
+}
+
+
+static void test_stable_sort_talloc_contrived_struct(void **state)
+{
+ int i, ret, prev;
+ size_t n = 800000;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ size_t key_index = 0;
+
+ struct contrived_struct *a = talloc_zero_array(mem_ctx,
+ struct contrived_struct,
+ n);
+
+ /* we don't really want a good RNG, we want mess and repeated values. */
+ uint32_t x = 89, y = (uint32_t)-6, z = 11;
+ for (i = 0; i < n; i++) {
+ a[i].index = &key_index;
+ a[i].key[0] = (x & 0xffff) - 0x8000;
+ a[i].key[1] = z & 255;
+ /* key[2] is original order, useful for checking stability */
+ a[i].key[2] = i;
+ x += z ^ y;
+ y *= z + (x + 0x5555);
+ z -= x ^ i;
+ }
+
+ /* 1. sort by key[0] */
+ ret = stable_sort_talloc(mem_ctx, a, n,
+ sizeof(struct contrived_struct),
+ (samba_compare_fn_t)cmp_contrived_struct);
+ assert_true(ret);
+ prev = a[0].key[0];
+ for (i = 1; i < n; i++) {
+ int value = a[i].key[0];
+ assert_true(value >= prev);
+ if (value == prev) {
+ /* we can test the stability by comparing key[2] */
+ assert_true(a[i].key[2] >= a[i - 1].key[2]);
+ }
+ prev = value;
+ }
+
+ /* 2. sort by key[1]. key[0] now indicates stability. */
+ key_index = 1;
+ ret = stable_sort_talloc(mem_ctx, a, n,
+ sizeof(struct contrived_struct),
+ (samba_compare_fn_t)cmp_contrived_struct);
+ assert_true(ret);
+ prev = a[0].key[1];
+ for (i = 1; i < n; i++) {
+ int value = a[i].key[1];
+ assert_true(value >= prev);
+ if (value == prev) {
+ assert_true(a[i].key[0] >= a[i - 1].key[0]);
+ }
+ prev = value;
+ }
+
+ /*
+ * 3. sort by key[2]. key[1] would now indicate stability, but we know
+ * that key[2] has no duplicates, so stability is moot.
+ */
+ key_index = 2;
+ ret = stable_sort_talloc(mem_ctx, a, n,
+ sizeof(struct contrived_struct),
+ (samba_compare_fn_t)cmp_contrived_struct);
+ assert_true(ret);
+ prev = a[0].key[2];
+ for (i = 1; i < n; i++) {
+ int value = a[i].key[2];
+ assert_true(value > prev);
+ prev = value;
+ }
+
+ /*
+ * 4. sort by key[0] again, using descending sort order. key[2] should
+ * still be in ascending order where there are duplicate key[0] values.
+ */
+ key_index = 0;
+ ret = stable_sort_talloc(mem_ctx, a, n,
+ sizeof(struct contrived_struct),
+ (samba_compare_fn_t)cmp_contrived_struct_rev);
+ assert_true(ret);
+ prev = a[0].key[0];
+ for (i = 1; i < n; i++) {
+ int value = a[i].key[0];
+ assert_true(value <= prev);
+ if (value == prev) {
+ assert_true(a[i].key[2] >= a[i - 1].key[2]);
+ }
+ prev = value;
+ }
+}
+
+
+
+static int cmp_integer_xor_blob(int *_a, int *_b, int *opaque)
+{
+ int a = *_a ^ *opaque;
+ int b = *_b ^ *opaque;
+
+ if (a > b) {
+ return 1;
+ }
+
+ if (a < b) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void test_stable_sort_talloc_r(void **state)
+{
+ int i;
+ size_t n = 1500;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ int opaque = 42;
+ bool ok;
+ int *a = talloc_array(mem_ctx, int, n);
+ for (i = 0; i < n; i++) {
+ a[i] = (i * 7) & 255;
+ }
+
+ ok = stable_sort_talloc_r(mem_ctx, a, n, sizeof(int),
+ (samba_compare_with_context_fn_t)cmp_integer_xor_blob,
+ &opaque);
+ assert_true(ok);
+
+ for (i = 1; i < n; i++) {
+ assert_true((a[i - 1] ^ opaque) <= (a[i] ^ opaque));
+ }
+}
+
+
+static void test_stable_sort_silly_size(void **state)
+{
+ bool ok;
+ int a[33] = {0};
+ int b[33] = {0};
+
+ ok = stable_sort(a,
+ b,
+ (SIZE_MAX / 2) + 2,
+ (SIZE_MAX / 2) + 2,
+ (samba_compare_fn_t)cmp_integer);
+ assert_false(ok);
+}
+
+static void test_stable_sort_null_array(void **state)
+{
+ bool ok;
+ int a[33] = {0};
+
+ ok = stable_sort(a,
+ NULL,
+ 33,
+ sizeof(int),
+ (samba_compare_fn_t)cmp_integer);
+ assert_false(ok);
+}
+
+
+
+
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_stable_sort),
+ cmocka_unit_test(test_stable_sort_talloc_short),
+ cmocka_unit_test(test_stable_sort_talloc_long),
+ cmocka_unit_test(test_stable_sort_talloc_contrived_struct),
+ cmocka_unit_test(test_stable_sort_talloc_r),
+ cmocka_unit_test(test_stable_sort_silly_size),
+ cmocka_unit_test(test_stable_sort_null_array),
+ };
+ if (!isatty(1)) {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/util/tests/test_sys_rw.c b/lib/util/tests/test_sys_rw.c
new file mode 100644
index 0000000..22688fb
--- /dev/null
+++ b/lib/util/tests/test_sys_rw.c
@@ -0,0 +1,178 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Unit test for sys_rw.c
+ *
+ * Copyright (C) Ralph Böhme 2021
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "system/dir.h"
+
+#include "lib/util/sys_rw.c"
+
+static void test_sys_io_ranges_overlap(void **state)
+{
+ bool overlap;
+
+ /*
+ * sys_io_ranges_overlap() args are:
+ *
+ * src size, src offset, dst size, dst offset
+ */
+
+ /* src and dst size 0 => no overlap */
+ overlap = sys_io_ranges_overlap(0, 0, 0, 0);
+ assert_false(overlap);
+
+ /* dst size 0 => no overlap */
+ overlap = sys_io_ranges_overlap(1, 0, 0, 0);
+ assert_false(overlap);
+
+ /* src size 0 => no overlap */
+ overlap = sys_io_ranges_overlap(0, 0, 1, 0);
+ assert_false(overlap);
+
+ /* same range => overlap */
+ overlap = sys_io_ranges_overlap(1, 0, 1, 0);
+ assert_true(overlap);
+
+ /*
+ * |.|
+ * |.|
+ * src before dst => no overlap
+ */
+ overlap = sys_io_ranges_overlap(1, 0, 1, 1);
+ assert_false(overlap);
+
+ /*
+ * |..|
+ * |..|
+ * src into dst => overlap
+ */
+ overlap = sys_io_ranges_overlap(2, 0, 2, 1);
+ assert_true(overlap);
+
+ /*
+ * |....|
+ * |..|
+ * src encompasses dst => overlap
+ */
+ overlap = sys_io_ranges_overlap(4, 0, 1, 2);
+ assert_true(overlap);
+
+
+ /*
+ * |..|
+ * |..|
+ * dst into src => overlap
+ */
+ overlap = sys_io_ranges_overlap(2, 1, 2, 0);
+ assert_true(overlap);
+
+ /*
+ * |..|
+ * |....|
+ * dst encompasses src => overlap
+ */
+ overlap = sys_io_ranges_overlap(2, 1, 4, 0);
+ assert_true(overlap);
+}
+
+static void test_sys_block_align(void **state)
+{
+ int asize;
+
+ asize = sys_block_align(0, 2);
+ assert_int_equal(asize, 0);
+ asize = sys_block_align(1, 2);
+ assert_int_equal(asize, 2);
+ asize = sys_block_align(2, 2);
+ assert_int_equal(asize, 2);
+ asize = sys_block_align(3, 2);
+ assert_int_equal(asize, 4);
+
+ asize = sys_block_align(0, 4);
+ assert_int_equal(asize, 0);
+ asize = sys_block_align(1, 4);
+ assert_int_equal(asize, 4);
+ asize = sys_block_align(3, 4);
+ assert_int_equal(asize, 4);
+ asize = sys_block_align(4, 4);
+ assert_int_equal(asize, 4);
+ asize = sys_block_align(5, 4);
+ assert_int_equal(asize, 8);
+ asize = sys_block_align(7, 4);
+ assert_int_equal(asize, 8);
+ asize = sys_block_align(8, 4);
+ assert_int_equal(asize, 8);
+ asize = sys_block_align(9, 4);
+ assert_int_equal(asize, 12);
+}
+
+static void test_sys_block_align_truncate(void **state)
+{
+ int asize;
+
+ asize = sys_block_align_truncate(0, 2);
+ assert_int_equal(asize, 0);
+ asize = sys_block_align_truncate(1, 2);
+ assert_int_equal(asize, 0);
+ asize = sys_block_align_truncate(2, 2);
+ assert_int_equal(asize, 2);
+ asize = sys_block_align_truncate(3, 2);
+ assert_int_equal(asize, 2);
+ asize = sys_block_align_truncate(4, 2);
+ assert_int_equal(asize, 4);
+ asize = sys_block_align_truncate(5, 2);
+ assert_int_equal(asize, 4);
+
+ asize = sys_block_align_truncate(0, 4);
+ assert_int_equal(asize, 0);
+ asize = sys_block_align_truncate(1, 4);
+ assert_int_equal(asize, 0);
+ asize = sys_block_align_truncate(3, 4);
+ assert_int_equal(asize, 0);
+ asize = sys_block_align_truncate(4, 4);
+ assert_int_equal(asize, 4);
+ asize = sys_block_align_truncate(5, 4);
+ assert_int_equal(asize, 4);
+ asize = sys_block_align_truncate(7, 4);
+ assert_int_equal(asize, 4);
+ asize = sys_block_align_truncate(8, 4);
+ assert_int_equal(asize, 8);
+ asize = sys_block_align_truncate(9, 4);
+ assert_int_equal(asize, 8);
+}
+
+int main(int argc, char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_sys_io_ranges_overlap),
+ cmocka_unit_test(test_sys_block_align),
+ cmocka_unit_test(test_sys_block_align_truncate),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/util/tests/test_talloc_keep_secret.c b/lib/util/tests/test_talloc_keep_secret.c
new file mode 100644
index 0000000..1462dab
--- /dev/null
+++ b/lib/util/tests/test_talloc_keep_secret.c
@@ -0,0 +1,94 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <string.h>
+#include <talloc.h>
+#include "lib/util/talloc_keep_secret.h"
+
+int rep_memset_s(void *dest, size_t destsz, int ch, size_t count);
+
+int rep_memset_s(void *dest, size_t destsz, int ch, size_t count)
+{
+ check_expected_ptr(dest);
+ check_expected(destsz);
+ check_expected(ch);
+ check_expected(count);
+
+ return 0;
+}
+
+static void test_talloc_keep_secret(void ** state)
+{
+ TALLOC_CTX *pool = NULL;
+ char *ptr1 = NULL;
+ char *ptr2 = NULL;
+ const char *ptr1_talloc_name = NULL;
+ size_t ptr1_size;
+ size_t i;
+
+ pool = talloc_pool(NULL, 256);
+ assert_non_null(pool);
+
+ ptr1 = talloc_strdup(pool, "secret");
+ assert_non_null(ptr1);
+ assert_string_equal(ptr1, "secret");
+
+ talloc_keep_secret(ptr1);
+
+ ptr1_talloc_name = talloc_get_name(ptr1);
+ assert_string_equal(ptr1_talloc_name, "ptr1");
+
+ ptr1_size = talloc_get_size(ptr1);
+ assert_int_equal(ptr1_size, strlen(ptr1) + 1);
+
+ expect_string(rep_memset_s, dest, "secret");
+ expect_value(rep_memset_s, destsz, strlen(ptr1) + 1);
+ expect_value(rep_memset_s, ch, (int)'\0');
+ expect_value(rep_memset_s, count, strlen(ptr1) + 1);
+
+ talloc_free(ptr1);
+
+ ptr2 = talloc_size(pool, ptr1_size);
+ assert_ptr_equal(ptr1, ptr2);
+
+ for (i = 1; i < ptr1_size; i++) {
+ assert_int_not_equal(ptr2[0], ptr2[i]);
+ }
+
+ talloc_free(pool);
+}
+
+static void test_talloc_keep_secret_validate_memset(void **state)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ char *password = NULL;
+
+ mem_ctx = talloc_new(NULL);
+ assert_non_null(mem_ctx);
+
+ password = talloc_strdup(mem_ctx, "secret");
+ assert_non_null(password);
+ talloc_keep_secret(password);
+
+ expect_string(rep_memset_s, dest, "secret");
+ expect_value(rep_memset_s, destsz, strlen(password) + 1);
+ expect_value(rep_memset_s, ch, (int)'\0');
+ expect_value(rep_memset_s, count, strlen(password) + 1);
+
+ talloc_free(mem_ctx);
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_talloc_keep_secret),
+ cmocka_unit_test(test_talloc_keep_secret_validate_memset),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/util/tests/test_util.c b/lib/util/tests/test_util.c
new file mode 100644
index 0000000..62f10ed
--- /dev/null
+++ b/lib/util/tests/test_util.c
@@ -0,0 +1,344 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Unit test for util.c
+ *
+ * Copyright (C) Christof Schmitt 2020
+ * Copyright (C) Andreas Schneider 2020
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "system/dir.h"
+
+#include "lib/util/util.c"
+
+struct test_paths {
+ char testdir[PATH_MAX];
+ char none[PATH_MAX];
+ char dir[PATH_MAX];
+ char dir_recursive[PATH_MAX];
+ mode_t dir_mode;
+ char file[PATH_MAX];
+ mode_t file_mode;
+ char symlink_none[PATH_MAX];
+ char symlink_dir[PATH_MAX];
+ char symlink_file[PATH_MAX];
+};
+
+static int group_setup(void **state)
+{
+ struct test_paths *paths = NULL;
+ char *testdir = NULL;
+ int ret, fd;
+
+ umask(0);
+
+ paths = malloc(sizeof(struct test_paths));
+ assert_non_null(paths);
+
+ strlcpy(paths->testdir, tmpdir(), sizeof(paths->testdir));
+ strlcat(paths->testdir, "/test_util_XXXXXX", sizeof(paths->testdir));
+ testdir = mkdtemp(paths->testdir);
+ assert_non_null(testdir);
+
+ strlcpy(paths->none, testdir, sizeof(paths->none));
+ strlcat(paths->none, "/none", sizeof(paths->none));
+
+ strlcpy(paths->dir, testdir, sizeof(paths->dir));
+ strlcat(paths->dir, "/dir", sizeof(paths->dir));
+ paths->dir_mode = 0750;
+ ret = mkdir(paths->dir, paths->dir_mode);
+ assert_return_code(ret, errno);
+
+ strlcpy(paths->dir_recursive, testdir, sizeof(paths->dir));
+ strlcat(paths->dir_recursive, "/dir_recursive", sizeof(paths->dir));
+ paths->dir_mode = 0750;
+ ret = mkdir(paths->dir_recursive, paths->dir_mode);
+ assert_return_code(ret, errno);
+
+ strlcpy(paths->file, testdir, sizeof(paths->file));
+ strlcat(paths->file, "/file", sizeof(paths->file));
+ paths->file_mode = 0640;
+ fd = creat(paths->file, paths->file_mode);
+ assert_return_code(fd, errno);
+ ret = close(fd);
+ assert_return_code(ret, errno);
+
+ strlcpy(paths->symlink_none, testdir, sizeof(paths->symlink_none));
+ strlcat(paths->symlink_none, "/symlink_none",
+ sizeof(paths->symlink_none));
+ ret = symlink("/none", paths->symlink_none);
+ assert_return_code(ret, errno);
+
+ strlcpy(paths->symlink_dir, testdir, sizeof(paths->symlink_dir));
+ strlcat(paths->symlink_dir, "/symlink_dir", sizeof(paths->symlink_dir));
+ ret = symlink(paths->dir, paths->symlink_dir);
+ assert_return_code(ret, errno);
+
+ strlcpy(paths->symlink_file, testdir, sizeof(paths->symlink_file));
+ strlcat(paths->symlink_file, "/symlink_file",
+ sizeof(paths->symlink_file));
+ ret = symlink(paths->file, paths->symlink_file);
+ assert_return_code(ret, errno);
+
+ *state = paths;
+
+ return 0;
+}
+
+static int torture_rmdirs(const char *path)
+{
+ DIR *d;
+ struct dirent *dp;
+ struct stat sb;
+ char *fname;
+
+ if ((d = opendir(path)) != NULL) {
+ while(stat(path, &sb) == 0) {
+ /* if we can remove the directory we're done */
+ if (rmdir(path) == 0) {
+ break;
+ }
+ switch (errno) {
+ case ENOTEMPTY:
+ case EEXIST:
+ case EBADF:
+ break; /* continue */
+ default:
+ closedir(d);
+ return 0;
+ }
+
+ while ((dp = readdir(d)) != NULL) {
+ size_t len;
+ /* skip '.' and '..' */
+ if (dp->d_name[0] == '.' &&
+ (dp->d_name[1] == '\0' ||
+ (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
+ continue;
+ }
+
+ len = strlen(path) + strlen(dp->d_name) + 2;
+ fname = malloc(len);
+ if (fname == NULL) {
+ closedir(d);
+ return -1;
+ }
+ snprintf(fname, len, "%s/%s", path, dp->d_name);
+
+ /* stat the file */
+ if (lstat(fname, &sb) != -1) {
+ if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
+ if (rmdir(fname) < 0) { /* can't be deleted */
+ if (errno == EACCES) {
+ closedir(d);
+ SAFE_FREE(fname);
+ return -1;
+ }
+ torture_rmdirs(fname);
+ }
+ } else {
+ unlink(fname);
+ }
+ } /* lstat */
+ SAFE_FREE(fname);
+ } /* readdir */
+
+ rewinddir(d);
+ }
+ } else {
+ return -1;
+ }
+
+ closedir(d);
+ return 0;
+}
+
+static int group_teardown(void **state)
+{
+ struct test_paths *paths = *state;
+ int ret;
+
+ ret = unlink(paths->file);
+ assert_return_code(ret, errno);
+
+ ret = unlink(paths->symlink_none);
+ assert_return_code(ret, errno);
+
+ ret = unlink(paths->symlink_dir);
+ assert_return_code(ret, errno);
+
+ ret = unlink(paths->symlink_file);
+ assert_return_code(ret, errno);
+
+ ret = torture_rmdirs(paths->testdir);
+ assert_return_code(ret, errno);
+
+ free(paths);
+ return 0;
+}
+
+static void test_directory_create_or_exists_none(void **state)
+{
+ struct test_paths *paths = *state;
+ bool b;
+ struct stat sbuf;
+ int ret;
+
+ b = directory_create_or_exist(paths->none, 0775);
+ assert_true(b);
+
+ ret = lstat(paths->none, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, 0775);
+ assert_true(S_ISDIR(sbuf.st_mode));
+}
+
+static int teardown_none_directory(void **state)
+{
+ struct test_paths *paths = *state;
+
+ rmdir(paths->none);
+ return 0;
+}
+
+static void test_directory_create_or_exists_dir(void **state)
+{
+ struct test_paths *paths = *state;
+ bool b;
+ struct stat sbuf;
+ int ret;
+
+ b = directory_create_or_exist(paths->dir, 770);
+ assert_true(b);
+
+ ret = lstat(paths->dir, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, paths->dir_mode);
+ assert_true(S_ISDIR(sbuf.st_mode));
+}
+
+static void test_directory_create_or_exists_file(void **state)
+{
+ struct test_paths *paths = *state;
+ bool b;
+ struct stat sbuf;
+ int ret;
+
+ b = directory_create_or_exist(paths->file, 770);
+ assert_false(b);
+
+ ret = lstat(paths->file, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, paths->file_mode);
+ assert_true(S_ISREG(sbuf.st_mode));
+}
+
+static void test_directory_create_or_exists_symlink_none(void **state)
+{
+ struct test_paths *paths = *state;
+ bool b;
+ struct stat sbuf;
+ int ret;
+
+ b = directory_create_or_exist(paths->symlink_none, 770);
+ assert_false(b);
+
+ ret = lstat(paths->symlink_none, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, 0777);
+ assert_true(S_ISLNK(sbuf.st_mode));
+}
+
+static void test_directory_create_or_exists_symlink_dir(void **state)
+{
+ struct test_paths *paths = *state;
+ bool b;
+ struct stat sbuf;
+ int ret;
+
+ b = directory_create_or_exist(paths->symlink_dir, 770);
+ assert_true(b);
+
+ ret = lstat(paths->symlink_dir, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, 0777);
+ assert_true(S_ISLNK(sbuf.st_mode));
+}
+
+static void test_directory_create_or_exists_symlink_file(void **state)
+{
+ struct test_paths *paths = *state;
+ bool b;
+ struct stat sbuf;
+ int ret;
+
+ b = directory_create_or_exist(paths->symlink_file, 770);
+ assert_false(b);
+
+ ret = lstat(paths->symlink_file, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, 0777);
+ assert_true(S_ISLNK(sbuf.st_mode));
+}
+
+static void test_directory_create_or_exists_recursive(void **state)
+{
+ struct test_paths *paths = *state;
+ char recursive_testdir[PATH_MAX] = {0};
+ struct stat sbuf = {0};
+ bool ok;
+ int ret;
+
+ ret = snprintf(recursive_testdir,
+ sizeof(recursive_testdir),
+ "%s/wurst/brot",
+ paths->dir_recursive);
+ assert_int_not_equal(ret, -1);
+
+ ok = directory_create_or_exists_recursive(recursive_testdir,
+ 0700);
+ assert_true(ok);
+
+ ret = lstat(recursive_testdir, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, 0700);
+ assert_true(S_ISDIR(sbuf.st_mode));
+}
+
+int main(int argc, char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_teardown(test_directory_create_or_exists_none,
+ teardown_none_directory),
+ cmocka_unit_test(test_directory_create_or_exists_dir),
+ cmocka_unit_test(test_directory_create_or_exists_file),
+ cmocka_unit_test(test_directory_create_or_exists_symlink_none),
+ cmocka_unit_test(test_directory_create_or_exists_symlink_dir),
+ cmocka_unit_test(test_directory_create_or_exists_symlink_file),
+ cmocka_unit_test(test_directory_create_or_exists_recursive),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, group_setup, group_teardown);
+}
diff --git a/lib/util/tests/test_util_paths.c b/lib/util/tests/test_util_paths.c
new file mode 100644
index 0000000..4dfe11c
--- /dev/null
+++ b/lib/util/tests/test_util_paths.c
@@ -0,0 +1,127 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2020 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include <talloc.h>
+
+#include "lib/util/util_paths.c"
+
+static int setup(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ assert_non_null(mem_ctx);
+ *state = mem_ctx;
+
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ TALLOC_FREE(mem_ctx);
+
+ return 0;
+}
+
+static void test_get_user_home_dir(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ struct passwd *pwd = getpwuid(getuid());
+ char *user;
+
+ user = get_user_home_dir(mem_ctx);
+ assert_non_null(user);
+ assert_string_equal(user, pwd->pw_dir);
+
+ TALLOC_FREE(user);
+}
+
+static void test_path_expand_tilde(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ char h[256] = {0};
+ char *d = NULL;
+ const char *user = NULL;
+ char *home = NULL;
+
+ user = getenv("USER");
+ if (user == NULL){
+ user = getenv("LOGNAME");
+ }
+
+ /* In certain CIs there no such variables */
+ if (user == NULL) {
+ struct passwd *pw = getpwuid(getuid());
+ if (pw){
+ user = pw->pw_name;
+ }
+ }
+
+ home = getenv("HOME");
+ assert_non_null(home);
+ snprintf(h, sizeof(h), "%s/.cache", home);
+
+ d = path_expand_tilde(mem_ctx, "~/.cache");
+ assert_non_null(d);
+ assert_string_equal(d, h);
+ TALLOC_FREE(d);
+
+ snprintf(h, sizeof(h), "%s/.cache/X~", home);
+ d = path_expand_tilde(mem_ctx, "~/.cache/X~");
+ assert_string_equal(d, h);
+ TALLOC_FREE(d);
+
+ d = path_expand_tilde(mem_ctx, "/guru/meditation");
+ assert_non_null(d);
+ assert_string_equal(d, "/guru/meditation");
+ TALLOC_FREE(d);
+
+ snprintf(h, sizeof(h), "~%s/.cache", user);
+ d = path_expand_tilde(mem_ctx, h);
+ assert_non_null(d);
+
+ snprintf(h, sizeof(h), "%s/.cache", home);
+ assert_string_equal(d, h);
+ TALLOC_FREE(d);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_get_user_home_dir),
+ cmocka_unit_test(test_path_expand_tilde),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, setup, teardown);
+
+ return rc;
+}
diff --git a/lib/util/tests/tfork-drd.supp b/lib/util/tests/tfork-drd.supp
new file mode 100644
index 0000000..7d0544b
--- /dev/null
+++ b/lib/util/tests/tfork-drd.supp
@@ -0,0 +1,14 @@
+{
+ tfork_pthread_cond_init
+ drd:CondErr
+ fun:pthread_cond_init_intercept
+ fun:pthread_cond_init@*
+ fun:tfork_atfork_child
+ fun:fork
+ fun:tfork_start_waiter_and_worker
+ fun:tfork_create
+ fun:tfork_thread
+ fun:vgDrd_thread_wrapper
+ fun:start_thread
+ fun:clone
+}
diff --git a/lib/util/tests/tfork-helgrind.supp b/lib/util/tests/tfork-helgrind.supp
new file mode 100644
index 0000000..4b62b2a
--- /dev/null
+++ b/lib/util/tests/tfork-helgrind.supp
@@ -0,0 +1,32 @@
+{
+ tfork_atexit_unknown1
+ Helgrind:Misc
+ fun:mutex_destroy_WRK
+ fun:pthread_mutex_destroy
+ obj:/usr/lib64/libp11-kit.so.0.3.0
+ fun:_dl_fini
+ fun:__run_exit_handlers
+ fun:exit
+ fun:(below main)
+}
+
+{
+ tfork_atexit_unknown2
+ Helgrind:Misc
+ fun:mutex_destroy_WRK
+ fun:pthread_mutex_destroy
+ fun:_dl_fini
+ fun:__run_exit_handlers
+ fun:exit
+ fun:(below main)
+}
+{
+ tfork_pthread_get_specific
+ Helgrind:Race
+ fun:tfork_global_get
+ fun:tfork_create
+ fun:tfork_thread
+ fun:mythread_wrapper
+ fun:start_thread
+ fun:clone
+}
diff --git a/lib/util/tests/tfork.c b/lib/util/tests/tfork.c
new file mode 100644
index 0000000..70ae975
--- /dev/null
+++ b/lib/util/tests/tfork.c
@@ -0,0 +1,855 @@
+/*
+ * Tests for tfork
+ *
+ * Copyright Ralph Boehme <slow@samba.org> 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include <tevent.h>
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "system/select.h"
+#include "libcli/util/ntstatus.h"
+#include "torture/torture.h"
+#include "lib/util/data_blob.h"
+#include "torture/local/proto.h"
+#include "lib/util/tfork.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/sys_rw.h"
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+static bool test_tfork_simple(struct torture_context *tctx)
+{
+ pid_t parent = getpid();
+ struct tfork *t = NULL;
+ pid_t child;
+ int ret;
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ torture_comment(tctx, "my parent pid is %d\n", parent);
+ torture_assert(tctx, getpid() != parent, "tfork failed\n");
+ _exit(0);
+ }
+
+ ret = tfork_destroy(&t);
+ torture_assert(tctx, ret == 0, "tfork_destroy failed\n");
+
+ return true;
+}
+
+static bool test_tfork_status(struct torture_context *tctx)
+{
+ struct tfork *t = NULL;
+ int status;
+ pid_t child;
+ bool ok = true;
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ _exit(123);
+ }
+
+ status = tfork_status(&t, true);
+ if (status == -1) {
+ torture_fail(tctx, "tfork_status failed\n");
+ }
+
+ torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
+ "tfork failed\n");
+ torture_assert_goto(tctx, WEXITSTATUS(status) == 123, ok, done,
+ "tfork failed\n");
+
+ torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
+
+done:
+ return ok;
+}
+
+static bool test_tfork_sigign(struct torture_context *tctx)
+{
+ struct tfork *t = NULL;
+ struct sigaction act;
+ pid_t child;
+ int status;
+ bool ok = true;
+ int ret;
+
+ act = (struct sigaction) {
+ .sa_flags = SA_NOCLDWAIT,
+ .sa_handler = SIG_IGN,
+ };
+
+ ret = sigaction(SIGCHLD, &act, NULL);
+ torture_assert_goto(tctx, ret == 0, ok, done, "sigaction failed\n");
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ sleep(1);
+ _exit(123);
+ }
+
+ child = fork();
+ if (child == -1) {
+ torture_fail(tctx, "fork failed\n");
+ return false;
+ }
+ if (child == 0) {
+ _exit(0);
+ }
+
+ status = tfork_status(&t, true);
+ if (status == -1) {
+ torture_fail(tctx, "tfork_status failed\n");
+ }
+
+ torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
+ "tfork failed\n");
+ torture_assert_goto(tctx, WEXITSTATUS(status) == 123, ok, done,
+ "tfork failed\n");
+ torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
+
+done:
+ return ok;
+}
+
+static void sigchld_handler1(int signum, siginfo_t *si, void *u)
+{
+ pid_t pid;
+ int status;
+
+ if (signum != SIGCHLD) {
+ abort();
+ }
+
+ pid = waitpid(si->si_pid, &status, 0);
+ if (pid != si->si_pid) {
+ abort();
+ }
+}
+
+static bool test_tfork_sighandler(struct torture_context *tctx)
+{
+ struct tfork *t = NULL;
+ struct sigaction act;
+ struct sigaction oldact;
+ pid_t child;
+ int status;
+ bool ok = true;
+ int ret;
+
+ act = (struct sigaction) {
+ .sa_flags = SA_SIGINFO,
+ .sa_sigaction = sigchld_handler1,
+ };
+
+ ret = sigaction(SIGCHLD, &act, &oldact);
+ torture_assert_goto(tctx, ret == 0, ok, done, "sigaction failed\n");
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ sleep(1);
+ _exit(123);
+ }
+
+ child = fork();
+ if (child == -1) {
+ torture_fail(tctx, "fork failed\n");
+ return false;
+ }
+ if (child == 0) {
+ _exit(0);
+ }
+
+ status = tfork_status(&t, true);
+ if (status == -1) {
+ torture_fail(tctx, "tfork_status failed\n");
+ }
+
+ torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
+ "tfork failed\n");
+ torture_assert_goto(tctx, WEXITSTATUS(status) == 123, ok, done,
+ "tfork failed\n");
+ torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
+
+done:
+ sigaction(SIGCHLD, &oldact, NULL);
+
+ return ok;
+}
+
+static bool test_tfork_process_hierarchy(struct torture_context *tctx)
+{
+ struct tfork *t = NULL;
+ pid_t pid = getpid();
+ pid_t child;
+ pid_t pgid = getpgid(0);
+ pid_t sid = getsid(0);
+ char *procpath = NULL;
+ int status;
+ struct stat st;
+ int ret;
+ bool ok = true;
+
+ procpath = talloc_asprintf(tctx, "/proc/%d/status", getpid());
+ torture_assert_not_null(tctx, procpath, "talloc_asprintf failed\n");
+
+ ret = stat(procpath, &st);
+ TALLOC_FREE(procpath);
+ if (ret != 0) {
+ if (errno == ENOENT) {
+ torture_skip(tctx, "/proc missing\n");
+ }
+ torture_fail(tctx, "stat failed\n");
+ }
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ char *cmd = NULL;
+ FILE *fp = NULL;
+ char line[64];
+ char *p;
+ pid_t ppid;
+
+ torture_assert_goto(tctx, pgid == getpgid(0), ok, child_fail, "tfork failed\n");
+ torture_assert_goto(tctx, sid == getsid(0), ok, child_fail, "tfork failed\n");
+
+ cmd = talloc_asprintf(tctx, "cat /proc/%d/status | awk '/^PPid:/ {print $2}'", getppid());
+ torture_assert_goto(tctx, cmd != NULL, ok, child_fail, "talloc_asprintf failed\n");
+
+ fp = popen(cmd, "r");
+ torture_assert_goto(tctx, fp != NULL, ok, child_fail, "popen failed\n");
+
+ p = fgets(line, sizeof(line) - 1, fp);
+ pclose(fp);
+ torture_assert_goto(tctx, p != NULL, ok, child_fail, "popen failed\n");
+
+ ret = sscanf(line, "%d", &ppid);
+ torture_assert_goto(tctx, ret == 1, ok, child_fail, "sscanf failed\n");
+ torture_assert_goto(tctx, ppid == pid, ok, child_fail, "process hierarchy not rooted at caller\n");
+
+ _exit(0);
+
+ child_fail:
+ _exit(1);
+ }
+
+ status = tfork_status(&t, true);
+ if (status == -1) {
+ torture_fail(tctx, "tfork_status failed\n");
+ }
+
+ torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
+ "tfork failed\n");
+ torture_assert_goto(tctx, WEXITSTATUS(status) == 0, ok, done,
+ "tfork failed\n");
+ torture_comment(tctx, "exit status [%d]\n", WEXITSTATUS(status));
+
+done:
+ return ok;
+}
+
+static bool test_tfork_pipe(struct torture_context *tctx)
+{
+ struct tfork *t = NULL;
+ int status;
+ pid_t child;
+ int up[2];
+ int down[2];
+ char c;
+ int ret;
+ bool ok = true;
+
+ ret = pipe(&up[0]);
+ torture_assert(tctx, ret == 0, "pipe failed\n");
+
+ ret = pipe(&down[0]);
+ torture_assert(tctx, ret == 0, "pipe failed\n");
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ close(up[0]);
+ close(down[1]);
+
+ ret = read(down[0], &c, 1);
+ torture_assert_goto(tctx, ret == 1, ok, child_fail, "read failed\n");
+ torture_assert_goto(tctx, c == 1, ok, child_fail, "read failed\n");
+
+ ret = write(up[1], &(char){2}, 1);
+ torture_assert_goto(tctx, ret == 1, ok, child_fail, "write failed\n");
+
+ _exit(0);
+
+ child_fail:
+ _exit(1);
+ }
+
+ close(up[1]);
+ close(down[0]);
+
+ ret = write(down[1], &(char){1}, 1);
+ torture_assert(tctx, ret == 1, "read failed\n");
+
+ ret = read(up[0], &c, 1);
+ torture_assert(tctx, ret == 1, "read failed\n");
+ torture_assert(tctx, c == 2, "read failed\n");
+
+ status = tfork_status(&t, true);
+ if (status == -1) {
+ torture_fail(tctx, "tfork_status failed\n");
+ }
+
+ torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
+ "tfork failed\n");
+ torture_assert_goto(tctx, WEXITSTATUS(status) == 0, ok, done,
+ "tfork failed\n");
+done:
+ return ok;
+}
+
+static bool test_tfork_twice(struct torture_context *tctx)
+{
+ struct tfork *t = NULL;
+ int status;
+ pid_t child;
+ pid_t pid;
+ int up[2];
+ int ret;
+ bool ok = true;
+
+ ret = pipe(&up[0]);
+ torture_assert(tctx, ret == 0, "pipe failed\n");
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ close(up[0]);
+
+ t = tfork_create();
+ if (t == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ sleep(1);
+ pid = getpid();
+ ret = write(up[1], &pid, sizeof(pid_t));
+ torture_assert_goto(tctx, ret == sizeof(pid_t), ok, child_fail, "write failed\n");
+
+ _exit(0);
+
+ child_fail:
+ _exit(1);
+ }
+
+ _exit(0);
+ }
+
+ close(up[1]);
+
+ ret = read(up[0], &pid, sizeof(pid_t));
+ torture_assert(tctx, ret == sizeof(pid_t), "read failed\n");
+
+ status = tfork_status(&t, true);
+ torture_assert_goto(tctx, status != -1, ok, done, "tfork_status failed\n");
+
+ torture_assert_goto(tctx, WIFEXITED(status) == true, ok, done,
+ "tfork failed\n");
+ torture_assert_goto(tctx, WEXITSTATUS(status) == 0, ok, done,
+ "tfork failed\n");
+done:
+ return ok;
+}
+
+static void *tfork_thread(void *p)
+{
+ struct tfork *t = NULL;
+ int status;
+ pid_t child;
+ uint64_t tid = (uint64_t)pthread_self();
+ uint64_t *result = NULL;
+ int up[2];
+ ssize_t nread;
+ int ret;
+
+ ret = pipe(up);
+ if (ret != 0) {
+ pthread_exit(NULL);
+ }
+
+ t = tfork_create();
+ if (t == NULL) {
+ pthread_exit(NULL);
+ }
+ child = tfork_child_pid(t);
+ if (child == 0) {
+ ssize_t nwritten;
+
+ close(up[0]);
+ tid++;
+ nwritten = sys_write(up[1], &tid, sizeof(uint64_t));
+ if (nwritten != sizeof(uint64_t)) {
+ _exit(1);
+ }
+ _exit(0);
+ }
+ close(up[1]);
+
+ result = malloc(sizeof(uint64_t));
+ if (result == NULL) {
+ pthread_exit(NULL);
+ }
+
+ nread = sys_read(up[0], result, sizeof(uint64_t));
+ if (nread != sizeof(uint64_t)) {
+ pthread_exit(NULL);
+ }
+
+ status = tfork_status(&t, true);
+ if (status == -1) {
+ pthread_exit(NULL);
+ }
+
+ pthread_exit(result);
+}
+
+static bool test_tfork_threads(struct torture_context *tctx)
+{
+ int ret;
+ bool ok = true;
+ const int num_threads = 64;
+ pthread_t threads[num_threads];
+ sigset_t set;
+ int i;
+
+#ifndef HAVE_PTHREAD
+ torture_skip(tctx, "no pthread support\n");
+#endif
+
+ /*
+ * Be nasty and taste for the worst case: ensure all threads start with
+ * SIGCHLD unblocked so we have the most fun with SIGCHLD being
+ * delivered to a random thread. :)
+ */
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+#ifdef HAVE_PTHREAD
+ ret = pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+#else
+ ret = sigprocmask(SIG_UNBLOCK, &set, NULL);
+#endif
+ if (ret != 0) {
+ return false;
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ ret = pthread_create(&threads[i], NULL, tfork_thread, NULL);
+ torture_assert_goto(tctx, ret == 0, ok, done,
+ "pthread_create failed\n");
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ void *p;
+ uint64_t *result;
+
+ ret = pthread_join(threads[i], &p);
+ torture_assert_goto(tctx, ret == 0, ok, done,
+ "pthread_join failed\n");
+ result = (uint64_t *)p;
+ torture_assert_goto(tctx, *result == (uint64_t)threads[i] + 1,
+ ok, done, "thread failed\n");
+ free(p);
+ }
+
+done:
+ return ok;
+}
+
+static bool test_tfork_cmd_send(struct torture_context *tctx)
+{
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ const char *cmd[2] = { NULL, NULL };
+ bool ok = true;
+
+ ev = tevent_context_init(tctx);
+ torture_assert_goto(tctx, ev != NULL, ok, done,
+ "tevent_context_init failed\n");
+
+ cmd[0] = talloc_asprintf(tctx, "%s/testprogs/blackbox/tfork.sh", SRCDIR);
+ torture_assert_goto(tctx, cmd[0] != NULL, ok, done,
+ "talloc_asprintf failed\n");
+
+ req = samba_runcmd_send(tctx, ev, timeval_zero(), 0, 0,
+ cmd, "foo", NULL);
+ torture_assert_goto(tctx, req != NULL, ok, done,
+ "samba_runcmd_send failed\n");
+
+ ok = tevent_req_poll(req, ev);
+ torture_assert_goto(tctx, ok, ok, done, "tevent_req_poll failed\n");
+
+ torture_comment(tctx, "samba_runcmd_send test finished\n");
+
+done:
+ TALLOC_FREE(ev);
+
+ return ok;
+}
+
+/*
+ * Test to ensure that the event_fd becomes readable after
+ * a tfork_process terminates.
+ */
+static bool test_tfork_event_file_handle(struct torture_context *tctx)
+{
+ bool ok = true;
+
+ struct tfork *t1 = NULL;
+ pid_t child1;
+ struct pollfd poll1[] = {
+ {
+ .fd = -1,
+ .events = POLLIN,
+ },
+ };
+
+ struct tfork *t2 = NULL;
+ pid_t child2;
+ struct pollfd poll2[] = {
+ {
+ .fd = -1,
+ .events = POLLIN,
+ },
+ };
+
+
+ t1 = tfork_create();
+ if (t1 == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+
+ child1 = tfork_child_pid(t1);
+ if (child1 == 0) {
+ /*
+ * Parent process will kill this with a SIGTERM
+ * so 10 seconds should be plenty
+ */
+ sleep(10);
+ exit(1);
+ }
+ poll1[0].fd = tfork_event_fd(t1);
+
+ t2 = tfork_create();
+ if (t2 == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child2 = tfork_child_pid(t2);
+ if (child2 == 0) {
+ /*
+ * Parent process will kill this with a SIGTERM
+ * so 10 seconds should be plenty
+ */
+ sleep(10);
+ exit(2);
+ }
+ poll2[0].fd = tfork_event_fd(t2);
+
+ /*
+ * Have forked two process and are in the master process
+ * Expect that both event_fds are unreadable
+ */
+ poll(poll1, 1, 0);
+ ok = !(poll1[0].revents & POLLIN);
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 1 event fd readable\n");
+ poll(poll2, 1, 0);
+ ok = !(poll2[0].revents & POLLIN);
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 1 event fd readable\n");
+
+ /* Kill the first child process */
+ kill(child1, SIGKILL);
+ sleep(1);
+
+ /*
+ * Have killed the first child, so expect it's event_fd to have gone
+ * readable.
+ *
+ */
+ poll(poll1, 1, 0);
+ ok = (poll1[0].revents & POLLIN);
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 1 event fd not readable\n");
+ poll(poll2, 1, 0);
+ ok = !(poll2[0].revents & POLLIN);
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 2 event fd readable\n");
+
+ /* Kill the secind child process */
+ kill(child2, SIGKILL);
+ sleep(1);
+ /*
+ * Have killed the children, so expect their event_fd's to have gone
+ * readable.
+ *
+ */
+ poll(poll1, 1, 0);
+ ok = (poll1[0].revents & POLLIN);
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 1 event fd not readable\n");
+ poll(poll2, 1, 0);
+ ok = (poll2[0].revents & POLLIN);
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 2 event fd not readable\n");
+
+done:
+ free(t1);
+ free(t2);
+
+ return ok;
+}
+
+/*
+ * Test to ensure that the status calls behave as expected after a process
+ * terminates.
+ *
+ * As the parent process owns the status fd's they get passed to all
+ * subsequent children after a tfork. So it's possible for another
+ * child process to hold the status pipe open.
+ *
+ * The event fd needs to be left open by tfork, as a close in the status
+ * code can cause issues in tevent code.
+ *
+ */
+static bool test_tfork_status_handle(struct torture_context *tctx)
+{
+ bool ok = true;
+
+ struct tfork *t1 = NULL;
+ pid_t child1;
+
+ struct tfork *t2 = NULL;
+ pid_t child2;
+
+ int status;
+ int fd;
+ int ev1_fd;
+ int ev2_fd;
+
+
+ t1 = tfork_create();
+ if (t1 == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+
+ child1 = tfork_child_pid(t1);
+ if (child1 == 0) {
+ /*
+ * Parent process will kill this with a SIGTERM
+ * so 10 seconds should be plenty
+ */
+ sleep(10);
+ exit(1);
+ }
+ ev1_fd = tfork_event_fd(t1);
+
+ t2 = tfork_create();
+ if (t2 == NULL) {
+ torture_fail(tctx, "tfork failed\n");
+ return false;
+ }
+ child2 = tfork_child_pid(t2);
+ if (child2 == 0) {
+ /*
+ * Parent process will kill this with a SIGTERM
+ * so 10 seconds should be plenty
+ */
+ sleep(10);
+ exit(2);
+ }
+ ev2_fd = tfork_event_fd(t2);
+
+ /*
+ * Have forked two process and are in the master process
+ * expect that the status call will block, and hence return -1
+ * as the processes are still running
+ * The event fd's should be open.
+ */
+ status = tfork_status(&t1, false);
+ ok = status == -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork status available for non terminated "
+ "process 1\n");
+ /* Is the event fd open? */
+ fd = dup(ev1_fd);
+ ok = fd != -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 1 event fd is not open");
+
+ status = tfork_status(&t2, false);
+ ok = status == -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork status available for non terminated "
+ "process 2\n");
+ /* Is the event fd open? */
+ fd = dup(ev2_fd);
+ ok = fd != -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 2 event fd is not open");
+
+ /*
+ * Kill the first process, it's status should be readable
+ * and it's event_fd should be open
+ * The second process's status should be unreadable.
+ */
+ kill(child1, SIGTERM);
+ sleep(1);
+ status = tfork_status(&t1, false);
+ ok = status != -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork status for child 1 not available after "
+ "termination\n");
+ /* Is the event fd open? */
+ fd = dup(ev2_fd);
+ ok = fd != -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 1 event fd is not open");
+
+ status = tfork_status(&t2, false);
+ ok = status == -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork status available for child 2 after "
+ "termination of child 1\n");
+
+ /*
+ * Kill the second process, it's status should be readable
+ */
+ kill(child2, SIGTERM);
+ sleep(1);
+ status = tfork_status(&t2, false);
+ ok = status != -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork status for child 2 not available after "
+ "termination\n");
+
+ /* Check that the event fd's are still open */
+ /* Is the event fd open? */
+ fd = dup(ev1_fd);
+ ok = fd != -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 1 event fd is not open");
+ /* Is the event fd open? */
+ fd = dup(ev2_fd);
+ ok = fd != -1;
+ torture_assert_goto(tctx, ok, ok, done,
+ "tfork process 2 event fd is not open");
+
+done:
+ return ok;
+}
+
+struct torture_suite *torture_local_tfork(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(mem_ctx, "tfork");
+
+ torture_suite_add_simple_test(suite,
+ "tfork_simple",
+ test_tfork_simple);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_status",
+ test_tfork_status);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_sigign",
+ test_tfork_sigign);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_sighandler",
+ test_tfork_sighandler);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_process_hierarchy",
+ test_tfork_process_hierarchy);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_pipe",
+ test_tfork_pipe);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_twice",
+ test_tfork_twice);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_threads",
+ test_tfork_threads);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_cmd_send",
+ test_tfork_cmd_send);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_event_file_handle",
+ test_tfork_event_file_handle);
+
+ torture_suite_add_simple_test(suite,
+ "tfork_status_handle",
+ test_tfork_status_handle);
+
+ return suite;
+}
diff --git a/lib/util/tests/time.c b/lib/util/tests/time.c
new file mode 100644
index 0000000..ec27f56
--- /dev/null
+++ b/lib/util/tests/time.c
@@ -0,0 +1,151 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ util time testing
+
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+static bool test_null_time(struct torture_context *tctx)
+{
+ torture_assert(tctx, null_time(0), "0");
+ torture_assert(tctx, null_time(0xFFFFFFFF), "0xFFFFFFFF");
+ torture_assert(tctx, null_time(-1), "-1");
+ torture_assert(tctx, !null_time(42), "42");
+ return true;
+}
+
+static bool test_null_nttime(struct torture_context *tctx)
+{
+ torture_assert(tctx, null_nttime(0), "0");
+ torture_assert(tctx, !null_nttime(NTTIME_FREEZE), "-1");
+ torture_assert(tctx, !null_nttime(NTTIME_THAW), "-2");
+ torture_assert(tctx, !null_nttime(42), "42");
+ return true;
+}
+
+
+static bool test_http_timestring(struct torture_context *tctx)
+{
+ const char *start = "Thu, 01 Jan 1970";
+ char *result;
+ /*
+ * Correct test for negative UTC offset. Without the correction, the
+ * test fails when run on hosts with negative UTC offsets, as the date
+ * returned is back in 1969 (pre-epoch).
+ */
+ time_t now = time(NULL);
+ struct tm local = *localtime(&now);
+ struct tm gmt = *gmtime(&now);
+ time_t utc_offset = mktime(&local) - mktime(&gmt);
+
+ result = http_timestring(tctx, 42 - (utc_offset < 0 ? utc_offset : 0));
+ torture_assert(tctx, !strncmp(start, result,
+ strlen(start)), result);
+ torture_assert_str_equal(tctx, "never",
+ http_timestring(tctx, get_time_t_max()), "42");
+ return true;
+}
+
+static bool test_timestring(struct torture_context *tctx)
+{
+ const char *start = "Thu Jan 1";
+ char *result;
+ /*
+ * Correct test for negative UTC offset. Without the correction, the
+ * test fails when run on hosts with negative UTC offsets, as the date
+ * returned is back in 1969 (pre-epoch).
+ */
+ time_t now = time(NULL);
+ struct tm local = *localtime(&now);
+ struct tm gmt = *gmtime(&now);
+ time_t utc_offset = mktime(&local) - mktime(&gmt);
+
+ result = timestring(tctx, 42 - (utc_offset < 0 ? utc_offset : 0));
+ torture_assert(tctx, !strncmp(start, result, strlen(start)), result);
+ return true;
+}
+
+static bool test_normalize_timespec(struct torture_context *tctx)
+{
+ const struct {
+ time_t in_s; long in_ns;
+ time_t out_s; long out_ns;
+ } data [] = {
+ { 0, 0, 0, 0 }
+ , { 1, 0, 1, 0 }
+ , { -1, 0, -1, 0 }
+ , { 0, 1000000000, 1, 0 }
+ , { 0, 2000000000, 2, 0 }
+ , { 0, 1000000001, 1, 1 }
+ , { 0, 2000000001, 2, 1 }
+ , { 0, -1000000000, -1, 0 }
+ , { 0, -2000000000, -2, 0 }
+ , { 0, -1000000001, -2, 999999999 }
+ , { 0, -2000000001, -3, 999999999 }
+ , { 0, -1, -1, 999999999 }
+ , { 1, -1, 0, 999999999 }
+ , { -1, -1, -2, 999999999 }
+ , { 0, 999999999, 0, 999999999 }
+ , { 0, 1999999999, 1, 999999999 }
+ , { 0, 2999999999, 2, 999999999 }
+ , { 0, -999999999, -1, 1 }
+ , { 0, -1999999999, -2, 1 }
+ , { 0, -2999999999, -3, 1 }
+ , { LONG_MAX, 1000000001, LONG_MAX, 999999999 } /* overflow */
+ , { LONG_MAX, 999999999, LONG_MAX, 999999999 } /* harmless */
+ , { LONG_MAX, -1, LONG_MAX-1, 999999999 } /* -1 */
+ , { LONG_MIN, -1000000001, LONG_MIN, 0 } /* overflow */
+ , { LONG_MIN, 0, LONG_MIN, 0 } /* harmless */
+ , { LONG_MIN, 1000000000, LONG_MIN+1, 0 } /* +1 */
+ };
+ int i;
+
+ for (i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
+ struct timespec ts = (struct timespec)
+ { .tv_sec = data[i].in_s
+ , .tv_nsec = data[i].in_ns };
+
+ normalize_timespec(&ts);
+
+ torture_assert_int_equal(tctx, ts.tv_sec, data[i].out_s,
+ "mismatch in tv_sec");
+ torture_assert_int_equal(tctx, ts.tv_nsec, data[i].out_ns,
+ "mismatch in tv_nsec");
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_local_util_time(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "time");
+
+ torture_suite_add_simple_test(suite, "null_time", test_null_time);
+ torture_suite_add_simple_test(suite, "null_nttime", test_null_nttime);
+ torture_suite_add_simple_test(suite, "http_timestring",
+ test_http_timestring);
+ torture_suite_add_simple_test(suite, "timestring",
+ test_timestring);
+ torture_suite_add_simple_test(suite, "normalize_timespec",
+ test_normalize_timespec);
+
+ return suite;
+}
diff --git a/lib/util/tests/util.c b/lib/util/tests/util.c
new file mode 100644
index 0000000..0b69e21
--- /dev/null
+++ b/lib/util/tests/util.c
@@ -0,0 +1,652 @@
+/*
+ * Tests for strv_util
+ *
+ * Copyright Martin Schwenke <martin@meltin.net> 2016
+ * Copyright Christof Schmitt <cs@samba.org> 2018
+ * Copyright Swen Schillig <swen@linux.ibm.com> 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <talloc.h>
+
+#include "replace.h"
+#include "system/filesys.h"
+
+#include "libcli/util/ntstatus.h"
+#include "torture/torture.h"
+#include "lib/util/data_blob.h"
+#include "torture/local/proto.h"
+
+#include "lib/util/samba_util.h"
+#include "lib/util/smb_strtox.h"
+
+#include "limits.h"
+#include "string.h"
+
+struct test_trim_string_data {
+ const char *desc;
+ const char *in;
+ const char *front;
+ const char *back;
+ const char *out;
+ bool ret;
+};
+
+static const struct test_trim_string_data test_trim_string_data[] = {
+ {
+ .desc = "All NULL",
+ .in = NULL,
+ .front = NULL,
+ .back = NULL,
+ .out = NULL,
+ .ret = false,
+ },
+ {
+ .desc = "Input NULL",
+ .in = NULL,
+ .front = "abc",
+ .back = "123",
+ .out = NULL,
+ .ret = false,
+ },
+ {
+ .desc = "Trim NULL",
+ .in = "abc",
+ .front = NULL,
+ .back = NULL,
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim empty",
+ .in = "abc",
+ .front = "",
+ .back = "",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim front, non-matching",
+ .in = "abc",
+ .front = "x",
+ .back = "",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim front, matches back",
+ .in = "abc",
+ .front = "c",
+ .back = "",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim front, partial-match",
+ .in = "abc",
+ .front = "ac",
+ .back = "",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim front, too long",
+ .in = "aaa",
+ .front = "aaaa",
+ .back = "",
+ .out = "aaa",
+ .ret = false,
+ },
+ {
+ .desc = "Trim front, 1 char, 1x",
+ .in = "abc",
+ .front = "a",
+ .back = "",
+ .out = "bc",
+ .ret = true,
+ },
+ {
+ .desc = "Trim front, 1 char, 2x",
+ .in = "aabc",
+ .front = "a",
+ .back = "",
+ .out = "bc",
+ .ret = true,
+ },
+ {
+ .desc = "Trim front, 1 char, 3x",
+ .in = "aaabc",
+ .front = "a",
+ .back = "",
+ .out = "bc",
+ .ret = true,
+ },
+ {
+ .desc = "Trim front, 1 char, matches all",
+ .in = "aaa",
+ .front = "a",
+ .back = "",
+ .out = "",
+ .ret = true,
+ },
+ {
+ .desc = "Trim front, 2 chars, 1x",
+ .in = "abc",
+ .front = "ab",
+ .back = "",
+ .out = "c",
+ .ret = true,
+ },
+ {
+ .desc = "Trim front, 2 chars, 2x",
+ .in = "ababc",
+ .front = "ab",
+ .back = "",
+ .out = "c",
+ .ret = true,
+ },
+ {
+ .desc = "Trim front, 3 chars, matches all",
+ .in = "abc",
+ .front = "abc",
+ .back = "",
+ .out = "",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, non-matching",
+ .in = "abc",
+ .front = "",
+ .back = "x",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim back, matches front",
+ .in = "abc",
+ .front = "",
+ .back = "a",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim back, partial-match",
+ .in = "abc",
+ .front = "",
+ .back = "xc",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim back, too long",
+ .in = "aaa",
+ .front = "",
+ .back = "aaaa",
+ .out = "aaa",
+ .ret = false,
+ },
+ {
+ .desc = "Trim back, 1 char, 1x",
+ .in = "abc",
+ .front = "",
+ .back = "c",
+ .out = "ab",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, 1 char, 2x",
+ .in = "abcc",
+ .front = "",
+ .back = "c",
+ .out = "ab",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, 1 char, 3x",
+ .in = "abccc",
+ .front = "",
+ .back = "c",
+ .out = "ab",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, 1 char, matches all",
+ .in = "aaa",
+ .front = "",
+ .back = "a",
+ .out = "",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, 2 chars, 1x",
+ .in = "abc",
+ .front = "",
+ .back = "bc",
+ .out = "a",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, 2 chars, 2x",
+ .in = "abcbc",
+ .front = "",
+ .back = "bc",
+ .out = "a",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, 3 chars, matches all",
+ .in = "abc",
+ .front = "",
+ .back = "abc",
+ .out = "",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, non-matching",
+ .in = "abc",
+ .front = "x",
+ .back = "y",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim both, reversed",
+ .in = "abc",
+ .front = "c",
+ .back = "a",
+ .out = "abc",
+ .ret = false,
+ },
+ {
+ .desc = "Trim both, 1 char, 1x",
+ .in = "abc",
+ .front = "a",
+ .back = "c",
+ .out = "b",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, 1 char, 2x",
+ .in = "aabcc",
+ .front = "a",
+ .back = "c",
+ .out = "b",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, 1 char, 3x",
+ .in = "aaabccc",
+ .front = "a",
+ .back = "c",
+ .out = "b",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, 1 char, matches all",
+ .in = "aaabbb",
+ .front = "a",
+ .back = "b",
+ .out = "",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, 2 chars, 1x",
+ .in = "abxbc",
+ .front = "ab",
+ .back = "bc",
+ .out = "x",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, 2 chars, 2x",
+ .in = "ababxyzbcbc",
+ .front = "ab",
+ .back = "bc",
+ .out = "xyz",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, 2 chars, front matches, back doesn't",
+ .in = "abcde",
+ .front = "ab",
+ .back = "xy",
+ .out = "cde",
+ .ret = true,
+ },
+ {
+ .desc = "Trim both, 2 chars, back matches, front doesn't",
+ .in = "abcde",
+ .front = "xy",
+ .back = "de",
+ .out = "abc",
+ .ret = true,
+ },
+ {
+ .desc = "Trim back, 3 chars, matches all",
+ .in = "abcxyz",
+ .front = "abc",
+ .back = "xyz",
+ .out = "",
+ .ret = true,
+ },
+};
+
+static bool test_trim_string(struct torture_context *tctx)
+{
+ int j;
+ for (j = 0; j < ARRAY_SIZE(test_trim_string_data); j++) {
+ bool ret;
+ const struct test_trim_string_data *d =
+ &test_trim_string_data[j];
+ char *str = talloc_strdup(tctx, d->in);
+ torture_assert(tctx, d->in == NULL || str != NULL,
+ "Out of memory");
+
+ torture_comment(tctx, "%s\n", d->desc);
+ ret = trim_string(str, d->front, d->back);
+ torture_assert(tctx, ret == d->ret,
+ "Incorrect return from trim_string()");
+ if (d->out == NULL) {
+ torture_assert(tctx, str == NULL, "Expected NULL");
+ } else {
+ torture_assert(tctx, str != NULL, "Expected non-NULL");
+ torture_assert_str_equal(tctx, str, d->out,
+ "Incorrect output");
+ }
+ TALLOC_FREE(str);
+ }
+
+ return true;
+}
+
+static bool test_directory_create_or_exist(struct torture_context *tctx)
+{
+ char *path = NULL, *new_path = NULL, *file_path = NULL;
+ bool ret = true, b = true;
+ int fd;
+ NTSTATUS status;
+ const mode_t perms = 0741;
+
+ status = torture_temp_dir(tctx, "util_dir", &path);;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Creating test directory failed.\n");
+
+ b = directory_create_or_exist(path, perms);
+ torture_assert_goto(tctx, b == true, ret, done,
+ "directory_create_or_exist on "
+ "existing directory failed.\n");
+
+ new_path = talloc_asprintf(tctx, "%s/%s", path, "dir");
+ torture_assert_goto(tctx, new_path != NULL, ret, done,
+ "Could not allocate memory for directory path\n");
+
+ b = directory_exist(new_path);
+ torture_assert_goto(tctx, b == false, ret, done,
+ "Check for non-existing directory failed.\n");
+
+ b = directory_create_or_exist(new_path, perms);
+ torture_assert_goto(tctx, b == true, ret, done,
+ "directory_create_or_exist for "
+ "new directory failed.\n");
+
+ b = directory_exist(new_path);
+ torture_assert_goto(tctx, b == true, ret, done,
+ "Check for existing directory failed.\n");
+
+ b = file_check_permissions(new_path, geteuid(), perms, NULL);
+ torture_assert_goto(tctx, b == true, ret, done,
+ "Permission check for directory failed.\n");
+
+ file_path = talloc_asprintf(tctx, "%s/%s", path, "file");
+ torture_assert_goto(tctx, file_path != NULL, ret, done,
+ "Could not allocate memory for file path\n");
+ fd = creat(file_path, perms);
+ torture_assert_goto(tctx, fd != -1, ret, done,
+ "Creating file failed.\n");
+ close(fd);
+
+ b = directory_create_or_exist(file_path, perms);
+ torture_assert_goto(tctx, b == false, ret, done,
+ "directory_create_or_exist for "
+ "existing file failed.\n");
+
+done:
+ return ret;
+}
+
+static bool test_mem_equal_const_time(struct torture_context *tctx)
+{
+ const char *test_string = "abcdabcd";
+
+ torture_assert(tctx, mem_equal_const_time("", "", 0),
+ "zero-length comparison failed");
+
+ torture_assert(tctx, mem_equal_const_time(test_string, test_string, 8),
+ "comparison with equal pointers failed");
+
+ torture_assert(tctx, mem_equal_const_time(test_string, test_string + 4, 4),
+ "comparison with non-equal pointers failed");
+
+ torture_assert(tctx, !mem_equal_const_time("abcd", "efgh", 4),
+ "comparison with different values failed");
+
+ return true;
+}
+
+static bool test_smb_strtoul_errno_check(struct torture_context *tctx)
+{
+ const char *number = "123";
+ unsigned long int val = 0;
+ unsigned long long int vall = 0;
+ int err;
+
+ /* select an error code which is not set by the smb_strtoul routines */
+ errno = EAGAIN;
+ err = EAGAIN;
+ val = smb_strtoul(number, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, errno == EAGAIN, "smb_strtoul: Expected EAGAIN");
+ torture_assert(tctx, err == 0, "smb_strtoul: Expected err = 0");
+ torture_assert(tctx, val == 123, "smb_strtoul: Expected value 123");
+
+ /* set err to an impossible value again before continuing */
+ err = EAGAIN;
+ vall = smb_strtoull(number, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, errno == EAGAIN, "smb_strtoull: Expected EAGAIN");
+ torture_assert(tctx, err == 0, "smb_strtoul: Expected err = 0");
+ torture_assert(tctx, vall == 123, "smb_strtoul: Expected value 123");
+
+ return true;
+}
+
+static bool test_smb_strtoul_negative(struct torture_context *tctx)
+{
+ const char *number = "-132";
+ const char *number2 = "132-";
+ unsigned long int val = 0;
+ unsigned long long int vall = 0;
+ int err;
+
+ err = 0;
+ smb_strtoul(number, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == EINVAL, "smb_strtoul: Expected EINVAL");
+
+ err = 0;
+ smb_strtoull(number, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == EINVAL, "smb_strtoull: Expected EINVAL");
+
+ /* it is allowed to have a "-" sign after a number,
+ * e.g. as part of a formular, however, it is not supposed to
+ * have an effect on the converted value.
+ */
+
+ err = 0;
+ val = smb_strtoul(number2, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == 0, "smb_strtoul: Expected no error");
+ torture_assert(tctx, val == 132, "smb_strtoul: Wrong value");
+
+ err = 0;
+ vall = smb_strtoull(number2, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == 0, "smb_strtoull: Expected no error");
+ torture_assert(tctx, vall == 132, "smb_strtoull: Wrong value");
+
+ return true;
+}
+
+static bool test_smb_strtoul_no_number(struct torture_context *tctx)
+{
+ const char *number = "ghijk";
+ const char *blank = "";
+ int err;
+
+ err = 0;
+ smb_strtoul(number, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == EINVAL, "smb_strtoul: Expected EINVAL");
+
+ err = 0;
+ smb_strtoull(number, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == EINVAL, "smb_strtoull: Expected EINVAL");
+
+ err = 0;
+ smb_strtoul(blank, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == EINVAL, "smb_strtoul: Expected EINVAL");
+
+ err = 0;
+ smb_strtoull(blank, NULL, 0, &err, SMB_STR_STANDARD);
+ torture_assert(tctx, err == EINVAL, "smb_strtoull: Expected EINVAL");
+
+ return true;
+}
+
+static bool test_smb_strtoul_allow_negative(struct torture_context *tctx)
+{
+ const char *number = "-1";
+ const char *number2 = "-1-1";
+ unsigned long res = 0;
+ unsigned long long res2 = 0;
+ char *end_ptr = NULL;
+ int err;
+
+ err = 0;
+ res = smb_strtoul(number, NULL, 0, &err, SMB_STR_ALLOW_NEGATIVE);
+ torture_assert(tctx, err == 0, "strtoul_err: Unexpected error");
+ torture_assert(tctx, res == ULONG_MAX, "strtoul_err: Unexpected value");
+
+ err = 0;
+ res2 = smb_strtoull(number, NULL, 0, &err, SMB_STR_ALLOW_NEGATIVE);
+ torture_assert(tctx, err == 0, "strtoull_err: Unexpected error");
+ torture_assert(tctx, res2 == ULLONG_MAX, "strtoull_err: Unexpected value");
+
+ err = 0;
+ smb_strtoul(number2, &end_ptr, 0, &err, SMB_STR_ALLOW_NEGATIVE);
+ torture_assert(tctx, err == 0, "strtoul_err: Unexpected error");
+ torture_assert(tctx, end_ptr[0] == '-', "strtoul_err: Unexpected end pointer");
+
+ err = 0;
+ smb_strtoull(number2, &end_ptr, 0, &err, SMB_STR_ALLOW_NEGATIVE);
+ torture_assert(tctx, err == 0, "strtoull_err: Unexpected error");
+ torture_assert(tctx, end_ptr[0] == '-', "strtoull_err: Unexpected end pointer");
+
+ return true;
+}
+
+static bool test_smb_strtoul_full_string(struct torture_context *tctx)
+{
+ const char *number = "123 ";
+ const char *number2 = "123";
+ int err;
+
+ err = 0;
+ smb_strtoul(number, NULL, 0, &err, SMB_STR_FULL_STR_CONV);
+ torture_assert(tctx, err == EINVAL, "strtoul_err: Expected EINVAL");
+
+ err = 0;
+ smb_strtoull(number, NULL, 0, &err, SMB_STR_FULL_STR_CONV);
+ torture_assert(tctx, err == EINVAL, "strtoull_err: Expected EINVAL");
+
+ err = 0;
+ smb_strtoul(number2, NULL, 0, &err, SMB_STR_FULL_STR_CONV);
+ torture_assert(tctx, err == 0, "strtoul_err: Unexpected error");
+
+ err = 0;
+ smb_strtoull(number2, NULL, 0, &err, SMB_STR_FULL_STR_CONV);
+ torture_assert(tctx, err == 0, "strtoull_err: Unexpected error");
+
+ return true;
+}
+
+static bool test_smb_strtoul_allow_no_conversion(struct torture_context *tctx)
+{
+ const char *number = "";
+ const char *number2 = "xyz";
+ unsigned long int n1 = 0;
+ unsigned long long int n2 = 0;
+ int err;
+
+ err = 0;
+ smb_strtoul(number, NULL, 0, &err, SMB_STR_ALLOW_NO_CONVERSION);
+ torture_assert(tctx, err == 0, "strtoul_err: Unexpected error");
+ torture_assert(tctx, n1 == 0, "strtoul_err: Unexpected value");
+
+ err = 0;
+ smb_strtoull(number, NULL, 0, &err, SMB_STR_ALLOW_NO_CONVERSION);
+ torture_assert(tctx, err == 0, "strtoull_err: Unexpected error");
+ torture_assert(tctx, n2 == 0, "strtoull_err: Unexpected value");
+
+ err = 0;
+ smb_strtoul(number2, NULL, 0, &err, SMB_STR_ALLOW_NO_CONVERSION);
+ torture_assert(tctx, err == 0, "strtoul_err: Unexpected error");
+ torture_assert(tctx, n1 == 0, "strtoul_err: Unexpected value");
+
+ err = 0;
+ smb_strtoull(number2, NULL, 0, &err, SMB_STR_ALLOW_NO_CONVERSION);
+ torture_assert(tctx, err == 0, "strtoull_err: Unexpected error");
+ torture_assert(tctx, n2 == 0, "strtoull_err: Unexpected value");
+
+ return true;
+}
+struct torture_suite *torture_local_util(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(mem_ctx, "util");
+
+ torture_suite_add_simple_test(suite,
+ "trim_string",
+ test_trim_string);
+ torture_suite_add_simple_test(suite,
+ "directory_create_or_exist",
+ test_directory_create_or_exist);
+ torture_suite_add_simple_test(suite,
+ "mem_equal_const_time",
+ test_mem_equal_const_time);
+ torture_suite_add_simple_test(suite,
+ "smb_strtoul(l) errno",
+ test_smb_strtoul_errno_check);
+ torture_suite_add_simple_test(suite,
+ "smb_strtoul(l) negative",
+ test_smb_strtoul_negative);
+ torture_suite_add_simple_test(suite,
+ "smb_strtoul(l) no number",
+ test_smb_strtoul_no_number);
+ torture_suite_add_simple_test(suite,
+ "smb_strtoul(l) allow_negative",
+ test_smb_strtoul_allow_negative);
+ torture_suite_add_simple_test(suite,
+ "smb_strtoul(l) full string conversion",
+ test_smb_strtoul_full_string);
+ torture_suite_add_simple_test(suite,
+ "smb_strtoul(l) allow no conversion",
+ test_smb_strtoul_allow_no_conversion);
+ return suite;
+}
diff --git a/lib/util/tests/util_str_escape.c b/lib/util/tests/util_str_escape.c
new file mode 100644
index 0000000..82e2209
--- /dev/null
+++ b/lib/util/tests/util_str_escape.c
@@ -0,0 +1,90 @@
+/*
+
+ util_str_escape testing
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/util/util_str_escape.h"
+
+static bool test_log_escape_empty_string(struct torture_context *tctx)
+{
+ char *result = log_escape( tctx, "");
+ torture_assert_str_equal(tctx, result, "", "Empty string handling");
+ return true;
+}
+
+static bool test_log_escape_null_string(struct torture_context *tctx)
+{
+ char *result = log_escape( tctx, NULL);
+ torture_assert(tctx, (result == NULL), "Empty string handling");
+ return true;
+}
+
+static bool test_log_escape_plain_string(struct torture_context *tctx)
+{
+ const char *input = "a plain string with no escapable characters";
+ const char *expected = "a plain string with no escapable characters";
+
+ char *result = log_escape( tctx, input);
+ torture_assert_str_equal(tctx, result, expected,
+ "Plain string handling");
+ return true;
+}
+
+static bool test_log_escape_string(struct torture_context *tctx)
+{
+ const char *input = "\a\b\f\n\r\t\v\\\x01";
+ const char *expected = "\\a\\b\\f\\n\\r\\t\\v\\\\\\x01";
+
+ char *result = log_escape( tctx, input);
+ torture_assert_str_equal(tctx, result, expected,
+ "Escapable characters in string");
+ return true;
+}
+
+static bool test_log_escape_hex_string(struct torture_context *tctx)
+{
+ const char *input = "\x01\x1F ";
+ const char *expected = "\\x01\\x1F ";
+
+ char *result = log_escape( tctx, input);
+ torture_assert_str_equal(tctx, result, expected,
+ "hex escaping");
+ return true;
+}
+struct torture_suite *torture_local_util_str_escape(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "util_str_escape");
+
+ torture_suite_add_simple_test(suite, "log_escape_empty_string",
+ test_log_escape_empty_string);
+ torture_suite_add_simple_test(suite, "log_escape_null_string",
+ test_log_escape_null_string);
+ torture_suite_add_simple_test(suite, "log_escape_plain_string",
+ test_log_escape_plain_string);
+ torture_suite_add_simple_test(suite, "log_escape_string",
+ test_log_escape_string);
+ torture_suite_add_simple_test(suite, "log_escape_hex_string",
+ test_log_escape_hex_string);
+
+
+ return suite;
+}
diff --git a/lib/util/tevent_debug.c b/lib/util/tevent_debug.c
new file mode 100644
index 0000000..4ec9057
--- /dev/null
+++ b/lib/util/tevent_debug.c
@@ -0,0 +1,116 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <tevent.h>
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_TEVENT
+
+static void samba_tevent_debug(void *context,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap) PRINTF_ATTRIBUTE(3,0);
+
+static void samba_tevent_debug(void *context,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap)
+{
+ int samba_level = -1;
+
+ switch (level) {
+ case TEVENT_DEBUG_FATAL:
+ samba_level = 0;
+ break;
+ case TEVENT_DEBUG_ERROR:
+ samba_level = 1;
+ break;
+ case TEVENT_DEBUG_WARNING:
+ samba_level = 2;
+ break;
+ case TEVENT_DEBUG_TRACE:
+ samba_level = 50;
+ break;
+ };
+
+ if (CHECK_DEBUGLVL(samba_level)) {
+ const char *name = (const char *)context;
+ char *message = NULL;
+ int ret;
+
+ ret = vasprintf(&message, fmt, ap);
+ if (ret == -1) {
+ return;
+ }
+
+ if (name == NULL) {
+ name = "samba_tevent";
+ }
+
+ DEBUG(samba_level, ("%s: %s", name, message));
+ free(message);
+ }
+}
+
+static void samba_tevent_abort_fn(const char *reason)
+{
+ smb_panic(reason);
+}
+
+static void samba_tevent_setup_abort_fn(void)
+{
+ static bool abort_fn_done;
+
+ if (!abort_fn_done) {
+ tevent_set_abort_fn(samba_tevent_abort_fn);
+ abort_fn_done = true;
+ }
+}
+
+void samba_tevent_set_debug(struct tevent_context *ev, const char *name)
+{
+ void *p = discard_const(name);
+ samba_tevent_setup_abort_fn();
+ tevent_set_debug(ev, samba_tevent_debug, p);
+
+ /* these values should match samba_tevent_debug() */
+ if (CHECK_DEBUGLVL(50)) {
+ tevent_set_max_debug_level(ev, TEVENT_DEBUG_TRACE);
+ } else if (CHECK_DEBUGLVL(2)) {
+ tevent_set_max_debug_level(ev, TEVENT_DEBUG_WARNING);
+ } else if (CHECK_DEBUGLVL(1)) {
+ tevent_set_max_debug_level(ev, TEVENT_DEBUG_ERROR);
+ } else {
+ tevent_set_max_debug_level(ev, TEVENT_DEBUG_FATAL);
+ }
+}
+
+struct tevent_context *samba_tevent_context_init(TALLOC_CTX *mem_ctx)
+{
+ struct tevent_context *ev;
+
+ samba_tevent_setup_abort_fn();
+
+ ev = tevent_context_init(mem_ctx);
+ if (ev) {
+ samba_tevent_set_debug(ev, NULL);
+ }
+
+ return ev;
+}
diff --git a/lib/util/tevent_ntstatus.c b/lib/util/tevent_ntstatus.c
new file mode 100644
index 0000000..7659f15
--- /dev/null
+++ b/lib/util/tevent_ntstatus.c
@@ -0,0 +1,114 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap unix errno around tevent_req
+ Copyright (C) Volker Lendecke 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../replace/replace.h"
+#include "tevent_ntstatus.h"
+#include "libcli/util/error.h"
+
+#define TEVENT_NTERROR_MAGIC (0x917b5acd)
+
+bool _tevent_req_nterror(struct tevent_req *req,
+ NTSTATUS status,
+ const char *location)
+{
+ uint64_t err;
+
+ if (NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /*
+ * I've put this variable here, because I'm not 100% certain
+ * how to correctly assign a 64-bit constant and left-shift it
+ * by 32 bits in a single expression. If anyone knows, feel
+ * free :-)
+ */
+ err = TEVENT_NTERROR_MAGIC;
+ err <<= 32;
+ err |= NT_STATUS_V(status);
+
+ return _tevent_req_error(req, err, location);
+}
+
+bool tevent_req_is_nterror(struct tevent_req *req, NTSTATUS *status)
+{
+ enum tevent_req_state state;
+ uint64_t err;
+
+ if (!tevent_req_is_error(req, &state, &err)) {
+ return false;
+ }
+ switch (state) {
+ case TEVENT_REQ_TIMED_OUT:
+ *status = NT_STATUS_IO_TIMEOUT;
+ break;
+ case TEVENT_REQ_NO_MEMORY:
+ *status = NT_STATUS_NO_MEMORY;
+ break;
+ case TEVENT_REQ_USER_ERROR:
+ if ((err >> 32) != TEVENT_NTERROR_MAGIC) {
+ abort();
+ }
+ *status = NT_STATUS(err & 0xffffffff);
+ break;
+ default:
+ *status = NT_STATUS_INTERNAL_ERROR;
+ break;
+ }
+ return true;
+}
+
+NTSTATUS tevent_req_simple_recv_ntstatus(struct tevent_req *req)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ /*
+ * Ignore result of tevent_req_is_nterror, we're only interested in
+ * the status
+ */
+ tevent_req_is_nterror(req, &status);
+ tevent_req_received(req);
+ return status;
+}
+
+void tevent_req_simple_finish_ntstatus(struct tevent_req *subreq,
+ NTSTATUS subreq_status)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+
+ TALLOC_FREE(subreq);
+
+ if (!NT_STATUS_IS_OK(subreq_status)) {
+ tevent_req_nterror(req, subreq_status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+bool tevent_req_poll_ntstatus(struct tevent_req *req,
+ struct tevent_context *ev,
+ NTSTATUS *status)
+{
+ bool ret = tevent_req_poll(req, ev);
+ if (!ret) {
+ *status = map_nt_error_from_unix_common(errno);
+ }
+ return ret;
+}
diff --git a/lib/util/tevent_ntstatus.h b/lib/util/tevent_ntstatus.h
new file mode 100644
index 0000000..570b6f9
--- /dev/null
+++ b/lib/util/tevent_ntstatus.h
@@ -0,0 +1,47 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap unix errno around tevent_req
+ Copyright (C) Volker Lendecke 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TEVENT_NTSTATUS_H
+#define _TEVENT_NTSTATUS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "../libcli/util/ntstatus.h"
+#include <tevent.h>
+
+bool _tevent_req_nterror(struct tevent_req *req,
+ NTSTATUS status,
+ const char *location);
+#define tevent_req_nterror(req, status) \
+ _tevent_req_nterror(req, status, __location__)
+bool tevent_req_is_nterror(struct tevent_req *req, NTSTATUS *pstatus);
+NTSTATUS tevent_req_simple_recv_ntstatus(struct tevent_req *req);
+
+/*
+ * Helper routine to pass the subreq_ntstatus to the req embedded in
+ * tevent_req_callback_data(subreq), which will be freed.
+ */
+void tevent_req_simple_finish_ntstatus(struct tevent_req *subreq,
+ NTSTATUS subreq_status);
+
+bool tevent_req_poll_ntstatus(struct tevent_req *req,
+ struct tevent_context *ev,
+ NTSTATUS *status);
+
+#endif
diff --git a/lib/util/tevent_req_profile.c b/lib/util/tevent_req_profile.c
new file mode 100644
index 0000000..2d280f7
--- /dev/null
+++ b/lib/util/tevent_req_profile.c
@@ -0,0 +1,506 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Helpers around tevent_req_profile
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <tevent.h>
+#include "lib/util/tevent_req_profile.h"
+#include "lib/util/time_basic.h"
+#include "lib/util/memory.h"
+
+static bool tevent_req_profile_string_internal(
+ const struct tevent_req_profile *profile,
+ unsigned indent,
+ unsigned max_indent,
+ char **string)
+{
+ struct timeval start, stop, diff;
+ struct timeval_buf start_buf, stop_buf;
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ pid_t pid;
+ enum tevent_req_state state;
+ const char *state_buf = NULL;
+ uint64_t user_error;
+ const struct tevent_req_profile *sub = NULL;
+ char *result;
+
+ tevent_req_profile_get_name(profile, &req_name);
+
+ tevent_req_profile_get_start(profile, &start_location, &start);
+ timeval_str_buf(&start, false, true, &start_buf);
+
+ tevent_req_profile_get_stop(profile, &stop_location, &stop);
+ timeval_str_buf(&stop, false, true, &stop_buf);
+
+ diff = tevent_timeval_until(&start, &stop);
+
+ tevent_req_profile_get_status(profile, &pid, &state, &user_error);
+
+ switch(state) {
+ case TEVENT_REQ_INIT:
+ state_buf = "TEVENT_REQ_INIT";
+ break;
+ case TEVENT_REQ_IN_PROGRESS:
+ state_buf = "TEVENT_REQ_IN_PROGRESS";
+ break;
+ case TEVENT_REQ_DONE:
+ state_buf = "TEVENT_REQ_DONE";
+ break;
+ case TEVENT_REQ_USER_ERROR:
+ state_buf = "TEVENT_REQ_USER_ERROR";
+ break;
+ case TEVENT_REQ_TIMED_OUT:
+ state_buf = "TEVENT_REQ_TIMED_OUT";
+ break;
+ case TEVENT_REQ_NO_MEMORY:
+ state_buf = "TEVENT_REQ_NO_MEMORY";
+ break;
+ case TEVENT_REQ_RECEIVED:
+ state_buf = "TEVENT_REQ_RECEIVED";
+ break;
+ default:
+ state_buf = "unknown";
+ break;
+ }
+
+ result = talloc_asprintf_append_buffer(
+ *string,
+ "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64"))\n",
+ indent,
+ "",
+ req_name,
+ start_location,
+ start_buf.buf,
+ stop_location,
+ stop_buf.buf,
+ (uintmax_t)diff.tv_sec,
+ (uintmax_t)diff.tv_usec,
+ state_buf,
+ (int)state,
+ user_error);
+ if (result == NULL) {
+ return false;
+ }
+ *string = result;
+
+ indent += 1;
+
+ if (indent >= max_indent) {
+ return true;
+ }
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+ bool ret;
+
+ ret = tevent_req_profile_string_internal(
+ sub,
+ indent,
+ max_indent,
+ string);
+ if (!ret) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+char *tevent_req_profile_string(TALLOC_CTX *mem_ctx,
+ const struct tevent_req_profile *profile,
+ unsigned indent,
+ unsigned max_indent)
+{
+ char *result;
+ bool ret;
+
+ result = talloc_strdup(mem_ctx, "");
+ if (result == NULL) {
+ return NULL;
+ }
+
+ ret = tevent_req_profile_string_internal(
+ profile,
+ indent,
+ max_indent,
+ &result);
+ if (!ret) {
+ TALLOC_FREE(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static ssize_t tevent_req_profile_pack_one(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen)
+{
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ struct timeval start_time, stop_time;
+ pid_t pid;
+ enum tevent_req_state state;
+ uint64_t user_error;
+ size_t pack_len, len;
+ int ret;
+
+ tevent_req_profile_get_name(profile, &req_name);
+ tevent_req_profile_get_start(profile, &start_location, &start_time);
+ tevent_req_profile_get_stop(profile, &stop_location, &stop_time);
+ tevent_req_profile_get_status(profile, &pid, &state, &user_error);
+
+ len = strlen(req_name)+1;
+ if (buflen >= len) {
+ memcpy(buf, req_name, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ pack_len = len;
+
+ len = strlen(start_location)+1;
+ pack_len += len;
+ if (pack_len < len) {
+ return -1; /* overflow */
+ }
+
+ if (buflen >= len) {
+ memcpy(buf, start_location, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ len = strlen(stop_location)+1;
+ pack_len += len;
+ if (pack_len < len) {
+ return -1; /* overflow */
+ }
+
+ if (buflen >= len) {
+ memcpy(buf, stop_location, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ ret = snprintf((char *)buf,
+ buflen,
+ "%ju %ju %ju %ju %d %d %"PRIu64"",
+ (uintmax_t)start_time.tv_sec,
+ (uintmax_t)start_time.tv_usec,
+ (uintmax_t)stop_time.tv_sec,
+ (uintmax_t)stop_time.tv_usec,
+ (int)pid,
+ (int)state,
+ user_error);
+ if (ret < 0) {
+ return -1;
+ }
+
+ /*
+ * Take care of the trailing 0. No overflow check, this would
+ * be a VERY small number of bits for "int".
+ */
+ ret += 1;
+
+ pack_len += ret;
+
+ return pack_len;
+}
+
+ssize_t tevent_req_profile_pack(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen)
+{
+ const struct tevent_req_profile *sub = NULL;
+ size_t num_sub;
+ ssize_t pack_len, profile_len;
+ int ret;
+
+ num_sub = 0;
+ pack_len = 0;
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+ num_sub += 1;
+ }
+
+ ret = snprintf((char *)buf, buflen, "%zu ", num_sub);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (buflen > (size_t)ret) {
+ buf += ret;
+ buflen -= ret;
+ }
+
+ pack_len = ret;
+
+ profile_len = tevent_req_profile_pack_one(profile, buf, buflen);
+ if (profile_len == -1) {
+ return -1;
+ }
+
+ if (buflen >= (size_t)profile_len) {
+ buf += profile_len;
+ buflen -= profile_len;
+ }
+
+ pack_len += profile_len;
+ if (pack_len < profile_len) {
+ return -1; /* overflow */
+ }
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+
+ profile_len = tevent_req_profile_pack(sub, buf, buflen);
+ if (profile_len == -1) {
+ return -1;
+ }
+
+ if (buflen >= (size_t)profile_len) {
+ buf += profile_len;
+ buflen -= profile_len;
+ }
+
+ pack_len += profile_len;
+ if (pack_len < profile_len) {
+ return -1; /* overflow */
+ }
+ }
+
+ return pack_len;
+}
+
+static bool parse_uintmax(const char *buf,
+ char delimiter,
+ uintmax_t *presult,
+ char **p_endptr)
+{
+ uintmax_t result;
+ char *endptr;
+
+ result = strtoumax(buf, &endptr, 10);
+ if ((result == UINTMAX_MAX) && (errno == ERANGE)) {
+ return false;
+ }
+ if (*endptr != delimiter) {
+ return false;
+ }
+
+ *presult = result;
+ *p_endptr = endptr+1;
+
+ return true;
+}
+
+static ssize_t tevent_req_profile_unpack_one(
+ const uint8_t *buf,
+ size_t buflen,
+ struct tevent_req_profile *profile)
+{
+ const char *orig_buf = (const char *)buf;
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ uintmax_t start_sec, start_usec, stop_sec, stop_usec, pid, state;
+ uintmax_t user_error;
+ char *next = NULL;
+ size_t len;
+ bool ok;
+
+ if (buflen == 0) {
+ return -1;
+ }
+ if (buf[buflen-1] != '\0') {
+ return -1;
+ }
+
+ req_name = (const char *)buf;
+ len = strlen(req_name)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ start_location = (const char *)buf;
+ len = strlen(start_location)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ stop_location = (const char *)buf;
+ len = strlen(stop_location)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ ok = parse_uintmax((const char *)buf, ' ', &start_sec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &start_usec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &stop_sec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &stop_usec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &pid, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &state, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, '\0', &user_error, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_name(profile, req_name);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_start(
+ profile,
+ start_location,
+ (struct timeval){ .tv_sec=start_sec, .tv_usec=start_usec });
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_stop(
+ profile,
+ stop_location,
+ (struct timeval){ .tv_sec=stop_sec, .tv_usec=stop_usec });
+ if (!ok) {
+ return -1;
+ }
+
+ tevent_req_profile_set_status(
+ profile,
+ pid,
+ (enum tevent_req_state)state,
+ user_error);
+
+ return next - orig_buf;
+}
+
+ssize_t tevent_req_profile_unpack(
+ const uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **p_profile)
+{
+ const uint8_t *orig_buf = buf;
+ struct tevent_req_profile *profile = NULL;
+ uintmax_t i, num_subprofiles;
+ char *next = NULL;
+ bool ok;
+ ssize_t len;
+
+ errno = 0;
+
+ if (buf[buflen-1] != '\0') {
+ return -1;
+ }
+
+ ok = parse_uintmax((const char *)buf, ' ', &num_subprofiles, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ len = (next - (const char *)buf);
+
+ buf += len;
+ buflen -= len;
+
+ profile = tevent_req_profile_create(mem_ctx);
+ if (profile == NULL) {
+ return -1;
+ }
+
+ len = tevent_req_profile_unpack_one(buf, buflen, profile);
+ if (len == -1) {
+ TALLOC_FREE(profile);
+ return -1;
+ }
+
+ buf += len;
+ buflen -= len;
+
+ for (i=0; i<num_subprofiles; i++) {
+ struct tevent_req_profile *subprofile;
+
+ len = tevent_req_profile_unpack(
+ buf,
+ buflen,
+ profile,
+ &subprofile);
+ if (len == -1) {
+ TALLOC_FREE(profile);
+ return -1;
+ }
+ buf += len;
+ buflen -= len;
+
+ tevent_req_profile_append_sub(profile, &subprofile);
+ }
+
+ *p_profile = profile;
+
+ return buf - orig_buf;
+}
diff --git a/lib/util/tevent_req_profile.h b/lib/util/tevent_req_profile.h
new file mode 100644
index 0000000..3bcdbc1
--- /dev/null
+++ b/lib/util/tevent_req_profile.h
@@ -0,0 +1,46 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Helpers around tevent_req_profile
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_UTIL_TEVENT_REQ_PROFILE_UNPACK
+#define __LIB_UTIL_TEVENT_REQ_PROFILE_UNPACK
+
+#include "replace.h"
+#include <tevent.h>
+
+char *tevent_req_profile_string(TALLOC_CTX *mem_ctx,
+ const struct tevent_req_profile *profile,
+ unsigned indent,
+ unsigned max_indent);
+ssize_t tevent_req_profile_pack(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen);
+ssize_t tevent_req_profile_unpack(
+ const uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **p_profile);
+
+#endif
diff --git a/lib/util/tevent_unix.c b/lib/util/tevent_unix.c
new file mode 100644
index 0000000..63bdaf6
--- /dev/null
+++ b/lib/util/tevent_unix.c
@@ -0,0 +1,73 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap unix errno around tevent_req
+ Copyright (C) Volker Lendecke 2009
+
+ ** NOTE! The following LGPL license applies to the tevent_unix
+ ** helper library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../replace/replace.h"
+#include "tevent_unix.h"
+
+bool tevent_req_is_unix_error(struct tevent_req *req, int *perrno)
+{
+ enum tevent_req_state state;
+ uint64_t err;
+
+ if (!tevent_req_is_error(req, &state, &err)) {
+ return false;
+ }
+ switch (state) {
+ case TEVENT_REQ_TIMED_OUT:
+ *perrno = ETIMEDOUT;
+ break;
+ case TEVENT_REQ_NO_MEMORY:
+ *perrno = ENOMEM;
+ break;
+ case TEVENT_REQ_USER_ERROR:
+ *perrno = err;
+ break;
+ default:
+ *perrno = EINVAL;
+ break;
+ }
+ return true;
+}
+
+int tevent_req_simple_recv_unix(struct tevent_req *req)
+{
+ int err = 0;
+
+ /*
+ * Ignore result of tevent_req_is_unix_error, we're only interested in
+ * the status
+ */
+ tevent_req_is_unix_error(req, &err);
+ tevent_req_received(req);
+ return err;
+}
+
+bool tevent_req_poll_unix(struct tevent_req *req, struct tevent_context *ev,
+ int *err)
+{
+ bool ret = tevent_req_poll(req, ev);
+ if (!ret) {
+ *err = errno;
+ }
+ return ret;
+}
diff --git a/lib/util/tevent_unix.h b/lib/util/tevent_unix.h
new file mode 100644
index 0000000..39689d6
--- /dev/null
+++ b/lib/util/tevent_unix.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap unix errno around tevent_req
+ Copyright (C) Volker Lendecke 2009
+
+ ** NOTE! The following LGPL license applies to the tevent_unix
+ ** helper library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TEVENT_UNIX_H
+#define _TEVENT_UNIX_H
+
+#include <tevent.h>
+
+bool tevent_req_is_unix_error(struct tevent_req *req, int *perrno);
+int tevent_req_simple_recv_unix(struct tevent_req *req);
+bool tevent_req_poll_unix(struct tevent_req *req, struct tevent_context *ev,
+ int *err);
+
+#endif
diff --git a/lib/util/tevent_werror.c b/lib/util/tevent_werror.c
new file mode 100644
index 0000000..edd503e
--- /dev/null
+++ b/lib/util/tevent_werror.c
@@ -0,0 +1,94 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap win32 errors around tevent_req
+ Copyright (C) Kai Blin 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../replace/replace.h"
+#include "tevent_werror.h"
+#include "libcli/util/error.h"
+
+bool _tevent_req_werror(struct tevent_req *req,
+ WERROR werror,
+ const char *location)
+{
+ return _tevent_req_error(req, W_ERROR_V(werror),
+ location);
+}
+
+bool tevent_req_is_werror(struct tevent_req *req, WERROR *error)
+{
+ enum tevent_req_state state;
+ uint64_t err;
+
+ if (!tevent_req_is_error(req, &state, &err)) {
+ return false;
+ }
+ switch (state) {
+ case TEVENT_REQ_TIMED_OUT:
+ *error = WERR_TIMEOUT;
+ break;
+ case TEVENT_REQ_NO_MEMORY:
+ *error = WERR_NOT_ENOUGH_MEMORY;
+ break;
+ case TEVENT_REQ_USER_ERROR:
+ *error = W_ERROR(err);
+ break;
+ default:
+ *error = WERR_INTERNAL_ERROR;
+ break;
+ }
+ return true;
+}
+
+WERROR tevent_req_simple_recv_werror(struct tevent_req *req)
+{
+ WERROR werror;
+
+ if (tevent_req_is_werror(req, &werror)) {
+ tevent_req_received(req);
+ return werror;
+ }
+ tevent_req_received(req);
+ return WERR_OK;
+}
+
+void tevent_req_simple_finish_werror(struct tevent_req *subreq,
+ WERROR subreq_error)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+
+ TALLOC_FREE(subreq);
+
+ if (!W_ERROR_IS_OK(subreq_error)) {
+ tevent_req_werror(req, subreq_error);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+bool tevent_req_poll_werror(struct tevent_req *req,
+ struct tevent_context *ev,
+ WERROR *err)
+{
+ bool ret = tevent_req_poll(req, ev);
+ if (!ret) {
+ NTSTATUS status = map_nt_error_from_unix_common(errno);
+ *err = ntstatus_to_werror(status);
+ }
+ return ret;
+}
diff --git a/lib/util/tevent_werror.h b/lib/util/tevent_werror.h
new file mode 100644
index 0000000..1e08c3d
--- /dev/null
+++ b/lib/util/tevent_werror.h
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap win32 errors around tevent_req
+ Copyright (C) Kai Blin 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TEVENT_WERROR_H
+#define _TEVENT_WERROR_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "../libcli/util/werror.h"
+#include <tevent.h>
+
+bool _tevent_req_werror(struct tevent_req *req,
+ WERROR werror,
+ const char *location);
+#define tevent_req_werror(req, werror) \
+ _tevent_req_werror(req, werror, __location__)
+bool tevent_req_is_werror(struct tevent_req *req, WERROR *error);
+WERROR tevent_req_simple_recv_werror(struct tevent_req *req);
+
+/*
+ * Helper routine to pass the subreq_werror to the req embedded in
+ * tevent_req_callback_data(subreq), which will be freed.
+ */
+void tevent_req_simple_finish_werror(struct tevent_req *subreq,
+ WERROR subreq_error);
+
+bool tevent_req_poll_werror(struct tevent_req *req,
+ struct tevent_context *ev,
+ WERROR *err);
+#endif
diff --git a/lib/util/tfork.c b/lib/util/tfork.c
new file mode 100644
index 0000000..316287b
--- /dev/null
+++ b/lib/util/tfork.c
@@ -0,0 +1,944 @@
+/*
+ fork on steroids to avoid SIGCHLD and waitpid
+
+ Copyright (C) Stefan Metzmacher 2010
+ Copyright (C) Ralph Boehme 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/tfork.h"
+#include "lib/util/debug.h"
+#include "lib/util/util_process.h"
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+#include <assert.h>
+
+/*
+ * This is how the process hierarchy looks like:
+ *
+ * +----------+
+ * | caller |
+ * +----------+
+ * |
+ * fork
+ * |
+ * v
+ * +----------+
+ * | waiter |
+ * +----------+
+ * |
+ * fork
+ * |
+ * v
+ * +----------+
+ * | worker |
+ * +----------+
+ */
+
+#ifdef HAVE_VALGRIND_HELGRIND_H
+#include <valgrind/helgrind.h>
+#endif
+#ifndef ANNOTATE_BENIGN_RACE_SIZED
+#define ANNOTATE_BENIGN_RACE_SIZED(obj, size, description)
+#endif
+
+#define TFORK_ANNOTATE_BENIGN_RACE(obj) \
+ ANNOTATE_BENIGN_RACE_SIZED( \
+ (obj), sizeof(*(obj)), \
+ "no race, serialized by tfork_[un]install_sigchld_handler");
+
+/*
+ * The resulting (private) state per tfork_create() call, returned as a opaque
+ * handle to the caller.
+ */
+struct tfork {
+ /*
+ * This is returned to the caller with tfork_event_fd()
+ */
+ int event_fd;
+
+ /*
+ * This is used in the caller by tfork_status() to read the worker exit
+ * status and to tell the waiter to exit by closing the fd.
+ */
+ int status_fd;
+
+ pid_t waiter_pid;
+ pid_t worker_pid;
+};
+
+/*
+ * Internal per-thread state maintained while inside tfork.
+ */
+struct tfork_state {
+ pid_t waiter_pid;
+ int waiter_errno;
+
+ pid_t worker_pid;
+};
+
+/*
+ * A global state that synchronizes access to handling SIGCHLD and waiting for
+ * children.
+ */
+struct tfork_signal_state {
+ bool available;
+
+#ifdef HAVE_PTHREAD
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+#endif
+
+ /*
+ * pid of the waiter child. This points at waiter_pid in either struct
+ * tfork or struct tfork_state, depending on who called
+ * tfork_install_sigchld_handler().
+ *
+ * When tfork_install_sigchld_handler() is called the waiter_pid is
+ * still -1 and only set later after fork(), that's why this is must be
+ * a pointer. The signal handler checks this.
+ */
+ pid_t *pid;
+
+ struct sigaction oldact;
+ sigset_t oldset;
+};
+
+static struct tfork_signal_state signal_state;
+
+#ifdef HAVE_PTHREAD
+static pthread_once_t tfork_global_is_initialized = PTHREAD_ONCE_INIT;
+static pthread_key_t tfork_global_key;
+#else
+static struct tfork_state *global_state;
+#endif
+
+static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p);
+
+#ifdef HAVE_PTHREAD
+static void tfork_global_destructor(void *state)
+{
+ anonymous_shared_free(state);
+}
+#endif
+
+static int tfork_acquire_sighandling(void)
+{
+ int ret = 0;
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_mutex_lock(&signal_state.mutex);
+ if (ret != 0) {
+ return ret;
+ }
+
+ while (!signal_state.available) {
+ ret = pthread_cond_wait(&signal_state.cond,
+ &signal_state.mutex);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ signal_state.available = false;
+
+ ret = pthread_mutex_unlock(&signal_state.mutex);
+ if (ret != 0) {
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+static int tfork_release_sighandling(void)
+{
+ int ret = 0;
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_mutex_lock(&signal_state.mutex);
+ if (ret != 0) {
+ return ret;
+ }
+
+ signal_state.available = true;
+
+ ret = pthread_cond_signal(&signal_state.cond);
+ if (ret != 0) {
+ pthread_mutex_unlock(&signal_state.mutex);
+ return ret;
+ }
+
+ ret = pthread_mutex_unlock(&signal_state.mutex);
+ if (ret != 0) {
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+#ifdef HAVE_PTHREAD
+static void tfork_atfork_prepare(void)
+{
+ int ret;
+
+ ret = pthread_mutex_lock(&signal_state.mutex);
+ assert(ret == 0);
+}
+
+static void tfork_atfork_parent(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&signal_state.mutex);
+ assert(ret == 0);
+}
+#endif
+
+static void tfork_atfork_child(void)
+{
+ int ret;
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_mutex_unlock(&signal_state.mutex);
+ assert(ret == 0);
+
+ ret = pthread_key_delete(tfork_global_key);
+ assert(ret == 0);
+
+ ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
+ assert(ret == 0);
+
+ /*
+ * There's no data race on the cond variable from the signal state, we
+ * are writing here, but there are no readers yet. Some data race
+ * detection tools report a race, but the readers are in the parent
+ * process.
+ */
+ TFORK_ANNOTATE_BENIGN_RACE(&signal_state.cond);
+
+ /*
+ * There's no way to destroy a condition variable if there are waiters,
+ * pthread_cond_destroy() will return EBUSY. Just zero out memory and
+ * then initialize again. This is not backed by POSIX but should be ok.
+ */
+ ZERO_STRUCT(signal_state.cond);
+ ret = pthread_cond_init(&signal_state.cond, NULL);
+ assert(ret == 0);
+#endif
+
+ if (signal_state.pid != NULL) {
+
+ ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
+ assert(ret == 0);
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_sigmask(SIG_SETMASK, &signal_state.oldset, NULL);
+#else
+ ret = sigprocmask(SIG_SETMASK, &signal_state.oldset, NULL);
+#endif
+ assert(ret == 0);
+
+ signal_state.pid = NULL;
+ }
+
+ signal_state.available = true;
+}
+
+static void tfork_global_initialize(void)
+{
+#ifdef HAVE_PTHREAD
+ int ret;
+
+ pthread_atfork(tfork_atfork_prepare,
+ tfork_atfork_parent,
+ tfork_atfork_child);
+
+ ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
+ assert(ret == 0);
+
+ ret = pthread_mutex_init(&signal_state.mutex, NULL);
+ assert(ret == 0);
+
+ ret = pthread_cond_init(&signal_state.cond, NULL);
+ assert(ret == 0);
+
+ /*
+ * In a threaded process there's no data race on t->waiter_pid as
+ * we're serializing globally via tfork_acquire_sighandling() and
+ * tfork_release_sighandling().
+ */
+ TFORK_ANNOTATE_BENIGN_RACE(&signal_state.pid);
+#endif
+
+ signal_state.available = true;
+}
+
+static struct tfork_state *tfork_global_get(void)
+{
+ struct tfork_state *state = NULL;
+#ifdef HAVE_PTHREAD
+ int ret;
+#endif
+
+#ifdef HAVE_PTHREAD
+ state = (struct tfork_state *)pthread_getspecific(tfork_global_key);
+#else
+ state = global_state;
+#endif
+ if (state != NULL) {
+ return state;
+ }
+
+ state = (struct tfork_state *)anonymous_shared_allocate(
+ sizeof(struct tfork_state));
+ if (state == NULL) {
+ return NULL;
+ }
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_setspecific(tfork_global_key, state);
+ if (ret != 0) {
+ anonymous_shared_free(state);
+ return NULL;
+ }
+#endif
+ return state;
+}
+
+static void tfork_global_free(void)
+{
+ struct tfork_state *state = NULL;
+#ifdef HAVE_PTHREAD
+ int ret;
+#endif
+
+#ifdef HAVE_PTHREAD
+ state = (struct tfork_state *)pthread_getspecific(tfork_global_key);
+#else
+ state = global_state;
+#endif
+ if (state == NULL) {
+ return;
+ }
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_setspecific(tfork_global_key, NULL);
+ if (ret != 0) {
+ return;
+ }
+#endif
+ anonymous_shared_free(state);
+}
+
+/**
+ * Only one thread at a time is allowed to handle SIGCHLD signals
+ **/
+static int tfork_install_sigchld_handler(pid_t *pid)
+{
+ int ret;
+ struct sigaction act;
+ sigset_t set;
+
+ ret = tfork_acquire_sighandling();
+ if (ret != 0) {
+ return -1;
+ }
+
+ assert(signal_state.pid == NULL);
+ signal_state.pid = pid;
+
+ act = (struct sigaction) {
+ .sa_sigaction = tfork_sigchld_handler,
+ .sa_flags = SA_SIGINFO,
+ };
+
+ ret = sigaction(SIGCHLD, &act, &signal_state.oldact);
+ if (ret != 0) {
+ return -1;
+ }
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+#ifdef HAVE_PTHREAD
+ ret = pthread_sigmask(SIG_UNBLOCK, &set, &signal_state.oldset);
+#else
+ ret = sigprocmask(SIG_UNBLOCK, &set, &signal_state.oldset);
+#endif
+ if (ret != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tfork_uninstall_sigchld_handler(void)
+{
+ int ret;
+
+ signal_state.pid = NULL;
+
+ ret = sigaction(SIGCHLD, &signal_state.oldact, NULL);
+ if (ret != 0) {
+ return -1;
+ }
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_sigmask(SIG_SETMASK, &signal_state.oldset, NULL);
+#else
+ ret = sigprocmask(SIG_SETMASK, &signal_state.oldset, NULL);
+#endif
+ if (ret != 0) {
+ return -1;
+ }
+
+ ret = tfork_release_sighandling();
+ if (ret != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void tfork_sigchld_handler(int signum, siginfo_t *si, void *p)
+{
+ if ((signal_state.pid != NULL) &&
+ (*signal_state.pid != -1) &&
+ (si->si_pid == *signal_state.pid))
+ {
+ return;
+ }
+
+ /*
+ * Not our child, forward to old handler
+ */
+ if (signal_state.oldact.sa_flags & SA_SIGINFO) {
+ signal_state.oldact.sa_sigaction(signum, si, p);
+ return;
+ }
+
+ if (signal_state.oldact.sa_handler == SIG_IGN) {
+ return;
+ }
+ if (signal_state.oldact.sa_handler == SIG_DFL) {
+ return;
+ }
+ signal_state.oldact.sa_handler(signum);
+}
+
+static pid_t tfork_start_waiter_and_worker(struct tfork_state *state,
+ int *_event_fd,
+ int *_status_fd)
+{
+ int p[2];
+ int status_sp_caller_fd = -1;
+ int status_sp_waiter_fd = -1;
+ int event_pipe_caller_fd = -1;
+ int event_pipe_waiter_fd = -1;
+ int ready_pipe_caller_fd = -1;
+ int ready_pipe_worker_fd = -1;
+ ssize_t nwritten;
+ ssize_t nread;
+ pid_t pid;
+ int status;
+ int fd;
+ char c;
+ int ret;
+
+ *_event_fd = -1;
+ *_status_fd = -1;
+
+ if (state == NULL) {
+ return -1;
+ }
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
+ if (ret != 0) {
+ return -1;
+ }
+ set_close_on_exec(p[0]);
+ set_close_on_exec(p[1]);
+ status_sp_caller_fd = p[0];
+ status_sp_waiter_fd = p[1];
+
+ ret = pipe(p);
+ if (ret != 0) {
+ close(status_sp_caller_fd);
+ close(status_sp_waiter_fd);
+ return -1;
+ }
+ set_close_on_exec(p[0]);
+ set_close_on_exec(p[1]);
+ event_pipe_caller_fd = p[0];
+ event_pipe_waiter_fd = p[1];
+
+
+ ret = pipe(p);
+ if (ret != 0) {
+ close(status_sp_caller_fd);
+ close(status_sp_waiter_fd);
+ close(event_pipe_caller_fd);
+ close(event_pipe_waiter_fd);
+ return -1;
+ }
+ set_close_on_exec(p[0]);
+ set_close_on_exec(p[1]);
+ ready_pipe_worker_fd = p[0];
+ ready_pipe_caller_fd = p[1];
+
+ pid = fork();
+ if (pid == -1) {
+ close(status_sp_caller_fd);
+ close(status_sp_waiter_fd);
+ close(event_pipe_caller_fd);
+ close(event_pipe_waiter_fd);
+ close(ready_pipe_caller_fd);
+ close(ready_pipe_worker_fd);
+ return -1;
+ }
+ if (pid != 0) {
+ /* The caller */
+
+ /*
+ * In a threaded process there's no data race on
+ * state->waiter_pid as we're serializing globally via
+ * tfork_acquire_sighandling() and tfork_release_sighandling().
+ */
+ TFORK_ANNOTATE_BENIGN_RACE(&state->waiter_pid);
+
+ state->waiter_pid = pid;
+
+ close(status_sp_waiter_fd);
+ close(event_pipe_waiter_fd);
+ close(ready_pipe_worker_fd);
+
+ set_blocking(event_pipe_caller_fd, false);
+
+ /*
+ * wait for the waiter to get ready.
+ */
+ nread = sys_read(status_sp_caller_fd, &c, sizeof(char));
+ if (nread != sizeof(char)) {
+ return -1;
+ }
+
+ /*
+ * Notify the worker to start.
+ */
+ nwritten = sys_write(ready_pipe_caller_fd,
+ &(char){0}, sizeof(char));
+ if (nwritten != sizeof(char)) {
+ close(ready_pipe_caller_fd);
+ return -1;
+ }
+ close(ready_pipe_caller_fd);
+
+ *_event_fd = event_pipe_caller_fd;
+ *_status_fd = status_sp_caller_fd;
+
+ return pid;
+ }
+
+#ifndef HAVE_PTHREAD
+ /* cleanup sigchld_handler */
+ tfork_atfork_child();
+#endif
+
+ /*
+ * The "waiter" child.
+ */
+ process_set_title("tfork waiter", "tfork waiter process");
+
+ CatchSignal(SIGCHLD, SIG_DFL);
+
+ close(status_sp_caller_fd);
+ close(event_pipe_caller_fd);
+ close(ready_pipe_caller_fd);
+
+ pid = fork();
+ if (pid == -1) {
+ state->waiter_errno = errno;
+ _exit(0);
+ }
+ if (pid == 0) {
+ /*
+ * The worker child.
+ */
+
+ close(status_sp_waiter_fd);
+ close(event_pipe_waiter_fd);
+
+ /*
+ * Wait for the caller to give us a go!
+ */
+ nread = sys_read(ready_pipe_worker_fd, &c, sizeof(char));
+ if (nread != sizeof(char)) {
+ _exit(1);
+ }
+ close(ready_pipe_worker_fd);
+
+ return 0;
+ }
+ state->worker_pid = pid;
+ process_set_title("tfork(%d)", "tfork waiter process(%d)", pid);
+
+ close(ready_pipe_worker_fd);
+
+ /*
+ * We're going to stay around until child2 exits, so lets close all fds
+ * other than the pipe fd we may have inherited from the caller.
+ *
+ * Dup event_sp_waiter_fd and status_sp_waiter_fd onto fds 0 and 1 so we
+ * can then call closefrom(2).
+ */
+ if (event_pipe_waiter_fd > 0) {
+ int dup_fd = 0;
+
+ if (status_sp_waiter_fd == 0) {
+ dup_fd = 1;
+ }
+
+ do {
+ fd = dup2(event_pipe_waiter_fd, dup_fd);
+ } while ((fd == -1) && (errno == EINTR));
+ if (fd == -1) {
+ state->waiter_errno = errno;
+ kill(state->worker_pid, SIGKILL);
+ state->worker_pid = -1;
+ _exit(1);
+ }
+ event_pipe_waiter_fd = fd;
+ }
+
+ if (status_sp_waiter_fd > 1) {
+ do {
+ fd = dup2(status_sp_waiter_fd, 1);
+ } while ((fd == -1) && (errno == EINTR));
+ if (fd == -1) {
+ state->waiter_errno = errno;
+ kill(state->worker_pid, SIGKILL);
+ state->worker_pid = -1;
+ _exit(1);
+ }
+ status_sp_waiter_fd = fd;
+ }
+
+ closefrom(2);
+
+ /* Tell the caller we're ready */
+ nwritten = sys_write(status_sp_waiter_fd, &(char){0}, sizeof(char));
+ if (nwritten != sizeof(char)) {
+ _exit(1);
+ }
+
+ tfork_global_free();
+ state = NULL;
+
+ do {
+ ret = waitpid(pid, &status, 0);
+ } while ((ret == -1) && (errno == EINTR));
+ if (ret == -1) {
+ status = errno;
+ kill(pid, SIGKILL);
+ }
+
+ /*
+ * This writes the worker child exit status via our internal socketpair
+ * so the tfork_status() implementation can read it from its end.
+ */
+ nwritten = sys_write(status_sp_waiter_fd, &status, sizeof(status));
+ if (nwritten == -1) {
+ if (errno != EPIPE && errno != ECONNRESET) {
+ _exit(errno);
+ }
+ /*
+ * The caller exited and didn't call tfork_status().
+ */
+ _exit(0);
+ }
+ if (nwritten != sizeof(status)) {
+ _exit(1);
+ }
+
+ /*
+ * This write to the event_fd returned by tfork_event_fd() and notifies
+ * the caller that the worker child is done and he may now call
+ * tfork_status().
+ */
+ nwritten = sys_write(event_pipe_waiter_fd, &(char){0}, sizeof(char));
+ if (nwritten != sizeof(char)) {
+ _exit(1);
+ }
+
+ /*
+ * Wait for our parent (the process that called tfork_create()) to
+ * close() the socketpair fd in tfork_status().
+ *
+ * Again, the caller might have exited without calling tfork_status().
+ */
+ nread = sys_read(status_sp_waiter_fd, &c, 1);
+ if (nread == -1) {
+ if (errno == EPIPE || errno == ECONNRESET) {
+ _exit(0);
+ }
+ _exit(errno);
+ }
+ if (nread != 1) {
+ _exit(255);
+ }
+
+ _exit(0);
+}
+
+static int tfork_create_reap_waiter(pid_t waiter_pid)
+{
+ pid_t pid;
+ int waiter_status;
+
+ if (waiter_pid == -1) {
+ return 0;
+ }
+
+ kill(waiter_pid, SIGKILL);
+
+ do {
+ pid = waitpid(waiter_pid, &waiter_status, 0);
+ } while ((pid == -1) && (errno == EINTR));
+ assert(pid == waiter_pid);
+
+ return 0;
+}
+
+struct tfork *tfork_create(void)
+{
+ struct tfork_state *state = NULL;
+ struct tfork *t = NULL;
+ pid_t pid;
+ int saved_errno = 0;
+ int ret = 0;
+ int ret2;
+
+#ifdef HAVE_PTHREAD
+ ret = pthread_once(&tfork_global_is_initialized,
+ tfork_global_initialize);
+ if (ret != 0) {
+ return NULL;
+ }
+#else
+ tfork_global_initialize();
+#endif
+
+ state = tfork_global_get();
+ if (state == NULL) {
+ return NULL;
+ }
+ *state = (struct tfork_state) {
+ .waiter_pid = -1,
+ .waiter_errno = ECANCELED,
+ .worker_pid = -1,
+ };
+
+ t = malloc(sizeof(struct tfork));
+ if (t == NULL) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ *t = (struct tfork) {
+ .event_fd = -1,
+ .status_fd = -1,
+ .waiter_pid = -1,
+ .worker_pid = -1,
+ };
+
+ ret = tfork_install_sigchld_handler(&state->waiter_pid);
+ if (ret != 0) {
+ goto cleanup;
+ }
+
+ pid = tfork_start_waiter_and_worker(state,
+ &t->event_fd,
+ &t->status_fd);
+ if (pid == -1) {
+ ret = -1;
+ goto cleanup;
+ }
+ if (pid == 0) {
+ /* In the worker */
+ tfork_global_free();
+ t->worker_pid = 0;
+ return t;
+ }
+
+ /*
+ * In a threaded process there's no data race on t->waiter_pid as
+ * we're serializing globally via tfork_acquire_sighandling() and
+ * tfork_release_sighandling().
+ */
+ TFORK_ANNOTATE_BENIGN_RACE(&t->waiter_pid);
+
+ t->waiter_pid = pid;
+ t->worker_pid = state->worker_pid;
+
+cleanup:
+ if (ret == -1) {
+ saved_errno = errno;
+
+ if (t != NULL) {
+ if (t->status_fd != -1) {
+ close(t->status_fd);
+ }
+ if (t->event_fd != -1) {
+ close(t->event_fd);
+ }
+
+ ret2 = tfork_create_reap_waiter(state->waiter_pid);
+ assert(ret2 == 0);
+
+ free(t);
+ t = NULL;
+ }
+ }
+
+ ret2 = tfork_uninstall_sigchld_handler();
+ assert(ret2 == 0);
+
+ tfork_global_free();
+
+ if (ret == -1) {
+ errno = saved_errno;
+ }
+ return t;
+}
+
+pid_t tfork_child_pid(const struct tfork *t)
+{
+ return t->worker_pid;
+}
+
+int tfork_event_fd(struct tfork *t)
+{
+ int fd = t->event_fd;
+
+ assert(t->event_fd != -1);
+ t->event_fd = -1;
+
+ return fd;
+}
+
+int tfork_status(struct tfork **_t, bool wait)
+{
+ struct tfork *t = *_t;
+ int status;
+ ssize_t nread;
+ int waiter_status;
+ pid_t pid;
+ int ret;
+
+ if (t == NULL) {
+ return -1;
+ }
+
+ if (wait) {
+ set_blocking(t->status_fd, true);
+
+ nread = sys_read(t->status_fd, &status, sizeof(int));
+ } else {
+ set_blocking(t->status_fd, false);
+
+ nread = read(t->status_fd, &status, sizeof(int));
+ if ((nread == -1) &&
+ ((errno == EAGAIN) || (errno == EWOULDBLOCK) || errno == EINTR)) {
+ errno = EAGAIN;
+ return -1;
+ }
+ }
+ if (nread != sizeof(int)) {
+ return -1;
+ }
+
+ ret = tfork_install_sigchld_handler(&t->waiter_pid);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /*
+ * This triggers process exit in the waiter.
+ * We write to the fd as well as closing it, as any tforked sibling
+ * processes will also have the writable end of this socket open.
+ *
+ */
+ {
+ size_t nwritten;
+ nwritten = sys_write(t->status_fd, &(char){0}, sizeof(char));
+ if (nwritten != sizeof(char)) {
+ close(t->status_fd);
+ return -1;
+ }
+ }
+ close(t->status_fd);
+
+ do {
+ pid = waitpid(t->waiter_pid, &waiter_status, 0);
+ } while ((pid == -1) && (errno == EINTR));
+ assert(pid == t->waiter_pid);
+
+ if (t->event_fd != -1) {
+ close(t->event_fd);
+ t->event_fd = -1;
+ }
+
+ free(t);
+ t = NULL;
+ *_t = NULL;
+
+ ret = tfork_uninstall_sigchld_handler();
+ assert(ret == 0);
+
+ return status;
+}
+
+int tfork_destroy(struct tfork **_t)
+{
+ struct tfork *t = *_t;
+ int ret;
+
+ if (t == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ kill(t->worker_pid, SIGKILL);
+
+ ret = tfork_status(_t, true);
+ if (ret == -1) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/lib/util/tfork.h b/lib/util/tfork.h
new file mode 100644
index 0000000..6c59caf
--- /dev/null
+++ b/lib/util/tfork.h
@@ -0,0 +1,111 @@
+/*
+ fork on steroids to avoid SIGCHLD and waitpid
+
+ Copyright (C) Stefan Metzmacher 2010
+ Copyright (C) Ralph Boehme 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef LIB_UTIL_TFORK_H
+#define LIB_UTIL_TFORK_H
+
+struct tfork;
+
+/**
+ * @brief a fork() that avoids SIGCHLD and waitpid
+ *
+ * This function is a solution to the problem of fork() requiring special
+ * preparations in the caller to handle SIGCHLD signals and to reap the child by
+ * wait()ing for it.
+ *
+ * The advantage over fork() is that the child process termination is signalled
+ * to the caller by making a pipe fd readable returned by tfork_event_fd(), in
+ * which case the exit status of the child can be fetched with tfork_status()
+ * without blocking.
+ *
+ * The child process will start with SIGCHLD handler set to SIG_DFL.
+ *
+ * @return On success, a struct tfork. NULL on failure.
+ * Use tfork_worker_pid() to get the pid of the created
+ * child and tfork_event_fd() to get the file descriptor
+ * that can be used to poll for process termination and
+ * reading the child process exit status.
+ *
+ * @note There's one thing this thing can't protect us against and that is if a
+ * process installs a SIGCHLD handler from one thread while another thread is
+ * running inside tfork_create() or tfork_status() and the signal handler
+ * doesn't forward signals for exited children it didn't fork, ie our children.
+ **/
+struct tfork *tfork_create(void);
+
+/**
+ * @brief Return the child pid from tfork_create()
+ *
+ * @param[in] t Pointer to struct tfork returned by tfork_create()
+ *
+ * @return In the caller this returns the pid of the child,
+ * in the child this returns 0.
+ **/
+pid_t tfork_child_pid(const struct tfork *t);
+
+/**
+ * @brief Return an event fd that signals child termination
+ *
+ * @param[in] t Pointer to struct tfork returned by tfork_create()
+ *
+ * It is the callers responsibility to ensure that the event fd returned by
+ * tfork_event_fd() is closed. By calling tfork_event_fd() ownership of the fd
+ * is transferred to the caller, calling tfork_event_fd() again will trigger an
+ * abort().
+ *
+ * @return An fd that becomes readable when the child created with
+ * tfork_create() terminates. It is guaranteed that a
+ * subsequent call to tfork_status() will not block and return
+ * the exit status of the child.
+ **/
+int tfork_event_fd(struct tfork *t);
+
+/**
+ * @brief Wait for the child to terminate and return its exit status
+ *
+ * @param[in] t Pointer-pointer to a struct tfork returned by
+ * tfork_create(). Upon successful completion t is freed and
+ * set to NULL.
+ *
+ * @param[in] wait Whether to wait for the child to change state. If wait is
+ * false, and the child hasn't changed state, tfork_status()
+ * will return -1 with errno set to EAGAIN. If wait is true,
+ * tfork_status() will block waiting for the child to change
+ * runstate.
+ *
+ * @return The exit status of the child, -1 on error.
+ *
+ * @note We overload the return value a bit, but a process exit status is pretty
+ * much guaranteed to be a 16-bit int and can't be -1.
+ **/
+int tfork_status(struct tfork **_t, bool wait);
+
+/**
+ * @brief Terminate the child discarding the exit status
+ *
+ * @param[in] t Pointer-pointer to a struct tfork returned by
+ * tfork_create(). Upon successful completion t is freed and
+ * set to NULL.
+ *
+ * @return 0 on success, -1 on error.
+ **/
+int tfork_destroy(struct tfork **_t);
+
+#endif /* LIB_UTIL_TFORK_H */
diff --git a/lib/util/tftw.c b/lib/util/tftw.c
new file mode 100644
index 0000000..c59bb6a
--- /dev/null
+++ b/lib/util/tftw.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2008-2018 by Andreas Schneider <asn@samba.org>
+ *
+ * Adopted from the csync source code
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include "lib/util/debug.h"
+
+#include "tftw.h"
+
+
+int tftw(TALLOC_CTX *mem_ctx, const char *fpath, tftw_walker_fn fn, size_t depth, void *userdata)
+{
+ char *filename = NULL;
+ char *d_name = NULL;
+ DIR *dh = NULL;
+ struct dirent *dirent = NULL;
+ struct stat sb = {0};
+ int rc = 0;
+
+ if (fpath[0] == '\0') {
+ errno = ENOENT;
+ goto error;
+ }
+
+ if ((dh = opendir(fpath)) == NULL) {
+ /* permission denied */
+ if (errno == EACCES) {
+ return 0;
+ } else {
+ DBG_ERR("opendir failed for: [%s]\n", strerror(errno));
+ goto error;
+ }
+ }
+
+ while ((dirent = readdir(dh))) {
+ int flag;
+
+ d_name = dirent->d_name;
+ if (d_name == NULL) {
+ goto error;
+ }
+
+ /* skip "." and ".." */
+ if (d_name[0] == '.' && (d_name[1] == '\0'
+ || (d_name[1] == '.' && d_name[2] == '\0'))) {
+ dirent = NULL;
+ continue;
+ }
+
+ filename = talloc_asprintf(mem_ctx, "%s/%s", fpath, d_name);
+ if (filename == NULL) {
+ goto error;
+ }
+
+ rc = lstat(filename, &sb);
+ if (rc < 0) {
+ dirent = NULL;
+ goto error;
+ }
+
+ switch (sb.st_mode & S_IFMT) {
+ case S_IFLNK:
+ flag = TFTW_FLAG_SLINK;
+ break;
+ case S_IFDIR:
+ flag = TFTW_FLAG_DIR;
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFSOCK:
+ case S_IFIFO:
+ flag = TFTW_FLAG_SPEC;
+ break;
+ default:
+ flag = TFTW_FLAG_FILE;
+ break;
+ }
+
+ DBG_INFO("walk: [%s]\n", filename);
+
+ /* Call walker function for each file */
+ rc = fn(mem_ctx, filename, &sb, flag, userdata);
+
+ if (rc < 0) {
+ DBG_ERR("provided callback fn() failed: [%s]\n",
+ strerror(errno));
+ closedir(dh);
+ goto done;
+ }
+
+ if (flag == TFTW_FLAG_DIR && depth) {
+ rc = tftw(mem_ctx, filename, fn, depth - 1, userdata);
+ if (rc < 0) {
+ closedir(dh);
+ goto done;
+ }
+ }
+ TALLOC_FREE(filename);
+ dirent = NULL;
+ }
+ closedir(dh);
+
+done:
+ TALLOC_FREE(filename);
+ return rc;
+error:
+ if (dh != NULL) {
+ closedir(dh);
+ }
+ TALLOC_FREE(filename);
+ return -1;
+}
diff --git a/lib/util/tftw.h b/lib/util/tftw.h
new file mode 100644
index 0000000..0d3d007
--- /dev/null
+++ b/lib/util/tftw.h
@@ -0,0 +1,32 @@
+#include <talloc.h>
+
+enum tftw_flags_e {
+ /* Regular file. */
+ TFTW_FLAG_FILE,
+ /* Directory. */
+ TFTW_FLAG_DIR,
+ /* Unreadable directory. */
+ TFTW_FLAG_DNR,
+ /* Unstatable file. */
+ TFTW_FLAG_NSTAT,
+ /* Symbolic link. */
+ TFTW_FLAG_SLINK,
+ /* Special file (fifo, ...). */
+ TFTW_FLAG_SPEC,
+
+ /* Directory, all subdirs have been visited. */
+ TFTW_FLAG_DP,
+ /* Symbolic link naming non-existing file. */
+ TFTW_FLAG_SLN
+};
+
+/* Maximum number of subdirectories to descend into */
+#define TFTW_MAX_DEPTH 50
+
+typedef int (*tftw_walker_fn)(TALLOC_CTX *mem_ctx,
+ const char *fpath,
+ const struct stat *sb,
+ enum tftw_flags_e flag,
+ void *userdata);
+
+int tftw(TALLOC_CTX *mem_ctx, const char *fpath, tftw_walker_fn fn, size_t depth, void *userdata);
diff --git a/lib/util/time.c b/lib/util/time.c
new file mode 100644
index 0000000..47ae320
--- /dev/null
+++ b/lib/util/time.c
@@ -0,0 +1,1494 @@
+/*
+ Unix SMB/CIFS implementation.
+ time handling functions
+
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/time.h"
+#include "byteorder.h"
+#include "time_basic.h"
+#include "lib/util/time.h" /* Avoid /usr/include/time.h */
+#include <sys/stat.h>
+#ifndef NO_CONFIG_H
+#include "config.h"
+#endif
+
+/**
+ * @file
+ * @brief time handling functions
+ */
+
+#define TIME_FIXUP_CONSTANT_INT INT64_C(11644473600)
+
+
+#define NSEC_PER_SEC 1000000000
+
+/**
+ External access to time_t_min and time_t_max.
+**/
+_PUBLIC_ time_t get_time_t_max(void)
+{
+ return TIME_T_MAX;
+}
+
+/**
+a wrapper to preferably get the monotonic time
+**/
+_PUBLIC_ void clock_gettime_mono(struct timespec *tp)
+{
+/* prefer a suspend aware monotonic CLOCK_BOOTTIME: */
+#ifdef CLOCK_BOOTTIME
+ if (clock_gettime(CLOCK_BOOTTIME,tp) == 0) {
+ return;
+ }
+#endif
+/* then try the monotonic clock: */
+#ifndef CUSTOM_CLOCK_MONOTONIC_IS_REALTIME
+ if (clock_gettime(CUSTOM_CLOCK_MONOTONIC,tp) == 0) {
+ return;
+ }
+#endif
+ clock_gettime(CLOCK_REALTIME,tp);
+}
+
+/**
+a wrapper to preferably get the monotonic time in seconds
+**/
+_PUBLIC_ time_t time_mono(time_t *t)
+{
+ struct timespec tp;
+
+ clock_gettime_mono(&tp);
+ if (t != NULL) {
+ *t = tp.tv_sec;
+ }
+ return tp.tv_sec;
+}
+
+
+#define TIME_FIXUP_CONSTANT 11644473600LL
+
+time_t convert_timespec_to_time_t(struct timespec ts)
+{
+ /* Ensure tv_nsec is less than 1sec. */
+ normalize_timespec(&ts);
+
+ /* 1 ns == 1,000,000,000 - one thousand millionths of a second.
+ increment if it's greater than 500 millionth of a second. */
+
+ if (ts.tv_nsec > 500000000) {
+ return ts.tv_sec + 1;
+ }
+ return ts.tv_sec;
+}
+
+struct timespec convert_time_t_to_timespec(time_t t)
+{
+ struct timespec ts;
+ ts.tv_sec = t;
+ ts.tv_nsec = 0;
+ return ts;
+}
+
+
+
+/**
+ Interpret an 8 byte "filetime" structure to a time_t
+ It's originally in "100ns units since jan 1st 1601"
+
+ An 8 byte value of 0xffffffffffffffff will be returned as a timespec of
+
+ tv_sec = 0
+ tv_nsec = 0;
+
+ Returns GMT.
+**/
+time_t nt_time_to_unix(NTTIME nt)
+{
+ return convert_timespec_to_time_t(nt_time_to_unix_timespec(nt));
+}
+
+
+/**
+put a 8 byte filetime from a time_t
+This takes GMT as input
+**/
+_PUBLIC_ void unix_to_nt_time(NTTIME *nt, time_t t)
+{
+ uint64_t t2;
+
+ if (t == (time_t)-1) {
+ *nt = UINT64_MAX;
+ return;
+ }
+
+ if (t == TIME_T_MAX || t == INT64_MAX) {
+ *nt = 0x7fffffffffffffffLL;
+ return;
+ }
+
+ if (t == 0) {
+ *nt = 0;
+ return;
+ }
+
+ t2 = t;
+ t2 += TIME_FIXUP_CONSTANT_INT;
+ t2 *= 1000*1000*10;
+
+ *nt = t2;
+}
+
+
+/**
+check if it's a null unix time
+**/
+_PUBLIC_ bool null_time(time_t t)
+{
+ return t == 0 ||
+ t == (time_t)0xFFFFFFFF ||
+ t == (time_t)-1;
+}
+
+
+/**
+check if it's a null NTTIME
+**/
+_PUBLIC_ bool null_nttime(NTTIME t)
+{
+ return t == 0;
+}
+
+/*******************************************************************
+ create a 16 bit dos packed date
+********************************************************************/
+static uint16_t make_dos_date1(struct tm *t)
+{
+ uint16_t ret=0;
+ ret = (((unsigned int)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
+ ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
+ return ret;
+}
+
+/*******************************************************************
+ create a 16 bit dos packed time
+********************************************************************/
+static uint16_t make_dos_time1(struct tm *t)
+{
+ uint16_t ret=0;
+ ret = ((((unsigned int)t->tm_min >> 3)&0x7) | (((unsigned int)t->tm_hour) << 3));
+ ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
+ return ret;
+}
+
+/*******************************************************************
+ create a 32 bit dos packed date/time from some parameters
+ This takes a GMT time and returns a packed localtime structure
+********************************************************************/
+static uint32_t make_dos_date(time_t unixdate, int zone_offset)
+{
+ struct tm *t;
+ uint32_t ret=0;
+
+ if (unixdate == 0) {
+ return 0;
+ }
+
+ unixdate -= zone_offset;
+
+ t = gmtime(&unixdate);
+ if (!t) {
+ return 0xFFFFFFFF;
+ }
+
+ ret = make_dos_date1(t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
+
+ return ret;
+}
+
+/**
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+**/
+_PUBLIC_ void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset)
+{
+ uint32_t x = make_dos_date(unixdate, zone_offset);
+ SIVAL(buf,offset,x);
+}
+
+/**
+put a dos date into a buffer (date/time format)
+This takes GMT time and puts local time in the buffer
+**/
+_PUBLIC_ void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
+{
+ uint32_t x;
+ x = make_dos_date(unixdate, zone_offset);
+ x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(buf,offset,x);
+}
+
+/**
+put a dos 32 bit "unix like" date into a buffer. This routine takes
+GMT and converts it to LOCAL time before putting it (most SMBs assume
+localtime for this sort of date)
+**/
+_PUBLIC_ void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
+{
+ if (!null_time(unixdate)) {
+ unixdate -= zone_offset;
+ }
+ SIVAL(buf,offset,unixdate);
+}
+
+/*******************************************************************
+ interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+ uint32_t p0,p1,p2,p3;
+
+ p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
+ p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
+
+ *second = 2*(p0 & 0x1F);
+ *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
+ *hour = (p1>>3)&0xFF;
+ *day = (p2&0x1F);
+ *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
+ *year = ((p3>>1)&0xFF) + 80;
+}
+
+/**
+ create a unix date (int GMT) from a dos date (which is actually in
+ localtime)
+**/
+_PUBLIC_ time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset)
+{
+ uint32_t dos_date=0;
+ struct tm t;
+ time_t ret;
+
+ dos_date = IVAL(date_ptr,0);
+
+ if (dos_date == 0) return (time_t)0;
+
+ interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
+ &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+ t.tm_isdst = -1;
+
+ ret = timegm(&t);
+
+ ret += zone_offset;
+
+ return ret;
+}
+
+/**
+like make_unix_date() but the words are reversed
+**/
+_PUBLIC_ time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset)
+{
+ uint32_t x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return pull_dos_date((const uint8_t *)&x, zone_offset);
+}
+
+/**
+ create a unix GMT date from a dos date in 32 bit "unix like" format
+ these generally arrive as localtimes, with corresponding DST
+**/
+_PUBLIC_ time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset)
+{
+ time_t t = (time_t)IVAL(date_ptr,0);
+
+ if (t == (time_t)0xFFFFFFFF) {
+ t = (time_t)-1;
+ }
+
+ if (!null_time(t)) {
+ t += zone_offset;
+ }
+ return t;
+}
+
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+char *timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires)
+{
+ struct timeval_buf tmp;
+ char *result;
+
+ result = talloc_strdup(ctx, timeval_str_buf(tp, false, hires, &tmp));
+ if (result == NULL) {
+ return NULL;
+ }
+
+ /*
+ * beautify the talloc_report output
+ *
+ * This is not just cosmetics. A C compiler might in theory make the
+ * talloc_strdup call above a tail call with the tail call
+ * optimization. This would render "tmp" invalid while talloc_strdup
+ * tries to duplicate it. The talloc_set_name_const call below puts
+ * the talloc_strdup call into non-tail position.
+ */
+ talloc_set_name_const(result, result);
+ return result;
+}
+
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+const char *timespec_string_buf(const struct timespec *tp,
+ bool hires,
+ struct timeval_buf *buf)
+{
+ time_t t;
+ struct tm *tm = NULL;
+ int len;
+
+ if (is_omit_timespec(tp)) {
+ strlcpy(buf->buf, "SAMBA_UTIME_OMIT", sizeof(buf->buf));
+ return buf->buf;
+ }
+
+ t = (time_t)tp->tv_sec;
+ tm = localtime(&t);
+
+ if (tm == NULL) {
+ if (hires) {
+ len = snprintf(buf->buf, sizeof(buf->buf),
+ "%ld.%09ld seconds since the Epoch",
+ (long)tp->tv_sec, (long)tp->tv_nsec);
+ } else {
+ len = snprintf(buf->buf, sizeof(buf->buf),
+ "%ld seconds since the Epoch", (long)t);
+ }
+ } else if (!hires) {
+ len = snprintf(buf->buf, sizeof(buf->buf),
+ "%04d-%02d-%02d %02d:%02d:%02d",
+ 1900 + tm->tm_year,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ } else {
+ len = snprintf(buf->buf, sizeof(buf->buf),
+ "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
+ 1900 + tm->tm_year,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ (long)tp->tv_nsec);
+ }
+ if (len == -1) {
+ return "";
+ }
+
+ return buf->buf;
+}
+
+char *current_timestring(TALLOC_CTX *ctx, bool hires)
+{
+ struct timeval tv;
+
+ GetTimeOfDay(&tv);
+ return timeval_string(ctx, &tv, hires);
+}
+
+/*
+ * Return date and time as a minimal string avoiding funny characters
+ * that may cause trouble in file names. We only use digits and
+ * underscore ... or a minus/hyphen if we got negative time.
+ */
+char *minimal_timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires)
+{
+ time_t t;
+ struct tm *tm;
+
+ t = (time_t)tp->tv_sec;
+ tm = localtime(&t);
+ if (!tm) {
+ if (hires) {
+ return talloc_asprintf(ctx, "%ld_%06ld",
+ (long)tp->tv_sec,
+ (long)tp->tv_usec);
+ } else {
+ return talloc_asprintf(ctx, "%ld", (long)t);
+ }
+ } else {
+ if (hires) {
+ return talloc_asprintf(ctx,
+ "%04d%02d%02d_%02d%02d%02d_%06ld",
+ tm->tm_year+1900,
+ tm->tm_mon+1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ (long)tp->tv_usec);
+ } else {
+ return talloc_asprintf(ctx,
+ "%04d%02d%02d_%02d%02d%02d",
+ tm->tm_year+1900,
+ tm->tm_mon+1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ }
+ }
+}
+
+char *current_minimal_timestring(TALLOC_CTX *ctx, bool hires)
+{
+ struct timeval tv;
+
+ GetTimeOfDay(&tv);
+ return minimal_timeval_string(ctx, &tv, hires);
+}
+
+/**
+return a HTTP/1.0 time string
+**/
+_PUBLIC_ char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
+{
+ char *buf;
+ char tempTime[60];
+ struct tm *tm = localtime(&t);
+
+ if (t == TIME_T_MAX) {
+ return talloc_strdup(mem_ctx, "never");
+ }
+
+ if (!tm) {
+ return talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
+ }
+
+#ifndef HAVE_STRFTIME
+ buf = talloc_strdup(mem_ctx, asctime(tm));
+ if (buf[strlen(buf)-1] == '\n') {
+ buf[strlen(buf)-1] = 0;
+ }
+#else
+ strftime(tempTime, sizeof(tempTime)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
+ buf = talloc_strdup(mem_ctx, tempTime);
+#endif /* !HAVE_STRFTIME */
+
+ return buf;
+}
+
+/**
+ Return the date and time as a string
+**/
+_PUBLIC_ char *timestring(TALLOC_CTX *mem_ctx, time_t t)
+{
+ char *TimeBuf;
+ char tempTime[80];
+ struct tm *tm;
+
+ tm = localtime(&t);
+ if (!tm) {
+ return talloc_asprintf(mem_ctx,
+ "%ld seconds since the Epoch",
+ (long)t);
+ }
+
+#ifdef HAVE_STRFTIME
+ /* Some versions of gcc complain about using some special format
+ * specifiers. This is a bug in gcc, not a bug in this code. See a
+ * recent strftime() manual page for details. */
+ strftime(tempTime,sizeof(tempTime)-1,"%a %b %e %X %Y %Z",tm);
+ TimeBuf = talloc_strdup(mem_ctx, tempTime);
+#else
+ TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
+ if (TimeBuf == NULL) {
+ return NULL;
+ }
+ if (TimeBuf[0] != '\0') {
+ size_t len = strlen(TimeBuf);
+ if (TimeBuf[len - 1] == '\n') {
+ TimeBuf[len - 1] = '\0';
+ }
+ }
+#endif
+
+ return TimeBuf;
+}
+
+/**
+ return a talloced string representing a NTTIME for human consumption
+*/
+_PUBLIC_ const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt)
+{
+ time_t t;
+ if (nt == 0) {
+ return "NTTIME(0)";
+ }
+ t = nt_time_to_full_time_t(nt);
+ return timestring(mem_ctx, t);
+}
+
+
+/**
+ put a NTTIME into a packet
+*/
+_PUBLIC_ void push_nttime(uint8_t *base, uint16_t offset, NTTIME t)
+{
+ SBVAL(base, offset, t);
+}
+
+/**
+ pull a NTTIME from a packet
+*/
+_PUBLIC_ NTTIME pull_nttime(uint8_t *base, uint16_t offset)
+{
+ NTTIME ret = BVAL(base, offset);
+ return ret;
+}
+
+/**
+ return (tv1 - tv2) in microseconds
+*/
+_PUBLIC_ int64_t usec_time_diff(const struct timeval *tv1, const struct timeval *tv2)
+{
+ int64_t sec_diff = tv1->tv_sec - tv2->tv_sec;
+ return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
+}
+
+/**
+ return (tp1 - tp2) in nanoseconds
+*/
+_PUBLIC_ int64_t nsec_time_diff(const struct timespec *tp1, const struct timespec *tp2)
+{
+ int64_t sec_diff = tp1->tv_sec - tp2->tv_sec;
+ return (sec_diff * 1000000000) + (int64_t)(tp1->tv_nsec - tp2->tv_nsec);
+}
+
+
+/**
+ return a zero timeval
+*/
+_PUBLIC_ struct timeval timeval_zero(void)
+{
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return tv;
+}
+
+/**
+ return true if a timeval is zero
+*/
+_PUBLIC_ bool timeval_is_zero(const struct timeval *tv)
+{
+ return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+/**
+ return a timeval for the current time
+*/
+_PUBLIC_ struct timeval timeval_current(void)
+{
+ struct timeval tv;
+ GetTimeOfDay(&tv);
+ return tv;
+}
+
+/**
+ return a timeval struct with the given elements
+*/
+_PUBLIC_ struct timeval timeval_set(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv;
+ tv.tv_sec = secs;
+ tv.tv_usec = usecs;
+ return tv;
+}
+
+
+/**
+ return a timeval ofs microseconds after tv
+*/
+_PUBLIC_ struct timeval timeval_add(const struct timeval *tv,
+ uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv2 = *tv;
+ const unsigned int million = 1000000;
+ tv2.tv_sec += secs;
+ tv2.tv_usec += usecs;
+ tv2.tv_sec += tv2.tv_usec / million;
+ tv2.tv_usec = tv2.tv_usec % million;
+ return tv2;
+}
+
+/**
+ return the sum of two timeval structures
+*/
+struct timeval timeval_sum(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
+}
+
+/**
+ return a timeval secs/usecs into the future
+*/
+_PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+ struct timeval tv = timeval_current();
+ return timeval_add(&tv, secs, usecs);
+}
+
+/**
+ return a timeval milliseconds into the future
+*/
+_PUBLIC_ struct timeval timeval_current_ofs_msec(uint32_t msecs)
+{
+ struct timeval tv = timeval_current();
+ return timeval_add(&tv, msecs / 1000, (msecs % 1000) * 1000);
+}
+
+/**
+ return a timeval microseconds into the future
+*/
+_PUBLIC_ struct timeval timeval_current_ofs_usec(uint32_t usecs)
+{
+ struct timeval tv = timeval_current();
+ return timeval_add(&tv, usecs / 1000000, usecs % 1000000);
+}
+
+/**
+ compare two timeval structures.
+ Return -1 if tv1 < tv2
+ Return 0 if tv1 == tv2
+ Return 1 if tv1 > tv2
+*/
+_PUBLIC_ int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return 1;
+ if (tv1->tv_sec < tv2->tv_sec) return -1;
+ if (tv1->tv_usec > tv2->tv_usec) return 1;
+ if (tv1->tv_usec < tv2->tv_usec) return -1;
+ return 0;
+}
+
+/**
+ return true if a timer is in the past
+*/
+_PUBLIC_ bool timeval_expired(const struct timeval *tv)
+{
+ struct timeval tv2 = timeval_current();
+ if (tv2.tv_sec > tv->tv_sec) return true;
+ if (tv2.tv_sec < tv->tv_sec) return false;
+ return (tv2.tv_usec >= tv->tv_usec);
+}
+
+/**
+ return the number of seconds elapsed between two times
+*/
+_PUBLIC_ double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2)
+{
+ return (tv2->tv_sec - tv1->tv_sec) +
+ (tv2->tv_usec - tv1->tv_usec)*1.0e-6;
+}
+
+/**
+ return the number of seconds elapsed since a given time
+*/
+_PUBLIC_ double timeval_elapsed(const struct timeval *tv)
+{
+ struct timeval tv2 = timeval_current();
+ return timeval_elapsed2(tv, &tv2);
+}
+/**
+ * return the number of seconds elapsed between two times
+ **/
+_PUBLIC_ double timespec_elapsed2(const struct timespec *ts1,
+ const struct timespec *ts2)
+{
+ return (ts2->tv_sec - ts1->tv_sec) +
+ (ts2->tv_nsec - ts1->tv_nsec)*1.0e-9;
+}
+
+/**
+ * return the number of seconds elapsed since a given time
+ */
+_PUBLIC_ double timespec_elapsed(const struct timespec *ts)
+{
+ struct timespec ts2 = timespec_current();
+ return timespec_elapsed2(ts, &ts2);
+}
+
+/**
+ return the lesser of two timevals
+*/
+_PUBLIC_ struct timeval timeval_min(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ if (tv1->tv_sec < tv2->tv_sec) return *tv1;
+ if (tv1->tv_sec > tv2->tv_sec) return *tv2;
+ if (tv1->tv_usec < tv2->tv_usec) return *tv1;
+ return *tv2;
+}
+
+/**
+ return the greater of two timevals
+*/
+_PUBLIC_ struct timeval timeval_max(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ if (tv1->tv_sec > tv2->tv_sec) return *tv1;
+ if (tv1->tv_sec < tv2->tv_sec) return *tv2;
+ if (tv1->tv_usec > tv2->tv_usec) return *tv1;
+ return *tv2;
+}
+
+/**
+ return the difference between two timevals as a timeval
+ if tv1 comes after tv2, then return a zero timeval
+ (this is *tv2 - *tv1)
+*/
+_PUBLIC_ struct timeval timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ struct timeval t;
+ if (timeval_compare(tv1, tv2) >= 0) {
+ return timeval_zero();
+ }
+ t.tv_sec = tv2->tv_sec - tv1->tv_sec;
+ if (tv1->tv_usec > tv2->tv_usec) {
+ t.tv_sec--;
+ t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
+ } else {
+ t.tv_usec = tv2->tv_usec - tv1->tv_usec;
+ }
+ return t;
+}
+
+
+/**
+ convert a timeval to a NTTIME
+*/
+_PUBLIC_ NTTIME timeval_to_nttime(const struct timeval *tv)
+{
+ return 10*(tv->tv_usec +
+ ((TIME_FIXUP_CONSTANT + (uint64_t)tv->tv_sec) * 1000000));
+}
+
+/**
+ convert a NTTIME to a timeval
+*/
+_PUBLIC_ void nttime_to_timeval(struct timeval *tv, NTTIME t)
+{
+ if (tv == NULL) return;
+
+ t += 10/2;
+ t /= 10;
+ t -= TIME_FIXUP_CONSTANT*1000*1000;
+
+ tv->tv_sec = t / 1000000;
+
+ if (TIME_T_MIN > tv->tv_sec || tv->tv_sec > TIME_T_MAX) {
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
+ return;
+ }
+
+ tv->tv_usec = t - tv->tv_sec*1000000;
+}
+
+/*******************************************************************
+yield the difference between *A and *B, in seconds, ignoring leap seconds
+********************************************************************/
+static int tm_diff(struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (1900 - 1);
+ int by = b->tm_year + (1900 - 1);
+ int intervening_leap_days =
+ (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
+ int years = ay - by;
+ int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
+ int hours = 24*days + (a->tm_hour - b->tm_hour);
+ int minutes = 60*hours + (a->tm_min - b->tm_min);
+ int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
+
+ return seconds;
+}
+
+
+/**
+ return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
+ */
+_PUBLIC_ int get_time_zone(time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ struct tm tm_utc;
+ if (!tm)
+ return 0;
+ tm_utc = *tm;
+ tm = localtime(&t);
+ if (!tm)
+ return 0;
+ return tm_diff(&tm_utc,tm);
+}
+
+/*
+ * Raw convert an NTTIME to a unix timespec.
+ */
+
+struct timespec nt_time_to_unix_timespec_raw(
+ NTTIME nt)
+{
+ int64_t d;
+ struct timespec ret;
+
+ d = (int64_t)nt;
+ /* d is now in 100ns units, since jan 1st 1601".
+ Save off the ns fraction. */
+
+ /*
+ * Take the last seven decimal digits and multiply by 100.
+ * to convert from 100ns units to 1ns units.
+ */
+ ret.tv_nsec = (long) ((d % (1000 * 1000 * 10)) * 100);
+
+ /* Convert to seconds */
+ d /= 1000*1000*10;
+
+ /* Now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT_INT;
+
+ ret.tv_sec = (time_t)d;
+ return ret;
+}
+
+struct timespec nt_time_to_unix_timespec(NTTIME nt)
+{
+ struct timespec ret;
+
+ if (nt == 0 || nt == UINT64_MAX) {
+ ret.tv_sec = 0;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ ret = nt_time_to_unix_timespec_raw(nt);
+
+ if (ret.tv_sec <= TIME_T_MIN) {
+ ret.tv_sec = TIME_T_MIN;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ if (ret.tv_sec >= TIME_T_MAX) {
+ ret.tv_sec = TIME_T_MAX;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+ return ret;
+}
+
+
+/**
+ check if 2 NTTIMEs are equal.
+*/
+bool nt_time_equal(NTTIME *t1, NTTIME *t2)
+{
+ return *t1 == *t2;
+}
+
+/**
+ Check if it's a null timespec.
+**/
+
+bool null_timespec(struct timespec ts)
+{
+ return ts.tv_sec == 0 ||
+ ts.tv_sec == (time_t)0xFFFFFFFF ||
+ ts.tv_sec == (time_t)-1;
+}
+
+/****************************************************************************
+ Convert a normalized timeval to a timespec.
+****************************************************************************/
+
+struct timespec convert_timeval_to_timespec(const struct timeval tv)
+{
+ struct timespec ts;
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return ts;
+}
+
+/****************************************************************************
+ Convert a normalized timespec to a timeval.
+****************************************************************************/
+
+struct timeval convert_timespec_to_timeval(const struct timespec ts)
+{
+ struct timeval tv;
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return tv;
+}
+
+/****************************************************************************
+ Return a timespec for the current time
+****************************************************************************/
+
+_PUBLIC_ struct timespec timespec_current(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return ts;
+}
+
+/****************************************************************************
+ Return the lesser of two timespecs.
+****************************************************************************/
+
+struct timespec timespec_min(const struct timespec *ts1,
+ const struct timespec *ts2)
+{
+ if (ts1->tv_sec < ts2->tv_sec) return *ts1;
+ if (ts1->tv_sec > ts2->tv_sec) return *ts2;
+ if (ts1->tv_nsec < ts2->tv_nsec) return *ts1;
+ return *ts2;
+}
+
+/****************************************************************************
+ compare two timespec structures.
+ Return -1 if ts1 < ts2
+ Return 0 if ts1 == ts2
+ Return 1 if ts1 > ts2
+****************************************************************************/
+
+_PUBLIC_ int timespec_compare(const struct timespec *ts1, const struct timespec *ts2)
+{
+ if (ts1->tv_sec > ts2->tv_sec) return 1;
+ if (ts1->tv_sec < ts2->tv_sec) return -1;
+ if (ts1->tv_nsec > ts2->tv_nsec) return 1;
+ if (ts1->tv_nsec < ts2->tv_nsec) return -1;
+ return 0;
+}
+
+/****************************************************************************
+ Round up a timespec if nsec > 500000000, round down if lower,
+ then zero nsec.
+****************************************************************************/
+
+void round_timespec_to_sec(struct timespec *ts)
+{
+ ts->tv_sec = convert_timespec_to_time_t(*ts);
+ ts->tv_nsec = 0;
+}
+
+/****************************************************************************
+ Round a timespec to usec value.
+****************************************************************************/
+
+void round_timespec_to_usec(struct timespec *ts)
+{
+ struct timeval tv = convert_timespec_to_timeval(*ts);
+ *ts = convert_timeval_to_timespec(tv);
+ normalize_timespec(ts);
+}
+
+/****************************************************************************
+ Round a timespec to NTTIME resolution.
+****************************************************************************/
+
+void round_timespec_to_nttime(struct timespec *ts)
+{
+ ts->tv_nsec = (ts->tv_nsec / 100) * 100;
+}
+
+/****************************************************************************
+ Put a 8 byte filetime from a struct timespec. Uses GMT.
+****************************************************************************/
+
+_PUBLIC_ NTTIME unix_timespec_to_nt_time(struct timespec ts)
+{
+ uint64_t d;
+
+ if (ts.tv_sec ==0 && ts.tv_nsec == 0) {
+ return 0;
+ }
+ if (ts.tv_sec == TIME_T_MAX) {
+ return 0x7fffffffffffffffLL;
+ }
+ if (ts.tv_sec == (time_t)-1) {
+ return UINT64_MAX;
+ }
+
+ d = ts.tv_sec;
+ d += TIME_FIXUP_CONSTANT_INT;
+ d *= 1000*1000*10;
+ /* d is now in 100ns units. */
+ d += (ts.tv_nsec / 100);
+
+ return d;
+}
+
+/*
+ * Functions supporting the full range of time_t and struct timespec values,
+ * including 0, -1 and all other negative values. These functions don't use 0 or
+ * -1 values as sentinel to denote "unset" variables, but use the POSIX 2008
+ * define UTIME_OMIT from utimensat(2).
+ */
+
+/**
+ * Check if it's a to be omitted timespec.
+ **/
+bool is_omit_timespec(const struct timespec *ts)
+{
+ return ts->tv_nsec == SAMBA_UTIME_OMIT;
+}
+
+/**
+ * Return a to be omitted timespec.
+ **/
+struct timespec make_omit_timespec(void)
+{
+ return (struct timespec){.tv_nsec = SAMBA_UTIME_OMIT};
+}
+
+/**
+ * Like unix_timespec_to_nt_time() but without the special casing of tv_sec=0
+ * and -1. Also dealing with SAMBA_UTIME_OMIT.
+ **/
+NTTIME full_timespec_to_nt_time(const struct timespec *_ts)
+{
+ struct timespec ts = *_ts;
+ uint64_t d;
+
+ if (is_omit_timespec(_ts)) {
+ return NTTIME_OMIT;
+ }
+
+ /* Ensure tv_nsec is less than 1 sec. */
+ while (ts.tv_nsec > 1000000000) {
+ if (ts.tv_sec > TIME_T_MAX) {
+ return NTTIME_MAX;
+ }
+ ts.tv_sec += 1;
+ ts.tv_nsec -= 1000000000;
+ }
+
+ if (ts.tv_sec >= TIME_T_MAX) {
+ return NTTIME_MAX;
+ }
+ if ((ts.tv_sec + TIME_FIXUP_CONSTANT_INT) <= 0) {
+ return NTTIME_MIN;
+ }
+
+ d = TIME_FIXUP_CONSTANT_INT;
+ d += ts.tv_sec;
+
+ d *= 1000*1000*10;
+ /* d is now in 100ns units. */
+ d += (ts.tv_nsec / 100);
+
+ return d;
+}
+
+/**
+ * Like nt_time_to_unix_timespec() but allowing negative tv_sec values and
+ * returning NTTIME=0 and -1 as struct timespec {.tv_nsec = SAMBA_UTIME_OMIT}.
+ *
+ * See also: is_omit_timespec().
+ **/
+struct timespec nt_time_to_full_timespec(NTTIME nt)
+{
+ struct timespec ret;
+
+ if (nt == NTTIME_OMIT) {
+ return make_omit_timespec();
+ }
+ if (nt == NTTIME_FREEZE || nt == NTTIME_THAW) {
+ /*
+ * This should be returned as SAMBA_UTIME_FREEZE or
+ * SAMBA_UTIME_THAW in the future.
+ */
+ return make_omit_timespec();
+ }
+ if (nt > NTTIME_MAX) {
+ nt = NTTIME_MAX;
+ }
+
+ ret = nt_time_to_unix_timespec_raw(nt);
+
+ if (ret.tv_sec >= TIME_T_MAX) {
+ ret.tv_sec = TIME_T_MAX;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * Note: this function uses the full time_t range as valid date values including
+ * (time_t)0 and -1. That means that struct timespec sentinel values (cf
+ * is_omit_timespec()) can't be converted to sentinel values in a time_t
+ * representation. Callers should therefore check the NTTIME value with
+ * null_nttime() before calling this function.
+ **/
+time_t full_timespec_to_time_t(const struct timespec *_ts)
+{
+ struct timespec ts = *_ts;
+
+ if (is_omit_timespec(_ts)) {
+ /*
+ * Unfortunately there's no sensible sentinel value in the
+ * time_t range that is not conflicting with a valid time value
+ * ((time_t)0 and -1 are valid time values). Bite the bullit and
+ * return 0.
+ */
+ return 0;
+ }
+
+ /* Ensure tv_nsec is less than 1sec. */
+ while (ts.tv_nsec > 1000000000) {
+ ts.tv_sec += 1;
+ ts.tv_nsec -= 1000000000;
+ }
+
+ /* 1 ns == 1,000,000,000 - one thousand millionths of a second.
+ increment if it's greater than 500 millionth of a second. */
+
+ if (ts.tv_nsec > 500000000) {
+ return ts.tv_sec + 1;
+ }
+ return ts.tv_sec;
+}
+
+/**
+ * Like nt_time_to_unix() but supports negative time_t values.
+ *
+ * Note: this function uses the full time_t range as valid date values including
+ * (time_t)0 and -1. That means that NTTIME sentinel values of 0 and -1 which
+ * represent a "not-set" value, can't be converted to sentinel values in a
+ * time_t representation. Callers should therefore check the NTTIME value with
+ * null_nttime() before calling this function.
+ **/
+time_t nt_time_to_full_time_t(NTTIME nt)
+{
+ struct timespec ts;
+
+ ts = nt_time_to_full_timespec(nt);
+ return full_timespec_to_time_t(&ts);
+}
+
+/**
+ * Like time_t_to_unix_timespec() but supports negative time_t values.
+ *
+ * This version converts (time_t)0 and -1 to an is_omit_timespec(), so 0 and -1
+ * can't be used as valid date values. The function supports values < -1 though.
+ **/
+struct timespec time_t_to_full_timespec(time_t t)
+{
+ if (null_time(t)) {
+ return (struct timespec){.tv_nsec = SAMBA_UTIME_OMIT};
+ }
+ return (struct timespec){.tv_sec = t};
+}
+
+#if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
+
+/* Old system - no ns timestamp. */
+time_t get_atimensec(const struct stat *st)
+{
+ return 0;
+}
+
+time_t get_mtimensec(const struct stat *st)
+{
+ return 0;
+}
+
+time_t get_ctimensec(const struct stat *st)
+{
+ return 0;
+}
+
+/* Set does nothing with no ns timestamp. */
+void set_atimensec(struct stat *st, time_t ns)
+{
+ return;
+}
+
+void set_mtimensec(struct stat *st, time_t ns)
+{
+ return;
+}
+
+void set_ctimensec(struct stat *st, time_t ns)
+{
+ return;
+}
+
+#elif HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
+
+time_t get_atimensec(const struct stat *st)
+{
+ return st->st_atimespec.tv_nsec;
+}
+
+time_t get_mtimensec(const struct stat *st)
+{
+ return st->st_mtimespec.tv_nsec;
+}
+
+time_t get_ctimensec(const struct stat *st)
+{
+ return st->st_ctimespec.tv_nsec;
+}
+
+void set_atimensec(struct stat *st, time_t ns)
+{
+ st->st_atimespec.tv_nsec = ns;
+}
+
+void set_mtimensec(struct stat *st, time_t ns)
+{
+ st->st_mtimespec.tv_nsec = ns;
+}
+
+void set_ctimensec(struct stat *st, time_t ns)
+{
+ st->st_ctimespec.tv_nsec = ns;
+}
+
+#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+
+time_t get_atimensec(const struct stat *st)
+{
+ return st->st_atim.tv_nsec;
+}
+
+time_t get_mtimensec(const struct stat *st)
+{
+ return st->st_mtim.tv_nsec;
+}
+
+time_t get_ctimensec(const struct stat *st)
+{
+ return st->st_ctim.tv_nsec;
+}
+
+void set_atimensec(struct stat *st, time_t ns)
+{
+ st->st_atim.tv_nsec = ns;
+}
+
+void set_mtimensec(struct stat *st, time_t ns)
+{
+ st->st_mtim.tv_nsec = ns;
+}
+void set_ctimensec(struct stat *st, time_t ns)
+{
+ st->st_ctim.tv_nsec = ns;
+}
+
+#elif HAVE_STRUCT_STAT_ST_MTIMENSEC
+
+time_t get_atimensec(const struct stat *st)
+{
+ return st->st_atimensec;
+}
+
+time_t get_mtimensec(const struct stat *st)
+{
+ return st->st_mtimensec;
+}
+
+time_t get_ctimensec(const struct stat *st)
+{
+ return st->st_ctimensec;
+}
+
+void set_atimensec(struct stat *st, time_t ns)
+{
+ st->st_atimensec = ns;
+}
+
+void set_mtimensec(struct stat *st, time_t ns)
+{
+ st->st_mtimensec = ns;
+}
+
+void set_ctimensec(struct stat *st, time_t ns)
+{
+ st->st_ctimensec = ns;
+}
+
+#elif HAVE_STRUCT_STAT_ST_MTIME_N
+
+time_t get_atimensec(const struct stat *st)
+{
+ return st->st_atime_n;
+}
+
+time_t get_mtimensec(const struct stat *st)
+{
+ return st->st_mtime_n;
+}
+
+time_t get_ctimensec(const struct stat *st)
+{
+ return st->st_ctime_n;
+}
+
+void set_atimensec(struct stat *st, time_t ns)
+{
+ st->st_atime_n = ns;
+}
+
+void set_mtimensec(struct stat *st, time_t ns)
+{
+ st->st_mtime_n = ns;
+}
+
+void set_ctimensec(struct stat *st, time_t ns)
+{
+ st->st_ctime_n = ns;
+}
+
+#elif HAVE_STRUCT_STAT_ST_UMTIME
+
+/* Only usec timestamps available. Convert to/from nsec. */
+
+time_t get_atimensec(const struct stat *st)
+{
+ return st->st_uatime * 1000;
+}
+
+time_t get_mtimensec(const struct stat *st)
+{
+ return st->st_umtime * 1000;
+}
+
+time_t get_ctimensec(const struct stat *st)
+{
+ return st->st_uctime * 1000;
+}
+
+void set_atimensec(struct stat *st, time_t ns)
+{
+ st->st_uatime = ns / 1000;
+}
+
+void set_mtimensec(struct stat *st, time_t ns)
+{
+ st->st_umtime = ns / 1000;
+}
+
+void set_ctimensec(struct stat *st, time_t ns)
+{
+ st->st_uctime = ns / 1000;
+}
+
+#else
+#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
+#endif
+
+struct timespec get_atimespec(const struct stat *pst)
+{
+ struct timespec ret;
+
+ ret.tv_sec = pst->st_atime;
+ ret.tv_nsec = get_atimensec(pst);
+ return ret;
+}
+
+struct timespec get_mtimespec(const struct stat *pst)
+{
+ struct timespec ret;
+
+ ret.tv_sec = pst->st_mtime;
+ ret.tv_nsec = get_mtimensec(pst);
+ return ret;
+}
+
+struct timespec get_ctimespec(const struct stat *pst)
+{
+ struct timespec ret;
+
+ ret.tv_sec = pst->st_ctime;
+ ret.tv_nsec = get_ctimensec(pst);
+ return ret;
+}
+
+/****************************************************************************
+ Deal with nanoseconds overflow.
+****************************************************************************/
+
+void normalize_timespec(struct timespec *ts)
+{
+ lldiv_t dres;
+
+ /* most likely case: nsec is valid */
+ if ((unsigned long)ts->tv_nsec < NSEC_PER_SEC) {
+ return;
+ }
+
+ dres = lldiv(ts->tv_nsec, NSEC_PER_SEC);
+
+ /* if the operation would result in overflow, max out values and bail */
+ if (dres.quot > 0) {
+ if ((int64_t)LONG_MAX - dres.quot < ts->tv_sec) {
+ ts->tv_sec = LONG_MAX;
+ ts->tv_nsec = NSEC_PER_SEC - 1;
+ return;
+ }
+ } else {
+ if ((int64_t)LONG_MIN - dres.quot > ts->tv_sec) {
+ ts->tv_sec = LONG_MIN;
+ ts->tv_nsec = 0;
+ return;
+ }
+ }
+
+ ts->tv_nsec = dres.rem;
+ ts->tv_sec += dres.quot;
+
+ /* if the ns part was positive or a multiple of -1000000000, we're done */
+ if (ts->tv_nsec > 0 || dres.rem == 0) {
+ return;
+ }
+
+ ts->tv_nsec += NSEC_PER_SEC;
+ --ts->tv_sec;
+}
diff --git a/lib/util/time.h b/lib/util/time.h
new file mode 100644
index 0000000..4870c84
--- /dev/null
+++ b/lib/util/time.h
@@ -0,0 +1,404 @@
+/*
+ Unix SMB/CIFS implementation.
+ time utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Andrew Bartlett 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_TIME_H_
+#define _SAMBA_TIME_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <talloc.h>
+#include <time.h>
+
+#ifndef TIME_T_MIN
+/* we use 0 here, because (time_t)-1 means error */
+#define TIME_T_MIN 0
+#endif
+
+/*
+ * we use the INT32_MAX here as on 64 bit systems,
+ * gmtime() fails with INT64_MAX
+ */
+#ifndef TIME_T_MAX
+#define TIME_T_MAX MIN(INT32_MAX,_TYPE_MAXIMUM(time_t))
+#endif
+
+/*
+ * According to Windows API FileTimeToSystemTime() documentation the highest
+ * allowed value " ... must be less than 0x8000000000000000.".
+ */
+#define NTTIME_MAX INT64_MAX
+
+/*
+ * The lowest possible value when NTTIME=0 is used as sentinel value.
+ */
+#define NTTIME_MIN 1
+
+/*
+ * NTTIME_OMIT in a setinfo tells us to not modify the corresponding on-disk
+ * timestamp value.
+ */
+#define NTTIME_OMIT 0
+
+/*
+ * Disable automatic timestamp updates, as described in MS-FSA. Samba doesn't
+ * implement this yet.
+ */
+#define NTTIME_FREEZE UINT64_MAX
+#define NTTIME_THAW (UINT64_MAX - 1)
+
+#define SAMBA_UTIME_NOW UTIME_NOW
+#define SAMBA_UTIME_OMIT UTIME_OMIT
+
+/* 64 bit time (100 nanosec) 1601 - cifs6.txt, section 3.5, page 30, 4 byte aligned */
+typedef uint64_t NTTIME;
+
+#define NTTIME_USEC (10UL)
+#define NTTIME_MSEC (1000UL * NTTIME_USEC)
+
+/**
+ External access to time_t_min and time_t_max.
+**/
+time_t get_time_t_max(void);
+
+/**
+a gettimeofday wrapper
+**/
+void GetTimeOfDay(struct timeval *tval);
+
+/**
+a wrapper to preferably get the monotonic time
+**/
+void clock_gettime_mono(struct timespec *tp);
+
+/**
+a wrapper to preferably get the monotonic time in s
+**/
+time_t time_mono(time_t *t);
+
+/**
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+**/
+time_t nt_time_to_unix(NTTIME nt);
+
+/**
+put a 8 byte filetime from a time_t
+This takes GMT as input
+**/
+void unix_to_nt_time(NTTIME *nt, time_t t);
+
+/**
+check if it's a null unix time
+**/
+bool null_time(time_t t);
+
+/**
+check if it's a null NTTIME
+**/
+bool null_nttime(NTTIME t);
+
+/**
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+**/
+void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset);
+
+/**
+put a dos date into a buffer (date/time format)
+This takes GMT time and puts local time in the buffer
+**/
+void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset);
+
+/**
+put a dos 32 bit "unix like" date into a buffer. This routine takes
+GMT and converts it to LOCAL time before putting it (most SMBs assume
+localtime for this sort of date)
+**/
+void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset);
+
+/**
+ create a unix date (int GMT) from a dos date (which is actually in
+ localtime)
+**/
+time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset);
+
+/**
+like make_unix_date() but the words are reversed
+**/
+time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset);
+
+/**
+ create a unix GMT date from a dos date in 32 bit "unix like" format
+ these generally arrive as localtimes, with corresponding DST
+**/
+time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset);
+
+/**
+ Return a date and time as a string (optionally with microseconds)
+
+ format is %Y/%m/%d %H:%M:%S if strftime is available
+**/
+
+char *timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires);
+
+struct timeval_buf;
+const char *timespec_string_buf(const struct timespec *tp,
+ bool hires,
+ struct timeval_buf *buf);
+
+/**
+ Return the current date and time as a string (optionally with microseconds)
+
+ format is %Y/%m/%d %H:%M:%S if strftime is available
+**/
+char *current_timestring(TALLOC_CTX *ctx, bool hires);
+
+/**
+ Return a date and time as a string (optionally with microseconds)
+
+ format is %Y%m%d_%H%M%S or %Y%m%d_%H%M%S_%us
+**/
+
+char *minimal_timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires);
+
+/**
+ Return the current date and time as a string (optionally with microseconds)
+
+ format is %Y%m%d_%H%M%S or %Y%m%d_%H%M%S_%us
+**/
+char *current_minimal_timestring(TALLOC_CTX *ctx, bool hires);
+
+/**
+return a HTTP/1.0 time string
+**/
+char *http_timestring(TALLOC_CTX *mem_ctx, time_t t);
+
+/**
+ Return the date and time as a string
+
+ format is %a %b %e %X %Y %Z
+**/
+char *timestring(TALLOC_CTX *mem_ctx, time_t t);
+
+/**
+ return a talloced string representing a NTTIME for human consumption
+*/
+const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt);
+
+/**
+ put a NTTIME into a packet
+*/
+void push_nttime(uint8_t *base, uint16_t offset, NTTIME t);
+
+/**
+ pull a NTTIME from a packet
+*/
+NTTIME pull_nttime(uint8_t *base, uint16_t offset);
+
+/**
+ return (tv1 - tv2) in microseconds
+*/
+int64_t usec_time_diff(const struct timeval *tv1, const struct timeval *tv2);
+
+/**
+ return (tp1 - tp2) in nanoseconds
+*/
+int64_t nsec_time_diff(const struct timespec *tp1, const struct timespec *tp2);
+
+/**
+ return a zero timeval
+*/
+struct timeval timeval_zero(void);
+
+/**
+ return true if a timeval is zero
+*/
+bool timeval_is_zero(const struct timeval *tv);
+
+/**
+ return a timeval for the current time
+*/
+struct timeval timeval_current(void);
+
+/**
+ return a timeval struct with the given elements
+*/
+struct timeval timeval_set(uint32_t secs, uint32_t usecs);
+
+/**
+ return a timeval ofs microseconds after tv
+*/
+struct timeval timeval_add(const struct timeval *tv,
+ uint32_t secs, uint32_t usecs);
+
+/**
+ return the sum of two timeval structures
+*/
+struct timeval timeval_sum(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+/**
+ return a timeval secs/usecs into the future
+*/
+struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs);
+
+/**
+ return a timeval milliseconds into the future
+*/
+struct timeval timeval_current_ofs_msec(uint32_t msecs);
+
+/**
+ return a timeval microseconds into the future
+*/
+struct timeval timeval_current_ofs_usec(uint32_t usecs);
+
+/**
+ compare two timeval structures.
+ Return -1 if tv1 < tv2
+ Return 0 if tv1 == tv2
+ Return 1 if tv1 > tv2
+*/
+int timeval_compare(const struct timeval *tv1, const struct timeval *tv2);
+
+/**
+ return true if a timer is in the past
+*/
+bool timeval_expired(const struct timeval *tv);
+
+/**
+ return the number of seconds elapsed between two times
+*/
+double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2);
+
+/**
+ return the number of seconds elapsed since a given time
+*/
+double timeval_elapsed(const struct timeval *tv);
+
+/**
+ return the number of seconds elapsed between two times
+*/
+double timespec_elapsed2(const struct timespec *ts1,
+ const struct timespec *ts2);
+/**
+ return the number of seconds elapsed since a given time
+*/
+double timespec_elapsed(const struct timespec *ts);
+
+/**
+ return the lesser of two timevals
+*/
+struct timeval timeval_min(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+/**
+ return the greater of two timevals
+*/
+struct timeval timeval_max(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+/**
+ return the difference between two timevals as a timeval
+ if tv1 comes after tv2, then return a zero timeval
+ (this is *tv2 - *tv1)
+*/
+struct timeval timeval_until(const struct timeval *tv1,
+ const struct timeval *tv2);
+
+/**
+ convert a timeval to a NTTIME
+*/
+NTTIME timeval_to_nttime(const struct timeval *tv);
+
+/**
+ convert a NTTIME to a timeval
+*/
+void nttime_to_timeval(struct timeval *tv, NTTIME t);
+
+/**
+ return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
+ */
+int get_time_zone(time_t t);
+
+/**
+ check if 2 NTTIMEs are equal.
+*/
+bool nt_time_equal(NTTIME *t1, NTTIME *t2);
+
+void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second);
+
+struct timespec nt_time_to_unix_timespec_raw(NTTIME nt);
+
+struct timespec nt_time_to_unix_timespec(NTTIME nt);
+
+time_t convert_timespec_to_time_t(struct timespec ts);
+
+struct timespec convert_time_t_to_timespec(time_t t);
+
+bool null_timespec(struct timespec ts);
+
+struct timespec convert_timeval_to_timespec(const struct timeval tv);
+struct timeval convert_timespec_to_timeval(const struct timespec ts);
+struct timespec timespec_current(void);
+struct timespec timespec_min(const struct timespec *ts1,
+ const struct timespec *ts2);
+int timespec_compare(const struct timespec *ts1, const struct timespec *ts2);
+void round_timespec_to_sec(struct timespec *ts);
+void round_timespec_to_usec(struct timespec *ts);
+void round_timespec_to_nttime(struct timespec *ts);
+NTTIME unix_timespec_to_nt_time(struct timespec ts);
+void normalize_timespec(struct timespec *ts);
+
+/*
+ * Functions supporting the full range of time_t and struct timespec values,
+ * including 0, -1 and all other negative values. These functions don't use 0 or
+ * -1 values as sentinel to denote "unset" variables, but use the POSIX 2008
+ * define UTIME_OMIT from utimensat(2).
+ */
+bool is_omit_timespec(const struct timespec *ts);
+struct timespec make_omit_timespec(void);
+NTTIME full_timespec_to_nt_time(const struct timespec *ts);
+struct timespec nt_time_to_full_timespec(NTTIME nt);
+time_t full_timespec_to_time_t(const struct timespec *ts);
+time_t nt_time_to_full_time_t(NTTIME nt);
+struct timespec time_t_to_full_timespec(time_t t);
+
+/*
+ * Functions to get and set the number of nanoseconds for times in a stat field.
+ * If the stat has timestamp granularity less than nanosecond, then the set_*
+ * operations will be lossy.
+ */
+struct stat;
+time_t get_atimensec(const struct stat *);
+time_t get_mtimensec(const struct stat *);
+time_t get_ctimensec(const struct stat *);
+void set_atimensec(struct stat *, time_t);
+void set_mtimensec(struct stat *, time_t);
+void set_ctimensec(struct stat *, time_t);
+
+/* These are convenience wrappers for the above getters. */
+struct timespec get_atimespec(const struct stat *);
+struct timespec get_mtimespec(const struct stat *);
+struct timespec get_ctimespec(const struct stat *);
+
+#endif /* _SAMBA_TIME_H_ */
diff --git a/lib/util/time_basic.c b/lib/util/time_basic.c
new file mode 100644
index 0000000..095236b
--- /dev/null
+++ b/lib/util/time_basic.c
@@ -0,0 +1,99 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * time handling functions
+ *
+ * Copyright (C) Andrew Tridgell 1992-2004
+ * Copyright (C) Stefan (metze) Metzmacher 2002
+ * Copyright (C) Jeremy Allison 2007
+ * Copyright (C) Andrew Bartlett 2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/time.h"
+#include "lib/util/time_basic.h"
+
+/**
+a gettimeofday wrapper
+**/
+_PUBLIC_ void GetTimeOfDay(struct timeval *tval)
+{
+#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
+ gettimeofday(tval,NULL);
+#else
+ gettimeofday(tval);
+#endif
+}
+
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+char *timeval_str_buf(const struct timeval *tp, bool rfc5424, bool hires,
+ struct timeval_buf *dst)
+{
+ time_t t;
+ struct tm *tm;
+ size_t len;
+
+ t = (time_t)tp->tv_sec;
+ tm = localtime(&t);
+
+ if (tm == NULL) {
+ if (hires) {
+ snprintf(dst->buf, sizeof(dst->buf),
+ "%ld.%06ld seconds since the Epoch",
+ (long)tp->tv_sec, (long)tp->tv_usec);
+ } else {
+ snprintf(dst->buf, sizeof(dst->buf),
+ "%ld seconds since the Epoch", (long)t);
+ }
+ return dst->buf;
+ }
+
+ len = snprintf(dst->buf, sizeof(dst->buf),
+ (rfc5424 ?
+ "%04d-%02d-%02dT%02d:%02d:%02d" :
+ "%04d/%02d/%02d %02d:%02d:%02d"),
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if ((rfc5424 || hires) && (len < sizeof(dst->buf))) {
+ len += snprintf(dst->buf + len, sizeof(dst->buf) - len,
+ ".%06ld", (long)tp->tv_usec);
+ }
+
+ if (rfc5424 && (len < sizeof(dst->buf))) {
+ struct tm tm_utc, tm_local;
+ int offset;
+
+ tm_local = *tm;
+ /* It is reasonable to assume that if localtime()
+ * worked above, then gmtime() should also work
+ * without error. */
+ tm_utc = *gmtime(&t);
+
+ offset = (tm_local.tm_hour - tm_utc.tm_hour) * 60 +
+ (tm_local.tm_min - tm_utc.tm_min);
+
+ snprintf(dst->buf + len, sizeof(dst->buf) - len,
+ "%c%02d:%02d",
+ (offset >=0 ? '+' : '-'),
+ abs(offset) / 60,
+ abs(offset) % 60);
+ }
+
+ return dst->buf;
+}
diff --git a/lib/util/time_basic.h b/lib/util/time_basic.h
new file mode 100644
index 0000000..e04cf1c
--- /dev/null
+++ b/lib/util/time_basic.h
@@ -0,0 +1,49 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * time handling functions
+ *
+ * Copyright (C) Andrew Tridgell 1992-2004
+ * Copyright (C) Stefan (metze) Metzmacher 2002
+ * Copyright (C) Jeremy Allison 2007
+ * Copyright (C) Andrew Bartlett 2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SAMBA_TIME_BASIC_H_
+#define _SAMBA_TIME_BASIC_H_
+
+struct timeval;
+
+/**
+a gettimeofday wrapper
+**/
+_PUBLIC_ void GetTimeOfDay(struct timeval *tval);
+
+struct timeval_buf { char buf[128]; };
+
+/**
+ Put a date and time into dst->buf, return it dst->buf
+ (optionally with microseconds)
+
+ If rfc5424 is true then produce the RFC5424 timestamp format (which
+ is a stricter instance of RFC3339 and is used for syslog). For
+ example: 2003-08-24T05:14:15.000003-07:00. Otherwise,
+ format is %Y/%m/%d %H:%M:%S
+**/
+
+char *timeval_str_buf(const struct timeval *tp, bool rfc5424, bool hires,
+ struct timeval_buf *dst);
+
+#endif /* _SAMBA_TIME_BASIC_H_ */
diff --git a/lib/util/tini.c b/lib/util/tini.c
new file mode 100644
index 0000000..36d7a45
--- /dev/null
+++ b/lib/util/tini.c
@@ -0,0 +1,320 @@
+/*
+ * Trivial smb.conf parsing code
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2014
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License Version 3 or later, in which case the
+ * provisions of the GPL are required INSTEAD OF the above restrictions.
+ * (This clause is necessary due to a potential bad interaction between the
+ * GPL and the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS 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 AUTHOR 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "tini.h"
+
+static bool c_isspace(char c)
+{
+ unsigned char uc = c;
+ if (c != uc) {
+ return false;
+ }
+ return isspace(uc);
+}
+
+static int next_content(FILE *f)
+{
+ int c;
+
+ for (c = fgetc(f); c != EOF; c = fgetc(f)) {
+ if (!c_isspace(c)) {
+ break;
+ }
+ if (c == '\n') {
+ break;
+ }
+ }
+
+ return c;
+}
+
+static int next_end_of_line(FILE *f)
+{
+ int c;
+
+ for (c = fgetc(f); c != EOF; c = fgetc(f)) {
+ if (c == '\n') {
+ break;
+ }
+ }
+ return c;
+}
+
+static bool make_space(char **buf, size_t *buflen, size_t position)
+{
+ char *tmp;
+
+ if (position < *buflen) {
+ return true;
+ }
+ tmp = realloc(*buf, (*buflen) * 2);
+ if (tmp == NULL) {
+ return false;
+ }
+ *buf = tmp;
+ *buflen *= 2;
+ return true;
+}
+
+/*
+ * Get a conf line into *pbuf (which must be a malloc'ed buffer already).
+ *
+ * Ignores leading spaces
+ * Ignores comment lines
+ * Ignores empty lines
+ * Takes care of continuation lines
+ * Zaps multiple spaces into one
+ */
+
+static int get_line(FILE *f, char **pbuf, size_t *pbuflen)
+{
+ int c;
+ char *buf;
+ size_t buflen, pos;
+
+ buf = *pbuf;
+ buflen = *pbuflen;
+ pos = 0;
+
+next_line:
+
+ c = next_content(f);
+ if (c == EOF) {
+ return ENOENT;
+ }
+
+ if ((c == '#') || (c == ';')) {
+ /*
+ * Line starting with a comment, skip
+ */
+ c = next_end_of_line(f);
+ if (c == EOF) {
+ return ENOENT;
+ }
+ goto next_line;
+ }
+
+ if (c == '\n') {
+ /*
+ * Blank line, skip
+ */
+ goto next_line;
+ }
+
+ for ( ; c != EOF ; c = fgetc(f)) {
+
+ if (c == '\n') {
+
+ if ((pos > 0) && (buf[pos-1] == '\\')) {
+ /*
+ * Line ends in "\". Continuation.
+ */
+ pos -= 1;
+ continue;
+ }
+
+ if ((pos > 1) && (buf[pos-2] == '\\') &&
+ c_isspace(buf[pos-1])) {
+ /*
+ * Line ends in "\ ". Mind that we zap
+ * multiple spaces into one. Continuation.
+ */
+ pos -= 2;
+ continue;
+ }
+
+ /*
+ * No continuation, done with the line
+ */
+ break;
+ }
+
+ if ((pos > 0) && c_isspace(buf[pos-1]) && c_isspace(c)) {
+ /*
+ * Zap multiple spaces to one
+ */
+ continue;
+ }
+
+ if (!make_space(&buf, &buflen, pos)) {
+ return ENOMEM;
+ }
+ buf[pos++] = c;
+ }
+
+ if (!make_space(&buf, &buflen, pos)) {
+ return ENOMEM;
+ }
+ buf[pos++] = '\0';
+
+ *pbuf = buf;
+ return 0;
+}
+
+static bool parse_section(
+ char *buf, bool (*sfunc)(const char *section, void *private_data),
+ void *private_data)
+{
+ char *p, *q;
+
+ p = buf+1; /* skip [ */
+
+ q = strchr(p, ']');
+ if (q == NULL) {
+ return false;
+ }
+ *q = '\0';
+
+ return sfunc(p, private_data);
+}
+
+static char *trim_one_space(char *buf)
+{
+ size_t len;
+
+ if (c_isspace(buf[0])) {
+ buf += 1;
+ }
+ len = strlen(buf);
+ if (len == 0) {
+ return buf;
+ }
+ if (c_isspace(buf[len-1])) {
+ buf[len-1] = '\0';
+ }
+
+ return buf;
+}
+
+static bool parse_param(char *buf,
+ bool allow_empty_value,
+ bool (*pfunc)(const char *name, const char *value,
+ void *private_data),
+ void *private_data)
+{
+ char *equals;
+ char *name;
+ const char *value;
+ size_t len;
+ bool no_value = false;
+
+ equals = strchr(buf, '=');
+ if (equals != NULL) {
+ *equals = '\0';
+ } else {
+ if (allow_empty_value) {
+ no_value = true;
+ } else {
+ return true;
+ }
+ }
+
+ name = trim_one_space(buf);
+ len = strlen(buf);
+ if (len == 0) {
+ return false;
+ }
+
+ if (no_value) {
+ value = "";
+ } else {
+ value = trim_one_space(equals+1);
+ }
+
+ return pfunc(name, value, private_data);
+}
+
+bool tini_parse(FILE *f,
+ bool allow_empty_value,
+ bool (*sfunc)(const char *section, void *private_data),
+ bool (*pfunc)(const char *name, const char *value,
+ void *private_data),
+ void *private_data)
+{
+ char *buf;
+ size_t buflen;
+
+ buflen = 256;
+
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ return false;
+ }
+
+ while (true) {
+ int ret;
+ bool ok;
+
+ ret = get_line(f, &buf, &buflen);
+
+ if (ret == ENOENT) {
+ /* No lines anymore */
+ break;
+ }
+
+ if (ret != 0) {
+ /* Real error */
+ free(buf);
+ return false;
+ }
+
+ switch(buf[0]) {
+ case 0:
+ continue;
+ break;
+ case '[':
+ ok = parse_section(buf, sfunc, private_data);
+ break;
+ default:
+ ok = parse_param(buf, allow_empty_value, pfunc, private_data);
+ break;
+ }
+
+ if (!ok) {
+ free(buf);
+ return false;
+ }
+ }
+ free(buf);
+ return true;
+}
diff --git a/lib/util/tini.h b/lib/util/tini.h
new file mode 100644
index 0000000..36fc080
--- /dev/null
+++ b/lib/util/tini.h
@@ -0,0 +1,45 @@
+/*
+ * Trivial smb.conf parsing code
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2014
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS 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 AUTHOR 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.
+ */
+
+#include <stdio.h>
+
+bool tini_parse(FILE *f,
+ bool allow_empty_value,
+ bool (*sfunc)(const char *section, void *private_data),
+ bool (*pfunc)(const char *name, const char *value,
+ void *private_data),
+ void *private_data);
diff --git a/lib/util/tiniparser.c b/lib/util/tiniparser.c
new file mode 100644
index 0000000..428ccff
--- /dev/null
+++ b/lib/util/tiniparser.c
@@ -0,0 +1,390 @@
+/*
+ * Trivial smb.conf parsing code
+ * iniparser compatibility layer.
+ *
+ * Copyright Jeremy Allison <jra@samba.org> 2014
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License Version 3 or later, in which case the provisions
+ * of the GPL are required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS 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 AUTHOR 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include "tini.h"
+#include "tiniparser.h"
+
+struct tiniparser_entry {
+ struct tiniparser_entry *next_entry;
+ char *key;
+ char *value;
+};
+
+struct tiniparser_section {
+ struct tiniparser_section *next_section;
+ struct tiniparser_entry *entry_list;
+ char section_name[];
+};
+
+struct tiniparser_dictionary {
+ struct tiniparser_section *section_list;
+};
+
+/*
+ * Find a section from a given key.
+ * Also return start of subkey.
+ * Return NULL if section name can't be found,
+ * if no section name given, or no subkey given.
+ */
+
+static struct tiniparser_section *find_section(struct tiniparser_dictionary *d,
+ const char *key,
+ const char **subkey)
+{
+ struct tiniparser_section *curr_section;
+ const char *p;
+ size_t section_len;
+
+ if (key == NULL) {
+ return NULL;
+ }
+ p = strchr(key, ':');
+ if (p == NULL) {
+ /* No section. */
+ return NULL;
+ }
+
+ section_len = p - key;
+ /* Ensure we have at least one character of section name. */
+ if (section_len == 0) {
+ return NULL;
+ }
+ /* Ensure we have at least one character of subkey. */
+ if (p[1] == '\0') {
+ return NULL;
+ }
+
+ for (curr_section = d->section_list;
+ curr_section;
+ curr_section = curr_section->next_section) {
+ /*
+ * Check if the key section matches the
+ * section name *exactly* (with terminating
+ * null after section_len characters.
+ */
+ if ((strncasecmp(key, curr_section->section_name, section_len) == 0) &&
+ (curr_section->section_name[section_len] == '\0')) {
+ *subkey = p+1;
+ return curr_section;
+ }
+ }
+ return NULL;
+}
+
+static struct tiniparser_entry *find_entry(struct tiniparser_section *section,
+ const char *key)
+{
+ struct tiniparser_entry *curr_entry;
+
+ for (curr_entry = section->entry_list;
+ curr_entry;
+ curr_entry = curr_entry->next_entry) {
+ if (strcasecmp(key,
+ curr_entry->key) == 0) {
+ return curr_entry;
+ }
+ }
+ return NULL;
+}
+
+const char *tiniparser_getstring(struct tiniparser_dictionary *d,
+ const char *key,
+ const char *default_value)
+{
+ struct tiniparser_section *section;
+ struct tiniparser_entry *entry;
+ const char *subkey;
+
+ section = find_section(d, key, &subkey);
+ if (section == NULL) {
+ return default_value;
+ }
+
+ entry = find_entry(section, subkey);
+ if (entry == NULL) {
+ return default_value;
+ }
+
+ return entry->value;
+}
+
+
+bool tiniparser_getboolean(struct tiniparser_dictionary *d,
+ const char *key,
+ bool default_value)
+{
+ const char *value = tiniparser_getstring(d, key, NULL);
+
+ if (value == NULL) {
+ return default_value;
+ }
+
+ switch(value[0]) {
+ case '1':
+ case 'T':
+ case 't':
+ case 'y':
+ case 'Y':
+ return true;
+ case '0':
+ case 'F':
+ case 'f':
+ case 'n':
+ case 'N':
+ return false;
+ default:
+ break;
+ }
+
+ return default_value;
+}
+
+int tiniparser_getint(struct tiniparser_dictionary *d,
+ const char *key,
+ int default_value)
+{
+ const char *value = tiniparser_getstring(d, key, NULL);
+
+ if (value == NULL) {
+ return default_value;
+ }
+
+ return (int)strtol(value, NULL, 0);
+}
+
+static bool value_parser(const char *key,
+ const char *value,
+ void *private_data)
+{
+ struct tiniparser_dictionary *d =
+ (struct tiniparser_dictionary *)private_data;
+ struct tiniparser_section *section = d->section_list;
+ struct tiniparser_entry *entry = NULL;
+ size_t val_len;
+ size_t key_len;
+
+ if (section == NULL) {
+ return false;
+ }
+ if (key == NULL) {
+ return false;
+ }
+ if (value == NULL) {
+ return false;
+ }
+
+ key_len = strlen(key) + 1;
+ val_len = strlen(value) + 1;
+
+ entry = find_entry(section, key);
+ if (entry) {
+ /* Replace current value. */
+ char *new_val = malloc(val_len);
+ if (new_val == NULL) {
+ return false;
+ }
+ memcpy(new_val, value, val_len);
+ free(entry->value);
+ entry->value = new_val;
+ return true;
+ }
+
+ /* Create a new entry. */
+ entry = malloc(sizeof(struct tiniparser_entry));
+ if (entry == NULL) {
+ return false;
+ }
+ entry->key = malloc(key_len);
+ if (entry->key == NULL) {
+ free(entry);
+ return false;
+ }
+ memcpy(entry->key, key, key_len);
+
+ entry->value = malloc(val_len);
+ if (entry->value == NULL) {
+ free(entry->key);
+ free(entry);
+ return false;
+ }
+ memcpy(entry->value, value, val_len);
+
+ entry->next_entry = section->entry_list;
+ section->entry_list = entry;
+ return true;
+}
+
+static bool section_parser(const char *section_name,
+ void *private_data)
+{
+ struct tiniparser_section **pp_section;
+ struct tiniparser_section *new_section;
+ struct tiniparser_dictionary *d =
+ (struct tiniparser_dictionary *)private_data;
+ size_t section_name_len;
+
+ if (section_name == NULL) {
+ return false;
+ }
+
+ /* Section names can't contain ':' */
+ if (strchr(section_name, ':') != NULL) {
+ return false;
+ }
+
+ /* Do we already have this section ? */
+ for (pp_section = &d->section_list;
+ *pp_section;
+ pp_section = &(*pp_section)->next_section) {
+ if (strcasecmp(section_name,
+ (*pp_section)->section_name) == 0) {
+ /*
+ * Move to the front of the list for
+ * value_parser() to find it.
+ */
+
+ /* First save current entry. */
+ struct tiniparser_section *curr_section = *pp_section;
+
+ /* Now unlink current entry from list. */
+ *pp_section = curr_section->next_section;
+
+ /* Make current entry next point to whole list. */
+ curr_section->next_section = d->section_list;
+
+ /* And replace list with current entry at start. */
+ d->section_list = curr_section;
+
+ return true;
+ }
+ }
+
+ section_name_len = strlen(section_name) + 1;
+
+ /* Create new section. */
+ new_section = malloc(
+ offsetof(struct tiniparser_section, section_name) +
+ section_name_len);
+ if (new_section == NULL) {
+ return false;
+ }
+
+ memcpy(new_section->section_name, section_name, section_name_len);
+
+ new_section->entry_list = NULL;
+
+ /* Add it to the head of the singly linked list. */
+ new_section->next_section = d->section_list;
+ d->section_list = new_section;
+ return true;
+}
+
+struct tiniparser_dictionary *tiniparser_load_stream(FILE *fp)
+{
+ bool ret;
+ struct tiniparser_dictionary *d = NULL;
+
+ d = malloc(sizeof(struct tiniparser_dictionary));
+ if (d == NULL) {
+ return NULL;
+ }
+ d->section_list = NULL;
+
+ ret = tini_parse(fp,
+ false,
+ section_parser,
+ value_parser,
+ d);
+ if (ret == false) {
+ tiniparser_freedict(d);
+ d = NULL;
+ }
+ return d;
+}
+
+struct tiniparser_dictionary *tiniparser_load(const char *filename)
+{
+ struct tiniparser_dictionary *d;
+ FILE *fp = fopen(filename, "r");
+
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ d = tiniparser_load_stream(fp);
+
+ fclose(fp);
+
+ return d;
+}
+
+void tiniparser_freedict(struct tiniparser_dictionary *d)
+{
+ struct tiniparser_section *curr_section, *next_section;
+
+ if (d == NULL) {
+ return;
+ }
+
+ for (curr_section = d->section_list;
+ curr_section;
+ curr_section = next_section) {
+ struct tiniparser_entry *curr_entry, *next_entry;
+
+ next_section = curr_section->next_section;
+
+ for (curr_entry = curr_section->entry_list;
+ curr_entry;
+ curr_entry = next_entry) {
+ next_entry = curr_entry->next_entry;
+
+ free(curr_entry->key);
+ free(curr_entry->value);
+ free(curr_entry);
+ }
+ free(curr_section);
+ }
+ free(d);
+}
diff --git a/lib/util/tiniparser.h b/lib/util/tiniparser.h
new file mode 100644
index 0000000..5356b22
--- /dev/null
+++ b/lib/util/tiniparser.h
@@ -0,0 +1,56 @@
+#ifndef _TINIPARSER_H_
+#define _TINIPARSER_H_
+/*
+ * Trivial smb.conf parsing code
+ * iniparser compatibility layer.
+ *
+ * Copyright Jeremy Allison <jra@samba.org> 2014
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS 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 AUTHOR 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.
+ */
+
+struct tiniparser_dictionary;
+
+bool tiniparser_getboolean(struct tiniparser_dictionary *d,
+ const char *key,
+ bool default_value);
+const char *tiniparser_getstring(struct tiniparser_dictionary *d,
+ const char *key,
+ const char *default_value);
+int tiniparser_getint(struct tiniparser_dictionary *d,
+ const char *key,
+ int default_value);
+struct tiniparser_dictionary *tiniparser_load_stream(FILE *fp);
+struct tiniparser_dictionary *tiniparser_load(const char *filename);
+void tiniparser_freedict(struct tiniparser_dictionary *d);
+
+#endif
diff --git a/lib/util/tsort.h b/lib/util/tsort.h
new file mode 100644
index 0000000..811d6cd
--- /dev/null
+++ b/lib/util/tsort.h
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ typesafe qsort
+
+ Copyright (C) Andrew Tridgell 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TSORT_H
+#define _TSORT_H
+#include <assert.h>
+
+/*
+ a wrapper around qsort() that ensures the comparison function is
+ type safe.
+ */
+#ifndef TYPESAFE_QSORT
+#define TYPESAFE_QSORT(base, numel, comparison) \
+do { \
+ if (numel > 1) { \
+ qsort(base, numel, sizeof((base)[0]), (int (*)(const void *, const void *))comparison); \
+ assert(comparison(&((base)[0]), &((base)[1])) <= 0); \
+ } \
+} while (0)
+#endif
+
+#endif
diff --git a/lib/util/unix_match.c b/lib/util/unix_match.c
new file mode 100644
index 0000000..38edc18
--- /dev/null
+++ b/lib/util/unix_match.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/talloc_stack.h"
+#include "lib/util/charset/charset.h"
+#include "lib/util/unix_match.h"
+
+/*********************************************************
+ Recursive routine that is called by unix_wild_match.
+*********************************************************/
+
+static bool unix_do_match(const char *regexp, const char *str)
+{
+ const char *p;
+
+ for( p = regexp; *p && *str; ) {
+
+ switch(*p) {
+ case '?':
+ str++;
+ p++;
+ break;
+
+ case '*':
+
+ /*
+ * Look for a character matching
+ * the one after the '*'.
+ */
+ p++;
+ if(!*p) {
+ return true; /* Automatic match */
+ }
+ while(*str) {
+
+ while(*str && (*p != *str)) {
+ str++;
+ }
+
+ /*
+ * Patch from weidel@multichart.de.
+ * In the case of the regexp
+ * '*XX*' we want to ensure there are
+ * at least 2 'X' characters in the
+ * string after the '*' for a match to
+ * be made.
+ */
+
+ {
+ int matchcount=0;
+
+ /*
+ * Eat all the characters that
+ * match, but count how many
+ * there were.
+ */
+
+ while(*str && (*p == *str)) {
+ str++;
+ matchcount++;
+ }
+
+ /*
+ * Now check that if the regexp
+ * had n identical characters
+ * that matchcount had at least
+ * that many matches.
+ */
+
+ while (*(p+1) && (*(p+1)==*p)) {
+ p++;
+ matchcount--;
+ }
+
+ if ( matchcount <= 0 ) {
+ return false;
+ }
+ }
+
+ /*
+ * We've eaten the match char
+ * after the '*'
+ */
+ str--;
+
+ if(unix_do_match(p, str)) {
+ return true;
+ }
+
+ if(!*str) {
+ return false;
+ } else {
+ str++;
+ }
+ }
+ return false;
+
+ default:
+ if(*str != *p) {
+ return false;
+ }
+ str++;
+ p++;
+ break;
+ }
+ }
+
+ if(!*p && !*str) {
+ return true;
+ }
+
+ if (!*p && str[0] == '.' && str[1] == 0) {
+ return true;
+ }
+
+ if (!*str && *p == '?') {
+ while (*p == '?') {
+ p++;
+ }
+ return(!*p);
+ }
+
+ if(!*str && (*p == '*' && p[1] == '\0')) {
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************
+ Simple case insensitive interface to a UNIX wildcard matcher.
+ Returns True if match, False if not.
+*******************************************************************/
+
+bool unix_wild_match(const char *pattern, const char *string)
+{
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *p2;
+ char *s2;
+ char *p;
+ bool ret = false;
+
+ p2 = strlower_talloc(ctx, pattern);
+ s2 = strlower_talloc(ctx, string);
+ if (!p2 || !s2) {
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ /* Remove any *? and ** from the pattern as they are meaningless */
+ for(p = p2; *p; p++) {
+ while( *p == '*' && (p[1] == '?' ||p[1] == '*')) {
+ memmove(&p[1], &p[2], strlen(&p[2])+1);
+ }
+ }
+
+ if (p2[0] == '*' && p2[1] == '\0') {
+ TALLOC_FREE(ctx);
+ return true;
+ }
+
+ ret = unix_do_match(p2, s2);
+ TALLOC_FREE(ctx);
+ return ret;
+}
diff --git a/lib/util/unix_match.h b/lib/util/unix_match.h
new file mode 100644
index 0000000..a7b6935
--- /dev/null
+++ b/lib/util/unix_match.h
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for Samba
+ Copyright (C) Jeremy Allison 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _UNIX_MASK_H_
+#define _UNIX_MASK_H_
+
+bool unix_wild_match(const char *pattern, const char *string);
+
+#endif
diff --git a/lib/util/unix_privs.c b/lib/util/unix_privs.c
new file mode 100644
index 0000000..9f28432
--- /dev/null
+++ b/lib/util/unix_privs.c
@@ -0,0 +1,92 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ gain/lose root privileges
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/fault.h"
+#include "system/passwd.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "../lib/util/unix_privs.h"
+#include "../lib/util/setid.h"
+
+/**
+ * @file
+ * @brief Gaining/losing root privileges
+ */
+
+/*
+ there are times when smbd needs to temporarily gain root privileges
+ to do some operation. To do this you call root_privileges(), which
+ returns a talloc handle. To restore your previous privileges
+ talloc_free() this pointer.
+
+ Note that this call is considered successful even if it does not
+ manage to gain root privileges, but it will call smb_abort() if it
+ fails to restore the privileges afterwards. The logic is that
+ failing to gain root access can be caught by whatever operation
+ needs to be run as root failing, but failing to lose the root
+ privileges is dangerous.
+
+ This also means that this code is safe to be called from completely
+ unprivileged processes.
+*/
+
+struct saved_state {
+ uid_t uid;
+};
+
+static int privileges_destructor(struct saved_state *s)
+{
+ if (geteuid() != s->uid &&
+ samba_seteuid(s->uid) != 0) {
+ smb_panic("Failed to restore privileges");
+ }
+ return 0;
+}
+
+/**
+ * Obtain root privileges for the current process.
+ *
+ * The privileges can be dropped by talloc_free()-ing the
+ * token returned by this function
+ */
+void *root_privileges(void)
+{
+ struct saved_state *s;
+ s = talloc(NULL, struct saved_state);
+ if (!s) return NULL;
+ s->uid = geteuid();
+ if (s->uid != 0) {
+ samba_seteuid(0);
+ }
+ talloc_set_destructor(s, privileges_destructor);
+ return s;
+}
+
+uid_t root_privileges_original_uid(void *s)
+{
+ struct saved_state *saved = talloc_get_type_abort(s, struct saved_state);
+ return saved->uid;
+}
diff --git a/lib/util/util.c b/lib/util/util.c
new file mode 100644
index 0000000..5f9310e
--- /dev/null
+++ b/lib/util/util.c
@@ -0,0 +1,1335 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001-2011
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+ Copyright (C) Volker Lendecke 2010
+ Copyright (C) Swen Schillig 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include <tevent.h>
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#include "system/shmem.h"
+#include "system/passwd.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "debug.h"
+#include "samba_util.h"
+#include "lib/util/select.h"
+#include <libgen.h>
+#include <gnutls/gnutls.h>
+
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
+#undef malloc
+#undef strcasecmp
+#undef strncasecmp
+#undef strdup
+#undef realloc
+#undef calloc
+
+/**
+ * @file
+ * @brief Misc utility functions
+ */
+
+/**
+ Find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call.
+**/
+_PUBLIC_ const char *tmpdir(void)
+{
+ char *p;
+ if ((p = getenv("TMPDIR")))
+ return p;
+ return "/tmp";
+}
+
+
+/**
+ Create a tmp file, open it and immediately unlink it.
+ If dir is NULL uses tmpdir()
+ Returns the file descriptor or -1 on error.
+**/
+int create_unlink_tmp(const char *dir)
+{
+ size_t len = strlen(dir ? dir : (dir = tmpdir()));
+ char fname[len+25];
+ int fd;
+ mode_t mask;
+
+ len = snprintf(fname, sizeof(fname), "%s/listenerlock_XXXXXX", dir);
+ if (len >= sizeof(fname)) {
+ errno = ENOMEM;
+ return -1;
+ }
+ mask = umask(S_IRWXO | S_IRWXG);
+ fd = mkstemp(fname);
+ umask(mask);
+ if (fd == -1) {
+ return -1;
+ }
+ if (unlink(fname) == -1) {
+ int sys_errno = errno;
+ close(fd);
+ errno = sys_errno;
+ return -1;
+ }
+ return fd;
+}
+
+
+/**
+ Check if a file exists - call vfs_file_exist for samba files.
+**/
+_PUBLIC_ bool file_exist(const char *fname)
+{
+ struct stat st;
+
+ if (stat(fname, &st) != 0) {
+ return false;
+ }
+
+ return ((S_ISREG(st.st_mode)) || (S_ISFIFO(st.st_mode)));
+}
+
+/**
+ * @brief Return a files modification time.
+ *
+ * @param fname The name of the file.
+ *
+ * @param mt A pointer to store the modification time.
+ *
+ * @return 0 on success, errno otherwise.
+ */
+_PUBLIC_ int file_modtime(const char *fname, struct timespec *mt)
+{
+ struct stat st = {0};
+
+ if (stat(fname, &st) != 0) {
+ return errno;
+ }
+
+ *mt = get_mtimespec(&st);
+ return 0;
+}
+
+/**
+ Check file permissions.
+**/
+
+_PUBLIC_ bool file_check_permissions(const char *fname,
+ uid_t uid,
+ mode_t file_perms,
+ struct stat *pst)
+{
+ int ret;
+ struct stat st;
+
+ if (pst == NULL) {
+ pst = &st;
+ }
+
+ ZERO_STRUCTP(pst);
+
+ ret = stat(fname, pst);
+ if (ret != 0) {
+ DEBUG(0, ("stat failed on file '%s': %s\n",
+ fname, strerror(errno)));
+ return false;
+ }
+
+ if (pst->st_uid != uid && !uid_wrapper_enabled()) {
+ DEBUG(0, ("invalid ownership of file '%s': "
+ "owned by uid %u, should be %u\n",
+ fname, (unsigned int)pst->st_uid,
+ (unsigned int)uid));
+ return false;
+ }
+
+ if ((pst->st_mode & 0777) != file_perms) {
+ DEBUG(0, ("invalid permissions on file "
+ "'%s': has 0%o should be 0%o\n", fname,
+ (unsigned int)(pst->st_mode & 0777),
+ (unsigned int)file_perms));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ Check if a directory exists.
+**/
+
+_PUBLIC_ bool directory_exist(const char *dname)
+{
+ struct stat st;
+ bool ret;
+
+ if (stat(dname,&st) != 0) {
+ return false;
+ }
+
+ ret = S_ISDIR(st.st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
+}
+
+/**
+ * Try to create the specified directory if it didn't exist.
+ * A symlink to a directory is also accepted as a valid existing directory.
+ *
+ * @retval true if the directory already existed
+ * or was successfully created.
+ */
+_PUBLIC_ bool directory_create_or_exist(const char *dname,
+ mode_t dir_perms)
+{
+ int ret;
+ mode_t old_umask;
+
+ /* Create directory */
+ old_umask = umask(0);
+ ret = mkdir(dname, dir_perms);
+ if (ret == -1 && errno != EEXIST) {
+ int dbg_level = geteuid() == 0 ? DBGLVL_ERR : DBGLVL_NOTICE;
+
+ DBG_PREFIX(dbg_level,
+ ("mkdir failed on directory %s: %s\n",
+ dname,
+ strerror(errno)));
+ umask(old_umask);
+ return false;
+ }
+ umask(old_umask);
+
+ if (ret != 0 && errno == EEXIST) {
+ struct stat sbuf;
+
+ ret = lstat(dname, &sbuf);
+ if (ret != 0) {
+ return false;
+ }
+
+ if (S_ISDIR(sbuf.st_mode)) {
+ return true;
+ }
+
+ if (S_ISLNK(sbuf.st_mode)) {
+ ret = stat(dname, &sbuf);
+ if (ret != 0) {
+ return false;
+ }
+
+ if (S_ISDIR(sbuf.st_mode)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+_PUBLIC_ bool directory_create_or_exists_recursive(
+ const char *dname,
+ mode_t dir_perms)
+{
+ bool ok;
+
+ ok = directory_create_or_exist(dname, dir_perms);
+ if (!ok) {
+ if (!directory_exist(dname)) {
+ char tmp[PATH_MAX] = {0};
+ char *parent = NULL;
+ size_t n;
+
+ /* Use the null context */
+ n = strlcpy(tmp, dname, sizeof(tmp));
+ if (n < strlen(dname)) {
+ DBG_ERR("Path too long!\n");
+ return false;
+ }
+
+ parent = dirname(tmp);
+ if (parent == NULL) {
+ DBG_ERR("Failed to create dirname!\n");
+ return false;
+ }
+
+ ok = directory_create_or_exists_recursive(parent,
+ dir_perms);
+ if (!ok) {
+ return false;
+ }
+
+ ok = directory_create_or_exist(dname, dir_perms);
+ }
+ }
+
+ return ok;
+}
+
+/**
+ * @brief Try to create a specified directory if it doesn't exist.
+ *
+ * The function creates a directory with the given uid and permissions if it
+ * doesn't exist. If it exists it makes sure the uid and permissions are
+ * correct and it will fail if they are different.
+ *
+ * @param[in] dname The directory to create.
+ *
+ * @param[in] uid The uid the directory needs to belong too.
+ *
+ * @param[in] dir_perms The expected permissions of the directory.
+ *
+ * @return True on success, false on error.
+ */
+_PUBLIC_ bool directory_create_or_exist_strict(const char *dname,
+ uid_t uid,
+ mode_t dir_perms)
+{
+ struct stat st;
+ bool ok;
+ int rc;
+
+ ok = directory_create_or_exist(dname, dir_perms);
+ if (!ok) {
+ return false;
+ }
+
+ rc = lstat(dname, &st);
+ if (rc == -1) {
+ DEBUG(0, ("lstat failed on created directory %s: %s\n",
+ dname, strerror(errno)));
+ return false;
+ }
+
+ /* Check ownership and permission on existing directory */
+ if (!S_ISDIR(st.st_mode)) {
+ DEBUG(0, ("directory %s isn't a directory\n",
+ dname));
+ return false;
+ }
+ if (st.st_uid != uid && !uid_wrapper_enabled()) {
+ DBG_NOTICE("invalid ownership on directory "
+ "%s\n", dname);
+ return false;
+ }
+ if ((st.st_mode & 0777) != dir_perms) {
+ DEBUG(0, ("invalid permissions on directory "
+ "'%s': has 0%o should be 0%o\n", dname,
+ (unsigned int)(st.st_mode & 0777), (unsigned int)dir_perms));
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ Sleep for a specified number of milliseconds.
+**/
+
+_PUBLIC_ void smb_msleep(unsigned int t)
+{
+ sys_poll_intr(NULL, 0, t);
+}
+
+/**
+ Get my own name, return in talloc'ed storage.
+**/
+
+_PUBLIC_ char *get_myname(TALLOC_CTX *ctx)
+{
+ char *p;
+ char hostname[HOST_NAME_MAX];
+
+ /* get my host name */
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ DEBUG(0,("gethostname failed\n"));
+ return NULL;
+ }
+
+ /* Ensure null termination. */
+ hostname[sizeof(hostname)-1] = '\0';
+
+ /* split off any parts after an initial . */
+ p = strchr_m(hostname, '.');
+ if (p) {
+ *p = 0;
+ }
+
+ return talloc_strdup(ctx, hostname);
+}
+
+/**
+ Check if a process exists. Does this work on all unixes?
+**/
+
+_PUBLIC_ bool process_exists_by_pid(pid_t pid)
+{
+ /* Doing kill with a non-positive pid causes messages to be
+ * sent to places we don't want. */
+ if (pid <= 0) {
+ return false;
+ }
+ return(kill(pid,0) == 0 || errno != ESRCH);
+}
+
+/**
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+**/
+
+_PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type)
+{
+ struct flock lock;
+ int ret;
+
+ DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = offset;
+ lock.l_len = count;
+ lock.l_pid = 0;
+
+ ret = fcntl(fd,op,&lock);
+
+ if (ret == -1 && errno != 0)
+ DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
+
+ /* a lock query */
+ if (op == F_GETLK) {
+ if ((ret != -1) &&
+ (lock.l_type != F_UNLCK) &&
+ (lock.l_pid != 0) &&
+ (lock.l_pid != tevent_cached_getpid())) {
+ DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
+ return true;
+ }
+
+ /* it must be not locked or locked by me */
+ return false;
+ }
+
+ /* a lock set or unset */
+ if (ret == -1) {
+ DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
+ (double)offset,(double)count,op,type,strerror(errno)));
+ return false;
+ }
+
+ /* everything went OK */
+ DEBUG(8,("fcntl_lock: Lock call successful\n"));
+
+ return true;
+}
+
+struct debug_channel_level {
+ int channel;
+ int level;
+};
+
+static void debugadd_channel_cb(const char *buf, void *private_data)
+{
+ struct debug_channel_level *dcl =
+ (struct debug_channel_level *)private_data;
+
+ DEBUGADDC(dcl->channel, dcl->level,("%s", buf));
+}
+
+static void debugadd_cb(const char *buf, void *private_data)
+{
+ int *plevel = (int *)private_data;
+ DEBUGADD(*plevel, ("%s", buf));
+}
+
+void print_asc_cb(const uint8_t *buf, int len,
+ void (*cb)(const char *buf, void *private_data),
+ void *private_data)
+{
+ int i;
+ char s[2];
+ s[1] = 0;
+
+ for (i=0; i<len; i++) {
+ s[0] = isprint(buf[i]) ? buf[i] : '.';
+ cb(s, private_data);
+ }
+}
+
+void print_asc(int level, const uint8_t *buf,int len)
+{
+ print_asc_cb(buf, len, debugadd_cb, &level);
+}
+
+static void dump_data_block16(const char *prefix, size_t idx,
+ const uint8_t *buf, size_t len,
+ void (*cb)(const char *buf, void *private_data),
+ void *private_data)
+{
+ char tmp[16];
+ size_t i;
+
+ SMB_ASSERT(len <= 16);
+
+ snprintf(tmp, sizeof(tmp), "%s[%04zX]", prefix, idx);
+ cb(tmp, private_data);
+
+ for (i=0; i<16; i++) {
+ if (i == 8) {
+ cb(" ", private_data);
+ }
+ if (i < len) {
+ snprintf(tmp, sizeof(tmp), " %02X", (int)buf[i]);
+ } else {
+ snprintf(tmp, sizeof(tmp), " ");
+ }
+ cb(tmp, private_data);
+ }
+
+ cb(" ", private_data);
+
+ if (len == 0) {
+ cb("EMPTY BLOCK\n", private_data);
+ return;
+ }
+
+ for (i=0; i<len; i++) {
+ if (i == 8) {
+ cb(" ", private_data);
+ }
+ print_asc_cb(&buf[i], 1, cb, private_data);
+ }
+
+ cb("\n", private_data);
+}
+
+/**
+ * Write dump of binary data to a callback
+ */
+void dump_data_cb(const uint8_t *buf, int len,
+ bool omit_zero_bytes,
+ void (*cb)(const char *buf, void *private_data),
+ void *private_data)
+{
+ int i=0;
+ bool skipped = false;
+
+ if (len<=0) return;
+
+ for (i=0;i<len;i+=16) {
+ size_t remaining_len = len - i;
+ size_t this_len = MIN(remaining_len, 16);
+ const uint8_t *this_buf = &buf[i];
+
+ if ((omit_zero_bytes == true) &&
+ (i > 0) && (remaining_len > 16) &&
+ (this_len == 16) && all_zero(this_buf, 16))
+ {
+ if (!skipped) {
+ cb("skipping zero buffer bytes\n",
+ private_data);
+ skipped = true;
+ }
+ continue;
+ }
+
+ skipped = false;
+ dump_data_block16("", i, this_buf, this_len,
+ cb, private_data);
+ }
+}
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level.
+ */
+_PUBLIC_ void dump_data(int level, const uint8_t *buf, int len)
+{
+ if (!DEBUGLVL(level)) {
+ return;
+ }
+ dump_data_cb(buf, len, false, debugadd_cb, &level);
+}
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level for
+ * debug class dbgc_class.
+ */
+_PUBLIC_ void dump_data_dbgc(int dbgc_class, int level, const uint8_t *buf, int len)
+{
+ struct debug_channel_level dcl = { dbgc_class, level };
+
+ if (!DEBUGLVLC(dbgc_class, level)) {
+ return;
+ }
+ dump_data_cb(buf, len, false, debugadd_channel_cb, &dcl);
+}
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level.
+ * 16 zero bytes in a row are omitted
+ */
+_PUBLIC_ void dump_data_skip_zeros(int level, const uint8_t *buf, int len)
+{
+ if (!DEBUGLVL(level)) {
+ return;
+ }
+ dump_data_cb(buf, len, true, debugadd_cb, &level);
+}
+
+static void fprintf_cb(const char *buf, void *private_data)
+{
+ FILE *f = (FILE *)private_data;
+ fprintf(f, "%s", buf);
+}
+
+void dump_data_file(const uint8_t *buf, int len, bool omit_zero_bytes,
+ FILE *f)
+{
+ dump_data_cb(buf, len, omit_zero_bytes, fprintf_cb, f);
+}
+
+/**
+ * Write dump of compared binary data to a callback
+ */
+void dump_data_diff_cb(const uint8_t *buf1, size_t len1,
+ const uint8_t *buf2, size_t len2,
+ bool omit_zero_bytes,
+ void (*cb)(const char *buf, void *private_data),
+ void *private_data)
+{
+ size_t len = MAX(len1, len2);
+ size_t i;
+ bool skipped = false;
+
+ for (i=0; i<len; i+=16) {
+ size_t remaining_len = len - i;
+ size_t remaining_len1 = 0;
+ size_t this_len1 = 0;
+ const uint8_t *this_buf1 = NULL;
+ size_t remaining_len2 = 0;
+ size_t this_len2 = 0;
+ const uint8_t *this_buf2 = NULL;
+
+ if (i < len1) {
+ remaining_len1 = len1 - i;
+ this_len1 = MIN(remaining_len1, 16);
+ this_buf1 = &buf1[i];
+ }
+ if (i < len2) {
+ remaining_len2 = len2 - i;
+ this_len2 = MIN(remaining_len2, 16);
+ this_buf2 = &buf2[i];
+ }
+
+ if ((omit_zero_bytes == true) &&
+ (i > 0) && (remaining_len > 16) &&
+ (this_len1 == 16) && all_zero(this_buf1, 16) &&
+ (this_len2 == 16) && all_zero(this_buf2, 16))
+ {
+ if (!skipped) {
+ cb("skipping zero buffer bytes\n",
+ private_data);
+ skipped = true;
+ }
+ continue;
+ }
+
+ skipped = false;
+
+ if ((this_len1 == this_len2) &&
+ (memcmp(this_buf1, this_buf2, this_len1) == 0))
+ {
+ dump_data_block16(" ", i, this_buf1, this_len1,
+ cb, private_data);
+ continue;
+ }
+
+ dump_data_block16("-", i, this_buf1, this_len1,
+ cb, private_data);
+ dump_data_block16("+", i, this_buf2, this_len2,
+ cb, private_data);
+ }
+}
+
+_PUBLIC_ void dump_data_diff(int dbgc_class, int level,
+ bool omit_zero_bytes,
+ const uint8_t *buf1, size_t len1,
+ const uint8_t *buf2, size_t len2)
+{
+ struct debug_channel_level dcl = { dbgc_class, level };
+
+ if (!DEBUGLVLC(dbgc_class, level)) {
+ return;
+ }
+ dump_data_diff_cb(buf1, len1, buf2, len2, true, debugadd_channel_cb, &dcl);
+}
+
+_PUBLIC_ void dump_data_file_diff(FILE *f,
+ bool omit_zero_bytes,
+ const uint8_t *buf1, size_t len1,
+ const uint8_t *buf2, size_t len2)
+{
+ dump_data_diff_cb(buf1, len1, buf2, len2, omit_zero_bytes, fprintf_cb, f);
+}
+
+/**
+ malloc that aborts with smb_panic on fail or zero size.
+**/
+
+_PUBLIC_ void *smb_xmalloc(size_t size)
+{
+ void *p;
+ if (size == 0)
+ smb_panic("smb_xmalloc: called with zero size.\n");
+ if ((p = malloc(size)) == NULL)
+ smb_panic("smb_xmalloc: malloc fail.\n");
+ return p;
+}
+
+/**
+ Memdup with smb_panic on fail.
+**/
+
+_PUBLIC_ void *smb_xmemdup(const void *p, size_t size)
+{
+ void *p2;
+ p2 = smb_xmalloc(size);
+ memcpy(p2, p, size);
+ return p2;
+}
+
+/**
+ strdup that aborts on malloc fail.
+**/
+
+char *smb_xstrdup(const char *s)
+{
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strdup
+#undef strdup
+#endif
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup rep_strdup
+#endif
+
+ char *s1 = strdup(s);
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strdup
+#undef strdup
+#endif
+#define strdup(s) __ERROR_DONT_USE_STRDUP_DIRECTLY
+#endif
+ if (!s1) {
+ smb_panic("smb_xstrdup: malloc failed");
+ }
+ return s1;
+
+}
+
+/**
+ strndup that aborts on malloc fail.
+**/
+
+char *smb_xstrndup(const char *s, size_t n)
+{
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strndup
+#undef strndup
+#endif
+#endif
+
+#if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP))
+#undef HAVE_STRNDUP
+#define strndup rep_strndup
+#endif
+
+ char *s1 = strndup(s, n);
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef strndup
+#undef strndup
+#endif
+#define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY
+#endif
+ if (!s1) {
+ smb_panic("smb_xstrndup: malloc failed");
+ }
+ return s1;
+}
+
+
+
+/**
+ Like strdup but for memory.
+**/
+
+_PUBLIC_ void *smb_memdup(const void *p, size_t size)
+{
+ void *p2;
+ if (size == 0)
+ return NULL;
+ p2 = malloc(size);
+ if (!p2)
+ return NULL;
+ memcpy(p2, p, size);
+ return p2;
+}
+
+/**
+ * Write a password to the log file.
+ *
+ * @note Only actually does something if DEBUG_PASSWORD was defined during
+ * compile-time.
+ */
+_PUBLIC_ void dump_data_pw(const char *msg, const uint8_t * data, size_t len)
+{
+#ifdef DEBUG_PASSWORD
+ DEBUG(11, ("%s", msg));
+ if (data != NULL && len > 0)
+ {
+ dump_data(11, data, len);
+ }
+#endif
+}
+
+static void dump_data_addbuf_cb(const char *buf, void *private_data)
+{
+ char **str = private_data;
+ talloc_asprintf_addbuf(str, "%s", buf);
+}
+
+_PUBLIC_ void dump_data_addbuf(const uint8_t *buf, size_t buflen, char **str)
+{
+ dump_data_cb(buf, buflen, false, dump_data_addbuf_cb, str);
+}
+
+
+/**
+ * see if a range of memory is all zero. A NULL pointer is considered
+ * to be all zero
+ */
+_PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size)
+{
+ size_t i;
+ if (!ptr) return true;
+ for (i=0;i<size;i++) {
+ if (ptr[i]) return false;
+ }
+ return true;
+}
+
+/**
+ realloc an array, checking for integer overflow in the array size
+*/
+_PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail)
+{
+#define MAX_MALLOC_SIZE 0x7fffffff
+ if (count == 0 ||
+ count >= MAX_MALLOC_SIZE/el_size) {
+ if (free_on_fail)
+ SAFE_FREE(ptr);
+ return NULL;
+ }
+ if (!ptr) {
+ return malloc(el_size * count);
+ }
+ return realloc(ptr, el_size * count);
+}
+
+/****************************************************************************
+ Type-safe malloc.
+****************************************************************************/
+
+void *malloc_array(size_t el_size, unsigned int count)
+{
+ return realloc_array(NULL, el_size, count, false);
+}
+
+/****************************************************************************
+ Type-safe memalign
+****************************************************************************/
+
+void *memalign_array(size_t el_size, size_t align, unsigned int count)
+{
+ if (el_size == 0 || count >= MAX_MALLOC_SIZE/el_size) {
+ return NULL;
+ }
+
+ return memalign(align, el_size*count);
+}
+
+/****************************************************************************
+ Type-safe calloc.
+****************************************************************************/
+
+void *calloc_array(size_t size, size_t nmemb)
+{
+ if (nmemb >= MAX_MALLOC_SIZE/size) {
+ return NULL;
+ }
+ if (size == 0 || nmemb == 0) {
+ return NULL;
+ }
+ return calloc(nmemb, size);
+}
+
+/**
+ Trim the specified elements off the front and back of a string.
+**/
+_PUBLIC_ bool trim_string(char *s, const char *front, const char *back)
+{
+ bool ret = false;
+ size_t front_len;
+ size_t back_len;
+ size_t len;
+
+ /* Ignore null or empty strings. */
+ if (!s || (s[0] == '\0')) {
+ return false;
+ }
+ len = strlen(s);
+
+ front_len = front? strlen(front) : 0;
+ back_len = back? strlen(back) : 0;
+
+ if (front_len) {
+ size_t front_trim = 0;
+
+ while (strncmp(s+front_trim, front, front_len)==0) {
+ front_trim += front_len;
+ }
+ if (front_trim > 0) {
+ /* Must use memmove here as src & dest can
+ * easily overlap. Found by valgrind. JRA. */
+ memmove(s, s+front_trim, (len-front_trim)+1);
+ len -= front_trim;
+ ret=true;
+ }
+ }
+
+ if (back_len) {
+ while ((len >= back_len) && strncmp(s+len-back_len,back,back_len)==0) {
+ s[len-back_len]='\0';
+ len -= back_len;
+ ret=true;
+ }
+ }
+ return ret;
+}
+
+/**
+ Find the number of 'c' chars in a string
+**/
+_PUBLIC_ _PURE_ size_t count_chars(const char *s, char c)
+{
+ size_t count = 0;
+
+ while (*s) {
+ if (*s == c) count++;
+ s ++;
+ }
+
+ return count;
+}
+
+/**
+ * Routine to get hex characters and turn them into a byte array.
+ * the array can be variable length.
+ * - "0xnn" or "0Xnn" is specially catered for.
+ * - The first non-hex-digit character (apart from possibly leading "0x"
+ * finishes the conversion and skips the rest of the input.
+ * - A single hex-digit character at the end of the string is skipped.
+ *
+ * valid examples: "0A5D15"; "0x123456"
+ */
+_PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len)
+{
+ size_t i = 0;
+ size_t num_chars = 0;
+
+ /* skip leading 0x prefix */
+ if (strncasecmp(strhex, "0x", 2) == 0) {
+ i += 2; /* skip two chars */
+ }
+
+ while ((i < strhex_len) && (num_chars < p_len)) {
+ bool ok = hex_byte(&strhex[i], (uint8_t *)&p[num_chars]);
+ if (!ok) {
+ break;
+ }
+ i += 2;
+ num_chars += 1;
+ }
+
+ return num_chars;
+}
+
+/**
+ * Parse a hex string and return a data blob.
+ */
+_PUBLIC_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex)
+{
+ DATA_BLOB ret_blob = data_blob_talloc(mem_ctx, NULL, strlen(strhex)/2+1);
+ if (ret_blob.data == NULL) {
+ /* ret_blob.length is already 0 */
+ return ret_blob;
+ }
+ ret_blob.length = strhex_to_str((char *)ret_blob.data, ret_blob.length,
+ strhex,
+ strlen(strhex));
+
+ return ret_blob;
+}
+
+/**
+ * Parse a hex dump and return a data blob. Hex dump is structured as
+ * is generated from dump_data_cb() elsewhere in this file
+ *
+ */
+_PUBLIC_ DATA_BLOB hexdump_to_data_blob(TALLOC_CTX *mem_ctx, const char *hexdump, size_t hexdump_len)
+{
+ DATA_BLOB ret_blob = { 0 };
+ size_t i = 0;
+ size_t char_count = 0;
+ /* hexdump line length is 77 chars long. We then use the ASCII representation of the bytes
+ * at the end of the final line to calculate how many are in that line, minus the extra space
+ * and newline. */
+ size_t hexdump_byte_count = (16 * (hexdump_len / 77));
+ if (hexdump_len % 77) {
+ hexdump_byte_count += ((hexdump_len % 77) - 59 - 2);
+ }
+
+ ret_blob = data_blob_talloc(mem_ctx, NULL, hexdump_byte_count+1);
+ for (; i+1 < hexdump_len && hexdump[i] != 0 && hexdump[i+1] != 0; i++) {
+ if ((i%77) == 0)
+ i += 7; /* Skip the offset at the start of the line */
+ if ((i%77) < 56) { /* position 56 is after both hex chunks */
+ if (hexdump[i] != ' ') {
+ char_count += strhex_to_str((char *)&ret_blob.data[char_count],
+ hexdump_byte_count - char_count,
+ &hexdump[i], 2);
+ i += 2;
+ } else {
+ i++;
+ }
+ } else {
+ i++;
+ }
+ }
+ ret_blob.length = char_count;
+
+ return ret_blob;
+}
+
+/**
+ * Print a buf in hex. Assumes dst is at least (srclen*2)+1 large.
+ */
+_PUBLIC_ void hex_encode_buf(char *dst, const uint8_t *src, size_t srclen)
+{
+ size_t i;
+ for (i=0; i<srclen; i++) {
+ snprintf(dst + i*2, 3, "%02X", src[i]);
+ }
+ /*
+ * Ensure 0-termination for 0-length buffers
+ */
+ dst[srclen*2] = '\0';
+}
+
+/**
+ * talloc version of hex_encode_buf()
+ */
+_PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len)
+{
+ char *hex_buffer;
+
+ hex_buffer = talloc_array(mem_ctx, char, (len*2)+1);
+ if (!hex_buffer) {
+ return NULL;
+ }
+ hex_encode_buf(hex_buffer, buff_in, len);
+ talloc_set_name_const(hex_buffer, hex_buffer);
+ return hex_buffer;
+}
+
+/**
+ variant of strcmp() that handles NULL ptrs
+**/
+_PUBLIC_ int strcmp_safe(const char *s1, const char *s2)
+{
+ if (s1 == s2) {
+ return 0;
+ }
+ if (s1 == NULL || s2 == NULL) {
+ return s1?-1:1;
+ }
+ return strcmp(s1, s2);
+}
+
+
+/**
+return the number of bytes occupied by a buffer in ASCII format
+the result includes the null termination
+limited by 'n' bytes
+**/
+_PUBLIC_ size_t ascii_len_n(const char *src, size_t n)
+{
+ size_t len;
+
+ len = strnlen(src, n);
+ if (len+1 <= n) {
+ len += 1;
+ }
+
+ return len;
+}
+
+_PUBLIC_ bool mem_equal_const_time(const void *s1, const void *s2, size_t n)
+{
+ /* Ensure we won't overflow the unsigned index used by gnutls. */
+ SMB_ASSERT(n <= UINT_MAX);
+
+ return gnutls_memcmp(s1, s2, n) == 0;
+}
+
+struct anonymous_shared_header {
+ union {
+ size_t length;
+ uint8_t pad[16];
+ } u;
+};
+
+/* Map a shared memory buffer of at least nelem counters. */
+void *anonymous_shared_allocate(size_t orig_bufsz)
+{
+ void *ptr;
+ void *buf;
+ size_t pagesz = getpagesize();
+ size_t pagecnt;
+ size_t bufsz = orig_bufsz;
+ struct anonymous_shared_header *hdr;
+
+ bufsz += sizeof(*hdr);
+
+ /* round up to full pages */
+ pagecnt = bufsz / pagesz;
+ if (bufsz % pagesz) {
+ pagecnt += 1;
+ }
+ bufsz = pagesz * pagecnt;
+
+ if (orig_bufsz >= bufsz) {
+ /* integer wrap */
+ errno = ENOMEM;
+ return NULL;
+ }
+
+#ifdef MAP_ANON
+ /* BSD */
+ buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED,
+ -1 /* fd */, 0 /* offset */);
+#else
+{
+ int saved_errno;
+ int fd;
+
+ fd = open("/dev/zero", O_RDWR);
+ if (fd == -1) {
+ return NULL;
+ }
+
+ buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
+ fd, 0 /* offset */);
+ saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+}
+#endif
+
+ if (buf == MAP_FAILED) {
+ return NULL;
+ }
+
+ hdr = (struct anonymous_shared_header *)buf;
+ hdr->u.length = bufsz;
+
+ ptr = (void *)(&hdr[1]);
+
+ return ptr;
+}
+
+void *anonymous_shared_resize(void *ptr, size_t new_size, bool maymove)
+{
+#ifdef HAVE_MREMAP
+ void *buf;
+ size_t pagesz = getpagesize();
+ size_t pagecnt;
+ size_t bufsz;
+ struct anonymous_shared_header *hdr;
+ int flags = 0;
+
+ if (ptr == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ hdr = (struct anonymous_shared_header *)ptr;
+ hdr--;
+ if (hdr->u.length > (new_size + sizeof(*hdr))) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ bufsz = new_size + sizeof(*hdr);
+
+ /* round up to full pages */
+ pagecnt = bufsz / pagesz;
+ if (bufsz % pagesz) {
+ pagecnt += 1;
+ }
+ bufsz = pagesz * pagecnt;
+
+ if (new_size >= bufsz) {
+ /* integer wrap */
+ errno = ENOSPC;
+ return NULL;
+ }
+
+ if (bufsz <= hdr->u.length) {
+ return ptr;
+ }
+
+ if (maymove) {
+ flags = MREMAP_MAYMOVE;
+ }
+
+ buf = mremap(hdr, hdr->u.length, bufsz, flags);
+
+ if (buf == MAP_FAILED) {
+ errno = ENOSPC;
+ return NULL;
+ }
+
+ hdr = (struct anonymous_shared_header *)buf;
+ hdr->u.length = bufsz;
+
+ ptr = (void *)(&hdr[1]);
+
+ return ptr;
+#else
+ errno = ENOSPC;
+ return NULL;
+#endif
+}
+
+void anonymous_shared_free(void *ptr)
+{
+ struct anonymous_shared_header *hdr;
+
+ if (ptr == NULL) {
+ return;
+ }
+
+ hdr = (struct anonymous_shared_header *)ptr;
+
+ hdr--;
+
+ munmap(hdr, hdr->u.length);
+}
+
+#ifdef DEVELOPER
+/* used when you want a debugger started at a particular point in the
+ code. Mostly useful in code that runs as a child process, where
+ normal gdb attach is harder to organise.
+*/
+void samba_start_debugger(void)
+{
+ int ready_pipe[2];
+ char c;
+ int ret;
+ pid_t pid;
+
+ ret = pipe(ready_pipe);
+ SMB_ASSERT(ret == 0);
+
+ pid = fork();
+ SMB_ASSERT(pid >= 0);
+
+ if (pid) {
+ c = 0;
+
+ ret = close(ready_pipe[0]);
+ SMB_ASSERT(ret == 0);
+#if defined(HAVE_PRCTL) && defined(PR_SET_PTRACER)
+ /*
+ * Make sure the child process can attach a debugger.
+ *
+ * We don't check the error code as the debugger
+ * will tell us if it can't attach.
+ */
+ (void)prctl(PR_SET_PTRACER, pid, 0, 0, 0);
+#endif
+ ret = write(ready_pipe[1], &c, 1);
+ SMB_ASSERT(ret == 1);
+
+ ret = close(ready_pipe[1]);
+ SMB_ASSERT(ret == 0);
+
+ /* Wait for gdb to attach. */
+ sleep(2);
+ } else {
+ char *cmd = NULL;
+
+ ret = close(ready_pipe[1]);
+ SMB_ASSERT(ret == 0);
+
+ ret = read(ready_pipe[0], &c, 1);
+ SMB_ASSERT(ret == 1);
+
+ ret = close(ready_pipe[0]);
+ SMB_ASSERT(ret == 0);
+
+ ret = asprintf(&cmd, "gdb --pid %u", getppid());
+ SMB_ASSERT(ret != -1);
+
+ execlp("xterm", "xterm", "-e", cmd, (char *) NULL);
+ smb_panic("execlp() failed");
+ }
+}
+#endif
diff --git a/lib/util/util.h b/lib/util/util.h
new file mode 100644
index 0000000..59d24a8
--- /dev/null
+++ b/lib/util/util.h
@@ -0,0 +1,94 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for Samba
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Swen Schillig 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __UTIL_SAMBA_UTIL_H__
+#define __UTIL_SAMBA_UTIL_H__
+
+/**
+ * Write dump of binary data to a callback
+ */
+void dump_data_cb(const uint8_t *buf, int len,
+ bool omit_zero_bytes,
+ void (*cb)(const char *buf, void *private_data),
+ void *private_data);
+
+/**
+ * Write dump of binary data to a FILE
+ */
+void dump_data_file(const uint8_t *buf, int len, bool omit_zero_bytes,
+ FILE *f);
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level.
+ */
+_PUBLIC_ void dump_data(int level, const uint8_t *buf,int len);
+
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level for
+ * debug class dbgc_class.
+ */
+_PUBLIC_ void dump_data_dbgc(int dbgc_class, int level, const uint8_t *buf, int len);
+
+/**
+ * Write dump of compared binary data to a callback
+ */
+void dump_data_diff_cb(const uint8_t *buf1, size_t len1,
+ const uint8_t *buf2, size_t len2,
+ bool omit_zero_bytes,
+ void (*cb)(const char *buf, void *private_data),
+ void *private_data);
+
+/**
+ * Write dump of compared binary data to the log file.
+ *
+ * The data is only written if the log level is at least level for
+ * debug class dbgc_class.
+ */
+_PUBLIC_ void dump_data_diff(int dbgc_class, int level,
+ bool omit_zero_bytes,
+ const uint8_t *buf1, size_t len1,
+ const uint8_t *buf2, size_t len2);
+
+/**
+ * Write dump of compared binary data to the given file handle
+ */
+_PUBLIC_ void dump_data_file_diff(FILE *f,
+ bool omit_zero_bytes,
+ const uint8_t *buf1, size_t len1,
+ const uint8_t *buf2, size_t len2);
+
+/**
+ * Write a password to the log file.
+ *
+ * @note Only actually does something if DEBUG_PASSWORD was defined during
+ * compile-time.
+ */
+_PUBLIC_ void dump_data_pw(const char *msg, const uint8_t * data, size_t len);
+
+/**
+ * Dump data to "str" via talloc_asprintf_addbuf()
+ */
+_PUBLIC_ void dump_data_addbuf(const uint8_t *buf, size_t buflen, char **str);
+#endif
diff --git a/lib/util/util_file.c b/lib/util/util_file.c
new file mode 100644
index 0000000..0e54dff
--- /dev/null
+++ b/lib/util/util_file.c
@@ -0,0 +1,498 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * SMB parameters and setup
+ * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
+ *
+ * Added afdgets() Jelmer Vernooij 2005
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/shmem.h"
+#include "system/filesys.h"
+#include <talloc.h>
+#include "lib/util/samba_util.h"
+#include "lib/util/sys_popen.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/debug.h"
+
+/**
+ * Read one line (data until next newline or eof) and allocate it
+ */
+_PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
+{
+ char *data = NULL;
+ ssize_t alloc_size = 0, offset = 0, ret;
+ int p;
+
+ if (hint <= 0) hint = 0x100;
+
+ do {
+ alloc_size += hint;
+
+ data = talloc_realloc(mem_ctx, data, char, alloc_size);
+
+ if (!data)
+ return NULL;
+
+ ret = read(fd, data + offset, hint);
+
+ if (ret == 0) {
+ return NULL;
+ }
+
+ if (ret == -1) {
+ talloc_free(data);
+ return NULL;
+ }
+
+ /* Find newline */
+ for (p = 0; p < ret; p++) {
+ if (data[offset + p] == '\n')
+ break;
+ }
+
+ if (p < ret) {
+ data[offset + p] = '\0';
+
+ /* Go back to position of newline */
+ lseek(fd, p - ret + 1, SEEK_CUR);
+ return data;
+ }
+
+ offset += ret;
+
+ } while ((size_t)ret == hint);
+
+ data[offset] = '\0';
+
+ return data;
+}
+
+char *fgets_slash(TALLOC_CTX *mem_ctx, char *s2, size_t maxlen, FILE *f)
+{
+ char *s = s2;
+ size_t len = 0;
+ int c;
+ bool start_of_line = true;
+
+ if (feof(f)) {
+ return NULL;
+ }
+
+ if (maxlen < 2) {
+ return NULL;
+ }
+
+ if (s2 == NULL) {
+ maxlen = MIN(maxlen,8);
+ s = talloc_array(mem_ctx, char, maxlen);
+ }
+
+ if (s == NULL) {
+ return NULL;
+ }
+
+ *s = 0;
+
+ while (len < maxlen-1) {
+ c = getc(f);
+ switch (c)
+ {
+ case '\r':
+ break;
+ case '\n':
+ while (len > 0 && s[len-1] == ' ') {
+ s[--len] = 0;
+ }
+ if (len > 0 && s[len-1] == '\\') {
+ s[--len] = 0;
+ start_of_line = true;
+ break;
+ }
+ return s;
+ case EOF:
+ if (len <= 0 && (s2 == NULL)) {
+ TALLOC_FREE(s);
+ }
+ return (len>0) ? s : NULL;
+ case ' ':
+ if (start_of_line) {
+ break;
+ }
+
+ FALL_THROUGH;
+ default:
+ start_of_line = false;
+ s[len++] = c;
+ s[len] = 0;
+ }
+ if ((s2 == NULL) && (len > maxlen-3)) {
+ size_t m;
+ char *t;
+
+ m = maxlen * 2;
+ if (m < maxlen) {
+ DBG_ERR("length overflow\n");
+ TALLOC_FREE(s);
+ return NULL;
+ }
+ maxlen = m;
+
+ t = talloc_realloc(mem_ctx, s, char, maxlen);
+ if (t == NULL) {
+ DBG_ERR("failed to expand buffer!\n");
+ TALLOC_FREE(s);
+ return NULL;
+ }
+
+ s = t;
+ }
+ }
+
+ return s;
+}
+
+/**
+load a file into memory from a fd.
+**/
+_PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ctx)
+{
+ FILE *file;
+ char *p = NULL;
+ size_t size = 0;
+ size_t chunk = 1024;
+ int err;
+ int fd_dup;
+
+ if (maxsize == 0) {
+ maxsize = SIZE_MAX;
+ }
+
+ fd_dup = dup(fd);
+ if (fd_dup == -1) {
+ return NULL;
+ }
+
+ file = fdopen(fd_dup, "r");
+ if (file == NULL) {
+ close(fd_dup);
+ return NULL;
+ }
+
+ while (size < maxsize) {
+ size_t newbufsize;
+ size_t nread;
+
+ chunk = MIN(chunk, (maxsize - size));
+
+ newbufsize = size + (chunk+1); /* chunk+1 can't overflow */
+ if (newbufsize < size) {
+ goto fail; /* overflow */
+ }
+
+ p = talloc_realloc(mem_ctx, p, char, newbufsize);
+ if (p == NULL) {
+ goto fail;
+ }
+
+ nread = fread(p+size, 1, chunk, file);
+ size += nread;
+
+ if (nread != chunk) {
+ break;
+ }
+ }
+
+ err = ferror(file);
+ if (err != 0) {
+ goto fail;
+ }
+
+ p[size] = '\0';
+
+ if (psize != NULL) {
+ *psize = size;
+ }
+
+ fclose(file);
+ return p;
+
+fail:
+ TALLOC_FREE(p);
+ fclose(file);
+ return NULL;
+}
+
+/**
+load a file into memory
+**/
+_PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx)
+{
+ int fd;
+ char *p;
+
+ if (!fname || !*fname) return NULL;
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) return NULL;
+
+ p = fd_load(fd, size, maxsize, mem_ctx);
+
+ close(fd);
+
+ return p;
+}
+
+/**
+parse a buffer into lines
+'p' will be freed on error, and otherwise will be made a child of the returned array
+**/
+static char **file_lines_parse_internal(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
+{
+ unsigned int i;
+ char *s, **ret;
+
+ if (!p) return NULL;
+
+ for (s = p, i=0; s < p+size; s++) {
+ if (s[0] == '\n') i++;
+ }
+
+ ret = talloc_zero_array(mem_ctx, char *, i+2);
+ if (!ret) {
+ talloc_free(p);
+ return NULL;
+ }
+
+ talloc_steal(ret, p);
+
+ ret[0] = p;
+ for (s = p, i=1; s < p+size; s++) {
+ if (s[0] == '\n') {
+ s[0] = 0;
+ ret[i] = s+1;
+ i++;
+ }
+ if (s[0] == '\r') s[0] = 0;
+ }
+
+ /* remove any blank lines at the end */
+ while (i > 0 && ret[i-1][0] == 0) {
+ i--;
+ }
+
+ if (numlines) *numlines = i;
+
+ return ret;
+}
+
+
+/**
+load a file into memory and return an array of pointers to lines in the file
+must be freed with talloc_free().
+**/
+_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
+{
+ char *p;
+ size_t size;
+
+ p = file_load(fname, &size, maxsize, mem_ctx);
+ if (!p) return NULL;
+
+ return file_lines_parse_internal(p, size, numlines, mem_ctx);
+}
+
+/**
+load a fd into memory and return an array of pointers to lines in the file
+must be freed with talloc_free(). If convert is true calls unix_to_dos on
+the list.
+**/
+_PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
+{
+ char *p;
+ size_t size;
+
+ p = fd_load(fd, &size, maxsize, mem_ctx);
+ if (!p) return NULL;
+
+ return file_lines_parse_internal(p, size, numlines, mem_ctx);
+}
+
+_PUBLIC_ char **file_lines_parse(const char *p_in,
+ size_t size,
+ int *numlines,
+ TALLOC_CTX *mem_ctx)
+{
+ /*
+ * Copy the incoming string so it can end up
+ * being owned by the returned pointer and
+ * freed when that is.
+ */
+ char *p = talloc_strdup(mem_ctx, p_in);
+ if (p == NULL) {
+ return NULL;
+ }
+ return file_lines_parse_internal(p, size, numlines, mem_ctx);
+}
+
+_PUBLIC_ bool file_save_mode(const char *fname, const void *packet,
+ size_t length, mode_t mode)
+{
+ ssize_t num_written;
+ int fd;
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, mode);
+ if (fd == -1) {
+ return false;
+ }
+ num_written = write(fd, packet, length);
+ if (num_written == -1 || (size_t)num_written != length) {
+ close(fd);
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+/**
+ save a lump of data into a file. Mostly used for debugging
+*/
+_PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length)
+{
+ return file_save_mode(fname, packet, length, 0644);
+}
+
+_PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap)
+{
+ char *p;
+ int len, ret;
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ len = vasprintf(&p, format, ap2);
+ va_end(ap2);
+ if (len <= 0) return len;
+ ret = write(fd, p, len);
+ SAFE_FREE(p);
+ return ret;
+}
+
+_PUBLIC_ int fdprintf(int fd, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vfdprintf(fd, format, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+/*
+ compare two files, return true if the two files have the same content
+ */
+bool file_compare(const char *path1, const char *path2)
+{
+ FILE *f1 = NULL, *f2 = NULL;
+ uint8_t buf1[1024], buf2[1024];
+ bool ret = false;
+
+ f1 = fopen(path1, "r");
+ if (f1 == NULL) {
+ goto done;
+ }
+ f2 = fopen(path2, "r");
+ if (f2 == NULL) {
+ goto done;
+ }
+
+ while (!feof(f1)) {
+ size_t n1 = fread(buf1, 1, sizeof(buf1), f1);
+ size_t n2 = fread(buf2, 1, sizeof(buf2), f2);
+
+ if (n1 != n2) {
+ goto done;
+ }
+ if (n1 == 0) {
+ ret = (feof(f1) && feof(f2));
+ goto done;
+ }
+ if (memcmp(buf1, buf2, n1) != 0) {
+ goto done;
+ }
+ if (n1 < sizeof(buf1)) {
+ bool has_error = (ferror(f1) || ferror(f2));
+ if (has_error) {
+ goto done;
+ }
+ }
+ }
+ ret = true;
+done:
+ if (f2 != NULL) {
+ fclose(f2);
+ }
+ if (f1 != NULL) {
+ fclose(f1);
+ }
+ return ret;
+}
+
+/**
+ Load from a pipe into memory.
+**/
+char *file_ploadv(char * const argl[], size_t *size)
+{
+ int fd, n;
+ char *p = NULL;
+ char buf[1024];
+ size_t total;
+
+ fd = sys_popenv(argl);
+ if (fd == -1) {
+ return NULL;
+ }
+
+ total = 0;
+
+ while ((n = sys_read(fd, buf, sizeof(buf))) > 0) {
+ p = talloc_realloc(NULL, p, char, total + n + 1);
+ if (p == NULL) {
+ DBG_ERR("failed to expand buffer!\n");
+ close(fd);
+ return NULL;
+ }
+ memcpy(p+total, buf, n);
+ total += n;
+ }
+
+ if (p != NULL) {
+ p[total] = 0;
+ }
+
+ /*
+ * FIXME: Perhaps ought to check that the command completed
+ * successfully (returned 0); if not the data may be
+ * truncated.
+ */
+ sys_pclose(fd);
+
+ if (size) {
+ *size = total;
+ }
+
+ return p;
+}
diff --git a/lib/util/util_id.c b/lib/util/util_id.c
new file mode 100644
index 0000000..19486f9
--- /dev/null
+++ b/lib/util/util_id.c
@@ -0,0 +1,89 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Helper routines for uid and gid arrays
+
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/samba_util.h"
+
+/****************************************************************************
+ Add a gid to an array of gids if it's not already there.
+****************************************************************************/
+
+bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid,
+ gid_t **gids, uint32_t *num_gids)
+{
+ uint32_t i;
+
+ if ((*num_gids != 0) && (*gids == NULL)) {
+ /*
+ * A former call to this routine has failed to allocate memory
+ */
+ return false;
+ }
+
+ for (i=0; i<*num_gids; i++) {
+ if ((*gids)[i] == gid) {
+ return true;
+ }
+ }
+
+ *gids = talloc_realloc(mem_ctx, *gids, gid_t, *num_gids+1);
+ if (*gids == NULL) {
+ *num_gids = 0;
+ return false;
+ }
+
+ (*gids)[*num_gids] = gid;
+ *num_gids += 1;
+ return true;
+}
+
+/****************************************************************************
+ Add a uid to an array of uids if it's not already there.
+****************************************************************************/
+
+bool add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid,
+ uid_t **uids, uint32_t *num_uids)
+{
+ uint32_t i;
+
+ if ((*num_uids != 0) && (*uids == NULL)) {
+ /*
+ * A former call to this routine has failed to allocate memory
+ */
+ return false;
+ }
+
+ for (i=0; i<*num_uids; i++) {
+ if ((*uids)[i] == uid) {
+ return true;
+ }
+ }
+
+ *uids = talloc_realloc(mem_ctx, *uids, uid_t, *num_uids+1);
+ if (*uids == NULL) {
+ *num_uids = 0;
+ return false;
+ }
+
+ (*uids)[*num_uids] = uid;
+ *num_uids += 1;
+ return true;
+}
diff --git a/lib/util/util_ldb.c b/lib/util/util_ldb.c
new file mode 100644
index 0000000..1fd5422
--- /dev/null
+++ b/lib/util/util_ldb.c
@@ -0,0 +1,114 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common share info functions
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Tim Potter 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <ldb.h>
+#include "lib/util/util_ldb.h"
+#include "lib/util/debug.h"
+
+/*
+ * search the LDB for the specified attributes - va_list variant
+ */
+int gendb_search_v(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *basedn,
+ struct ldb_message ***msgs,
+ const char * const *attrs,
+ const char *format,
+ va_list ap)
+{
+ enum ldb_scope scope = LDB_SCOPE_SUBTREE;
+ struct ldb_result *res;
+ char *expr = NULL;
+ int ret;
+
+ if (format) {
+ expr = talloc_vasprintf(mem_ctx, format, ap);
+ if (expr == NULL) {
+ return -1;
+ }
+ } else {
+ scope = LDB_SCOPE_BASE;
+ }
+
+ res = NULL;
+
+ ret = ldb_search(ldb, mem_ctx, &res, basedn, scope, attrs,
+ expr?"%s":NULL, expr);
+
+ if (ret == LDB_SUCCESS) {
+ DBG_DEBUG("%s %s -> %d\n",
+ basedn?ldb_dn_get_linearized(basedn):"NULL",
+ expr?expr:"NULL", res->count);
+
+ ret = res->count;
+ if (msgs != NULL) {
+ *msgs = talloc_steal(mem_ctx, res->msgs);
+ }
+ talloc_free(res);
+ } else if (scope == LDB_SCOPE_BASE && ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ret = 0;
+ if (msgs != NULL) *msgs = NULL;
+ } else {
+ DBG_INFO("search failed: %s\n",
+ ldb_errstring(ldb));
+ ret = -1;
+ if (msgs != NULL) *msgs = NULL;
+ }
+
+ talloc_free(expr);
+
+ return ret;
+}
+
+/*
+ * search the LDB for the specified attributes - varargs variant
+ */
+int gendb_search(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *basedn,
+ struct ldb_message ***res,
+ const char * const *attrs,
+ const char *format, ...)
+{
+ va_list ap;
+ int count;
+
+ va_start(ap, format);
+ count = gendb_search_v(ldb, mem_ctx, basedn, res, attrs, format, ap);
+ va_end(ap);
+
+ return count;
+}
+
+/*
+ * search the LDB for a specified record (by DN)
+ */
+int gendb_search_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_message ***res,
+ const char * const *attrs)
+{
+ return gendb_search(ldb, mem_ctx, dn, res, attrs, NULL);
+}
+
diff --git a/lib/util/util_ldb.h b/lib/util/util_ldb.h
new file mode 100644
index 0000000..6691644
--- /dev/null
+++ b/lib/util/util_ldb.h
@@ -0,0 +1,50 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common share info functions
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Tim Potter 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef __LIB_UTIL_UTIL_LDB_H__
+#define __LIB_UTIL_UTIL_LDB_H__
+
+struct ldb_dn;
+
+/* The following definitions come from lib/util/util_ldb.c */
+
+int gendb_search_v(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *basedn,
+ struct ldb_message ***msgs,
+ const char * const *attrs,
+ const char *format,
+ va_list ap) PRINTF_ATTRIBUTE(6,0);
+int gendb_search(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *basedn,
+ struct ldb_message ***res,
+ const char * const *attrs,
+ const char *format, ...) PRINTF_ATTRIBUTE(6,7);
+int gendb_search_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ struct ldb_message ***res,
+ const char * const *attrs);
+
+#endif /* __LIB_UTIL_UTIL_LDB_H__ */
diff --git a/lib/util/util_net.c b/lib/util/util_net.c
new file mode 100644
index 0000000..48c9552
--- /dev/null
+++ b/lib/util/util_net.c
@@ -0,0 +1,1240 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1992-2007
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+ Copyright (C) Tim Potter 2000-2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/locale.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "lib/util/select.h"
+#include "lib/util/util_net.h"
+
+#undef strcasecmp
+#undef strncasecmp
+
+/*******************************************************************
+ Set an address to INADDR_ANY.
+******************************************************************/
+
+void zero_sockaddr(struct sockaddr_storage *pss)
+{
+ /* Ensure we're at least a valid sockaddr-storage. */
+ *pss = (struct sockaddr_storage) { .ss_family = AF_INET };
+}
+
+static char *normalize_ipv6_literal(const char *str, char *buf, size_t *_len)
+{
+#define IPv6_LITERAL_NET ".ipv6-literal.net"
+ const size_t llen = sizeof(IPv6_LITERAL_NET) - 1;
+ size_t len = *_len;
+ int cmp;
+ size_t i;
+ size_t idx_chars = 0;
+ size_t cnt_delimiter = 0;
+ size_t cnt_chars = 0;
+
+ if (len <= llen) {
+ return NULL;
+ }
+
+ /* ignore a trailing '.' */
+ if (str[len - 1] == '.') {
+ len -= 1;
+ }
+
+ len -= llen;
+ if (len >= INET6_ADDRSTRLEN) {
+ return NULL;
+ }
+ if (len < 2) {
+ return NULL;
+ }
+
+ cmp = strncasecmp(&str[len], IPv6_LITERAL_NET, llen);
+ if (cmp != 0) {
+ return NULL;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (idx_chars != 0) {
+ break;
+ }
+
+ switch (str[i]) {
+ case '-':
+ buf[i] = ':';
+ cnt_chars = 0;
+ cnt_delimiter += 1;
+ break;
+ case 's':
+ buf[i] = SCOPE_DELIMITER;
+ idx_chars += 1;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'A':
+ case 'b':
+ case 'B':
+ case 'c':
+ case 'C':
+ case 'd':
+ case 'D':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ buf[i] = str[i];
+ cnt_chars += 1;
+ break;
+ default:
+ return NULL;
+ }
+ if (cnt_chars > 4) {
+ return NULL;
+ }
+ if (cnt_delimiter > 7) {
+ return NULL;
+ }
+ }
+
+ if (cnt_delimiter < 2) {
+ return NULL;
+ }
+
+ for (; idx_chars != 0 && i < len; i++) {
+ switch (str[i]) {
+ case SCOPE_DELIMITER:
+ case ':':
+ return NULL;
+ default:
+ buf[i] = str[i];
+ idx_chars += 1;
+ break;
+ }
+ }
+
+ if (idx_chars == 1) {
+ return NULL;
+ }
+
+ buf[i] = '\0';
+ *_len = len;
+ return buf;
+}
+
+/**
+ * Wrap getaddrinfo...
+ */
+bool interpret_string_addr_internal(struct addrinfo **ppres,
+ const char *str, int flags)
+{
+ int ret;
+ struct addrinfo hints;
+#if defined(HAVE_IPV6)
+ char addr[INET6_ADDRSTRLEN*2] = { 0, };
+ unsigned int scope_id = 0;
+ size_t len = strlen(str);
+#endif
+
+ ZERO_STRUCT(hints);
+
+ /* By default make sure it supports TCP. */
+ hints.ai_socktype = SOCK_STREAM;
+
+ /* always try as a numeric host first. This prevents unnecessary name
+ * lookups, and also ensures we accept IPv6 addresses */
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+#if defined(HAVE_IPV6)
+ if (len < sizeof(addr)) {
+ char *p = NULL;
+
+ p = normalize_ipv6_literal(str, addr, &len);
+ if (p != NULL) {
+ hints.ai_family = AF_INET6;
+ str = p;
+ }
+ }
+
+ if (strchr_m(str, ':')) {
+ char *p = strchr_m(str, SCOPE_DELIMITER);
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifname.
+ */
+
+ if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
+ /* Length of string we want to copy.
+ This is IP:v6:addr (removing the %ifname).
+ */
+ len = PTR_DIFF(p,str);
+
+ if (len+1 > sizeof(addr)) {
+ /* string+nul too long for array. */
+ return false;
+ }
+ if (str != addr) {
+ memcpy(addr, str, len);
+ }
+ addr[len] = '\0';
+
+ str = addr;
+ }
+ }
+#endif
+
+ ret = getaddrinfo(str, NULL, &hints, ppres);
+ if (ret == 0) {
+#if defined(HAVE_IPV6)
+ struct sockaddr_in6 *ps6 = NULL;
+
+ if (scope_id == 0) {
+ return true;
+ }
+ if (ppres == NULL) {
+ return true;
+ }
+ if ((*ppres) == NULL) {
+ return true;
+ }
+ if ((*ppres)->ai_addr->sa_family != AF_INET6) {
+ return true;
+ }
+
+ ps6 = (struct sockaddr_in6 *)(*ppres)->ai_addr;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
+ ps6->sin6_scope_id == 0) {
+ ps6->sin6_scope_id = scope_id;
+ }
+#endif
+
+ return true;
+ }
+
+ hints.ai_flags = flags;
+
+ /* Linux man page on getaddrinfo() says port will be
+ uninitialized when service string is NULL */
+
+ ret = getaddrinfo(str, NULL,
+ &hints,
+ ppres);
+
+ if (ret) {
+ DEBUG(3, ("interpret_string_addr_internal: "
+ "getaddrinfo failed for name %s (flags %d) [%s]\n",
+ str, flags, gai_strerror(ret)));
+ return false;
+ }
+ return true;
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Takes a flag which allows it to
+ prefer an IPv4 address (needed for DC's).
+******************************************************************/
+
+static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
+ const char *str,
+ int flags,
+ bool prefer_ipv4)
+{
+ struct addrinfo *res = NULL;
+ int int_flags;
+
+ zero_sockaddr(pss);
+
+ if (flags & AI_NUMERICHOST) {
+ int_flags = flags;
+ } else {
+ int_flags = flags|AI_ADDRCONFIG;
+ }
+
+ if (!interpret_string_addr_internal(&res, str, int_flags)) {
+ return false;
+ }
+ if (!res) {
+ return false;
+ }
+
+ if (prefer_ipv4) {
+ struct addrinfo *p;
+
+ for (p = res; p; p = p->ai_next) {
+ if (p->ai_family == AF_INET) {
+ memcpy(pss, p->ai_addr, p->ai_addrlen);
+ break;
+ }
+ }
+ if (p == NULL) {
+ /* Copy the first sockaddr. */
+ memcpy(pss, res->ai_addr, res->ai_addrlen);
+ }
+ } else {
+ /* Copy the first sockaddr. */
+ memcpy(pss, res->ai_addr, res->ai_addrlen);
+ }
+
+ freeaddrinfo(res);
+ return true;
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Address agnostic version.
+******************************************************************/
+
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags)
+{
+ return interpret_string_addr_pref(pss,
+ str,
+ flags,
+ false);
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Version that prefers IPv4.
+******************************************************************/
+
+bool interpret_string_addr_prefer_ipv4(struct sockaddr_storage *pss,
+ const char *str,
+ int flags)
+{
+ return interpret_string_addr_pref(pss,
+ str,
+ flags,
+ true);
+}
+
+/**
+ * Interpret an internet address or name into an IP address in 4 byte form.
+ * RETURNS IN NETWORK BYTE ORDER (big endian).
+ */
+
+uint32_t interpret_addr(const char *str)
+{
+ uint32_t ret;
+
+ /* If it's in the form of an IP address then
+ * get the lib to interpret it */
+ if (is_ipaddress_v4(str)) {
+ struct in_addr dest;
+
+ if (inet_pton(AF_INET, str, &dest) <= 0) {
+ /* Error - this shouldn't happen ! */
+ DEBUG(0,("interpret_addr: inet_pton failed "
+ "host %s\n",
+ str));
+ return 0;
+ }
+ ret = dest.s_addr; /* NETWORK BYTE ORDER ! */
+ } else {
+ /* Otherwise assume it's a network name of some sort and use
+ getaddrinfo. */
+ struct addrinfo *res = NULL;
+ struct addrinfo *res_list = NULL;
+ if (!interpret_string_addr_internal(&res_list,
+ str,
+ AI_ADDRCONFIG)) {
+ DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
+ return 0;
+ }
+
+ /* Find the first IPv4 address. */
+ for (res = res_list; res; res = res->ai_next) {
+ if (res->ai_family != AF_INET) {
+ continue;
+ }
+ if (res->ai_addr == NULL) {
+ continue;
+ }
+ break;
+ }
+ if(res == NULL) {
+ DEBUG(3,("interpret_addr: host address is "
+ "invalid for host %s\n",str));
+ if (res_list) {
+ freeaddrinfo(res_list);
+ }
+ return 0;
+ }
+ memcpy((char *)&ret,
+ &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
+ sizeof(ret));
+ if (res_list) {
+ freeaddrinfo(res_list);
+ }
+ }
+
+ /* This is so bogus - all callers need fixing... JRA. */
+ if (ret == (uint32_t)-1) {
+ return 0;
+ }
+
+ return ret;
+}
+
+/**
+ A convenient addition to interpret_addr().
+**/
+_PUBLIC_ struct in_addr interpret_addr2(const char *str)
+{
+ struct in_addr ret;
+ uint32_t a = interpret_addr(str);
+ ret.s_addr = a;
+ return ret;
+}
+
+/**
+ Check if an IP is the 0.0.0.0.
+**/
+
+_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip)
+{
+ return ip.s_addr == 0;
+}
+
+/**
+ Are two IPs on the same subnet?
+**/
+
+_PUBLIC_ bool same_net_v4(struct in_addr ip1, struct in_addr ip2, struct in_addr mask)
+{
+ uint32_t net1,net2,nmask;
+
+ nmask = ntohl(mask.s_addr);
+ net1 = ntohl(ip1.s_addr);
+ net2 = ntohl(ip2.s_addr);
+
+ return((net1 & nmask) == (net2 & nmask));
+}
+
+/**
+ * Return true if a string could be an IPv4 address.
+ */
+
+bool is_ipaddress_v4(const char *str)
+{
+ int ret = -1;
+ struct in_addr dest;
+
+ ret = inet_pton(AF_INET, str, &dest);
+ if (ret > 0) {
+ return true;
+ }
+ return false;
+}
+
+bool is_ipv6_literal(const char *str)
+{
+#if defined(HAVE_IPV6)
+ char buf[INET6_ADDRSTRLEN*2] = { 0, };
+ size_t len = strlen(str);
+ char *p = NULL;
+
+ if (len >= sizeof(buf)) {
+ return false;
+ }
+
+ p = normalize_ipv6_literal(str, buf, &len);
+ if (p == NULL) {
+ return false;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+/**
+ * Return true if a string could be a IPv6 address.
+ */
+
+bool is_ipaddress_v6(const char *str)
+{
+#if defined(HAVE_IPV6)
+ int ret = -1;
+ char *p = NULL;
+ char buf[INET6_ADDRSTRLEN] = { 0, };
+ size_t len;
+ const char *addr = str;
+ const char *idxs = NULL;
+ unsigned int idx = 0;
+ struct in6_addr ip6;
+
+ p = strchr_m(str, ':');
+ if (p == NULL) {
+ return is_ipv6_literal(str);
+ }
+
+ p = strchr_m(str, SCOPE_DELIMITER);
+ if (p && (p > str)) {
+ len = PTR_DIFF(p, str);
+ idxs = p + 1;
+ } else {
+ len = strlen(str);
+ }
+
+ if (len >= sizeof(buf)) {
+ return false;
+ }
+ if (idxs != NULL) {
+ strncpy(buf, str, len);
+ addr = buf;
+ }
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifidx.
+ */
+ if (idxs != NULL) {
+ char c;
+
+ ret = sscanf(idxs, "%5u%c", &idx, &c);
+ if (ret != 1) {
+ idx = 0;
+ }
+
+ if (idx > 0 && idx < UINT16_MAX) {
+ /* a valid index */
+ idxs = NULL;
+ }
+ }
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifname.
+ */
+ if (idxs != NULL) {
+ idx = if_nametoindex(idxs);
+
+ if (idx > 0) {
+ /* a valid index */
+ idxs = NULL;
+ }
+ }
+
+ if (idxs != NULL) {
+ return false;
+ }
+
+ ret = inet_pton(AF_INET6, addr, &ip6);
+ if (ret <= 0) {
+ return false;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+/**
+ * Return true if a string could be an IPv4 or IPv6 address.
+ */
+
+bool is_ipaddress(const char *str)
+{
+ return is_ipaddress_v4(str) || is_ipaddress_v6(str);
+}
+
+/**
+ * Is a sockaddr a broadcast address ?
+ */
+
+bool is_broadcast_addr(const struct sockaddr *pss)
+{
+#if defined(HAVE_IPV6)
+ if (pss->sa_family == AF_INET6) {
+ const struct in6_addr *sin6 =
+ &((const struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_MULTICAST(sin6);
+ }
+#endif
+ if (pss->sa_family == AF_INET) {
+ uint32_t addr =
+ ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
+ return addr == INADDR_BROADCAST;
+ }
+ return false;
+}
+
+/**
+ * Check if an IPv7 is 127.0.0.1
+ */
+bool is_loopback_ip_v4(struct in_addr ip)
+{
+ struct in_addr a;
+ a.s_addr = htonl(INADDR_LOOPBACK);
+ return(ip.s_addr == a.s_addr);
+}
+
+/**
+ * Check if a struct sockaddr is the loopback address.
+ */
+bool is_loopback_addr(const struct sockaddr *pss)
+{
+#if defined(HAVE_IPV6)
+ if (pss->sa_family == AF_INET6) {
+ const struct in6_addr *pin6 =
+ &((const struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_LOOPBACK(pin6);
+ }
+#endif
+ if (pss->sa_family == AF_INET) {
+ const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
+ return is_loopback_ip_v4(*pin);
+ }
+ return false;
+}
+
+/**
+ * Check if a struct sockaddr has an unspecified address.
+ */
+bool is_zero_addr(const struct sockaddr_storage *pss)
+{
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ const struct in6_addr *pin6 =
+ &((const struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_UNSPECIFIED(pin6);
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
+ return is_zero_ip_v4(*pin);
+ }
+ if (pss->ss_family == AF_UNSPEC) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Set an IP to 0.0.0.0.
+ */
+void zero_ip_v4(struct in_addr *ip)
+{
+ ZERO_STRUCTP(ip);
+}
+
+bool is_linklocal_addr(const struct sockaddr_storage *pss)
+{
+#ifdef HAVE_IPV6
+ if (pss->ss_family == AF_INET6) {
+ const struct in6_addr *pin6 =
+ &((const struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_LINKLOCAL(pin6);
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ const struct in_addr *pin =
+ &((const struct sockaddr_in *)pss)->sin_addr;
+ struct in_addr ll_addr;
+ struct in_addr mask_addr;
+
+ /* 169.254.0.0/16, is link local, see RFC 3927 */
+ ll_addr.s_addr = 0xa9fe0000;
+ mask_addr.s_addr = 0xffff0000;
+ return same_net_v4(*pin, ll_addr, mask_addr);
+ }
+ return false;
+}
+
+/**
+ * Convert an IPv4 struct in_addr to a struct sockaddr_storage.
+ */
+void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in_addr ip)
+{
+ struct sockaddr_in *sa = (struct sockaddr_in *)ss;
+ ZERO_STRUCTP(ss);
+ sa->sin_family = AF_INET;
+ sa->sin_addr = ip;
+}
+
+#if defined(HAVE_IPV6)
+/**
+ * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
+ */
+void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in6_addr ip)
+{
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
+ memset(ss, '\0', sizeof(*ss));
+ sa->sin6_family = AF_INET6;
+ sa->sin6_addr = ip;
+}
+#endif
+
+/**
+ * Are two IPs on the same subnet?
+ */
+bool same_net(const struct sockaddr *ip1,
+ const struct sockaddr *ip2,
+ const struct sockaddr *mask)
+{
+ if (ip1->sa_family != ip2->sa_family) {
+ /* Never on the same net. */
+ return false;
+ }
+
+#if defined(HAVE_IPV6)
+ if (ip1->sa_family == AF_INET6) {
+ struct sockaddr_in6 ip1_6 = *(const struct sockaddr_in6 *)ip1;
+ struct sockaddr_in6 ip2_6 = *(const struct sockaddr_in6 *)ip2;
+ struct sockaddr_in6 mask_6 = *(const struct sockaddr_in6 *)mask;
+ char *p1 = (char *)&ip1_6.sin6_addr;
+ char *p2 = (char *)&ip2_6.sin6_addr;
+ char *m = (char *)&mask_6.sin6_addr;
+ size_t i;
+
+ for (i = 0; i < sizeof(struct in6_addr); i++) {
+ *p1++ &= *m;
+ *p2++ &= *m;
+ m++;
+ }
+ return (memcmp(&ip1_6.sin6_addr,
+ &ip2_6.sin6_addr,
+ sizeof(struct in6_addr)) == 0);
+ }
+#endif
+ if (ip1->sa_family == AF_INET) {
+ return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
+ ((const struct sockaddr_in *)ip2)->sin_addr,
+ ((const struct sockaddr_in *)mask)->sin_addr);
+ }
+ return false;
+}
+
+/**
+ * Are two sockaddr 's the same family and address ? Ignore port etc.
+ */
+
+bool sockaddr_equal(const struct sockaddr *ip1,
+ const struct sockaddr *ip2)
+{
+ if (ip1->sa_family != ip2->sa_family) {
+ /* Never the same. */
+ return false;
+ }
+
+#if defined(HAVE_IPV6)
+ if (ip1->sa_family == AF_INET6) {
+ return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
+ &((const struct sockaddr_in6 *)ip2)->sin6_addr,
+ sizeof(struct in6_addr)) == 0);
+ }
+#endif
+ if (ip1->sa_family == AF_INET) {
+ return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
+ &((const struct sockaddr_in *)ip2)->sin_addr,
+ sizeof(struct in_addr)) == 0);
+ }
+ return false;
+}
+
+/**
+ * Is an IP address the INADDR_ANY or in6addr_any value ?
+ */
+bool is_address_any(const struct sockaddr *psa)
+{
+#if defined(HAVE_IPV6)
+ if (psa->sa_family == AF_INET6) {
+ const struct sockaddr_in6 *si6 = (const struct sockaddr_in6 *)psa;
+ if (memcmp(&in6addr_any,
+ &si6->sin6_addr,
+ sizeof(in6addr_any)) == 0) {
+ return true;
+ }
+ return false;
+ }
+#endif
+ if (psa->sa_family == AF_INET) {
+ const struct sockaddr_in *si = (const struct sockaddr_in *)psa;
+ if (si->sin_addr.s_addr == INADDR_ANY) {
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
+{
+#if defined(HAVE_IPV6)
+ if (psa->sa_family == AF_INET6) {
+ ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
+ }
+#endif
+ if (psa->sa_family == AF_INET) {
+ ((struct sockaddr_in *)psa)->sin_port = htons(port);
+ }
+}
+
+
+/****************************************************************************
+ Get a port number in host byte order from a sockaddr_storage.
+****************************************************************************/
+
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
+{
+ uint16_t port = 0;
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ /* IPv6 */
+ const struct sockaddr_in6 *sa6 =
+ (const struct sockaddr_in6 *)pss;
+ port = ntohs(sa6->sin6_port);
+#endif
+ } else {
+ const struct sockaddr_in *sa =
+ (const struct sockaddr_in *)pss;
+ port = ntohs(sa->sin_port);
+ }
+ return port;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_sockaddr_len(char *dest,
+ size_t destlen,
+ const struct sockaddr *psa,
+ socklen_t psalen)
+{
+ if (destlen > 0) {
+ dest[0] = '\0';
+ }
+ (void)sys_getnameinfo(psa,
+ psalen,
+ dest, destlen,
+ NULL, 0,
+ NI_NUMERICHOST);
+ return dest;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_sockaddr(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa)
+{
+ return print_sockaddr_len(dest, destlen, (const struct sockaddr *)psa,
+ sizeof(struct sockaddr_storage));
+}
+
+/****************************************************************************
+ Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+ const struct sockaddr_storage *pss)
+{
+ char addr[INET6_ADDRSTRLEN];
+ char *dest = NULL;
+ int ret;
+
+ /* Linux getnameinfo() man pages says port is uninitialized if
+ service name is NULL. */
+
+ ret = sys_getnameinfo((const struct sockaddr *)pss,
+ sizeof(struct sockaddr_storage),
+ addr, sizeof(addr),
+ NULL, 0,
+ NI_NUMERICHOST);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ dest = talloc_asprintf(ctx, "[%s]", addr);
+#else
+ return NULL;
+#endif
+ } else {
+ dest = talloc_asprintf(ctx, "%s", addr);
+ }
+
+ return dest;
+}
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+typedef struct smb_socket_option {
+ const char *name;
+ int level;
+ int option;
+ int value;
+ int opttype;
+} smb_socket_option;
+
+static const smb_socket_option socket_options[] = {
+ {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
+ {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
+ {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
+#ifdef TCP_NODELAY
+ {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
+#endif
+#ifdef TCP_KEEPCNT
+ {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
+#endif
+#ifdef TCP_KEEPIDLE
+ {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
+#endif
+#ifdef TCP_KEEPINTVL
+ {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
+#endif
+#ifdef IPTOS_LOWDELAY
+ {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+ {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
+#endif
+#ifdef SO_REUSEPORT
+ {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
+#endif
+#ifdef SO_SNDBUF
+ {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+ {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+ {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+ {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+ {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+ {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
+#endif
+#ifdef TCP_FASTACK
+ {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
+#endif
+#ifdef TCP_QUICKACK
+ {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, 0, OPT_BOOL},
+#endif
+#ifdef TCP_NODELAYACK
+ {"TCP_NODELAYACK", IPPROTO_TCP, TCP_NODELAYACK, 0, OPT_BOOL},
+#endif
+#ifdef TCP_KEEPALIVE_THRESHOLD
+ {"TCP_KEEPALIVE_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, 0, OPT_INT},
+#endif
+#ifdef TCP_KEEPALIVE_ABORT_THRESHOLD
+ {"TCP_KEEPALIVE_ABORT_THRESHOLD", IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, 0, OPT_INT},
+#endif
+#ifdef TCP_DEFER_ACCEPT
+ {"TCP_DEFER_ACCEPT", IPPROTO_TCP, TCP_DEFER_ACCEPT, 0, OPT_INT},
+#endif
+#ifdef TCP_USER_TIMEOUT
+ {"TCP_USER_TIMEOUT", IPPROTO_TCP, TCP_USER_TIMEOUT, 0, OPT_INT},
+#endif
+ {NULL,0,0,0,0}};
+
+/****************************************************************************
+ Print socket options.
+****************************************************************************/
+
+static void print_socket_options(TALLOC_CTX *ctx, int s)
+{
+ const smb_socket_option *p = &socket_options[0];
+ char *str = NULL;
+
+ if (DEBUGLEVEL < 5) {
+ return;
+ }
+
+ str = talloc_strdup(ctx, "");
+ if (str == NULL) {
+ DBG_WARNING("talloc failed\n");
+ goto done;
+ }
+
+ for (; p->name != NULL; p++) {
+ int ret, val;
+ socklen_t vlen = sizeof(val);
+
+ ret = getsockopt(s, p->level, p->option, (void *)&val, &vlen);
+ if (ret == -1) {
+ DBG_INFO("Could not test socket option %s: %s.\n",
+ p->name, strerror(errno));
+ continue;
+ }
+
+ talloc_asprintf_addbuf(
+ &str,
+ "%s%s=%d",
+ str[0] != '\0' ? ", " : "",
+ p->name,
+ val);
+ }
+
+ DEBUG(5, ("socket options: %s\n", str));
+done:
+ TALLOC_FREE(str);
+ }
+
+/****************************************************************************
+ Set user socket options.
+****************************************************************************/
+
+void set_socket_options(int fd, const char *options)
+{
+ TALLOC_CTX *ctx = talloc_new(NULL);
+ char *tok;
+
+ while (next_token_talloc(ctx, &options, &tok," \t,")) {
+ int ret=0,i;
+ int value = 1;
+ char *p;
+ bool got_value = false;
+
+ if ((p = strchr_m(tok,'='))) {
+ *p = 0;
+ value = atoi(p+1);
+ got_value = true;
+ }
+
+ for (i=0;socket_options[i].name;i++)
+ if (strequal(socket_options[i].name,tok))
+ break;
+
+ if (!socket_options[i].name) {
+ DEBUG(0,("Unknown socket option %s\n",tok));
+ continue;
+ }
+
+ switch (socket_options[i].opttype) {
+ case OPT_BOOL:
+ case OPT_INT:
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,
+ (char *)&value,sizeof(int));
+ break;
+
+ case OPT_ON:
+ if (got_value)
+ DEBUG(0,("syntax error - %s "
+ "does not take a value\n",tok));
+
+ {
+ int on = socket_options[i].value;
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,
+ (char *)&on,sizeof(int));
+ }
+ break;
+ }
+
+ if (ret != 0) {
+ /* be aware that some systems like Solaris return
+ * EINVAL to a setsockopt() call when the client
+ * sent a RST previously - no need to worry */
+ DEBUG(2,("Failed to set socket option %s (Error %s)\n",
+ tok, strerror(errno) ));
+ }
+ }
+
+ print_socket_options(ctx, fd);
+ TALLOC_FREE(ctx);
+}
+
+/*
+ * Utility function that copes only with AF_INET and AF_INET6
+ * as that's all we're going to get out of DNS / NetBIOS / WINS
+ * name resolution functions.
+ */
+
+bool sockaddr_storage_to_samba_sockaddr(
+ struct samba_sockaddr *sa, const struct sockaddr_storage *ss)
+{
+ sa->u.ss = *ss;
+
+ switch (ss->ss_family) {
+ case AF_INET:
+ sa->sa_socklen = sizeof(struct sockaddr_in);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ sa->sa_socklen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool samba_sockaddr_set_port(struct samba_sockaddr *sa, uint16_t port)
+{
+ if (sa->u.sa.sa_family == AF_INET) {
+ sa->u.in.sin_port = htons(port);
+ return true;
+ }
+#ifdef HAVE_IPV6
+ if (sa->u.sa.sa_family == AF_INET6) {
+ sa->u.in6.sin6_port = htons(port);
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool samba_sockaddr_get_port(const struct samba_sockaddr *sa, uint16_t *port)
+{
+ if (sa->u.sa.sa_family == AF_INET) {
+ *port = ntohs(sa->u.in.sin_port);
+ return true;
+ }
+#ifdef HAVE_IPV6
+ if (sa->u.sa.sa_family == AF_INET6) {
+ *port = ntohs(sa->u.in6.sin6_port);
+ return true;
+ }
+#endif
+ return false;
+}
+
+int samba_socket_poll_error(int fd)
+{
+ struct pollfd pfd = {
+ .fd = fd,
+#ifdef POLLRDHUP
+ .events = POLLRDHUP, /* POLLERR and POLLHUP are not needed */
+#endif
+ };
+ int ret;
+
+ errno = 0;
+ ret = sys_poll_intr(&pfd, 1, 0);
+ if (ret == 0) {
+ return 0;
+ }
+ if (ret != 1) {
+ return POLLNVAL;
+ }
+
+ if (pfd.revents & POLLERR) {
+ return POLLERR;
+ }
+ if (pfd.revents & POLLHUP) {
+ return POLLHUP;
+ }
+#ifdef POLLRDHUP
+ if (pfd.revents & POLLRDHUP) {
+ return POLLRDHUP;
+ }
+#endif
+
+ /* should never be reached! */
+ return POLLNVAL;
+}
+
+int samba_socket_sock_error(int fd)
+{
+ int ret, error = 0;
+ socklen_t len = sizeof(error);
+
+ /*
+ * if no data is available check if the socket is in error state. For
+ * dgram sockets it's the way to return ICMP error messages of
+ * connected sockets to the caller.
+ */
+ ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
+ if (ret == -1) {
+ return ret;
+ }
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+int samba_socket_poll_or_sock_error(int fd)
+{
+ int ret;
+ int poll_error = 0;
+
+ poll_error = samba_socket_poll_error(fd);
+ if (poll_error == 0) {
+ return 0;
+ }
+
+#ifdef POLLRDHUP
+ if (poll_error == POLLRDHUP) {
+ errno = ECONNRESET;
+ return -1;
+ }
+#endif
+
+ if (poll_error == POLLHUP) {
+ errno = EPIPE;
+ return -1;
+ }
+
+ /*
+ * POLLERR and POLLNVAL fallback to
+ * getsockopt(fd, SOL_SOCKET, SO_ERROR)
+ * and force EPIPE as fallback.
+ */
+
+ errno = 0;
+ ret = samba_socket_sock_error(fd);
+ if (ret == 0) {
+ errno = EPIPE;
+ }
+
+ if (errno == 0) {
+ errno = EPIPE;
+ }
+
+ return -1;
+}
diff --git a/lib/util/util_net.h b/lib/util/util_net.h
new file mode 100644
index 0000000..1aed45a
--- /dev/null
+++ b/lib/util/util_net.h
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for Samba
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_UTIL_NET_H_
+#define _SAMBA_UTIL_NET_H_
+
+#include "system/network.h"
+
+struct samba_sockaddr {
+ socklen_t sa_socklen;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 in6;
+#endif
+ struct sockaddr_un un;
+ struct sockaddr_storage ss;
+ } u;
+};
+
+/* The following definitions come from lib/util/util_net.c */
+
+void zero_sockaddr(struct sockaddr_storage *pss);
+
+bool interpret_string_addr_internal(struct addrinfo **ppres,
+ const char *str, int flags);
+
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags);
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Version that prefers IPv4.
+******************************************************************/
+
+bool interpret_string_addr_prefer_ipv4(struct sockaddr_storage *pss,
+ const char *str,
+ int flags);
+
+void set_sockaddr_port(struct sockaddr *psa, uint16_t port);
+
+/**
+ Check if an IP is the 0.0.0.0.
+**/
+_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip);
+
+void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in_addr ip);
+#if defined(HAVE_IPV6)
+/**
+ * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
+ */
+void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in6_addr ip);
+#endif
+/**
+ Are two IPs on the same subnet?
+**/
+_PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
+
+/**
+ Return true if a string could be a pure IP address.
+**/
+_PUBLIC_ bool is_ipaddress(const char *str);
+
+bool is_broadcast_addr(const struct sockaddr *pss);
+bool is_loopback_ip_v4(struct in_addr ip);
+bool is_loopback_addr(const struct sockaddr *pss);
+bool is_zero_addr(const struct sockaddr_storage *pss);
+void zero_ip_v4(struct in_addr *ip);
+bool is_linklocal_addr(const struct sockaddr_storage *pss);
+/**
+ Interpret an internet address or name into an IP address in 4 byte form.
+**/
+_PUBLIC_ uint32_t interpret_addr(const char *str);
+
+/**
+ A convenient addition to interpret_addr().
+**/
+_PUBLIC_ struct in_addr interpret_addr2(const char *str);
+
+_PUBLIC_ bool is_ipaddress_v4(const char *str);
+_PUBLIC_ bool is_ipv6_literal(const char *str);
+_PUBLIC_ bool is_ipaddress_v6(const char *str);
+
+bool is_address_any(const struct sockaddr *psa);
+bool same_net(const struct sockaddr *ip1,
+ const struct sockaddr *ip2,
+ const struct sockaddr *mask);
+bool sockaddr_equal(const struct sockaddr *ip1,
+ const struct sockaddr *ip2);
+
+bool is_address_any(const struct sockaddr *psa);
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss);
+char *print_sockaddr_len(char *dest,
+ size_t destlen,
+ const struct sockaddr *psa,
+ socklen_t psalen);
+char *print_sockaddr(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa);
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+ const struct sockaddr_storage *pss);
+
+void set_socket_options(int fd, const char *options);
+
+bool sockaddr_storage_to_samba_sockaddr(
+ struct samba_sockaddr *sa, const struct sockaddr_storage *ss);
+bool samba_sockaddr_set_port(struct samba_sockaddr *sa, uint16_t port);
+bool samba_sockaddr_get_port(const struct samba_sockaddr *sa, uint16_t *port);
+
+/*
+ * check for POLLERR or POLL*HUP
+ */
+int samba_socket_poll_error(int fd);
+/*
+ * getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len)
+ */
+int samba_socket_sock_error(int fd);
+/*
+ * check for POLL*HUP and fallback to
+ * getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len)
+ */
+int samba_socket_poll_or_sock_error(int fd);
+
+#endif /* _SAMBA_UTIL_NET_H_ */
diff --git a/lib/util/util_paths.c b/lib/util/util_paths.c
new file mode 100644
index 0000000..ce93028
--- /dev/null
+++ b/lib/util/util_paths.c
@@ -0,0 +1,170 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2007
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) James Peach 2006
+ Copyright (c) 2020 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "dynconfig/dynconfig.h"
+#include "lib/util/util_paths.h"
+#include "system/passwd.h"
+#include "system/filesys.h"
+
+/**
+ * @brief Returns an absolute path to a file in the Samba modules directory.
+ *
+ * @param name File to find, relative to MODULESDIR.
+ *
+ * @retval Pointer to a string containing the full path.
+ **/
+
+char *modules_path(TALLOC_CTX *mem_ctx, const char *name)
+{
+ return talloc_asprintf(mem_ctx, "%s/%s", get_dyn_MODULESDIR(), name);
+}
+
+/**
+ * @brief Returns an absolute path to a file in the Samba data directory.
+ *
+ * @param name File to find, relative to CODEPAGEDIR.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+
+char *data_path(TALLOC_CTX *mem_ctx, const char *name)
+{
+ return talloc_asprintf(mem_ctx, "%s/%s", get_dyn_CODEPAGEDIR(), name);
+}
+
+/**
+ * @brief Returns the platform specific shared library extension.
+ *
+ * @retval Pointer to a const char * containing the extension.
+ **/
+
+const char *shlib_ext(void)
+{
+ return get_dyn_SHLIBEXT();
+}
+
+static char *get_user_home_dir(TALLOC_CTX *mem_ctx)
+{
+ struct passwd pwd = {0};
+ struct passwd *pwdbuf = NULL;
+ char *buf = NULL;
+ char *out = NULL;
+ long int initlen;
+ size_t len;
+ int rc;
+
+ initlen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (initlen == -1) {
+ len = 1024;
+ } else {
+ len = (size_t)initlen;
+ }
+ buf = talloc_size(mem_ctx, len);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ rc = getpwuid_r(getuid(), &pwd, buf, len, &pwdbuf);
+ while (rc == ERANGE) {
+ size_t newlen = 2 * len;
+ if (newlen < len) {
+ /* Overflow */
+ goto done;
+ }
+ len = newlen;
+ buf = talloc_realloc_size(mem_ctx, buf, len);
+ if (buf == NULL) {
+ goto done;
+ }
+ rc = getpwuid_r(getuid(), &pwd, buf, len, &pwdbuf);
+ }
+ if (rc != 0 || pwdbuf == NULL ) {
+ const char *szPath = getenv("HOME");
+ if (szPath == NULL) {
+ goto done;
+ }
+ len = strnlen(szPath, PATH_MAX);
+ if (len >= PATH_MAX) {
+ goto done;
+ }
+ out = talloc_strdup(mem_ctx, szPath);
+ goto done;
+ }
+
+ out = talloc_strdup(mem_ctx, pwd.pw_dir);
+done:
+ TALLOC_FREE(buf);
+ return out;
+}
+
+char *path_expand_tilde(TALLOC_CTX *mem_ctx, const char *d)
+{
+ char *h = NULL, *r = NULL;
+ const char *p = NULL;
+ struct stat sb = {0};
+ int rc;
+
+ if (d[0] != '~') {
+ return talloc_strdup(mem_ctx, d);
+ }
+ d++;
+
+ /* handle ~user/path */
+ p = strchr(d, '/');
+ if (p != NULL && p > d) {
+ struct passwd *pw;
+ size_t s = p - d;
+ char u[128];
+
+ if (s >= sizeof(u)) {
+ return NULL;
+ }
+ memcpy(u, d, s);
+ u[s] = '\0';
+
+ pw = getpwnam(u);
+ if (pw == NULL) {
+ return NULL;
+ }
+ h = talloc_strdup(mem_ctx, pw->pw_dir);
+ } else {
+ p = d;
+ h = get_user_home_dir(mem_ctx);
+ }
+ if (h == NULL) {
+ return NULL;
+ }
+
+ rc = stat(h, &sb);
+ if (rc != 0) {
+ TALLOC_FREE(h);
+ return NULL;
+ }
+
+ r = talloc_asprintf(mem_ctx, "%s%s", h, p);
+ TALLOC_FREE(h);
+
+ return r;
+}
diff --git a/lib/util/util_paths.h b/lib/util/util_paths.h
new file mode 100644
index 0000000..cf34f69
--- /dev/null
+++ b/lib/util/util_paths.h
@@ -0,0 +1,63 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba utility functions
+ * Copyright (C) Andrew Tridgell 1992-1998
+ * Copyright (C) Jeremy Allison 2001-2007
+ * Copyright (C) Simo Sorce 2001
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ * Copyright (C) James Peach 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_UTIL_PATHS_H__
+#define __LIB_UTIL_PATHS_H__
+
+#include <talloc.h>
+
+/**
+ * @brief Returns an absolute path to a file in the Samba modules directory.
+ *
+ * @param name File to find, relative to MODULESDIR.
+ *
+ * @retval Pointer to a string containing the full path.
+ **/
+char *modules_path(TALLOC_CTX *mem_ctx, const char *name);
+
+/**
+ * @brief Returns an absolute path to a file in the Samba data directory.
+ *
+ * @param name File to find, relative to CODEPAGEDIR.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+char *data_path(TALLOC_CTX *mem_ctx, const char *name);
+
+/**
+ * @brief Returns the platform specific shared library extension.
+ *
+ * @retval Pointer to a const char * containing the extension.
+ **/
+const char *shlib_ext(void);
+
+/**
+ * @brief Expand a directory starting with a tilde '~'
+ *
+ * @param[in] d The directory to expand.
+ *
+ * @return The expanded directory, NULL on error.
+ */
+char *path_expand_tilde(TALLOC_CTX *mem_ctx, const char *d);
+
+#endif
diff --git a/lib/util/util_process.c b/lib/util/util_process.c
new file mode 100644
index 0000000..a10b85c
--- /dev/null
+++ b/lib/util/util_process.c
@@ -0,0 +1,101 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Process utils.
+ *
+ * Copyright (c) 2013 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "util_process.h"
+#include "replace.h"
+
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
+/*
+ * These variables are static so that we can access them
+ * with process_get_short_title() and process_get_long_title(). The
+ * purpose of this is to allow smb_panic_log() to print them.
+ */
+static char short_comment[16] = {0,};
+static char long_comment[256] = {0,};
+static char binary_name[256];
+
+void process_set_title(const char *short_format, const char *long_format, ...)
+{
+#if defined(HAVE_PRCTL) && defined(PR_SET_NAME)
+ if (short_format != NULL) {
+ va_list ap;
+
+ va_start(ap, long_format);
+ vsnprintf(short_comment, sizeof(short_comment), short_format, ap);
+ va_end(ap);
+
+ prctl(PR_SET_NAME, (unsigned long) short_comment, 0, 0, 0);
+ }
+#endif
+
+ if (long_format != NULL) {
+ va_list ap;
+
+ va_start(ap, long_format);
+ vsnprintf(long_comment, sizeof(long_comment), long_format, ap);
+ va_end(ap);
+
+ setproctitle("%s", long_comment);
+ }
+}
+
+const char *process_get_short_title(void)
+{
+ return short_comment;
+}
+
+const char *process_get_long_title(void)
+{
+ return long_comment;
+}
+
+/*
+ * This is just for debugging in a panic, so we don't want to do
+ * anything more than return a fixed pointer, so we save a copy to a
+ * static variable.
+ */
+void process_save_binary_name(const char *progname)
+{
+ strlcpy(binary_name, progname, sizeof(binary_name));
+}
+
+/* Samba binaries will set this during popt handling */
+const char *process_get_saved_binary_name(void)
+{
+ return binary_name;
+}
+
+
+int prctl_set_comment(const char *comment_format, ...)
+{
+ char comment[16];
+ va_list ap;
+
+ va_start(ap, comment_format);
+ vsnprintf(comment, sizeof(comment), comment_format, ap);
+ va_end(ap);
+
+ process_set_title("%s", "%s", comment);
+ return 0;
+}
diff --git a/lib/util/util_process.h b/lib/util/util_process.h
new file mode 100644
index 0000000..4da135b
--- /dev/null
+++ b/lib/util/util_process.h
@@ -0,0 +1,84 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Process utils.
+ *
+ * Copyright (c) 2013 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SAMBA_UTIL_PROCESS_H
+#define _SAMBA_UTIL_PROCESS_H
+
+#include "replace.h"
+
+/**
+ * @brief Set the process comment name.
+ *
+ * @param[in] comment The comment to set which shouldn't be longer than 16
+ * 16 characters (including \0).
+ *
+ * @return -1 on error, 0 on success.
+ */
+int prctl_set_comment(const char *comment_format, ...) PRINTF_ATTRIBUTE(1,2);
+
+/**
+ * @brief Set the process comment name and longname
+ *
+ * @param[in] short_format The comment to set which shouldn't be longer than 16
+ * 16 characters (including \0).
+ * @param[in] long_format The format string and arguments to produce the long
+ * form of the process name.
+ *
+ * @return -1 on error, 0 on success.
+ */
+void process_set_title(const char *short_format, const char *long_format, ...)
+ PRINTF_ATTRIBUTE(1,3) PRINTF_ATTRIBUTE(2,3);
+
+/**
+ * @brief Get the process comment name set from process_set_title()
+ *
+ * @return process comment name
+ */
+const char *process_get_short_title(void);
+
+/**
+ * @brief Get the process longname set from process_set_title()
+ *
+ * @return process longname
+ */
+const char *process_get_long_title(void);
+
+/*
+ * @brief Save the binary name for later printing in smb_panic()
+ *
+ * @param[in] progname The binary name at process startup
+ *
+ * This is just for debugging in a panic, so we don't want to do
+ * anything more than return a fixed pointer, so we save a copy to a
+ * static variable.
+ */
+void process_save_binary_name(const char *progname);
+
+/**
+ * @brief Get the binary name set at startup process_save_binary_name()
+ *
+ * @return binary name set at startup
+ */
+/* Samba binaries will set this during popt handling */
+const char *process_get_saved_binary_name(void);
+
+
+#endif
diff --git a/lib/util/util_pw.c b/lib/util/util_pw.c
new file mode 100644
index 0000000..8035de4
--- /dev/null
+++ b/lib/util/util_pw.c
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Safe versions of getpw* calls
+
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2005
+ Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Timur Bakeyev 2005
+ Copyright (C) Bjoern Jacke 2006-2007
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include "system/passwd.h"
+#include "lib/util/util_pw.h"
+
+struct passwd *tcopy_passwd(TALLOC_CTX *mem_ctx,
+ const struct passwd *from)
+{
+ struct passwd *ret;
+ size_t len = 0;
+
+ len += strlen(from->pw_name)+1;
+ len += strlen(from->pw_passwd)+1;
+ len += strlen(from->pw_gecos)+1;
+ len += strlen(from->pw_dir)+1;
+ len += strlen(from->pw_shell)+1;
+
+ ret = talloc_pooled_object(mem_ctx, struct passwd, 5, len);
+
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ ret->pw_name = talloc_strdup(ret, from->pw_name);
+ ret->pw_passwd = talloc_strdup(ret, from->pw_passwd);
+ ret->pw_uid = from->pw_uid;
+ ret->pw_gid = from->pw_gid;
+ ret->pw_gecos = talloc_strdup(ret, from->pw_gecos);
+ ret->pw_dir = talloc_strdup(ret, from->pw_dir);
+ ret->pw_shell = talloc_strdup(ret, from->pw_shell);
+
+ return ret;
+}
+
+struct passwd *getpwnam_alloc(TALLOC_CTX *mem_ctx, const char *name)
+{
+ struct passwd *temp;
+
+ temp = getpwnam(name);
+
+ if (!temp) {
+#if 0
+ if (errno == ENOMEM) {
+ /* what now? */
+ }
+#endif
+ return NULL;
+ }
+
+ return tcopy_passwd(mem_ctx, temp);
+}
+
+/****************************************************************************
+ talloc'ed version of getpwuid.
+****************************************************************************/
+
+struct passwd *getpwuid_alloc(TALLOC_CTX *mem_ctx, uid_t uid)
+{
+ struct passwd *temp;
+
+ temp = getpwuid(uid);
+
+ if (!temp) {
+#if 0
+ if (errno == ENOMEM) {
+ /* what now? */
+ }
+#endif
+ return NULL;
+ }
+
+ return tcopy_passwd(mem_ctx, temp);
+}
diff --git a/lib/util/util_pw.h b/lib/util/util_pw.h
new file mode 100644
index 0000000..fae4da9
--- /dev/null
+++ b/lib/util/util_pw.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Safe versions of getpw* calls
+
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1997-2001.
+ Copyright (C) Andrew Bartlett 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIB_UTIL_UTIL_PW_H__
+#define __LIB_UTIL_UTIL_PW_H__
+
+struct passwd *tcopy_passwd(TALLOC_CTX *mem_ctx,
+ const struct passwd *from);
+struct passwd *getpwnam_alloc(TALLOC_CTX *mem_ctx, const char *name);
+struct passwd *getpwuid_alloc(TALLOC_CTX *mem_ctx, uid_t uid);
+
+#endif /* __LIB_UTIL_UTIL_PW_H__ */
diff --git a/lib/util/util_runcmd.c b/lib/util/util_runcmd.c
new file mode 100644
index 0000000..ea2e8ee
--- /dev/null
+++ b/lib/util/util_runcmd.c
@@ -0,0 +1,379 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ run a child command
+
+ Copyright (C) Andrew Tridgell 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+ this runs a child command with stdout and stderr going to the Samba
+ log
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include <tevent.h>
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+#include "../lib/util/tevent_unix.h"
+#include "../lib/util/tfork.h"
+#include "../lib/util/sys_rw.h"
+
+struct samba_runcmd_state {
+ int stdout_log_level;
+ int stderr_log_level;
+ struct tevent_fd *fde_stdout;
+ struct tevent_fd *fde_stderr;
+ struct tevent_fd *fde_status;
+ int fd_stdin, fd_stdout, fd_stderr, fd_status;
+ char *arg0;
+ pid_t pid;
+ struct tfork *tfork;
+ char buf[1024];
+ uint16_t buf_used;
+};
+
+static void samba_runcmd_cleanup_fn(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct samba_runcmd_state *state = tevent_req_data(
+ req, struct samba_runcmd_state);
+
+ if (state->tfork != NULL) {
+ tfork_destroy(&state->tfork);
+ }
+ state->pid = -1;
+
+ if (state->fd_stdin != -1) {
+ close(state->fd_stdin);
+ state->fd_stdin = -1;
+ }
+}
+
+int samba_runcmd_export_stdin(struct tevent_req *req)
+{
+ struct samba_runcmd_state *state = tevent_req_data(req,
+ struct samba_runcmd_state);
+ int ret = state->fd_stdin;
+
+ state->fd_stdin = -1;
+
+ return ret;
+}
+
+static void samba_runcmd_io_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+/*
+ run a command as a child process, with a timeout.
+
+ any stdout/stderr from the child will appear in the Samba logs with
+ the specified log levels
+ */
+struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct timeval endtime,
+ int stdout_log_level,
+ int stderr_log_level,
+ const char * const *argv0, ...)
+{
+ struct tevent_req *req;
+ struct samba_runcmd_state *state;
+ int p1[2], p2[2], p3[2];
+ char **argv;
+ va_list ap;
+
+ if (argv0 == NULL) {
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct samba_runcmd_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->stdout_log_level = stdout_log_level;
+ state->stderr_log_level = stderr_log_level;
+ state->fd_stdin = -1;
+
+ state->arg0 = talloc_strdup(state, argv0[0]);
+ if (tevent_req_nomem(state->arg0, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (pipe(p1) != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ if (pipe(p2) != 0) {
+ close(p1[0]);
+ close(p1[1]);
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ if (pipe(p3) != 0) {
+ close(p1[0]);
+ close(p1[1]);
+ close(p2[0]);
+ close(p2[1]);
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ state->tfork = tfork_create();
+ if (state->tfork == NULL) {
+ close(p1[0]);
+ close(p1[1]);
+ close(p2[0]);
+ close(p2[1]);
+ close(p3[0]);
+ close(p3[1]);
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ state->pid = tfork_child_pid(state->tfork);
+ if (state->pid != 0) {
+ /* the parent */
+ close(p1[1]);
+ close(p2[1]);
+ close(p3[0]);
+ state->fd_stdout = p1[0];
+ state->fd_stderr = p2[0];
+ state->fd_stdin = p3[1];
+ state->fd_status = tfork_event_fd(state->tfork);
+
+ set_blocking(state->fd_stdout, false);
+ set_blocking(state->fd_stderr, false);
+ set_blocking(state->fd_stdin, false);
+ set_blocking(state->fd_status, false);
+
+ smb_set_close_on_exec(state->fd_stdin);
+ smb_set_close_on_exec(state->fd_stdout);
+ smb_set_close_on_exec(state->fd_stderr);
+ smb_set_close_on_exec(state->fd_status);
+
+ tevent_req_set_cleanup_fn(req, samba_runcmd_cleanup_fn);
+
+ state->fde_stdout = tevent_add_fd(ev, state,
+ state->fd_stdout,
+ TEVENT_FD_READ,
+ samba_runcmd_io_handler,
+ req);
+ if (tevent_req_nomem(state->fde_stdout, req)) {
+ close(state->fd_stdout);
+ close(state->fd_stderr);
+ close(state->fd_status);
+ return tevent_req_post(req, ev);
+ }
+ tevent_fd_set_auto_close(state->fde_stdout);
+
+ state->fde_stderr = tevent_add_fd(ev, state,
+ state->fd_stderr,
+ TEVENT_FD_READ,
+ samba_runcmd_io_handler,
+ req);
+ if (tevent_req_nomem(state->fde_stdout, req)) {
+ close(state->fd_stdout);
+ close(state->fd_stderr);
+ close(state->fd_status);
+ return tevent_req_post(req, ev);
+ }
+ tevent_fd_set_auto_close(state->fde_stderr);
+
+ state->fde_status = tevent_add_fd(ev, state,
+ state->fd_status,
+ TEVENT_FD_READ,
+ samba_runcmd_io_handler,
+ req);
+ if (tevent_req_nomem(state->fde_stdout, req)) {
+ close(state->fd_stdout);
+ close(state->fd_stderr);
+ close(state->fd_status);
+ return tevent_req_post(req, ev);
+ }
+ tevent_fd_set_auto_close(state->fde_status);
+
+ if (!timeval_is_zero(&endtime)) {
+ tevent_req_set_endtime(req, ev, endtime);
+ }
+
+ return req;
+ }
+
+ /* the child */
+ close(p1[0]);
+ close(p2[0]);
+ close(p3[1]);
+ close(0);
+ close(1);
+ close(2);
+
+ /* we want to ensure that all of the network sockets we had
+ open are closed */
+ tevent_re_initialise(ev);
+
+ /* setup for logging to go to the parents debug log */
+ dup2(p3[0], 0);
+ dup2(p1[1], 1);
+ dup2(p2[1], 2);
+
+ close(p1[1]);
+ close(p2[1]);
+ close(p3[0]);
+
+ argv = str_list_copy(state, discard_const_p(const char *, argv0));
+ if (!argv) {
+ fprintf(stderr, "Out of memory in child\n");
+ _exit(255);
+ }
+
+ va_start(ap, argv0);
+ while (1) {
+ const char **l;
+ char *arg = va_arg(ap, char *);
+ if (arg == NULL) break;
+ l = discard_const_p(const char *, argv);
+ l = str_list_add(l, arg);
+ if (l == NULL) {
+ fprintf(stderr, "Out of memory in child\n");
+ _exit(255);
+ }
+ argv = discard_const_p(char *, l);
+ }
+ va_end(ap);
+
+ (void)execvp(state->arg0, argv);
+ fprintf(stderr, "Failed to exec child - %s\n", strerror(errno));
+ _exit(255);
+ return NULL;
+}
+
+/*
+ handle stdout/stderr from the child
+ */
+static void samba_runcmd_io_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct samba_runcmd_state *state = tevent_req_data(req,
+ struct samba_runcmd_state);
+ int level;
+ char *p;
+ int n, fd;
+
+ if (!(flags & TEVENT_FD_READ)) {
+ return;
+ }
+
+ if (fde == state->fde_stdout) {
+ level = state->stdout_log_level;
+ fd = state->fd_stdout;
+ } else if (fde == state->fde_stderr) {
+ level = state->stderr_log_level;
+ fd = state->fd_stderr;
+ } else {
+ int status;
+
+ status = tfork_status(&state->tfork, false);
+ if (status == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return;
+ }
+ DBG_ERR("Bad read on status pipe\n");
+ tevent_req_error(req, errno);
+ return;
+ }
+ state->pid = -1;
+ TALLOC_FREE(fde);
+
+ if (WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ status = WTERMSIG(status);
+ } else {
+ status = ECHILD;
+ }
+
+ DBG_NOTICE("Child %s exited %d\n", state->arg0, status);
+ if (status != 0) {
+ tevent_req_error(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+ }
+
+ n = read(fd, &state->buf[state->buf_used],
+ sizeof(state->buf) - state->buf_used);
+ if (n > 0) {
+ state->buf_used += n;
+ } else if (n == 0) {
+ if (fde == state->fde_stdout) {
+ talloc_free(fde);
+ state->fde_stdout = NULL;
+ return;
+ }
+ if (fde == state->fde_stderr) {
+ talloc_free(fde);
+ state->fde_stderr = NULL;
+ return;
+ }
+ return;
+ }
+
+ while (state->buf_used > 0 &&
+ (p = (char *)memchr(state->buf, '\n', state->buf_used)) != NULL) {
+ int n1 = (p - state->buf)+1;
+ int n2 = n1 - 1;
+ /* swallow \r from child processes */
+ if (n2 > 0 && state->buf[n2-1] == '\r') {
+ n2--;
+ }
+ DEBUG(level,("%s: %*.*s\n", state->arg0, n2, n2, state->buf));
+ memmove(state->buf, p+1, sizeof(state->buf) - n1);
+ state->buf_used -= n1;
+ }
+
+ /* the buffer could have completely filled - unfortunately we have
+ no choice but to dump it out straight away */
+ if (state->buf_used == sizeof(state->buf)) {
+ DEBUG(level,("%s: %*.*s\n",
+ state->arg0, state->buf_used,
+ state->buf_used, state->buf));
+ state->buf_used = 0;
+ }
+}
+
+int samba_runcmd_recv(struct tevent_req *req, int *perrno)
+{
+ if (tevent_req_is_unix_error(req, perrno)) {
+ tevent_req_received(req);
+ return -1;
+ }
+
+ tevent_req_received(req);
+ return 0;
+}
diff --git a/lib/util/util_str.c b/lib/util/util_str.c
new file mode 100644
index 0000000..7c1d15d
--- /dev/null
+++ b/lib/util/util_str.c
@@ -0,0 +1,307 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/samba_util.h"
+#include "system/locale.h"
+#include "smb_strtox.h"
+#undef strncasecmp
+#undef strcasemp
+
+/**
+ * @file
+ * @brief String utilities.
+ **/
+
+/**
+ * Parse a string containing a boolean value.
+ *
+ * val will be set to the read value.
+ *
+ * @retval true if a boolean value was parsed, false otherwise.
+ */
+_PUBLIC_ bool conv_str_bool(const char * str, bool * val)
+{
+ char * end = NULL;
+ long lval;
+
+ if (str == NULL || *str == '\0') {
+ return false;
+ }
+
+ lval = strtol(str, &end, 10 /* base */);
+ if (end == NULL || *end != '\0' || end == str) {
+ return set_boolean(str, val);
+ }
+
+ *val = (lval) ? true : false;
+ return true;
+}
+
+/**
+ * Convert a size specification like 16K into an integral number of bytes.
+ **/
+_PUBLIC_ bool conv_str_size_error(const char * str, uint64_t * val)
+{
+ char * end = NULL;
+ unsigned long long lval;
+ int error = 0;
+
+ if (str == NULL || *str == '\0') {
+ return false;
+ }
+
+ lval = smb_strtoull(str, &end, 10, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ return false;
+ }
+
+ if (*end) {
+ if (strwicmp(end, "K") == 0) {
+ lval *= 1024ULL;
+ } else if (strwicmp(end, "M") == 0) {
+ lval *= (1024ULL * 1024ULL);
+ } else if (strwicmp(end, "G") == 0) {
+ lval *= (1024ULL * 1024ULL * 1024ULL);
+ } else if (strwicmp(end, "T") == 0) {
+ lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
+ } else if (strwicmp(end, "P") == 0) {
+ lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL);
+ } else {
+ return false;
+ }
+ }
+
+ *val = (uint64_t)lval;
+ return true;
+}
+
+/**
+ * Parse a uint64_t value from a string
+ *
+ * val will be set to the value read.
+ *
+ * @retval true if parsing was successful, false otherwise
+ */
+_PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val)
+{
+ unsigned long long lval;
+ int error = 0;
+
+ if (str == NULL || *str == '\0') {
+ return false;
+ }
+
+ lval = smb_strtoull(str, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
+ if (error != 0) {
+ return false;
+ }
+
+ *val = (uint64_t)lval;
+ return true;
+}
+
+/**
+ * Compare 2 strings.
+ *
+ * @note The comparison is case-insensitive.
+ **/
+_PUBLIC_ bool strequal(const char *s1, const char *s2)
+{
+ if (s1 == s2)
+ return true;
+ if (!s1 || !s2)
+ return false;
+
+ return strcasecmp_m(s1,s2) == 0;
+}
+
+/**
+ * @file
+ * @brief String utilities.
+ **/
+
+static bool next_token_internal_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep,
+ bool ltrim)
+{
+ const char *s;
+ const char *saved_s;
+ char *pbuf;
+ bool quoted;
+ size_t len=1;
+
+ *pp_buff = NULL;
+ if (!ptr) {
+ return(false);
+ }
+
+ s = *ptr;
+
+ /* default to simple separators */
+ if (!sep) {
+ sep = " \t\n\r";
+ }
+
+ /* find the first non sep char, if left-trimming is requested */
+ if (ltrim) {
+ while (*s && strchr_m(sep,*s)) {
+ s++;
+ }
+ }
+
+ /* nothing left? */
+ if (!*s) {
+ return false;
+ }
+
+ /* When restarting we need to go from here. */
+ saved_s = s;
+
+ /* Work out the length needed. */
+ for (quoted = false; *s &&
+ (quoted || !strchr_m(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ }
+ }
+
+ /* We started with len = 1 so we have space for the nul. */
+ *pp_buff = talloc_array(ctx, char, len);
+ if (!*pp_buff) {
+ return false;
+ }
+
+ /* copy over the token */
+ pbuf = *pp_buff;
+ s = saved_s;
+ for (quoted = false; *s &&
+ (quoted || !strchr_m(sep,*s)); s++) {
+ if ( *s == '\"' ) {
+ quoted = !quoted;
+ } else {
+ *pbuf++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *pbuf = 0;
+
+ return true;
+}
+
+bool next_token_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep)
+{
+ return next_token_internal_talloc(ctx, ptr, pp_buff, sep, true);
+}
+
+/*
+ * Get the next token from a string, return false if none found. Handles
+ * double-quotes. This version does not trim leading separator characters
+ * before looking for a token.
+ */
+
+bool next_token_no_ltrim_talloc(TALLOC_CTX *ctx,
+ const char **ptr,
+ char **pp_buff,
+ const char *sep)
+{
+ return next_token_internal_talloc(ctx, ptr, pp_buff, sep, false);
+}
+
+/**
+ * Get the next token from a string, return False if none found.
+ * Handles double-quotes.
+ *
+ * Based on a routine by GJC@VILLAGE.COM.
+ * Extensively modified by Andrew.Tridgell@anu.edu.au
+ **/
+_PUBLIC_ bool next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
+{
+ const char *s;
+ bool quoted;
+ size_t len=1;
+
+ if (!ptr)
+ return false;
+
+ s = *ptr;
+
+ /* default to simple separators */
+ if (!sep)
+ sep = " \t\n\r";
+
+ /* find the first non sep char */
+ while (*s && strchr_m(sep,*s))
+ s++;
+
+ /* nothing left? */
+ if (!*s)
+ return false;
+
+ /* copy over the token */
+ for (quoted = false; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ *buff++ = *s;
+ }
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *buff = 0;
+
+ return true;
+}
+
+/**
+ Set a boolean variable from the text value stored in the passed string.
+ Returns true in success, false if the passed string does not correctly
+ represent a boolean.
+**/
+
+_PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean)
+{
+ if (strwicmp(boolean_string, "yes") == 0 ||
+ strwicmp(boolean_string, "true") == 0 ||
+ strwicmp(boolean_string, "on") == 0 ||
+ strwicmp(boolean_string, "1") == 0) {
+ *boolean = true;
+ return true;
+ } else if (strwicmp(boolean_string, "no") == 0 ||
+ strwicmp(boolean_string, "false") == 0 ||
+ strwicmp(boolean_string, "off") == 0 ||
+ strwicmp(boolean_string, "0") == 0) {
+ *boolean = false;
+ return true;
+ }
+ return false;
+}
diff --git a/lib/util/util_str_common.c b/lib/util/util_str_common.c
new file mode 100644
index 0000000..bf66647
--- /dev/null
+++ b/lib/util/util_str_common.c
@@ -0,0 +1,154 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2001
+ Copyright (C) Simo Sorce 2001-2002
+ Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "lib/util/samba_util.h"
+
+/**
+Do a case-insensitive, whitespace-ignoring ASCII string compare.
+**/
+_PUBLIC_ int strwicmp(const char *psz1, const char *psz2)
+{
+ /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
+ /* appropriate value. */
+ if (psz1 == psz2)
+ return (0);
+ else if (psz1 == NULL)
+ return (-1);
+ else if (psz2 == NULL)
+ return (1);
+
+ /* sync the strings on first non-whitespace */
+ while (1) {
+ while (isspace((int)*psz1))
+ psz1++;
+ while (isspace((int)*psz2))
+ psz2++;
+
+ /*
+ * This does not do a genuine multi-byte comparison,
+ * instead it just uses the fast-path for ASCII in
+ * these common routines
+ */
+ if (toupper_m((unsigned char)*psz1) != toupper_m((unsigned char)*psz2)
+ || *psz1 == '\0'
+ || *psz2 == '\0')
+ break;
+ psz1++;
+ psz2++;
+ }
+ return (*psz1 - *psz2);
+}
+
+/**
+ String replace.
+ NOTE: oldc and newc must be 7 bit characters
+**/
+void string_replace( char *s, char oldc, char newc )
+{
+ while (*s != '\0') {
+ size_t c_size;
+ next_codepoint(s, &c_size);
+
+ if (c_size == 1) {
+ if (*s == oldc) {
+ *s = newc;
+ }
+ }
+ s += c_size;
+ }
+}
+
+
+/**
+ Paranoid strcpy into a buffer of given length (includes terminating
+ zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
+ and replaces with '_'. Deliberately does *NOT* check for multibyte
+ characters. Treats src as an array of bytes, not as a multibyte
+ string. Any byte >0x7f is automatically converted to '_'.
+ other_safe_chars must also contain an ascii string (bytes<0x7f).
+**/
+
+char *alpha_strcpy(char *dest,
+ const char *src,
+ const char *other_safe_chars,
+ size_t maxlength)
+{
+ size_t len, i;
+
+ if (!dest) {
+ smb_panic("ERROR: NULL dest in alpha_strcpy");
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+
+ len = strlen(src);
+ if (len >= maxlength)
+ len = maxlength - 1;
+
+ if (!other_safe_chars)
+ other_safe_chars = "";
+
+ for(i = 0; i < len; i++) {
+ int val = (src[i] & 0xff);
+ if (val > 0x7f) {
+ dest[i] = '_';
+ continue;
+ }
+ if (isupper(val) || islower(val) ||
+ isdigit(val) || strchr(other_safe_chars, val))
+ dest[i] = src[i];
+ else
+ dest[i] = '_';
+ }
+
+ dest[i] = '\0';
+
+ return dest;
+}
+
+char *talloc_alpha_strcpy(TALLOC_CTX *mem_ctx,
+ const char *src,
+ const char *other_safe_chars)
+{
+ char *dest = NULL;
+ size_t slen;
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ slen = strlen(src);
+
+ dest = talloc_zero_size(mem_ctx, slen + 1);
+ if (dest == NULL) {
+ return NULL;
+ }
+
+ alpha_strcpy(dest, src, other_safe_chars, slen + 1);
+ return dest;
+}
diff --git a/lib/util/util_str_escape.c b/lib/util/util_str_escape.c
new file mode 100644
index 0000000..750d64b
--- /dev/null
+++ b/lib/util/util_str_escape.c
@@ -0,0 +1,127 @@
+/*
+ Samba string escaping routines
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/util/debug.h"
+#include "lib/util/util_str_escape.h"
+
+
+/*
+ * Calculate the encoded length of a character for log_escape
+ *
+ */
+static size_t encoded_length(char c)
+{
+ if (c != '\\' && c > 0x1F) {
+ return 1;
+ } else {
+ switch (c) {
+ case '\a':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ case '\\':
+ return 2; /* C escape sequence */
+ default:
+ return 4; /* hex escape \xhh */
+ }
+ }
+}
+
+/*
+ * Escape any control characters in the inputs to prevent them from
+ * interfering with the log output.
+ */
+char *log_escape(TALLOC_CTX *frame, const char *in)
+{
+ size_t size = 0; /* Space to allocate for the escaped data */
+ char *encoded = NULL; /* The encoded string */
+ const char *c;
+ char *e;
+
+ if (in == NULL) {
+ return NULL;
+ }
+
+ /* Calculate the size required for the escaped array */
+ c = in;
+ while (*c) {
+ size += encoded_length( *c);
+ c++;
+ }
+ size++;
+
+ encoded = talloc_array( frame, char, size);
+ if (encoded == NULL) {
+ DBG_ERR( "Out of memory allocating encoded string\n");
+ return NULL;
+ }
+
+ c = in;
+ e = encoded;
+ while (*c) {
+ if (*c != '\\' && *c > 0x1F) {
+ *e++ = *c++;
+ } else {
+ switch (*c) {
+ case '\a':
+ *e++ = '\\';
+ *e++ = 'a';
+ break;
+ case '\b':
+ *e++ = '\\';
+ *e++ = 'b';
+ break;
+ case '\f':
+ *e++ = '\\';
+ *e++ = 'f';
+ break;
+ case '\n':
+ *e++ = '\\';
+ *e++ = 'n';
+ break;
+ case '\r':
+ *e++ = '\\';
+ *e++ = 'r';
+ break;
+ case '\t':
+ *e++ = '\\';
+ *e++ = 't';
+ break;
+ case '\v':
+ *e++ = '\\';
+ *e++ = 'v';
+ break;
+ case '\\':
+ *e++ = '\\';
+ *e++ = '\\';
+ break;
+ default:
+ snprintf(e, 5, "\\x%02X", *c);
+ e += 4;
+ }
+ c++;
+ }
+ }
+ *e = '\0';
+ return encoded;
+}
diff --git a/lib/util/util_str_escape.h b/lib/util/util_str_escape.h
new file mode 100644
index 0000000..0b4c596
--- /dev/null
+++ b/lib/util/util_str_escape.h
@@ -0,0 +1,27 @@
+/*
+ Samba string escaping routines
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_UTIL_STR_ESCAPE_H
+#define _SAMBA_UTIL_STR_ESCAPE_H
+
+#include <talloc.h>
+
+char *log_escape(TALLOC_CTX *frame, const char *in);
+
+#endif
diff --git a/lib/util/util_str_hex.c b/lib/util/util_str_hex.c
new file mode 100644
index 0000000..553fb30
--- /dev/null
+++ b/lib/util/util_str_hex.c
@@ -0,0 +1,69 @@
+#include "replace.h"
+#include "util_str_hex.h"
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/misc.h"
+
+static bool hex_uint16(const char *in, uint16_t *out)
+{
+ uint8_t hi=0, lo=0;
+ bool ok = hex_byte(in, &hi) && hex_byte(in+2, &lo);
+ *out = (((uint16_t)hi)<<8) + lo;
+ return ok;
+}
+
+bool hex_uint32(const char *in, uint32_t *out)
+{
+ uint16_t hi=0, lo=0;
+ bool ok = hex_uint16(in, &hi) && hex_uint16(in+4, &lo);
+ *out = (((uint32_t)hi)<<16) + lo;
+ return ok;
+}
+
+bool parse_guid_string(const char *s, struct GUID *guid)
+{
+ bool ok;
+ int i;
+ /* "e12b56b6-0a95-11d1-adbb-00c04fd8d5cd"
+ | | | | |
+ | | | | \ node[6]
+ | | | \_____ clock_seq[2]
+ | | \__________ time_hi_and_version
+ | \_______________ time_mid
+ \_____________________ time_low
+ */
+
+ ok = hex_uint32(s, &guid->time_low);
+ if (!ok || (s[8] != '-')) {
+ return false;
+ }
+ s += 9;
+
+ ok = hex_uint16(s, &guid->time_mid);
+ if (!ok || (s[4] != '-')) {
+ return false;
+ }
+ s += 5;
+
+ ok = hex_uint16(s, &guid->time_hi_and_version);
+ if (!ok || (s[4] != '-')) {
+ return false;
+ }
+ s += 5;
+
+ ok = hex_byte(s, &guid->clock_seq[0]) &&
+ hex_byte(s+2, &guid->clock_seq[1]);
+ if (!ok || (s[4] != '-')) {
+ return false;
+ }
+ s += 5;
+
+ for (i = 0; i < 6; i++) {
+ ok = hex_byte(s, &guid->node[i]);
+ if (!ok) {
+ return false;
+ }
+ s += 2;
+ }
+
+ return true;
+}
diff --git a/lib/util/util_str_hex.h b/lib/util/util_str_hex.h
new file mode 100644
index 0000000..7dd527f
--- /dev/null
+++ b/lib/util/util_str_hex.h
@@ -0,0 +1,5 @@
+#include "replace.h"
+
+bool hex_uint32(const char *in, uint32_t *out);
+struct GUID;
+bool parse_guid_string(const char *s, struct GUID *guid);
diff --git a/lib/util/util_strlist.c b/lib/util/util_strlist.c
new file mode 100644
index 0000000..e102002
--- /dev/null
+++ b/lib/util/util_strlist.c
@@ -0,0 +1,561 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "debug.h"
+#include "tsort.h"
+
+#include "util_strlist.h"
+
+#undef strcasecmp
+
+/**
+ * @file
+ * @brief String list manipulation
+ */
+
+/**
+ build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc)
+*/
+_PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx)
+{
+ char **ret = talloc_zero_array(mem_ctx, char *, 1);
+ return ret;
+}
+
+/**
+ place the only element 'entry' into a new, NULL terminated string list
+*/
+_PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx, const char *entry)
+{
+ char **ret = NULL;
+
+ ret = talloc_array(mem_ctx, char *, 2);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ ret[0] = talloc_strdup(ret, entry);
+ if (!ret[0]) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret[1] = NULL;
+
+ return ret;
+}
+
+/**
+ build a null terminated list of strings from a input string and a
+ separator list. The separator list must contain characters less than
+ or equal to 0x2f for this to work correctly on multi-byte strings
+*/
+_PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
+{
+ int num_elements = 0;
+ char **ret = NULL;
+
+ if (sep == NULL) {
+ sep = LIST_SEP;
+ }
+
+ ret = talloc_array(mem_ctx, char *, 1);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ while (string && *string) {
+ size_t len = strcspn(string, sep);
+ char **ret2;
+
+ if (len == 0) {
+ string += strspn(string, sep);
+ continue;
+ }
+
+ ret2 = talloc_realloc(mem_ctx, ret, char *,
+ num_elements+2);
+ if (ret2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = ret2;
+
+ ret[num_elements] = talloc_strndup(ret, string, len);
+ if (ret[num_elements] == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ num_elements++;
+ string += len;
+ }
+
+ ret[num_elements] = NULL;
+
+ return ret;
+}
+
+/**
+ * build a null terminated list of strings from an argv-like input string
+ * Entries are separated by spaces and can be enclosed by quotes.
+ * Does NOT support escaping
+ */
+_PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
+{
+ int num_elements = 0;
+ char **ret = NULL;
+
+ ret = talloc_array(mem_ctx, char *, 1);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (sep == NULL)
+ sep = " \t\n\r";
+
+ while (string && *string) {
+ size_t len = strcspn(string, sep);
+ char *element;
+ char **ret2;
+
+ if (len == 0) {
+ string += strspn(string, sep);
+ continue;
+ }
+
+ if (*string == '\"') {
+ string++;
+ len = strcspn(string, "\"");
+ element = talloc_strndup(ret, string, len);
+ string += len + 1;
+ } else {
+ element = talloc_strndup(ret, string, len);
+ string += len;
+ }
+
+ if (element == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
+ if (ret2 == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret = ret2;
+
+ ret[num_elements] = element;
+
+ num_elements++;
+ }
+
+ ret[num_elements] = NULL;
+
+ return ret;
+
+}
+
+/**
+ * join a list back to one string
+ */
+_PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char separator)
+{
+ char *ret = NULL;
+ int i;
+
+ if (list[0] == NULL)
+ return talloc_strdup(mem_ctx, "");
+
+ ret = talloc_strdup(mem_ctx, list[0]);
+
+ for (i = 1; list[i]; i++) {
+ talloc_asprintf_addbuf(&ret, "%c%s", separator, list[i]);
+ }
+
+ return ret;
+}
+
+/** join a list back to one (shell-like) string; entries
+ * separated by spaces, using quotes where necessary */
+_PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
+{
+ char *ret = NULL;
+ int i;
+
+ if (list[0] == NULL)
+ return talloc_strdup(mem_ctx, "");
+
+ if (strchr(list[0], ' ') || strlen(list[0]) == 0)
+ ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
+ else
+ ret = talloc_strdup(mem_ctx, list[0]);
+
+ for (i = 1; list[i]; i++) {
+ if (strchr(list[i], ' ') || strlen(list[i]) == 0) {
+ talloc_asprintf_addbuf(&ret, "%c\"%s\"", sep, list[i]);
+ } else {
+ talloc_asprintf_addbuf(&ret, "%c%s", sep, list[i]);
+ }
+ }
+
+ return ret;
+}
+
+/**
+ return the number of elements in a string list
+*/
+_PUBLIC_ size_t str_list_length(const char * const *list)
+{
+ size_t ret;
+ for (ret=0;list && list[ret];ret++) /* noop */ ;
+ return ret;
+}
+
+
+/**
+ copy a string list
+*/
+_PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
+{
+ int i;
+ char **ret;
+
+ if (list == NULL)
+ return NULL;
+
+ ret = talloc_array(mem_ctx, char *, str_list_length(list)+1);
+ if (ret == NULL)
+ return NULL;
+
+ for (i=0;list && list[i];i++) {
+ ret[i] = talloc_strdup(ret, list[i]);
+ if (ret[i] == NULL) {
+ talloc_free(ret);
+ return NULL;
+ }
+ }
+ ret[i] = NULL;
+ return ret;
+}
+
+/**
+ Return true if all the elements of the list match exactly.
+ */
+_PUBLIC_ bool str_list_equal(const char * const *list1,
+ const char * const *list2)
+{
+ int i;
+
+ if (list1 == NULL || list2 == NULL) {
+ return (list1 == list2);
+ }
+
+ for (i=0;list1[i] && list2[i];i++) {
+ if (strcmp(list1[i], list2[i]) != 0) {
+ return false;
+ }
+ }
+ if (list1[i] || list2[i]) {
+ return false;
+ }
+ return true;
+}
+
+
+/**
+ add an entry to a string list
+*/
+_PUBLIC_ const char **str_list_add(const char **list, const char *s)
+{
+ size_t len = str_list_length(list);
+ const char **ret;
+
+ ret = talloc_realloc(NULL, list, const char *, len+2);
+ if (ret == NULL) return NULL;
+
+ ret[len] = talloc_strdup(ret, s);
+ if (ret[len] == NULL) return NULL;
+
+ ret[len+1] = NULL;
+
+ return ret;
+}
+
+/**
+ * @brief Extend a talloc'ed string list with a printf'ed string
+ *
+ * str_list_add_printf() does nothing if *plist is NULL and it sets
+ * *plist to NULL on failure. It is designed to avoid intermediate
+ * NULL checks:
+ *
+ * argv = str_list_make_empty(ctx);
+ * str_list_add_printf(&argv, "smbstatus");
+ * str_list_add_printf(&argv, "--configfile=%s", config);
+ * if (argv == NULL) {
+ * goto nomem;
+ * }
+ *
+ * @param[in,out] plist The talloc'ed list to extend
+ * @param[in] fmt The format string
+ */
+void str_list_add_printf(char ***plist, const char *fmt, ...)
+{
+ char **list = *plist;
+ size_t len;
+ char **tmp = NULL;
+ va_list ap;
+
+ if (list == NULL) {
+ return;
+ }
+ len = str_list_length((const char * const *)list);
+
+ tmp = talloc_realloc(NULL, list, char *, len+2);
+ if (tmp == NULL) {
+ goto fail;
+ }
+ list = tmp;
+ list[len+1] = NULL;
+
+ va_start(ap, fmt);
+ list[len] = talloc_vasprintf(list, fmt, ap);
+ va_end(ap);
+
+ if (list[len] == NULL) {
+ goto fail;
+ }
+ *plist = list;
+
+ return;
+fail:
+ TALLOC_FREE(list);
+ *plist = NULL;
+}
+
+/**
+ remove an entry from a string list
+*/
+_PUBLIC_ void str_list_remove(const char **list, const char *s)
+{
+ int i;
+
+ for (i=0;list[i];i++) {
+ if (strcmp(list[i], s) == 0) break;
+ }
+ if (!list[i]) return;
+
+ for (;list[i];i++) {
+ list[i] = list[i+1];
+ }
+}
+
+
+/**
+ return true if a string is in a list
+*/
+_PUBLIC_ bool str_list_check(const char **list, const char *s)
+{
+ int i;
+
+ for (i=0; list != NULL && list[i] != NULL; i++) {
+ if (strcmp(list[i], s) == 0) return true;
+ }
+ return false;
+}
+
+/**
+ return true if a string is in a list, case insensitively
+*/
+_PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
+{
+ int i;
+
+ for (i=0; list != NULL && list[i] != NULL; i++) {
+ if (strcasecmp(list[i], s) == 0) return true;
+ }
+ return false;
+}
+
+
+/**
+ append one list to another - expanding list1
+*/
+_PUBLIC_ const char **str_list_append(const char **list1,
+ const char * const *list2)
+{
+ size_t len1 = str_list_length(list1);
+ size_t len2 = str_list_length(list2);
+ const char **ret;
+ size_t i;
+
+ ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
+ if (ret == NULL) return NULL;
+
+ for (i=len1;i<len1+len2;i++) {
+ ret[i] = talloc_strdup(ret, list2[i-len1]);
+ if (ret[i] == NULL) {
+ return NULL;
+ }
+ }
+ ret[i] = NULL;
+
+ return ret;
+}
+
+static int list_cmp(const char **el1, const char **el2)
+{
+ return strcmp(*el1, *el2);
+}
+
+/*
+ return a list that only contains the unique elements of a list,
+ removing any duplicates
+ */
+_PUBLIC_ const char **str_list_unique(const char **list)
+{
+ size_t len = str_list_length(list);
+ const char **list2;
+ size_t i, j;
+ if (len < 2) {
+ return list;
+ }
+ list2 = (const char **)talloc_memdup(list, list,
+ sizeof(list[0])*(len+1));
+ TYPESAFE_QSORT(list2, len, list_cmp);
+ list[0] = list2[0];
+ for (i=j=1;i<len;i++) {
+ if (strcmp(list2[i], list[j-1]) != 0) {
+ list[j] = list2[i];
+ j++;
+ }
+ }
+ list[j] = NULL;
+ list = talloc_realloc(NULL, list, const char *, j + 1);
+ talloc_free(list2);
+ return list;
+}
+
+/*
+ very useful when debugging complex list related code
+ */
+_PUBLIC_ void str_list_show(const char **list)
+{
+ int i;
+ DEBUG(0,("{ "));
+ for (i=0;list && list[i];i++) {
+ DEBUG(0,("\"%s\", ", list[i]));
+ }
+ DEBUG(0,("}\n"));
+}
+
+
+
+/**
+ append one list to another - expanding list1
+ this assumes the elements of list2 are const pointers, so we can re-use them
+*/
+_PUBLIC_ const char **str_list_append_const(const char **list1,
+ const char **list2)
+{
+ size_t len1 = str_list_length(list1);
+ size_t len2 = str_list_length(list2);
+ const char **ret;
+ size_t i;
+
+ ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
+ if (ret == NULL) return NULL;
+
+ for (i=len1;i<len1+len2;i++) {
+ ret[i] = list2[i-len1];
+ }
+ ret[i] = NULL;
+
+ return ret;
+}
+
+/**
+ * Add a string to an array of strings.
+ *
+ * num should be a pointer to an integer that holds the current
+ * number of elements in strings. It will be updated by this function.
+ */
+_PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx,
+ const char *str, const char ***strings, size_t *num)
+{
+ char *dup_str = talloc_strdup(mem_ctx, str);
+
+ *strings = talloc_realloc(mem_ctx,
+ *strings,
+ const char *, ((*num)+1));
+
+ if ((*strings == NULL) || (dup_str == NULL)) {
+ *num = 0;
+ return false;
+ }
+
+ (*strings)[*num] = dup_str;
+ *num += 1;
+
+ return true;
+}
+
+/**
+ add an entry to a string list
+ this assumes s will not change
+*/
+_PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
+{
+ size_t len = str_list_length(list);
+ const char **ret;
+
+ ret = talloc_realloc(NULL, list, const char *, len+2);
+ if (ret == NULL) return NULL;
+
+ ret[len] = s;
+ ret[len+1] = NULL;
+
+ return ret;
+}
+
+/**
+ copy a string list
+ this assumes list will not change
+*/
+_PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
+ const char **list)
+{
+ int i;
+ const char **ret;
+
+ if (list == NULL)
+ return NULL;
+
+ ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
+ if (ret == NULL)
+ return NULL;
+
+ for (i=0;list && list[i];i++) {
+ ret[i] = list[i];
+ }
+ ret[i] = NULL;
+ return ret;
+}
diff --git a/lib/util/util_strlist.h b/lib/util/util_strlist.h
new file mode 100644
index 0000000..5c3a7ee
--- /dev/null
+++ b/lib/util/util_strlist.h
@@ -0,0 +1,156 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_UTIL_STRLIST_H
+#define _SAMBA_UTIL_STRLIST_H
+
+#include <talloc.h>
+
+/* separators for lists */
+#ifndef LIST_SEP
+#define LIST_SEP " \t,\n\r"
+#endif
+
+/**
+ build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc)
+*/
+char **str_list_make_empty(TALLOC_CTX *mem_ctx);
+
+/**
+ place the only element 'entry' into a new, NULL terminated string list
+*/
+char **str_list_make_single(TALLOC_CTX *mem_ctx,
+ const char *entry);
+
+/**
+ build a null terminated list of strings from a input string and a
+ separator list. The separator list must contain characters less than
+ or equal to 0x2f for this to work correctly on multi-byte strings
+*/
+char **str_list_make(TALLOC_CTX *mem_ctx, const char *string,
+ const char *sep);
+
+/**
+ * build a null terminated list of strings from an argv-like input string
+ * Entries are separated by spaces and can be enclosed by quotes.
+ * Does NOT support escaping
+ */
+char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string,
+ const char *sep);
+
+/**
+ * join a list back to one string
+ */
+char *str_list_join(TALLOC_CTX *mem_ctx, const char **list,
+ char separator);
+
+/** join a list back to one (shell-like) string; entries
+ * separated by spaces, using quotes where necessary */
+char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list,
+ char sep);
+
+/**
+ return the number of elements in a string list
+*/
+size_t str_list_length(const char * const *list);
+
+/**
+ copy a string list
+*/
+char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list);
+
+/**
+ Return true if all the elements of the list match exactly.
+ */
+bool str_list_equal(const char * const *list1,
+ const char * const *list2);
+
+/**
+ add an entry to a string list
+*/
+const char **str_list_add(const char **list, const char *s);
+
+/*
+ * Extend a list with a printf'ed string
+ */
+void str_list_add_printf(char ***plist, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2,3);
+
+/**
+ remove an entry from a string list
+*/
+void str_list_remove(const char **list, const char *s);
+
+/**
+ return true if a string is in a list
+*/
+bool str_list_check(const char **list, const char *s);
+
+/**
+ return true if a string is in a list, case insensitively
+*/
+bool str_list_check_ci(const char **list, const char *s);
+/**
+ append one list to another - expanding list1
+*/
+const char **str_list_append(const char **list1,
+ const char * const *list2);
+
+/**
+ remove duplicate elements from a list
+*/
+const char **str_list_unique(const char **list);
+
+/*
+ very useful when debugging complex list related code
+ */
+void str_list_show(const char **list);
+
+
+/**
+ append one list to another - expanding list1
+ this assumes the elements of list2 are const pointers, so we can re-use them
+*/
+const char **str_list_append_const(const char **list1,
+ const char **list2);
+
+/**
+ Add a string to an array of strings.
+
+ num should be a pointer to an integer that holds the current
+ number of elements in strings. It will be updated by this function.
+ */
+bool add_string_to_array(TALLOC_CTX *mem_ctx,
+ const char *str, const char ***strings, size_t *num);
+
+/**
+ add an entry to a string list
+ this assumes s will not change
+*/
+const char **str_list_add_const(const char **list, const char *s);
+
+/**
+ copy a string list
+ this assumes list will not change
+*/
+const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
+ const char **list);
+
+#endif /* _SAMBA_UTIL_STRLIST_H */
diff --git a/lib/util/util_strlist_v3.c b/lib/util/util_strlist_v3.c
new file mode 100644
index 0000000..75973f2
--- /dev/null
+++ b/lib/util/util_strlist_v3.c
@@ -0,0 +1,128 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/locale.h"
+#include "lib/util/tsort.h"
+
+#undef strcasecmp
+
+/**
+ * @file
+ * @brief String list manipulation v3
+ */
+
+/**
+ * Needed for making an "unconst" list "const"
+ */
+_PUBLIC_ const char **const_str_list(char **list)
+{
+ return discard_const_p(const char *, list);
+}
+
+/**
+ * str_list_make, v3 version. The v4 version does not
+ * look at quoted strings with embedded blanks, so
+ * do NOT merge this function please!
+ */
+#define S_LIST_ABS 16 /* List Allocation Block Size */
+
+char **str_list_make_v3(TALLOC_CTX *mem_ctx, const char *string,
+ const char *sep)
+{
+ char **list;
+ const char *str;
+ char *s, *tok;
+ int num, lsize;
+
+ if (!string || !*string)
+ return NULL;
+
+ list = talloc_array(mem_ctx, char *, S_LIST_ABS+1);
+ if (list == NULL) {
+ return NULL;
+ }
+ lsize = S_LIST_ABS;
+
+ s = talloc_strdup(list, string);
+ if (s == NULL) {
+ DEBUG(0,("str_list_make: Unable to allocate memory\n"));
+ TALLOC_FREE(list);
+ return NULL;
+ }
+
+ /*
+ * DON'T REPLACE THIS BY "LIST_SEP". The common version of
+ * LIST_SEP does not contain the ;, which used to be accepted
+ * by Samba 4.0 before param merges. It would be the far
+ * better solution to split the _v3 version again to source3/
+ * where it belongs, see the _v3 in its name.
+ *
+ * Unfortunately it is referenced in /lib/param/loadparm.c,
+ * which depends on the version that the AD-DC mandates,
+ * namely without the ; as part of the list separator. I am
+ * missing the waf fu to properly work around the wrong
+ * include paths here for this defect.
+ */
+ if (sep == NULL) {
+ sep = " \t,;\n\r";
+ }
+
+ num = 0;
+ str = s;
+
+ while (next_token_talloc(list, &str, &tok, sep)) {
+
+ if (num == lsize) {
+ char **tmp;
+
+ lsize += S_LIST_ABS;
+
+ tmp = talloc_realloc(mem_ctx, list, char *,
+ lsize + 1);
+ if (tmp == NULL) {
+ DEBUG(0,("str_list_make: "
+ "Unable to allocate memory\n"));
+ TALLOC_FREE(list);
+ return NULL;
+ }
+
+ list = tmp;
+
+ memset (&list[num], 0,
+ ((sizeof(char*)) * (S_LIST_ABS +1)));
+ }
+
+ list[num] = tok;
+ num += 1;
+ }
+
+ list[num] = NULL;
+
+ TALLOC_FREE(s);
+ return list;
+}
+
+const char **str_list_make_v3_const(TALLOC_CTX *mem_ctx,
+ const char *string,
+ const char *sep)
+{
+ return const_str_list(str_list_make_v3(mem_ctx, string, sep));
+}
diff --git a/lib/util/util_tdb.c b/lib/util/util_tdb.c
new file mode 100644
index 0000000..d8672c3
--- /dev/null
+++ b/lib/util/util_tdb.c
@@ -0,0 +1,525 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ tdb utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2006
+ Copyright (C) Volker Lendecke 2007-2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+#include "lib/util/memory.h"
+#include "lib/util/byteorder.h"
+#include "system/filesys.h"
+#include "../lib/tdb/include/tdb.h"
+#include "../lib/util/util_tdb.h"
+
+/* these are little tdb utility functions that are meant to make
+ dealing with a tdb database a little less cumbersome in Samba */
+
+/***************************************************************
+ Make a TDB_DATA and keep the const warning in one place
+****************************************************************/
+
+TDB_DATA make_tdb_data(const uint8_t *dptr, size_t dsize)
+{
+ TDB_DATA ret;
+ ret.dptr = discard_const_p(uint8_t, dptr);
+ ret.dsize = dsize;
+ return ret;
+}
+
+bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2)
+{
+ if (t1.dsize != t2.dsize) {
+ return false;
+ }
+ return (memcmp(t1.dptr, t2.dptr, t1.dsize) == 0);
+}
+
+bool tdb_data_is_empty(TDB_DATA d)
+{
+ return (d.dsize == 0) || (d.dptr == NULL);
+}
+
+TDB_DATA string_tdb_data(const char *string)
+{
+ return make_tdb_data((const uint8_t *)string, string ? strlen(string) : 0 );
+}
+
+TDB_DATA string_term_tdb_data(const char *string)
+{
+ return make_tdb_data((const uint8_t *)string, string ? strlen(string) + 1 : 0);
+}
+
+TDB_DATA tdb_data_talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data) {
+ TDB_DATA ret = {
+ .dptr = (uint8_t *)talloc_size(mem_ctx, data.dsize+1),
+ .dsize = data.dsize
+ };
+ if (ret.dptr == NULL) {
+ ret.dsize = 0;
+ } else {
+ memcpy(ret.dptr, data.dptr, data.dsize);
+ ret.dptr[ret.dsize] = '\0';
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+ Lock a chain by string. Return non-zero if lock failed.
+****************************************************************************/
+
+int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ return tdb_chainlock(tdb, key);
+}
+
+/****************************************************************************
+ Unlock a chain by string.
+****************************************************************************/
+
+void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ tdb_chainunlock(tdb, key);
+}
+
+/****************************************************************************
+ Read lock a chain by string. Return non-zero if lock failed.
+****************************************************************************/
+
+int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ return tdb_chainlock_read(tdb, key);
+}
+
+/****************************************************************************
+ Read unlock a chain by string.
+****************************************************************************/
+
+void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval)
+{
+ TDB_DATA key = string_term_tdb_data(keyval);
+
+ tdb_chainunlock_read(tdb, key);
+}
+
+
+/****************************************************************************
+ Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
+ Output is int32_t in native byte order.
+****************************************************************************/
+
+static int fetch_int32_parser(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ if (data.dsize == sizeof(int32_t)) {
+ *((int32_t *)private_data) = PULL_LE_I32(data.dptr, 0);
+ }
+ return 0;
+}
+
+static int32_t tdb_fetch_int32_byblob(struct tdb_context *tdb, TDB_DATA key)
+{
+ int32_t v = -1;
+ int32_t ret = tdb_parse_record(tdb, key, fetch_int32_parser, &v);
+ if (ret == -1) {
+ return ret;
+ }
+ return v;
+}
+
+/****************************************************************************
+ Fetch a int32_t value by string key, return -1 if not found.
+ Output is int32_t in native byte order.
+****************************************************************************/
+
+int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr)
+{
+ return tdb_fetch_int32_byblob(tdb, string_term_tdb_data(keystr));
+}
+
+/****************************************************************************
+ Store a int32_t value by an arbitrary blob key, return 0 on success, -ve on failure.
+ Input is int32_t in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+static int tdb_store_int32_byblob(struct tdb_context *tdb, TDB_DATA key,
+ int32_t v)
+{
+ TDB_DATA data;
+ int32_t v_store;
+
+ SIVAL(&v_store,0,v);
+ data.dptr = (unsigned char *)&v_store;
+ data.dsize = sizeof(int32_t);
+
+ return tdb_store(tdb, key, data, TDB_REPLACE);
+}
+
+/****************************************************************************
+ Store a int32_t value by string key, return 0 on success, -ve on failure.
+ Input is int32_t in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v)
+{
+ return tdb_store_int32_byblob(tdb, string_term_tdb_data(keystr), v);
+}
+
+/****************************************************************************
+ Fetch a uint32_t value by a arbitrary blob key, return false if not found.
+ Output is uint32_t in native byte order.
+****************************************************************************/
+
+static int fetch_uint32_parser(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+ if (data.dsize != sizeof(uint32_t)) {
+ return -1;
+ }
+ *((uint32_t *)private_data) = PULL_LE_U32(data.dptr, 0);
+ return 0;
+}
+
+static bool tdb_fetch_uint32_byblob(struct tdb_context *tdb, TDB_DATA key,
+ uint32_t *value)
+{
+ int ret = tdb_parse_record(tdb, key, fetch_uint32_parser, value);
+
+ if (ret == -1) {
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Fetch a uint32_t value by string key, return false if not found.
+ Output is uint32_t in native byte order.
+****************************************************************************/
+
+bool tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value)
+{
+ return tdb_fetch_uint32_byblob(tdb, string_term_tdb_data(keystr), value);
+}
+
+/****************************************************************************
+ Store a uint32_t value by an arbitrary blob key, return true on success, false on failure.
+ Input is uint32_t in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+static bool tdb_store_uint32_byblob(struct tdb_context *tdb, TDB_DATA key,
+ uint32_t value)
+{
+ TDB_DATA data;
+ uint32_t v_store;
+ bool ret = true;
+
+ SIVAL(&v_store, 0, value);
+ data.dptr = (unsigned char *)&v_store;
+ data.dsize = sizeof(uint32_t);
+
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ ret = false;
+
+ return ret;
+}
+
+/****************************************************************************
+ Store a uint32_t value by string key, return true on success, false on failure.
+ Input is uint32_t in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+
+bool tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value)
+{
+ return tdb_store_uint32_byblob(tdb, string_term_tdb_data(keystr), value);
+}
+/****************************************************************************
+ Store a buffer by a null terminated string key. Return 0 on success, -ve
+ on failure.
+****************************************************************************/
+
+int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_store(tdb, key, data, flags);
+}
+
+/****************************************************************************
+ Fetch a buffer using a null terminated string key. Don't forget to call
+ free() on the result dptr.
+****************************************************************************/
+
+TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_fetch(tdb, key);
+}
+
+/****************************************************************************
+ Delete an entry using a null terminated string key.
+****************************************************************************/
+
+int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr)
+{
+ TDB_DATA key = string_term_tdb_data(keystr);
+
+ return tdb_delete(tdb, key);
+}
+
+/****************************************************************************
+ Atomic integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+
+int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
+{
+ int32_t val;
+ int32_t ret = -1;
+
+ if (tdb_lock_bystring(tdb, keystr) != 0)
+ return -1;
+
+ if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
+ /* The lookup failed */
+ if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
+ /* but not because it didn't exist */
+ goto err_out;
+ }
+
+ /* Start with 'old' value */
+ val = *oldval;
+
+ } else {
+ /* It worked, set return value (oldval) to tdb data */
+ *oldval = val;
+ }
+
+ /* Increment value for storage and return next time */
+ val += change_val;
+
+ if (tdb_store_int32(tdb, keystr, val) != 0)
+ goto err_out;
+
+ ret = 0;
+
+ err_out:
+
+ tdb_unlock_bystring(tdb, keystr);
+ return ret;
+}
+
+/****************************************************************************
+ Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+
+bool tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
+{
+ uint32_t val;
+ bool ret = false;
+
+ if (tdb_lock_bystring(tdb, keystr) != 0)
+ return false;
+
+ if (!tdb_fetch_uint32(tdb, keystr, &val)) {
+ /* It failed */
+ if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
+ /* and not because it didn't exist */
+ goto err_out;
+ }
+
+ /* Start with 'old' value */
+ val = *oldval;
+
+ } else {
+ /* it worked, set return value (oldval) to tdb data */
+ *oldval = val;
+
+ }
+
+ /* get a new value to store */
+ val += change_val;
+
+ if (!tdb_store_uint32(tdb, keystr, val))
+ goto err_out;
+
+ ret = true;
+
+ err_out:
+
+ tdb_unlock_bystring(tdb, keystr);
+ return ret;
+}
+
+/****************************************************************************
+ Return an NTSTATUS from a TDB_ERROR
+****************************************************************************/
+
+NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
+{
+ NTSTATUS result;
+
+ switch (err) {
+ case TDB_SUCCESS:
+ result = NT_STATUS_OK;
+ break;
+ case TDB_ERR_CORRUPT:
+ result = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ break;
+ case TDB_ERR_IO:
+ result = NT_STATUS_UNEXPECTED_IO_ERROR;
+ break;
+ case TDB_ERR_OOM:
+ result = NT_STATUS_NO_MEMORY;
+ break;
+ case TDB_ERR_EXISTS:
+ result = NT_STATUS_OBJECT_NAME_COLLISION;
+ break;
+
+ case TDB_ERR_LOCK:
+ /*
+ * TDB_ERR_LOCK is very broad, we could for example
+ * distinguish between fcntl locks and invalid lock
+ * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
+ * compromise.
+ */
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ break;
+
+ case TDB_ERR_NOLOCK:
+ case TDB_ERR_LOCK_TIMEOUT:
+ /*
+ * These two ones in the enum are not actually used
+ */
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ break;
+ case TDB_ERR_NOEXIST:
+ result = NT_STATUS_NOT_FOUND;
+ break;
+ case TDB_ERR_EINVAL:
+ result = NT_STATUS_INVALID_PARAMETER;
+ break;
+ case TDB_ERR_RDONLY:
+ result = NT_STATUS_ACCESS_DENIED;
+ break;
+ case TDB_ERR_NESTING:
+ result = NT_STATUS_INTERNAL_ERROR;
+ break;
+ default:
+ result = NT_STATUS_INTERNAL_ERROR;
+ break;
+ };
+ return result;
+}
+
+int map_unix_error_from_tdb(enum TDB_ERROR err)
+{
+ int result = EINVAL;
+
+ switch (err) {
+ case TDB_SUCCESS:
+ result = 0;
+ break;
+ case TDB_ERR_CORRUPT:
+ result = EILSEQ;
+ break;
+ case TDB_ERR_IO:
+ result = EIO;
+ break;
+ case TDB_ERR_OOM:
+ result = ENOMEM;
+ break;
+ case TDB_ERR_EXISTS:
+ result = EEXIST;
+ break;
+
+ case TDB_ERR_LOCK:
+ /*
+ * TDB_ERR_LOCK is very broad, we could for example
+ * distinguish between fcntl locks and invalid lock
+ * sequences. EWOULDBLOCK is wrong, but there is no real
+ * generic lock error code in errno.h
+ */
+ result = EWOULDBLOCK;
+ break;
+
+ case TDB_ERR_NOLOCK:
+ case TDB_ERR_LOCK_TIMEOUT:
+ /*
+ * These two ones in the enum are not actually used
+ */
+ result = ENOLCK;
+ break;
+ case TDB_ERR_NOEXIST:
+ result = ENOENT;
+ break;
+ case TDB_ERR_EINVAL:
+ result = EINVAL;
+ break;
+ case TDB_ERR_RDONLY:
+ result = EROFS;
+ break;
+ case TDB_ERR_NESTING:
+ /*
+ * Well, this db is already busy...
+ */
+ result = EBUSY;
+ break;
+ };
+ return result;
+}
+
+struct tdb_fetch_talloc_state {
+ TALLOC_CTX *mem_ctx;
+ uint8_t *buf;
+};
+
+static int tdb_fetch_talloc_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct tdb_fetch_talloc_state *state = private_data;
+ state->buf = talloc_memdup(state->mem_ctx, data.dptr, data.dsize);
+ return 0;
+}
+
+int tdb_fetch_talloc(struct tdb_context *tdb, TDB_DATA key,
+ TALLOC_CTX *mem_ctx, uint8_t **buf)
+{
+ struct tdb_fetch_talloc_state state = { .mem_ctx = mem_ctx };
+ int ret;
+
+ ret = tdb_parse_record(tdb, key, tdb_fetch_talloc_parser, &state);
+ if (ret == -1) {
+ enum TDB_ERROR err = tdb_error(tdb);
+ return map_unix_error_from_tdb(err);
+ }
+
+ if (state.buf == NULL) {
+ return ENOMEM;
+ }
+
+ *buf = state.buf;
+ return 0;
+}
diff --git a/lib/util/util_tdb.h b/lib/util/util_tdb.h
new file mode 100644
index 0000000..010521d
--- /dev/null
+++ b/lib/util/util_tdb.h
@@ -0,0 +1,125 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ tdb utility functions
+
+ Copyright (C) Andrew Tridgell 1992-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _____LIB_UTIL_UTIL_TDB_H__
+#define _____LIB_UTIL_UTIL_TDB_H__
+
+#include "replace.h"
+#include <tdb.h>
+#include "libcli/util/ntstatus.h"
+
+/***************************************************************
+ Make a TDB_DATA and keep the const warning in one place
+****************************************************************/
+TDB_DATA make_tdb_data(const uint8_t *dptr, size_t dsize);
+bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2);
+bool tdb_data_is_empty(TDB_DATA d);
+TDB_DATA string_tdb_data(const char *string);
+TDB_DATA string_term_tdb_data(const char *string);
+TDB_DATA tdb_data_talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data);
+
+/****************************************************************************
+ Lock a chain by string. Return non-zero if lock failed.
+****************************************************************************/
+int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval);
+
+/****************************************************************************
+ Unlock a chain by string.
+****************************************************************************/
+void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval);
+
+/****************************************************************************
+ Read lock a chain by string. Return non-zero if lock failed.
+****************************************************************************/
+int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval);
+
+/****************************************************************************
+ Read unlock a chain by string.
+****************************************************************************/
+void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval);
+
+/****************************************************************************
+ Fetch a int32_t value by string key, return -1 if not found.
+ Output is int32_t in native byte order.
+****************************************************************************/
+int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr);
+
+/****************************************************************************
+ Store a int32_t value by string key, return 0 on success, -ve on failure.
+ Input is int32_t in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v);
+
+/****************************************************************************
+ Fetch a uint32_t value by string key, return -1 if not found.
+ Output is uint32_t in native byte order.
+****************************************************************************/
+bool tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value);
+
+/****************************************************************************
+ Store a uint32_t value by string key, return true on success, false on failure.
+ Input is uint32_t in native byte order. Output in tdb is in little-endian.
+****************************************************************************/
+bool tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value);
+
+/****************************************************************************
+ Store a buffer by a null terminated string key. Return 0 on success, -ve
+ on failure.
+****************************************************************************/
+int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags);
+
+/****************************************************************************
+ Fetch a buffer using a null terminated string key. Don't forget to call
+ free() on the result dptr.
+****************************************************************************/
+TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr);
+
+/****************************************************************************
+ Delete an entry using a null terminated string key. 0 on success, -ve on err.
+****************************************************************************/
+int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr);
+
+/****************************************************************************
+ Atomic integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val);
+
+/****************************************************************************
+ Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
+****************************************************************************/
+bool tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val);
+
+/****************************************************************************
+ Return an NTSTATUS from a TDB_ERROR
+****************************************************************************/
+
+NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err);
+
+/****************************************************************************
+ Return an errno from a TDB_ERROR
+****************************************************************************/
+
+int map_unix_error_from_tdb(enum TDB_ERROR err);
+
+int tdb_fetch_talloc(struct tdb_context *tdb, TDB_DATA key,
+ TALLOC_CTX *mem_ctx, uint8_t **buf);
+
+#endif /* _____LIB_UTIL_UTIL_TDB_H__ */
diff --git a/lib/util/wscript b/lib/util/wscript
new file mode 100644
index 0000000..425f659
--- /dev/null
+++ b/lib/util/wscript
@@ -0,0 +1,32 @@
+def options(opt):
+ ''' This is a bit strange, but disable is the flag, not enable. '''
+ opt.add_option('--disable-fault-handling', action='store_true', dest='disable_fault_handling', help=('disable the fault handlers'), default=False)
+
+ # We do not want libunwind by default (backtrace_symbols() in
+ # glibc is better) but allow (eg) IA-64 to build with it where it
+ # might be better (per old comment in fault.c)
+ opt.samba_add_onoff_option('libunwind',
+ default=None,
+ help='''Use libunwind instead of the default backtrace_symbols()
+ from libc, for example on IA-64 where it might give a better
+ backtrace.''')
+
+ opt.add_option('--with-systemd',
+ help=("Enable systemd integration"),
+ action='store_true', dest='enable_systemd')
+
+ opt.add_option('--without-systemd',
+ help=("Disable systemd integration"),
+ action='store_false', dest='enable_systemd')
+
+ opt.add_option('--with-lttng',
+ help=("Enable lttng integration"),
+ action='store_true', dest='enable_lttng')
+
+ opt.add_option('--without-lttng',
+ help=("Disable lttng integration"),
+ action='store_false', dest='enable_lttng')
+
+ opt.add_option('--with-gpfs',
+ help=("Directory under which gpfs headers are installed"),
+ action="store", dest='gpfs_headers_dir')
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
new file mode 100644
index 0000000..b4fcfea
--- /dev/null
+++ b/lib/util/wscript_build
@@ -0,0 +1,415 @@
+#!/usr/bin/env python
+
+# Please add any new SAMBA_SUBSYSTEM/SAMBA_LIBRARY to the bottom of the file
+# unless they are also required to build standalone ctdb.
+
+bld.SAMBA_LIBRARY('time-basic',
+ source='time_basic.c',
+ deps='replace',
+ private_library=True,
+ local_include=False)
+
+bld.SAMBA_SUBSYSTEM('tini',
+ source='tini.c',
+ provide_builtin_linking=True,
+ local_include=False)
+
+bld.SAMBA_SUBSYSTEM('tiniparser',
+ source='tiniparser.c',
+ deps='tini',
+ provide_builtin_linking=True,
+ local_include=False)
+
+bld.SAMBA_SUBSYSTEM('strv',
+ source='strv.c',
+ deps='talloc',
+ local_include=False)
+
+bld.SAMBA_SUBSYSTEM('close-low-fd',
+ source='close_low_fd.c',
+ deps='replace',
+ local_include=False)
+
+bld.SAMBA_LIBRARY('sys_rw',
+ source='sys_rw.c sys_rw_data.c',
+ deps='replace iov_buf',
+ local_include=False,
+ private_library=True)
+
+samba_debug_add_deps = ''
+samba_debug_add_inc = ''
+
+if bld.CONFIG_SET('HAVE_GPFS'):
+ bld.SAMBA_SUBSYSTEM('gpfswrap',
+ source='gpfswrap.c',
+ deps='replace',
+ local_include=False,
+ includes=bld.CONFIG_GET('CPPPATH_GPFS'))
+ samba_debug_add_deps += ' gpfswrap'
+ samba_debug_add_inc += bld.CONFIG_GET('CPPPATH_GPFS')
+
+bld.SAMBA_LIBRARY('samba-debug',
+ source='debug.c',
+ deps='replace time-basic close-low-fd talloc socket-blocking' + samba_debug_add_deps,
+ public_deps='systemd systemd-journal lttng-ust',
+ local_include=False,
+ includes='lib/util/debug-classes ' + samba_debug_add_inc,
+ private_library=True)
+
+bld.SAMBA_LIBRARY('socket-blocking',
+ source='blocking.c',
+ local_include=False,
+ private_library=True)
+
+bld.SAMBA_LIBRARY('talloc_report',
+ source='talloc_report.c',
+ local_include=False,
+ public_deps='talloc',
+ private_library=True
+ )
+
+bld.SAMBA_LIBRARY('talloc_report_printf',
+ source='talloc_report_printf.c',
+ local_include=False,
+ public_deps='talloc',
+ private_library=True
+ )
+
+bld.SAMBA_SUBSYSTEM('smb-panic',
+ source='''
+ fault.c
+ signal.c
+ util_process.c
+ ''',
+ deps='''
+ replace
+ samba-debug
+ LIBUNWIND
+ execinfo
+ ''',
+ local_include=False)
+
+bld.SAMBA_SUBSYSTEM('samba-util-core',
+ source='''
+ data_blob.c
+ util_file.c
+ sys_popen.c
+ time.c
+ util.c
+ idtree.c
+ substitute.c
+ util_strlist.c
+ strv_util.c
+ bitmap.c
+ select.c
+ pidfile.c
+ become_daemon.c
+ mkdir_p.c
+ ''',
+ deps='''
+ time-basic
+ samba-debug
+ socket-blocking
+ talloc
+ tevent
+ execinfo
+ pthread
+ strv
+ tini
+ smb_strtox
+ smb-panic
+ gnutls
+ ''',
+ public_deps='systemd systemd-daemon sys_rw',
+ local_include=False)
+
+bld.SAMBA_SUBSYSTEM('smb_strtox',
+ source='smb_strtox.c',
+ provide_builtin_linking=True,
+ local_include=False)
+
+
+bld.SAMBA_LIBRARY('iov_buf',
+ source='iov_buf.c',
+ deps='talloc',
+ local_include=False,
+ private_library=True)
+
+bld.SAMBA_LIBRARY('msghdr',
+ source='msghdr.c',
+ deps='replace iov_buf',
+ local_include=False,
+ private_library=True)
+
+bld.SAMBA_LIBRARY('genrand',
+ source='genrand.c',
+ deps='replace gnutls smb-panic',
+ local_include=False,
+ private_library=True)
+
+bld.SAMBA_LIBRARY('stable_sort',
+ source='stable_sort.c',
+ deps='replace',
+ public_deps='talloc',
+ local_include=False,
+ private_library=True)
+
+if bld.env.SAMBA_UTIL_CORE_ONLY:
+
+ bld.SAMBA_LIBRARY('tevent-util',
+ source='tevent_unix.c',
+ local_include=False,
+ deps='tevent',
+ private_library=True)
+
+else:
+
+ bld.env.public_headers_skip.append('charset_compat.h')
+
+ bld.SAMBA_BINARY('genrandperf',
+ source='tests/genrandperf.c',
+ deps='genrand replace',
+ local_include=False,
+ install=False)
+
+ # TODO: Rewrite ms_fnmatch_core() for a better API.
+ ms_fnmatch_cflags=''
+ if bld.CONFIG_SET('HAVE_WNO_ERROR_ARRAY_BOUNDS'):
+ ms_fnmatch_cflags='-Wno-error=array-bounds'
+ bld.SAMBA_SUBSYSTEM('SAMBA_UTIL_MS_FNMATCH',
+ source='ms_fnmatch.c',
+ deps='talloc',
+ cflags=ms_fnmatch_cflags,
+ local_include=False)
+
+ bld.SAMBA_LIBRARY('samba-util',
+ source='''
+ base64.c
+ dprintf.c
+ fsusage.c
+ genrand_util.c
+ getpass.c
+ idtree_random.c
+ memcache.c
+ params.c
+ rbtree.c
+ rfc1738.c
+ server_id.c
+ smb_threads.c
+ system.c
+ talloc_keep_secret.c
+ talloc_stack.c
+ tevent_debug.c
+ tfork.c
+ tftw.c
+ unix_match.c
+ util_id.c
+ util_net.c
+ util_paths.c
+ util_str.c
+ util_str_common.c
+ util_strlist_v3.c
+ ''',
+ deps='''
+ samba-util-core
+ DYNCONFIG
+ close-low-fd
+ tiniparser
+ genrand
+ util_str_hex
+ SAMBA_UTIL_MS_FNMATCH
+ ''',
+ public_deps='talloc tevent execinfo pthread LIBCRYPTO charset util_setid',
+ public_headers='''
+ attr.h
+ data_blob.h
+ debug.h
+ discard.h
+ time.h
+ idtree.h
+ idtree_random.h
+ blocking.h
+ signal.h
+ substitute.h
+ fault.h
+ genrand.h
+ tfork.h
+ ''',
+ header_path= [ ('dlinklist.h samba_util.h', '.'), ('*', 'util') ],
+ local_include=False,
+ vnum='0.0.1',
+ pc_files='samba-util.pc'
+ )
+
+ bld.SAMBA_LIBRARY('samba-modules',
+ source='modules.c',
+ deps='samba-errors samba-util',
+ local_include=False,
+ private_library=True)
+
+ bld.SAMBA_LIBRARY('asn1util',
+ source='asn1.c',
+ deps='talloc samba-util',
+ private_library=True,
+ local_include=False)
+
+
+ bld.SAMBA_SUBSYSTEM('UNIX_PRIVS',
+ source='unix_privs.c',
+ autoproto='unix_privs.h',
+ deps='replace talloc',
+ local_include=False,
+ )
+
+
+ bld.SAMBA_LIBRARY('util_tdb',
+ source='util_tdb.c',
+ local_include=False,
+ public_deps='tdb talloc',
+ private_library=True
+ )
+
+ bld.SAMBA_LIBRARY('tevent-util',
+ source='''
+ tevent_unix.c
+ tevent_ntstatus.c
+ tevent_werror.c
+ tevent_req_profile.c
+ ''',
+ local_include=False,
+ public_deps='tevent samba-errors',
+ public_headers='tevent_ntstatus.h tevent_unix.h tevent_werror.h',
+ header_path=[ ('*', 'util') ],
+ pc_files=[],
+ vnum='0.0.1'
+ )
+
+ bld.SAMBA_LIBRARY('util_setid',
+ source='setid.c',
+ local_include=False,
+ private_library=True
+ )
+
+ bld.SAMBA_SUBSYSTEM('util_ldb',
+ source='util_ldb.c',
+ local_include=False,
+ public_deps='ldb',
+ public_headers='util_ldb.h'
+ )
+
+
+ bld.SAMBA_SUBSYSTEM('UTIL_RUNCMD',
+ source='util_runcmd.c',
+ local_include=False,
+ public_deps='tevent'
+ )
+
+ bld.SAMBA_SUBSYSTEM('UTIL_PW',
+ source='util_pw.c',
+ local_include=False,
+ public_deps='talloc'
+ )
+
+ bld.SAMBA_LIBRARY('server_id_db',
+ source='server_id_db.c',
+ deps='talloc tdb strv util_tdb tdb-wrap samba-util',
+ local_include=False,
+ private_library=True)
+
+ bld.SAMBA_SUBSYSTEM('access',
+ source='access.c',
+ deps='interfaces samba-util',
+ local_include=False)
+
+ bld.SAMBA_SUBSYSTEM('util_str_escape',
+ source='util_str_escape.c',
+ deps='talloc',
+ local_include=False)
+
+ bld.SAMBA_SUBSYSTEM('util_str_hex',
+ source='util_str_hex.c',
+ deps='talloc',
+ local_include=False)
+
+ bld.SAMBA_BINARY('test_rfc1738',
+ source='tests/rfc1738.c',
+ deps='cmocka replace samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_ms_fnmatch',
+ source='tests/test_ms_fnmatch.c',
+ deps='cmocka replace samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_talloc_keep_secret',
+ source='tests/test_talloc_keep_secret.c',
+ deps='cmocka replace samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_byteorder',
+ source='tests/test_byteorder.c',
+ deps='cmocka replace samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_bytearray',
+ source='tests/test_bytearray.c',
+ deps='cmocka replace samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_byteorder_verify',
+ source='tests/test_byteorder_verify.c',
+ deps='cmocka replace samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_util_paths',
+ source='tests/test_util_paths.c',
+ deps='cmocka replace talloc samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_util',
+ source='tests/test_util.c',
+ deps='cmocka replace talloc samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_memcache',
+ source='tests/test_memcache.c',
+ deps='cmocka replace talloc samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_sys_rw',
+ source='tests/test_sys_rw.c',
+ deps='cmocka replace samba-util',
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_s4_logging',
+ source='tests/test_logging.c',
+ deps=' '.join(['CMDLINE_S4',
+ 'samba-util',
+ 'popt']),
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_s3_logging',
+ source='tests/test_logging.c',
+ deps=' '.join(['CMDLINE_S3',
+ 'samba-util',
+ 'popt']),
+ cflags="-D USING_CMDLINE_S3",
+ local_include=False,
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_stable_sort',
+ source='tests/test_stable_sort.c',
+ deps='cmocka replace talloc stable_sort',
+ local_include=False,
+ for_selftest=True)
diff --git a/lib/util/wscript_configure b/lib/util/wscript_configure
new file mode 100644
index 0000000..27206e0
--- /dev/null
+++ b/lib/util/wscript_configure
@@ -0,0 +1,189 @@
+#!/usr/bin/env python
+from waflib import Logs, Options, Errors
+
+import os, sys
+
+if Options.options.disable_fault_handling:
+ conf.DEFINE('HAVE_DISABLE_FAULT_HANDLING',1)
+
+# backtrace could be in libexecinfo or in libc.
+# This is our preferred backtrace handler (more useful output than libunwind as at Ubuntu 20.04 x86_64)
+conf.CHECK_FUNCS_IN('backtrace backtrace_symbols', 'execinfo', checklibc=True, headers='execinfo.h')
+conf.CHECK_HEADERS('execinfo.h')
+
+conf.SET_TARGET_TYPE('LIBUNWIND', 'EMPTY')
+if Options.options.with_libunwind:
+ if conf.check_cfg(package='libunwind-generic',
+ args='--cflags --libs',
+ msg='Checking for libunwind',
+ uselib_store='LIBUNWIND',
+ mandatory=False):
+ if conf.CHECK_HEADERS('libunwind.h'):
+ conf.SET_TARGET_TYPE('LIBUNWIND', 'SYSLIB')
+ else:
+ raise Errors.WafError('--with-libunwind specified but libunwind not found')
+elif Options.options.with_libunwind == None:
+ if not conf.CONFIG_SET('HAVE_BACKTRACE_SYMBOLS') \
+ and not Options.options.disable_fault_handling:
+ raise Errors.WafError(
+'''backtrace_symbols() not found but
+--with-libunwind not specified.
+Use --without-libunwind to build without internal backtrace support or
+--disable-fault-handling to totally defer fault handling to the OS.''')
+
+conf.CHECK_STRUCTURE_MEMBER('struct statvfs', 'f_frsize', define='HAVE_FRSIZE', headers='sys/statvfs.h')
+
+# all the different ways of doing statfs
+statfs_types = [
+ ( 'STAT_STATVFS',
+ 'statvfs (SVR4)',
+ 'struct statvfs fsd; exit(statvfs(0, &fsd))',
+ 'sys/statvfs.h' ),
+
+ ( 'STAT_STATFS3_OSF1',
+ '3-argument statfs function (DEC OSF/1)',
+ 'struct statfs fsd; fsd.f_fsize = 0; exit(statfs(".", &fsd, sizeof(struct statfs)))',
+ 'sys/param.h sys/mount.h' ),
+
+ ( 'STAT_STATFS2_BSIZE',
+ 'two-argument statfs with statfs.bsize',
+ 'struct statfs fsd; fsd.f_bsize = 0; exit(statfs(".", &fsd))',
+ 'sys/param.h sys/mount.h sys/vfs.h' ),
+
+ ( 'STAT_STATFS4',
+ 'four-argument statfs (AIX-3.2.5, SVR3)',
+ 'struct statfs fsd; exit(statfs(".", &fsd, sizeof fsd, 0))',
+ 'sys/statfs.h' ),
+
+ ( 'STAT_STATFS2_FSIZE',
+ 'two-argument statfs with statfs.fsize',
+ 'struct statfs fsd; fsd.f_fsize = 0; exit(statfs(".", &fsd))',
+ 'sys/param.h sys/mount.h' ),
+
+ ( 'STAT_STATFS2_FS_DATA',
+ 'two-argument statfs with struct fs_data (Ultrix)',
+ 'struct fs_data fsd; exit(statfs(".", &fsd) != 1)',
+ 'sys/param.h sys/mount.h sys/fs_types.h' )
+]
+
+found_statfs=False
+for (define, msg, code, headers) in statfs_types:
+ if conf.CHECK_CODE(code,
+ define=define,
+ headers=headers,
+ msg='Checking for %s' % msg,
+ local_include=False):
+ found_statfs=True
+ break
+
+if not found_statfs:
+ print("FATAL: Failed to find a statfs method")
+ raise
+
+conf.CHECK_CODE("""struct statfs fsd;
+ fsd.f_bsize = 0;
+ fsd.f_iosize = 0;
+ return (statfs (".", &fsd));
+ """,
+ headers='sys/param.h sys/mount.h sys/vfs.h',
+ define='BSD_STYLE_STATVFS',
+ msg='Checking for *bsd style statfs with statfs.f_iosize',
+ execute=True,
+ local_include=False)
+
+conf.CHECK_CODE('struct statvfs buf; buf.f_fsid = 0',
+ define='HAVE_FSID_INT',
+ msg='Checking if f_fsid is an integer',
+ execute=False,
+ local_include=False,
+ headers='sys/statvfs.h')
+
+# fsusage.c assumes that statvfs has an f_frsize entry. Some weird
+# systems use f_bsize.
+conf.CHECK_CODE('struct statvfs buf; buf.f_frsize = 0',
+ define='HAVE_FRSIZE',
+ msg='Checking that statvfs.f_frsize works',
+ headers='sys/statvfs.h',
+ execute=False,
+ local_include=False)
+
+# Some systems use f_flag in struct statvfs while others use f_flags
+conf.CHECK_CODE('struct statvfs buf; buf.f_flag = 0',
+ define='HAVE_STATVFS_F_FLAG',
+ msg='Checking whether statvfs.f_flag exists',
+ headers='sys/statvfs.h',
+ local_include=False,
+ execute=False)
+
+conf.CHECK_CODE('struct statvfs buf; buf.f_flags = 0',
+ define='HAVE_STATVFS_F_FLAGS',
+ msg='Checking whether statvfs.f_flags exists',
+ headers='sys/statvfs.h',
+ local_include=False,
+ execute=False)
+
+# Check for mallinfo2() first and fallback to mallinfo() if not found
+body = '''mi.arena + mi.ordblks + mi.smblks + mi.hblks + mi.hblkhd +
+ mi.usmblks + mi.fsmblks + mi.uordblks + mi.fordblks + mi.keepcost'''
+if not conf.CHECK_CODE('''struct mallinfo2 mi = mallinfo2(); return %s;'''
+ % body, 'HAVE_MALLINFO2',
+ msg="Checking for mallinfo2()",
+ headers='malloc.h'):
+ conf.CHECK_CODE('''struct mallinfo mi = mallinfo(); return %s;'''
+ % body, 'HAVE_MALLINFO',
+ msg="Checking for mallinfo()",
+ headers='malloc.h')
+
+#
+# systemd removed the libsystemd-daemon and libsystemd-journal libraries. In newer
+# versions it is only libsystemd. As waf pkg-config handling does not provide
+# targets which could be used as a dependency based on the package name we need
+# to look for them on our own. This enabled one of the library targets based on
+# which version we detect.
+#
+conf.SET_TARGET_TYPE('systemd-daemon', 'EMPTY')
+conf.SET_TARGET_TYPE('systemd-journal', 'EMPTY')
+conf.SET_TARGET_TYPE('systemd', 'EMPTY')
+
+if Options.options.enable_systemd != False:
+ r_daemon = conf.CHECK_CFG(package='libsystemd-daemon', args='--cflags --libs',
+ msg='Checking for libsystemd-daemon')
+ r_journal = conf.CHECK_CFG(package='libsystemd-journal', args='--cflags --libs',
+ msg='Checking for libsystemd-journal')
+ if r_daemon is None and r_journal is None:
+ conf.CHECK_CFG(package='libsystemd', args='--cflags --libs',
+ msg='Checking for libsystemd')
+ conf.CHECK_LIB('systemd', shlib=True)
+ else:
+ conf.CHECK_LIB('systemd-daemon', shlib=True)
+ conf.CHECK_LIB('systemd-journal', shlib=True)
+
+conf.SET_TARGET_TYPE('lttng-ust', 'EMPTY')
+
+if Options.options.enable_lttng != False:
+ conf.CHECK_CFG(package='lttng-ust', args='--cflags --libs',
+ msg='Checking for lttng-ust', uselib_store="LTTNG-UST")
+ conf.CHECK_HEADERS('lttng/tracef.h', lib='lttng-st')
+ conf.CHECK_LIB('lttng-ust', shlib=True)
+
+if (conf.CONFIG_SET('HAVE_LTTNG_TRACEF_H') and
+ conf.CONFIG_SET('HAVE_LTTNG_UST')):
+ conf.DEFINE('HAVE_LTTNG_TRACEF', '1')
+ conf.env['HAVE_LTTNG_TRACEF'] = True
+
+if Options.options.gpfs_headers_dir:
+ conf.env['CPPPATH_GPFS'] = Options.options.gpfs_headers_dir
+ if conf.CHECK_HEADERS('gpfs.h', False, False, "gpfs"):
+ Logs.info('Using gpfs.h from %s' % Options.options.gpfs_headers_dir)
+ conf.DEFINE('HAVE_GPFS', '1')
+else:
+ conf.env['CPPPATH_GPFS'] = "/usr/lpp/mmfs/include/"
+ if conf.CHECK_HEADERS('gpfs.h', False, False, "gpfs"):
+ Logs.info('Using gpfs.h from installed gpfs package.')
+ conf.DEFINE('HAVE_GPFS', '1')
+ else:
+ if sys.platform.startswith('linux'):
+ conf.env['CPPPATH_GPFS'] = os.path.abspath("third_party/gpfs")
+ if conf.CHECK_HEADERS('gpfs.h', False, False, "gpfs"):
+ Logs.info('Using gpfs.h from third_party directory.')
+ conf.DEFINE('HAVE_GPFS', '1')
diff --git a/lib/wscript_build b/lib/wscript_build
new file mode 100644
index 0000000..94bc764
--- /dev/null
+++ b/lib/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+# a grouping library for event and socket related subsystems
+bld.SAMBA_LIBRARY('samba-sockets',
+ source=[],
+ private_library=True,
+ grouping_library=True,
+ deps='LIBTSOCKET samba_socket tevent-util')